【发布时间】:2021-12-04 08:57:57
【问题描述】:
主要问题
我的 FlatList 忽略了子组件的记忆。
说明
我已经实现了一个自定义组件“网格”,它只是将给定的数据呈现在具有网格布局的 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}
/>
);
}
另外,我有一个顶级组件,它只是在我的自定义 Grid 组件中呈现我的 memoized 组件,使用自定义 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 函数返回的记忆化组件在 data prop 更改时会神奇地重新渲染。
例如,如果我在当前数据列表中添加一个新元素,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,所以我认为错误出在父组件之一(Grid 或 UserPostsGrid)中。
关于我做错了什么有什么想法吗?
注意
从
修改数据道具(父级中的状态)后 data=[{id: "1", ...}]
到
data=[{id: "2", ...}, {id: "1", ...}]
我在控制台中得到了这个:
"Rerendering grid item! uri..."
"Rerendering grid item! uri..."
没有执行 ARE EQUAL 功能!!!!!!
【问题讨论】:
标签: javascript reactjs react-native memoization