iT邦幫忙

0

React和DOM的那些事-節點更新

點擊進入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的更新

更新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的更新

更新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);
    }
  }
}

總結

整個節點的更新過程比較單純,將新的屬性值或者新的文本內容設置到節點上,並不涉及其他復雜的操作,比較好理解。


尚未有邦友留言

立即登入留言