react 【useMome、useCallback原理详解】

前言

  useMome和useCallback实现原理完全一致

 useMemo(() => fn, []);
    //等效于
 useCallback(fn, []);

不同的点

  useCallback

//第一个参数接收一个函数,useCallback调用后返回一个新的被缓存的记忆函数
useCallback(fn, []); //return 一个新的function

  useMemo

 //第一个参数接收一个函数,useMemo调用后返回第一个参数函数return的被缓存的记忆的值
useMemo(() => fn, []); //return 一个fn的记忆function
useMemo(() => obj, []); //return 一个obj的记忆Object

作用影响

  测试代码

function Home() {
  const [state, setState] = useState("initialization");

  //普通函数
  const fn = () => {
    console.log("普通函数输出:", state);
  };

  //记忆函数,这里第二个参数设置为[],表示不依赖任何值,只在组件初始化时创建memoizedFn,组件更新时不更新memoizedFn
  const memoizedFn = useCallback(() => {
    console.log("memoized函数输出:", state);
  }, []);

  //组件Home,mount 和 update时都执行
  fn();
  memoizedFn();

  const update = () => {
    setState("initialization" + new Date().getTime());
  };
  return (
    <div>
      <div>state值:{state}</div>
      <button onClick={update}>改变state</button>
    </div>
  );
}

  作用

    1.在组件初始化时,fn 和 memoizedFn 都会拿取到state的最新值initialization吗?

    2.在组件更新后只要依赖的项没有发生变化,那么memoizedFn输出的结果永远是旧值?

    3.如果使用的是非响应式(useState())的普通变量,memoizedFn还会保留它吗?

    4.多个memoizedFn嵌套使用,该如何缓存结果?

  验证

    1.【验证1】在组件初始化时,fn 和 memoizedFn 都会拿取到state的最新值initialization

    

       可以看到在初始化时,可以看到普通函数 fn 和 记忆函数memoizedFn 都打印出了state的初始值:inittialization

    2.【验证2】在组件更新后只要依赖的项没有发生变化,那么memoizedFn输出的结果永远是旧值

    

      可以看到当组件更新后,普通函数fn 读取到了最新的state值:initialization1640850521426,而memoizedFn函数,输出的还是组件创建时的旧state值:inittialization,这就意味着当依赖项(我们这里设置的:[]),没有改变时无论我们执行多少次memoizedFn函数,始终输出的都是上一次更新或者时创建时的旧值,在memoizedFn使用的所有变量(state),都是被缓存的旧值

    3.【验证3】.如果使用的是非响应式(useState())的普通变量,memoizedFn还会保留它吗

     修改代码

function Home() {
  const [state, setState] = useState("initialization");
  let normal = "init noraml"; //增加normal变量

  //普通函数
  const fn = () => {
    console.log("普通函数输出:", state, "noraml:", normal); //增加输出
  };

  //记忆函数
  const memoizedFn = useCallback(() => {
    console.log("memoized函数输出:", state, "noraml:", normal); //增加输出
  }, []);

  //组件Home,mount 和 update时都执行

      //... 

  const update = () => {
    const date = new Date().getTime();
    setState("initialization" + date);
    normal = "init noraml" + date; //增加输出
  };
    //...
}

    

     可以看到,在第一次更新state时,memoizedFn 并没有缓存noraml的旧值init noraml,而在第二次更新时,使用的是第一次更新时的缓存值,这是一个很奇怪的点,官方上并没有给出答案,但是却推荐,不要在useCallback中使用外部的普通变量,尽量在useCallback类定义变量,以确保变量能得到我们预期的结果

 const memoizedFn = useCallback(() => {
    let normal = "init noraml";
    console.log("memoized函数输出:", state, "noraml:", normal); //增加输出
  }, []);

    4.【验证4】多个memoizedFn嵌套使用,该如何缓存结果

      修改代码

function Home() {
  const [state, setState] = useState("initialization");

  //记忆函数1 无任何依赖
  const memoizedFn1 = useCallback(() => {
    console.log("memoized函数1 输出:", state);
    console.log("memoized函数1调用memoizedFn2");
    memoizedFn2();
  }, []);

  //记忆函数1 无任何依赖
  const memoizedFn2 = useCallback(() => {
    console.log("memoized函数2 输出:", state);
  }, [state]);

  //组件Home,mount 和 update时都执行
  memoizedFn1();
console.log(
"直接调用memoizedFn2"); memoizedFn2();
const update
= () => { const date = new Date().getTime(); setState("initialization" + date); //使用setState改动state console.log("=====组件更新====="); }; return ( <div> <div>state值:{state}</div> <button onClick={update}>改变state</button> </div> ); }

    

    可以看出,在memoizedFn1中的执行的memoizedFn2,即便memoizedFn2中设置的依赖[state]发生更新,memoizedFn2读取的state仍是旧值,这就意味着在memoizedFn内部的函数,只要最外层的memoized不发生更新,那么内部函数使用的所有变量都为旧值

    

 

 

posted @ 2021-12-31 10:12  眼里有激光  阅读(1328)  评论(0编辑  收藏  举报