当组件装载的时候
function mountState<S>(
initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {
const hook = mountWorkInProgressHook();
if (typeof initialState === 'function') {
// $FlowFixMe: Flow doesn't like mixed types
initialState = initialState();
}
hook.memoizedState = hook.baseState = initialState;
const queue = (hook.queue = {
pending: null,
dispatch: null,
lastRenderedReducer: basicStateReducer,
lastRenderedState: (initialState: any),
});
const dispatch: Dispatch<
BasicStateAction<S>,
> = (queue.dispatch = (dispatchAction.bind(
null,
currentlyRenderingFiber,
queue,
): any));
return [hook.memoizedState, dispatch];
}
可以看出代码主要就是初始化hook.memoizedState和queue.dispatch的值,其中hook.queue中包含lastRenderedReducer和lastRenderedState,根据字面意思我们就知道,保存的是当前的值,其中lastRenderedReducer的值为:
function basicStateReducer<S>(state: S, action: BasicStateAction<S>): S {
// $FlowFixMe: Flow doesn't like mixed types
return typeof action === 'function' ? action(state) : action;
}
lastRenderedState的值为:initialState。也就是装载时的值。
其中dispatch也就是更新state的。
function dispatchAction<S, A>(
fiber: Fiber,
queue: UpdateQueue<S, A>,
action: A,
) {
const eventTime = requestEventTime();
const suspenseConfig = requestCurrentSuspenseConfig();
const lane = requestUpdateLane(fiber, suspenseConfig);
const update: Update<S, A> = {
eventTime,
lane,
suspenseConfig,
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)
) {
didScheduleRenderPhaseUpdateDuringThisPass = didScheduleRenderPhaseUpdate = true;
} else {
if (
fiber.lanes === NoLanes &&
(alternate === null || alternate.lanes === NoLanes)
) {
const lastRenderedReducer = queue.lastRenderedReducer;
if (lastRenderedReducer !== null) {
const currentState: S = (queue.lastRenderedState: any);
const eagerState = lastRenderedReducer(currentState, action);
update.eagerReducer = lastRenderedReducer;
update.eagerState = eagerState;
if (is(eagerState, currentState)) {
return;
}
}
}
scheduleUpdateOnFiber(fiber, lane, eventTime);
}
}
我删除了没有必要的注释和调试代码。我们知道装载的时候传进来的参数,其中:
- filter
currentlyRenderingFiber
- queue
{
pending: null,
dispatch: null,
lastRenderedReducer: basicStateReducer,
lastRenderedState: (initialState: any),
}
- action 这是使用者传入的
说个简单例子来看:
// 初始的状态
const initialState = 0
// state定义
const [count, setCount] = useState(initialState)
// 当我们更新的时候
setCount((count) => count + 1)
// 相当于调用了
dispatch((count) => count + 1) // 这里的action就是(count) => count + 1
dispatchAction函数中下面三个:
const eventTime = requestEventTime();
const suspenseConfig = requestCurrentSuspenseConfig();
const lane = requestUpdateLane(fiber, suspenseConfig);
跟请求相关,这个跟内部调度有关,目前还不知道。暂时先放一放。
准备功能,只不过这些都不是这次关心的重点,或者以后有用:
const pending = queue.pending;
if (pending === null) {
update.next = update;
} else {
update.next = pending.next;
pending.next = update;
}
queue.pending = update;
肯定会走if,因为装载的时候pending的值为null,所以这里相当于:
update.next = update;
queue.pending = update;
看值是怎么更新的:
const currentState: S = (queue.lastRenderedState: any);
const eagerState = lastRenderedReducer(currentState, action);
update.eagerReducer = lastRenderedReducer;
update.eagerState = eagerState;
可以看出,更新的值是通过lastRenderedReducer得到的。这个函数的定义在上面,非常简单。这些准备工作做完了,就开始了react内部的一些功能,这块以后再看。
scheduleUpdateOnFiber(fiber, lane, eventTime);
当组件更新的时候
function updateState<S>(
initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {
return updateReducer(basicStateReducer, (initialState: any));
}
这个函数会在组件除了初次渲染以后每次渲染的时候调用。我们看看updateReducer函数:
function updateReducer<S, I, A>(
reducer: (S, A) => S,
initialArg: I,
init?: I => S,
): [S, Dispatch<A>] {
const hook = updateWorkInProgressHook();
const queue = hook.queue;
queue.lastRenderedReducer = reducer;
const current: Hook = (currentHook: any);
let baseQueue = current.baseQueue;
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) {
const first = baseQueue.next;
let newState = current.baseState;
let newBaseState = null;
let newBaseQueueFirst = null;
let newBaseQueueLast = null;
let update = first;
do {
const suspenseConfig = update.suspenseConfig;
const updateLane = update.lane;
const updateEventTime = update.eventTime;
if (!isSubsetOfLanes(renderLanes, updateLane)) {
const clone: Update<S, A> = {
eventTime: updateEventTime,
lane: updateLane,
suspenseConfig: suspenseConfig,
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;
}
currentlyRenderingFiber.lanes = mergeLanes(
currentlyRenderingFiber.lanes,
updateLane,
);
markSkippedUpdateLanes(updateLane);
} else {
if (newBaseQueueLast !== null) {
const clone: Update<S, A> = {
eventTime: updateEventTime,
lane: NoLane,
suspenseConfig: update.suspenseConfig,
action: update.action,
eagerReducer: update.eagerReducer,
eagerState: update.eagerState,
next: (null: any),
};
newBaseQueueLast = newBaseQueueLast.next = clone;
}
markRenderEventTimeAndConfig(updateEventTime, suspenseConfig);
if (update.eagerReducer === reducer) {
newState = ((update.eagerState: any): S);
} else {
const action = update.action;
newState = reducer(newState, action);
}
}
update = update.next;
} while (update !== null && update !== first);
if (newBaseQueueLast === null) {
newBaseState = newState;
} else {
newBaseQueueLast.next = (newBaseQueueFirst: any);
}
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.memoizedState, dispatch],跟上面的都是一样的,其中第一个hook.memoizedState的相关的:
let newState = current.baseState;
do {
const suspenseConfig = update.suspenseConfig;
const updateLane = update.lane;
const updateEventTime = update.eventTime;
if (!isSubsetOfLanes(renderLanes, updateLane)) {
const clone: Update<S, A> = {
eventTime: updateEventTime,
lane: updateLane,
suspenseConfig: suspenseConfig,
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;
}
currentlyRenderingFiber.lanes = mergeLanes(
currentlyRenderingFiber.lanes,
updateLane,
);
markSkippedUpdateLanes(updateLane);
} else {
if (newBaseQueueLast !== null) {
const clone: Update<S, A> = {
eventTime: updateEventTime,
lane: NoLane,
suspenseConfig: update.suspenseConfig,
action: update.action,
eagerReducer: update.eagerReducer,
eagerState: update.eagerState,
next: (null: any),
};
newBaseQueueLast = newBaseQueueLast.next = clone;
}
markRenderEventTimeAndConfig(updateEventTime, suspenseConfig);
if (update.eagerReducer === reducer) {
newState = ((update.eagerState: any): S);
} else {
const action = update.action;
newState = reducer(newState, action);
}
}
update = update.next;
} while (update !== null && update !== first);
if (newBaseQueueLast === null) {
newBaseState = newState;
} else {
newBaseQueueLast.next = (newBaseQueueFirst: any);
}
if (!is(newState, hook.memoizedState)) {
markWorkInProgressReceivedUpdate();
}
hook.memoizedState = newState;
同时也发现只有当baseQueue不为null的时候才会进行,否则使用原来的值,所以还需要看一下baseQueue的来源:
let baseQueue = current.baseQueue;
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;
}
看了看baseQueue的来源发现这一块目前还不能了解。
所以关于这个我们假定不为null,也就是if (baseQueue !== null) 这个条件满足。
发现大部分看不懂,其中:
if (update.eagerReducer === reducer) {
newState = ((update.eagerState: any): S);
} else {
const action = update.action;
newState = reducer(newState, action);
}
其中的update.eagerReducer我们可以知道,在装载的时候这里的值,也就是初始化的lastRenderedReducer,这个的值默认是下面的:
function basicStateReducer<S>(state: S, action: BasicStateAction<S>): S {
// $FlowFixMe: Flow doesn't like mixed types
return typeof action === 'function' ? action(state) : action;
}
也就是当以前的和现在的相同则使用以前的state,否者就需要调用当前的更新state,只不过我并不知道什么情况下相等,什么情况下不想等。这一点需要我进一步学习才可得知。
我也是在学习怎么看源码,所以如果真的有人看到了,并发现不对的地方,还望指出,看源码的方法如果有更好也可以告知。在此感谢