当前位置: 首页 > news >正文

从 Vue 到 React:React.memo + useCallback 组合技

目录

    • 一、Vue 与 React 的组件更新机制对比
    • 二、React.memo 是什么?
    • 三、常见坑:为什么我用了 React.memo 还是会重新渲染?
    • 四、解决方案:useMemo / useCallback 缓存引用
    • 五、Vue 3 中有类似的性能控制需求吗?
    • 六、组合优化小技巧总结
    • 七、不过话又说回来

一、Vue 与 React 的组件更新机制对比

在 Vue 中,组件的更新依赖于响应式系统的依赖追踪:

<!-- Vue 模板中 -->
<Child :data="data" />
  • 父组件更新时,Vue 会判断 data 是否变更;
  • data 是响应式对象,它会做“依赖追踪”;
  • 子组件是否更新由内部响应式系统决定,开发者很少手动优化。

而在 React 中:

<Child data={data} />
  • React 默认只做浅比较
  • 只要 data 是一个新对象(哪怕值完全相同),就会触发 Child 重新渲染;
  • 所以你需要用 React.memo + useCallback + useMemo手动优化性能。

二、React.memo 是什么?

const MemoizedComponent = React.memo(Component);

React.memo 是一个高阶组件,用于缓存函数组件的渲染结果,仅在 props 变化时才重新渲染。

它做了啥?

  • 对 props 进行浅比较
  • 如果 props 没变(===),则跳过子组件渲染;

三、常见坑:为什么我用了 React.memo 还是会重新渲染?

来看一个经典例子:

const Parent = () => {const [count, setCount] = useState(0);const data = { text: "hello" }; // ⚠️ 每次渲染都是新对象!return (<><button onClick={() => setCount(c => c + 1)}>+</button><Child data={data} /></>);
};const Child = React.memo(({ data }) => {console.log("Child render");return <div>{data.text}</div>;
});

🔎 结果:

  • 每点一次按钮,Child 都会重新渲染!
  • 虽然 data 的值没有变,但对象引用变了{} 是新对象);
  • 所以 React.memo 判定 props 变了,触发更新。

四、解决方案:useMemo / useCallback 缓存引用

const data = useMemo(() => ({ text: "hello" }), []);

或者对于函数:

const handleClick = useCallback(() => {console.log("clicked");
}, []);

这就保证了 引用不变,从而让 React.memo 的比较机制生效。


完整示例:

const Parent = () => {const [count, setCount] = useState(0);const data = useMemo(() => ({ text: "hello" }), []);const handleClick = useCallback(() => {console.log("clicked");}, []);return (<><button onClick={() => setCount(c => c + 1)}>+</button><Child data={data} onClick={handleClick} /></>);
};const Child = React.memo(({ data, onClick }) => {console.log("Child render");return <button onClick={onClick}>{data.text}</button>;
});

🧠 现在:

  • 点击按钮不会触发 Child 重新渲染;
  • 因为 dataonClick 的引用没变;
  • React.memo 正常工作,组件性能得到提升。

五、Vue 3 中有类似的性能控制需求吗?

Vue 3 的响应式机制天然做了很多“追踪 + 缓存”,组件不会因为 props 引用变化而轻易重新渲染,只要你不写复杂嵌套 watch / watchEffect,基本不用显式控制更新。

但 React 是“纯函数组件 + 浅比较 + 显式控制”模式,性能优化基本靠开发者手动干预。


六、组合优化小技巧总结

目标工具组合
避免组件重复渲染React.memo
保证函数 prop 引用稳定useCallback
保证对象 prop 引用稳定useMemo
高性能组件拆分 + 精准更新控制React.memo + useCallback + useMemo

七、不过话又说回来

关于这个优化的组合手段,在实际开发中,往往不是“用不用”,而是“什么时候用、用在哪、用多少”。盲目无脑使用很容易陷入“性能优化反而拖慢开发效率”的误区。

❌ 常见错误:

const value = useMemo(() => expensiveCalculation(data), [data]);

