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

为何已memo化的React组件仍被Profiler标记重复渲染?

问题原因与解决方案

核心问题:children引用不稳定导致RenderList重渲染

点击App按钮触发setSome(false)时,App组件会重新渲染,此时<TestProvider>内部的所有JSX元素都会被重新创建——包括<Counter />和<RenderList><MamaMia /></RenderList>。

  • Counter组件用memo包裹且无传入props,React浅比较后判定props未变化,因此不会重渲染。
  • 但RenderList的children是<MamaMia />,每次App渲染都会生成全新的<MamaMia />元素引用,memo对RenderList的props做浅比较时,会认为children已变更,进而触发重渲染。你在RenderList内部用useMemo包裹children无效,因为依赖的children本身就是新引用,useMemo每次都会重新执行。

解决方法:稳定children的引用

要让RenderList不因为children变化重渲染,需确保每次App渲染时,传递给RenderList的children引用保持不变,以下两种方式均可实现:

方式1:在App中用useMemo包裹children元素

修改App组件,通过useMemo固定<MamaMia />的引用:

function App() {
  const [some, setSome] = useState(true);
  // 稳定MamaMia的引用
  const stableMamaMia = useMemo(() => <MamaMia />, []);
  
  return (
    <>
      <button onClick={() => setSome(false)}>iam App's BTN !</button>
      <TestProvider>
        <Counter />
        <RenderList>
          {stableMamaMia}
        </RenderList>
      </TestProvider>
    </>
  );
}

方式2:将children提取为独立的memo组件

把RenderList的子内容封装成独立的memo组件,确保其引用稳定:

// 新增独立组件
const RenderListContent = memo(() => <MamaMia />);

function App() {
  const [some, setSome] = useState(true);
  return (
    <>
      <button onClick={() => setSome(false)}>iam App's BTN !</button>
      <TestProvider>
        <Counter />
        <RenderList>
          <RenderListContent />
        </RenderList>
      </TestProvider>
    </>
  );
}

补充说明

memo的浅比较仅检查props的引用是否变化,对于JSX元素这类对象,只要每次渲染生成新对象,就会被判定为props变更。因此关键是要让传递给memo组件的props引用保持稳定,而非在组件内部对已变化的props做memo处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 03:06:09