普段思ったことや、雑記。

Menu & Search

React Native開発のつらい点まとめ

2017年5月14日
React

React Native v0.42で開発していて、つらい点を述べていく。良い点はあったかもしれないが、忘れてしまった…(良い点含めたより公平な意見は、あらためてまた今度書く)。なお、製品でReact Nativeを運用されている方で、他にもつらいとおっしゃっている方もいるようなので、自分がReact Nativeに対して感じているこのつらさは間違っていないと思う。

大前提として「React Nativeは、Viewしか扱わないReactがベース」である

これがそもそものReact Nativeがつらいと思える根本的な原因かもしれない。React Nativeのコンセプト通り、React Nativeではたしかに、Reactの知見をほとんどそのまま流用してReact Nativeではアプリケーションを開発することができる。しかし、その知見のもととなる本家ReactはViewしか取扱いをせず、HTTP通信だったり、ルーティングだったりはサポートしない。よって、これらをするために、HTTP通信、ルーターと、React以外に他のパッケージを読み込み、View以外に必要な機能を追加していくことになる。また、Reactのライフサイクルメソッドはシンプルで、画面コンポーネントがマウントされそうとともにライフサイクルが開始し、最初のライフサイクルメソッドがフックされ、画面がアンマウントされそうになると最後のライフサイクルメソッドが呼ばれる。ここで問題なのが基本動作がこのライフサイクル、画面と、画面内のコンポーネント描画のタイミングに縛られるということだ(Reactのライフサイクルメソッドはこちら→ https://facebook.github.io/react/docs/react-component.html)。Webより複雑なイベントハンドリング、コントロールを求められるクライアントアプリケーションともなると、Webではそれで解決していた部分でも、いわゆる「かゆいところに手がとどかない」状態でやりづらく感じることがある。

つらい点一覧

だいたい言いたいことは言ったのだが(いきなりReactをクライアントアプリに使おうとするのが悪い、みたいな感じで極論すぎるが…)、細かいことについても下記に書いていく。

ことあるごとに、パッケージを追加していく開発スタイル

冒頭でも述べたが、実際はReact Nativeのコンポーネントとして、パッケージが多く公開していて、ちょっと凝った機能を持ったコンポーネントはOSSとして公開されているコンポーネントを使用するシーンが多い。例えば、小さなあたりで言うと、画面全体をロックしたい場合はちょっと工夫が必要で、これは用途にもよるが react-native-loading-spinner-overlay を使ったり、大きなあたりでいうと、チャット機能を実装したいとなれば、react-native-gifted-chatを使ったりする。あとは、UIの補助にはUIコンポーネントがまとまったNativeBaseを使うこともある。該当のReact Nativeのバージョンで動いているうちは良いのだが、開発中は結構盛り盛りでこういったパッケージを入れていくので、どのパッケージがメンテナンスがされなくなっただとか、ロックインの発生が気になる。

WebでのReactのライフサイクルメソッドがネイティブアプリにマッチしているとはいえない

冒頭で述べたように、React Nativeの処理はコンポーネントのライフサイクルに縛られるため、柔軟性に乏しい。Webよりクライアントアプリケーションのほうが繊細な挙動ができるため、もう少しクライアントアプリ向けのイベントが欲しい気がする(例えば画面が切り替わる際にコンポーネントを破棄するか生かすか選べるとか。そもそもReact管轄外だから積んでるのはわかっているけど…)。あくまでViewのライフサイクルにロジックを紐付ける感じになるので、どうしてもWebっぽい作りになる。ゆえに、React Nativeは画面をまたいだ場合の処理というのが結構苦手だ。

よく使われる定番のパッケージすら安定していない・ハマる

react-native-router-fluxはよく使われるルーターだが、動作が安定しないことがある。また、NativeBaseはよく使われるUIライブラリだが、デザインを調整しようとなると、最初導入した際には良い具合な見た目だったものの、調整段階で結局は外したほうがマシと、よかれと思って導入した後にハマったり、調整に時間を使うことがある。

新しめな資料は英語しかない

React Nativeの日本語資料は現行の開発で参考にした機会はなかったように思える。日本でもReact Nativeを採用して開発している企業はまだ少ないようなので当然だと思うが、資料が英語のみとなった場合での調査コストの増加は技術選定時には見逃せない点である。

気がついたらGithubのIssueを読んでいる。気がついたらソースの中身を読んでいる。気がついたら1〜2年前のStack Overflowをじっくり読んでいる

要するに、React Nativeと非公式パッケージのドキュメントが貧弱ということだ。React Native公式では、標準コンポーネントで使えるオプションだったり、サンプルコードを解説こそしてあるが、かなりあっさりしている。また、非公式のパッケージはコンポーネントで使えるオプションこそ列挙してあるが、使い方はソースコード読んでね!とか平気で書いてあるので、ドキュメントについてはもはや期待できない。

iOSはわりとしっかり動くが、Androidでは挙動が遅かったり、あやしいことが度々ある

React NativeはiOSのために作られたのかと思うほど、iOSでは思ったように動く。しかし、Androidでは最新機種をもってしてもリリースビルドでもモッサリしているし、デバッグモードで実行ともなるとその動作の重さがより際立つことになる。また、ちょっとした動作の不備、例えばコンポーネントがiOSシミュレータでは見えていたが、Android端末では見えない、などの事態があった。

デバッガの動作が不安定だし、重い

React Nativeのデバッガの出来は相当悪いと思う(2017年5月23日追記:フロントエンドには、react-Native-debaggerを使用)。React Nativeをデバッグモードで実行していると、iOSシミュレータのリロード中に接続不能になって、ビルドから始めることも結構ある(8081で起動しているデバッガから応答がないだとか、そんな感じのエラーメッセージが出てデバッグ中アプリが動かなくなる)。iOSではシミュレータ、実機ともにデバッグ時のアプリケーションの速度はストレスというほどでもないが、Androidの実機デバッグではデバッグ時の重さが際立つ。そのため、Androidの長めのテストは、リリースビルドをかけてやることが多かった。

React Nativeで解決できない箇所は、React Nativeが吐き出したネイティヴ向けのコードをメンテナンスすれば良いと思っていたら、難易度高そうで諦めた

React Nativeについてよく調べずに使っていたというのがそもそもの失敗だったのだが、Androidを例にすると、React Native上で画面が複数記述してあったとしても、Androidでは画面が1つだけ、ファイルでいうとMainActivity1つしか生成されない。実際のコードを見てみて気づいたのだが、MainActivity内でコンポーネントを書き換えを延々しているようで、例えば「ここの画面のテキストフォームはAndoroidだと表示崩れを起こしているから、React Nativeが生成したAndroidのネイティブコードを操作しよう」ということが非常にやりにくいということだ。もしかしたらうまいことできる方法があるのかもしれないが、Androidのコード郡をパッと見た感じが不明だったので、今のところは時間的余裕がない限りは積極的にはやらないほうが良さそうと結論付けている。

コンポーネント志向とか言いながら、オリジナルのコンポーネントの再利用が起きなくて、コンポーネントのメリットをあまり享受できた感じがしない

これはアプリケーションの規模感にもよるかもしれない。React Nativeでオリジナルのコンポーネントを作ったとして、再利用する機会がほとんどなかった。コンポーネント化の目的が再利用というよりかは、画面の肥大化を防いだり、コンポーネントに分けることで適切にスコープを設定するために再利用可能なコンポーネントとして定義していた。別な箇所で少し述べたが、Reactコンポーネントは、インタフェースが統一になるので、OSSのコンポーネントを統合するのには非常に役に立つものである。

GUIでUIを編集できるツールがない・これというオンリーワンなIDEがない

ReactのコミュニティはJavaScript界隈の中では、かなり大きいコミュニティだと思う。これだけ流行っているような感じなのだが、まだ発展途上のようで、React関係のIDEはいくつかあるものの、これを使えば間違いないというものは現状存在しない。よって、開発ともなると、皆思い思いのエディタでコードを書いているのが現状だ。IDEがないことにより、ネイティブアプリ開発者にはもはや当然となっている、IDEのGUIによってUIパーツの位置決めをしていくという当然のこともReact Nativeでは不能である。Reactコミュニティは急速に発展しているのと、あとはReact Native自体がまだv1.0に達していないことから(2017年5月14日現在)、今後IDEにまつわる問題は解消するかもしれない、…が、あまり期待しないことにする。Web開発者がReact Nativeを扱いだすとこの点はあまり気にならない、むしろ今まで通りにWebのReact開発でそうであったように、JSXタグを打ち込んでいくので慣れている感すら感じるかもしれない。一方で、XcodeやAndroid Studio、UnityなどのクライアントアプリのIDE使用経験者にとっては、標準のUIアセットを閲覧できないこと、GUIによるアバウトな位置決めすらできないことなど、色々とストレスを感じる環境かもしれない。

アプリケーションのパフォーマンスは各端末上で動作するJavaScriptインタプリタの性能頼み

React NativeはiOS端末だと本当によく動くが、一方でAndroid端末では最近の端末ですらリリースビルドでもモッサリした感じになる。React Nativeの動作は、端末のハードウェア性能、該当OSのJavaScriptインタプリタの性能に依存するので、特に機種によって性能差やOSバージョンの差異が激しいAndroidでは動作検証に注意が必要だ。

画面切り替えをすると、表示中コンポーネントがアンマウントされる。新しい画面が出現するとコンポーネントがマウントされる。画面をアンマウントされなくて良く、バックグラウンドで動作するという選択肢はなく、画面の状態・処理状態を任意に保持・破棄することができない

React Nativeは普通に組んでいくとどうしても作りがWebっぽくなってしまう。理由は簡単で、WebのReactのライフサイクルメソッドがそのままReact Nativeで使われるため、画面コンポーネントに縛られた構造になる。別に画面を再レンダリングしなくてもよいのに、コンポーネントが生成されようとすると、強制的に再レンダリングをする(※2017年5月15日追記: react-native-router-fluxを使うことでこれを防ぐことができるが、それでも少し扱いにくい)。この仕組みが世界観的にはWebアプリケーションの作りによく似ている。純粋なAndroidでは、View(Acitivity)以外にServiceと呼ばれる画面に紐付かないプログラムも記述できる。React Nativeでも、バックグラウンドタスクを実行できるようだが、react-native-workersのようなパッケージに頼るしかないようだ。React Nativeでバックグラウンド処理をするとして、JavaScriptはシングルスレッドなので、刺さる処理があるとアプリケーションの動作に影響があるため、よく考えて処理を書く必要がありそうだ。

画面間での情報の受け渡しに非常に弱く、基本的にはReduxなどの外部でstateを管理するシステムを使うことになる

Reactの基本思想はコンポーネントに閉じていて、「親から子へ、単方向のデータの流れです」なんていう設計思想であるが、じゃあネイティブアプリみたいに大量の画面が発生して、他画面に変更通知をするにはどうすればいいの?という状況では、お分かりの通りReact単体ではこの問題は解決することはできず、Reduxなどの他の手段に頼ることになる。ネイティブアプリ向けライブラリなんだからこのへんもしっかりサポートしようよ…と思うのだが、おとなしくReduxのような、コンポーネントに閉じずに外部でもstateを管理するシステムを使えということらしい。一方で、Reduxにみるようなコンポーネントへの更新通知に頼らず、なんなら情報を画面おきにクライアントDBにでも保存していってしまえ!という思想の場合、データストアにKVSのAsycStorageがあるじゃないか、と言われる方もいると思うが、たまにアクセスに失敗することがあったり、ちょっと挙動が怪しいことがある(※事象としてはiOSシミュレータ上で、たまにAsyncStorageへのアクセスでコケることが確認できた。なので、AsyncStorageは必要以上には使わないようにしている。実機では今のところは同様の現象は未確認)。AsyncStorageは、KVSのわりにデータの保存形式がMongoDBみたいにゆるくないので、データの保存先としてそもそも扱いにくい。Reduxによる他画面への更新通知以外に、データストアの力で解決するような他の逃げ方でいうと、RealmのReact Native版を使うことを思いついたが、これは未検証である。

プッシュ通知が公式では最新のv0.45でもiOSしかサポートされていない

見出しの通りで、結局Androidも両対応となると、react-native-push-notificationのようなパッケージに頼るしかない。ネイティブアプリの基本的な機能の実装すら、公式がサポートに消極的な様子が伺える。

総評: React Nativeでは、ネイティブアプリ開発に必要不可欠なものすら公式から提供されていない。なので、色々とパッケージを盛りまくって、盛ったパッケージの英文資料を読みまくり、JSXタグを打つのが開発の大半となってしまう。Androidについては気合いでなんとかする

React Native開発では、これが定番のパッケージらしいとかを調べ、Railsにgemを入れるが如く、React Nativeに色々とパッケージを盛っていき、該当パッケージの動作検証しつつ、取り入れていくのが主な開発スタイルだ。なぜこうなってしまうのか。それは、冒頭で述べた通り「React自体がViewしか扱わない」からなのが根本原因として、そしてReact NativeはReactをネイティブアプリとして動作させるだけで、Facebook社の気まぐれによりちょっとしたネイティブアプリ向けのViewや機能を提供しているだけのプラットフォームだ(※あくまでv1,0以下、v0.42の感想)。クライアントアプリケーションを作る際の環境にするためにパッケージをどんどん追加していかないとReact Nativeが使い物にならないから、そうするしかない。そのパッケージを追加していく過程では、英文資料がやたら出てくるのでもちろんそれは読むし(公式が出してるパッケージなどなく、有志が公開しているパッケージなのですごく雑な英語なので読みづらいし、情報量が少ない)、英文が理解できたら資料の通りにJSXタグを打つのみだ。それでうまくいけば良いが、思いの外、Androidの動作状況が芳しくなく、色々と頭を悩ませる。それは気合でなんとかする。

最後までつらいことづくしだが、React Native開発で最もつらいことは、開発時間うち調査にかける時間が多く、もっとこうするとユーザ体験が向上するとか、ロジックの部分とか、本来クライアントアプリを作る上で最も労力を割くべき工程に頭と時間を使えていないことだ。

そして仮にそこ時間を使うとしても、React Nativeを使ってiOS、AndroidともにSwiftやJavaで書かれたよく工夫されたネイティブアプリケーション並みの品質のアプリ向けを作るには、想像以上の労力を要するという感覚がある。なんにせよ現行はv1.0以下なので、色々言いたいことはあるのだが、開発バージョンとしてみればこんなものなんだと思う。

Article Tags
mmiyauchi

プログラムを書きながらTranceを聴くのが良いですね。みなさんも聴いたほうがいいですよ、Trance。EDMよりハードトランスでしょ。

Related article

Meteorのブームが来るか来ないと言われれば、来ないと思ってしまった件

2016年秋頃から、…

Meteorアプリケーション(Blaze)の運用をしてみてハマったこと

※前提…Meteor…

DockerでJavaScriptシェル(Node.js実行環境)をつくる

JavaScript…

5 Discussion to this post

  1. 7番目の宮内 より:

    Ver 5000兆くらいになったら、使えるようになるんですかね?

    • mmiyauchi より:

      >> 7番目の宮内さん

      コメントありがとうございます。
      そうですね、React Nativeがv5,000,000,000,000になる頃には、もはやReact Nativeは既に時代遅れになっており、あたらしく「React Real」が出てきて、
      JSXタグで現実世界の物質もレンダリングできる程度には進化しているんじゃあないでしょうか。

      世の中、たいていのことはJSXタグでラップしてrenderメソッドを実行すれば解決するような素晴らしい世界になると良いですね!

  2. 8番目の宮内 より:

    og:imageが真っ白です。

    • mmiyauchi より:

      >> 8番目の宮内さん

      コメントありがとうございます。
      今日は宮内がやけに多いですね。

      たしかに、そうですね。
      日曜日の昼下がりで気分で書いたポエムなので、記事にサムネ画像を設定していなかったです。 とりあえずReactのロゴをサムネ画像にしておきました。

  3. 9番目の宮内 より:

    Unreal Engine, Unity, Xamarin… の比較資料まーだー?

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

Type your search keyword, and press enter to search