很多人会这么写,但:

  • 如果 expensiveCalculation() 实际上并不耗时;
  • 或者 data 频繁变化,memo 无意义;
  • 那么你加了 useMemo 不但没有优化,还增加了复杂度。

所以重点是:只有在“真的影响性能”时才用。


那【何时该用】呢?

场景是否建议使用 Memo 类 Hook
父组件频繁更新,子组件 props 不变✅ 使用 React.memo + useCallback
传递对象或函数给子组件✅ 保持引用稳定,避免不必要更新
有昂贵计算(排序、大数据处理等)✅ 使用 useMemo 缓存计算结果
props 很简单,子组件渲染开销很小(比如一个 <span>❌ 不需要,优化反而复杂
自己写了一堆 memo,但还是更新很慢❌ 可能是 Context/状态设计问题
拥有大量动态子组件(如大表格、虚拟滚动列表)✅ 搭配 memouseMemo、分块渲染等
使用 Context 时⚠️ memo 可能无效,需额外处理

下面看看两类重点问题

  1. Context 泄漏导致 memo 失效
<MyContext.Provider value={contextValue}><MemoizedChild />
</MyContext.Provider>

每次 context value 变,整个 Provider 下所有组件都会重新渲染,哪怕用了 React.memo

解决方式:

  • 避免 context value 是新对象(useMemo 包装);
  • 或者将 context 拆分成多个 Provider;
  • 或使用第三方库如 zustand 做 context 分片;

  1. 大量嵌套组件的 props 传递链

假如你有一个页面,父组件的数据变化会层层传到第 6 层子组件,那你会发现:

  • 就算第 6 层用 React.memo,如果 props 是对象或函数,还是会触发更新;
  • useMemo / useCallback 会让代码变得繁琐难读。

解决方式:

  • 使用全局状态管理(如 zustand)代替 props;
  • 通过组合组件逻辑 & 提前拆分优化更新粒度;
  • 或者用 memo + useContextSelector(experimental)做局部响应式。

Vue 的响应式机制帮我们自动完成“依赖追踪 + 缓存更新”,你不用担心引用变化;
但在 React 中,这些都需要你自己判断并手动处理。

所以:

  • 不要滥用 memo 系列 Hook,性能优化是“按需用药”;
  • 越复杂的页面越要拆组件,避免“父更新拖着全家跑”;
  • 适度引入状态管理工具,别让 props 变成“传话筒”。

相关文章:

  • php 支付宝官方 Alipay Easy SDK
  • es的range失效
  • 【Docker】在Ubuntu平台上的安装部署
  • 无线监控系统分类全解析:搭配视频融合平台EasyCVR开启高效监控
  • 23种设计模式-结构型模式之组合模式(Java版本)
  • 黑马商城-微服务笔记
  • 云原生时代的双轮驱动
  • Unity 将Excel表格中的数据导入到Mysql数据表中
  • 4.23刷题记录(栈与队列专题)
  • 将输入帧上下文打包到下一个帧的预测模型中用于视频生成
  • RocketMQ 核心架构速览
  • Elasticsearch复习笔记
  • 数据集 | 苹果目标检测数据集
  • 车载功能测试-车载域控/BCM控制器测试用例开发流程【用例导出方法+优先级划分原则】
  • 如何避免AI编造虚假文献
  • CSS-跟随图片变化的背景色
  • 从GPT-5到Claude 3:大模型竞赛的下一站是什么?
  • 【ROS2】机器人操作系统安装到Ubuntu简介
  • 基于STM32、HAL库的MCP42010T数字电位器驱动程序设计
  • WebGL简介
  • 北京顺义潮白河大桥主跨坍塌原因公布,已成立事故调查组
  • 驯服象牙塔:美国政府对大学的战争是一场善恶对抗吗
  • 王励勤当选中国乒乓球协会新一任主席
  • 海南公布知识产权保护典型案例,一企业违规申请注册“中华”商标被处罚
  • 中国全国政协-越南祖国阵线中央暨边境省份组织第三次友好交流活动在南宁开幕
  • 经常失眠,睡眠质量低?也许只是缺这种营养