滚动列表时反应本机 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 值进行比较,以避免不必要的重新渲染。

这适用于 numbersstringsbooleans 等基本类型值。

对于引用类型值(objectsarrays),这种比较并不总是准确的。这就是你的行为。 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 重新渲染的主要内容,如果未能解决你的问题,请参考以下文章

反应本机列表页脚组件未显示(功能组件)

在本机反应中回调 scrollToLocation

当焦点文本输入反应本机时,滚动视图无法滚动

与成长中的孩子反应本机滚动视图

反应本机重新渲染导致视图滚动到顶部-我的键在渲染之间是不是发生变化?

当状态/道具改变时,反应原生动画部分列表跳到顶部