架构分层
- scheduler 调度
- reconciler 协调
- render 渲染
scheduler:event loops —— 宏任务方式执行任务
- scheduleCallback:方法加入到调度队列中,每次会对队列重新排序
- requestHostTimeout(setTimeout)-> advanceTimers:将 timer 中过期任务放到 task 中
- requestHostCallback(MessageChannel 或 setTimeout) -> flushWork -> workLoop: 执行 taskQueue 中优先级最高的任务
reconciler
- beginWork —— “递”过程: 首先从 rootFiber 开始向下深度优先遍历。为遍历到的每个 Fiber 节点调用 beginWork 方法。 该方法会根据传入的 Fiber 节点创建子 Fiber 节点,并将这两个 Fiber 节点连接起来。 当遍历到叶子节点(即没有子组件的组件)时就会进入“归”阶段。
- completeWork —— “归”过程: 在“归”阶段会调用 completeWork 处理 Fiber 节点。 当某个 Fiber 节点执行完 completeWork,如果其存在兄弟 Fiber 节点(即 fiber.sibling !== null),会进入其兄弟 Fiber 的“递”阶段。 如果不存在兄弟 Fiber,会进入父级 Fiber 的“归”阶段。 “递”和“归”阶段会交错执行直到“归”到 rootFiber。至此,render 阶段的工作就结束了。
beginWork
- reconcileChildren —— diff 算法
completeUnitOfWork
- completeWork
- function 组件:不处理
- class 组件
- HostComponent:创建 dom 节点,将子节点插入到该 dom 中;
- effect 链表:将要更新的 fiber 连成链表;rootFiber.firstEffect = 指向第一个要更新的 fiber
render:React 中 commitRoot 方法
commitBeforeMutationEffects
- commitBeforeMutationLifeCycles
- class:执行 getSnaphotBeforeUpdate 生命周期方法;获取当前 DOM 信息,提供给 componentDidUpdate 使用
- HostRoot:清空节点内容
- 判断当前 Fiber 是否存在 useEffect;存在,开启 useEffect 调度队列任务
commitMutationEffects:针对真实 dom 进行操作
- commitDetachRef:ref = null 重置
- commitPlacement:添加元素
- commitWork
- function:执行 useLayoutEffect 的 destroy 方法
- HostComponent:commitUpdate —— 对 html 标签添加 value、attribute、style
commitLayoutEffects
- commitLifeCycle
- function:执行 useLayoutEffect 的 createfangf;将 useEffect 放到数组中,等待执行
- class:执行 componentDidMount 或 componentDidUpdate
- commitAttachRef:ref = dom 实例
其他方法
- ensureRootIsScheduled:将满足条件的方法放到调度队列中
- flushSyncCallbackQueue: 执行 syncQueue 中方法
- flushPassiveEffects:当新的调度任务开始时,是否上次的 useEffect 方法还没有执行,先执行掉
- processUpdateQueue:将 pending 的值放到 baseState 上,firstBaseUpdate/lastBaseUpdate
- lanes 优先级;低优先级的占到位数越多
react: setState, hooks -> dispatchAction
setState 是同步的,调用 scheduleUpdateOnFiber -> ensureRootIsScheduled,判断当前 调度队列中存在了,就不会再次入栈;最后调用 processUpdateQueue 得到新的 state 和 memoizedState;
class 生命周期
- render
- constructor
- componentDidMount
- componentDidUpdate
- componentWillUnmount
- shouldComponentUpdate
- getDerivedStateFromProps: pure function,返回参数;返回 null,不更新 state 中数据
- getSnapshotBeforeUpdate: 在组件更新之前,捕获 DOM 信息
hooks
- Fiber.memorized: Function Component 对应 Fiber 保存的 hooks 链表;指向第一个 hook 地址
- hook.memorized: Hooks 链表中保存单一 hook 对应的数据
- 不同类型 hook 的 memoizedState 保存不同类型数据,具体如下:
- useState:对于 const [state, updateState] = useState(initialState),memoizedState 保存 state 的值
- useReducer:对于 const [state, dispatch] = useReducer(reducer, {}),memoizedState 保存 state 的值
- useEffect:memoizedState 保存包含 useEffect 回调函数、依赖项等的链表数据结构 effect,你可以在这里 (opens new window)看到 effect 的创建过程。effect 链表同时会保存在 fiber.updateQueue 中
- useRef:对于 useRef(1),memoizedState 保存{current: 1}
- useMemo:对于 useMemo(callback, [depA]),memoizedState 保存[callback(), depA]
- useCallback:对于 useCallback(callback, [depA]),memoizedState 保存[callback, depA]。与 useMemo 的区别是,useCallback 保存的是 callback 函数本身,而 useMemo 保存的是 callback 函数的执行结果
- 有些 hook 是没有 memoizedState 的,比如:useContext
- updateWorkInProgressHook: 找到对应的 hook,根据 update 计算该 hook 的新 state 并返回
function dispatchAction(fiber, queue, action) {
...
// 执行 nextChildren = Component(props, secondArg); 时,触发了useState方法
if (fiber === currentlyRenderingFiber$1 || alternate !== null && alternate === currentlyRenderingFiber$1) {
didScheduleRenderPhaseUpdateDuringThisPass = didScheduleRenderPhaseUpdate = true;
} else { // 当前Fiber处理NoLanes状态,此时触发useState方法,发现更新值与之前值一样时,取消此次更新
if (fiber.lanes === NoLanes && (alternate === null || alternate.lanes === NoLanes)) {
...
if (objectIs(eagerState, currentState)) {
return;
}
...
}
...
scheduleUpdateOnFiber(fiber, lane, eventTime);
}
}