• React 正确使用useCallback useMemo的姿势


    正确使用useCallback useMemo的姿势

    说起useCallback useMemo大家肯定在React都不陌生,但是真正了解它们的作用,还是有一部分同学对此是一知半解,只是知道用它,却不知道它真正的含义。今天带大家学习一下它们的真正蕴藏的作用。
    useCallback useMemo 都是记忆函数,什么是记忆函数呢?
    用个最简单的例子来讲 useState 也是记忆函数 细想一下以下代码,为什么setcount每次改变会引起组件重新render,但是count为什么不会再次被初始值0进行赋值呢?如果是这样的话,我们就不能修改成功了,所以说存在某个地方保存了state的值,而这个地方是不会受到render的影响的,state就被缓存起来了。

    const [count, setcount] = useState(0);
    
    • 1

    那么 useCallback useMemo 也是被缓存起来了吗?让我们逐个来看看

    useCallback

    useCallback 的作用是啥?我们来看看下面的代码

    import React, { memo, useCallback, useState } from "react";
    
    const HookTest = memo(() => {
      const [count, setcount] = useState(0);
      const [num, setnum] = useState(100);
      const showCount = () => {
     	console.log("没事执行玩玩", count + "$");
      };
      
    //  const showCount = useCallback(() => {
    //    console.log("没事执行玩玩", count + "$");
    //  }, [count]);
    
     
      return (
        <div>
          <h2>HookTest:useCallback----useMemo</h2>
          <h3>useCallBack</h3>
          <h4>
            count:{count}---num:{num}
          </h4>
          <button onClick={showCount}>showCount</button>
          <button onClick={(e) => setcount(count + 3)}>+3</button>
          <button onClick={(e) => setnum(num * 10)}>*10</button>
      );
    });
    
    export default HookTest;
    
    
    • 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
    • 29

    正常执行的话,修改count 和 num 都会触发 render ,这是毫无疑问的。那么showCount 每次render也会被重新创建一次,这也是情理之中的。
    但是我们想想,真的有必要每次render都重新创建showCount 吗?现在可能只有一个函数,函数体也简单,重新创建也影响不了什么,但是真正开发的时候却是我们要考虑的问题。
    所以 useCallback 来帮我们解决这个问题了!

    import React, { memo, useCallback, useState } from "react";
    
    const HookTest = memo(() => {
      const [count, setcount] = useState(0);
      const [num, setnum] = useState(100);
    //  const showCount = () => {
    // 	console.log("没事执行玩玩", count + "$");
    //  };
      
      const showCount = useCallback(() => {
        console.log("没事执行玩玩", count + "$");
      }, [count]);
    
     
      return (
        <div>
          <h2>HookTest:useCallback----useMemo</h2>
          <h3>useCallBack</h3>
          <h4>
            count:{count}---num:{num}
          </h4>
          <button onClick={showCount}>showCount</button>
          <button onClick={(e) => setcount(count + 3)}>+3</button>
          <button onClick={(e) => setnum(num * 10)}>*10</button>
      );
    });
    
    export default HookTest;
    
    • 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

    useCallback 接收两个参数 第一个为需要缓存的函数 第二个为数组,装载依赖

    那么现在的 showCount 和之前的又有什么不一样呢?
    现在的 showCount 是被缓存起来了,组件render时,如果装载依赖的数组中的依赖未更新,那么依然采用缓存的函数。
    也就是说只有当我点修改count时触发更新组件render后,showCount 也重新创建,但是当我进行其他的操作引起组件render时,由于此时条件依赖跟装载依赖的数组中依赖毫无关系,showCount 用的是缓存里的函数。
    这就是 useCallback 的正确使用方法啦~

    useMemo

    看下面案例

    import React, { memo, useMemo, useState } from "react";
    
    const HookTest = memo(() => {
    const [count, setcount] = useState(0);
      const [arr, setarr] = useState([
        {
          flag: true,
          num: 20,
        },
        {
          flag: false,
          num: 10,
        },
        {
          flag: true,
          num: 40,
        },
        {
          flag: true,
          num: 60,
        },
        {
          flag: true,
          num: 70,
        },
        {
          flag: true,
          num: 80,
        },
      ]);
    
       const allNum = () =>
         arr.reduce(
           (preValue, currentValue) =>
             currentValue.flag ? preValue + currentValue.num : preValue,
           0
         );
    
      return (
        <div>
          <h2>HookTest:useCallback----useMemo</h2>
          <h3>useMemo</h3>
           <h4>
            count:{count}
          </h4>
          <button onClick={(e) => setcount(count + 3)}>+3</button>
          <h4>all:{allNum}</h4>
        </div>
      );
    });
    
    export default HookTest;
    
    
    • 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
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    很简单的小案例,根据条件对数组求和操作
    同样我们点击修改count 然后组件重新render
    此时我们考虑一个问题,是不是 allNum 又进行了一次复杂的运行然后得到结果
    现在看来才几条数据,怎么复杂了,我们得考虑数组若是几百上千上万呢?
    我们都知道组件渲染是很频繁的,那么每次渲染我们真的有必要去每次进行复杂的运算吗?
    所以这就是性能优化的另一个点了 引出 useMemo来帮助我们解决

    将allNum 改造后

    const allNum = () =>
         arr.reduce(
           (preValue, currentValue) =>
             currentValue.flag ? preValue + currentValue.num : preValue,
           0
         );
      
      const allNum = useMemo(
        () =>
          arr.reduce(
            (preValue, currentValue) =>
              currentValue.flag ? preValue + currentValue.num : preValue,
            0
          ),
        [arr]
      );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    useMemo 同样接收两个参数 第一个参数是函数的返回值!! 第二个为数组,装载依赖
    用了之后呢?有那些改变呢?
    现在 allNum 不再是一个函数了,而是一个返回值
    现在如果进行和依赖数组无关的render时,allNum 将采用上次缓存的返回值,不用再去傻傻的计算一遍啦。

    这就是 useMemo 的正确使用方法啦~

    总结

    简单给大家总结下
    useCallback 缓存函数
    useMemo 缓存函数返回值
    都是解决组件频繁渲染从而频繁创建函数及频繁运行函数
    正确的思路应该是 跟我有关的时候我才需要去重新创建函数及重新运行函数
    跟我无关的时候,直接拿上一次的缓存结果就行啦!

    求赞!!!

    在这里插入图片描述

  • 相关阅读:
    超详细的三星全系列机型线刷图文教程和相关注意操作常识 二
    swagger2文档基于knife4j 2.0.5二次封装工具
    Python | Leetcode Python题解之第199题二叉树的右视图
    论文阅读 (69):Collaborative Learning for Deep Neural Networks
    NSFC申请不中的反思 (内部讨论)
    阿里云oss丨You have no right to access this object because of bucket acl.
    Python实现猎人猎物优化算法(HPO)优化BP神经网络分类模型(BP神经网络分类算法)项目实战
    REST API设计原则:构建可扩展、易维护的 API
    maven创建父子依赖项目—pom
    Spark rdd之mappartition妙用
  • 原文地址:https://blog.csdn.net/kzj0916/article/details/126195000