React DevTools Profiler:再レンダリングを特定してパフォーマンス改善
Profilerタブとは
React DevToolsの「Profiler」タブはReactコンポーネントのレンダリングを録画・計測するツールです。どのコンポーネントが何回・何ms かかって再レンダリングされたかを可視化でき、パフォーマンス問題の原因を特定できます。
開き方
- ブラウザの開発者ツールを開く(
F12) - 「⚛ Profiler」タブを選択
録画の基本操作
録画開始 → 操作 → 録画停止
- 左上の ● 録画ボタンをクリック(赤くなる)
- アプリ上で計測したい操作を行う(ボタンクリック・入力・ページ遷移など)
- 録画ボタンを再度クリックして停止
録画が終わると結果が表示されます。
フレームグラフの見方
録画後に「Flamegraph」タブが表示されます。
Commit #1 Commit #2 Commit #3 5.2ms 1.1ms 8.7ms
上部にコミット(Reactが実際にDOMを更新したタイミング)のリストが表示されます。数字はそのコミットの処理時間です。
フレームグラフの色
| 色 | 意味 |
|---|---|
| グレー | 今回のコミットで再レンダリングされなかった |
| 青〜黄 | 再レンダリングされた(明るいほど時間がかかっている) |
| 赤・オレンジ | 時間がかかっている(要注意) |
グレーのコンポーネントはスキップされており、パフォーマンスに影響しません。
再レンダリングの原因を確認する
フレームグラフでコンポーネントをクリックすると右ペインに詳細が表示されます。
UserCard レンダリング時間: 3.2ms レンダリングされた理由: props が変わった name: "田中" → "田中太郎"
レンダリングされた理由 の表示:
| 表示 | 意味 |
|---|---|
props が変わった |
親から渡されたpropsが変化した |
state が変わった |
自身のstateが変化した |
context が変わった |
useContextの値が変化した |
フックが変わった |
useStateやuseReducerの値が変化した |
親がレンダリングされたため |
propsが変わっていないのに親の再レンダリングに巻き込まれた ← 改善候補 |
「親がレンダリングされたため」が表示されたコンポーネントは React.memo で最適化できる可能性があります。
Ranked チャートの見方
「Ranked」タブに切り替えると、レンダリング時間が長い順にコンポーネントが並びます。
HeavyList ████████████ 12.3ms UserCard ████ 3.2ms Header ██ 1.1ms
どのコンポーネントがボトルネックになっているかを素早く把握できます。
最適化の前後を比較する
React.memo で不要な再レンダリングを防ぐ
// 最適化前:親が再レンダリングするたびにUserCardも再レンダリング function UserCard({ name }: { name: string }) { return <div>{name}</div> } // 最適化後:propsが変わらなければスキップ const UserCard = React.memo(({ name }: { name: string }) => { return <div>{name}</div> })
Profilerで録画 → React.memo を適用 → 再度録画して比較することで効果を確認できます。
useCallback でコールバックの再生成を防ぐ
// 毎回新しい関数オブジェクトが生成されるため、React.memoが効かない function Parent() { const handleClick = () => { /* ... */ } return <Child onClick={handleClick} /> } // useCallbackで関数を安定させる function Parent() { const handleClick = useCallback(() => { /* ... */ }, []) return <Child onClick={handleClick} /> }
useMemo で重い計算をスキップする
// レンダリングのたびに重い計算が実行される function Component({ data }: { data: number[] }) { const result = heavyCalculation(data) // 毎回実行 // useMemoでdataが変わったときだけ計算する const result = useMemo(() => heavyCalculation(data), [data]) return <div>{result}</div> }
Profilerの設定
歯車アイコン → 「Profiler」タブで以下を設定できます。
| 設定 | 説明 |
|---|---|
| Record why each component rendered | なぜ再レンダリングされたか記録する(推奨) |
| Hide commits below X ms | 短時間のコミットを非表示にして見やすくする |
「Record why each component rendered」は有効にしておくと、レンダリング理由が右ペインに表示されてデバッグが楽になります。
よくある改善パターン
| 症状 | 原因 | 対策 |
|---|---|---|
| 子コンポーネントが毎回再レンダリングされる | propsが変わっていないのに親が再レンダリング | React.memo を適用 |
React.memo を付けても再レンダリングされる |
関数・オブジェクトのpropsが毎回新規生成 | useCallback / useMemo で安定させる |
| 特定のコンポーネントだけ遅い | 重い計算がレンダリングごとに実行される | useMemo で計算をキャッシュ |
| リスト全体が遅い | リストアイテムが毎回全件再レンダリング | React.memo + key の見直し |
まとめ
録画開始 → 操作 → 録画停止 ↓ Flamegraphで時間がかかっているコンポーネントを確認 ↓ 「親がレンダリングされたため」の箇所を React.memo で対応 ↓ 再度録画して改善を確認
| ツール | 用途 |
|---|---|
| Flamegraph | コミットごとのレンダリング構造を視覚化 |
| Ranked | レンダリング時間が長い順に確認 |
| レンダリング理由 | なぜ再レンダリングされたかを特定 |
React.memo |
propsが変わらなければスキップ |
useCallback |
関数を安定させてmemoを有効にする |
useMemo |
重い計算をキャッシュ |
DevToolsの基本(Components タブ)は「React DevTools 入門:Components タブでpropsとstateを確認する」を参照してください。
Reactのプロジェクト作成から始める場合は「React + Vite でプロジェクト作成」を参照してください。