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
(完)