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

React组件优化:选中项时仅重渲染目标子组件

React选中单个Item时所有组件重渲染的解决方案

问题根源

你的代码里有三个核心问题导致所有Item都触发重渲染:

  1. MemoizedItem定义位置错误:把MemoizedItem = memo(Item)放在了App组件内部,每次App状态更新(selected变化)都会重新创建这个组件,memo的缓存完全失效。
  2. 事件函数未缓存:selectHandler没有用useCallback缓存,每次App渲染都会生成新的函数实例,所有Item接收的selectHandler props都会变化,memo浅比较判定props更新,触发重渲染。
  3. props传递冗余:给每个Item传了整个selected数组,每次选中/取消操作都会生成新的数组引用,所有Item的selected props都发生变化,必然全部重渲染。

修复后的完整代码

import { memo, useState, useCallback } from "react";

const items = Array(100)
  .fill(null)
  .map((item, index) => {
    return { ...item, id: crypto.randomUUID(), name: `hello - ${index + 1}` };
  });

type PropsItem = {
  data: { id: string; name: string };
  isSelected: boolean;
  selectHandler: (isIncluded: boolean, id: string) => void;
};

const Item = ({ data, isSelected, selectHandler }: PropsItem) => {
  return (
    <div className="cursor-pointer min-w-[170px] text-center p-2">
      {isSelected ? (
        <s className="text-2xl" onClick={() => selectHandler(true, data.id)}>
          {data.name}
        </s>
      ) : (
        <p className="text-2xl" onClick={() => selectHandler(false, data.id)}>
          {data.name}
        </p>
      )}
    </div>
  );
};

// 把MemoizedItem移到组件外部,确保只创建一次
const MemoizedItem = memo(Item);

const App = () => {
  const [selected, setSelected] = useState<string[]>([]);

  // 用useCallback缓存事件函数,避免每次渲染生成新实例
  const selectHandler = useCallback((isIncluded: boolean, id: string) => {
    if (isIncluded) {
      setSelected(prev => prev.filter(idx => idx !== id));
    } else {
      setSelected(prev => [...prev, id]);
    }
  }, []); // 依赖为空,因为用了函数式更新,不需要依赖selected

  return (
    <div className="flex flex-col gap-5 items-center justify-center py-10">
      {items.map(item => (
        <MemoizedItem
          key={item.id}
          data={item}
          // 只传递当前Item的选中状态布尔值,而非整个数组
          isSelected={selected.includes(item.id)}
          selectHandler={selectHandler}
        />
      ))}
    </div>
  );
};

export default App;

关键修复点说明

  • MemoizedItem移到外部:保证组件实例唯一,memo的缓存逻辑能正常工作。
  • useCallback缓存事件函数:让所有Item接收的selectHandler引用始终一致,不会因为App渲染触发不必要的重渲染。
  • 传递布尔值而非数组:只有选中状态变化的Item,其isSelected props才会改变,其他Item的props完全不变,memo会跳过这些组件的重渲染。

内容的提问来源于stack exchange,提问作者Mario Podolinský

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 07:55:20