點擊進入React源碼調試倉庫。
React的更新最終要落實到頁面上,所以本文主要講解DOM節點(HostComponent)和文本節點(HostText)的更新,對於前者來說更新是props的更新,對後者來說更新是文字內容的更新。
commitWork
是節點更新的入口。
function commitMutationEffectsImpl(
fiber: Fiber,
root: FiberRoot,
renderPriorityLevel,
) {
...
switch (primaryEffectTag) {
...
case Update: {
const current = fiber.alternate;
commitWork(current, fiber);
break;
}
}
}
commitWork重點處理了HostComponent和HostText。
更新HostText,實際上也就是更新文本內容,過程比較簡單,最終調用commitTextUpdate
來設置文本內容。
function commitWork(current: Fiber | null, finishedWork: Fiber): void {
...
switch (finishedWork.tag) {
...
case HostText: {
const textInstance: TextInstance = finishedWork.stateNode;
const newText: string = finishedWork.memoizedProps;
const oldText: string =
current !== null ? current.memoizedProps : newText;
commitTextUpdate(textInstance, oldText, newText);
return;
}
}
...
}
更新HostComponent是更新fiber節點上的props,這需要使用到在render階段的complete過程中節點props的diff結果:fiber.updateQueue。再來回顧壹下它的形式:數組,以2為單位,index為偶數的是key,為奇數的是value。
[ 'style', { color: 'blue' }, title, '測試標題' ]
整個更新過程就是遍歷數組,最終調用updateDOMProperties
將屬性和值設置到DOM節點上。
function updateDOMProperties(
domElement: Element,
updatePayload: Array<any>,
wasCustomComponentTag: boolean,
isCustomComponentTag: boolean,
): void {
// 遍歷updateQueue數組,應用更新
for (let i = 0; i < updatePayload.length; i += 2) {
const propKey = updatePayload[i];
const propValue = updatePayload[i + 1];
if (propKey === STYLE) {
setValueForStyles(domElement, propValue);
} else if (propKey === DANGEROUSLY_SET_INNER_HTML) {
setInnerHTML(domElement, propValue);
} else if (propKey === CHILDREN) {
setTextContent(domElement, propValue);
} else {
setValueForProperty(domElement, propKey, propValue, isCustomComponentTag);
}
}
}
整個節點的更新過程比較單純,將新的屬性值或者新的文本內容設置到節點上,並不涉及其他復雜的操作,比較好理解。