Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ListView onEndReached不停调用 #520

Closed
leonardgithub opened this issue Nov 13, 2016 · 29 comments
Closed

ListView onEndReached不停调用 #520

leonardgithub opened this issue Nov 13, 2016 · 29 comments
Assignees

Comments

@leonardgithub
Copy link

本地环境

antd-mobile 版本:├─┬ antd-mobile@0.9.6
操作系统及其版本:Ubuntu 16.04
浏览器及其版本:Chrome Versión 52.0.2743.116 (64-bit)

你做了什么?

引入 antd-mobile 的 ListView, 并上拉

你期待的结果是:
ListView onEndReached使用正常

实际上的结果:
onEndReached不停调用,无法停止

可重现的在线演示
no

@dotaeye
Copy link

dotaeye commented Nov 14, 2016

我也碰到这个问题,我的环境是有RefreshControl的时候 ,并且手动设置了ListView的高

@leonardgithub
Copy link
Author

Can anyone fix this quickly? It's urgent

@warmhug
Copy link
Contributor

warmhug commented Nov 29, 2016

ListView 在滑动到达 onEndReachedThreshold 指定的距离后,继续滑动,会通过 scroll 事件、每隔 scrollEventThrottle 设置的时间、就会触发一次 onEndReached 回调。

I am sorry for the previous mistakes, please see this commit.

ListView 每隔 scrollEventThrottle 设置的时间、就会触发onScroll回调。
在滑动到达 onEndReachedThreshold 指定的距离临界值时、会触发一次 onEndReached 调用(在 threshold 的距离内“来回滑动”、不会再触发调用,只有滑回到外边、再次滑动到达 onEndReachedThreshold 指定的距离临界值时会再次触发调用)所以,如果 onEndReachedThreshold 设置的比较小,很容易滑出去再滑进来、也就很容易触发“不必要的”多次 onEndReached 调用,容易引起重复 Ajax 请求问题。

所以在实际项目里:在 onEndReached 调用里,需要结合一次 Ajax 请求开始到结束的 loading 状态,自行做避免重复请求的代码控制,详细做法参考官方 demo。

@dreamllq
Copy link

dreamllq commented Mar 3, 2017

这个onEndReached太坑了。。我理解的 :你们判断渲染的DOM长度和datasource里的长度一致时,调用onEndReached函数,是为了预加载一页的数据,但是现在 你预加载一页数据的时候,没有按照pageSize的大小进行渲染,然后就导致渲染的DOM长度和datasource里的长度同时增加,然后就出现了递归调用,而这个递归又没有出口 ,就会导致循环调用onEndReached函数。

@jxintang
Copy link

jxintang commented Mar 3, 2017

@warmhug 貌似不能通过Ajax的请求开始和介乎的loading状态来判断吧?
因为ajax结束时loading状态为false,但是此时onEndReached方法可能仍然在执行(被循环调用),但这时loading状态已经为false

@dancinglone
Copy link

@jxintang 是的,我也是像你这样理解,并且遇到这样的问题。ajax结束时,loading状态变为false,onEndReached 还是会执行。 并且,refreshControl组合在一起用的时候,下拉刷新清空了列表,同样会触发onEndReached,但这时并不是“onEndReachedThreshold 指定的距离后,继续滑动”. 求解。

warmhug added a commit that referenced this issue Mar 10, 2017
@zhengxianyu
Copy link

在onEndReached里面判断一下数据是否已经加载完全,如果没有加载完毕再把isLoading设置为true,就可以了。就是,在设置isLoading为true前加个条件,不要直接写

@dancinglone
Copy link

@warmhug
感谢回复!
我的场景可能有点不一样。
是这样的。我是列表是整合了refreshControl和上拉加载更多,用redux管理状态。 下拉刷新的时候,为了更新列表,会清空列表。数据未返回的时候,可以通过状态判断去阻止onEndReadched回调中接口请求的发起。但问题是,数据返回后,我把刷新状态设为“非刷新中”状态后,会在短暂的时间内,列表界面还没渲染出来,还是会发生onEndReached的回调,并且状态已经是“非刷新中”,所以会导致发起了数据请求。

@jxintang 你的问题是否也一样?

@35860368
Copy link

35860368 commented Mar 14, 2017

我也碰到了类型的问题,但是我是在下拉刷新的时候出现下拉刷新无法结束的情况,refreshing等于true的时候也无法结束下拉刷新,我们的列表是套用了ant mobile的ListView, RefreshControl组件。数据方面,数据官方demo的写死的数据,我这里通过异步请求的数据

@leonardgithub
Copy link
Author

leonardgithub commented Mar 14, 2017

