;

Ichizokuは日本唯一のSentry公認販売業者です。
日本語のドキュメント、動画、サポート窓口で日本のお客様のSentry活用を支援します。

【React Native】パフォーマンス改善戦略:最新の手法とツール

Article by: Simon Grimm

 
 

本記事は、Galaxies.dev の創業者である Simon Grimm によるゲスト投稿です。Galaxies.dev は、ハンズオン形式のコース、専門家のガイダンス、そして個別サポートを通じて、開発者が React Native を習得できるよう支援するプラットフォームです。

React Native のパフォーマンスは、これまで以上に重要になっています。

新しいアーキテクチャが安定版となり、アプリが電光石火のネイティブ体験と競い合う中で、ユーザーは1秒未満の読み込み時間と滑らかな60fpsの操作感を期待しています。遅いアプリはユーザーを苛立たせるだけではなく、最終的な利益にも直結します。実際、100msの遅延でもコンバージョン率が7%低下し得ることを示す調査があります。

そこで、朗報です!

新しいアーキテクチャを備えた React Native 0.80 以降に、Expo RouterReanimated 4 といった最新ツール、そして Sentry による包括的なモニタリングを組み合わせることで、開発者は高パフォーマンスなアプリを作るための強力な手段を手にできます。ただし、大きな力には、それに見合う技術が必要です。

本ガイドでは、起動時の最初の印象という重要な局面から、高負荷時でも滑らかなアニメーションを維持する方法まで、React Native アプリのパフォーマンスをあらゆる面で最適化するための実証済みの戦略を解説します。

本記事で扱う内容は次のとおりです。

  1. 操作可能になるまでの時間(TTI)の短縮する
  2. React の最適化
  3. 60フレーム/秒(FPS)を達成する
  4. リスト表示のパフォーマンスを改善する
  5. 丁寧な状態管理

 

各トピックには、今日から実装できる実際のコード例と実践的なツール選定のおすすめを含めています。

さらに、Sentry が提供するシグナル(指標)を見ながら、アプリ内で何が起きているのか、そしてどう直せばよいのかを理解する方法も掘り下げます。

React Native アプリを、パフォーマンスの強力なアプリへと変えていきましょう。

 

 

1. 操作可能になるまでの時間(TTI)を短縮する

TTI はアプリ起動後に「使える状態」になるまでの速さを測る指標です。アプリアイコンをタップしてから、ラグや処理中スピナーで待たされることなく、ユーザーが実際に UI を操作できるようになるまでの時間を指します。

 

起動時の処理を最小限にする

パフォーマンスを最も悪化させる原因は何でしょうか?

それは、ユーザーがアプリを操作できるようになる前に、やるべき以上の処理をしてしまうことです。起動中の1ミリ秒1ミリ秒が、あの重要な TTI 指標に積み上がっていきます。

このコードはシンプルですが、起動時にやりすぎの処理をしてしまう典型例です。heavyDataProcessing 関数がメインスレッドをブロックし、アプリが操作可能になるまでを遅らせています。

ただ、いつもこんなに分かりやすいとは限りません。そういうときは、プロファイリングツールを使って何が起きているのかを把握する必要があります。

新しい React Native DevTools では、j を押すだけでツールを開き、「Profiler」タブに移動できます。そこから、各関数やコンポーネントの実行にどれくらい時間がかかったのかを確認できます。

Profiler を理解するのは、いつも簡単とは限りません。しかし React Native にはプロファイリングに関する優れたガイドがあります。

また Sentry を利用している場合は、React Native Profiling 機能を使って、本番環境でアプリ内で何が起きているのかを把握することもできます。

これは、開発中だけでなく実際のユーザーに対して、アプリ内のどの関数が最も実行時間を消費しているのかを理解するうえで非常に有効です。また、時間の経過とともにコードの実行時間がどう改善したか、あるいはパフォーマンスが悪化するリグレッションが発生していないかも確認できます。

 

Expo Routerで遅延ロードを使う

Expo Router を使うと、コード分割がとても簡単になります。アプリ内の各画面ごとにルートやコンポーネントを自然に作る形になるためです。

