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不發生更新,那么內部函數使用的所有變量都為舊值

    

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM