再レンダリングの最適化について
レンダリングとは
簡単に説明すると、下記の流れをまとめてレンダリングという
- コンポーネントの呼び出し
- 修正前後の差分の検出
- 差分があった場合にDOMの更新
レンダリングの種類
初期レンダリング
- web画面が初めて表示される時のレンダリング
- ブラウザ更新した際にはこっちが行われる
- 全てのDOMを使用して描画される
再レンダリング
- 2回目以降のレンダリング
- データが更新された時などに行われる
- 差分のみ更新される
再レンダリングされる条件
stateの変更
- コンポーネントの状態が
useState
フックなどを通じて変更された時、再レンダリングされる
propsの変更
- 親コンポーネントから渡されるプロップスが変更された時、それを受け取る受け取る子コンポーネントは再レンダリングされる
親コンポーネントのレンダリング
- 親コンポーネントが再レンダリングされた場合、その子コンポーネントもデフォルトでは再レンダリングされる
Contextの変更
- Contextを使用している場合、そのContextが更新されると、それを使用している全てのコンポーネントが再レンダリングされる
最適化方法
- 何も考えずに実装をしていると、何かステータスが変わると見境無く再レンダリングされてしまう
- 下記に後述するメモ化を利用することで、必要な時に必要なだけ再レンダリングを行えるように設定する
コンポーネントのメモ化
- 方法: メモ化したいコンポーネントをReact.memoで囲う
- 親コンポーネントがレンダリングされた時に、子コンポーネントが見境無く再レンダリングされるのを防ぐことができる
- コンポーネントをメモ化すると親要素に変更があっても再レンダリングされない
- propsの変更がある場合は再レンダリングされる
- ※ memo化も多少の負荷があるため、何も考えずにつけていい訳では無いが、基本的にはつけた方が良い
関数のメモ化
- 方法: メモ化したい関数をuseCallbackで囲う
- 関数を子コンポーネントに渡すと、関数に変化が無くても子コンポーネントは再レンダリングされてしまう。
→これを防ぐことができる - 関数に依存する値が変更されるまで初回の関数を保持し続ける
- ※ useCallbackにも負荷があるため、長い計算を必要とする関数や、初回以降不変の関数などにつけると良い
変数のメモ化
- 方法: メモ化したい変数をuseMemoで囲う
- 変数の無駄な再計算を防ぐことができる
- 計算に依存する値が変更されるまで初回の計算結果を保持し続ける
- ※ useMemo自体にも負荷があるため、複雑な計算をしている変数のみ使うと良い