滚动列表时反应本机 VirtualizedList 重新渲染
Posted
技术标签:
【中文标题】滚动列表时反应本机 VirtualizedList 重新渲染【英文标题】:React native VirtualizedList Re-render while scroll the list 【发布时间】:2022-01-13 08:57:05 【问题描述】:我的虚拟化列表初始渲染记录最多 30 条,同时渲染数据列表自动重新渲染 2 到 4 次,并且新数据添加到列表中
在多次渲染时,我们无法执行任何操作,例如触摸或导航到另一个屏幕
我的代码
class HomeDetails extends PureComponent
constructor(props)
super(props);
this.cellRefs = ;
this.flatListRef = React.createRef();
getItem = (data, index) =>
if (index in data)
return
key: `$data[index].id - $index`,
id: data[index].id,
accountId: data[index].accountId,
displayName: data[index].displayName,
fullName: data[index].fullName,
;
;
keyExtractor(item, index)
return `$item.id - $index`;
getItemCount = data =>
return data.length;
;
_renderItem =(item,index) =>
console.log(
'Rerendring',
item.accountId,
moment().format('MM/DD/YY hh:mm:ss a'),
);
return (
<View key=index style=height: 50, flexDirection: 'row'>
<Text>`$item.accountId $moment().format(
'MM/DD/YY hh:mm:ss a',
)`</Text>
</View>
);
render()
return (
<VirtualizedList
onScroll=this.onScrollHandler
onViewableItemsChanged=this._onViewableItemsChanged
viewabilityConfig=viewabilityConfig
scrollEventThrottle=16
ref=this.flatListRef
horizontal=false
decelerationRate="normal"
showsHorizontalScrollIndicator=false
showsVerticalScrollIndicator=false
data=this.props.responseRecord
pagingEnabled=true
scrollToOverflowEnabled=false
renderItem=this._renderItem
keyExtractor=this.keyExtractor
getItemCount=this.getItemCount
getItem=this.getItem
windowSize=21
progressViewOffset=20
initialNumToRender=15
maxToRenderPerBatch=15
updateCellsBatchingPeriod=100
onEndReached=val =>
return this.props.getExtraData(2, 1);
onEndReachedThreshold=0.1
refreshing=this.props.postLoading
extraData=this.props.refreshData
disableIntervalMomentum=false
removeClippedSubviews=true
onRefresh=() =>
return this.props.getExtraData(1, 1);
ItemSeparator=this.ItemSeparator
ListFooterComponent=this.renderFooter
/>
)
const mapStateToProps = (post, auth, common) =>
const
responseRecord,
postLoading,
refreshData,
= post;
return
responseRecord,
postLoading,
refreshData,
;
;
const mapDispatchToProps =
getExtraData,
;
export default connect(mapStateToProps, mapDispatchToProps)(HomeDetails);
.................................................. ....................
1.对于最初的 30 条记录,其重新渲染超过 2 次 2.当添加更多记录时,其重新渲染超过 4 到 6 次 3.用purecomponent试过,但没有运气
在小吃中部署的代码 https://snack.expo.dev/@pandianvpsm/cd5737
【问题讨论】:
【参考方案1】:在内部,React 的 PureComponent 实现了 shouldComponentUpdate
方法,并将之前的 props 值与新的 props 或 state 值进行比较,以避免不必要的重新渲染。
这适用于 numbers
、strings
和 booleans
等基本类型值。
对于引用类型值(objects
和 arrays
),这种比较并不总是准确的。这就是你的行为。 this.props.responseRecord
是一个对象数组(引用类型)。
我们可以通过实现我们自己的componentShouldUpdate
方法来解决这个问题,如下所示:
/** Trigger component rerender only new elements added */
shouldComponentUpdate(nextProps, nextState)
return this.props.responseRecord.length !== nextProps.responseRecord.length
完整代码如下
class HomeDetails extends React.Component
constructor(props)
super(props);
this.cellRefs = ;
this.flatListRef = React.createRef();
/** Trigger component rerender only new elements added */
shouldComponentUpdate(nextProps, nextState)
return this.props.responseRecord.length !== nextProps.responseRecord;
getItem = (data, index) =>
if (index in data)
return
key: `$data[index].id - $index`,
id: data[index].id,
accountId: data[index].accountId,
displayName: data[index].displayName,
fullName: data[index].fullName,
;
;
keyExtractor(item, index)
return `$item.id - $index`;
getItemCount = (data) =>
return data.length;
;
_renderItem = ( item, index ) =>
console.log(
"Rerendring",
item.accountId,
moment().format("MM/DD/YY hh:mm:ss a")
);
return (
<View key=index style= height: 50, flexDirection: "row" >
<Text>`$item.accountId $moment().format(
"MM/DD/YY hh:mm:ss a"
)`</Text>
</View>
);
;
render()
return (
<VirtualizedList
onScroll=this.onScrollHandler
onViewableItemsChanged=this._onViewableItemsChanged
viewabilityConfig=viewabilityConfig
scrollEventThrottle=16
ref=this.flatListRef
horizontal=false
decelerationRate="normal"
showsHorizontalScrollIndicator=false
showsVerticalScrollIndicator=false
data=this.props.responseRecord
pagingEnabled=true
scrollToOverflowEnabled=false
renderItem=this._renderItem
keyExtractor=this.keyExtractor
getItemCount=this.getItemCount
getItem=this.getItem
windowSize=21
progressViewOffset=20
initialNumToRender=15
maxToRenderPerBatch=15
updateCellsBatchingPeriod=100
onEndReached=(val) =>
return this.props.getExtraData(2, 1);
onEndReachedThreshold=0.1
refreshing=this.props.postLoading
extraData=this.props.refreshData
disableIntervalMomentum=false
removeClippedSubviews=true
onRefresh=() =>
return this.props.getExtraData(1, 1);
ItemSeparator=this.ItemSeparator
ListFooterComponent=this.renderFooter
/>
);
const mapStateToProps = ( post, auth, common ) =>
const responseRecord, postLoading, refreshData = post;
return
responseRecord,
postLoading,
refreshData,
;
;
const mapDispatchToProps =
getExtraData,
;
export default connect(mapStateToProps, mapDispatchToProps)(HomeDetails);
【讨论】:
感谢您的回复,但仍然出现连续渲染,我不知道如何解决这个问题,请任何人帮助我以上是关于滚动列表时反应本机 VirtualizedList 重新渲染的主要内容,如果未能解决你的问题,请参考以下文章