函数式组件中,使用useCallback对函数进行缓存(被外层函数包裹,相当于闭包),组件再次更新时(函数重新执行)会根据依赖是否变化决定选用缓存函数【之前生成的函数】还是新函数【新生成的上下文】。
一般会在嵌套组件中,与函数式组件的memo和类组件的PureComponent一起使用【会对传入props参数逐个进行浅比较决定是否需要更新】,来提高页面性能。

  1. 传入箭头函数还是普通函数没有影响

  2. useCallback第二个参数决定组件更新是否生成新函数,函数内部使用到的依赖尽可能在第二个参数写全,否则会有意想不到的问题(序列4)。

    何时生成新函数第二个参数
    组件首次执行及更新都会生成新函数
    组件首次执行生成,之后不变[]
    组件首次执行、依赖变化时生成新函数[state, ref.current] 这两类
  3. 嵌套组件中 memo搭配useCallback和不使用useCallback对子组件更新的影响
    (情况1)不使用useCallback时,外层组件每次更新相当于重新生成新函数funcHang,传给子组件。子组件通过memo包裹对传入props参数进行浅比较,发现onClick触发的函数有变化,进而子组件更新。
    在这里插入图片描述
    (情况2)使用useCallback时,第二参数为[],外层组件每次更新时(暂时不考虑依赖)都会复用上次函数。子组件接收到传入props的funcHang没有变化,所以子组件不会发生更新。
    在这里插入图片描述

  4. setxxx更新逻辑:
         当setxxx触发更新时,App函数重新执行(相当于新的作用域),当执行到const funcHang = useCallback(...); useCallback内部会比较之前依赖preDeps和现在依赖nextDeps 是否相等if (areHookInputsEqual(nextDeps, prevDeps));相等true直接返回之前函数,不相等false就返回最新传入的函数。

以下是依赖没写全,导致函数没有及时更新。访问不到最新的数据问题:

  • (步骤0)代码及初始界面: useCallback函数内部使用了count1和count2,可依赖只有count1:

    export function App() {
    	const [count1, setCount1] = useState(0);
        const [count2, setCount2] = useState(0);
       // 当count2发生变化时,触发funcHang内部count2是0;除非count1变化引起生成新函数count2才是最新值
        const funcHang = useCallback(function() {
            console.log("function run:", count1, count2);
        }, [count1]);
        
        return (
        	<div>
        		<h2>params: { count1 } { count2 }</h2>
        		<button onClick={ funcHang }>触发</button>
                <button onClick={ e => { setCount1(pre => pre + 1);} }>update Count1</button>
                <button onClick={ e => { setCount2(pre => pre + 1);} }>update Count2</button>
        	</div>
        )
    }
    

    在这里插入图片描述

  • (步骤1)点击按钮update Count1,再触发。打印输出function run: 1 0
    在这里插入图片描述

  • (步骤2)点击按钮update Count2,再触发。打印输出function run: 1 0
    在这里插入图片描述

  • (步骤3)再次点击按钮update Count1,再触发。打印输出function run: 2 1
    在这里插入图片描述

    分析:

    • 当count1变化,useCallback内部依赖比较发生变化,返回false,返回当前执行App上下文包裹的函数。
    • 当count2变化,useCallback内部依赖比较没有变化,返回true,返回之前App上下文包裹的函数。

    总结:函数使用的是生成时所处App上下文中的数据,注意函数何时会被更新;

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