从首页路由切换到搜索页,滚动页面时,List组件setState报错
来源:9-6 结果列表
郭小新
2018-06-16
从首页路由切换到搜索页,滚动页面时,List组件setState报错,可能是对已挂载的组件使用setState。
首页和搜索页都引用同一个List木偶组件,感觉像是List组件没有卸载就调用异步函数。
Bug:

后台数据也是混论的,在搜索页下拉List,首页的List也同时在向后台请求数据
出现关键字那里已经切换到搜索页
代码:
Home(container)
class Home extends React.Component{
constructor(props,context){
super(props,context);
}
render(){
return (
<div>
<HomeHeader cityName={this.props.userInfo.cityName} history={this.props.history} />
<Banner />
<div style={{height:'15px'}}>{/*分割线*/}</div>
<Ad />
<List cityName={this.props.userInfo.cityName} />
</div>
);
}
componentWillUnmount(){
console.log('Home unmount');
}
componentDidMount(){
console.log('Home did mount');
this.changeCity();
}
changeCity(){
// 从 localStorage 中获取城市
let cityName = localStore.getItem(CITYNAME);
if(cityName == null){
cityName = '北京';
}
// 将城市信息存储到 redux 中
this.props.userInfoActions.update({
cityName: cityName
});
}
}
Home-List(container)
class List extends React.Component{
constructor(props,context){
super(props,context);
this.state = {
data: [],
hasMore: false,//是否有下一页数据
isLoadingMore: false,//是否正在 加载更多
nextPage: 1//下一页
};
}
render(){
return (
<div>
<h2 className="home-list-title">猜你喜欢</h2>
{
this.state.data.length
? <HomeList data={this.state.data} />
: <div>加载中...</div>
}
{
this.state.hasMore
? <ListLoadMore isLoadingMore={this.state.isLoadingMore} loadMoreFn={this.loadListMore.bind(this)} />
: ''
}
</div>
);
}
componentWillUnmount(){
console.log('HomeList unmount');
this._isMounted = false;
}
componentDidMount(){
console.log('HomeList did mount');
this._isMounted = true;
this.loadListData();
}
//加载 List 数据
loadListData(){
const cityName = this.props.cityName;
const promiseData = getListData(cityName,0);//返回 promise 对象
this.handlePromise2Json(promiseData);
}
//处理加载的数据 promise对象->json
handlePromise2Json(promiseData){
promiseData.then(res => {
return res.json();
}).then(json => {
const data = json.data;
const hasMore = json.hasMore;
if(this._isMounted){
this.setState({
data: this.state.data.concat(data),
hasMore: hasMore
});
}
})
}
//加载更多 List 数据
loadListMore(){
//更新状态
this.setState({
isLoadingMore: true
});
//加载数据
const cityName = this.props.cityName;
const page = this.state.nextPage;
const promiseData = getListData(cityName,page);
this.handlePromise2Json(promiseData);
//更新状态
if(this._isMounted){
this.setState({
isLoadingMore:false,
nextPage: this.state.nextPage + 1
});
}
}
}
List(component)
class HomeList extends React.Component{
constructor(props,context){
super(props,context);
}
render(){
return (
<div id="home-list">
{
this.props.data.map((item,index) => {
return <ListItem key={index} data={item} />
})
}
</div>
);
}
componentWillUnmount(){
console.log('List unmount');
console.log('---------------');
}
componentDidMount(){
console.log('List did mount');
console.log('---------------');
}
}
ListLoadMore(component)
class ListLoadMore extends React.Component{
constructor(props){
super(props);
}
render(){
return (
<div className="list-load-more" ref='loadMore'>
{
this.props.isLoadingMore
? <span>加载中...</span>
: <span>加载更多</span>
}
</div>
);
}
componentDidMount(){
// 卸载监听
window.removeEventListener('scroll',handleScroll);
// 上拉时自动加载更多 list 内容
let timeoutId;
const isLoadingMore = this.props.isLoadingMore;
const loadMoreFn = this.props.loadMoreFn;
const loadMore = this.refs.loadMore;
const callback = function(){
// 获取 加载更多元素 与视窗顶部的距离
const top = loadMore.getBoundingClientRect().top;
// 获取可视窗口的高度
const screenHeight = window.screen.height;
if(top < screenHeight){
loadMoreFn();
}
};
// 处理 scroll 事件
const handleScroll = function(){
if(isLoadingMore){
return;
}
if(timeoutId){
//50 毫秒内存在该定时器则清空重置
clearTimeout(timeoutId);
}
timeoutId = setTimeout(callback,50);
}
// 利用节流方式监听 scroll 事件,提高性能
window.addEventListener('scroll',handleScroll);
}
}
export default ListLoadMore;写回答
2回答
-
双越
2018-06-19
看代码感觉没啥问题,你这样改改试一下。在 ListLoadMore 组件的 componentDidMount 函数体的最上部,加上一句:卸载掉 window 的 scroll 监听。
这样试一下,有问题再回复我。
012018-06-20 -
双越
2018-06-17
吧 ListLoadMore 的代码也贴出来看一下
012018-06-18
相似问题