从 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
重新渲染; - 因为
data
和onClick
的引用没变; 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/状态设计问题 |
拥有大量动态子组件(如大表格、虚拟滚动列表) | ✅ 搭配 memo 、useMemo 、分块渲染等 |
使用 Context 时 | ⚠️ memo 可能无效,需额外处理 |
下面看看两类重点问题
- Context 泄漏导致 memo 失效
<MyContext.Provider value={contextValue}><MemoizedChild />
</MyContext.Provider>
每次 context value 变,整个 Provider 下所有组件都会重新渲染,哪怕用了
React.memo
解决方式:
- 避免 context value 是新对象(
useMemo
包装); - 或者将 context 拆分成多个 Provider;
- 或使用第三方库如
zustand
做 context 分片;
- 大量嵌套组件的 props 传递链
假如你有一个页面,父组件的数据变化会层层传到第 6 层子组件,那你会发现:
- 就算第 6 层用
React.memo
,如果 props 是对象或函数,还是会触发更新; - 用
useMemo
/useCallback
会让代码变得繁琐难读。
解决方式:
- 使用全局状态管理(如
zustand
)代替 props; - 通过组合组件逻辑 & 提前拆分优化更新粒度;
- 或者用
memo
+useContextSelector
(experimental)做局部响应式。
Vue 的响应式机制帮我们自动完成“依赖追踪 + 缓存更新”,你不用担心引用变化;
但在 React 中,这些都需要你自己判断并手动处理。
所以:
- 不要滥用 memo 系列 Hook,性能优化是“按需用药”;
- 越复杂的页面越要拆组件,避免“父更新拖着全家跑”;
- 适度引入状态管理工具,别让
props
变成“传话筒”。
相关文章:
从 Vue 到 React:React.memo + useCallback 组合技
目录 一、Vue 与 React 的组件更新机制对比二、React.memo 是什么?三、常见坑:为什么我用了 React.memo 还是会重新渲染?四、解决方案:useMemo / useCallback 缓存引用五、Vue 3 中有类似的性能控制需求吗?六、组合优化…...
1656打印路径-Floyd/图论-链表/数据结构
蓝桥账户中心 1.税收: “城市的税收”:所以是中介点的税收,经过该点后加上 2.路径: 用数组存储前驱节点从而串成链表 pre[ i ][ j ]代表的是从 i 到 j 的最短路径上 j 的前驱节点是什么 那么便可以pre[ i ][ j ]k 把k加入pa…...
Linux网络编程 从集线器到交换机的网络通信全流程——基于Packet Tracer的深度实验
这里我们先下载一个软件:Packet Tracer 用来搭建网络拓扑图的,是模拟和查看数据在网络中传输的详细过程的 在软件这里可以添加设备 知识点1【集线器】(Hub) 1、先配置一下主机的IP 这里我们设置IP一定要在同一个网段ÿ…...
深入学习Axios:现代前端HTTP请求利器
文章目录 深入学习Axios:现代前端HTTP请求利器一、Axios简介与安装什么是Axios?安装Axios 二、Axios基础使用发起GET请求发起POST请求并发请求 三、Axios高级特性创建Axios实例配置默认值拦截器取消请求 四、Axios与TypeScript五、最佳实践1. 封装Axios2…...
FANUC机器人GI与GO位置数据传输设置
FANUC机器人GI与GO位置数据传输设置(整数小数分开发) 一、概述 在 Fanuc 机器人应用中,如果 IO 点位足够,可以利用机器人 IO 传输位置数据及偏移位置数据等。 二、操作步骤 1、确认通讯软件安装 首先确认机器人控制柜已经安装…...
微服务 RabbitMQ 组件的介绍、安装与使用详解
微服务 RabbitMQ 组件的介绍、安装与使用 在现代微服务架构中,服务之间的通信通常采用消息队列的方式,来解耦服务之间的依赖、提高系统的可靠性和扩展性。RabbitMQ 作为一种高效、可靠的消息队列系统,已经广泛应用于微服务架构中。本文将介绍…...
Vue3速通笔记
Vue3入门到实战 尚硅谷Vue3入门到实战,最新版vue3TypeScript前端开发教程 1. Vue3简介 2020年9月18日,Vue.js发布版3.0版本,代号:One Piece(n经历了:4800次提交、40个RFC、600次PR、300贡献者官方发版地…...
Spring Boot 项目:如何在 JAR 运行时读取外部配置文件
在 Spring Boot 项目中,我们常常需要在生产环境中灵活地配置应用,尤其是当我们将项目打包为 JAR 文件时,如何在运行时通过外部配置文件(如 application.yml 或 application.properties)替换 JAR 内部的配置就变得尤为重…...
Certimate本地化自动化 SSL/TLS 证书管理解决方案
一、背景与挑战 多域名管理复杂 运维团队往往需要为多个子域、泛域名乃至不同项目的域名分别申请证书,手动操作容易出错且耗时。续期易忘风险 主流免费证书(如 Let’s Encrypt)有效期仅 90 天,需要定期续期,人工监控门…...
vue+flask+lstm高校舆情分析系统 | 可获取最新数据!
文章结尾部分有CSDN官方提供的学长 联系方式名片 文章结尾部分有CSDN官方提供的学长 联系方式名片 关注B站,有好处! 编号:F020 gaoxiao 架构:vueflaskLSTMMySQL 功能: 微博信息爬取、情感分析、基于负面消极内容舆情分…...
Cisco-Torch:思科设备扫描器!全参数详细教程!Kali Linux教程!
简介 cisco-torch 与同类工具的主要区别在于其广泛使用 fork 技术,可以在后台启动多个扫描进程,从而最大限度地提高扫描效率。此外,它还可以根据需要同时使用多种应用层指纹识别方法。我们希望能够快速发现运行 Telnet、SSH、Web、NTP、TFTP…...
Go协程的调用与原理
Goroutine Go不需要像C或者Java那样手动管理线程,Go语言的goroutine机制自动帮你管理线程。 使用goroutine、 Go语言中使用goroutine非常简单,只需要在调用函数的时候在前面加上go关键字,就可以为一个函数创建一个goroutine。 一个gorout…...
论文精读:大规模MIMO波束选择问题的量子计算解决方案
论文精读:大规模MIMO波束选择问题的量子计算解决方案 概要: 随着大规模多输入多输出系统(MIMO)在5G及未来通信技术中的应用,波束选择问题(MBS)成为提升系统性能的关键。传统的波束选择方法面临计…...
将 MySQL 8 主从复制延迟优化到极致
目录 一、网络资源不足引起的复制延迟 1. 执行监控确认延迟原因 2. 估算所需带宽 (1)基本公式 (2)实际测量方法 二、大事务或大查询引起的复制延迟 1. 主库大事务 2. 从库大查询 3. 估算所需 I/O 能力 (1&am…...
路由与OSPF学习
【路由是跨网段通讯的必要条件】 路由指的是在网络中,数据包从源主机传输到目的主机的路径选择过程。 路由通常涉及以下几个关键元素: 1.路由器:是一种网络设备,负责将数据包从一个网络传输到另一个网络。路由器根据路由表来决定…...
Spring Security:企业级安全架构的设计哲学与工程实践
一、核心架构与设计理念 Spring Security作为Spring生态中的安全基石,其架构设计遵循**“分层过滤"与"组件化扩展”**两大原则。整个安全框架本质上是一个由多个过滤器构成的链式处理模型(Filter Chain),每个过滤器负责…...
NLP高频面试题(五十二)——BERT 变体详解
在现代自然语言处理领域,BERT 系列模型不断演进,衍生出多种变体,它们通过改进预训练任务、模型结构和训练策略,在不同应用场景下取得了更优表现。本文首先概览主要 BERT 变体(如 ALBERT、RoBERTa、ELECTRA、SpanBERT、Transformer-XL 等),随后针对以下几个关键问题逐一展…...
C++Primer 编程练习 第二章
最近想重新看一下CPrimer,顺便敲一下他的编程练习题,虽然很简单,但是就当是锻炼一下vim的熟练度和手感 由于按照章节顺序来说是初学者,不会对输入内容做过多的判断,只对问题作出基本实现 第二章 1 #include <ios…...
Vue.js 新手小白指南:从起源到实战
🌟 Vue 的来源 Vue.js 由**尤雨溪(Evan You)**在2014年创建,最初是作为个人项目开发,灵感来源于他在 Google 使用 AngularJS 的经验。Vue 的设计目标是提供一个更轻量级、更易上手的前端框架。 如今,Vue …...
策略模式:动态切换算法的设计智慧
策略模式:动态切换算法的设计智慧 一、模式核心:定义一系列算法并可相互替换 在软件开发中,常常会遇到需要根据不同情况选择不同算法的场景。例如,在电商系统中,根据不同的促销活动(如满减、折扣、赠品&a…...
Vm免安装直接使用虚拟机win7系统
教程 一、下载并解压资料里面的vmx压缩包 二、使用Vm软件打开刚刚解压的vmx文件即可使用虚拟机的win7系统 资料下载 点击下载...
LSTM-GAN生成数据技术
1. 项目概述 本项目利用生成对抗网络(GAN)技术来填补时间序列数据中的缺失值。项目实现了两种不同的GAN模型:基于LSTM的GAN(LSTM-GAN)和基于多层感知机的GAN(MLP-GAN),并对两种模型…...
26、C# 中是否可以继承String类?为什么?
在 C# 中,不能直接继承 String 类(System.String)。这是由于以下几个原因: 1、String 类是 sealed 的 String 类在 .NET 中被标记为 sealed,这意味着它是一个密封类,不能被继承。 sealed 关键字的作用是防…...
gem5教程第五章 了解gem5默认配置脚本
在本章中,我们将探讨如何使用gem5附带的默认配置脚本。 gem5附带了许多配置脚本,使您能够非常快速地使用gem5。 然而,一个常见的陷阱是在不完全理解所模拟内容的情况下使用这些脚本。在使用gem5进行计算机架构研究时,充分了解您正在模拟的系统非常重要。本章将引导您了解默…...
什么是鸿蒙南向开发?什么是北向开发?
文章目录 鸿蒙南向开发 vs 北向开发:底层与生态的双向赋能一、鸿蒙南向开发:连接硬件的底层基石二、鸿蒙北向开发:构建全场景应用生态三、南向与北向:互补与协同四、如何选择开发方向?结语 鸿蒙南向开发 vs 北向开发:…...
蓝桥杯 19. 最大比例
最大比例 原题目链接 题目描述 X 星球的某个大奖赛设了 M 级奖励。每个级别的奖金是一个正整数。 并且,相邻两个级别间的比例是一个固定值,也就是说:所有级别的奖金构成一个等比数列。 例如: 奖金数列为 16, 24, 36, 54&…...
制造业数字化转型标杆解析:从冀凯机电到君乐宝的启示
1. 执行摘要 数字化转型已成为现代制造业提升竞争力、实现高质量发展的核心驱动力。本文旨在通过深入剖析冀凯装备制造股份有限公司(冀凯机电)和君乐宝乳业集团(君乐宝)两家不同行业背景企业的数字化转型实践,提炼可供…...
【OSCP-vulnhub】Raven-2
目录 端口扫描 本地/etc/hosts文件解析 目录扫描: 第一个flag 利用msf下载exp flag2 flag3 Mysql登录 查看mysql的运行权限 MySql提权:UDF 查看数据库写入条件 查看插件目录 查看是否可以远程登录 gcc编译.o文件 创建so文件 创建临时监听…...
配置MambaIRv2: Attentive State Space Restoration的环境
github上代码的地址: csguoh/MambaIR: [ECCV2024, CVPR2025] MambaIR and MambaIRv2! 一开始直接输入命令 conda env create -f environment.yaml 安装了半天爆出来好几个错误,其中一个是没有nvcc 输入以下命令: module avail 发现没有…...
4.23晚间工作总结
主要工作:将ClassicDetail界面拆分成utils,apis,stores,css,vue多个文件,方便后续重用 具体代码截图:...
Maven 项目中引入本地 JAR 包
在日常开发过程中,我们有时会遇到一些未上传到 Maven 中央仓库或公司私有仓库的 JAR 包,比如第三方提供的 SDK 或自己编译的库。这时候,我们就需要将这些 JAR 包手动引入到 Maven 项目中。本文将介绍两种常见方式:将 JAR 安装到本…...
SpringBoot整合SSE,基于okhttp
一、引入依赖 <dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp</artifactId><version>4.10.0</version> </dependency> <dependency><groupId>com.squareup.okhttp3</groupId><…...
从云端到边缘:云原生后端架构在边缘计算中的演进与实践
📝个人主页🌹:慌ZHANG-CSDN博客 🌹🌹期待您的关注 🌹🌹 一、引言:为何云原生后端正在走向边缘? 随着物联网(IoT)、5G 和实时应用的快速发展,越来越多的数据在终端产生并需要即时处理。传统云计算虽强大,但将所有数据上送云端再处理,带来高延迟与带宽压力。…...
pytest心得体会
一、如何单独运行某条用例 在参数化测试中总有些用例失败,由于前后置数据的关系需要单独运行那条用例如何运行呢 方法一:直接查看控制台运行用例 确定是[2-case_data8] pytest.main(["-sv","testcase/违规告警/test_违规告警_非合同车…...
《Cesium 中两点绘制线的实现:实线、虚线、动态线、流动线详解》
摘要 在 Cesium 三维地球可视化开发中,两点之间绘制线是常见的需求。本文详细介绍如何在 Cesium 中实现两点间绘制实线、虚线、动态线和流动线,并提供完整的代码示例,方便开发者快速上手,满足不同场景下的可视化需求。 一、环境与依赖 本文代码基于 Cesium 库进行开发,…...
【EasyPan】MySQL FIELD() 函数实现自定义排序
【EasyPan】项目常见问题解答(自用&持续更新中…)汇总版 MySQL FIELD() 函数解析 一、FIELD() 函数技术解析 /* 基础语法 */ FIELD(column_name, value1, value2, ..., valueN)核心特性 特性说明返回值机制返回字段值在参数列表中的索引位置&…...
搭建TypeScript单元测试环境
我们在学习TypeScript的时候如果能够搭建一个单元测试的环境,那写些demo会很简单,下面我们使用jest来搭建一个单元测试环境 Jest 是一个由 Facebook 开发并开源的 JavaScript 测试框架,被广泛应用于前端和 Node.js 项目的单元测试。以下是关…...
Vue3父子组件数据同步方法
在 Vue 3 中,当子组件需要修改父组件传递的数据副本并同步更新时,可以通过以下步骤实现: 方法 1:使用 v-model 和计算属性(实时同步) 父组件: vue <template><ChildComponent v-mo…...
免费且开源的企业级监控解决方案:Zabbix
一、Zabbix 简介 Zabbix 是一款功能强大的企业级开源监控解决方案。它可以监控各种 IT 基础设施组件,包括网络设备、服务器、虚拟机、云服务、应用程序和数据库等。Zabbix 提供实时的监控、告警、报表和可视化功能,帮助用户及时发现和解决 IT 系统中的问…...
高并发系统的通用设计方法是什么?
背景 高并发系统的通用设计方法是解决系统在面对大量用户访问时的性能瓶颈问题。当系统遇到性能瓶颈时,通常是因为某个单点资源(如数据库、后端云服务器、网络带宽等)达到了极限。 为了提升整个系统的容量,需要找到这个瓶颈资源…...
ubuntu系统下部署使用git教程
在ubuntu系统下部署并使用git教程 1.下载并安装 sudo apt update sudo apt install git2.检验安装是否成功 git --version若输出git版本号即为成功。 3.配置参数 git config --global user.name "你的名字" git config --global user.email "你的邮箱&quo…...
redis client.ttl(key)
对应 Redis 的 TTL 命令: bash 复制 下载 TTL key 使用示例 1. 基本用法 java 复制 下载 try (Jedis jedis jedisPool.getResource()) {long ttl jedis.ttl("user:1001:session");if (ttl > 0) {System.out.println("键将在 " t…...
基于ACL方式手动建立站点间 IPSec 隧道
换句话说 不使用 IKE 自动协商,而是静态配置密钥和 SPI(安全参数索引)来配置隧道规则 环境基础 还是使用eNSP软件进行模拟,等后面再更新实际通信中的环境 没有框架,就没有基本思路 还是使用前面文章GRE VPN的拓扑&…...
电池大脑的基准测试及AI拓展
从为我们的智能手机供电到驱动电动汽车,我们的日常生活都离不开锂离子电池(LIB)。但是,理解其复杂的内部运作并预测其性能需要精密的工具。由此引入了多孔电极理论(PET)模型,我们可以将其视为模…...
数据通信学习笔记之OSPF的基础术语
Router ID RouterID 用于在自治系统中唯一标识一省运行 OSPF 的路由器,它是一个 32 位的无符号整数 配置完成后,如果需要修改 Router ID 的话,需要重启进程才能上生效 <Huawei>reset ospf 1 process // 重启 ospf 进程 1 Route…...
Android Cordova 开发 - Cordova 快速入门(Cordova 环境配置、Cordova 第一个应用程序)
一、Cordova 1、Cordova 概述 Cordova 是使用 HTML,CSS 和 JavaScript 构建混合移动应用程序的平台 2、Cordova 特征 (1)命令行界面(Cordova CLI) 这是可用于启动项目,构建不同平台的进程,…...
AndroidAutomotive模块介绍(四)VehicleHal介绍
前言 前面的文章中,描述了 Android Automotive 的框架中应用、Framework 层服务等知识,本篇文章将会继续按照 Android Automotive 框架介绍 Vehicle Hal 层服务的内容。 上一篇:AndroidAutomotive模块介绍(三)CarSer…...
Pingora vs. Nginx vs. 其他主流代理服务器性能对比
Pingora vs. Nginx vs. 其他主流代理服务器性能对比 核心对比概览 特性Pingora (Cloudflare)NginxEnvoyHAProxyCaddyTraefik开发公司CloudflareNginx, Inc/F5Lyft/CNCFHAProxy TechApache 2.0社区Containous核心语言RustCCCGoGo并发模型异步/多线程事件驱动事件驱动事件驱动协…...
4月23日作业
需求: 1,R5为ISP,其上只能配置IP地址; R5与其他所有直连设备间均使用公有IP;环回地址为100.1.1.1/32 2,R4设备为企业出口路由器 3,整个OSPF环境IP基于172.16.0.0/16划分; 4&…...
5.学习笔记-SpringMVC(P53-P60)
1.响应 (1)响应页面 (2)响应数据(异步提交):文本数据、json数据 2.REST风格 (1)REST:表现形式状态转换。 (2)传统风格资源描述形式 3.Restful入门案例 5.基于RESTful页面数据…...