【React系列】React.memo() vs useMemo()

news/2025/10/21 8:17:33/文章来源:https://www.cnblogs.com/Dsir/p/19154052

React.memo()与useMemo()之间有什么主要区别?

性能优化是一只web开发中的一个重要讨论点。对于react团队同样如此,为了实现加速组件的渲染速度,采用“备忘录”的方式。
所以这个时候就React.memo()和 useMemo 钩子 就为了解决这个问题产生了。本文将比较和对比React.memo和useMemo(),同时讨论它们的用例。

React.memo()和useMemo()的必要性

理解我们为什么需要React.memo()和useMemo()的最好方法是看看React是如何在没有记忆化的情况下重新呈现组件的。
为此,让我们考虑一个有两个React组件的简单例子。第一个组件是父组件。它有一个按钮,可以增加计数变量的值。
import Child from './Child'
import React, { useState } from 'react'export default function Parent() {const [count, setCount] = useState<number>(0)const handleClick = () => {setCount(count + 1)}console.log('prent')return (<div><button onClick={handleClick}>Increase Count</button><h2>{count}</h2><Child name={'Child COmponnt'} /></div>)
}
第二个组件是子组件,它显示从父组件传来的名字。
import React, { Component } from 'react'export default function Child(props) {console.log('Child Render')return (<div><h2>{props.name}</h2></div>)
}
一旦用户点击 "增加计数 "按钮,计数就会增加,这将导致父组件的重新渲染.
在这里,count变量的值变化并不影响props传递到子变量,子组件也不应该重新渲染。
在这里如果你业务代码逐渐开始多了,然后里面刚刚好采用了这种方式去开发对应的业务代码,页面的性能可想而知,会根据代码的增量而成反比。

在这里插入图片描述
从上述所见,不难看出每当父组件被重新渲染时,子组件的渲染方法也被调用。这将触发子组件的虚拟DOM与之前的虚拟DOM状态做差异检查。
但是,真实的DOM不会改变,因为子组件没有变化。虽然真实的DOM没有变化,但与虚拟的DOM进行比较需要一些时间才能看到相同的内容。因此,这种行为会导致严重的性能问题,并增加大规模应用的加载时间。

这就是为什么我们需要使用React.memo()和useMemo()来优化React组件的渲染过程。

什么是React.memo()?

React.memo()是在React 16.6中引入的,以避免功能组件中不必要的重新渲染。它是一个高阶组件,接受另一个组件的props。只有当props发生变化时,它才会渲染该组件。
现在让我们再次研究上述例子,了解React.memo()是如何工作的。但是,这一次,我们需要用React.memo()来包装子组件。

import React, { Component, memo } from 'react'function Child(props) {console.log('Child Render')return (<div><h2>{props.name}</h2></div>)
}export default memo(Child)

当我们点击增加计数按钮,子组件不会重现的,应用程序将重用前面呈现输出。
在这里插入图片描述
重要的是要记住,React.memo()将只检查props的改变。
如果功能组件有useState、useReducer或useContext等Hooks,它仍然会在状态或上下文发生变化时强制重新渲染。

此外,React.memo()将浅层地比较props对象中的复杂对象。对于特定业务场景可能需要类似shouldComponentUpdate这样的 API,你也可以传递一个自定义的比较函数作为第二个参数,基本用法在上一案例。高阶用法如下所示:

export function Child(props) { /* render using props */}
function areSame(prevProps, nextProps) { /* return true if passing nextProps to render would return the same result as passing prevProps to render, otherwise return false */return prevProps === nextProps;}export default React.memo(Child, areSame);

什么是useMemo()?

useMemo()是开发者中最常用的React Hooks之一。它接受一个函数和一个依赖关系数组作为输入,并将该函数返回的值备忘化。
useMemo()的特点是,只有当其中一个依赖关系发生变化时,它才会重新计算备忘的值。这种优化有助于避免在每次渲染时进行昂贵的计算。
现在写一个例子,了解useMemo()是如何工作的:

