关于React Native中FlatList的onEndReached属性频繁调用的一种解决办法
FlatList组件是RN0.43后引入的组件。作为高性能列表组件,FlatList在ListView的基础上优化了加载性能并简化了渲染过程。不仅如此,该组件还提供了onRefresh和onEndReached属性,用来定义上拉和下拉的功能。然而笔者发现,当FlatList组件的父组件高度不为定值的时候,onEndReached属性调用会出现问题,List并未滑到底部就会被频繁触发,导致功能异常。通常我们会使用Flexbox弹性盒布局,不会给列表组件设置固定width和height值,因此出现这种问题很可能是FlatList不能够正确的判断是否到达容器底部。
1 <View style={{flex:1}}> 2 <FlatList data={this.props.data} 3 renderItem={({item})=>{ 4 return (<MyItem data={item} clickItem={()=>{ 5 this.props.getItem(item); 6 }}/>); 7 }} 8 onEndReached{()=>{ 9 this.props.loadMore(); 10 }}/> 11 </View>
这种情况下我们可以使用ScrollView的属性手动判断容器底部,因为当我们打开官方关于FlatList组件的介绍(https://facebook.github.io/react-native/docs/flatlist)时,我们发现它继承了ScrollView所有的属性。紧接着,我们找到onScroll和onContentSizeChange属性来代替原来的onEndReached和onEndReachedThreshold(IOS)属性。实现如下:
1 constructor(props){ 2 super(props); 3 this.state={ 4 loading:false 5 } 6 } 7 --------------------------以下属性添加到FlatList中-------------------------- 8 onScroll={(event)=>{ 9 let offsetY = event.nativeEvent.contentOffset.y; 10 let contentHeight = event.nativeEvent.contentSize.height; 11 let originHeight = event.nativeEvent.layoutMeasurement.height; 12 if(!this.state.loading){ 13 if(offsetY+originHeight+200>=contentHeight){ 14 this.setState({ 15 loading:true, 16 }); 17 this.props.loadMore(); 18 } 19 } 20 console.log(this.state.loading+","+offsetY); 21 }} 22 onContentSizeChange={(contentWidth, contentHeight)=>{ 23 if(this.state.loading){ 24 this.setState({ 25 loading:false, 26 }); 27 } 28 }}
其实现原理是
- 滑动时获取屏幕高度、FlatList已在竖轴滑动的数值,以及FlatList内容总高度,以此手动判断当前是否到达底部,到达后设置系统“loading”状态,发送载入请求
- 当载入请求发送后,会从网络api获取新数据并添加到FlatList中,从而激活onContentSizeChange中定义的函数,将“loading”状态释放。
ps:本解决方案未考虑数据获取失败情况,有需求可自行在onScroll中添加setTimeout进行延迟释放“loading”状态。