reactjs React中的useCallback与useEffect

djmepvbi  于 2023-06-22  发布在  React
关注(0)|答案(4)|浏览(157)

useEffect作为第二个参数传递依赖关系时与useCallback有什么不同?
当作为第二个参数传递的依赖关系发生变化时,这两个函数不是都运行作为第一个参数传递的函数/代码吗?
从我所读到的内容来看,这两个钩子的目的是不同的,但我的问题是,它们在实际上是否可以互换使用,因为它们在功能上做着相同的事情

bpzcxfmw

bpzcxfmw1#

不,它们不一样。

useEffect-用于在组件发生更改时运行副作用。useEffect不会返回任何内容。它只是运行组件中的一段代码。
useCallback-虽然useCallback返回一个函数,但它实际上并不执行代码。重要的是要理解函数是JavaScript中的对象。如果不使用useCallback,则在组件内部定义的函数将在组件重新构建时重新创建。

示例

考虑这个例子,这个组件将进入无限循环。想想为什么?

const TestComponent = props => {
  const testFunction = () => {
    // does something.
  };

  useEffect(() => {
    testFunction();
    // The effect calls testFunction, hence it should declare it as a dependency
    // Otherwise, if something about testFunction changes (e.g. the data it uses), the effect would run the outdated version of testFunction
  }, [testFunction]);
};

因为在每次渲染时,testFunction都将被重新创建,并且我们已经知道,当testFunction发生变化时,useEffect将运行代码。由于testFunction在每次渲染时都会改变,useEffect将继续运行,因此是一个无限循环。
为了解决这个问题,我们必须告诉react,嘿,请不要在每次渲染时重新创建testFunction,只在第一次渲染时创建它(或者当它所依赖的东西发生变化时)。

const TestComponent = props => {
  const testFunction = useCallback(() => {
    // does something.
  }, []);

  useEffect(() => {
    testFunction();
    // The effect calls testFunction, hence it should declare it as a dependency
    // Otherwise, if something about testFunction changes (e.g. the data it uses), the effect would run the outdated version of testFunction
  }, [testFunction]);
};

这不会是一个无限循环,因为testFunction的示例只会在第一次渲染时改变,因此useEffect只会运行一次。

o8x7eapl

o8x7eapl2#

他们太不一样了。
useEffect将 * 在依赖数组更改时运行 * 内部的函数。
useCallback将在依赖数组改变时 * 创建一个新函数 *。
您不能单独使用useCallback切换useEffect,因为您还需要逻辑来运行新创建的函数。(我想如果你也使用ref的话,你也可以实现这个,但那会很奇怪。
你不能用useEffect切换useCallback,因为你通常不想立即运行新创建的函数--相反,你通常想把它作为一个 prop 传递给其他组件。
useCallback的存在主要是为了优化,以减少子组件的重新呈现。

7y4bm7vi

7y4bm7vi3#

useEffect会在依赖数组发生变化时运行内部函数。
useCallback会在依赖数组发生变化时创建一个新函数。

让我们举一个例子,如果我运行下面的代码并单击第一个按钮,它将始终重新渲染MemoComponent以及。为什么是因为我们每次都在传递新的onClick函数给这个。为了避免重新渲染MemoComponent,我们可以做的是wrap onClick to usefallback。每当你想创建一个新的函数时,将状态传递给依赖数组。
如果你想对状态变化执行一些操作,你可以在useEffect中编写。

const Button = ({ onClick }) => {
  console.log("Render");
  return <button onClick={onClick}>Click</button>;
};

const MemoComponent = React.memo(Button);
export default function Home() {
    const [state, setState] = useState(1);

    useEffect(() => {
        console.log(state); // this will execute when state changes
    }, [state]);

    const onClick = () => {};

    // const onClick = useCallback(() => {},[])
    return (
        <main>
        <button onClick={() => setState(1 + state)}>{state}</button>
        <MemoComponent onClick={onClick} />
        </main>
    );
}
8zzbczxx

8zzbczxx4#

使用效果

它是类组件生命周期方法componentDidMount、componentWillUnmount、componentDidUpdate等的替代方法。您也可以使用它来在依赖关系更改时创建副作用,即如果某个变量发生变化,请执行此操作。
每当你有一些逻辑被执行作为状态变化的React或在变化即将发生之前。

useEffect(() => {
  // execute when state changed
  () => {
    // execute before state is changed
  }
}, [state]);

OR

useEffect(() => {
  // execute when state changed
  () => {
    // execute before state is changed
  }
}, []);

使用回调

在每次渲染时,功能组件中的所有内容都将再次运行。如果子组件依赖于父组件的函数,则每次父组件重新渲染时,子组件将重新渲染,即使该函数“没有更改”(引用更改,但函数所做的不会更改)。它用于优化,避免不必要的子级渲染,使函数仅在依赖项更改时更改引用。当一个函数是副作用的依赖项时,你应该使用它。使用效果。
每当你有一个依赖于某些状态的函数时。这个钩子用于性能优化,除非依赖状态被改变,否则可以防止组件内的函数被重新分配。

const myFunction = useCallback(() => {
  // execute your logic for myFunction
}, [state]);

如果没有useCallback,myFunction将在每次渲染时重新分配。因此,它使用了更多的计算时间,就像useCallback一样。

相关问题