import Child from './Child'
import React, { useState, useRef, useMemo } from 'react'export default function Parent() {const [count, setCount] = useState<number>(0)const [times, setTimes] = useState<number>(0)const handleClick = () => {setCount(count + 1)}const useMemoRef = useRef(0)const incrementUseMemoRef = () => useMemoRef.current++const memoizedValue = useMemo(() => incrementUseMemoRef(), [times])console.log('prent render')return (<div><button onClick={() => setTimes(times + 1)}>Force Child Render</button><br /><br /><br /><button onClick={handleClick}>Increase Count</button><Child memoizedValue={memoizedValue} /></div>)
}

这表明在父组件中,我们正在使用useRef()Hook来跟踪子组件重新渲染的次数。useMemo()Hook调用了incrementUseMemoRef函数,由useMemo() Hook返回的值然后被存储在memoizedValue变量中。每次依赖关系更新时,它都会将我们的useMemoRef.current的值增加一个。你会看到,如果你点击增加计数按钮,memoizedValue并没有得到更新。

import React, { Component, memo } from 'react'function Child({ memoizedValue }) {console.log('Child Render')return (<div><h2>Child Component</h2><p>I will only re-render when you click <b>Force Child Render.</b></p></div>)
}
export default memo(Child)

在这里插入图片描述

由于memoizedValue被更新,子组件只有在你点击Force Child Render按钮时才会被重新渲染。

什么时候使用useMemo?

在使用useMemo()钩子之前,你需要确保几点:

  1. 你已经分析了这个组件,并验证了它是否在每次渲染时都会计算一个昂贵的值。
  2. 因为它是在渲染时执行的,你的useMemo()钩子没有副作用,所有的副作用都在useEffect()钩子里。
  3. 你不会违反任何React Hooks规则和标准。

使用useMemo()的理想情况是当你有计算密集型的函数时。useMemo()函数可以记忆你的函数返回的值,并在不同的渲染中保持它的内存。在大多数情况下,它返回一个你不能在你的React组件之外运行的结果。

这类似于将一个函数的响应保存到一个变量中,然后从变量中引用响应值,而不必每次都执行该函数。

你应该使用React.memo()还是useMemo()?

在React.memo()和useMemo()之间做出选择应该是很简单的。现在你对它们都有了充分的了解。

1.使用React.memo来记忆整个组件。
2.使用useMemo在一个功能组件中对一个值进行备忘。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/941907.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【每日积累】javascript 一文弄懂eval

eval 动态化执行语句 概述 eval方法是javascript的全局方法,能够执行含有javascript代码的字符串,虽然eval方法带来强大的动态执行功能,但考虑其负面影响,建议少用,在特殊情况下可以使用eval方法动态改变代码的执…

腾讯云COS通过CDN加速配置指南 - 教程

腾讯云COS通过CDN加速配置指南 - 教程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Mona…

前端: 如何优化列表大批量的数据渲染

需求点:如何列表数据渲染进行优化? 最近业务上也碰到这个问题点。上网也查了查资料,貌似也经常问,特此写文章记录下来。关于如何处理以上上面的业务痛点: 就两点: 1 、虚拟列表是最主流的解决方案,不渲染所有的…

量子计算25年发展历程与技术挑战

本文回顾了量子信息处理会议25年发展历程,探讨了量子计算从理论到实验的突破,包括量子算法实现、量子复杂性理论对数学的影响,以及当前面临的可扩展性、错误率控制和实际应用等关键技术挑战。25年量子信息处理发展历…

tomcat启动一次问题的处理。

tomcat启动一次问题的处理。说明:2025.10.20,出现启动tomcat对任何请求都没有响应的情况。通过删除 $tomcat/work/Catalina 下的全部数据。并重启解决。但是重启需要的时间比较久。大约5分钟。

软件开发 --- trae如何和环境配合执行

软件开发 --- trae如何和环境配合执行trae会自动执行代码,但是执行前需要我们提前安装好所有的执行环境。 有的环境可能需要手动配合,比如trae在执行这个代码前手动触发环境执行。

marmot的一些特点

marmot的一些特点以前简单介绍过marmot ,以下说下一些特点 特点当前版本已经通过nats server 包内置到了服务中,不需要独立部署nats 了,但是推荐还是部署3个节点 默认内置的nats 没有开启认证,注意使用,同时nats …

