我有一个包含大约 14k 个节点的树/目录结构化数据。
我想阻止树的所有子项重新渲染,因为它需要太长时间。单击按钮时可以扩展和最小化节点,这会将节点的 id 添加到保存在 Redux 状态中的 expanded
Set
。目前,当向 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;
};
但这并不能阻止其他孩子重新渲染。
感谢任何帮助或提示!
答案 0 :(得分:0)
我无法在不改变树结构的情况下阻止重新渲染。我已将树展平为一个列表,并确保 TreeTableBranch
像这样使用 React.memo:export default React.memo(TreeTableBranch);
正如@Sam 提到的那样,没有添加比较函数及其父级。我还删除了@glinda93 建议的传递 onExpand
、onAddCategory
和 onDeleteCategory
函数道具,尽管我不能 100% 确定这是否修复了它。
最后,我意识到大树的初始渲染仍然需要很长时间,所以有了这种扁平化的结构,使用 react-window
来虚拟化列表要容易得多。