tomoima525's blog

Androidとか技術とかその他気になったことを書いているブログ。世界の秘密はカレーの中にある!サンフランシスコから発信中。

2020 年の React Native 開発

2019 年は React Native にとってはさまざまな変化があったので、それらを振返りつつこの記事では最近の React Native をめぐる状況と個人的見解について書きます。採用を検討している方、Flutter などのクロスプラットフォーム開発フレームワークと比べたいという方の参考になれば幸いです。
フラットに書くことを意識していますが、いち利用者としてのバイアスがあることをご了承ください。

開発体験

開発体験はここ一年で劇的に向上していて、特にプロジェクトの立ち上げ~機能開発までのプロセスはネイティブコードによる開発を上回っていると感じています。大きくは下記のような改善がありました。

Fast Refresh

React における Hot Reload と呼ばれる JS を保存したときに特定のコンポーネントに対して変更を適用させる機能です。便利そうな機能ですが、React Native ではうまく動かず、開発者によってしばしばオフにされる機能でした。Dan Abramov 氏によってフルスクラッチで書き直された Fast Refresh は以下のような機能を備えています。

  • コードを保存すると即時反映される(Functional Component であれば state も保持される)
  • コードにミスがあってエラー画面が出ても修正後再起動することなくコンポーネントを再描画できる

Fast Refresh は 0.61 からサポートされています。
特にナビゲーションを使ったライブラリだと、コードを更新するたびにリロードする必要があったのですが、Fast Refresh によってストレスなく開発できるようになりました。

facebook.github.io

Auto Linking

React Native でネイティブをラップしたサードパーティ製のライブラリを導入する場合、ネイティブのライブラリ設定を更新する必要がありました。
例えば Android の場合、 build.gradle や settings.gradle の Gradle ファイル、Application クラスにそれぞれパッケージを追加するコードを書く必要があります。これは react-native-link により自動的に書くことができるのですが、うまく動かないケースや追加で設定が必要なケース(推移的な依存関係の解決など)もあって、面倒な作業のひとつでした。
今後はサードパーティ製ライブラリが Auto Linking に対応していれば、npm へのライブラリ追加だけで依存関係は解決されるようになります。

cli/autolinking.md at master · react-native-community/cli · GitHub

CocoaPods の標準採用

0.60 より CocoaPods が標準で採用になりました。これまでの React Native だとサードパーティ製ライブラリの導入のために Xcode のプロジェクト設定を書き換えたりする必要がしばしばあり、環境設定の複雑さを増していました。CocoaPods により Swift などの Dynamic frameworks を必要とするライブラリが導入しやすくなるといったメリットもあります。

https://facebook.github.io/react-native/blog/2019/07/03/version-60#cocoapods-by-default

CocoaPods のデメリットとしては初回インストールの時間がかかる点で、特に CI への影響が大きいですが、CocoaPods 自体が 1.7.2 から CDN をサポートしています。会社のプロジェクトでは CDN に切り替えたところ 13 - 15 分ほど CI の時間は短縮されました。

Expo によるワンストップ開発環境構築

これは 2019 年に始まったわけではないですが、Expo の登場によって React Native の環境構築やアプリのリリースは容易になりました。react-native-cli もプロジェクト構築の優れたコマンドラインツールですが、XcodeAndroid Studio の導入は必要ですし、さらにアプリのリリースについてはネイティブの知識もある程度求められます。Expo はプラットフォームごとの IDE なしに開発を始められるだけでなく、アプリの配布、リリース機能まで提供しています。

expo.io

Expo 内部では fork された React Native が使われているため、最新の機能を使うためには少々待つ必要がありますが、ちょっとしたアプリや動作検証は他のどのプラットフォームよりも速く作れるんじゃないかと思います。

フレームワーク/アーキテクチャ

フレームワークアーキテクチャに関してもこの一年で大幅なアップデートがありました。

Lean Core

