为何已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
相关产品推荐
相关产品推荐

