用React的useCallback钩子代替useEffect的意图是什么?

时间:2019-01-25 18:51:08

标签: reactjs react-hooks

我试图了解使用React的useCallback钩子代替useEffect钩子的用例。

它们似乎都充当其输入状态更改的侦听器(示例取自React Docs):

useEffect(
  () => {
    const subscription = props.source.subscribe();
    return () => {
      subscription.unsubscribe();
    };
  },
  [props.source],
);

const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b],
);

但是,useEffect钩提供了清理资源的额外好处,就像以前使用componentWillUnmount一样。

那么,使用useCallback的好用例是什么?而且,我在这里想念什么?

1 个答案:

答案 0 :(得分:7)

useEffect具有与之相关的非常特定的时序方面,您可以阅读有关here的内容。指定的功能将在渲染完成且DOM已更新后执行。每次渲染后,第二个参数数组中指定的任何值都会更改。

useCallback不会自动执行任何操作。它返回一个可以由任何触发它的代码执行的函数。没有监听导致回调执行的更改。数组值仅控制返回该函数的哪个实例。数组值不控制函数执行的时间。

一个关键的用例是将此功能作为道具传递给子组件以用作事件处理程序。 useCallback允许您定义一个内联函数以用作事件处理程序(因此它可以访问定义该函数的上下文中的任何其他变量),而无需在每次渲染时都向子级传递唯一的prop。只要第二个参数数组中的值未更改,就将返回与先前渲染相同的函数。因此,如果子组件是纯组件,则不会因为总是接收到唯一的事件处理函数而被迫重新渲染。

没有useCallback

const Parent = ()=> {
   const [a, setA] = useState(null);
   const eventHandler = ()=> {
      // every render creates a unique instance of eventHandler
      // even though it always does the same thing so long as 'a' hasn't changed
      doSomethingWithA(a);
   }
   return <Child onClick={eventHandler}/>
}

useCallback

const Parent = ()=> {
   const [a, setA] = useState(null);
   const eventHandler = useCallback(()=> {
      // A unique function instance is passed in to useCallback on every render, but
      // eventHandler will be set to the first instance of this function
      // (i.e. potentially an instance of the function that was passed to useCallback
      // on a previous rendering) that was passed to useCallback
      // for the current value of 'a'.
      doSomethingWithA(a);
   }, [a]);
   return <Child onClick={eventHandler}/>
}

This articleuseCallback和其他挂钩的用例上比React文档提供了更多细节。