问题如图:
当数据量大的时候(涉及几千条数据),当加载下一页快速滑动到底部的时候,出现白屏及反应速率慢,当滑动到几十页的时候,加载一次页面的时间需要2~3秒,这对使用者来说是不可以接受的。而且在每一列的元素上,有多种点击事件,点击可以弹框查看内部详情。
具体分析代码下来,把涉及flatlist的代码从头到尾重写下来。发现了如下几个问题:
1、renderItem
这是最主要的问题,如果flatlist出现加载效率差,速度慢,反应卡,首先检查你的renderItem。
flatlist在官方教程中两个required项,一个是data,数组,另一个就是renderItem。
我一开始是这样写的:
const renderItem = ({item}) => {
const renderList = [
{
fieldName: item.name || '无',
textStyle: {color: '#409EFF', textAlign: 'center'},
itemStyle: { flexDirection: 'column' },
pressFun: () => callPhone(item)
},
{
fieldName: item.companyShortName,
textStyle: {fontSize: 26},
pressFun: () => pressFactory(item)
},
{
fieldName: status,
textStyle: {fontSize: 26},
pressFun: () => showTwoCard(item)
},
{
fieldName: 'press',
textStyle: {color: '#409EFF'},
pressFun: gotoRecordOfWorking
},
{
fieldName: MEMBERS_STATUS[item.status],
textStyle: {fontSize: 26},
pressFun: () => changeStatus(item)
},
{
fieldName: 'press' ,
textStyle: {color: '#409EFF'},
pressFun: () => pressName(item)
};
return(<View>{renderList.map(list => (...))}</View>)
];
因为多个页面的大致结构都是如此,我便想着使用数组便利新创建的数组并且渲染出来。一开始数据量小的时候这样写没有问题,但当数据量大的时候。就会导致在渲染每一条数据的过程中,每条数据都会创建一个数组,数组里面每一项还有个函数与外部作用域的点击函数相联系,当渲染到1000条数据的时候,意味着一次要创建1000*数组长度的渲染量,就会导致渲染性能的不足。
所以,renderItem里面的结构要尽可能的减少赋值变量,尽可能减少外部应用,也就是直接return(
<></>)标签结构,这样就不会导致在加载大量数据的时候(我是一次20条数据)计算量过大导致cpu及内存的大量占用。
2、getItemLayout
这一点也是我没想到的地方,当我解决完上面的问题后,发现快速滑动时加载的速度有了很大改善,但还是出现白屏的现象。我就开始考虑是不是涉及列表的布局结构跟不上渲染的速度,最后发现确实是这个问题。我设置的一个renderitem的高度是80dp,但是getItemLayout这个属性我设置的ITEM_HEIGHT却是90,这样就会导致在渲染的过程中他flatlist给我预留的初渲染高度是90*data.length,但实际渲染确实80*data.length。这样与实际item高度就对应不上,就出现了白屏的现象。所以第二点就是确认getItemLayout属性计算的高度与renderItem设置的高度是否一致。
getItemLayout={(data, index)=>({length: 90, offset: 90 * index, index})}
出现这个性能问题,因为我代码已经写好了,组件全都封装完成。结果在压力测试上大数据量的时候就出现了这个问题,一开始我百思不得其解,一度以为是RN的效率太差,使用了多种优化手段(useMemo,useCallback,类组件中的PureComponent,rn的问题在网上的解决方案少,且实时性差,都22年了都在用hooks了还一直看到几年前的类组件,很是烦恼啊。。)
后续才发现是代码写的不规范,并且由于代码量大,分析过程中也是困难重重,最后我只能从flatlist组件重新一点点构建起来。。。处理这个问题花了几个小时QAQ,磨人啊