ReactHook
ReactHook 思维导图
Fiber Node 结构
这里只关系与 hooks 实现有关的内容
属性名 | 类型 | 说明 | ||||
---|---|---|---|---|---|---|
tag | Number | 组件类型。如这个组件是类组件、函数式组件,或其它什么类型的组件。 | ||||
type | Function | String | Symbol | Number | Object | FiberNode的类型。对于Component类的组件,type就是它的Class名。对于函数式组件来说,type就是这个FiberNode对应的函数本身。 |
memoizedState | Object | 当前 state。 具体的说,这是组件的第一个Hook (组件hook作为一个环形单向链表存在) | ||||
updateQueue | Object | 更新队列。记录了React组件更新的副作用,在EffectHook中会谈到。 |
Hook (memoizedState)
这指的是Fiber.memoizedState 的链表项内容
属性名 | 类型 | 说明 | |
---|---|---|---|
memoizedState | any | hook的当前值 (不同的hook有不同的结构) | |
queue | UpdateQueue<any, any> | null | 当前hook的更新队列 |
next | Hook | null | 这个hook后面的一个hook |
为什么 hook 是一个环形链表 ?为了性能考虑,如果用数组,插入和删除复杂度高
如果使用单向链表,插入需要遍历到最后,使用环形链表比较好
Dispatcher
React 根据渲染阶段的不同,使用不同的 dispatcher ,执行其中的函数(hook)
- 挂载 HooksDispatcherOnMount (通过当前hook是否为空判断) --> 绑定更新函数到 fiber 上
- 更新 HooksDispatcherOnUpdate --> 读取旧状态,合并更新队列,计算新值触发更新
- 一个在渲染过程中触发的再次更新: HooksDispatcherOnRerender
- 用于错误处理的:(在非法位置调用hook)ContextOnlyDispatcher --> 抛出异常(在执行完渲染后再切换回这里)
javaScript
const HooksDispatcherOnMount: Dispatcher = {
useEffect: mountEffect,
useMemo: mountMemo,
useState: mountState,
...
};
const HooksDispatcherOnUpdate: Dispatcher = {
useEffect: updateEffect,
useMemo: updateMemo,
useState: updateState,
...
};
流程
state
-
挂载
-
首次调用的时候,将 hook 数据挂载到 WIP Fiber 上 (memorizedState) 形成一个 单向链表
-
使用 HooksDispatcherOnMount ,此时 Hook 调用 mountXXX 方法,初始化状态,绑定更新函数
- 生成的 dispatch 除了通过 bind 绑定了当前上下文,还提前传入的 FiberNode 等参数
-
最终返回 [ state ,dispatch ]
-
-
更新 ( 调用 setState )
- 从当前 Current 树中获取旧 Fiber 的 hook 数据
- 通过 HooksDispatcherOnUpdate ,创建 action 推入 推入对应 hook 的 queue 上
- 触发调度 ,开始构建 WIP 树 : 通过 updateWorkInProgressHook 从 Current 中取出旧状态,计算并更新到新的 WIP 的 Hook 链表中
- 调度器根据优先级判断是否需要中断/重组任务队列
effect
-
挂载
-
首次调用的时候,HooksDispatcherOnMount 调用 mountEffect 方法,创建 Effect 对象
- 挂载到 WIP 树到 updateQueue 环形链表中 (创建的时候需要执行一次)
-
-
更新
- 在 beforeMutation 阶段,通过与当前 current 树上的 effect 的依赖的对比,判断是否需要执行 updateQueue 中的函数(打标)
- 最后在执行完更新,调度执行 updateQueue 。 保存 destory 函数(在Effect对象内)
-
卸载
- 卸载的时候需要执行 Effect 的所有 destory 函数
Effect List
Effect List 副作用链在 compeletWork 环节收集,收集的内容是 fiber 节点上的 Effect 副作用 和 DOM 操作函数。
EffectList 会在commit 阶段执行三次遍历
- Before Mutation 异步调度 effect (messageChannel 宏任务)
- Mutation 同步执行 DOM
- Layout 同步执行 layoutEffect (此时DOM还没有渲染,只是挂载,所以能够防止闪屏)
Redux 单项数据流
React-Router
笔者才疏学浅,各位读者多多担待,不吝赐教。