zoukankan      html  css  js  c++  java
  • React Hooks: useCallback理解

    useCallback把匿名回调“存”起来

    避免在component render时候声明匿名方法,因为这些匿名方法会被反复重新声明而无法被多次利用,然后容易造成component反复不必要的渲染。

     在Class component当中我们通常将回调函数声明为类成员:

    class MyComponent extends React.Component {
        constructor(props) {
            super(props);
            this.clickCallback = this.clickCallback.bind(this);
        }
        clickCallback() {
            // ...
        }
        render() {
            return <button onClick={this.clickCallback}>Click Me!</button>;
        }
    }

    使用useCallback hook就可以避免bind操作:

    function MyComponent(props) {
        const clickCallback = React.useCallback(() => {
            // ...
        }, []);
        return <button onClick={clickCallback}>Click Me!</button>;
    }

    useCallback缓存函数

    const fnA = useCallback(fnB, [a])
    

      上面的useCallback会将我们传递给它的函数fnB返回,并且将这个结果缓存;当依赖a变更时,会返回新的函数。既然返回的是函数,我们无法很好的判断返回的函数是否变更,所以我们可以借助ES6新增的数据类型Set来判断,具体如下:

    import React, { useState, useCallback } from 'react';
     
    const set = new Set();
     
    export default function Callback() {
        const [count, setCount] = useState(1);
        const [val, setVal] = useState('');
     
        const callback = useCallback(() => {
            console.log(count);
        }, [count]);
        set.add(callback);
     
     
        return <div>
            <h4>{count}</h4>
            <h4>{set.size}</h4>
            <div>
                <button onClick={() => setCount(count + 1)}>+</button>
                <input value={val} onChange={event => setVal(event.target.value)}/>
            </div>
        </div>;
    }

    我们可以看到,每次修改count,set.size就会+1,这说明useCallback依赖变量count,count变更时会返回新的函数;而val变更时,set.size不会变,说明返回的是缓存的旧版本函数。

    使用场景:

    有一个父组件,其中包含子组件,子组件接收一个函数作为props;通常而言,如果父组件更新了,子组件也会执行更新;但是大多数场景下,更新是没有必要的,我们可以借助useCallback来返回函数,然后把这个函数作为props传递给子组件;这样,子组件就能避免不必要的更新。

    import React, { useState, useCallback, useEffect } from 'react';
    function Parent() {
        const [count, setCount] = useState(1);
        const [val, setVal] = useState('');
     
        const callback = useCallback(() => {
            return count;
        }, [count]);
        return <div>
            <h4>{count}</h4>
            <Child callback={callback}/>
            <div>
                <button onClick={() => setCount(count + 1)}>+</button>
                <input value={val} onChange={event => setVal(event.target.value)}/>
            </div>
        </div>;
    }
     
    function Child({ callback }) {
        const [count, setCount] = useState(() => callback());
        useEffect(() => {
            setCount(callback());
        }, [callback]);
        return <div>
            {count}
        </div>
    }

    不仅是上面的例子,所有依赖本地状态或props来创建函数,需要使用到缓存函数的地方,都是useCallback的应用场景。

    useEffect、useMemo、useCallback都是自带闭包的。也就是说,每一次组件的渲染,其都会捕获当前组件函数上下文中的状态(state, props),所以每一次这三种hooks的执行,反映的也都是当前的状态,你无法使用它们来捕获上一次的状态。对于这种情况,我们应该使用ref来访问。

  • 相关阅读:
    远程连接redis服务
    redis的安装以及启动
    Easyui学习之右键菜单easyui-menu
    富文本编辑器KindEditor的使用
    zookeeper启动失败解决方法
    在TortoiseSVN使用clean up
    kettle性能优化
    idea快捷键
    Spring Cloud服务网关 Zuul Filter使用
    添加路由
  • 原文地址:https://www.cnblogs.com/Nyan-Workflow-FC/p/11287276.html
Copyright © 2011-2022 走看看