@dancinglone 应该是这种情况。个人认为,即使不是fetch获取数据,onEndReached也不应该不停地被调用才对。需要用户自己做个loading标识显得有点生硬。
可否换成:onEndReached只触发一次,此时ListView滚动中,onEndReached不会触发多次。待ListView停止滚动后,onEndReached就又处于可触发的状态。

@dancinglone
Copy link

@leonardgithub 嗯,这个需要慢慢完善吧。我更着急现在问题怎样解决呢,有什么idea不,求指点。 我怀疑只是我没有理解清楚一些什么 。这个是比较常规的东西,如果有问题应该好多人会遇到啊。

@warmhug
Copy link
Contributor

warmhug commented Mar 15, 2017

数据返回后,我把刷新状态设为“非刷新中”状态后,会在短暂的时间内,列表界面还没渲染出来,还是会发生onEndReached的回调

@dancinglone 这个可能会出现,设置下scrollEventThrottle,或者 settimeout 试试。

@35860368 现在 demo 的数据虽然是写死,但已经用 settimeout 模拟 ajax 返回了、基本和真实场景一样。另外 RefreshControl 遇到的问题,建议做个能跑的 demo,放到 GitHub 上我一起看下,可以参考 https://github.com/ant-design/antd-mobile-samples/tree/master/web-webpack 这里做下。

@leonardgithub onEndReached 多次被调用 和 react-native ListView 表现一致,至于这样是否合理正确,也认为有待确认。

@35860368
Copy link

35860368 commented Mar 16, 2017

@warmhug
这是我的代码
onRefresh = () => {
this.initData = [];
this.setState({
refreshing: true,
});
const param = { pageIndex: 1, pageSize: 10, listTitile: '美食' };
this.props.dispatch({ type: 'list/fetchonRefresh', payload: param });
};
我的意思是settimeout 只是模拟ajax数据返回,但是在实际情况中,我这边的情况是,只有当有请求返回的时候才去执行 this.setState({refreshing: false, });
但是实际情况是但我请求返回是,我去执行 this.setState({refreshing: false, });的时候,RefreshControl 的refreshing的状态还是true,并没有修改成false

@xoptimal
Copy link

xoptimal commented Apr 5, 2017

@warmhug 参考最新 commit ~ 仍然有不解的地方, 还请指教 !

场景: ListView 列表 -> 滑动到底部 -> 加载更多 -> 触发 onEndReached 关键代码:

onEndReached = (event) => {
    if (event && this.props.loadMore) {
      const {isLoadMore, loadMore} = this.props.loadMore;
      if (isLoadMore) {
        if (!this.state.isLoading) {
          this.setState({isLoading: true, loadMoreValue: '加载中...'});
          loadMore(this.onLoadMoreCallback.bind(this));
        }
      } else {
        this.setState({loadMoreValue: '加载完毕'});
      }
    }
  }

说明:

  • 判断条件有三个( 是否使用加载更多, 是否正在加载, 是否还有更多) ...
  • 在测试网络断开的情况下, 就出现了 onEndReached 被触发多次的问题 ~

网络请求关键代码 (dva -> fetch):

try {
  const result = yield call(FindService.requestCommodity, {page: tempPage});

  yield put({
    type   : 'saveFindList',
    payload: {
      list     : result.list,
      pageCount: result.pageCount,
      page     : tempPage,
      hasLoadMore
    }
  });
  yield callback(SUCCESS);
} catch (err) {
  yield callback(FAILED);
}

回调处理关键代码:

  onLoadMoreCallback(state) {
    const stateValue = state == 1 ? '加载中' : state == 2 ? '没有更多' : state == 3 ? '加载失败' : '加载更多';
    this.setState({isLoading: false, loadMoreValue: stateValue});
  }

问题:
网络异常, 直接抛Error , 走 callback , 导致 isLoading 为 true, 然后 onEndReached 自动被触发, 而且触发多次

期待结果:
请问如何让它只触发一次 ~

@warmhug
Copy link
Contributor

warmhug commented Apr 6, 2017

@xoptimal 网络异常 回调里,能把 isLoading、loadMore 这些都设为 false 吗?

@xoptimal
Copy link

xoptimal commented Apr 7, 2017

@warmhug 每次请求结果, 都会判断是否还有加载更多, 以及设置isLoading 为false , 我目前的做法是为了避免多次请求, 在请求结果上, 做了个延迟的处理, 是失败的情况下, 需要过5秒才可重新请求, 但是这个用户体验感觉并不好 .... 后续的5秒用户只能等待 ~

@liuming0712
Copy link

尝试把每页的条数增大一些,请求的数据填充的页面高度少于设定容器的高度会自动触发onEndReached事件

@szqiuboshi
Copy link

请问这个问题解决了没

@ylquankai
Copy link

+1

@warmhug
Copy link
Contributor

