我有一个树/目录结构的数据,大约有14k个节点。我想防止树的所有子级重新渲染,因为它需要太长的时间。单击按钮时,可以展开和最小化节点,该按钮将节点的id添加到以Redux状态保存的expanded
Set
中。当前,将类别添加到"集"时,将重新渲染整个树。我该如何防止这种情况发生?
数据结构:
[
{
"id": "1",
"name": "Category 1",
"children": [
{
"id": "11",
"name": "Category 1-1",
"children": []
}
]
},
{
"id": "2",
"name": "Category 2",
"children": [
{
"id": "3",
"name": "Category 2-1",
"children": [
...children
]
}
]
}
... and so forth
]
我有一个递归TreeTableBranch
组件,它递归地呈现它的子级:
const TreeTableBranch: React.FC<Props> = ({
node,
level,
onExpand
}) => {
const expanded = useSelector((state: AppState) => state.categories.expanded);
const shouldExpand = expanded.has(node.category.id);
return (
...lots of divs for rendering a node
<button onClick={onExpand}>Expand<Button/>
{ shouldExpand &&
node.children.map((v,i) => (
<TreeTableBranch
key={v.category.id}
node={v}
level={level + 1}
onExpand={onExpand}
/>
)}
)
}
但是,由于expanded
列表已修改,所有子项都将重新渲染。我尝试使用useMemo()
如下:
const children = useMemo(() => {
return (
shouldExpand &&
node.children.map((v, i) => (
<TreeTableBranch
key={`category-branch-${v.category.id}`}
node={v}
level={level + 1}
onExpand={onExpand}
onAddCategory={onAddCategory}
onDeleteCategory={onDeleteCategory}
/>
))
);
}, [shouldExpand]);
但是,这不起作用,可能是因为expanded
列表已被修改。
我也试过这样使用React.memo()
:
const areEqual = (prevProps: Props, nextProps: Props) => {
return prevProps.shouldExpand === nextProps.shouldExpand;
};
但这并不能阻止其他孩子重新渲染。
任何帮助或提示都将不胜感激!
如果不更改树的结构,我无法阻止重新渲染。我已经将树扁平化为一个列表,并确保TreeTableBranch
使用React.memo,就像@Sam提到的那样:export default React.memo(TreeTableBranch);
没有添加compasion函数及其父函数。我还删除了@glinda93建议的传递onExpand
、onAddCategory
和onDeleteCategory
功能道具,尽管我不能100%确定这是否修复了它
最后,我意识到大型树的初始渲染仍然需要很长时间,因此使用这种扁平化的结构,使用react-window
虚拟化列表要容易得多。