近年の React Native の課題としてレポジトリサイズの巨大化や内部構造の複雑化がありました。特に内部の複雑さやレガシーコードは問題で、一部の機能変更によって全体が影響を受けるために修正に時間がかかるケースが度々あったようです。そこでコア機能以外は切り離し、コミュニティで管理するようなスリム化が実施されました。

Lean Core · Issue #6 · react-native-community/discussions-and-proposals · GitHub

分割されたレポジトリ群は 2019/6 時点で 800 以上の PR を受けつけ、バグ修正/リリースなどのメンテナンス性が向上したと述べられています。

React Native Open Source Update June 2019 · React Native

Android

これまで Android は Second citizen 的な立ち位置で、特にパフォーマンスに関しては iOS に対して大きく劣っていました。どっこい 2019 年は Facebook React Native Core チームが本腰を入れてきたようです。特に React Native の実行速度の最適化を行った JS Engine である Hermes により、実際にアプリを触れる速度(TTI)が 2 倍近く高速化されました。

f:id:tomoima525:20200114115336p:plain

またそれとは別に 64bit CPU への対応や AndroidX のサポートがコミュニティの協力のもと実施されています。個人的には前述の Lean Core に伴って Gradle の記述が簡易化されたことが素晴らしいなと思います。

www.youtube.com

最新の React への追随

React への追随も問題なく、Hooks も発表の3ヶ月後(2019/2 v0.59)で対応しています。また 2018 年までは React は Facebook の都合なのか常に alpha バージョンが指定されており、React 起因のバグを踏んだ場合の調査を難しくしていました。が、2019 年以降は semver に沿ったバージョンが設定されるようになっています。

蛇足ですが TypeScript に関しては 2018 年時点でサポートされており、react-native-cli で構築する初期プロジェクトで TypeScript を指定することができます。

コミュニティ

2019 年は Facebook が本気で React Native コミュニティ作りに力を入れた年でもあります。

What do you dislike about React Native?

2018 年末に Facebook React Native Core Team のメンバーが What do you dislike about React Native?と題して React Native のイケてない点について投稿および投票をお願いするスレッドを Github の issue に立てました。この issue は非常に話題になり、開発者から多くの意見があつまりました。

コミュニティからの指摘に対し 2 月には Core Team の返答が投稿され、対応事項の優先順位がつけられました。この結果産まれたのが Fast Refresh や Auto Linking などの革新的な機能です。

2018 年までは Pull Request や issue は放置されがちだったのですが、現在では継続的にレビュー/マージが実施されるようになっています。この結果日々の Pull Request 数が 3 -> 6(2019/6 時点)に増え、ますます活発になってきていると言えます。

react-native-community 管理下のライブラリの普及

Lean Core プロジェクトにて複数の機能が react-native-community に移譲された結果、多くの個人管理されていたライブラリもこの傘下に入りました。この結果、破壊的変更を伴うような更新についてコミュニティが足並みをそろえて対応できるようになり、混乱が避けられるようになりました。

その一例が Android Support Library から AndroidX への移行です。Github issue 上で対応方法及びルール作りの策定が行われ、コミュニティにより新たなツールが実装されました。

AndroidX Migration Plan · Issue #129 · react-native-community/discussions-and-proposals · GitHub

またコミュニティが大きくなり react-native-maps などデファクトスタンダードなライブラリが登場するにつれ、プロジェクトのディレクトリ構造や Gradle や PodSpec 設定ファイルの記法についてもそれらを参考に統一が図られるようになってきています。

React Native の課題

こんな感じで 2019 年は React Native が進化した一年でしたが、一方で未だに抱えている課題もあります。

依然としてメジャーバージョンアップなし

現時点での最新バージョンは 0.61.4 で、未だにメジャーバージョンアップの噂がありません。インタフェースが安定しない、後方互換を壊す修正がいつ何時入るかわからないという点で開発者としては若干不安になります。

