React:防止重新渲染孩子的大树结构

时间:2021-07-20 15:43:14

标签: reactjs typescript react-redux react-hooks

我有一个包含大约 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;
};

但这并不能阻止其他孩子重新渲染。

感谢任何帮助或提示!

1 个答案:

答案 0 :(得分:0)

我无法在不改变树结构的情况下阻止重新渲染。我已将树展平为一个列表,并确保 TreeTableBranch 像这样使用 React.memo:export default React.memo(TreeTableBranch); 正如@Sam 提到的那样,没有添加比较函数及其父级。我还删除了@glinda93 建议的传递 onExpandonAddCategoryonDeleteCategory 函数道具,尽管我不能 100% 确定这是否修复了它。

最后,我意识到大树的初始渲染仍然需要很长时间,所以有了这种扁平化的结构,使用 react-window 来虚拟化列表要容易得多。

相关问题