我们逐渐解析其原理,先看看源码:
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,因为在编写代码的时候有时候会忘记添加依赖。
我之前不了解,认为内部使用的实现是把依赖当成函数传入其中,所以函数的声明就进行一次,然而并不是这样。
这里的依赖仅仅是props和state,其他是最新的。