React Native と Flutterを比較してみた

こんにちは。株式会社カミナシの keinuma です。 今回はReact NativeとFlutterの比較についてまとめてみました。

弊社ではモバイルアプリ開発にReact Native + Expoを利用しています。ExpoはCLIを筆頭に便利な機能が多く、開発フローの基盤になっています。 そんな中、クロスプラットフォームのライブラリとして人気を博しているFlutterと比較すると何が違うのか知りたくてまとめてみました。

比較する上で以下の観点に絞ってみていきます。

  • 基本情報
  • 開発環境
  • UI
  • 状態管理
  • テスト

基本情報

FlutterとReact Nativeの言語、提供元でまとめてみました。 ここ1ヶ月ほどFlutterを調べてみた中でDart言語はJavaやJS, Pythonなどのいいところをあわせもっていて書きやすい言語だなと感じました。

これまで静的型付け言語をやっていれば学習コストは高くないと思います。

Flutter React Native
企業 Google Facebook
言語 Dart JavaScript
GitHubスター数 107k 91.3k

開発環境

React Native

開発環境の構築やローカル環境の起動はExpoが便利です。 Expo CLIでは主に以下の機能が提供されています。

  • 新しいプロジェクトの作成
  • ローカル環境の起動
    • シミュレータ起動
    • ログ実行
  • Publish
  • 各プラットフォーム向けのビルド

ローカル環境を起動すると以下の画面が表示されます。 ログの出力やシミュレータの起動、実機で確認する導線が1画面にまとまっていてとても便利です。

f:id:kaminashi-developer:20201124011021p:plain
expo local

LintやmonorepoなどはNPMで用意されているものを活用できます。 弊社でもESLint + Prettierによるコード整形とLernaによるmonorepo構成を採用しています。

Flutter

FlutterもCLIである Flutter CLIが提供されています。 機能はExpo CLIと同じようにローカル環境の起動や各プラットフォームのビルドなどがあり、開発に必要な物が用意されています。

Expoの場合はテストやコード整形は他のライブラリに任せていましたが、Flutterではテスト実行やコードフォーマット、ローカライゼーションなどをCLI上で実行することができます。

NPMほど成熟したライブラリがない分、Flutter上で用意されている機能が多い印象です。

UI<レンダリング編>

React Native

React Nativeはレンダリングのコア部分を react と共有していて、各プラットフォームごとのUIコンポーネント出力しています。(例:React Nativeの ViewAndroidandroid.view であり、iOSUIView と一致)

そのためプラットフォームのスタイルにそったUIを実装することができます。 一方でコアとなる機能数は多くないのでUIライブラリに依存して実装する必要が出てきます。

Flutter

f:id:kaminashi-developer:20201124013543p:plain
Flutter

Flutterは フレームワークAPIを担う flutter/flutter と低レイヤの flutter/engine に分かれています。 flutter/engineC++で書かれていて、グラフィックライブラリ Skia を使ってネイティブコンポーネントを利用せずレンダリングしています。

ネイティブコンポーネントを利用していませんがAndroid向けにはMaterial, iOS向けにはCupertinoのテーマが用意されています。

UI<実装編>

React Native

React NativeのコンポーネントをJSXでUIを実装します。 スタイルも StyleSheet がReact Nativeに含まれているので、CSSライクに書くことができます。

黒背景に白文字のHello Worldを実装して比較します。

// React Native
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';

export default class App extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <Text>Hello world!</Text>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center'
  }
});

HTMLタグは使わずに全て react-native ライブラリに含まれてるコンポーネントで実装するのが特徴的です。

Flutter

Flutterは元々Reactにインスパイアされて開発されているライブラリなので宣言的にUIを記述する方針は一緒です。 JSXの代わりにWidgetを使ってUIを実装していきます。

先ほどReact Nativeで書いた同じUIをFlutterに書き換えてみます。 こちらのサンプルは Flutter for React Native developers に記載されている内容です。 

// Flutter
import 'package:flutter/material.dart';

void main() {
  runApp(
    Center(
      child: Text(
        'Hello, world!',
        textDirection: TextDirection.ltr,
      ),
    ),
  );
}

FlutterではデフォルトでMaterialのテーマを利用でき、その中にレイアウト専用のWidgetや状態管理のWidgetが用意されています。 また、フォントサイズや色などの基本情報も用意されていているのが特徴的です。

状態管理

React Native

React Nativeのローカルコンポーネントの状態管理では react-hooksが提供されています。 Reactでグローバルの状態管理を扱うライブラリは複数あります。

これらの中で多くのラリブラリが単一データフローを採用していて、データの更新フローを一つの流れにしています。

Flutter

Flutterでも公式ではないもののローカルでの状態管理にReact Hooksと同等の機能を使える Flutter Hooks があります。

グローバルの状態管理は調べたところ、いくつかライブラリがありました。

React同様にRxとReduxをFlutterで使えるライブラリ

Flutterで使えるライブラリ

中でも最後に書いてるRiverpodを使った状態管理の実装方法はmonoさんの記事を参考にしています。Riverpodはproviderの改良版になっていて、Freezedによってimmutableに状態を扱えるのでReduxに慣れていても安心感のある構造になっています。(コードを生成するのは独特だなと思いました)

テスト

React Native

React Nativeでテストする場合はNPMに用意されているライブラリを使うことになります。

Flutter

Flutterは公式に用意されているライブラリ(flutter_test, flutter_driver)に単体テストからWidgetテスト、E2Eまで含まれています。 ドキュメントに詳細がまとめられていてわかりやすいです。

まとめ

ここまでReact NativeとFlutterを比較してきました。調べ始めた当初はFlutterはまだ早いと思っていたのですが、開発する上でネックになることはないと感じました。開発環境もドキュメントも充実しているのでスムーズにアプリを開発できそうです。

一方でReact NativeのいいところはJavaScript資産を活用できることだと思います。弊社でもWebアプリをReactで開発しているのでモバイルアプリと共有しているコードは多いです。今後もどちらのメリットが大きいかを判断した上で技術選定できるようにしていきたいです。機会があればFlutterも使ってみたいと思います。

参考