Reactのレンダリングプロセス
2021/01/10
Reactのレンダリングプロセスには2段階のステージがある。
①Render ステージ
②Commit ステージ
①のRenderステージは、仮想DOMの構築から差分検出処理(リコンシリエーション)までを含む。
②のCommitステージは、検出した差分を実DOMに反映する段階である。
①Renderステージ
このステージで行われることは、
- 仮想DOMの構築
- 差分検出処理
である。
RenderステージでレンダリングされているDOMについては、React Developer Tools
のHighlight updates when components render
機能で可視化することができる。
①-1 仮想DOMの構築
初回レンダリングではマウントが起こり、DOMを0から構築する。マウント後はpropsやstateの変更が起きたコンポーネント、及びその子コンポーネントのみ再レンダリングされる。(createReactElement()
が実行される。)
ここでいうレンダリングとは、関数コンポーネントの本体(あるいはクラスコンポーネントのrender()
)が呼ばれることを指す。
この段階の無駄な再レンダリングを防ぐ方法を以下に示す。
関数コンポーネントの場合
const MyComponent = React.memo(function MyComponent(props) {
/* render using props */
});
もしあるコンポーネントが同じ props を与えられたときに同じ結果をレンダーするなら、React はコンポーネントのレンダーをスキップし、最後のレンダー結果を再利用します。
React.memoを使用することで、受け取ったpropsが等価の場合にそのコンポーネントのレンダリングをスキップすることができる。
const memoizedCallback = useCallback(
() => {doSomething(a, b);},
[a, b],
);
React.memoと併用することで、コンポーネントの不要な再レンダリングをスキップできる。あるコンポーネントにアロー関数をpropsとして渡している場合は、renderのたびに新しい関数を生成するため、React.memoが意味をなさなくなる。useCallbackはアロー関数の再生成を防ぐことができる。
クラスコンポーネントの場合
-
- props(とstate)の変更を検知し、変更が無いとみなされれば、そのコンポーネントのレンダリングをスキップすることができる。
- デフォルトでは
ShouldComponentUpdate()
は常にtrueを返すため、常に再レンダリングが起こるようになっている。
-
- 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
で確認することができる。
参考
- Reactのレンダリングに関する完全ガイド - Qiita
- React.memo / useCallback / useMemo の使い方、使い所を理解してパフォーマンス最適化をする - Qiita
- リアルな DOM はなぜ遅いのか
- React に優しい僕でありたい - Qiita
- React製のSPAのパフォーマンスチューニング実例
/post-10
Reactのレンダリングプロセス
Related Posts