さらにそれだけでなく、非同期ルートを使っている場合、React Suspense を利用してルート単位で JavaScript バンドルを自動的に分割することもできます。

まだ実験的な機能ではありますが、app.json ファイルで有効化できます。

ルートを切り替えると、(開発中は)小さなローディングスピナーが表示され、コンポーネントが必要になったときにだけマウントされていることが分かります。

 
Expo Atlas でアプリのバンドルサイズを削減する

バンドルサイズは起動時間に直結します。特に、端末性能が低い場合やネットワークが遅い場合は影響が大きくなります。

ここでも Expo が用意してくれています。Expo Atlas というツールを使うと、アプリのバンドルサイズを分析し、サイズ増加の主な要因(最も大きな寄与要素)を特定できます。

ローカルで実行するには、EXPO_ATLAS 環境変数を true に設定してアプリを実行またはエクスポートします。あるいは、アプリを動かしているターミナルで Shift+M を押し、DevTools から「Open expo-atlas」を選ぶだけでもOKです。

 

次のようなレポートが表示されます。

これは、アプリのどの部分がバンドル内で最も容量を占めているのか、そしてそれらをどう最適化すべきかを理解するうえで有効です。

 

2. React の最適化

React Native アプリの本質は React アプリでもあるため、React 固有のパフォーマンス原則はモバイルでも同じように当てはまります。

課題は、モバイル端末はデスクトップブラウザよりもリソース制約が厳しい点です。そのため、非効率な React パターンのコストはさらに大きくなります。不要な再レンダリングが起きるコンポーネントは、Web ブラウザでは少し遅くなる程度かもしれませんが、ミドルレンジの Android 端末ではフレームレートが 60 FPS を下回る原因になり得ます。

朗報なのは、React Native にはこうした問題を特定して修正するための強力なツールが揃っていることです。どのコンポーネントが再レンダリングされているのかを可視化する可視化できる Profiler からから、メモリリーク検出、さらにコードを自動最適化する予定の React Compiler まで、幅広く用意されています。

このセクションでは、アプリのパフォーマンスに最も大きな影響を与える React 固有の最適化を取り上げます。

 

コンポーネントのレンダー時に更新をハイライトする

まず最初にやるべきことは、アプリ内で何が起きているのかを把握することです。そのために、React Native DevTools の Profiler はとても有効です。

再レンダリングが発生しているコンポーネントを確認したいので、Profiler で「Highlight Updates(更新をハイライト)」オプションをオンにします。

これにより、UI 上で再レンダリングされているコンポーネントがハイライト表示されます。

アプリ内を操作(画面遷移など)しながらこの機能を使い、本来よりも頻繁に再レンダリングしているコンポーネントを見つけましょう。

もしコンポーネントが常に(または理由なく)再レンダリングしているようなら、前述した通り Profiler をさらに掘り下げて、理由を確認できます。

要点をまとめると、次を確認してください。

  • Settings > Profiler >「Record why each component rendered」 を使い、どの props や state が変わったのかを正確に見る
  • 「Highlight updates when components render」 を有効にして、どのコンポーネントが再レンダリングしているかを視覚的に確認する
  • Flamegraph 表示ではコンポーネント階層とレンダー時間が分かります。背の高いバーがある場所は遅いコンポーネントの目印です

 

React Compiler を有効化する

useMemouseCallback を使った手動のメモ化は、React のパフォーマンス最適化の標準的な方法でしたが、ミスが起きやすく、記述も冗長になりがちです。

React Compiler はコンポーネントを自動的に最適化してくれるため、状況を大きく変えます。ただし安定版になるまでは、戦略的なメモ化が依然として重要です。

まだ Expo SDK 53 を使っている場合は、次のようにパッケージをインストールできます。

ただし、SDK 54 以降では、これはもう不要になります。

現在は app.json ファイルで有効化するだけでOKです。

その後は、手動のメモ化を削除して、コンパイラに最適化を任せられます。

 

JavaScript のメモリリークを修正する

