📱

FlutterとReact Nativeの両方で開発・運用を経験した結果、選ぶならどちら?

2021/12/16に公開

この記事は、株式会社アトラエのアドベントカレンダー2021年16日目の記事です。昨日の記事は、@wasao15 による「アトラエ(AI)将棋部について」でした。


はじめに

こんにちは!People Techのアトラエでエンジニアをしている @risafj です。入社したのが2021年4月なので、アドカレは初参加です。

私は現在、FlutterとReact Nativeの両方でiOS/Androidアプリの開発・運用をしています。その経験を踏まえて、各フレームワークでの開発の感想や、これからアプリを作るならどちらがおすすめといった話をしたいと思います!

Flutter開発経験

半年程度あります。
IT業界に強い転職サイトGreenのiOS/Androidアプリの開発・運用を担当しており、機能開発・不具合修正・CIツールの整備などを行なっています。

FlutterでAndroid版アプリを開発したメンバーの記事はこちら(私が入社前の話です):
https://note.com/raykaga/n/n52c1ee039331

React Native開発経験

1年強あります。
カップルなど2人で使うことに特化した家計簿アプリ「Warikani」を個人で開発し、リリース後も機能追加などを続けています。

https://warikani.page.link/app

この記事で書くこと・書かないこと

  • 書くこと:FlutterとReact Nativeで開発してきた個人的な感想。もし間違っている点があったらご教示ください。
  • 書かないこと:それぞれのフレームワークのパフォーマンス比較や、DartとTypeScript・JavaScriptの言語的特徴の詳しい話。

最初に結論

ほとんどの場合Flutterをおすすめします!
JavaScript・TypeScriptが得意な方で「学習コストを最低限に押さえて速くアプリを開発したい」という場合は、React Nativeもアリだと思います。

Flutterの好きなところ

1. 爆速Material Design

Flutterを使うと、おそらく最速でMaterial Designのアプリを作ることができます(さすがGoogle)。MaterialAppというクラスが用意されており、これをアプリのトップレベルに置くことでFlutterが提供するMaterial Designのウィジェットが使えるようになります。

// app.dart
import 'package:flutter/material.dart';
 
class App extends StatelessWidget {
    
    Widget build(BuildContext context) {
        return MaterialApp(
	  // この中にrouting, theming, localesなどの情報を書く
        );
    }
}

Flutterが提供するウィジェットというのは、例えばボタンひとつとっても TextButtonElevatedButtonOutlinedButton などが用意されており、カスタマイズも簡単です。

Material Designに基づいたウィジェット一覧:
https://docs.flutter.dev/development/ui/widgets/material

一方、React Nativeではボタンコンポーネントをはじめ、MaterialAppで提供されるようなコンポーネントは用意されていません。
ボタンが必要なら、タップを検知するコンポーネント TouchableOpacityの中に Text を入れて自作することになります(あるいはthird partyのコンポーネントライブラリを使う)。

また、Material Designに直接関係ない部分でも、Flutterはスタイリングを楽にする工夫が凝らされています。例えば画面の真ん中にローディングアイコンを表示したい場合、Flutterならこれだけです。Center が縦軸・横軸の真ん中に置いてくれます。

Center(child: CircularProgressIndicator())

Center のほかにも RowColumn なども用意されています。

一方、React NativeはもっとCSSに近い雰囲気でスタイルを当てることになります。

// JSXのテンプレートの部分
<View style={ styles.centerView }>
  <ActivityIndicator />
</View>

// スタイリングの部分
const styles = StyleSheet.create({
  centerView: {
    justifyContent: 'center',
    alignItems: 'center',
  }
})

もちろん、自分で CenterView のようなコンポーネントを定義すればFlutterと同じようなことができますが、プリセットで Center などが用意されているのは個人的には好感度高かったです。

2. 型の安全性

「DartとTypeScript・JavaScriptの言語的特徴の詳しい話はしません」と最初に書いておきながら、言語的特徴の話ですがw

Dartは、コンパイル時とランタイムの両方に型のチェックを行っており、型安全性が優れています。一方でTypeScriptはコンパイル時に静的型チェックを行いますが、最終的には型のことを何も知らないJavaScriptになってしまいます。

Dartの安心感を伝える良い例が思いつかなかったので、公式ドキュメントから引用します。
Dartでは以下のコードはruntime errorになります。

void main() {
  List<Animal> animals = [Dog()];
  List<Cat> cats = animals as List<Cat>;
}

一方、TypeScriptでは以下はエラーになりません。

type Dog = {
  name: 'Pochi' | 'Wanwan'
}

type Cat = {
  name: 'Tama' | 'Mike'
}

type Animal = Dog | Cat

const main = () => {
  const dog: Dog = { name: 'Pochi' }
  const animals: Animal[] = [dog]

  const cats: Cat[] = animals as Cat[]
  console.log(cats)
}

main()
// 実行時の出力内容:
// [ { name: 'Pochi' } ]

このような例のほかにも、React NativeのライブラリはTypeScript未対応で型ファイルがないといったことも無きにしもあらずなので、そういった意味でもFlutterのほうが安心です。

React Nativeの好きなところ

1. ほぼReact

Reactが書ければ非常にスムーズにReact Nativeの開発に入れると思います。
JSXの部分については、ウェブで使う要素をそのまま使うわけにはいきませんが、頭の中で置き換えればOKです。

例えば…

  • divView
  • ulliFlatList と、そのなかの renderItem

あまりに似ているので、私が学び始めたときはReact Nativeのコードの部分で苦戦した記憶よりも、App Storeへのアップロードの方法、Provisioning Profile周りといったアプリ開発全般の部分が難しいと感じた記憶があります。

2. テンプレートとスタイルが分離されている

ウェブ用のReactなどを見慣れていたからかもしれませんが、テンプレートとスタイルが分離されている点はReact Nativeのほうが読みやすいと今でも感じています。

またボタンの例になりますが、React Nativeで書いたらこんなイメージです。

export const Button = ({ onPress }: ButtonProps) => {
  return (
    <TouchableOpacity
      onPress={ onPress }
      style={ styles.button }
    >
      <Text style={ styles.buttonText }>
        '押してみて!'
      </Text>
    </TouchableOpacity>
  )
}

const styles = StyleSheet.create({
  button: {
    height: 40,
    width: 100,
    borderRadius: 10,
    backgroundColor: 'green',
  },
  buttonText: {
    color: 'white',
    fontSize: 16
  }
})

一方、Flutterで書いたらこんな感じです。

ElevatedButton(
  style: ElevatedButton.styleFrom(
    primary: Colors.green),
  onPressed: onPressed,
  child: const Text(
    '押してみて!',
    style: TextStyle(
      color: Colors.white,
      fontSize: 16,
    ),
  ),
),

Flutterのほうがコード全体は短いですが、React Nativeはテンプレート部分とスタイル部分の区別が一目瞭然だと思います。
(React Nativeでもinline stylesで書いたらテンプレートとスタイルが一緒になりますが、公式には Stylesheet.create がおすすめされています)

まとめ

私自身はReact Nativeも好きですが、今からアプリを作るなら基本的にFlutterがおすすめです。

さいごに

最後まで読んでいただき、ありがとうございました!
株式会社アトラエでは一緒に働く仲間を募集しています。興味ある方は、ぜひスライドをご覧ください!

アドベントカレンダーは明日 @shogotgm さんの予定です!お楽しみに。

Discussion