点击进入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); } } }
整个节点的更新过程比较单纯,将新的属性值或者新的文本内容设置到节点上,并不涉及其他复杂的操作,比较好理解。
欢迎扫码关注公众号,发现更多技术文章