React.memo()、useCallback()、useMemo() 区别及基本使用

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React.memo()、useCallback()、useMemo() 区别及基本使用相关的知识,希望对你有一定的参考价值。

参考技术A 先来看个简单的例子

当我们点击父组件按钮时,父组件的状态 parentCount 会被更新,导致父组件重新渲染,子组件也会重新渲染;而此时我们的子组件和父组件之间并没有依赖关系,因此这种重复渲染是可以优化掉的,可以使用 React.memo 包裹子组件

对外部而言, React.memo 会检查 props 的变更,仅当传入的 props 发生变化时组件才会重新渲染,这时我们再点击父组件按钮,子组件就不会重新渲染了

修改下我们的例子,注意这里用 React.memo 包裹了子组件,保证测试时子组件重新渲染只受传入的 props 变化的影响

点击第一个按钮,依赖项变更,输出重新执行了计算,点击第二个按钮,因为更改的不是计算值的依赖项,因此不会重新计算,子组件也不会重新渲染

当点击第二个按钮时,子组件也会重新渲染

给 computedFn 加上 useCallBack

这时再点击父组件第二个按钮子组件,子组件不会重新渲染,因为 useCallback 的依赖项没变更,返回的是上一次渲染的函数,因此传入子组件的props没变,组件不会重新渲染

看看官方介绍

可以理解为:用 useRef 创建的对象有个 current 属性,这个属性就像个盒子,啥都能存,包括 DOM 节点;返回的 ref 对象在组件的整个生命周期内保持不变,即存在 current 的值不受组件重新渲染影响,始终保持着一开始的引用;同时该属性的变更也不会触发组件的重新渲染;这个属性的初始值为 useRef 的参数

看看官方例子

当把 useRef 创建的对象传给 DOM 元素的 ref 属性时,react会把当前 DOM 元素的引用存入 current 属性,这样就可以通过ref对象直接操作 DOM 元素了

react——useMemo——useCallback——性能优化——React.memo

useMemo缓存计算结果值

记忆组件,可以理解为计算属性(它是类组件中的memoizeOne组件是一样的,只不过,useMemo是内置功能,无需安装) 性能优化


useMemo它可以对于【数值】进行缓存,如果你的依赖项没有发生改变,则下一次调用时,读取上一次的缓存,从而提升性能。


使用的方法:

  • 将计算函数放入useMemo,作为参数一,缓存计算结果
  • 如果useMemo参数2为一个空数据,则它只会执行一次,后续它所计算的变量的值发生的改变,它也不会重新计算,因为它没有依赖
  • 如果参数2中的数组为多个元素,则其中任意一个元素发生了改变,则它都会重新计算一次
import React,  useMemo, useState  from 'react'
const App = () => 
    const [num1, setNum1] = useState(1)
    const [num2, setNum2] = useState(2)
    const sum = () => 
        console.log('fn')/* 买菜 */
        return num1 + num2
    
    const sum1 = useMemo(() => 
        console.log('useMemo')
        return num1 + num2
      , [num1, num2])
    
    return (
        <div>
            <h1>执行三次</h1>
            <div>sum()</div>
            <div>sum()</div>
            <div>sum()</div>
            <hr />
            <h3>useMemo计算出来的数值</h3>
            <div>sum1</div>
            <div>sum1</div>
            <div>sum1</div>

            <button onClick=() => setNum1(v => v + 1)>修改num1值</button>
      		<button onClick=() => setNum2(v => v + 1)>修改num2值</button>
        </div>
    );


export default App;

useCallback 它是用来缓存函数的

如果给 子组件一个方法,用来修改父组件的数据。那么每执行一次,父组件就会重新赋值一次方法给 子组件。子组件也就要重新渲染。

import React,  useCallback, useState, useEffect  from 'react'
const Child = ( addCount ) => 
    useEffect(() => 
        console.log('更新了 addCount')
    , [addCount])

    return (
        <div>
            <h3>Child组件</h3>
            <button
                onClick=() => 
                    addCount(1)
                
            >
                修改count值 -- Child组件
            </button>
        </div>
    )


const App = () => 
    const [count, setCount] = useState(100)

	在没有缓存此函数时,App组件重新执行后,它会再次赋值一次
    const addCount = n => 
        console.log('addcount')
        setCount(v => v + n)
    
    return (
        <div>
            <h3>App -- count</h3>
            <Child addCount=addCount />
        </div>
    )

export default App

useCallback来缓存函数

import React,  useCallback, useState, useEffect  from 'react'
import _ from 'lodash'
// useCallback 它是用来缓存函数的
const Child = ( addCount ) => 
    useEffect(() => 
        console.log('更新了 addCount')
    , [addCount])

    return (
        <div>
            <h3>Child组件</h3>
            <button
                onClick=() => 
                    addCount(1)
                
            >
                修改count值 -- Child组件
            </button>
        </div>
    )


const App = () => 
    const [count, setCount] = useState(100)
    const addCount = useCallback(n => 
        setCount(v => v + n)
      , [])
    return (
        <div>
            <h3>App -- count</h3>
            <Child addCount=addCount />
        </div>
    )

export default App

React.memo

React.memo顶层Api方法,它可以用来减少子组件的重复渲染次数,从而提升组件渲染性能.

  • React.memo它是一个只能在函数组件中使用的顶层Api方法
  • shouldComponentUpdate它必须要有一个返回值,true则表示继续渲染,false停止渲染
  • React.memo参数2返回值如果为true则表示停止渲染,false继续渲染
prevProps 旧的props数据   object
nextProps 新的props数据   object
可以比较两者的不同,来决定是否重新渲染
参数2写的回调函数,一般情况下都在props传过来的数据为引用类型,才需要手动来判断,如果是基本类型则不需要写参数2,来手动判断。
import React,  useState, memo  from 'react'
import _ from 'lodash'
const Child = memo(
    ( count ) => 
        console.log('child')
        return (
            <div>
                <h3>child组件 -- count.n</h3>
            </div>
        )
    ,
    (prevProps, nextProps) => _.isEqual(prevProps, nextProps)
)
const App = () => 
    let [count, setCount] = useState( n: 100 )
    let [name, setName] = useState('张三')

    return (
        <div>
            <h3>App -- count.n</h3>
            <input type="text" value=name onChange=e => setName(e.target.value) />
            <button
                onClick=() => 
                    setCount( n: Date.now() )
                
            >
                ++++
            </button>
            <Child count=count />
        </div>
    )


export default App

以上是关于React.memo()、useCallback()、useMemo() 区别及基本使用的主要内容,如果未能解决你的问题,请参考以下文章

React性能优化之memo,useMemo,useCallback的使用与区别

react——useMemo——useCallback——性能优化——React.memo

react——useMemo——useCallback——性能优化——React.memo

1024用代码改变世界useMemo 和 useCallback|React.memo使用场景

[React] Preventing extra re-rendering with function component by using React.memo and useCallback(代码

reac中useCallback使用