Obake Engineer Blog

Reactのレンダリングプロセス

2021/01/10

Reactのレンダリングプロセスには2段階のステージがある。
①Render ステージ
②Commit ステージ

①のRenderステージは、仮想DOMの構築から差分検出処理(リコンシリエーション)までを含む。 ②のCommitステージは、検出した差分を実DOMに反映する段階である。

React のライフサイクルメソッド図

①Renderステージ

このステージで行われることは、

  1. 仮想DOMの構築
  2. 差分検出処理

である。
RenderステージでレンダリングされているDOMについては、React Developer ToolsHighlight updates when components render機能で可視化することができる。

①-1 仮想DOMの構築

初回レンダリングではマウントが起こり、DOMを0から構築する。マウント後はpropsやstateの変更が起きたコンポーネント、及びその子コンポーネントのみ再レンダリングされる。(createReactElement()が実行される。)

ここでいうレンダリングとは、関数コンポーネントの本体(あるいはクラスコンポーネントのrender())が呼ばれることを指す。

この段階の無駄な再レンダリングを防ぐ方法を以下に示す。

関数コンポーネントの場合

jsx
const MyComponent = React.memo(function MyComponent(props) {
  /* render using props */
});

もしあるコンポーネントが同じ props を与えられたときに同じ結果をレンダーするなら、React はコンポーネントのレンダーをスキップし、最後のレンダー結果を再利用します。

React.memoを使用することで、受け取ったpropsが等価の場合にそのコンポーネントのレンダリングをスキップすることができる。

jsx
const memoizedCallback = useCallback(
  () => {doSomething(a, b);},
  [a, b],
);

React.memoと併用することで、コンポーネントの不要な再レンダリングをスキップできる。あるコンポーネントにアロー関数をpropsとして渡している場合は、renderのたびに新しい関数を生成するため、React.memoが意味をなさなくなる。useCallbackはアロー関数の再生成を防ぐことができる。

クラスコンポーネントの場合

  • ShouldComponentUpdate()

    • props(とstate)の変更を検知し、変更が無いとみなされれば、そのコンポーネントのレンダリングをスキップすることができる。
    • デフォルトではShouldComponentUpdate()は常にtrueを返すため、常に再レンダリングが起こるようになっている。
  • PureComponent

    • propsとstateをshallow compareし、変更が無いとみなされれば、そのコンポーネントのレンダリングをスキップすることができる。
    • ShouldComponentUpdateの代用となる。
    • [React] Component と PureComponentの違い - Qiita

①-2 差分検出処理

①-1で構築した仮想DOMと、実DOMの差分を検出する。
このときkey値が同じDOMは差分が無いとみなすことができ、後の実DOM構築の処理を少なくすることができる。
詳しくはReact公式の差分検出処理を参照。

②Commitステージ

①-2で検出した差分を実DOMに反映する段階である。 このとき描画されるDOMは、Chrome devtoolsのrendering > paintflashingで確認することができる。

参考

/post-10

Reactのレンダリングプロセス

Related Posts

obake
Obake Engineer Blog