认识
一、认识
useCallback
用于缓存函数,当组件重现渲染时不会重新创建该函数(防止父组件重新渲染导致函数引用发生变化)。用法如下所示:
const cachedFn = useCallback(fn, dependencies)
二、细节
2.1 hook
const hook = {
next: null,
baseQueue: null,
baseState: null,
updateQueue: null,
memoizedState: null
};
2.2 hook.memoizedState
hook.memoizedState
用于存储 [callback, depA]
数组
2.3 fiber.memoizedState
fiber.memoizedState
用于存储 hooks
链表
三、执行函数组件
在 React.js
的 beginWork
阶段, 遇到 FunctionComponent
类型的 Fiber
, 会执行 updateFunctionComponent
。updateFunctionComponent
内部调用 renderWithHooks
。主要工作如下:
-
重置状态: 函数组件执行前, 重置当前正在处理的
hook
、当前正在使用的hook
-
记录当前组件
fiber
: 通过currentlyRenderingFiber
变量记录当前组件fiber
-
选择对应阶段的
Hook
:mount
阶段选择HooksDispatcherOnMount
作为Hooks Map
,update
阶段选择HooksDispatcherOnUpdate
作为Hooks Map
。 函数组件mount
阶段 创建hook
数据结构, 存储到fiber.memoizedState
或者hook.next
, 初次建立其hooks
与fiber
之间的关系。函数组件update
阶段 找到当前函数组件fiber
, 找到当前hook
, 更新hook
状态。 -
执行函数组件: 执行我们真正函数组件,所有的
hooks
将依次执行, 每个hook
内部要根据currentlyRenderingFiber
读取对应的内容, -
重置状态: 执行完
Component
, 立马重置currentlyRenderingFiber
, 防止函数组件外部调用。置当前正在处理的hook
、当前正在使用的hook
3.1 /packages/react-reconciler/fiberHooks.js
export function renderWithHooks(workInProgress, Component, lane) {
renderLane = lane;
currentlyRenderingFiber = workInProgress;
workInProgress.memoizedState = null;
workInProgress.updateQueue = null;
const current = workInProgress.alternate;
if (current !== null) {
// update
currentDispatcher.current = HooksDispatcherOnUpdate;
} else {
// mount
currentDispatcher.current = HooksDispatcherOnMount;
}
const props = workInProgress.pendingProps;
const children = Component(props);
currentHook = null;
renderLane = NoLane;
workInProgressHook = null;
currentlyRenderingFiber = null;
return children;
}
3.2 /packages/react-reconciler/fiberHooks.js
/**
* @description: Mount 阶段 Hooks 实现
*/
const HooksDispatcherOnMount = {
use,
useRef: mountRef,
useMemo: mountMemo,
useState: mountState,
useEffect: mountEffect,
useContext: readContext,
useCallback: mountCallback,
useTransition: mountTransition
};
/**
* @description: Update 阶段 Hooks 实现
*/
const HooksDispatcherOnUpdate = {
use,
useRef: updateRef,
useMemo: updateMemo,
useState: updateState,
useEffect: updateEffect,
useContext: readContext,
useCallback: updateCallback,
useTransition: updateTransition
};
四、函数组件 mount 阶段 Hook
mount
阶段: 创建 hook
对象, 将 callback
参数和 deps
以数组的形式存储至 hook.memoizedState
中。最后返回 callback
参数。
function mountCallback(callback, deps) {
const hook = mountWorkInProgressHook();
const nextDeps = deps === undefined ? null : deps;
hook.memoizedState = [callback, nextDeps];
return callback;
}
五、函数组件 update 阶段 Hook
update
阶段: 获取当前 hook
对象, 读取当前 hook
对象的 memoizedState
值, 对比存储在 memoizedState
中的 deps
与用户传递的 deps
, 如果相等, 直接返回 memoizedState
数组的第一个值。如果不相等, 将 callback
参数和 deps
以数组的形式存储至 hook.memoizedState
中。最后返回 callback
参数。
function updateCallback(callback, deps) {
const hook = updateWorkInProgressHook();
const nextDeps = deps === undefined ? null : deps;
const prevState = hook.memoizedState;
if (nextDeps !== null) {
const prevDeps = prevState[1];
if (areHookInputsEqual(nextDeps, prevDeps)) {
return prevState[0];
}
}
hook.memoizedState = [callback, nextDeps];
return callback;
}