React Native - FlatLists重新渲染记忆组件.备忘录不起作用)



主要问题

My FlatList忽略子组件的记忆。

我已经实现了一个自定义组件"Grid",它只是呈现给定的数据在一个FlatList与网格布局。

代码如下:

export default function Grid({
data = [],
keyExtractor,
numColumns = 4,
initialNumToRender,
renderItem,
itemMargin = StyleSheet.hairlineWidth,
isLoading,
onEndReachedThreshold = 0.5,
onEndReached,
...props
}) {
const renderGridItem = (item) => {
const { index } = item;
const { width } = Dimensions.get("window");
const size = Math.floor(
PixelRatio.roundToNearestPixel(
(width - itemMargin * (numColumns - 1)) / numColumns
)
);
// We don't want to include a `marginLeft` on the first item of a row
const marginLeft = index % numColumns === 0 ? 0 : itemMargin;
// We don't want to include a `marginTop` on the first row of the grid
const marginTop = index < numColumns ? 0 : itemMargin;
return renderItem({
...item,
size,
marginLeft,
marginTop,
});
};
const renderFooter = () => {
if (!isLoading) return null;
return (
<View style={globalStyles.listFooter}>
<Loading />
</View>
);
};
return (
<FlatList
{...props}
data={data}
keyExtractor={keyExtractor}
numColumns={numColumns}
initialNumToRender={initialNumToRender}
renderItem={renderGridItem}
ListFooterComponent={renderFooter}
onEndReachedThreshold={onEndReachedThreshold}
onEndReached={onEndReached}
style={globalStyles.listContainer}
contentContainerStyle={globalStyles.listContainer}
/>
);
}

另外,我有一个顶层组件,它只是渲染我的记忆组件,使用自定义renderItem函数:

export default function UserPostsGrid({
listKey,
data = [],
numColumns,
initialNumToRender,
itemMargin,
isLoading,
ListEmptyComponent,
onEndReached,
...props
}) {
const keyExtractor = useCallback(({ id }) => id, []);
const renderItem = useCallback(
({ item, index, size, marginLeft, marginTop }) => {
const style = {
width: size,
height: size,
marginLeft,
marginTop,
};
return <UserPostsGridItem item={item} index={index} style={style} />;
},
[]
);
return (
<Grid
{...props}
listKey={listKey}
data={data}
keyExtractor={keyExtractor}
numColumns={numColumns}
renderItem={renderItem}
initialNumToRender={initialNumToRender}
isLoading={isLoading}
removeClippedSubviews={false}
ListEmptyComponent={ListEmptyComponent}
itemMargin={itemMargin}
onEndReachedThreshold={0.5}
onEndReached={onEndReached}
/>
);
}

问题是,由于某种原因,我记忆的组件从renderItem函数返回,当数据道具改变时,神奇地重新渲染。

例如,如果我向当前数据列表添加一个新元素,FlatList将重新呈现它的所有项。

这是我记忆的组件:

function UserPostsGridItem({
item: {
index,
images: [{ uri, thumbnailUri }],
},
style,
}) {
const handleOnPress = () => {
// TODO - Push card lists stack
console.log(index);
};
console.log("Rerendering grid item!", uri);
return (
<TouchableOpacity activeOpacity={0.5} onPress={handleOnPress} style={style}>
<Image
uri={uri}
thumbnailUri={thumbnailUri}
imageFadeDuration={200}
thumbnailFadeDuration={100}
withLoading={false}
style={globalStyles.flexContainer}
/>
</TouchableOpacity>
);
}
function areUserPostsGridItemPropsEqual() {
console.log("Running areEqual"); // <---- NOTE THIS!
return true;
}
export default memo(UserPostsGridItem, areUserPostsGridItemPropsEqual);
如你所见,我的areEqual方法返回true,所以我认为错误是在父组件(网格或UserPostsGrid)之一。

你知道我做错了什么吗?

注意

修改data prop(父节点中的状态)之后
data=[{id: "1", ...}]

data=[{id: "2", ...}, {id: "1", ...}]

我在控制台上得到这个:

"Rerendering grid item! uri..."
"Rerendering grid item! uri..."

= =函数没有被执行!!!!!!

好了,问题出在numColumns>1 .

由于虚拟化,我的组件被重新挂载,不重新渲染。