中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

React18系列commit怎么實現

發布時間:2023-01-17 09:21:37 來源:億速云 閱讀:94 作者:iii 欄目:開發技術

本文小編為大家詳細介紹“React18系列commit怎么實現”,內容詳細,步驟清晰,細節處理妥當,希望這篇“React18系列commit怎么實現”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。

正文

本系列是講述從0開始實現一個react18的基本版本。由于React源碼通過Mono-repo 管理倉庫,我們也是用pnpm提供的workspaces來管理我們的代碼倉庫,打包我們使用rollup進行打包。

React中commit分為下面三個階段,這節我們講解簡單的commit階段:

  • beforeMutation階段

  • mutation階段

  • layout階段

這節主要講解commit其中的mutation placement階段:

我們經常把Renderer工作的階段被稱為commit階段。在commit階段,會將我們上一講中生成的各種flags提交(commit)到宿主環境UI中。我們前端通常使用的是ReactDOM進行處理。這節我們簡單的實現了一個ReactDom包,看看是如何把調和和瀏覽器環境連起來的。

橋梁

React中,react-reconcilerreact-dom是2個不同的包,react-dom主要是提供瀏覽器宿主相關的方法。回想我們每次在使用react開發項目的過程中,通過下方代碼調用:

ReactDom.createRoot(root).render(<App />)

所以需要提供createRoot方法。返回一個render方法,接收ReactElement元素。

export function createRoot(container: Container) {
  const root = createContainer(container);
  return {
    render(element: ReactElementType) {
      updateContainer(element, root);
    },
  };
}

內部通過createContainerupdateContainer建立2個包的連接。具體的流程可以查看我們之前的章節。

commit Effect

在上一節中,我們在workLoop執行完后后得到了一個帶有標記的wip fiber tree(如下圖所示), 在commit階段,我們要通過這個fiber樹將內容渲染到屏幕中。

React18系列commit怎么實現

commitRoot執行

將最后生成的finishedWork傳遞給commitRoot, 然后根據頂部的flagssubtreeFlags來判斷是否有渲染節點:

function commitRoot(root: FiberRootNode) {
  const finishedWork = root.finishedWork;
  if (finishedWork === null) {
    return;
  }
  // 重置
  root.finishedWork = null;
  // 判斷是否存在子階段需要執行的操作
  const subtreeHasEffect =
    (finishedWork.subtreeFlags & MutationMask) !== NoFlags; // 子節點是否有更新
  const rootHasEffect = (finishedWork.flags & MutationMask) !== NoFlags; // 根節點是否更新
  if (subtreeHasEffect || rootHasEffect) {
    // beforeMutation
    // mutation Placement
    commitMutationEffects(finishedWork);
    root.current = finishedWork;
    // layout
  } else {
    root.current = finishedWork;
  }
}

commitMutationEffects執行

我們知道div對應的fiberNode是標有flags = placement的,所以在hostFiberNode中的subtreeHasEffect是有值的,所以會走到commitMutationEffects分支。那它內部到底是有什么作用呢?

commitMutationEffects執行的主要作用就是找到對應flags的fiberNode, 并執行相應的Dom操作。

  • 我們需要向下遍歷找到最底部的subtreeFlags不為0的fiberNode的子fiberNode節點

  • 由于父節點的subtreeFlags存在,不代表child對應的flags存在,可能是child對應的sibling節點的flags存在

  • 所以在找到對應的subtreeFlagschild的fiberNode后,需要在向上遍歷,查找對應的sibling節點。

commitMutationEffectsOnFibers

對每一個fiberNode我們會執行commit Effects的操作。

const commitMutationEffectsOnFibers = (finishedWork: FiberNode) => {
  const flags = finishedWork.flags;
  if ((flags & Placement) !== NoFlags) {
    commitPlacement(finishedWork);
    finishedWork.flags &= ~Placement;
  }
  // flags update
  // flags childDeletion
};
const commitPlacement = (finishWork: FiberNode) => {
  if (__DEV__) {
    console.warn("執行commitPlacement操作", finishWork);
  }
  // parentDom 插入 finishWork對應的dom
  // 1. 找到parentDom
  const hostParent = getHostParent(finishWork);
  if (hostParent !== null) {
    appendPlacementNodeIntoContainer(finishWork, hostParent);
  }
};

其中有一個getHostParent是獲取到對應父Container(容器元素),對應瀏覽器環境就是Dom,

getHostParent執行

找父contianer容器,向上遞歸 主要是分為2大類。第一類是對應HostComponent(類似<div>), 第二類就是根節點(#root), 他們分別對應不同的位置。

function getHostParent(fiber: FiberNode): Container | null {
  let parent = fiber.return;
  while (parent) {
    const parentTag = parent.tag;
    // HostComponent  HostRoot
    if (parentTag === HostComponent) {
      return parent.stateNode as Container;
    }
    if (parentTag === HostRoot) {
      return (parent.stateNode as FiberRootNode).container;
    }
    parent = parent.return;
  }
  if (__DEV__) {
    console.warn("未找到HostParent");
  }
  return null;
}

appendPlacementNodeIntoContainer執行

當我們上一步找到父container后,接下來就是要把自身的stateNode插入到父container中,然后渲染的界面上。

appendPlacementNodeIntoContainer 這個函數接受2個參數,第一個是當前fiberNode, 第二個父container。想想什么樣的fiberNode需要渲染到屏幕中。目前demo層級來看,只有下面2個節點需要展示到屏幕中。

  • HostComponent

  • HostText

所以appendPlacementNodeIntoContainer需要向下找到對應的節點。然后插入到contaienr中

function appendPlacementNodeIntoContainer(
  finishedWork: FiberNode,
  hostParent: Container
) {
  // fiber Host
  if (finishedWork.tag === HostComponent || finishedWork.tag === HostText) {
    appendChildToContainer(hostParent, finishedWork.stateNode);
    return;
  }
  const child = finishedWork.child;
  if (child !== null) {
    appendPlacementNodeIntoContainer(child, hostParent);
    let sibling = child.sibling;
    while (sibling !== null) {
      appendPlacementNodeIntoContainer(sibling, hostParent);
      sibling = sibling.sibling;
    }
  }
  return null;
}

例子:

我們通過一個特定的例子,來講解commit mutation中具體的執行過程。比如:我們有如下的結構,更新的flags標記如下:

React18系列commit怎么實現

commitMutationEffects會找到subtreeFlags值不為0的頂層fiberNode,然后開始向下遍歷,直到找到world fiberNode

遞歸向上的執行commitMutationEffectsOnFibers,先自己,然后sibling, 然后return

commitMutationEffectsOnFibers: 例如world fiberNode,自身flags = 1,然后會通過getHostParent找到類型為HostComponentdiv fiberNode, 然后把自己的stateNode對應的dom, 通過appendChild插入到div fiberNodestateNode中。

這樣一直向上,最終就會把div fiberNode對應的dom元素,appendroot中。

讀到這里,這篇“React18系列commit怎么實現”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

南阳市| 四平市| 革吉县| 章丘市| 新密市| 托克逊县| 余庆县| 蒲城县| 荣昌县| 绵阳市| 益阳市| 昔阳县| 无极县| 信宜市| 克什克腾旗| 平罗县| 绥宁县| 乌审旗| 巧家县| 南通市| 宜良县| 闵行区| 许昌市| 株洲市| 黄大仙区| 永州市| 大姚县| 绥阳县| 西安市| 通海县| 东安县| 松滋市| 大余县| 瑞安市| 武宁县| 定襄县| 宾川县| 临清市| 盘山县| 正蓝旗| 沈丘县|