ReactNativeでイラストアプリを作った時の感想まとめ

## 概要
前々からReactNativeに興味があり、いつか気合入れたアプリ1つ作って感触を確かめてみようと思っていた。

今回ようやく1つアプリを作ることができたので、色々良い点、つらい点をまとめていこうと思う。

## 成果物
### イラスト閲覧アプリ
<img width="200" alt="Image uploaded from iOS.png" src="https://qiita-image-store.s3.amazonaws.com/0/20629/207edbae-0900-d64f-cc27-3d9621b4060a.png">

## 最初にまとめ
良い点はもう色々な人が大体まとめて新鮮味が無いと思うので、さらっと書く

* 想像していたよりも要求通りの機能が実装できた
* コード変更後の更新が早いし楽
	* 開発ツールが充実している
	* Command + Rキー押すだけで即時反映できるのすごい
* Reactで組める
	* データバインディングのフレームワークが標準で用意されてるような環境
	* Androidはデータバインディングライブラリが用意されてるが、iOSには無いのでこの環境は嬉しい
* CSSの知識で組めるレイアウトが便利！
	* ボーダーや角丸表現は圧倒的にやりやすい
	* flexは慣れるとスムーズに組める
* リスト表示の実装が簡単
	* AndroidやiOSは色々準備しないといけないが、ReactNativeは実質コンポーネント返す関数書けば終わる
* iOSのキーボードの扱いが楽
	* キーボード表示時のView移動の実装が楽
	* それ用のコンポーネントが提供されている
	* https://facebook.github.io/react-native/docs/keyboardavoidingview.html

以降は良い点以外を書いてく

## つらい・ハマったところ
### グリッド表示で苦戦
FlatListがカラム数を指定できるプロパティを持っていたので、これを使えばいけるかな？と思ったのだが、最終行の表示数がカラム数より少ないと項目の幅が引き伸ばされてしまい表示がおかしい。

ドキュメントを見るとflexWrapのようなジグザグなレイアウトになるよっていうのが書いてあり、AndroidのGridLayoutManagerの表示とは違うことがわかった。(カラム数を指定すると各項目の幅を自動調整してくれる)

同じ苦しみを持ってる人はいるだろうと、ライブラリを探してみたのだが、思いのほか見つからない。あるのはStaticなグリッドを組むやつで、リスト表示のパフォーマンスが落ちるようなものだった。

とりあえずそれっぽいのは見つけたのだが、ListViewがベースなのと、スクロールトップのメソッドが呼べなさそうだったので諦めた。
https://github.com/phil-r/react-native-grid-component

結局自分でコンポーネントを作ることにした。
(npmのライブラリに切り出すかも)

### iOSで画面遷移直後にエッジスワイプで戻ると、以降のFlatListがinitialRenderしか表示しなくなる
画面をスタックする時にアニメーションが走るのだが、その途中でエッジスワイプを動作させるとアプリを再起動するまでinitialRenderで指定した値分しか描画しなくなる。

まず再現方法の把握とその後の原因調査が非常に難しかったが、自分の場合は以下のissueコメントの方法で回避することができた。

https://github.com/facebook/react-native/issues/15734#issuecomment-333297942

厳密には`getItemLayout`を利用しているFlatListの画面に遷移する際に、アニメーション中にエッジスワイプをすると起きる現象のようだった。

### Router選定に悩む
個人的には`react-navigation`のあとに`react-native-router-flux`がしっくりきた
https://github.com/aksonov/react-native-router-flux

多くの部分で便利なライブラリなのだが、気になる点もある。

自分がハマった例だと、タブを押した時に画面のスタックを戻す処理を実現するために`backToInitial`をTabsに設定していた。

この後追加作業で、Twitterのようにタブを押した時にスクロールトップさせる処理を書こうとして各画面のnavigationOptionsに`tabBarOnPress`を設定したが動作しなかった。

疑問に思ってコードを読んでいると、`backToInitial`の中で`tabBarOnPress`にコールバックがセットされていて、自分が指定したコールバックを上書きしてしまっていた。

結果的に`backToInitial`を指定せずに、自分でこの処理+スクロールトップのコールバックを呼ぶ処理を定義して各画面に持たせることで実装した。

今回タブの中にStackを入れるような実装になっているのだが、これをどうやってこのライブラリで表現するのかしばらく試行錯誤していた。ルーティングの定義は最初は苦戦するかもしれない。(雑にスタックしてくようなやつは楽)

## 調べてること
*進展があれば追記していきます*🙇

### ViewPagerAndroidのパフォーマンスが悪い

横方向にページを表示する機能を入れたかったので、AndroidはViewPagerAndroidを使って実装しようとした。

ただ画面表示時にものすごい遅い事に気付き、調べてみたらどうやら全ての項目を一度に描画してるようだ(そりゃ重い)
https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/views/viewpager/ReactViewPager.java#L47

**(2018/02/13) 追記**
https://github.com/hudl/react-native-android-fragment

RactRootViewを使うとViewPagerからComponentのViewを生成できそうだなと思ったので、ReactRootViewをFragmentで使えるライブラリを用いてViewPagerクラスを作ってみた。

結果的にはOffScreenPagerLimitを設定すると、最初の分だけ描画してそれ以降は描画してくれなくて諦めた。(OffScreenPagerLimit=1の場合は最初の両サイドだけ描画してくれる)

ただまだ調べきれてないような気がするのでしばらく試行錯誤しそう。

Native UI Component触る機会としてはいい勉強になった。

## Androidの動作が重い？
iPhoneでは満足に動作するのだが、Android端末で動作させると重いケースが何箇所かあった。

Androidの端末もそれなりの値段で性能のある端末なので、他のアプリを使っていても基本的には遅くはならない。

体感でわかったのは横方向のPageScrolledなFlatListと縦方向のScrollViewを組み合わせた画面が2枚くらい乗るとスクロールが重くなる。

多少複雑な構造なのだが、AndroidでViewPagerを使った画面だとこのような条件で重くなることはないので、Componentの組み合わせは気にした方が良いのかなと思った。
(react-native-router-fluxによる画面スタックがそもそも遅い可能性もあるので、地道に調べる)

## 最後にメモてきな
* つらいとこはあったが概ね満足
* コンポーネントは特に手を加えていかなくても大体そのまま使えた
* FlexBoxは慣れてくると快適
    * 後半は苦もなくスムーズに組めた
* NativeModuleで制約がどれくらいあるかは調査中
* 実務で使えるかどうかで言えば要件次第かなという印象
    * 単純な要件のアプリに使えそう
    * 進んで使いたいかと言われると、現状ではやっていく気持ちが必要

これからもしばらく使ってみようと思う