一、Update
位置:
Update
位置如下( 详情请看React源码解析之ReactDOM.render() ):
updateContainer()
—>
updateContainerAtExpirationTime()
—>
scheduleRootUpdate()
—>
createUpdate()
作用:
(1)用来记录组件的状态变化
(2)存放在UpdateQueue
中
(3)多个Update
可以同时存在
比如设置三个setState()
,React
是不会立即更新的,而是放到UpdateQueue
中,再去更新
源码:
export const UpdateState = 0;
export const ReplaceState = 1;
export const ForceUpdate = 2;
export const CaptureUpdate = 3;
export function createUpdate(
expirationTime: ExpirationTime,
suspenseConfig: null | SuspenseConfig,
): Update<*> {
return {
//更新的过期时间
expirationTime,
suspenseConfig,
// export const UpdateState = 0;
// export const ReplaceState = 1;
// export const ForceUpdate = 2;
// export const CaptureUpdate = 3;
//重点提下CaptureUpdate,在React16后有一个ErrorBoundaries功能
//即在渲染过程中报错了,可以选择新的渲染状态(提示有错误的状态),来更新页面
tag: UpdateState, //0更新 1替换 2强制更新 3捕获性的更新
//更新内容,比如setState接收的第一个参数
payload: null,
//对应的回调,比如setState({}, callback )
callback: null,
//指向下一个更新
next: null,
//指向下一个side effect
nextEffect: null,
};
}
解析:
update属性的解释均已写在代码中,需要注意的是
(1)tag
的值为CaptureUpdate
时,为捕获性更新,也就是在更新中捕获到错误时,渲染成错误状态
(2)多个update
会push
进更新队列中,next
属性指向下一节点
二、UpdateQueue
位置:
UpdateQueue
位置如下( 详情请看React源码解析之ReactDOM.render() ):
updateContainer()
—>
updateContainerAtExpirationTime()
—>
scheduleRootUpdate()
—>
enqueueUpdate(current, update)
——>
createUpdateQueue()
作用:
依次执行内部的update
源码:
//创建更新队列
export function createUpdateQueue<State>(baseState: State): UpdateQueue<State> {
const queue: UpdateQueue<State> = {
//应用更新后的state
baseState,
//队列中的第一个update
firstUpdate: null,
//队列中的最后一个update
lastUpdate: null,
//队列中第一个捕获类型的update
firstCapturedUpdate: null,
//队列中最后一个捕获类型的update
lastCapturedUpdate: null,
//第一个side effect
firstEffect: null,
//最后一个side effect
lastEffect: null,
firstCapturedEffect: null,
lastCapturedEffect: null,
};
return queue;
}
解析:
(1)baseState
在组件setState
后,渲染并更新state
,在下次更新时,拿的就是这次更新过的state
(2)firstUpdate
和lastUpdate
之间的update
通过上个update
的next
串联
三、enqueueUpdate()
作用:
单向链表,用来存放update
,next
来串联update
源码:
//每次setState都会update,每次update,都会入updateQueue
//current即fiber
export function enqueueUpdate<State>(fiber: Fiber, update: Update<State>) {
// Update queues are created lazily.
//alternate即workInProgress
//fiber即current
//current到alternate即workInProgress有一个映射关系
//所以要保证current和workInProgress的updateQueue是一致的
const alternate = fiber.alternate;
//current的队列
let queue1;
//alternate的队列
let queue2;
//如果alternate为空
if (alternate === null) {
// There's only one fiber.
queue1 = fiber.updateQueue;
queue2 = null;
//如果queue1仍为空,则初始化更新队列
if (queue1 === null) {
queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState);
}
} else {
// There are two owners.
//如果alternate不为空,则取各自的更新队列
queue1 = fiber.updateQueue;
queue2 = alternate.updateQueue;
if (queue1 === null) {
if (queue2 === null) {
// Neither fiber has an update queue. Create new ones.
//初始化
queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState);
queue2 = alternate.updateQueue = createUpdateQueue(
alternate.memoizedState,
);
} else {
// Only one fiber has an update queue. Clone to create a new one.
//如果queue2存在但queue1不存在的话,则根据queue2复制queue1
queue1 = fiber.updateQueue = cloneUpdateQueue(queue2);
}
} else {
if (queue2 === null) {
// Only one fiber has an update queue. Clone to create a new one.
queue2 = alternate.updateQueue = cloneUpdateQueue(queue1);
} else {
// Both owners have an update queue.
}
}
}
if (queue2 === null || queue1 === queue2) {
// There's only a single queue.
//将update放入queue1中
appendUpdateToQueue(queue1, update);
} else {
// There are two queues. We need to append the update to both queues,
// while accounting for the persistent structure of the list — we don't
// want the same update to be added multiple times.
//react不想多次将同一个的update放入队列中
//如果两个都是空队列,则添加update
if (queue1.lastUpdate === null || queue2.lastUpdate === null) {
// One of the queues is not empty. We must add the update to both queues.
appendUpdateToQueue(queue1, update);
appendUpdateToQueue(queue2, update);
}
//如果两个都不是空队列,由于两个结构共享,所以只在queue1加入update
//在queue2中,将lastUpdate指向update
else {
// Both queues are non-empty. The last update is the same in both lists,
// because of structural sharing. So, only append to one of the lists.
appendUpdateToQueue(queue1, update);
// But we still need to update the `lastUpdate` pointer of queue2.
queue2.lastUpdate = update;
}
}
}
解析:
(1)queue1
取的是fiber.updateQueue
;
queue2
取的是alternate.updateQueue
(2)如果两者均为null
,则调用createUpdateQueue()
获取初始队列
(3)如果两者之一为null
,则调用cloneUpdateQueue()
从对方中获取队列
(4)如果两者均不为null
,则将update
作为lastUpdate
(完)
网友评论