React Native アプリのメモリリークは、気づきにくい一方で致命的になり得ます。ページ遷移で後始末がされやすい Web ブラウザと違い、モバイルアプリはメモリ上により長く残り続けます。小さなリークでも時間とともに積み重なり、最終的にはクラッシュや動作の重さ(もたつき)につながります。

これは React Native アプリでよくある問題で、原因は多くの場合次のようなものです。

  • 削除されていないイベントリスナー
  • クリアされていない interval(定期実行)
  • クローズされていない WebSocket 接続

 

以下は、複数のメモリリークを含むコンポーネントの例です。

さて、これらすべてを見つけて修正できると思いますが、わかりやすくするために、アプリにメモリ リークがないことを確認する方法を以下に示します。

もちろん、ここまで挙げたのはメモリリークや JavaScript 最適化の具体例の一部にすぎません。そもそも最初から、クリーンな JavaScript、ひいては React のコードを書くことが重要です。

 

 

3. 60フレーム/秒(FPS)を達成する

滑らかなアニメーションと操作感こそが、「良い」React Native アプリと「素晴らしい」React Native アプリを分けます。60 FPS では、1フレームあたりレンダリングに使える時間は 16.67 ミリ秒しかありません。しかもそこには、JavaScript の実行、ネイティブブリッジとの通信、UI 更新まで含まれます。

この閾値を下回ると、ユーザーはすぐにカクつきを感じます。特にスクロール、画面遷移、ジェスチャー駆動のアニメーションといった重要な操作中は顕著です。

React Native の新アーキテクチャは、ブリッジ通信のオーバーヘッドを減らすことで大きく助けになりますが、それでもメインの JavaScript スレッドから処理を外すための戦略は必要です。ここで、Reanimated 4 のような最新ツール、パフォーマンス監視、そして丁寧なスレッド管理が重要になります。

このセクションでは、高負荷時でもバターのように滑らかな 60 FPS 体験を維持するために必要な手法とツールを取り上げます。

 

React パフォーマンスモニターで FPS をリアルタイムに確認する

リアルタイムの FPS 監視は、開発中にパフォーマンスのリグレッション(悪化)を即座に検知するのに役立ちます。アプリが 60 FPS で動いているか、もしそうでないならなぜなのかを把握するための、とてもシンプルな方法です。

Expo アプリでツールシートを開くには、Mac なら CMD + Control + Z、それ以外なら Ctrl + Shift + Z を押し、Performance Monitor を有効にします。

60 FPS を達成するための最初のステップは、アプリ内で何が起きているのかを理解することです。

 

JavaScript スレッドをブロックしない

滑らかなパフォーマンスにとって最大の敵は、重い計算処理で JavaScript スレッドをブロックしてしまうことです。Web ブラウザには Web Workers がありますが、React Native では JavaScript スレッドがアプリのロジックだけでなく UI 更新も担います。ここを塞いでしまうと、アプリ全体がフリーズします。

重い計算処理は、基本的にはバックエンド側にオフロードするのが望ましいですが、アプリ内で実行せざるを得ないケースもあります。そうした場合は、React 18 の Transition API を活用すると効果があることがあります。
 

React Native DevTools のプロファイリングツールと同様に、Flashlight でもアプリのパフォーマンスをライブで確認できます。

 

Sentry のトレーシングを使う

パフォーマンスの高い React コードを書くことに加えて、Sentry のトレーシング機能を使って、アプリ内で何が起きているのかを理解することもできます。

トレーシングを有効にすると、エラーの収集に加えて、複数のサービスやアプリケーション間のやり取り(インタラクション)も監視できます。React Native アプリは複数のバックエンドサービス、サードパーティ API、ネイティブモジュールと通信することが多いため、これは特に重要です。

開発中の出来事しか見えない従来のデバッグツールと違い、Sentry のトレーシングは、実際のユーザーから得られる現実のパフォーマンスデータを提供します。端末の種類、ネットワーク状況、アプリのバージョンが異なる環境を横断して把握できます。

