更新逻辑
- 在
Fiber
上创建Update
。- 设置相关属性
lane
、eventTime
、payload
、callback
。 - 函数:
createUpdate
->enqueueUpdate
- 设置相关属性
- 通过
Scheduler
调度安排渲染。- 确认渲染任务
performConcurrentWorkOnRoot
或performSyncWorkOnRoot
的优先级、执行时机。 - 函数:
scheduleUpdateOnFiber
->ensureRootIsScheduled
- 确认渲染任务
数据结构
Class Component
UpdateQueue
由Update
节点构成的循环链表。SharedQueue
是链表尾结点。
type Update<State> = {
// 事件时间,后面会删除,将在根目录中存储转换->事件时间的映射.
eventTime: number,
// 优先级
lane: Lane,
// 更新类型
// 对应 UpdateState、ReplaceState、ForceUpdate、CaptureUpdate
tag: 0 | 1 | 2 | 3,
// newState 或者 newState函数
payload: any,
callback: (() => mixed) | null,
// 下一个update
next: Update<State> | null,
};
type UpdateQueue<State> = {
// update list 循环链表
shared: SharedQueue<State>,
// 下面3个值,都是 中断保护现场 的状态。
// 更新被高优先级打断时,打断前的值。
baseState: State,
firstBaseUpdate: Update<State> | null,
lastBaseUpdate: Update<State> | null,
// 副作用
effects: Array<Update<State>> | null,
};
type SharedQueue<State> = {
// UpdateQueue的尾结点,是循环链表
pending: Update<State> | null,
// UpdateQueue的优先级,会merge更新队列的lane
lanes: Lanes,
interleaved: Update<State> | null,
};
type Fiber = {
// state保存的是值
memoizedState: any
// UpdateQueue
updateQueue:UpdateQueue
}
Function Component
函数组件的状态是Hooks
管理的,所以每个Hooks
都有自己的UpdateQueue
。
type Update<S, A> = {
lane: Lane, // 优先级
action: A, // newState 或者 newState函数
hasEagerState: boolean, // state 优化
eagerState: S | null, // state 优化
next: Update<S, A>, // 下一个update
};
type UpdateQueue<S, A> = {
// update list 尾结点,是循环链表
pending: Update<S, A> | null,
// UpdateQueue的优先级,会merge更新队列的lane
lanes: Lanes,
// 对应的dispatch函数
dispatch: (A => mixed) | null,
// 每次使用useReducer传入的,重新赋值reducer函数。每次使用都是最新的。
lastRenderedReducer: ((S, A) => S) | null,
// 上一次调度更新hook计算出的state。
lastRenderedState: S | null,
interleaved: Update<S, A> | null,
};
type Hook = {
// state
memoizedState: any,
// UpdateQueue
queue: any,
// 下一个hook
next: Hook | null,
// 下面2个值,都是 中断保护现场 的状态。
// 更新被高优先级打断时,打断前的值。
baseState: any,
// 打断前的UpdateQueue
baseQueue: Update<any, any> | null,
};
type Fiber = {
// state保存的是hook链表的尾结点。一个循环链表
memoizedState: Hook
// Hook有自己的updateQueue,
// fiber的UpdateQueue暂时无用。
}
触发更新的方式
ReactDOM.render
Update
的数据结构与ClassCompoent
相同。
updateContainer
ReactDOM.render
和ReactDOM.createRoot().render
都是调用updateContainer
。
//ReactDOM.render(element)和ReactDOM.createRoot(element).render都是调用updateContainer。
export function updateContainer(
element: ReactNodeList,
container: OpaqueRoot,
parentComponent: ?React$Component<any, any>,
callback: ?Function,
): Lane {
// current是FiberRoot
const current = container.current;
// 时间
const eventTime = requestEventTime();
// 优先级
const lane = requestUpdateLane(current);
const context = getContextForSubtree(parentComponent);
if (container.context === null) {
container.context = context;
} else {
container.pendingContext = context;
}
// 创建update,ClassComponent的。
const update = createUpdate(eventTime, lane);
// FiberRoot的payload是所挂载的DOM节点
// React DevTools目前依赖于这个属性
update.payload = {element};
callback = callback === undefined ? null : callback;
if (callback !== null) {
update.callback = callback;
}
// 将Update添加到Fiber.updateQueue 队尾。
enqueueUpdate(current, update, lane);
// 调度更新任务
const root = scheduleUpdateOnFiber(current, lane, eventTime);
// 调度优先级相关
if (root !== null) {
entangleTransitions(root, current, lane);
}
return lane;
}
this.setState -- Class Component
ClassComponent
的state
操作,都由一个classComponentUpdater
对象提供。
在组件创建时,添加到实例中instance.updater = classComponentUpdater
。
enqueueSetState
// this.setState 实际调用函数
enqueueSetState(inst, payload, callback) {
// 获取组件对应的fiber
const fiber = getInstance(inst);
const eventTime = requestEventTime();
const lane = requestUpdateLane(fiber);
// 创建Update。 赋值lane、eventTime、payload、callback
const update = createUpdate(eventTime, lane);
update.payload = payload;
update.callback = callback;
// 将Update添加到Fiber.updateQueue 队尾。
enqueueUpdate(fiber, update, lane);
// 调度更新任务
const root = scheduleUpdateOnFiber(fiber, lane, eventTime);
// 调度优先级相关
if (root !== null) {
entangleTransitions(root, fiber, lane);
}
}
this.fourceUpdate -- Class Component
与this.setState
基本一致。
只有update
数据稍有改动
// this.fourceUpdate 实际调用函数
// 不同点:不能传入payload
enqueueForceUpdate(inst, callback) {
const fiber = getInstance(inst);
const eventTime = requestEventTime();
const lane = requestUpdateLane(fiber);
// 不同点:payload为null. (创建时默认为null)
const update = createUpdate(eventTime, lane);
// 不同点:更新tag ForceUpdate
update.tag = ForceUpdate;
enqueueUpdate(fiber, update, lane);
const root = scheduleUpdateOnFiber(fiber, lane, eventTime);
if (root !== null) {
entangleTransitions(root, fiber, lane);
}
}
useReducer -- Function Component
新版本将 useReducer
与useState
区分开了,因为旧版useReducer
有一些BUG。
dispatchReducerAction
function dispatchReducerAction<S, A>(
fiber: Fiber,
queue: UpdateQueue<S, A>,
action: A,
) {
const lane = requestUpdateLane(fiber);
// update
const update: Update<S, A> = {
lane, // 优先级
action,
hasEagerState: false,
eagerState: null,
next: (null: any),
};
// fiber是否正在render
// 正在render是指,组件函数执行时触发 更新(即触发此函数)
if (isRenderPhaseUpdate(fiber)) {
// eg: <Test/> 组件内直接 dispatch(1), 这时组件render会立即触发此函数。
// (优化手段)
// 在组件函数执行完毕后,
// 重复调用此组件函数。
// 直到组件调用时,没有触发更新。
// 若触发次数过多,进行报错。
// 处理逻辑在:函数组件渲染函数 renderWithHooks 中。
// 将Update添加到Fiber.memoizedState(Hook).queue 队尾。
enqueueRenderPhaseUpdate(queue, update);
} else {
// 将Update添加到Fiber.memoizedState(Hook).queue 队尾。
enqueueUpdate(fiber, queue, update, lane);
const eventTime = requestEventTime();
// 调度更新任务
const root = scheduleUpdateOnFiber(fiber, lane, eventTime);
// 调度优先级相关
if (root !== null) {
entangleTransitionUpdate(root, queue, lane);
}
}
}
useState -- Function Component
新版本将 useReducer
与useState
区分开了,因为旧版useReducer
有一些BUG。
Update 数据结构
// eg: dispatch( n => n+1 )
const update: Update<S, A> = {
lane, // 优先级
action,// dispatch传参 eg: n => n+1
hasEagerState: false, //
eagerState: null, //
next: (null: any),//next update
};
dispatchSetState
function dispatchSetState<S, A>(
fiber: Fiber,
queue: UpdateQueue<S, A>,
action: A,
) {
const lane = requestUpdateLane(fiber);
const update: Update<S, A> = {
lane,
action,
hasEagerState: false,
eagerState: null,
next: (null: any),
};
// fiber是否正在render
// 正在render是指,组件函数执行时触发 更新(即触发此函数)
if (isRenderPhaseUpdate(fiber)) {
// eg: <Test/> 组件内直接 dispatch(1), 这时组件render会立即触发此函数。
// (优化手段)
// 在组件函数执行完毕后,
// 重复调用此组件函数。
// 直到组件调用时,没有触发更新。
// 若触发次数过多,进行报错。
// 处理逻辑在:函数组件渲染函数 renderWithHooks 中。
// 将Update添加到Fiber.memoizedState(Hook).queue 队尾。
enqueueRenderPhaseUpdate(queue, update);
} else {
// 将Update添加到Fiber.memoizedState(Hook).queue 队尾。
enqueueUpdate(fiber, queue, update, lane);
const alternate = fiber.alternate;
if (
// 说明fiber上面没update,这是本轮第一个update!
fiber.lanes === NoLanes &&
(alternate === null || alternate.lanes === NoLanes)
) {
// 直接计算state,因为是第一个update,不用考虑优先级的其他逻辑。
// 这是优化,尽量减少状态调度。
const lastRenderedReducer = queue.lastRenderedReducer;
if (lastRenderedReducer !== null) {
let prevDispatcher;
try {
// 上一次useReducer的state。
const currentState: S = (queue.lastRenderedState: any);
// 计算本次的state
const eagerState = lastRenderedReducer(currentState, action);
// 记录是否 执行过 此优化逻辑。
update.hasEagerState = true;
update.eagerState = eagerState;
// 新旧state相同,不更新。
if (is(eagerState, currentState)) { return; }
} catch (error) {
// Suppress the error. It will throw again in the render phase.
}
}
}
const eventTime = requestEventTime();
// 调度更新任务
const root = scheduleUpdateOnFiber(fiber, lane, eventTime);
// 调度优先级相关
if (root !== null) {
entangleTransitionUpdate(root, queue, lane);
}
}
}
并发模式下的state更新公式
baseState
+ Update1
+ Updata2
+(优先级足够的Update
) = newState
- baseState:上一轮更新后的
state
值,若被高优先级打断,则值为中断发生前一个计算出的值。 - 会过滤掉优先级不足的
Update
。
安排渲染
根据update
,和当前react
运行状态,调度渲染任务。
scheduleUpdateOnFiber
调度fiber
上的update
。
export function scheduleUpdateOnFiber(
fiber: Fiber,
lane: Lane,
eventTime: number,
): FiberRoot | null {
// 将lane合并到,此fiber到Root的路径上的所有Fiber中。
const root = markUpdateLaneFromFiberToRoot(fiber, lane);
if (root === null) { return null; }
// 标记根有一个挂起的更新
markRootUpdated(root, lane, eventTime);
if (
// 正在渲染,且root和正在work的root相同。
(executionContext & RenderContext) !== NoLanes &&
root === workInProgressRoot
) {
// 共用当前render。merge lane。
workInProgressRootRenderPhaseUpdatedLanes = mergeLanes(
workInProgressRootRenderPhaseUpdatedLanes,
lane,
);
} else {
// 调度一个渲染任务
ensureRootIsScheduled(root, eventTime);
if (
lane === SyncLane && //同步优先级
executionContext === NoContext && // 执行上下文,无任务
(fiber.mode & ConcurrentMode) === NoMode && // 不是并发模式
) {
// 兼容 leacy 模式的正确渲染。
// eg: 在setTimeout,接口等异步,调用setState,会走此逻辑。
// 直接进行渲染。
flushSyncCallbacksOnlyInLegacyMode();
}
}
return root;
}
ensureRootIsScheduled
为root
调度performSyncWorkOnRoot
(渲染)
function ensureRootIsScheduled(root: FiberRoot, currentTime: number) {
// 保存,调度单元,scheduler所创建的task对象,与并发模式的调度有关。
const existingCallbackNode = root.callbackNode;
// 是否有 lane 饿死,标记为过期。
markStarvedLanesAsExpired(root, currentTime);
// 找到优先级最高的lane
const nextLanes = getNextLanes(
root,
root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes,
);
// 无任务
if (nextLanes === NoLanes) {
if (existingCallbackNode !== null) {
cancelCallback(existingCallbackNode);
}
root.callbackNode = null;
root.callbackPriority = NoLane;
return;
}
// 根据lane,获取优先级
const newCallbackPriority = getHighestPriorityLane(nextLanes);
const existingCallbackPriority = root.callbackPriority;
if (
// 检查是否有一个正在执行的的任务,优先级相同复用它。
existingCallbackPriority === newCallbackPriority &&
) {
return;
}
if (existingCallbackNode != null) {
//取消现有的回调。我们将在下面安排一个新的。
cancelCallback(existingCallbackNode);
}
// Schedule 一个新的 callback.
let newCallbackNode;
// 同步优先级
if (newCallbackPriority === SyncLane) {
// 将performSyncWorkOnRoot放入 同步执行回调队列 SyncCallbacks
if (root.tag === LegacyRoot) {
// legacy模式,调度渲染performSyncWorkOnRoot
scheduleLegacySyncCallback(performSyncWorkOnRoot.bind(null, root));
} else {
// 并发模式,调度渲染performSyncWorkOnRoot
scheduleSyncCallback(performSyncWorkOnRoot.bind(null, root));
}
// 是否支持微任务
// 当前是同步优先级,立即执行渲染
if (supportsMicrotasks) {
// flushSyncCallbacks,即立刻执行performSyncWorkOnRoot
scheduleMicrotask(flushSyncCallbacks);
} else {
// flushSyncCallbacks,即立刻执行performSyncWorkOnRoot
scheduleCallback(ImmediateSchedulerPriority, flushSyncCallbacks);
}
newCallbackNode = null;
} else {
// 并发模式 异步优先级。
let schedulerPriorityLevel;
// lane => scheduler Priority
switch (lanesToEventPriority(nextLanes)) {
case DiscreteEventPriority:
schedulerPriorityLevel = ImmediateSchedulerPriority;
break;
case ContinuousEventPriority:
schedulerPriorityLevel = UserBlockingSchedulerPriority;
break;
case DefaultEventPriority:
schedulerPriorityLevel = NormalSchedulerPriority;
break;
case IdleEventPriority:
schedulerPriorityLevel = IdleSchedulerPriority;
break;
default:
schedulerPriorityLevel = NormalSchedulerPriority;
break;
}
// 保存,调度单元,scheduler所创建的task对象
newCallbackNode = scheduleCallback(
schedulerPriorityLevel,
performConcurrentWorkOnRoot.bind(null, root),
);
}
// 保存,调度优先级
root.callbackPriority = newCallbackPriority;
// 保存,调度单元,scheduler所创建的task对象
root.callbackNode = newCallbackNode;
}
performSyncWorkOnRoot
此函数将会 diff
且渲染DOM
。
此文不细说具体怎么渲染。
综述
写作时间:2021-01-16
react版本:17.0.3