javascript - React Native - FlatLists re-renders memoized components (React.memo not working)
问题描述
Main Problem
My FlatList ignores the children components memoizations.
Explanation
I have implemented a custom Component "Grid", which just renders the given data in a FlatList with a Grid layout.
Here is the code:
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}
/>
);
}
Also, I have a top level component, which just renders my memoized component inside my custom Grid component, using a custom renderItem function:
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}
/>
);
}
The thing is, that for some reason, my memoized components which are returned from the renderItem function, are magically re-rendered when the data prop changes.
For example, if I add a new element to my current data list, the FlatList will re-render all of its items.
Here is my memoized component:
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);
As you can see, my areEqual method returns true, so I suppose the error is in one of the parent components (Grid or UserPostsGrid).
Any ideas about what am I doing wrong?
Note
After modifying the data prop (state in a parent) from
data=[{id: "1", ...}]
to
data=[{id: "2", ...}, {id: "1", ...}]
I get this in the console:
"Rerendering grid item! uri..."
"Rerendering grid item! uri..."
THE ARE EQUAL FUNCTION IS NOT BEING EXECUTED!!!!!!
解决方案
好的,问题在于 numColumns > 1。
由于虚拟化,我的组件正在重新安装,而不是重新渲染。
推荐阅读
- spring-mvc - 将列表对象从 thymeleaf 发送到控制器
- python-3.x - 从 CSV 文件中删除标题
- javascript - 如何使用 JavaScript 将文本从一个字段复制到另一个选项卡菜单的字段?
- php - 致命错误:在布尔值上调用成员函数 getData()
- python - ColumnTransformer 和 FeatureUnion 之间的 Scikit-Learn 管道代码差异
- android - android studio 导入 GreenDao 后无法解析 DaoMaster
- c++ - Valgrind 插入排序的大小为 8 的无效读取
- image - 更改图片时如何销毁缓存图像
- ios - 错误 ITMS-90730ITMS 无法在 Xcode 10.2.1 中上传 IPA
- bootstrap-4 - Bootstrap-4 脚本的最佳位置和脚本的标签