在每一个hook执行时,会赋值会全局变量firstWorkInProgressHook
在组件完成时会被挂载在memoizedState
effect放在updateQueue
属性中,构建完成以后是一条单向链表
在dispatch
函数调用时,会把更新之后的值挂载在queue的last属性上也是链表
构建的过程也就是将要执行的函数组件对应的fiber节点赋值为全局变量,对应的hook挂载在全局变量中,执行完成以后把hook链表再放在当前fiber节点上。
React hook 链表实现
// 在每个hook挂载时的执行函数。 保存在全局变量中。 形成链表
function mountWorkInProgressHook() {
var hook = {
memoizedState: null,
baseState: null,
queue: null,
baseUpdate: null,
next: null
};
if (workInProgressHook === null) {
// 挂载到最后一个
firstWorkInProgressHook = workInProgressHook = hook;
} else {
// 增加一个
workInProgressHook = workInProgressHook.next = hook;
}
return workInProgressHook;
}
// 最终的hook链表, 保存在函数组件对应fiberNode上
fiberNode.memoizedState = firstWorkInProgressHook = {
// 组件内最终使用的值
memoizedState: null,
baseState: null,
queue:null | {
// 链接action形成的update对象
last: null,
dispatch: null,
eagerReducer: basicStateReducer,
eagerState: initialState
},
baseUpdate: null,
// 指向下一个hook节点
next: null
}
// update对象,会挂载在首次mount时绑定的queue对象的last指针上
const update = {
expirationTime: _expirationTime,
action: action,
eagerReducer: null,
eagerState: null,
// 链接下一个update对象的指针,会形成一个环状链表
next: null
}
useState的更新也是异步的,多个更新会形成多节点的环状链表。更新之后此次的action对象会赋值给 baseUpdate属性,在第二次更新时baseUpdate不等于null,环状链表会被剪开,最后返回更新后的值
为hook添加可更新的功能
dispatchAction
函数在hook中使用, 构建update对象之后会调度这次更新
mountStae:
function mountState<S>(
initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {
// 获取下一个需要挂载的hook对象,
const hook = mountWorkInProgressHook();
if (typeof initialState === 'function') {
initialState = initialState();
}
// 挂载hook绑定的state
hook.memoizedState = hook.baseState = initialState;
// 创建一个hook的更新队列
const queue = (hook.queue = {
pending: null,
dispatch: null,
lastRenderedReducer: basicStateReducer,
lastRenderedState: (initialState: any),
});
const dispatch = (queue.dispatch = (dispatchAction.bind(
null,
currentlyRenderingFiber, // 当前执行的function组件对应的fiber节点
queue, // 一个hook对应的更新队列
): any));
return [hook.memoizedState, dispatch];
}
dispatchAction:
// 删除了dev环境的运行时
function dispatchAction<S, A>(
fiber: Fiber,
queue: UpdateQueue<S, A>,
action: A,
) {
// 获取当前时间
const eventTime = requestEventTime();
// 获取当前可用的lane.
const lane = requestUpdateLane(fiber);
// 创建一个updae对象
const update = {
lane,
action,
eagerReducer: null,
eagerState: null,
next: (null: any),
};
// 循环链表
const pending = queue.pending;
if (pending === null) {
update.next = update;
} else {
update.next = pending.next;
pending.next = update;
}
// 更新头节点
queue.pending = update;
const alternate = fiber.alternate;
if (
fiber === currentlyRenderingFiber ||
(alternate !== null && alternate === currentlyRenderingFiber)
) {
// 首次挂载时的更新并不会立即执行,会在commit阶段的结尾重新调度一次更新
didScheduleRenderPhaseUpdateDuringThisPass = didScheduleRenderPhaseUpdate = true;
} else {
// 当前时第一次更新,必须第一时间计算最新的state
if (
fiber.lanes === NoLanes &&
(alternate === null || alternate.lanes === NoLanes)
) {
// lastRenderedReducer是 basicStateReducer
// useState是一个特殊的useReducer 本质两个相同,区别就是采用的reducer不同
// basicStateReducer 是react内部为state使用的reducer
const lastRenderedReducer = queue.lastRenderedReducer;
if (lastRenderedReducer !== null) {
try {
const currentState: S = (queue.lastRenderedState: any);
// 计算的最新state
const eagerState = lastRenderedReducer(currentState, action);
update.eagerReducer = lastRenderedReducer;
// 挂载在循环链表上
update.eagerState = eagerState;
if (is(eagerState, currentState)) {
/*
前后两个state如果引用相同会直接return。 所以在react里数据的不可变性尤为重要
假如直接的修改原state可能会暂时解决现在的问题,但是依赖state的后续节点还是会出问题
*/
return;
}
} catch (error) {}
}
// 对于当前的fiber节点发起一次调度。
// 可能会被批量更新优化调,也可能会被打断或者打断其他的更新
scheduleUpdateOnFiber(fiber, lane, eventTime);
}
// 更新需要的时间相关
if (enableSchedulingProfiler) {
markStateUpdateScheduled(fiber, lane);
}
}
updateState:
function updateReducer<S, I, A>(
reducer: (S, A) => S,
initialArg: I,
init?: I => S,
): [S, Dispatch<A>] {
// 获取更新时的下一个hook对象
const hook = updateWorkInProgressHook();
const queue = hook.queue;
// reducer 对于state来说是basicStateReducer, 也就是默认的
queue.lastRenderedReducer = reducer;
const current: Hook = (currentHook: any);
// 基本的更新队列
let baseQueue = current.baseQueue;
// 在dispatchAction中构建的更新循环链表
const pendingQueue = queue.pending;
if (pendingQueue !== null) {
// 合并
if (baseQueue !== null) {
const baseFirst = baseQueue.next;
const pendingFirst = pendingQueue.next;
baseQueue.next = pendingFirst;
pendingQueue.next = baseFirst;
}
current.baseQueue = baseQueue = pendingQueue;
// 剪开循环链表
queue.pending = null;
}
// 对于存在的更新队列开始计算更新
if (baseQueue !== null) {
// We have a queue to process.
const first = baseQueue.next;
let newState = current.baseState;
let newBaseState = null;
let newBaseQueueFirst = null;
let newBaseQueueLast = null;
let update = first;
do {
const updateLane = update.lane;
// 优先级不够,跳过本次更新
if (!isSubsetOfLanes(renderLanes, updateLane)) {
const clone: Update<S, A> = {
lane: updateLane,
action: update.action,
eagerReducer: update.eagerReducer,
eagerState: update.eagerState,
next: (null: any),
};
if (newBaseQueueLast === null) {
newBaseQueueFirst = newBaseQueueLast = clone;
newBaseState = newState;
} else {
newBaseQueueLast = newBaseQueueLast.next = clone;
}
// 优先级不够,合并lane
currentlyRenderingFiber.lanes = mergeLanes(
currentlyRenderingFiber.lanes,
updateLane,
);
markSkippedUpdateLanes(updateLane);
}
// 执行本次更新
else {
if (newBaseQueueLast !== null) {
// 将要被提交的更新, 不会被打断的更新
const clone: Update<S, A> = {
lane: NoLane,
action: update.action,
eagerReducer: update.eagerReducer,
eagerState: update.eagerState,
next: (null: any),
};
newBaseQueueLast = newBaseQueueLast.next = clone;
}
// 直接使用计算过的值, 也就是basicStateReducer计算过的值
if (update.eagerReducer === reducer) {
newState = ((update.eagerState: any): S);
} else {
const action = update.action;
// 这个reducer就是useReducer(reducer)
newState = reducer(newState, action);
}
}
update = update.next;
} while (update !== null && update !== first); // 循环链表
// 如果更新完毕就返回最新的state
if (newBaseQueueLast === null) {
// 这里只有在本次更新产生的循环链表更新队列基于上一次的basestate更新完毕时才会被赋值为新的
newBaseState = newState;
} else {
// 合并
newBaseQueueLast.next = (newBaseQueueFirst: any);
}
// 两个state不同,重新更新
if (!is(newState, hook.memoizedState)) {
markWorkInProgressReceivedUpdate();
}
hook.memoizedState = newState;
hook.baseState = newBaseState;
// 将被执行完毕的链表节点保存
hook.baseQueue = newBaseQueueLast;
queue.lastRenderedState = newState;
}
const dispatch: Dispatch<A> = (queue.dispatch: any);
return [hook.memoizedState, dispatch];
}
hook中的更新和setState的更新区别是,state不会被合并也就是没有使用Object.assagin()
setState的更新由updater对象提供。计算完成过state之后的更新和hook一致
on ✌️
let workInProgress = null, workInProgressRoot = null;
let workInProgressHook = null, firstWorkInProgressHook = null;
const currentHook = {
current: null
};
function mountCurrentHook(initialiState) {
const nextHook = {
memoizedState: initialiState,
baseState: initialiState,
queue: null,
next: null
};
// 首次挂载hook
if (firstWorkInProgressHook === null) {
firstWorkInProgressHook = workInProgressHook = nextHook;
} else {
workInProgressHook = workInProgressHook.next = nextHook;
}
return workInProgressHook;
}
function updateCurrentHook() {
let currentAction = workInProgressHook.queue.pending;
workInProgressHook.queue.pending = null;
let nextState = workInProgressHook.memoizedState;
if (currentAction !== null) {
currentAction.next.next = null;
while (currentAction !== null) {
let nextAction = currentAction.action;
if (typeof nextAction === "function") {
nextState = nextAction(workInProgressHook.memoizedState);
} else {
nextState = nextAction;
}
currentAction = currentAction.next;
}
}
workInProgressHook.memoizedState = nextState;
let nextHook = workInProgressHook;
if (firstWorkInProgressHook === workInProgressHook) {
firstWorkInProgressHook = workInProgressHook;
} else {
workInProgressHook = workInProgressHook.next;
}
return nextHook;
}
export function render(el, callback) {
const fiberRoot = {
element: el,
memoizedState: null,
callback: callback
};
currentHook.current = mountCurrentHook;
workInProgress = workInProgressRoot = fiberRoot;
schedulerUpdateFiberOnRoot(fiberRoot);
}
function schedulerUpdateFiberOnRoot(current) {
/* 理论上来说应该每次都从当前的fiber节点通过return指针找当应用的根节点,从根节点一次向下深度优先遍历。查找更新提交变更 */
workInProgress = workInProgressRoot;
workInProgressHook = firstWorkInProgressHook = workInProgress.memoizedState;
let jsx /* --~ */ = workInProgress.element();
workInProgress.memoizedState = firstWorkInProgressHook;
workInProgressHook = firstWorkInProgressHook = null;
workInProgress.callback(jsx)
document.getElementById("root").textContent = JSON.stringify({ count: jsx.count }, null, 4)
if (currentHook.current !== updateCurrentHook) {
currentHook.current = updateCurrentHook;
};
}
export function useState(initialiState) {
const hook = currentHook.current(initialiState);
const queue = hook.queue = {
pending: null,
dispatch: null
};
return [hook.memoizedState, dispatchAction.bind(null, queue, workInProgress)];
}
function dispatchAction(queue, fiber, action) {
const update = {
action,
nextState: null,
next: null
};
const pending = queue.pending;
if (pending === null) {
update.next = update;
} else {
// 插入一个新的udate对象,构成循环链表
update.next = pending.next;
pending.next = update;
}
queue.pending = update;
schedulerUpdateFiberOnRoot(fiber);
}
之前写的,现在加上 我也忘了能不能运行