搜尋

首頁  >  問答  >  主體

了解React中useCallback的依賴項快取和引用

<p>useCallback鉤子只緩存函數引用還是也緩存函數本身的值/結果?另外,在依賴陣列中使用ref是否真的產生任何效果,例如元件的ref?如果沒有,那麼有沒有辦法確保ref值的變更有適當的效果? </p> <p>我原以為只有函數引用會被緩存,但在閱讀了一篇文章後得知,useCallback(fn, deps)等同於useMemo(() => fn, deps),我不確定這是否實際上是這種情況。此外,我嘗試使用元件的ref作為依賴項(如Video.js和react-slick),但我認為與其他依賴項相比,它沒有太大的影響。 </p>
P粉044526217P粉044526217470 天前551

全部回覆(1)我來回復

  • P粉170438285

    P粉1704382852023-08-16 09:43:21

    是的,useCallback的目的是允許函數在渲染之間保持其引用,除非你指定的依賴項發生了變化。

    例如,如果你有一個函數f(x,y)=>x y,你可以使用空的依賴數組useCallback((x,y)=>x y,[ ]),這個函數將永遠不會改變。它始終會產生一致的行為,因為它只使用其參數來解析輸出。但是,如果你有另一個函數h和另一個外部值z,它可能會發生變化,而h定義為h(x ,y)=>x y z,那麼你需要將z包含在依賴項中,以便如果z發生變化,從useCallback返回的函數將具有新的引用。

    因此,useCallback的用途通常是當你傳遞函數時,它不會觸發子元件重新渲染,或者當你在子元件的useEffect宣告中使用函數作為依賴項時。如果函數內部的操作很昂貴,那麼useCallback就不太有用了,你應該單獨對結果進行記憶。

    關於ref的事情,我認為在依賴項中包含ref並不會有任何作用,它就像數組為空一樣。也許如果ref被儲存在狀態中,可能會有用,但我不太確定。

    這裡有一個連結https://stackblitz.com/edit/stackblitz-starters-wwyw9f?file=src/App.tsx,裡面有一些例子,也許有用。

    如果可能會被刪除,我也可以將其貼過來。

    import * as React from 'react';
    import './style.css';
    
    export default function App() {
      //x and y to be used as function arguments
      const [x, setX] = React.useState(0);
      const [y, setY] = React.useState(0);
    
      //z is variable also used in function calculation but not as an argument
      const [z, setZ] = React.useState(0);
    
      const ref = React.useRef<number>(0);
    
      //counter to see how many times function updates
      //will start at 2 cause strict mode but that's no issue really
      const [i, setI] = React.useState(0);
    
      //function to add x and y from args and add z from state
      const fn = React.useCallback(
        (x: number, y: number) => {
          // console.log(`${x}+${y}`);
          return x + y + z;
        },
        [z] // if you remove z and update it get wrong result
      );
    
      //update fn count on fn change
      React.useEffect(() => {
        setI((i) => i + 1);
      }, [fn]);
    
      React.useEffect(() => {
        console.log('nice');
        return () => console.log('ref cleanup');
      }, [ref]);
    
      return (
        <div>
          <pre>{JSON.stringify({ x, y, z })}</pre>
          <button onClick={() => setX((x) => x + 1)}> x ++</button>
          <button onClick={() => setY((y) => y + 1)}> y ++</button>
          <button onClick={() => setZ((z) => z + 1)}> z ++</button>
    
          <pre>x+y+z={fn(x, y)}</pre>
    
          <pre>fnCount:{i}</pre>
    
          <button
            onClick={() => {
              ref.current = ref.current++;
            }}
          >
            ref++
          </button>
        </div>
      );
    }

    希望能對你有幫助

    回覆
    0
  • 取消回覆