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

如何避免嵌套map以提升React分组列表渲染性能

React分组列表渲染性能优化方案

问题核心原因

首先明确性能问题的两个核心诱因:

  1. 每次组件重渲染时都会重复执行分组计算、嵌套遍历生成JSX的逻辑,无任何缓存机制,你在return中直接调用渲染函数确实是性能下降的核心原因之一——只要组件触发重渲染,即使itemSet没有任何变化,分组、遍历逻辑都会完整执行一遍。
  2. 分组层级的React.Fragment没有添加唯一key,且你使用了小写开头的<group>、<item>组件(React会将小写开头的标签识别为原生HTML标签,无法正确做组件diff优化),导致React无法复用已有DOM节点,只能全量销毁重建。

优化方案(含消除嵌套映射的实现)

方案1:保留嵌套逻辑但做全链路缓存(改造成本最低)

嵌套map本身不是性能问题,不合理的无缓存重复计算才是,不需要完全消除嵌套,优化点如下:

  • 用useMemo缓存分组结果,仅当itemSet变化时才重新计算分组
  • 给分组层级添加唯一key
  • 修正组件名大写规范,子组件用React.memo包裹避免不必要重渲染
  • 缓存渲染结果,避免每次重渲染重复生成JSX

优化后代码示例:

import { useMemo } from 'react';

// 组件名必须大写开头,建议用React.memo包裹
const Group = React.memo(({ name }) => <div>{name}</div>);
const Item = React.memo(({ id, item }) => <div key={id}>{item}</div>);

// 业务组件内逻辑
const YourComponent = () => {
  const itemSet = [
    { id: 1, group: 'A', item : 'someitem' },
    { id: 2, group: 'A',  item : 'someitem' },
    { id: 3, group: 'B',  item : 'someitem' },
    { id: 4, group: 'B', item : 'someitem' },
  ];

  // 缓存分组结果,仅itemSet变化时重新计算
  const groupedItems = useMemo(() => {
    return itemSet.reduce((group, item) => {
      if (!group[item.group]) {
        group[item.group] = [];
      }
      group[item.group].push(item);
      return group;
    }, {});
  }, [itemSet]);

  // 缓存渲染的JSX,仅groupedItems变化时重新生成
  const renderList = useMemo(() => {
    return Object.entries(groupedItems).map(([group, items]) => (
      // 分组层级必须加唯一key
      <React.Fragment key={group}>
        <Group name={group} />
        {items.map((item) => (
          <Item
            key={item.id}
            id={item.id}
            item={item.item}
          />
        ))}
      </React.Fragment>
    ));
  }, [groupedItems]);

  return (
    <MuiThemeProvider theme={themeDark}>
      <AppBar />
      <CssBaseline />
      {renderList}
    </MuiThemeProvider>
  );
};

方案2:完全消除嵌套map的实现

如果需要彻底去掉嵌套遍历,可以提前对原始数据做预处理,给每个项插入分组标记,仅用一层map完成渲染:

// 预处理数据,生成带分组标记的展平列表
const flattedItems = useMemo(() => {
  const sorted = [...itemSet].sort((a, b) => a.group.localeCompare(b.group));
  const result = [];
  let lastGroup = null;
  sorted.forEach(item => {
    if (item.group !== lastGroup) {
      // 插入分组头标记项
      result.push({ type: 'group', id: `group_${item.group}`, name: item.group });
      lastGroup = item.group;
    }
    result.push({ type: 'item', ...item });
  });
  return result;
}, [itemSet]);

// 仅一层map完成渲染,无嵌套
const renderList = useMemo(() => {
  return flattedItems.map(item => {
    if (item.type === 'group') {
      return <Group key={item.id} name={item.name} />;
    }
    return <Item key={item.id} id={item.id} item={item.item} />;
  });
}, [flattedItems]);

这个方案可以完全消除嵌套映射,渲染效率和单层遍历一致。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 03:18:05