環境設定の複雑さ、複雑な依存関係

コミュニティでは"Most of time used in React Native is the configuration"といったコメントがしばしば見受けられます。Auto Linking によってライブラリの設定は容易になりましたが、それ以外の Babel や Metro など色々な依存関係と複雑な設定が開発者をよく苦しめます。

特に面倒なのが React Native のアップグレードで、1,2 バージョン更新を怠るだけでビルドすら通らなくなることもザラです。本体については diff-helper によって少しずつ改善されてきていますが、メンテが遅れているライブラリで生じる不具合も非常に多いです。

React Native を採用する(個人的な)選定基準

たまに他社の方から「React Native を採用すべきですか」といった質問やアドバイスを求められたりするので、個人的な選定基準について触れておきます。

チームメンバーのスキルセット

チームメンバーが Web に強くかつモバイルアプリ開発をしたい場合、React Native のラーニングコストはかなり低くなるので非常におすすめです。iOS または Android どちらかのアプリケーションエンジニアしかいないケースにおいても Web エンジニアが肩代わりすることができるので、選択を視野に入れてよいと思います。

ネイティブ実装がどの程度必要か

これから作ろうと考えているサービスがどの程度ネイティブ固有の API を利用するかも大きな判断基準になります。

例えば React Native でカメラライブラリといえば react-native-camera がスタンダードですが、このライブラリで実現できる以上のことを実装したい場合は、ネイティブ実装は避けられないでしょう。ネイティブで実装する場合も React Native のモジュールの制約でネイティブライブラリをそのまま利用できないことがよくあるので、ネイティブの低レイヤー知識と経験*1が求められます。そのような場合は React Native を使うメリットは薄いので、いっそのことネイティブで実装したほうが長期的には良いと考えます。

なお、一部をネイティブ、残りを React Native にするハイブリッドアプリは全くおすすめしません。大きな理由は RN - Native 間の画面遷移の実装難度です。Native -> RN -> Native といった画面遷移でデータを持ち回す場合に RN - Native 間でやり取りする必要があり、実装が容易に複雑化します。データトラッキングなども橋渡しの実装が必要になったり余計な工数が増えがちです。ハイブリッドにするくらいなら WebView をおいて Web 側で実装したほうがはるかに工数は少なく済むでしょう。

会社/サービスの種類

個人的にはリソースが限られたスタートアップであれば React Native を強く推したいです。立ち上げからリリースまでのサイクルはネイティブ実装よりはるかに速く、On The Air 配信も可能なのでイテレーションも高速に回せます。パフォーマンスについても iOS に関してはネイティブと区別がつかないレベルであると言えます。Discord のように iOS のみ React Native を採用している例もあります。

blog.discordapp.com

サービスの種類も重要な基準で、例えばリスト更新やチャットなどがメインのアプリであれば、React Native の方が開発体験も向上し品質もネイティブと遜色ないものが実装できると思います。

Expo については便利な反面、中長期的に見ると技術負債になると考えています。Expo の機能に縛られるのでデザインや仕様に制約がでること、"おまかせ"が売りのフレームワークなので、一度 Eject(ライブラリを自分で管理する設定に切り替える)すると不要なライブラリの依存関係に苦しめられることになります。Expo はあくまで検証用途で、早い時期に React Native またはネイティブの乗り換えるべきでしょう。

React Native、React の今後

現在 React Native ではUI レイヤーのリアーキテクチャNative Module の開発方法の改善について議論が進められており、今年も引き続き活発に開発が続けられそうです。

また周りを見回してみると、React だけでなく、Facebook が力を入れている VR や (react-360) ARなど、今後のプラットフォームとなりうる分野で React が使われています。

React の志向する "Learn once, Write Anywhere" な世界は意外と近いのかもしれません。

*1:最近だとHttpsリクエストのローカルキャッシュのためにDiskLruとMemoryLruを組み合わせたfetch機構を実装したりしました