我在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设置为1,就会重新渲染其他图像,并触发SingeImage类的componendDidMount。
这是一个问题,因为我开始在componendDidMount()中上载特定图像,并且每次上载成功时,都会从FlatList中删除该图像。 重新上载所有其他图像,并重新开始其上载过程。
如果我只显示一行并且未设置numColumns,则列表中的每个元素仅呈现一次,并且一切正常。
我会错过什么吗?或者如何防止列表重新呈现修改数据数组的每个项目?
答案 0 :(得分:1)
首先,请务必牢记重新渲染和重新安装之间的区别。可以很好地重新渲染组件(在您的情况下,SingleImage
),但是重新安装它们并不好,因为在这种情况下,组件会被破坏并重新创建,当然会丢失状态
现在到了这一点:FlatList扩展了VirtualizedList
简而言之,FlatList不会实例化并使创建的要渲染的组件的所有实例保持活动状态。想象一个包含10000个项目的列表,它将不会创建10000个虚拟化通过维护活动项目的有限渲染窗口并用适当大小的空白空间替换渲染窗口之外的所有项目,大大提高了内存消耗和大型列表的性能
SingleImage
实例并使它们保持活动状态。取而代之的是,它将仅创建其中的一些(通常与屏幕上的显示一样多),并且在您滚动时,先前渲染的结果将被丢弃,并且这些“插槽”将重新用于包含其他数据的项目。这就是虚拟化的本质,它允许通过仅绘制一小部分数据来显示无限大的列表
此处的“绘图”是关键(这就是为什么将该道具称为renderItem
而不是Item
的原因)。它只会在“插槽”上画一些东西而忽略它。这就是您无法在FlatList的renderItem中渲染有状态组件的原因。这些项目的内部状态不会保留在重新渲染中
正确的方法是在FlatList之外处理图像上传,并且仅使用FlatList绘制具有无状态组件的UI。作为一种更便宜的选择,如果您真的想将逻辑和表示保留在一个SingleImage
组件中,则可以使用this.state.images.map
而不是FlatList(就像在React Web中那样)来确保所有项目都同时渲染并在重新渲染时保留其身份
我想,没有numColumns
道具集就不会出错的原因是,因为numColumns触发了一些其他的重新渲染,但是具有额外的重新渲染很好,这不是问题的根源。基本上,如果没有numColumns
,您会很幸运,因为列表中没有足够的项目可以进行虚拟化。如果再添加一些项目,即使没有numColumns