• React@16.x(27)useCallBack


    1,引入

    先来看一个例子:

    1.1,举例:

    import React, { PureComponent, useState } from "react";
    
    class Child extends PureComponent {
        render() {
            console.log("child render");
            return (
                <>
                    <div>{this.props.txt}</div>
                    <button onClick={this.props.onClick}>改变txt</button>
                </>
            );
        }
    }
    
    export default function App() {
        console.log("App render");
        const [txt, setTxt] = useState("abc");
        return (
            <Child
                txt={txt}
                onClick={() => {
                    setTxt(Math.random());
                }}
            ></Child>
        );
    }
    

    注意,子组件是类组件,并且使用了 PureComponent,所以每次 props 改变,也就是点击按钮都会输出:

    App render
    child render
    

    现在修改父组件,增加了一个状态的改变:

    export default function App() {
        console.log("App render");
        const [txt, setTxt] = useState("abc");
        const [n, setN] = useState(0);
        return (
            <>
                <Child
                    txt={txt}
                    onClick={() => {
                        setTxt(Math.random());
                    }}
                ></Child>
                <input
                    type="number"
                    value={n}
                    onChange={(e) => {
                        setN(e.target.value);
                    }}
                />
            </>
        );
    }
    

    理论上来说,状态变量 n 发生变化时,父组件会重新渲染打印 App render 没有问题。但子组件的不会有打印,因为传递给它的状态没有改变

    可状态变量 n 发生变化时,会打印:

    App render
    child render
    

    其实问题出现在 this.props.onClick 上了,注意到传递给它的是一个函数,而在父组件重新渲染时,会产生一个新的函数
    此时对子组件来说,函数的引用地址发生了变化,所以 PureComponent “失效了”。

    <Child
       txt={txt}
        onClick={() => {
            setTxt(Math.random());
        }}
    ></Child>
    

    1.2,新的问题

    接着会发现,无论怎么做,传递给子组件的都是一个新的函数:

    写法1:

    export default function App() {
        // ...
        // App 组件重新调用,会重新生成新函数。
        function handleClick() {
            setTxt(Math.random());
        }
        return (
            <>
                <Child txt={txt} onClick={handleClick}></Child>
                { // ... }
            </>
        );
    }
    

    写法2:

    每次还是新的函数。

    function handleClick(setTxt) {
        setTxt(Math.random());
    }
    
    export default function App() {
        // ...
        return (
            <>
                <Child txt={txt} onClick={() => handleClick(setTxt)}></Child>
                { // ... }
            </>
        );
    }
    

    所以,需要一个方法,能够将函数的引用值固定,不要每次渲染都是新函数,才能解决这个问题。

    2,useCallBack 介绍

    作用:用于得到一个固定引用值的函数。通常用它来进行性能优化。

    使用:接收2个参数,

    1. 参数1函数,useCallBack 会固定该函数的引用,只要依赖项(参数2)没有发生变化,则使用返回之前的函数地址。
    2. 参数2数组,依赖项。
    3. 返回值,固定函数的引用地址。

    可以看到,和 useEffect 很像。依赖项不发生变化,第1个函数不会再次执行。

    改造上面的例子

    import React, { useCallback } from "react";
    
    export default function App() {
        // ...
        const handleClick = useCallback(() => {
            setTxt(Math.random());
        }, []);
        return (
            <>
                <Child txt={txt} onClick={handleClick}></Child>
                { // ... }
            </>
        );
    }
    

    第2个参数传不传 [txt] 效果是一样的。
    因为如果传递 txt,则只有 txt 发生变化,才会返回新函数。


    以上。

  • 相关阅读:
    详解容灾恢复过程中跨数据中心级的关键故障切换
    记录:移动设备软件开发(Activity的显式启动和隐式启动)
    SpringBoot的自动装配源码分析(2022.11.07)
    实用工具推荐--GIF动图裁剪工具IIMG(免注册且免费)
    React从入门到精通
    美创这款产品入选《2022年度浙江省首版次软件产品应用推广指导目录入围名单》
    C++是如何从代码到游戏的
    数学建模-插值算法、拟合算法
    【飞桨PaddleSpeech语音技术课程】— 语音识别-定制化识别
    mysql5.7停止维护时间
  • 原文地址:https://blog.csdn.net/qq_40147756/article/details/139579859