React Nativeを最後に触ったのは2018年ごろだった。
それから8年。ポケモン図鑑アプリを作るにあたって久しぶりに触ったので所感のまとめ。
題材
お勉強のためにPokeAPIを使ったポケモン図鑑アプリを題材にした。
技術スタックはこんな感じ。
- React Native 0.83.2 + React 19
- Expo SDK 55 / Expo Router
- TypeScript 5.9
- TanStack Query v5
- Zod v4
- react-native-reanimated v4
- ESLint
- Prettier
React Nativeは0.84.0が最新だがExpo SDK55が0.83系をサポートしているのでこのバージョン構成です。
Expo
8年前はライブラリの互換性が面倒だった印象ですが、この辺が楽になった気がした。 iOS / Android フォルダは基本的に触らず、設定は app.json / app.config.ts に書く形になる。
Expo Goで開発中の検証はできるし、ビルドはeasで可能。しかもクラウドなのでmacなくてもiosビルドができるとか。 この辺昔は面倒で、androidのSDKのバージョンを編集したりした記憶がある。
ルーティング
ルーティングはExpo Router。
app/ 配下にファイルを置くだけでルーティングが完成する。シンプル。
app/
_layout.tsx # ルートレイアウト
(tabs)/
_layout.tsx # タブナビゲーション
index.tsx # 一覧画面
explore.tsx # 詳細画面
こんなシンプルな構成で動く。
Reduxじゃない
昔はReduxがトレンドだった気がしたんだけど、今はそんなこともなさそう。 今はReact Hooksが標準で使えるのとカスタムHookによる拡張性がある。
ライブラリ充実感
API呼び出しどうするのかなと思って調べつつ、useEffectの中でfetchは嫌だなあと思ったらTanStack Queryがある。 レスポンスのスキーマはzodがある。
ローカルDBもまだ触っていないが、TanStack DB というプロジェクトも出てきているらしい。(8年前は Realm を使っていた記憶がある。)
アニメーションしたいなら react-native-reanimated
New Architecture
昔はパフォーマンスが悪いとか言われてたらしいが、New Architectureで改善されたらしい。 以前のアーキテクチャは「Bridge」によりJavaScriptとネイティブ間のやりとりを非同期でJSONメッセージでやりとりしていた。データ量が多いとカクツキやネイティブからの結果が必要な処理においてレイテンシが起きるなどパフォーマンスが低下する問題があった。
これを New Architecture では Bridge を廃止し、JavaScript Interface(JSI)を用いてネイティブコードへ直接アクセスできるようになった。 従来のJSONシリアライズによるメッセージングが不要になり、同期・非同期の両方で効率よく通信できるようになった。
Fabric
新しいレンダリングシステム。従来は非同期処理の制約により、レイアウト更新のタイミングによってUIのジャンプやレイアウトのズレが発生することがあった。Fabricでは複数の優先順位付けと同期イベントをサポートして適切なタイミングで処理する。
パイプラインは3つのフェーズ。
- レンダー
- コミット
- マウント
1.レンダーでは、React Element Treesを作成する処理を実行。C++でReact Shadow Treeを作成
2.コミットでは、React Element TreeとReact Shadow Treeの両方を「次のツリー」としてマウントされる。レイアウト情報の計算もスケジュールする。この処理はバックグラウンドスレッドで非同期的に実行される。
3.マウントでは、レイアウト計算の結果が反映されたReact Shadow TreeがホストViewに変換される
TurboModule
旧来の Native Modules を置き換えるもの。型安全性の特徴あり。 TypeScript で型定義を書いて、Kotlin/Swift のコードを紐付ける形になっている。 codegenにより一部のコードが自動生成される (abstract class)
TypeScript (Spec)
↓
Codegen
↓
Native Interface (自動生成)
↓
Native Implementation (実装したいものを書く)
Hermesエンジン
以前はJavaScriptCoreだったが、起動が遅いなどの問題があった。 MetaがHermes エンジンを開発して、メモリ使用量が小さくなり起動も速くなる。
大きな違いはバイトコード生成のタイミング。 JavaScriptCore は実行時にパース・コンパイルが行われるのに対し、Hermes はビルド時にバイトコードへ事前コンパイルされる。 JavaScriptCoreは起動時にパースとコンパイルが走るため起動が遅いが、Hermesは事前処理をするため起動が速いメリットがある。
DevTools
以前はChrome DevToolsに依存していた記憶があるが、現在はReact Native DevToolsが統合されており
- React DevTools
- Network
- Performance
などが確認できるようになっている。
ただしExpo環境ではNetworkタブが表示されないことがあり、その場合はProxymanなどのプロキシツールを使う必要があった。
エコシステム
8年前は「React Native独自の世界」という印象だったが、現在はかなりWeb Reactのエコシステムと近い。
- TanStack Query
- Zod
- React Hooks
- ファイルベースルーティング
など、Webで使うライブラリがそのまま使えるとのこと。
Webの技術やノウハウを応用できる利点だと思うが、自分の様なネイティブアプリ開発者からするとReact Nativeでクロスプラットフォーム開発を習得して、Webのフロンエンドにも滲み出していける利点もあるかもしれない。
まとめ
8年ぶりに触ったReact Nativeは、いい感じに進化していた。