当 numColumns > 1 时防止 FlatList 重新渲染

Prevent FlatList from re renders when numColumns > 1

我在一个react native项目中使用FlatList来显示一个图片网格视图,代表一个上传队列。

<FlatList
  extraData={this.state.images}
  data={this.state.images}
  renderItem={this.renderItem}
  keyExtractor={image => {
   return image.id;
  }}
/>



renderItem = ({item, index}) => {

    return (
      <TouchableOpacity
        id={item.id}
        delayLongPress={500}
        //onLongPress={() => this.props.onLongPressImage(item)}
      >
        <SingleImage
          onFinishUpload={this.props.onFinishUpload}
          index={index}
          item={item}
          title={this.props.title}
        />
      </TouchableOpacity>
    );
};

每次添加或删除图像时,只要我设置 numColumns > 1,就会重新渲染其他图像,并触发 SingeImage class 的 componendDidMount。

这是个问题,因为我在 componendDidMount() 中开始上传特定图像,每次上传成功时,图像都会从 FlatList 中删除。 所有其他正在上传的图像都重新安装并重新开始它们的上传过程。

如果我只显示一行且未设置 numColumns,则列表的每个元素只呈现一次并且一切正常。

我是否遗漏了什么或者我如何防止列表重新呈现数据数组被修改的每个项目?

First, it's important to keep in mind difference between re-render and remount. It's perfectly fine components (SingleImage in your case) to re-render, but NOT fine for them to remount because in that case components are destroyed and re-created and, of course, lose state

Now to the point: FlatList extends VirtualizedList

Virtualization massively improves memory consumption and performance of large lists by maintaining a finite render window of active items and replacing all items outside of the render window with appropriately sized blank space

In a nutshell, FlatList does not instantiate and keep alive all the instances of component you create to render. Imagine a list with 10000 items, it will NOT create 10000 instances of SingleImage and keep them alive. Instead, it will create only a few of them (usually as many as fit on the screen) and, as you scroll, the result of a previous render will be discarded and these "slots" will be reused for items with other data. This is the essence of virtualization, which allows displaying of infinitely large lists by drawing only a small portion of data

"Drawing" is the key here (that's why the prop is called renderItem, not Item). It will just draw something on the "slot" and forget about it. This is the reason you can't render stateful components in FlatList's renderItem. Internal state of these items is not preserved on re-renders

The correct way to do this would be handling image uploading outside of FlatList and only using FlatList to draw the UI with stateless components. As a cheaper alternative, if you really want to keep logic and presentation inside one SingleImage component, you can use this.state.images.map instead of FlatList (like you would do it in React web) to make sure all items are rendered at the same time and preserve their identity across re-renders

The reason why it doesn't bug out without numColumns prop set is, I suppose, due to the fact that numColumns triggers some additional re-renders, but having additional re-renders is perfectly fine and is not a root of a problem. Basically, without numColumns you are just getting lucky because there isn't enough of items in the list for virtualization to take place. If you added some more items, you would observe the same effect even without numColumns