React.memo vs. useMemo: Major differences and use cases

news/2024/12/25 13:28:12/文章来源:https://www.cnblogs.com/saaspeter/p/18531247

from:   https://blog.logrocket.com/react-memo-vs-usememo/

 

Memoization is one of the ways to optimize performance. In this article, we’ll explore how it works in React.

What is memoization?

In simple terms, memoization is a process that allows us to cache the values of recursive/expensive function calls so that the next time the function is called with the same argument(s), the cached value is returned rather than having to re-compute the function.

This ensures that our applications run faster because we avoid the time it would usually take to re-execute the function by returning a value that’s already stored in memory.

Why use memoization in React?

In React functional components, when props within a component change, the entire component re-renders by default. In other words, if any value within a component updates, the entire component will re-render, including functions/components that have not had their values/props altered.

Let’s look at a simple example where this happens. We’ll build a basic app that tells users what wine goes best with the cheese they’ve selected.

We’ll start by setting up two components. The first component will allow the user to select a cheese. It’ll then display the name of the wine that goes best with that cheese. The second component will be a child of the first component. In this component, nothing changes. We’ll use this component to keep track of how many times React re-renders.

Let’s start with our parent component: <ParentComponent />.

N.B., the classNames used in this example come from Tailwind CSS.

// components/parent-component.js
import Counts from "./counts";
import Button from "./button";
import { useState, useEffect } from "react";
import constants from "../utils";
const { MOZARELLA, CHEDDAR, PARMESAN, CABERNET, CHARDONAY, MERLOT } = constants;export default function ParentComponent() {const [cheeseType, setCheeseType] = useState("");const [wine, setWine] = useState("");const whichWineGoesBest = () => {switch (cheeseType) {case MOZARELLA:return setWine(CABERNET);case CHEDDAR:return setWine(CHARDONAY);case PARMESAN:return setWine(MERLOT);default:CHARDONAY;}};useEffect(() => {let mounted = true;if (mounted) {whichWineGoesBest();}return () => (mounted = false);}, [cheeseType]);return (<div className="flex flex-col justify-center items-center"><h3 className="text-center dark:text-gray-400 mt-10">Without React.memo() or useMemo()</h3><h1 className="font-semibold text-2xl dark:text-white max-w-md text-center">Select a cheese and we will tell you which wine goes best!</h1><div className="flex flex-col gap-4 mt-10"><Button text={MOZARELLA} onClick={() => setCheeseType(MOZARELLA)} /><Button text={CHEDDAR} onClick={() => setCheeseType(CHEDDAR)} /><Button text={PARMESAN} onClick={() => setCheeseType(PARMESAN)} /></div>{cheeseType && (<p className="mt-5 dark:text-green-400 font-semibold">For {cheeseType}, <span className="dark:text-yellow-500">{wine}</span>{" "}goes best.</p>)}<Counts /></div>);
}

The second component is a <Counts /> component that keeps track of how many times the entire <ParentComponent /> component re-renders.

