首页 > 其他分享 >React.memo vs. useMemo: Major differences and use cases

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

时间:2024-11-06 23:08:22浏览次数:1  
标签:Major useMemo memo component React re our

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">
          <button
            className="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.js

function 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.

标签:Major,useMemo,memo,component,React,re,our
From: https://www.cnblogs.com/saaspeter/p/18531247

相关文章

  • [Memory leak] 3. Garbage collection in Closure
    Examplecode:functioncreateIncrease(){constdoms=newArray(100000).fill(0).map((_,i)=>{constdom=document.createElement('div');dom.innerHTML=i;returndom;});functionincrease(){doms.forEach((dom)=&g......
  • [Memory Leak] 1. console.log cause memory leak
    Examplecode:<template><button@click="handleClick">Hello,Vue-CLI</button></template><script>exportdefault{methods:{handleClick(){constarr=newArray(100000).fill(0);console.log(......
  • clickhouse 异常提示 DB::Exception: Memory limit (total) exceeded
    新建的测试环境,内存比较少,登录后显示如下提示信息:#clickhouse-clientClickHouseclientversion24.9.2.42(officialbuild).Connectingtolocalhost:9000asuserdefault.Passwordforuser(default):Connectingtolocalhost:9000asuserdefault.ConnectedtoCli......
  • DATA 2100 Major Python Programming
    DATA2100MajorHomeworkPythonProgramming100pointsPurposeInthisassignment,studentswillapplytheir(Python)programmingskillstodevelopadataentryapplicationthatvalidatesentriesagainstadatabaseandthenrecordsvalidentriestothesamed......
  • Dedecms后台 Fatal error:Allowed memory size of 8388608 bytes 提示的解决方法
    修改 .htaccess 文件在 .htaccess 文件的最上面添加:php_valuemax_execution_time1200php_valuememory_limit200Mphp_valuepost_max_size200Mphp_valueupload_max_filesize200M修改 php.ini 文件将 memory_limit 的值从 8M 改为 12M 或更......
  • Major GC和Full GC的区别是什么
    MajorGC和FullGC是Java垃圾收集中的两种重要过程。它们的主要区别包括:1.作用范围不同;2.触发条件和时机有所不同;3.对系统性能的影响程度不同;4.处理对象的差异;5.与各种垃圾收集器的关联程度有所差异。理解这两种GC的区别对于Java开发和性能调优都是至关重要的。1.作用范围不同......
  • ERROR: Unexpected bus error encountered in worker. This might be caused by insuf
    简介:使用YOLO11在Docker里面训练,出现一堆报错#ImageWoof数据集分析狗fromultralyticsimportYOLO#Loadamodelmodel=YOLO("yolo11n-cls.pt")#loadapretrainedmodel(recommendedfortraining)#Trainthemodelmodel.train(data="imagewoof160"......
  • memo
    paddleocr的C++推理onnxruntime的C++部署yolo8-seg的C++版onnxruntime推理案例1yolo8-seg的C++版onnxruntime推理案例2paddleocr的C++版onnxruntime推理案例u-net的C++版onnxruntime推理案例......
  • react.js中useMemo和useEffect的区别
    1、当messages发生变化时执行scrollToBottom方法useEffect(()=>{scrollToBottom();},[messages]);constscrollToBottom=()=>{//页面滚动到底部messagesEndRef.current?.scrollIntoView({behavior:"smooth"});}以上例子中,useEffect可以用useMemo代替吗?不可......
  • 面试真题:OOM(OutOfMemoryError)SOF(StackOverflow)你遇到过哪些情况
    前言本来想着给自己放松一下,刷刷博客,慕然回首,OOM?SOF?似乎有点模糊了,那就大概看一下Java面试题吧。好记性不如烂键盘***12万字的java面试题整理***OOM你遇到过哪些情况,SOF你遇到过哪些情况OOM:1,OutOfMemoryError异常除了程序计数器外,虚拟机内存的其他几个运行时区域都有发生......