React Hooks ----useCallback()了解及使用

2,774 阅读4分钟

官网

useCallback 它可以让你在重新渲染之间缓存函数定义。

const cachedFn = useCallback(fn, dependencies)

参数:
fn:要缓存的函数值。它可以接受任何参数并返回任何值。在初始渲染期间,React将返回(不是调用!)你的函数。在下一次渲染时,如果依赖关系自上次渲染以来没有改变,React将再次给你相同的功能。

dependencies: fn代码中引用的所有响应值的列表。响应式值包括props、state以及所有直接在组件内部声明的变量和函数。写法:[dep1, dep2, dep3],内部通过Object.is进行比较。

useCallback 的自身处理

在函数第一次创建,使用useCallback会将该函数地址缓存起来,当组件再次更新的时候,会拿到该地址,再次赋给该函数,类似于一个引用缓存的操作。

const xxx = useCallback(callback,[dependencies])
  • 组件第一次渲染,useCallback执行,创建一个函数“callback”,赋值给xxx
  • 组件后续每一次更新,判断依赖的状态值是否改变,如果改变,则重新创建新的函数堆,赋值给xxx;但是如果,依赖的状态没有更新「或者没有设置依赖“[]”」则xxx获取的一直是第一次创建的函数堆,不会创建新的函数出来!!
  • 或者说,基于useCallback,可以始终获取第一次创建函数的堆内存地址(或者说函数的引用)

使用场景

这个整体来看,就是父组件在给子组件传递参数的时候,不想在每次父组件变化的时候,整体进行渲染,只想对有数据变化的子组件进行渲染 对于在父组件内数据变化,但是变化的数据和传递给部分子组件内的数据并无关系,如果父组件渲染,子组件内也是全部会进行渲染,这个会消耗不必要的性能。

如果子组件内只使用 React.memo ,传递的有props及回调函数,组件内对传递过来的props是可以进行浅比较,如果props一致的话,被React.memo包装的组件就不会渲染,如果不一致,就会渲染。

但是当父组件传递的props是回调函数,父组件每次渲染时给子组件传递的函数都是一个新的函数引用 React.memo 就认为props 发生变化并重新渲染, 起不到优化的作用。

useCallback 就是为了解决这个 React.memo 优化失效的问题, 它会在父组件外部缓存函数, 当父组件渲染时, 会返回函数的缓存, 让 React.memo 能拿到相同的函数引用, 从而让优化生效。

在类组件中, 因为可以通过 this 来获取同一个方法引用来避免这个问题。

操作过程

1.将需要缓存的回调函数经过 useCallback 包裹,返回一个回调函数 2.需要用到改函数的子组组件使用 React.memoReact.pureComponent 3.对传递的回调函数进行校验查看等

例子:

import React, { useState, useCallback } from "react";
import { Button } from 'antd';

const Child = React.memo(function Child({ handle }) {
    console.log('Child Render');
    return <div onClick={() => handle()}>
        我是子组件
    </div>;
});
const Demo = function Demo() {
    let [x, setX] = useState(0);

    const handle = useCallback(() => { }, []);

    return <div className="vote-box">
        <Child handle={handle} />
        <div className="main">
            <p>{x}</p>
        </div>
        <div className="footer">
            <Button type="primary" onClick={() => setX(x + 1)}>累加</Button>
        </div>
    </div>;
};


export default Demo;

运行结果:

图片.png

可以看到,经过操作之后,当父组件变化,但是函数内无变化的情况下,子组件是不会渲染的。

依赖传递 dependencies

图片.png

当内部传递的count变化时,子组件内同步更新

笔记

在父组件给子组件的传值过程中,传递了变量、字符串等及父组件内创建的回调函数等一系列数据,但是 在父组件渲染的过程当中,传递的数据等操作没有任何数据变化的情况下,正常情况是父组件的每次渲染也会导致子组件渲染。

但是我们不想让子组件在数据无变化的时候进行渲染,就需要进行缓存或者是比较操作等 【个人感觉比较类似于 shouldComponentUpdate 判断一下内部值是否一致,一致就渲染等操作,这句纯属个人瞎猜,具体得验证】

React.memo 对传递的props 是进行了浅比较操作,但是对回调函数无法进行操作,产生了 useCallback 弥补这部分回调函数的缓存操作,减少子组件渲染。

总结

useCallback 使用目的:减少回调函数对子组件渲染影响

使用原因React.memo 对传递的回调函数无法判断,传递的函数会导致子组件渲染

使用结果:当传递的回调函数无依赖变化的情况下,每次都是返回第一次创建的值,组件渲染减少

优点:当依赖的值变化才会让相关组件进行渲染,减少了性能消耗

但是 useCallback 不能乱用

不能乱用的原因: 1.如果没设置任何依赖,则函数永远在第一次组件渲染,产生的闭包中创建 2.其本身也有自己的处理逻辑和緩存的机制,这个也消耗时间