搜索

首页  >  问答  >  正文

了解React中useCallback的依赖项缓存和引用

<p>useCallback钩子只缓存函数引用还是也缓存函数本身的值/结果?另外,在依赖数组中使用ref是否真的产生任何效果,例如组件的ref?如果没有,那么有没有办法确保ref值的更改有适当的效果?</p> <p>我原以为只有函数引用会被缓存,但在阅读了一篇文章后得知,useCallback(fn, deps)等同于useMemo(() => fn, deps),我不确定这是否实际上是这种情况。此外,我尝试使用组件的ref作为依赖项(如Video.js和react-slick),但我认为与其他依赖项相比,它没有太大的影响。</p>
P粉044526217P粉044526217501 天前578

全部回复(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%2FApp.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
  • 取消回复