【Reactが動く仕組み】シリーズ
Reactでコードを書いて、アプリは作れる。
でも、「どうやって動いているのか?」と聞かれると、言葉にできない…。
一歩踏み出して、「裏側の仕組みを理解して説明できる」を目指したシリーズです。
全7弾で以下の内容を記載予定です。
1.Node.js(実行環境)
2.ビルド(構築の流れ)
3.Babel / polyfill(変換)
4.DOM / 仮想DOM(仕組み)
5.レンダリング(動き)
6.再レンダリング(なぜ起きる?)
7.最適化(どう見極める?)
今回はその第6弾として、「再レンダリング」について整理していきます。
はじめに
第5弾では、レンダリングの仕組みについて整理しました。
👉 stateが変わると、コンポーネントが再実行される
👉 仮想DOMが再生成され、差分だけが更新される
という流れでした。
しかし、Reactを使っていると、
「なんでこれ再レンダリングされるの?」
「別に変えてないのに…」
と、違和感を感じることがあります。
この記事でわかること
- 再レンダリングとは何か
- なぜ意図しない再レンダリングが起きるのか
- Reactの挙動の考え方
再レンダリングとは何か
再レンダリングとは、
👉 コンポーネント関数が再実行されること
👉 「描画し直す」ではなく、「再計算される」イメージ
ここで重要なのは
👉 「DOMが全部更新される」わけではないということ
👉 実際に更新されるのは「差分だけ」
あくまで
- 関数が再実行される
- 仮想DOMが作られる
- 差分だけ更新される
再レンダリングは重くなる?
❌ 再レンダリング = 重い
必ずしもそうではありません
Reactは差分更新するため、
多くの場合は問題にならない
👉 「回数」よりも「処理の重さ」が重要
ではなぜ「意図しない」と感じる再レンダリングが発生するのか?
ここが本題です。
原因① 親コンポーネントが再レンダリングされている
Reactの基本ルール
👉 親が再レンダリングされると、子も再レンダリングされる
例:
function Parent() {
const [count, setCount] = useState(0);
return <Child />;
}
setCount が呼ばれると
- Childも再レンダリングされる
- 子の中身が変わってなくても関係ない
つまり、ツリー構造で「下に伝播する」
原因② propsが変わったと判定される
Reactは【前回と今回で値が違うか】で判断しています
例えば
<Child data={{ value: 1 }} />
毎回新しいオブジェクトが作られる
↓
毎回違うと判定される
↓
結果:毎回再レンダリング
原因③ 関数も毎回作られている
<Child onClick={() => console.log("click")} />
JavaScriptでは関数も「値」として扱われるため
この関数は、毎回新しく生成されている
つまり
propsが変わった扱いになる
原因④ stateが変わっている(当たり前だけど重要)
setCount(count + 1);
これは当然 ↓
再レンダリングが発生する
ただし
「どこが再レンダリングされるか」は意識する必要がある
ここまでの整理
再レンダリングが起きる主な原因 ↓
- stateが変わった
- 親が再レンダリングされた
- propsが変わった(オブジェクト・関数)
👉 ほとんどはReactの仕様通り
じゃあ防ぐべきなのか?
ここが大事☆
全部防ぐ必要はない
なぜなら
👉 Reactはもともと再レンダリングを前提に設計されている
むしろ
過剰に最適化すると複雑になる
どう考えるべきか
推奨される考え方 ↓
👉 「問題が出たら最適化する」
最初から
- useMemo
- useCallback
- React.memo
を多用する必要はない
👉 シンプルに書いてみて、「まずは正しく動くこと」を優先する
まとめ
- 再レンダリングとは、コンポーネントの再実行
- DOMが全部更新されるわけではない
- 主な原因は、state・親・propsの変化
- 多くの場合、再レンダリングは問題ない
👉 再レンダリングは「悪」ではなく、Reactの正常な動き
第7弾に向けて
ここまでで、再レンダリングの仕組みは見えてきました。
では次に気になるのは
👉 「どこまでが問題で、どこから最適化すべきなのか?」
次回は「最適化」をテーマに、
パフォーマンス改善の考え方を整理していきます。