详细介绍React中的useCallback

52 阅读3分钟

useCallback 是 React 提供的一个 Hook,它用于缓存函数,以便在组件的多次渲染之间保持函数引用的一致性。这个 Hook 在优化那些依赖于函数不变性的场景中特别有用,如防止不必要的重新渲染、减少计算量或处理事件处理器和其他回调函数。

基本用法

useCallback 接收两个参数:一个是你想要缓存的函数,另一个是这个函数的依赖数组。它返回的是缓存版本的函数。

const memoizedCallback = useCallback(
  () => {
    // 这里是你的函数逻辑
  },
  [/* 依赖列表 */],
);

只有当依赖列表中的依赖发生变化时,才会重新创建这个函数。如果依赖列表是空数组 [],则该函数只会在组件初次渲染时创建一次。

为什么使用 useCallback

在 React 中,函数组件的渲染意味着执行其函数体。在这个过程中,组件内部定义的所有函数都会被重新创建。大多数情况下,这并不是问题。然而,在以下情况中,重新创建函数可能会导致性能问题或不必要的渲染:

  • 将回调函数传递给经过优化的子组件时,如 React.memo 包裹的子组件。如果回调函数的引用每次渲染时都不同,即使其他 props 没有变化,子组件也会重新渲染。
  • 当一个回调被用作其他 Hook 的依赖时,如 useEffect。如果回调函数每次都是新的,那么即使实际逻辑没有变化,也可能触发额外的重渲染或副作用执行。

示例

假设我们有一个组件,它接收一个用户 ID,并在点击按钮时获取用户信息。

const UserInfo = ({ userId }) => {
  const fetchUser = useCallback(() => {
    fetch(`/api/users/${userId}`)
      .then(response => response.json())
      .then(data => console.log(data));
  }, [userId]); // 依赖于 userId

  return <button onClick={fetchUser}>Load User Info</button>;
};

在这个例子中,fetchUser 回调依赖于 userId。只有当 userId 发生变化时,fetchUser 才会被重新创建。这保证了即使 UserInfo 组件因其他状态或 props 的变化而重新渲染,只要 userId 没变,传给按钮的 onClick 处理器仍然保持不变,避免了不必要的渲染或逻辑执行。

注意事项

  • 过度使用 useCallback 可能会导致代码复杂且难以维护,因为管理函数的依赖可能会变得困难。
  • 在某些情况下,缓存函数可能不会带来显著性能提升,甚至可能因为额外的缓存逻辑而稍微降低性能。因此,建议仅在确实需要时使用 useCallback

总的来说,useCallback 是 React 中一个有用的 Hook,它可以帮助避免因函数重新创建导致的不必要渲染,特别是在将回调函数传递给子组件或用作其他 Hook 依赖时。

个人总结

useCallback就是用来缓存函数的,如果一个函数是其他的组件的依赖,或者是其他hooks的依赖,比如useEffect,那么每次组件更新渲染时,都会引起函数重新赋值,导致其他依赖项重新执行。 比如上面总结的在React.memo和useEffect中使用时。