React Nativeのパフォーマンス改善を学ぶために意図的にパフォーマンスを悪くしたアプリを題材にパフォーマンスの測定と改善をしてみた。
- はじめに
- まずベースライン計測
- 改善前の計測値
- Perf Monitor(Performance Monitor)の見方
- React Native DevTools Profiler の見方
- 観測(改善前)
- Profiler
- 実装した改善
- 改善後の計測値
- Profiler
- 改善前後 比較
- まとめ
題材はこちら。PokeAPIを利用したポケモン図鑑アプリ。
はじめに
わざとリスト画面をScrollViewで実装して、それを元にパフォーマンスを測定する。 FlatListとScrollViewでどれほど差が出るか確認してみる。
まずベースライン計測
まずは Performance Monitor( Perf Monitor ) と React Native DevTools Profiler で、同じ操作を繰り返して計測した。
計測操作
- 通常スクロール
- タイプ連続切替
改善前の計測値
まずは改善前のそれぞれの計測値
| 計測ツール | 計測結果 |
|---|---|
| Performance Monitor | 通常スクロール![]() |
| Performance Monitor | タイプ連続切替![]() |
| React Native DevTools Profiler | ![]() |
Perf Monitor(Performance Monitor)の見方

何を見るツールか
- 実機操作中の「今の重さ」をざっくり把握するためのメーター
- まずは体感と数値を結びつける用途で使う
主要指標
- UI FPS:
- 画面描画スレッドのフレームレート
- 低いとスクロールやアニメーションがガタつく
- JS FPS:
- JavaScriptスレッドのフレームレート
- 低いとタップ反応遅延、状態更新遅れ、切替時の詰まりが出る
- RAM:
- 使用メモリの目安
- 操作を重ねても増え続けるなら要注意
- Layout (ms):
- レイアウト計算の時間目安
- 大きいと描画タイミングが崩れやすい
どう読むか
- 常時値より「操作直後の落ち込み」を見る
- UI は高いのに JS が落ちる:
- 見た目は動くが操作が重い状態
- JS は高いのに UI が落ちる:
- 描画側の負荷が高い状態
0fpsが出る:- 瞬間的な詰まり(フリーズに近い)を疑う
React Native DevTools Profiler の見方

何を見るツールか
- 「どこが」「どれくらい時間を使ったか」を特定するツール
- Perf Monitorで異常を見つけた後、原因を掘るために使う
主要項目
- Commit:
- 1回の更新単位
- 棒グラフの高い山が重い更新
- Render (ms):
- そのコミットで描画計算に使った時間
- 16msを大きく超えるとフレーム落ちしやすい
- Layout effects / Passive effects:
- Effect処理にかかった時間
- ここが大きいと描画以外の後処理がボトルネック
- What caused this update?:
- 更新起点のコンポーネント/要因
各ビューの使い分け
- Ranked:
- 時間の大きいコンポーネントを上位から確認
- まず犯人候補を絞る
- Flamegraph:
- どの親子ツリーで時間を使ったかを可視化
- 再レンダー範囲の広さを把握する
どう読むか(今回の実例)
- Render
1190ms、Passive effects463.9ms - 更新原因が
/index.tsxに集中
観測(改善前)
通常スクロール
| 指標 | 値 |
|---|---|
| UI FPS | 約 119 |
| JS FPS | 約 119 |
| RAM | 約 345MB |
通常スクロール単体では破綻していない。快適に動く。
タイプを連続切替
| 指標 | 値 |
|---|---|
| UI FPS | 約 85 |
| JS FPS | 0fps が発生(瞬間停止) |
| RAM | 約 502MB |
明確に重い。JS が瞬間停止し、UI も落ちる。RAM は通常スクロール比で約 150MB 増と、上昇幅が目立つ。
Profiler
改善前のプロファイルを見ると、タイプ切替時にかなり重いコミットが出ていた。
Render: 1190msPassive effects: 463.9ms- 更新原因:
/index.tsx(リスト画面)
実装した改善
ここから改善のターン。
やったことは冒頭の通り、一覧を FlatList にする。
ScrollViewをやめる- ページングを
onEndReachedに戻す - ヘッダー/空表示/フッターを
FlatList側へ寄せる - 2カラムは
columnWrapperStyleベースに戻す
改善後の計測値
| 計測ツール | 計測結果 |
|---|---|
| Performance Monitor | 通常スクロール![]() |
| Performance Monitor | タイプ連続切替![]() |
| React Native DevTools Profiler | ![]() |
観測(改善後)
通常スクロール
| 指標 | 値 |
|---|---|
| UI FPS | 約 119 |
| JS FPS | 約 119 |
| RAM | 約 295MB |
通常スクロールは引き続き安定。大きなカクつきは確認されていない。
タイプを連続切替
| 指標 | 値 |
|---|---|
| UI FPS | 119 |
| JS FPS | 37 |
| RAM | 約 263MB |
UI は安定しているが、連続切替時は JS の落ち込みが残る。 ただし改善前の「0fps が発生」からは改善している。
Profiler
- Render:
221ms - Passive effects:
4.8ms - 更新原因:
VirtualizedList+/index.tsxに収束
改善前後 比較
Performance Monitor比較
| 観測シーン | 指標 | before | after | 評価 |
|---|---|---|---|---|
| 通常スクロール | UI FPS | 119 | 119 | ほぼ変化なし |
| 通常スクロール | JS FPS | 119 | 119 | ほぼ変化なし |
| 通常スクロール | RAM | 約 345MB | 約 295MB | 改善 |
| タイプ連続切替 | UI FPS | 約 85 | 約 119 | 改善 |
| タイプ連続切替 | JS FPS | 0 | 約 37 | ほぼ変化なし |
| タイプ連続切替 | RAM | 約 502MB | 約 263MB | 大幅改善 |
React Native DevTools Profiler比較
| 指標 | before | after | 評価 |
|---|---|---|---|
| Render | 1190ms | 221ms | 大幅改善 |
| Passive effects | 463.9ms | 4.8ms | 大幅改善 |
| 更新原因 | /index.tsx | VirtualizedList + /index.tsx | 改善方向に収束 |
まとめ
極端にわざとパフォーマンスを悪くした例なので改善後の数字が明らかによくなりましたが、パフォーマンスを改善したいときはまず測定とどこに着目するといいかまとめました。 Expo上でPerfomance monitorで見れるのはすごいなと思ったものの、ちゃんと見るならDevTools Profilerが適しているかなと思った。
他にはHermes で起動時間も改善したりするらしいので試してみたい。




