如何让React.memo包裹的组件仅在初始加载时渲染一次?
核心问题
代码不生效的根本原因是将React.memo包裹的子组件定义在了父组件的函数执行体内部,这直接导致React.memo的优化逻辑完全失效:
- 父组件每触发一次重渲染,都会重新执行
ParentComponent内部的所有代码,const ChildComponent = React.memo(...)会在每次渲染时生成一个全新的组件引用。 - React的虚拟DOM diff规则中,如果前后两次渲染同一位置的组件类型(引用)不一致,会直接销毁旧组件实例、重新挂载新组件,根本不会触发
React.memo的自定义比较逻辑,你写的永远返回true的比较函数连执行机会都没有,自然拦不住重渲染。
除此之外当前写法还有一个潜在性能问题:传给ChildComponent的items是内联定义的对象,每次父组件渲染都会生成新的对象引用,哪怕组件定义位置正确,也会额外触发memo的比较逻辑,产生不必要的开销。
修复方案
按照以下两点调整即可实现子组件仅初始加载时渲染一次的需求:
- 将
ChildComponent的定义挪到ParentComponent外部,保证组件引用全局唯一、不会随父组件渲染变化 - 固定传给子组件的props引用,避免每次渲染生成新的props对象
修正后的参考代码:
import React, { useMemo } from 'react'; // 子组件定义移到父组件外,保证引用稳定 const ChildComponent = React.memo(({ items }) => { const { param1, param2, param3 } = items; // 其余业务逻辑 return (<Box>子组件内容</Box>); }, () => true); // 自定义比较函数永远返回true,跳过所有props更新触发的重渲染 const ParentComponent = (props) => { // 用useMemo固化props对象的引用,空依赖数组表示仅组件初始化时生成一次 const childItems = useMemo(() => ({ param1: 'some val..', param2: 'some val..', param3: 'some val..', }), []); return (<Box> <ChildComponent items={childItems} /> {/* 其余父组件业务内容 */} </Box>); }
补充:如果子组件完全不需要接收任何动态变化的props,还有更简单的实现方式:直接把子组件的JSX节点用
useMemo包裹、设置空依赖数组,存在父组件里直接渲染即可,连React.memo都不需要使用。
内容的提问来源于stack exchange,提问作者Vlado
相关产品推荐
相关产品推荐

