认识
一、认识
二、数据结构
2.1 hook
const hook = {
next: null,
baseQueue: null,
baseState: null,
updateQueue: null,
memoizedState: null
};
2.2 hook.memoizedState
hook.memoizedState
用于存储 { current: xxx}
对象
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
useState
在 mount
阶段创建当前 hook
, 处理初始值, 创建 updateQueue
数据结构, hook.updateQueue
保存已创建好的 updateQueue
, hook.memoizedState
存储初始值。通过 dispatchSetState
创建 dispatch
方法, 同 初始值
一同以数组的形式返回。
返回的形式是数组, 而不是对象: 因为数组解构时可以任意命名, 而对象解构需要属性名一致, 不方便。
创建 dispatchSetState
的主要逻辑为: dispatchSetState
通过 .bind
方法, 预先传入 fiber
与 updateQueue
, 当用户调用 dispatch
时, 传入一个值, 这个作为 action
参数传入。在 dispatchSetState
中通过 action
和当前优先级创建 update
数据结构, 随后进行 eagerState
优化策略, 如果前后数据无变化, 只需将 update
加入 updateQueue.shared.pending
中皆可, 并且更新优先级为 NoLane
。如果前后数据有变化, 在update
加入 updateQueue.shared.pending
的同时, 以传入的 Lane
优先级, 调用 scheduleUpdateOnFiber
开启调度更新流程。 其中 update
加入 updateQueue.shared.pending
中形成环状链表
五、函数组件 update 阶段 Hook
三、工作流程
3.1 标记 Ref
标记 Ref
需要满足:
-
mount
时: 存在Ref
-
update
时:Ref
引用变化
标记的时机包括:
-
beginWork
-
completeWork
3.2 执行 Ref
对于正常的绑定操作:
-
解绑之前的
Ref
-
绑定新的
Ref
对于组件卸载:
- 解绑之前的
Ref