You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为递归渲染的Material UI TreeView添加useCallback/useMemo做性能优化

Material UI TreeView 性能优化方案(基于useCallback/useMemo)

性能瓶颈说明

原有实现中renderTree函数会在组件每次重渲染时重新生成引用,递归渲染逻辑会导致所有TreeItem节点在父组件重渲时全部重新渲染,节点数量达到数百级时会出现明显卡顿、交互延迟问题。

核心优化步骤

  • 用React.memo封装独立的树节点组件,只有当节点属性发生变化时才会触发当前节点重渲染,阻断不必要的重渲染链路
  • 用useCallback缓存递归渲染函数,保证函数引用稳定,不会触发子组件的无效重渲染
  • 用useMemo缓存树结构数据源,避免数据源引用无意义变更导致的全量节点重渲染

优化后完整代码

import * as React from 'react';
import TreeView from '@mui/lab/TreeView';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import ChevronRightIcon from '@mui/icons-material/ChevronRight';
import TreeItem from '@mui/lab/TreeItem';

// 1. 用memo封装独立的树节点组件,浅比较props判断是否需要重渲
const MemoTreeItem = React.memo(({ node, renderTree }) => {
  return (
    <TreeItem nodeId={node.id} label={node.name}>
      {Array.isArray(node.children)
        ? node.children.map((child) => renderTree(child))
        : null}
    </TreeItem>
  );
});

// 固定的静态数据源可以直接放在组件外部,避免组件重渲时重复创建
const staticData = {
  id: 'root',
  name: 'Parent',
  children: [
    {
      id: '1',
      name: 'Child - 1',
    },
    {
      id: '3',
      name: 'Child - 3',
      children: [
        {
          id: '4',
          name: 'Child - 4',
        },
      ],
    },
  ],
};

export default function RichObjectTreeView() {
  // 2. 如果数据源是动态生成/接口返回的,用useMemo缓存固定引用
  const treeData = React.useMemo(() => {
    // 动态数据处理逻辑写在这里,比如格式化接口返回的节点数据
    return staticData;
  }, []); // 依赖项填会触发数据变更的变量,比如接口返回的原始数据

  // 3. 用useCallback缓存递归渲染函数,固定引用
  const renderTree = React.useCallback((node) => {
    return <MemoTreeItem key={node.id} node={node} renderTree={renderTree} />;
  }, []);

  return (
    <TreeView
      aria-label="rich object"
      defaultCollapseIcon={<ExpandMoreIcon />}
      defaultExpanded={['root']}
      defaultExpandIcon={<ChevronRightIcon />}
      sx={{ height: 110, flexGrow: 1, maxWidth: 400, overflowY: 'auto' }}
    >
      {renderTree(treeData)}
    </TreeView>
  );
}

额外优化建议

  • 节点的key必须使用稳定的唯一值(比如节点id),禁止使用数组索引作为key
  • 节点数量超过500时可以搭配虚拟滚动方案,仅渲染可视区域内的节点,进一步降低渲染性能消耗
  • 如果节点有复杂的自定义渲染内容,可以单独把渲染逻辑用useMemo缓存,避免每次重渲都重复生成DOM结构

内容的提问来源于stack exchange,提问作者Django

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 05:06:01