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

React顶层组件缓存疑问:为何不直接跳过未变props组件重渲染?

React中props未变时为何不直接跳过重渲染,反而推荐用useMemo?

问题描述

作为React新手,我了解到当组件自身或任一祖先组件的state发生变化时,该组件会重新渲染。但这种默认渲染所有嵌套组件的行为在性能上并非最优,尤其是对于深度嵌套的组件。React文档建议使用useMemo缓存其JSX以提升性能。

我有个疑问:如果组件的props未发生变化,React直接跳过该组件的重渲染、避免对比虚拟DOM子树,难道不是更高效吗?

换句话说,React原本需要重新渲染组件并对比其虚拟DOM子树与之前的DOM树,以此确定要应用哪些DOM更新;若能判断出props未变化,完全可以省去这一过程。因为props未变时,返回的JSX会与之前一致,组件子树不会有变化,也就无需更新浏览器DOM,根本不需要进行JSX缓存。


回答

其实React早就提供了对应的解决方案——React.memo!

当你用React.memo包裹一个组件时,React会自动做以下事情:

  • 对比该组件前后接收的props(默认是浅对比)
  • 如果props完全没有变化,就直接跳过这个组件的重渲染流程,连虚拟DOM的对比步骤都省了
  • 只有当props确实发生变化时,才会重新执行组件函数、进行虚拟DOM对比和可能的DOM更新

那为什么文档还会提到用useMemo缓存JSX呢?这俩是互补的优化手段,适用场景不同:

  1. React.memo是组件级别的优化:它针对的是整个独立组件,帮你跳过组件的重渲染,但前提是这个组件的props能被正确识别为“未变化”
  2. useMemo是组件内部的优化:
    • 如果你在组件内部直接返回一段复杂的JSX片段(不是独立组件),useMemo可以缓存这段JSX,避免每次渲染都重新创建虚拟DOM节点
    • 更常见的场景是:当你传递给子组件的props是对象、数组这类引用类型时,每次父组件渲染都会创建新的引用,哪怕内容没变,React.memo的浅对比会误以为props变了,这时候用useMemo缓存这个引用,就能让React.memo正常工作

举个实际的例子:

// 用React.memo包裹子组件,props不变则跳过重渲染
const Child = React.memo(({ userInfo }) => {
  console.log('Child组件渲染了');
  return <div>{userInfo.name}</div>;
});

function Parent() {
  const [count, setCount] = useState(0);
  
  // 如果不用useMemo,每次Parent渲染都会创建新的userInfo对象
  // React.memo浅对比会认为props变了,导致Child重复渲染
  const userInfo = useMemo(() => ({ name: '李四', age: 25 }), []);

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>计数:{count}</button>
      <Child userInfo={userInfo} />
    </div>
  );
}

再总结下核心逻辑:

  • 当组件props未变时,React.memo确实能直接跳过重渲染,这比“渲染后再对比虚拟DOM”高效得多
  • useMemo不是用来替代React.memo的,它更多是解决「props引用变化但内容没变」的问题,或者缓存组件内部的复杂计算结果,让React.memo的优化能生效,同时也能避免不必要的重复计算

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 03:52:42