✍️

普段Flutterを触ってる人がReact Native(+Expo)を触ってみた 2024/12

2024/12/18に公開

普段はFlutterでモバイルアプリ開発をやっているKurogoma4Dですが、最近技術スタックがFlutter OTP[1] みたいになってきているのを感じてます。

会社所属のエンジニアとしても個人のスキルとしても他の技術に触れなさすぎるのも良くない、というのと、最近 React NativeExpo を使ったアプリがパフォーマンスも改善されてるし結構いい感じらしい、という噂を聞いたということで、React Native(以下RNと略す)をちょっと触ってみました。

やったこと

まずはExpoの公式ドキュメントにある Expo Tutorial を一通りやってみました。

https://docs.expo.dev/tutorial/introduction/

その後、自分で使いたいアプリを一個作ってみました。

https://github.com/Kurogoma4D/SecureBoard

画像を登録して、アプリ起動時に設定してある生体認証をクリアしたときのみ内容が見える、というものです。
具体的に何に使うんですか?ってツッコミは一旦しないでください。

RN+Expoを触って良かったこと

TypeScriptで書くのでベースのDXが良い

(DX: Developer Experience)
普段からVS Codeを使っているので、TypeScriptを書く環境が整っている(or すぐ整えられる)状態で開発が始められるのはいいですね。

AndroidやiOS向けのアプリをビルドする際は最終的にAndroid Studio、Xcodeが必要になりますが(EASを使う場合を除く)、Flutterと同じで大方の開発はVS Code上で完結します。

TypeScriptはVS Code上での補完やAIアシストが充実しているので、困ったことがあってもエディタ上で完結することは多いです。

(まぁ、Dartでもその辺の体験は良いですけどね🤫)

一回ビルドしたらHMRでスムーズに開発できる

これもFlutterで言うHot-reloadに通じる話ですが、やっぱりHMR(Hot Module Replacement)は偉大です。

参考文献として、RNの公式ブログとwebpack本家のドキュメントを置いておきます。HMRとは何ぞや、となっている方は以下をご覧ください。

https://reactnative.dev/blog/2016/03/24/introducing-hot-reloading

https://webpack.js.org/concepts/hot-module-replacement/

ネイティブのViewになるので、各種inspectorでViewの様子が見られる

xcode-inspector
XcodeのinspectorでViewを見ている図

Viewとして描画したものが最終的にどういうconstraintsになっているか、みたいな確認をしたいときには便利かと思います。
Reactの世界でどうなってるか、を見たければ別途それ用のDevToolもあります。

react-native-reanimatedが結構便利

https://docs.swmansion.com/react-native-reanimated/

Flutterで言うAnimated系Widgetのようなお手軽さで、アプリにアニメーションを導入することができます。

function App() {
  const width = useSharedValue(100);
  const handlePress = () => {
    width.value = withSpring(width.value + 50);
  };
  return <Animated.View style={{ ...styles.box, width }} />
}

こんな感じ↑のコードで、こんな感じ↓の出力が得られます。超お手軽。

React Native Reanimated
react-native-reanimatedの例 https://docs.swmansion.com/react-native-reanimated/

Androidでビルド時の様子がだいぶ可視化されてておもろい

Android build log
こんな感じ

アイコンとかの設定がめっちゃ楽

アプリ名とかアイコンとか、通常 AndroidManifest.xml なり Info.plist なり違うサイズのアセットを自前で用意するなり、ネイティブの開発では色々と設定が大変な部分があります。
Expoでは、app.json を編集して npx expo prebuild:android を叩けば大抵の設定は完了するのでめっちゃ楽です。
環境分けに関してはちゃんと調べてないですが🤫

Flutterでもアイコンなら例えば flutter_launcher_icons を使えば楽できます。アプリ名はよくネイティブいじりますがね……

RN+Expoを触ってイマイチだったこと

「一回ビルドしたらHMRでスムーズに開発できる」のデメリット

これはイマイチと言うかある程度仕方ない部分ではありますが、Flutterでは感じることのないデメリットがあるな、と思いました。
RNでは Native module に変更がない限りは基本的にdevサーバーを立ち上げるだけで開発ができますが、逆に変更があった場合はビルドし直さなければなりません。
その際、コマンドとしてはnpx expo start ではなく npx expo run:androidnpx expo run:ios といったコマンドを使うことになります。

Native module に変更があるにもかかわらず、誤って npx expo start だけしてしまった場合、往々にしてランタイムエラーが起こります( Error: Native module not found 的なやつ)。
こう言うと当然の話ではありますが、自分が何をしようとしているのか・何をしたのかは常に把握しておきましょう。

ビルド自体の時間もなにもない状態にもかかわらずネイティブアプリと比べると段違いに遅い

場合によりけりですが、ビルドの時間がめっちゃ遅いときがあります。
おそらくJSの実行環境が入ってたり諸々必要なものが多い関係かと思われます。

ライブラリの追加など Native module に変更があったとしてもビルドが早かったりそうでもなかったりマチマチなので、流石にキャッシュ等で最適化はされているもののどれくらいビルドに時間がかかるか、はやってみないとわからない印象でした。

Flutterで言うWrap with widgetがなくてぐぬぬ…ってなる

どっちかって言うとReact単体の話にはなりますが、コンポーネントを組み立てるときに便利なCode Actionsが無いなぁという話です。

Wrap with widget
これ

FlutterではWidgetを組み立てる際、↑の画像のようなCode ActionsをWidget上で呼び出すことで、カーソル位置のWidgetをラップしたり削除したり、という記述が簡単にできます。
これと同じものがReactでほしい……😫
普段Reactを書いている友人にどうしているか聞いてみたところ、普通に中身をカットしてタグ書いて中にペーストしてるそうで、「あまり気にしたことない」とのことでした。
作ろうと思えば作れるかなこれ🤔

総評

実際にRN+Expoでアプリを作ってみて、特に大きな問題もなく開発体験もパフォーマンスも悪くないな、というのが第一の感想です。大手企業のアプリで採用されていることもあり、クロスプラットフォームで開発したいときの選択肢には余裕で入ってくるかと思います。

ネイティブUIのレンダリングをする系のフレームワークだとUIの自由度が低いんじゃないか[2]、と勝手に思ってましたが、全然そんなこともなく、Webと同じようにCSS的なものでカスタマイズが自由にできるしアニメーションも手軽にできることがわかりました(FlutterのAnimationControllerみたいに原理的なAPIを使うところまでは調べてないので、あくまで所感)。

FlutterとRNを比較したときに考える点としては今のところ以下があるかなと思いました。

  • Android/iOS/Web以外のプラットフォームを考慮するかどうか
    • 各種デスクトップはFlutterのほうが楽に組み込める(と思う)
  • プロトタイプ的な開発(PoC)かどうか
    • PoC的なものをスピード感持って作るなら、UIの自由度が高いFlutterのほうがやりやすい印象
    • リリースに向けて改めて検討するのはありだと思う(言語が違うのでそれなりにコストはかかるが、もし余裕があれば)
脚注
  1. One Trick Ponyの略で、主にゲーマーの間で使われるネットスラング。一つのキャラクターや武器に特化したプレイスタイルをする人を指す。いい意味でも悪い意味でも使われる。 ↩︎

  2. 過去にXamarin Formsを経験しているのでそれを引きずっている。ここはアップデートできて良かった。 ↩︎

Sun* Developers

Discussion