首页 > 其他分享 >【React系列】React.memo() vs useMemo()

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

时间:2023-10-11 11:45:05浏览次数:41  
标签:渲染 useMemo memo React Child 组件

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

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

本文将比较和对比React.memo和useMemo(),同时讨论它们的用例。
 
  • 1
  • 2
  • 3
  • 4

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

理解我们为什么需要React.memo()和useMemo()的最好方法是看看React是如何在没有记忆化的情况下重新呈现组件的。
为此,让我们考虑一个有两个React组件的简单例子。第一个组件是父组件。它有一个按钮,可以增加计数变量的值。
 
  • 1
  • 2
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>
  )
}
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
第二个组件是子组件,它显示从父组件传来的名字。
 
  • 1
import React, { Component } from 'react'

export default function Child(props) {
  console.log('Child Render')
  return (
    <div>
      <h2>{props.name}</h2>
    </div>
  )
}
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
一旦用户点击 "增加计数 "按钮,计数就会增加,这将导致父组件的重新渲染.
在这里,count变量的值变化并不影响props传递到子变量,子组件也不应该重新渲染。
在这里如果你业务代码逐渐开始多了,然后里面刚刚好采用了这种方式去开发对应的业务代码,页面的性能可想而知,会根据代码的增量而成反比。
 
  • 1
  • 2
  • 3

在这里插入图片描述
从上述所见,不难看出每当父组件被重新渲染时,子组件的渲染方法也被调用。这将触发子组件的虚拟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)
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

当我们点击增加计数按钮,子组件不会重现的,应用程序将重用前面呈现输出。
在这里插入图片描述
重要的是要记住,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);
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

什么是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>
  )
}
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

这表明在父组件中,我们正在使用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)
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

在这里插入图片描述

由于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在一个功能组件中对一个值进行备忘。

 

标签:渲染,useMemo,memo,React,Child,组件
From: https://www.cnblogs.com/sexintercourse/p/17756704.html

相关文章

  • React Hooks之useRef详解
    ReactHooks之useRef详解最新推荐文章于 2023-08-2621:32:11 发布RayShyy于2023-02-1810:23:20发布2717收藏5分类专栏:React文章标签:react.jsHookHooksuseRefref版权React专栏收录该内容4篇文章0订阅订阅专栏......
  • 前端进阶系列——理解 React Ref
    前端进阶系列——理解ReactRef秦书羽杭州@朝夕光年​关注他 17人赞同了该文章Ref是Reference(引用)的缩写。一、前言在React中通常遵循“自上而下”的“单向数据流”。父组件和子组件的通讯只能通过Props。如果要修改一个子组件,我们要修改......
  • React跨路由组件动画
    我们是袋鼠云数栈UED团队,致力于打造优秀的一站式数据中台产品。我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值。本文作者:佳岚回顾传统React动画对于普通的React动画,我们大多使用官方推荐的react-transition-group,其提供了四个基本组件Transition、CSSTr......
  • 盘点KendoReact五大功能,让JavaScript数据网格构建更轻松!
    在本文中,我们将为大家分享KendoReact DataGrid中最受欢迎的五大功能:性能、数据组织、列和行交互、编辑自定义以及导出。有了这些功能,开发者大可不必从头开始构建JavaScript数据网格了!KendoUI是带有jQuery、Angular、React和Vue库的JavaScriptUI组件的最终集合,无论选择哪种Jav......
  • 如何编写难以维护的 React 代码?耦合通用组件与业务逻辑
    在众多项目中,React代码的维护经常变得棘手。其中一个常见问题是:将业务逻辑直接嵌入通用组件中,导致通用组件与业务逻辑紧密耦合,使其失去“通用性”。这种做法使通用组件过于依赖具体业务逻辑,导致代码难以维护和扩展。示例:屎山是如何逐步堆积的让我们看一个例子:我们在业务组件Pag......
  • useState() and useEffect() in react
    foruseState(),see:https://www.freecodecamp.org/news/usestate-vs-redux-state-management/  foruseEffect(),see: https://www.freecodecamp.org/news/react-useeffect-absolute-beginners/简单说就是:当前component之行完毕后会之行useEffect定义的第一个参数的函......
  • [完结16章]React18内核探秘:手写React高质量源码迈向高阶开发
    点击下载——[完结16章]React18内核探秘:手写React高质量源码迈向高阶开发  提取码:8epr手写React高质量源码,迈向高阶开发React18内核探秘:手写React高质量源码迈向高阶开发batching批处理,说的是,可以将回调函数中多个setState事件合并为一次渲染,因此是异步的。解决的问题是......
  • CUDA_ERROR_OUT_OF_MEMORY: out of memory
     2023-02-0422:17:02.457962:Itensorflow/stream_executor/cuda/cuda_driver.cc:831]failedtoallocate152.00M(159383552bytes)fromdevice:CUDA_ERROR_OUT_OF_MEMORY:outofmemory 查看GPU内存使用情况:nvidia-smi   命令行如何查看GPU的内存使用情况?......
  • React 大师版
    第一部分一、todoList案例相关知识点 1.拆分组件、实现静态组件,注意:className、style的写法 2.动态初始化列表,如何确定将数据放在哪个组件的state中? ——某个组件使用:放在其自身的state中 ——某些组件使用:放在他们共同的父组件state中(官方称此操作为:状态提升) 3.关于......
  • 创建vue3项目、setup函数、ref函数、reactive函数、计算监听属性、生命周期、torefs、
    创建vue3项目#两种方式-vue-cli:vue脚手架---》创建vue项目---》构建vue项目--》工具链跟之前一样-vite:https://cn.vitejs.dev/-npmcreatevue@latest一路选择即可#运行vue3项目-vue-cli跟之前一样-vi......