// components/counts.js
import { useRef } from "react";
export default function Counts() {const renderCount = useRef(0);return (<div className="mt-3"><p className="dark:text-white">Nothing has changed here but I've now rendered:{" "}<span className="dark:text-green-300 text-grey-900">{(renderCount.current ++)} time(s)</span></p></div>);
}

Here’s the example above at work when we click on the name of a cheese:

Example of React Without Memoization

Our <Counts /> component within our <ParentComponent /> counts how many times changes to the <ParentComponent /> forces the <Counts /> component to re-render.

Currently, clicking on the name of a cheese will update the name of the cheese to be displayed. It’ll also update the name of the wine to be displayed. Not only will the <ParentComponent /> re-render, but the <Counts /> component will also re-render even though nothing within it has changed.

Imagine having a component displaying thousands of data, and each time the user clicks a button, every piece of data in that component or tree re-renders when they don’t need to. This is where React.memo() or useMemo() becomes necessary to give us performance optimizations.


Over 200k developers use LogRocket to create better digital experiences

Learn more →

Now, let’s explore React.memo, then useMemo(). Afterward, we’ll compare the differences between them and learn when you should use one over the other.

What is React.memo()?

React.memo() was released with React v16.6. While class components already allowed you to control re-renders with the use of PureComponent or shouldComponentUpdate, React 16.6 introduced the ability to do the same with functional components.

React.memo() is a higher-order component (HOC), which is a fancy name for a component that takes a component as a prop and returns a component that prevents a component from re-rendering if the props (or values within it) have not changed.

We’ll take the same example above but use React.memo() in our <Counts /> component. All we need to do is wrap our <Counts /> component with React.memo() like below:

import { useRef } from "react";
function Counts() {const renderCount = useRef(0);return (<div className="mt-3"><p className="dark:text-white">Nothing has changed here but I've now rendered:{" "}<span className="dark:text-green-300 text-grey-900">{(renderCount.current ++)} time(s)</span></p></div>);
}
export default React.memo(Counts);

Now, when we select a cheese type by clicking on it, our <Counts /> component will not re-render.

Example Using React.memo()

What is useMemo()?

While React.memo() is a HOC, useMemo() is a React Hook. With useMemo(), we can return memoized values and avoid re-rendering if the dependencies to a function have not changed.

To use useMemo() within our code, React developers have some advice for us:

  • You may rely on useMemo() as a performance optimization, not as a semantic guarantee
  • Every value referenced inside the function should also appear in the dependencies array

For our next example, we’ll make some changes to our <ParentComponent />. The code below only shows the new changes to the <ParentComponent /> we previously created.

// components/parent-component.js
.
.
import { useState, useEffect, useRef, useMemo } from "react";
import UseMemoCounts from "./use-memo-counts";export default function ParentComponent() {..const [times, setTimes] = useState(0);const useMemoRef = useRef(0);const incrementUseMemoRef = () => useMemoRef.current++;// uncomment the next line to test that <UseMemoCounts /> will re-render every t ime the parent re-renders.// const memoizedValue = useMemoRef.current++;// the next line ensures that <UseMemoCounts /> only renders when the times value changes
const memoizedValue = useMemo(() => incrementUseMemoRef(), [times]);..return (<div className="flex flex-col justify-center items-center border-2 rounded-md mt-5 dark:border-yellow-200 max-w-lg m-auto pb-10 bg-gray-900">..<div className="mt-4 text-center"><buttonclassName="bg-indigo-200 py-2 px-10 rounded-md"onClick={() => setTimes(times+1)}>Force render</button><UseMemoCounts memoizedValue={memoizedValue} /></div></div>);
}

First, we’re bringing in the all-important useMemo() Hook. We’re also bringing in the useRef() Hook to help us track how many re-renders have occurred in our component. Next, we declare a times state that we will later update in order to trigger/force a re-render.

Afterward, we declare a memoizedValue variable that stores the value returned by the useMemo() Hook. The useMemo() Hook calls our incrementUseMemoRef function, which increments the value of our useMemoRef.current by one each time there is a change in the dependencies, i.e., the times value changes.



We then create a button that updates the value of times when clicked. Clicking this button will cause our useMemo() Hook to be triggered, the value of memoizedValue to update, and our <UseMemoCounts /> component to re-render.

For this example, we’ve also renamed our <Counts /> component to <UseMemoCounts />, and it now takes a memoizedValue prop.

Here’s what it looks like:

// components/use-memo-counts.jsfunction UseMemoCounts({memoizedValue}) {return (<div className="mt-3"><p className="dark:text-white max-w-md">I'll only re-render when you click <span className="font-bold text-indigo-400">Force render.</span> </p><p className="dark:text-white">I've now rendered: <span className="text-green-400">{memoizedValue} time(s)</span> </p></div>);
}
export default UseMemoCounts;

Now, when we click any of the cheese buttons, our memoizedValue does not update. But when we click the Force render button, we see that our memoizedValue updates and the <UseMemoCounts /> component re-renders.

Usememo() example

If you comment out our current memoizedValue line, and uncomment out the line above it:

  const memoizedValue = useMemoRef.current++;

…you’ll see that the <UseMemoCounts /> component will re-render each time the <ParentComponent /> renders.

Wrapping up: The major differences between React.memo() and useMemo()

From the example above, we can see the major differences between React.memo() and useMemo():

  • React.memo() is a higher-order component that we can use to wrap components that we do not want to re-render unless props within them change
  • useMemo() is a React Hook that we can use to wrap functions within a component. We can use this to ensure that the values within that function are re-computed only when one of its dependencies change

While memoization might seem like a neat little trick to use everywhere, you should use it only when you absolutely need those performance gains. Memoization uses up memory space on the machine it’s being run on and, as such, may lead to unintended effects.

And that wraps up this article!

You can access the full code for this example on GitHub and a live example here.

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

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

相关文章

菱形

1/定义在同一平面内,有一组邻边相等的平行四边形是菱形如图,四边形 \(ABCD\) 是一个菱形 2/性质 首先,在平行四边形原有的基础上,菱形还有一些特有的性质:对角线互相垂直 \(\because \text{平行四边形}ABCD\) \(\therefore AO = OC, BO = OD\) \(\because AB = BC\) \(\th…

个人练习前端技术使用Bootstrap、JQuery、thymeleaf

个人练习前端技术使用Bootstrap、JQuery、thymeleaf说明:本代码只是为了本人练习前后端联动技术,包含html,jquery,thymeleaf模板、ajax请求及后端功能联动,方便自己查找及使用。@目录代码场景场景1.table批量查询功能(有默认值),点击"查询最新数据"从后台查询…

uBlocklist屏蔽垃圾搜索结果

近年来特别是 Google 的中文搜索结果体验越来越差,出现了越来越多「不知所谓」的网站,这些网站通过机器翻译、直接复制的方式「拼接」而成一个网站占据了大量的搜索结果,这类网站就是——「内容牧场」。 什么是内容牧场 内容农场(或内容工厂,英文名为 content farm)是指生…

正则表达式如何匹配中文

正则表达式如何匹配中文\w匹配的仅仅是中文,数字,字母,对于国人来讲,仅匹配中文时常会用到,见下 匹配中文字符的正则表达式:[\u4e00-\u9fa5]或许你也需要匹配双字节字符,所谓“双字节字符”就是长度是两个字节(byte)的字符,比如“嗨”、“!”、“。”,汉字及中文标…

windows下电脑自定义磁盘图标,u盘图标,文件夹图标

闲言 更改图标要确定有ico(icon)格式图片文件, 文件比例1:1, 一般像素大小比例推荐128:128 确保文件后缀有显示目录闲言寻找或制作ico图片直接下载网络图片制作ico文件在线制作本地制作ico磁盘/U盘图标更改文件夹图标更改 寻找或制作ico图片 直接下载网络图片 这里推荐阿里巴巴…

Macbook M1下安装elasticsearch

一、下载安装包(Kibana 的版本需要和 Elasticsearch 的版本一致。这是官方支持的配置。) 地址分别为:ElasticSearch:https://www.elastic.co/cn/downloads/elasticsearch kibana:https://www.elastic.co/cn/downloads/kibana对于Mac M1芯片基于ARM架构应该选择Aarch64(另…

博客园sakura主题只显示每天一篇或者显示不完随笔bug的修复

关于主题只显示每天第一个博文的的bug 问题 在布置sakura博客园主题的时候,发现这个主题只会显示每一天发布的博文中最晚发布的,其他的就不发了,很奇怪。去去翻了这个主题作者的博文也说了有这bug,但由于这个主题一直没更新,所以也一直没修复。因为比较喜欢这个主题,也抱…

element Plus 设置主题背景色

其主要通过给html动态的添加一个dark类。 主要要通过dom获取html标签,然后给html标签设置className 需要在main.ts中引入dark所在的css文件:具体可以参考element Plus的官网

基于ACO蚁群优化的VRPSD问题求解matlab仿真,输出规划路径结果和满载率

1.程序功能描述 基于ACO蚁群优化的VRPSD问题求解matlab仿真,输出ACO优化的收敛曲线,规划路径结果和每一条路径的满载率。 2.测试软件版本以及运行结果展示MATLAB2022a版本运行 3.核心程序%搜索 for i=1:Iteration iis_best=0; for j=1:Npop%蚂蚁搜索一次Ants …

六自由度Stewart控制系统matlab仿真,带GUI界面

1.课题概述六自由度Stewart平台控制系统是一种高精度、高稳定性的运动模拟装置,广泛应用于飞行模拟、汽车驾驶模拟、虚拟现实、精密定位等领域。其工作原理基于Stewart机构(也称为并联机构)的设计理念,通过六个独立的线性致动器(通常为液压缸或电动推杆)连接固定基座与移…

20241106-语音视频转文字的测试及其价格

一、绘影Ai字幕价格 个人专业版本60元, 商用大约一个120元,支持批量。 二、手机app 讯飞语音、语音转文字等 讯飞听见迅捷转语音 https://www.bilibili.com/read/cv21023516/ 功能 价格 视频、语音转文字的原理 涉及的模型 感悟: 我使用33字幕本地识别,实在太废时间了。我…

javascript模块 (Module) 简介

https://blog.csdn.net/chehec2010/article/details/119804381随着ES6的出现,js模块已经成为正式的标准了。曾经为了解决js模块问题而发展起来的民间秘籍,requireJs(AMD)、SeaJs(CMD)、Node(CommonJs),已经或者不久的将来会成为历史。了解历史也是很重要的,因为正式标准就是…