🔖

React操作によりアップデートからDomへ反映までの流れ②(1-2の変化)

2022/08/24に公開

背景

今までは二つのステップを進んできました。

  1. 初期マウントのステップ:画面なにもない時に、画面をローディングして、0が画面に出てきたステップ。
    https://zenn.dev/villa_ak99/articles/2e4194e8367452

  2. 初めてクリックにより、画面は0から1へ変化したステップ。
    https://zenn.dev/villa_ak99/articles/af47a6601c877c

今回、2を踏まえて、もう一度クリックします、画面上は1から2まで変化します。
クリックしてから、メモリにどのような変化があるかを説明いたします。

Reactバージョン情報

    "react": "^18.0.2",
    "react-dom": "^18.0.2",

コード

app.tsx

import { useState } from 'react';

function App() {
  const [num,setNum] = useState(0)

  return (
    <div className="container" onClick={() => setNum(num + 1)}>
      <p className='subContainer'>
        {num}
      </p>
    </div>
  );
  
}

export default App;

レンダリングフェーズ

Top->Down beginWork

1. 最初の状態

現在、メモリの中には、二つのFiberNodeツリーが存在しています。

  • 右側のFiberNodeツリー(初期マウントの時(空白->0)に構築したFiberNodeツリー)
  • 左側のFiberNodeツリー(0->1へ変化する時に構築したFiberNodeツリー)
    現在一番上のfiberRootNodeからcurrentプロパティで指しているFiberNodeツリーは左側のFiberNodeツリーです。それはcurrentと呼びます。
2. クリックにより、以下の手順が発生します
  • 現在のFiberNodeツリーのApp関数のFiberNodeのmemorizedStateプロパティーにアップデート情報を入れます。(memorizedState.queue.interleavedに入れます)
  • memorizedState.queue.interleaved -> memorizedState.queue.pendding(この変換はreact18からの設計です)
  • レンダリングを促します。
3.rootFiberのレンダリング
  • 構築中のFiberNodeツリーのrootFiberを作ります。ここは最初マウント時に作ったrootFiberをそのまま使い回します。
  • ただし、pendingProps, types,memorizedStateなど最新の情報はcurrentのrootFiberに存在しますので、これらのプロパティーそのままcurrentから引用します。
  • 使いまわしたrootFiberのchildを一時的にcurrentツリーのrootFiber.childに指します。
4. App関数のFiberNodeのレンダリング
  • 最初マウント時に作ったApp関数のFiberNodeをそのまま使い回します。
  • pendingProps, types,memorizedStateなど最新の情報はcurrentのapp関数のFiberNodeに存在しますので、これらのプロパティーそのままcurrentから引用します。
  • 使いまわしたApp関数のFiberNodeのchildを一時的にcurrentツリーのApp関数のFiberNodeのchildに指します。
  • 構築中のFiberNodeツリーのrootFiberのchildを使いましたApp関数のFiberNodeに指します。
5.div.containerのFiberNodeのレンダリング
  • workInProgressとcurrentポインターは一個したの層に移動します。
  • 関数Appを実行し、実行結果はReact.Element型になり、実行結果を返します。
  • 最初マウント時に作ったdiv.containerのFiberNodeをそのまま使い回します。
  • types,memorizedStateなど最新の情報はcurrentのdiv.containerのFiberNodeに存在しますので、これらのプロパティーそのままcurrentから引用します。penddingPropsは関数Appの実行から生成したオブジェクトなので、それをpenddingPropsの値として更新します。
  • 構築中のFiberツリーの関数AppのFiberNodeのchildプロパティーを作ったdiv.containerのFiberNodeに指します。
6.p.subContainerのFiberNodeのレンダリング
  • workInProgressとcurrentポインターは一個したの層に移動します。
  • 最初マウント時に作ったp.subContainerのFiberNodeをそのまま使い回します。
  • types,memorizedStateなど最新の情報はcurrentのp.subContainerのFiberNodeに存在しますので、これらのプロパティーそのままcurrentから引用します。penddingPropsは関数Appの実行から生成したオブジェクトなので、それをpenddingPropsの値として更新します。
    penddingPropsは以下になります。
pendingProps:
children: 2
className: "subContainer"

7. 葉FiberNodeまでたどりつきます。
  • workInProgressとcurrentポインターは一個したの層に移動します。

ここまでTop2Downのdfsは完了、これからDown2Topバックトラッキングになります。

Back -> Top CompleteWork

1. p.subContainerのFiberNodeのupdateQueueの計算
  • FiberNodeにあるpendingProsプロパティーからmemorizedPropsプロパティーと比較、updateQueueを計算します

    計算したupdateQueueは以下になります、それはp.subContainerのFiberNodeのupdateQueueプロパティーに入れておきます。
 ['children', '2']
2. div.containerのFiberNodeのupdateQueueの計算

  • currentとworkInProgressは上のFiberNodeに戻ります
  • div.containerのFiberNodeのUpdateQueueを計算します。計算方法は前のステップと同じく、pendingPropsとmemorizedPropsと比較して、結果を得ます。
  • 計算したupdateQueueは以下になります
[]
3. App関数のFiberNodeのupdateQueue計算

  • currentとworkInProgressは上のFiberNodeに戻ります
    App関数のFiberNodeはReact上の定義ではMemoComponentなので、特にupdateQueueを計算しません
    updateQueueはnullのままになっています。
4. rootFiberのupdateQueue計算

  • currentとworkInProgressは上のFiberNodeに戻ります
    rootFiberはReact上の定義としてはHostRootなので、特にupdateQueueを計算しません、updateQueueは変わりません。

ここまではReactのレンダリング段階が終わります。
レンダリング段階では主に以下の作業がされました

  1. FiberNodeの再構築、使いまわせるFiberNodeはそのまま使いまわします。
  2. FiberNodeのpendingPropsを元にupdateQueueを計算します。これからのcommitフェーズの材料となるのは、計算したupdateQueueです。

commitフェーズ

Discussion