hooks中的useCallbak源码

304 阅读2分钟

我们逐渐解析其原理,先看看源码:

export function useCallback<T>(
  callback: T,
  deps: Array<mixed> | void | null,
): T {
  const dispatcher = resolveDispatcher();
  return dispatcher.useCallback(callback, deps);
}

我们看到接受两个参数:callback,deps。 其中第一个参数就是我们传入的函数,第二个就是函数的依赖。 下面我们再看看dispatcher,看看dispatcher内部的实现。

function resolveDispatcher() {
  const dispatcher = ReactCurrentDispatcher.current;
  invariant(
    dispatcher !== null,
    'Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' +
      ' one of the following reasons:\n' +
      '1. You might have mismatching versions of React and the renderer (such as React DOM)\n' +
      '2. You might be breaking the Rules of Hooks\n' +
      '3. You might have more than one copy of React in the same app\n' +
      'See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.',
  );
  return dispatcher;
}

这是得到这个对象的地方。我们又看到这个是从ReactCurrentDispatcher中的current中得到的。

const ReactCurrentDispatcher = {
  /**
   * @internal
   * @type {ReactComponent}
   */
  current: (null: null | Dispatcher),
};

import type {Dispatcher} from 'react-reconciler/src/ReactInternalTypes';看到是在这里,我们进去看看,这里是类型,根据类型查找函数的实现。 经过我们搜索查找,找到了函数的实现:

function updateCallback<T>(callback: T, deps: Array<mixed> | void | null): T {
  const hook = updateWorkInProgressHook();
  const nextDeps = deps === undefined ? null : deps;
  const prevState = hook.memoizedState;
  if (prevState !== null) {
    if (nextDeps !== null) {
      const prevDeps: Array<mixed> | null = prevState[1];
      if (areHookInputsEqual(nextDeps, prevDeps)) {
        return prevState[0];
      }
    }
  }
  hook.memoizedState = [callback, nextDeps];
  return callback;
}

还有一个:

function mountCallback<T>(callback: T, deps: Array<mixed> | void | null): T {
  const hook = mountWorkInProgressHook();
  const nextDeps = deps === undefined ? null : deps;
  hook.memoizedState = [callback, nextDeps];
  return callback;
}

有两种实现,主要看下面的条件,也就是判断是更新还是组件刚好装载:

ReactCurrentDispatcher.current =
      current === null || current.memoizedState === null
        ? HooksDispatcherOnMount
        : HooksDispatcherOnUpdate;

通过源码可知,当依赖发生改变的时候才会使用新定义的函数,否者使用以前的定义。感觉作用并不是很大,因为当执行函数的时候如果里面有跟组件相关的依赖,大部分都是希望使用最新的数据,而不是以前的。除非你想使用以前的数据。

除此之外都尽量不要使用这个API,因为在编写代码的时候有时候会忘记添加依赖。

我之前不了解,认为内部使用的实现是把依赖当成函数传入其中,所以函数的声明就进行一次,然而并不是这样。

这里的依赖仅仅是propsstate,其他是最新的。