1、Update
位置:Update
位置以下( 详情请看React源码解析之ReactDOM.render() ):updateContainer()
—>updateContainerAtExpirationTime()
—>scheduleRootUpdate()
—>createUpdate()
javascript
做用:
(1)用来记录组件的状态变化
(2)存放在UpdateQueue
中
(3)多个Update
能够同时存在
好比设置三个setState()
,React
是不会当即更新的,而是放到UpdateQueue
中,再去更新java
源码:react
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
时,为捕获性更新,也就是在更新中捕获到错误时,渲染成错误状态web
(2)多个update
会push
进更新队列中,next
属性指向下一节点app
2、UpdateQueue
位置:UpdateQueue
位置以下( 详情请看React源码解析之ReactDOM.render() ):updateContainer()
—>updateContainerAtExpirationTime()
—>scheduleRootUpdate()
—>enqueueUpdate(current, update)
——>createUpdateQueue()
ide
做用:
依次执行内部的update
spa
源码:code
//建立更新队列
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
orm
(2)firstUpdate
和lastUpdate
之间的update
经过上个update
的next
串联cdn
3、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
(完)