🔖
React操作によりアップデートからDomへ反映までの流れ②(1-2の変化)
背景
今までは二つのステップを進んできました。
-
初期マウントのステップ:画面なにもない時に、画面をローディングして、0が画面に出てきたステップ。
https://zenn.dev/villa_ak99/articles/2e4194e8367452 -
初めてクリックにより、画面は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のレンダリング段階が終わります。
レンダリング段階では主に以下の作業がされました
- FiberNodeの再構築、使いまわせるFiberNodeはそのまま使いまわします。
- FiberNodeのpendingPropsを元にupdateQueueを計算します。これからのcommitフェーズの材料となるのは、計算したupdateQueueです。
Discussion