灵异组件
众所周知,列表是移动开发中非常常用的组件(控件)。原生的列表,拿iOS来来说,有UITableView & UICollectionview,就算是长列表的情况也只是加载速度慢,不会出现突然不再加载的情况,Android的应该也是这种情况。但是React-Native中提供的列表就会出现突然不再加载的情况,严格来说是列表的item不再渲染了,因为查看数据,发现列表的数据的数据是正确的。React-Native提供给开发者的列表组件有三种, FlatList
, SectionList
,ListView
,目前的使用情况来看,FlatList
& SectionList
都会出现这种灵异事件。
使用场景
国家手机号代码列表
由于项目的需要,目前的App需要提供一个全球的手机号代码列表,供用户注册的时候,选择自己国家的手机号代码。列表见下图:
这个列表的数据一共是242条,由于需要排序分组并且给用户提供索引,所以采用sectionList来实现该页面。页面刚完成的时候,效果还算可以,除了快速滑动的时候会出现白屏,索引的跳转不是很准确(我从网上查了一下,那两个是React-native本省的问题),算是完成任务,就提交给策划,然后进行新功能的开发。
实现代码如下:
render(){ return (); } _renderItem = (info: any) => { return ( this.sectionList=el} initialNumToRender={20} showsVerticalScrollIndicator={true} // onEndReachedThreshold={0.1} // onEndReached={()=> this.loadMoreData(false)} sections={this.state.totalSections} renderItem={this._renderItem} getItemLayout={this._getItemLayout} keyExtractor={(item: Item, index: number)=> index.toString()} extraData={this.state} renderSectionHeader={this._renderSectionHeader} ItemSeparatorComponent={()=> }> ); } _getItemLayout = (data:any, index:number) => { const itemHeight = 40; return { length: itemHeight, offset: (itemHeight + 0) * index, index, }; } _renderSectionHeader = (info: any) => { let txt = info.section.key; return {txt} } itemSelected(item: Item){ console.log('the current item is===='+JSON.stringify(item)); const result = item.countryCode + ' ' + item.phoneCode; if(this.props.updatePhoneCode){ this.props.updatePhoneCode(result, item.phoneCode); this.props.navigator.pop(); } } onSideBarSelected(letter:string){ let sections: sectionData[] = this.state.totalSections; if (sections) { for (let index = 0; index < sections.length; index++) { let item = sections[index]; if (item.key === letter) { console.log('the current index i ==' + index); this.sectionList.scrollToLocation({animated: true, itemIndex: 0, sectionIndex: index, viewPosition: 0.0}); break; } } } }
好友列表
好友列表,好友列表的效果和上面一样,也是需要分组和索引,由于好友列表开发的比较早,我是采用的FlatList
实现的功能。
代码如下:
renderSuccessView(){ return (); } _renderItem = (item:any) => { console.log('the current item-->' + JSON.stringify(item)+" key: "+ item.item.key); return ( this.list = el} data={this.state.listData} extraData={this.state} keyExtractor={(item: any, index: number)=> index.toString()} renderItem={this._renderItem} getItemLayout={this._getItemLayout} ListEmptyComponent={this.renderEmptyView} ItemSeparatorComponent={this.itemSeparator} initialNumToRender={20} //onEndReachedThreshold={0.8} //legacyImplementation={this.state.listData.length > 0} showsVerticalScrollIndicator={true} /> ); }
好友列表刚开始做的时候bug比较多,经过几次修改,修复了出现的那些bug,效果也打到达了策划的要求。本以为任务完成了,还算完美。但是在接下来的反复测试中,灵异事件出现了。
灵异事件
在测试的过程中,出现了好友列表只加载10条的情况,10是initialNumToRender
设置第一屏渲染的数据条数。而且很奇怪,好友列表第一个固定的分组是好友的申请记录,其余的显示已经是好友的数据,按拼音的首字母进行分组排序。好友申请记录的显示逻辑是一开始最多显示5条,点击展开按钮,在全部显示出来。
好友列表的灵异事件刚开始发现的时候,好友申请记录显示了5条,已经是好友的数据显示了5条,当点击了申请记录的展开按钮,申请记录是6条,已经是好友的数据就少了最后一条,变成了4条,但是把申请收齐,好友数据又成了5条了。
刚开始以为是之前的bug没有改彻底,之前因为因为有key重复的情况,出现了数据缺少的情况,经过反复review代码,发现不是那个bug。反复进入好友列表,发现只渲染10条的灵异事件,低端机上比较容易出现,比如iphone5S,Android的低端机上也比较容易出现,高端机上出现的频率很低。
于是去测试国家编码列表,那个列表一共是242条数据,也是右边有分组索引,也出现了同样的问题。
而且出现的时候列表的可滑动区域变得很大,打印数据源,发现数据源是正常的,只是屏幕上只渲染了initialNumToRender设置的条数,就算你设置了2,也只显示2条,设置一个很大的值,也能渲染,就是渲染慢,要等待,数据条数越多,时间越长。
网上查了很多资料,尝试了很多解决办法。
- 1.分页加载数据。
- 2.列表的Item继承PureComponent。
- 3.使用ListView替代。
分页加载
分页加载是网上查找到的,说是FlatList
& SectionList
提供了分页加载的触发方法,当一屏数据快要滑动到底部的时候,触发一个方法,可以再去加载另外一部分数据。于是乎赶紧实现了一把,数据也是分页加载的,经过反复测试,发现分页加载的情况下,也会出现不再渲染的情况。而且因为列表右边有索引,分页加载其实也不能满足需求,本想着分页加载能够解决灵异事件,去和策划沟通一下,索引的功能稍微改一改,结果发现分页加载的思路也行不通。
item继承PureComponent
网上查到一份资料,有人说是把列表的item的直接继承PureComponent
(之前继承的是React.Component
),于是满怀希望赶紧把item重新改写了一下,最后发现然并卵,那个灵异效果依旧会出现。
使用ListView替代
使用ListView
替代,查了一下关芳芳文档,说是ListView
本身的性能不好,才重新封装了
FlatList
& SectionList
来替代它。用ListView
替代以后,列表能够完全渲染了,就是有点慢,而且官方文档说ListView
在超出屏幕之外,并没有做回收,数据量打了,终究是个隐患。内存暴涨,滑动卡顿。 其实在测试的过程中,发现如果直接把 列表的initialNumToRender设置成列表数据的长度,也能暂时解决问题,但是数据量大了,加载会很慢。拿国家编码列表来举例,242条数据,大概需要卡住5s左右,随着数据量的增大,效果可想而知,好友列表的数据容纳量目标是1500条,瞬间就泪崩了。
总结
目前来说,经过网上查询资料,自己尝试,都木有彻底解决React-Native列表的灵异问题,目前的解决方案,只是暂时性,数据量大了,问题会很明显,希望遇到过同样问题的同学,能够一起讨论解决,共同成长,或者有解决方案,麻烦告知一声,谢谢了。