Sentry トレーシングの強みは、さまざまなパフォーマンス問題の「点」をつなげられることにあります。ユーザーから「遅い」と報告があったとき、原因が遅い API 呼び出しなのか、非効率な React コンポーネントなのか、メモリリークなのか、あるいは複数要因の組み合わせなのかを Sentry で確認できます。React DevTools だけでは、アプリケーションの React 層しか見えないため、こうした包括的な把握はできません。

トランザクション以外にも、特定のアクションが発生するまでの時間を測る方法として Span があります。

Span の最も基本的な使い方は、次のようになります。

 
Span を使えば、バックエンドへの API 呼び出しのような処理時間はもちろん、リスト項目のレンダーにかかる時間までトレースできます。こうした情報は最終的に、アプリ内で何が起きているのか、そしてどこを改善できるのかを示すシグナルになります。

 

 

4. リスト表示のパフォーマンスを改善する

リストは、React Native のパフォーマンス問題が最も顕在化しやすい場所です。最適化が不十分なリストは、たった100件のアイテムでもアプリを 30 FPS まで落とし得ます。一方、適切に最適化されたリストなら、数千件のアイテムでも 60 FPS で滑らかに扱えます。

この差は、React Native がリストをどのようにレンダーするかを理解し、用途に合ったツールを選べるかにかかっています。

組み込みの FlatList はシンプルなケースには十分ですが、FlashListLegendList のような最近の代替手段は、モバイルでのパフォーマンスに特化して設計されています。適切なレンダー最適化と賢いデータハンドリングと組み合わせれば、複雑なデータでも即応性の高いリストを作れます。

 

FlashList / LegendList を使う

データを ScrollView の中でそのまま map するのは、基本的には避けるべきです。FlatList はシンプルなケースには十分ですが、多くの場合は FlashListLegendList の利用を検討するとよいでしょう。

両者の API はほぼ同じです。ただし、FlashList はパフォーマンス最適化、LegendList はメモリ使用量の最適化に重点が置かれています。

どちらも FlatList の置き換え(drop-in replacement)として使えるので、コードの変更は最小限で済みます。

ただ、適切なリストコンポーネントを使うだけでは不十分で、リスト項目をどうレンダーするかも重要です。

 

効率的なリストのレンダー関数

高速なリストを実現する鍵は、レンダー関数をできるだけ軽量に保つことです。

この例では、日付のフォーマット処理やスタイルの計算がスクロールのたびに実行されてしまい、フレーム落ちの原因になります。

高コストな計算はすべて useMemo 内で一度だけ行われ、レンダー関数は事前計算済みの値を表示するだけになります。

この例では、重い処理は一度だけ実行され、さらにリスト項目がメモ化されているため、props が変わらない限り再レンダリングされません。

そしてこの記事を注意深く読んでいれば、まもなく React.memo を外して、コンパイラに最適化を任せられるようになることも分かるはずです。

 

リストの変更(ミューテーション)と再レンダリングを理解する

リストデータの更新方法は、パフォーマンスに大きく影響します。見落としやすいポイントですが、パフォーマンス問題のよくある原因でもあります。

ミューテーション(破壊的変更)は再レンダリングを適切に発生させないことがあり、反対に配列を丸ごと更新すると全アイテムが再レンダリングされてしまいます。

データ更新のより良い方法は、次のようになります。

 

 

ただ、ライブラリの導入に抵抗がないなら、優れた選択肢はいくつかあります。

 

可能な限り Jotai / Zustand を使ってアトミックな状態管理にする

複雑な状態管理が必要な場合は、JotaiZustand のようなアトミック(粒度の細かい)状態管理ライブラリを検討してください。これらのライブラリは細かなリアクティビティを提供するため、コンポーネントは依存している特定の状態が変わったときにだけ再レンダリングされます。

Jotai の使用例は、次のようになります。

小さな Atom に分けておけば、useAtomValue フックを使って Atom の値を取得しつつ、Atom が変化してもコンポーネントを再レンダリングさせない、といった使い方もできます。

それに加えて、Zustand は 2024 年の State Management 分野の Rising Star でもあり、ほとんどあらゆる用途に適した優れた選択肢です。