应用安全 --- 如何反编译一个超大的函数

应用安全 --- 如何反编译一个超大的函数先用ida反编译一下 再用claude max 完善代码并配合完整的提示词 再次执行上述过程直到没有任何遗漏的代码

藏宝阁

书籍轻松主义★★★★☆反脆弱★★★★★娱乐至死★★★★☆动物庄园★★★★★谈谈方法★★★★☆小说雪中悍刀行★★★★★剑来★★★★★斗破苍穹★★★★★完美世界★★★★★武动乾坤★★★☆☆我在精神病院学斩神…

【模块化解读】commonjs vs commonjs2 exports vs module.exports

背景 最近在用typescript写工具库的时候,无意中在 webpack中看到了两个关键字,commonjs 和 commonjs2. 瞬间产生了好奇。后面看了issues才得知它们与模块化 导出有着密切关系。 CommonJs spec defines only exports.…

【GitHub每日速递 251021】一键将全新Arch安装变身超美现代Web开发系统!Omarchy太神了

原文: https://mp.weixin.qq.com/s/aE_bPqSXRQxxH7zq_4HYIQ 一键将全新Arch安装变身超美现代Web开发系统!Omarchy太神了 omarchy 是一个基于 Arch Linux 和 Hyprland 桌面环境的自动化配置工具。简单讲,它是一套预设…

[Mongodb]mongodb的安装以及增删改查

mongodb的安装 mongo主页 下载完成之后将目录放置下方 /usr/local/安装之后就配置环境变量: vim ~/.bash_profile下方是我自己的环境变量配置 # JDK_HOMEJAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_321.j…

PHP 8.5 新特性 闭包可以作为常量表达式了

PHP 8.5 新特性 闭包可以作为常量表达式了 PHP 8.5 又带来了一个让人兴奋的新特性:闭包现在可以作为常量表达式使用了,这意味着它们可以出现在默认参数或属性值中。 你是不是也遇到过这种情况:想在 PHP 中把闭包设置为…

【JavaScript-基础】split,splice,slice 三者的用法

split,splice,slice 三者的用法 很多知识点不熟悉可以自行去下面链接查询: mdn web docs 最近一直忙于搞python,等后续有时间更新python相关的内容。毕竟现在在弄web.有些知识点需要巩固,以便自己后续带人和巩固自己…

2025 代码源 CSP-S 模拟赛复盘

Day 16 T1 双重心 分类讨论一下:是原树的双重心之一,考虑把这条边割掉,接到另一个连通块的任意一个点上都是可行的。 不割掉原树上的双重心的边,两侧的连通块内的的任意一条边可以断开,连通块内相互连边就行。 考…

2025.10.21——1绿

普及+/提高 P1347 排序 wpmx昨晚写的有意思的题,数据范围比较小,我就直接用set+m次拓扑排序,30min写出来,要注意输出顺序后的句号,以及特判n==1

【JavaScript-基础】map、forEach、for、for in、for of等的区别

tips:循环虽好,大家都得按自己所需场景进行使用。个人建议,不喜勿喷 forEach forEach: forEach(item,index,array), item:当前处理的数据,index:下标, array:整个数组 遍历全部数据,不能通过return结束循环,消耗…

dotnet 利用 Windows 注册表实现开机自动启动

本文记录一个开机自动启动实现方法,通过写入到注册表实现开机之后,用户登录完成之后让应用程序开机自启本文将演示写入 HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run 注册表路线,实现应用程序…

帮我回答这些问题

◦ 以太坊交易的数据结构及EIP1559/712协议的理解。 ◦ 以太坊的账⼾是如何⽣产的,公私钥的关系。 ◦ 以太坊区块链浏览器⼀般会展⽰哪些信息,⼤概能知道。 ◦ 以太坊交易nonce的作⽤,nonce异常交易如何处理。 ◦ 以…

使用uWSGI和Nginx部署深度学习模型指南

本文详细介绍了如何通过uWSGI应用服务器和Nginx反向代理将深度学习模型部署为可扩展的Web服务,涵盖WSGI协议原理、服务器配置步骤及性能优化要点,帮助构建高并发生产级AI应用。如何使用uWSGI和Nginx部署深度学习模型…