• React.memo()、useCallback()和useMemo()的用法--性能优化--缓存


    React的性能优化的途径之一是对组件、函数和函数的执行结果进行缓存,让组件在重新渲染的时候避开一些不必要的代码执行。

    React.memo()、 钩子函数useCallback和useMemo对react中的组件、函数、函数执行结果进行了缓存的实现。

    React.memo()

    react组件发生重新渲染的情况:

    • 组件的自身的state发生了变化。
    • 该组件的父组件重新渲染会引发子组件的重新渲染。

    父组件每次重新渲染都触发子组件的重新渲染有的时候是没有必要的,即当子组件的内部数据不依赖于父组件此次的重新渲染,那么我们就没有必要去对子组件进行重新渲染。即有的组件无论如何渲染,每次的渲染结果都是相同的,很显然这种渲染是完全没有必要的。
    为了减少这种组件的渲染,React提供了一个高阶函数React.memo(),可以用来根据组件的props对组件进行缓存。

    import React, {useState } from 'react'
    import ComA from './ComA';
    
    export default function index() {
        const [count,setCount] = useState(1);
        const handleAddBtn = useCallback(() => {
            setCount(prevState=>prevState+1)
        },[])
      return (
          <div>
              <h1>美好生活的缔造者!{count}</h1>
              <button onClick={handleAddBtn}>+</button>
              <ComA />
          </div>
      )
    }
    import React from 'react'
    
    function ComA() {
        console.log('A组件重新渲染了')
      return (
          <div>
              <h2>我是组件A</h2>
          </div>
      )
    }
    
    export default React.memo(ComA);
    
    • 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
    • 28

    上面的代码中,当父组件重新渲染并不会引起子组件ComA的重新渲染,这就是Reat.memo()高阶函数的作用。
    使用了React.memo()的组件当它的父祖辈组件发生重新渲染,而子组件的props没有发生变化时,它会直接将缓存中的组件渲染结果返回而不是再次触发该子组件的重新渲染,这样一来就大大的降低了子组件重新渲染的次数。
     用法:不直接将组件进行导出,而是在组件的外层套上一层React.memo()函数,这样的话,该组件就具有了缓存功能。
     总结:React.memo主要是为了避免渲染父组件,而子组件不需要进行重新渲染的情况下,对该组件进行一个缓存,而不是每次重新渲染父组件的时候,该组件都进行重新渲染。
    当父祖辈组件进行重新渲染的时候,React.memo()包裹的子组件只会根据props判断是否也需要重新渲染,和state无关,当前组件的state发生变化时,组件依然会正常的进行重新渲染。
    只有当该组件的props属性发生变化时,才会触发组件的重新渲染,即React.memo()是用来缓存组件的。

    被 React.memo 包装的组件,在父组件重新渲染的时候(前提),React.memo方法会对 props 做一个浅层比较,如果 props 没有发生改变,则不会重新渲染此组件。

    在这里插入图片描述

    useCallback记忆函数

    在前面的React.memo()我们已经对组件进行了缓存,但是如果父组件给子组件传递的是一个 函数,那么当父组件进行重新渲染的时候,子组件还是会跟着进行重新渲染。那应该怎么办呢?
    因为父组件重新渲染的时候,组件中的相应函数也会重新创建一遍,导致我们props里面传递的函数的值发生了改变,所以子组件在使用React.memo的情况下,依然进行了重新渲染。所以就要使用我们的useCallback钩子函数。
    缓存函数,提高性能,为了优化react性能。
    useCallback是一个钩子函数,用来创建React中的回调函数。

    在函数组件体中定义的函数会在每次函数组件重新渲染中进行重新创建,所以为了缓存函数,不需要每次渲染组件的时候都去创建它。useCallback是对我们的回调函数(响应函数)做了一个缓存,不必要每次都去创建一个新的函数。

    在函数组件体中定义的函数会在每次函数组件重新渲染中进行重新创建,所以为了缓存函数,不需要每次渲染组件的时候都去创建它。 内联回调函数和依赖项数组作为参数,该回调函数仅在某个依赖项改变时才会更新。
    之前普通的函数会在组件每次重新渲染的时候进行重新创建,在内存中生成一个具有新的引用地址的函数。
    组件执行一次,组件内部定义的函数就会重新执行一次,使用useCallback就可以避免这个问题。
    useCallback创建的回调函数不会总在组件重新渲染时重新创建。

    const handleAddBtn = useCallback(() => {
            setCount(prevState=>prevState+1)
        },[])
    
    • 1
    • 2
    • 3

    useCallback的第二个参数用来指定依赖项。

    • 当依赖数组中的变量发生变化时,回调函数才会重新创建。
    • 一定要将回调函数中使用到的所有变量都设置到依赖数组中,这样才能确保在变量发生变化的时候,函数进行重新创建,除了setState…
    • 如果不指定依赖数组,回调函数会在组件每次渲染的时候都会重新创建,这样就失去了它的意义了。
    • 如果依赖数组是一个空数组,回调函数则只会在组件初始化渲染的时候创建一次。
    • 在实现减少不必要渲染的优化过程中,useCallback和React.memo是一对利器。

    useMemo记忆值

    useMemo和useCallback十分相似,主要区别在于useMemo返回一个记忆值,useCallback返回一个记忆函数。即useCallback用来缓存函数对象,useMemo用来缓存函数的执行结果。

    在函数组件中,有一些函数实现了很复杂的逻辑,执行速度比较慢,所以为了避免这种执行速度很慢的函数重新执行,我们可以把这种函数的执行结果通过useMemo来进行缓存。

    const result = useMemo(()=>{
        return 复杂逻辑函数();
    },[依赖项])
    
    • 1
    • 2
    • 3

    useMemo中的函数会在依赖项发生变化时执行,注意!是执行,这点和useCallback不同,useCallback是创建。执行后返回执行结果,如果依赖项不发生变化,则一直会返回上次的结果,不会再执行函数。这样一来就避免复杂逻辑的重复执行。

    总结

    React.memo()用来缓存组件。
    useCallback用来缓存一个函数。
    useMemo用来缓存一个函数的执行结果。

  • 相关阅读:
    PHP笔记 28 29 30 31
    Python决策树
    xml转txt,划分数据集(train、test、val)
    【使用工具在Vs-code/WebStorm构建Vue项目】
    Oracle/PLSQL: Covar_samp Function
    网上花店销售系统(附源码+课件+讲解+资料+数据库)
    1022 D进制的A+B
    AI,如何让照片中的表情动起来
    nodejs系列-使用nodejs链接MongoDB数据库问题总结
    Mysql 性能分析(慢日志、profiling、explain)、读写分离(主从架构)、分库分表(垂直分库、垂直分表、水平分表)
  • 原文地址:https://blog.csdn.net/weixin_45012866/article/details/127420328