賢い状態管理とは、用途に合ったツールを選ぶことです。Context は、テーマやユーザー認証のように「変更頻度が低く、多くの場所で必要になるデータ」に向いています。一方、複雑で頻繁に変化する状態には、Jotai や Zustand のようなアトミック系ライブラリのほうが、コードの複雑さを増やしすぎずに、より良いパフォーマンスを得られます。

 

 

まとめ:電光石火の React Native アプリへの道

高パフォーマンスな React Native アプリを作ることは、あらゆる最適化を一度に全部適用することではありません。ボトルネックがどこにあるのかを理解し、適切な解決策を体系的に当てていくことが重要です。

 

パフォーマンス最適化チェックリスト

最初はプロファイリング、次に最適化です。推測ではなく、React Native DevTools と Sentry の Performance Monitoring を使って、実際のパフォーマンス問題を特定してください。多くの開発者は、本当のボトルネックが見過ごされている一方で、見当違いの最適化に時間を使ってしまいがちです。

効果が大きい基本に集中しましょう。

  • 起動時の処理を最小化し、可能なものは遅延ロードする
  • Expo Atlas でバンドルサイズを適切に管理する
  • UI スレッドを決してブロックしない。Reanimated 4 と worklets を活用して滑らかなアニメーションを実現する
  • リスト性能のために FlatList を FlashList に置き換える
  • アプリの複雑さに応じて状態管理戦略を選ぶ

 

差がつくツール

React Native のエコシステムは大きく進化しました。React Compiler、Expo Router、FlashList といった最新ツールは、あると便利なものにとどまりません。最小限のコード変更でアプリのパフォーマンスを大きく改善し得る、まさに“ゲームチェンジャー”です。

監視とデバッグの観点では、開発の早い段階で Sentry React Native SDK を組み込むことをおすすめします。初日から実ユーザーデータと詳細なエラートラッキングが手に入ると、パフォーマンス問題ははるかに見つけやすく、直しやすくなります。ちなみに Sentry には Expo との連携もあり、Expo のデプロイに対する Sentry のクラッシュレポートやセッションリプレイを、Expo 側から直接確認できます。

 

60 FPS という目標

60 FPS は、ただの“良い数字”ではありません。ユーザーにとってアプリが本当にネイティブらしく感じられる境目(閾値)です。開発中は React Perf Monitor を使い、Android では Flashlight を使ってより詳細にプロファイリングしましょう。アニメーションが滑らかで、操作の反応が即座であれば、ユーザーはそれを確実に感じ取ります。

 

学び続け、計測し続ける

パフォーマンス最適化は一度きりの作業ではなく、継続的なプロセスです。アプリが成長し、React Native のエコシステムが進化するにつれて、新たなボトルネックが現れ、より良い解決策も登場します。

重要なのは、チームの中に「パフォーマンスを意識する文化」を作ることです。プロファイリングを開発フローの一部に組み込み、機能ごとにパフォーマンス予算を設定し、最適化の効果は必ず計測しましょう。

ユーザーは、より良いレビュー、より長いセッション時間、そして途中離脱の少なさで応えてくれます。アプリストアの評価がプロダクトの命運を左右し得る世界では、こうした改善は技術的な“あったら良い”ではなく、ビジネス上の必須事項です。

これらの最適化を実装する準備はできましたか?

まずは今のアプリをプロファイリングし、このガイドの中から一番手を付けやすい改善を選び、改善効果を計測してください。パフォーマンス最適化は旅ですが、これらのツールと手法があれば、本当に光る React Native アプリを作るための準備は整っています。

 

 

Original Page: React Native performance tactics: Modern strategies and tools

 

 




IchizokuはSentryと提携し、日本でSentry製品の導入支援、テクニカルサポート、ベストプラクティスの共有を行なっています。Ichizokuが提供するSentryの日本語サイトについてはこちらをご覧ください。導入に関するご相談がございましたら、どうぞお気軽にお問い合わせください。

 

シェアする

Recent Posts