先看一下官方对于useCallback的定义:
useCallback是一个允许你在多次渲染中缓存函数的React Hook
这句话包含了俩个因素:
- useCallback的作用:缓存函数
- useCallback的使用场景:多次渲染下
什么叫多次渲染呢?组件嵌套的时候会存在多次渲染,如下:
import React, { useState, useCallback, memo} from 'react';
const Child = (props) => {
    console.log('子组件渲染了')
    const {childCount} = props;
    return (
        <div>
            <h1>子组件:{childCount}</h1>
        </div>
    )
}
const Parent = () => {
    console.log('父组件渲染了')
    const [count, setCount] = useState(0);
    const [childCount, setChildCOunt] = useState(0)
    return (
        <div>
            <h1>父组件:{count}</h1>
            <button onClick={()=>{setCount(count+1)}}>点击父组件值加一</button>
            <Child childCount={childCount}/>
        </div>
    )
}
export default Parent;

通过这个例子,我们能看到,当父组件中的state发生变化的时候,子组件也会触发渲染,即使变化的state并没有作为props传入子组件
如何解决这个问题呢?React.memo登场,只需要将Child用memo包裹,如下:
const Child = memo((props) => {
    console.log('子组件渲染了')
    const {childCount} = props;
    return (
        <div>
            <h1>子组件:{childCount}</h1>
        </div>
    )
})
memo 允许你的组件在 props 没有改变的情况下跳过重新渲染(注意默认是浅比较)
 但是如果传入子组件的props中包含了一个函数的话,会发生什么事呢?
import React, { useState, useCallback, memo} from 'react';
const Child = memo((props) => {
    console.log('子组件渲染了')
    const {childCount,watchChildCount} = props;
    //执行传入的watchChildCount
    watchChildCount()
    return (
        <div>
            <h1>子组件:{childCount}</h1>
        </div>
    )
})
const Parent = () => {
    console.log('父组件渲染了')
    const [count, setCount] = useState(0);
    const [childCount, setChildCount] = useState(0)
    //给子组件传入一个函数
    const watchChildCount = () => {
        console.log(childCount,'打印childCount')
    }
    return (
        <div>
            <h1>父组件:{count}</h1>
            <button onClick={()=>{setCount(count+1)}}>点击父组件值加一</button>
            <Child childCount={childCount} watchChildCount={watchChildCount}/>
            <button onClick={() => {setChildCount(childCount+1)}}>点击子组件值加一</button>
        </div>
    )
}
export default Parent;
此时你再点击 父组件值加一 的这个按钮,会发现,即使子组件已经被memo包裹了,子组件还是触发了渲染
这是因为,组件每次渲染的时候,其中的函数都会被重新创建,React.memo使用的是浅比较,所以看似作为props的fn没有发生变化,其实它已经是一个新的fn了
如何解决这个问题呢?useCallback登场
const watchChildCount = useCallback(() => {
    console.log(childCount,'打印childCount')
},[childCount])
useCallback能够将函数缓存起来,只依赖于给定的状态值来确定该函数是否需要重新创建,避免父组件每次更新都创建的这种情况
以上代码都是即粘即用的,感兴趣的可以自己cra一个react项目,去试一下



















