ReactにおけるDOM構築について
ReactはDOMを仮に構築する仕組みを備えており、仮想DOMを設計してからリアルDOMを作成するため、従来のDOMやフレームワークで構築されたDOMに比べて処理のスピードが速く、Webページの表示を高速で切り替えることができます。
DOMについて
DOM(Document Object Model)は、HTMLファイルのソースコードのことではなく、画面を表示するまでに解釈したHTML/CSS/JavaScriptによって構築されたDOM(ツリー)を指します。DOMはChromeやFireFox、Safari、IEなどのブラウザ上で、Webページを描画するために構築されます。
Chromeの開発者ツールのElementsタブでDOMツリーを見てみます(イメージ)。
ここで表示されているものはHTMLのソースコードそのものではなく、ブラウザ上にwebページを描画するために解釈されたHTML/CSS/JavaScriptよって構築されたDOMになります。
DOMツリーの最上階は「Document」で、DocumentとはHTML全体を表しています。
DOMはWebページとスクリプトやプログラミング言語を接続するものであり、JavaScriptなどによって、要素の値をダイレクトに操作することができます。
JavaScriptや従来のフレームワーク(jQueryなど)では、スクリプトのロジックから受け取った情報をもとにHTMLを作成し、それを元にブラウザに表示するための描画を行います。
状態が変わるなど情報に変化があった場合は、改めて情報を受け取り直してからDOMを再構築し、それを元に再描画を行って画面を変化させるので表示が遅くなってしまいます。
仮想DOM(VIRTUAL DOM)について
Reactにおける仮想DOMとは、情報を受け取ってもすぐにはブラウザの描画を行わず、まずはバーチャルなDOM(プログラム的に作成された仮のDOM)を構築することを指します。そして、構築された仮想DOMの内容を元にHTMLを作成し、実際のDOM(リアルDOM)に同期されます。このプロセスは差分検出処理 (reconciliation)と呼ばれます。
この仮想DOMはリアルDOMに比べ、ページ表示の高速化を実現します。
仮想DOMを利用することで、ページ変更前と変更後を仮想DOMを比較、情報が変化した部分だけを素早く見つけ出し、変更差分だけリアルDOMに反映するので、変更が最小限に抑えられるという仕組みです。
無駄のないDOMの操作処理を行うことで、ページ表示の高速化によるパフォーマンス向上を実現します
コンポーネントのレンダリングと描画について
レンダリングとは
Reactにおけるレンダリングとは、現在のPropsとStateを元に、コンポーネントに対して、それらがどのように画面上に表示されるか、実際にDOMに変更を加える必要があるかどうかを知るために行われるプロセスです。
コンポーネントツリーのルートから開始し、前回との差分を見つけるために下方にループしていき、デフォルトでは子孫コンポーネントのすべてが再帰的にレンダリングします。言い換えると親コンポーネントがレンダリングするとその子コンポーネントもすべてレンダリングされるということです。
関数コンポーネントのレンダリングは以下のタイミングで行われます。
- コンポーネントの初回レンダリング時
- 親コンポーネントがレンダリングされた時すべての子コンポーネントは無条件にレンダリングされる
- コンポーネント内で定義された
useState()
の状態変数/現在の値に変化があった時 - カスタムフックからコンポーネントが受け取っている変数が変化した時
Reactがレンダリングを行うのは、変更前と変更後の仮想DOMを構築し変更差分を検出することで、リアルDOMを構築する必要があるかどうかを知るための手段です。変更差分がなければ、DOMの更新は行われません。
描画とは
描画とは、レンダリングによって変更差分が見つかった場合に構築されたリアルDOMをブラウザに反映させることを指します。よってReactがコンポーネントを再レンダリングしても、変更差分がなければ再描画されません。
「レンダリング」の結果、変更差分があった場合「描画」されるので、しっかり区別します。
Reactにおけるパフォーマンス・チューニング
Reactコンポーネントで行われるレンダリングの一連の流れは、当然コストがかかってきます。レンダリングに問題があるわけではないのですが、レンダリングには時間やコストがかかり、レンダリングの結果、変更差分がなく、DOMに変更がなかった場合、結果的に「無駄なレンダリング」がおこなわれてしまったことになります。
コンポーネントのPropsとStateが変更されていないことが事前にわかっていれば、レンダリング出力は同じなので、作業をスキップできるはずです!!
↓パフォーマンス・チューニングの記事も参考にしてみてください↓
【React】もっと速くなる!?React.memo, useCallBack, useMemoでパフォーマンス最適化に挑戦!