warmhug commented Jul 17, 2017

@leonardgithub this is not a bug, it's Normal behavior.

@leonardgithub
Copy link
Author

Not a bug? But why so many users encounter this problem?

@leonardgithub
Copy link
Author

leonardgithub commented Jul 17, 2017

My issue was referred by other user, I am not the only user which encounter the problem, please check the 6th point on https://github.com/TerryBeanX2/Webpack-React-Router-Redux-ES6#几点心得

@leonardgithub
Copy link
Author

If such a problems exists, can the antd-mobile's ListView be used in the production environment?

@Jude214
Copy link

Jude214 commented Jul 27, 2017

使用以下代码似乎能解决不断请求的问题

//hide the toast in a short time delay,otherwise loading toast won't be shown if hidden immediately
hideLoading = (msg) => {
       setTimeout(()=>{ 
             Toast.hide();
             if (msg) {
                  Toast.info(msg, 1.5);
			}
		}, 1000);
	};
	setNoLoading = (msg) => {
		this.hideLoading(msg);
		setTimeout(()=>{
			this.setState({isLoading: false});
		},3000);
	};
	onReachEnd = (e) => {
		console.log('上拉',this.state.isLoading);
		if (this.state.isLoading) {
			return
		}
		if (!this.hasMore) {
			Toast.info('无更多数据', 1.5);
			return;
		}
		this.setState({isLoading: true});
		let last = this.recordData[this.recordData.length - 1];
		if (last && last.time) {
			Toast.loading('加载中', 10);
			Service.traceList('0', last.time).then((response) => {
				if (response.code == 1) {
					this.setNoLoading();
					this.hasMore = response.hasMore || false;
					let newL = response.info || [];
					this.recordData = this.recordData.concat(newL);
					this.setState({
						dataSource: this.state.dataSource.cloneWithRows(this.recordData)
					});
				} else {
					this.setNoLoading(response.msg);
				}
			}, (error) => {
				this.setNoLoading();
			});
		}
	};

@xsf0105
Copy link

xsf0105 commented Sep 9, 2017

is there anyone who solve this problem?

@warmhug
Copy link
Contributor

warmhug commented Sep 11, 2017

In antd-mobile@2.0 , you can use PullToRefersh and react-infinite or your custom infinite-scroll.
@paranoidjk will add them soon.


Irrelevant comments have been deleted.

@ant-design ant-design deleted a comment from afc163 Sep 12, 2017
@ant-design ant-design deleted a comment from leonardgithub Sep 12, 2017
@ant-design ant-design deleted a comment from leonardgithub Sep 12, 2017
@ant-design ant-design deleted a comment from leonardgithub Sep 12, 2017
@ant-design ant-design deleted a comment from leonardgithub Sep 12, 2017
@ant-design ant-design deleted a comment from se1phine Sep 12, 2017
@ant-design ant-design deleted a comment from GZWZC Sep 12, 2017
@ant-design ant-design deleted a comment from GZWZC Sep 12, 2017
@ant-design ant-design deleted a comment from leonardgithub Sep 12, 2017
@ant-design ant-design deleted a comment from leonardgithub Sep 12, 2017
@ant-design ant-design deleted a comment from GZWZC Sep 12, 2017
@ant-design ant-design deleted a comment from leonardgithub Sep 12, 2017
@camnpr
Copy link

camnpr commented Sep 15, 2017

关于onEndReached 我的处理是:
onEndReached = (event) => { // load new data // hasMore: from backend data, indicates whether it is the last page, here is false // 没有任何在加载的状态, event对象不会空, 数据集大于等于每页的个数, 没有更多记录 if (this.state.isLoading || !event || dataList.length<10 || !this.state.hasMore) { return; } this.setState({ isLoading: true }); this.fetchData('Home/Search', {action:'quanziList', pageNo: ++pageIndex, uid:this.state.uid, type:this.state.type}); }
测试滑动加载,不会重复请求多次。
你的接口数据,要返回总数,以在componentWillReceiveProps里来更新hasMore。
例子地址:https://www.kuabaobao.com/quanzi
关于:cloneWithRowsAndSections 弄数据,有点怪怪的。
参考说明:https://github.com/ant-design/ant-design-mobile/blob/master/components/list-view/index.zh-CN.md
也许这个RefreshControl和ListView终要被PullToRefersh和react-infinite代替。

@Tsionhe
Copy link

Tsionhe commented May 7, 2018

监测滚动的距离

onScroll = (event) => {
   if(this.state.isLoading) {
      this.state.scrollTop = event.target.scrollTop
    }
}

页面渲染完执行滚动到原位置

this.lv.scrollTo(0, this.state.scrollTop)

@yibingxiong
Copy link

It's too hard!(我太难了)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests