ReactNativeを触るにあたって読んだドキュメント、ツール、サンプルまとめて整理してみた

先日、ReactNativeでiOS/Androidアプリを書いている友人に、**"プログラミング触ったことない友達が二週間でReactNativeでアプリ作ったよ"**と言われました。次々に新しいものが出てくるJS界隈をずっと敬遠していたものの、彼の言葉を聞いてちょっと触ってみようと思い、そのために読んだドキュメントや準備したことなどをまとめてみました。
重要度をを☆(最高5☆)で評価しています。最低限☆5を抑えれば初めてでも開発できるのではないかと思います。

#自分の前提条件
- Androidエンジニア
- Javascriptについての知識は基本レベル。Node.jsを使ったbot開発の経験あり。近年のJS周りの話(React, Angular JS, ES6)はほぼ知らない。
- iOSの知識も小さなアプリを幾つか作った程度のレベル。


#ドキュメント
ReactNativeを始めるに当たっては思いの外色々なドキュメントに目を通さなくてはいけなかったです。Androidを書くためにはJavaを知っていないといけないのと同じ具合ですかね。とりあえず以下を把握できていれば十分じゃないかと思いました。

## ReactNative(重要度☆☆☆☆☆)
なにはともあれ [ReactNative](https://facebook.github.io/react-native/)は素晴らしいサイトでした。
Docs配下にある The Basicsを追っていけば、基本的なアーキテクチャやコンポーネントを理解するのに十分です。簡単にUI Componentがいじくれるので、感動します。

## ES2015(重要度☆☆)
https://babeljs.io/learn-es2015/
ReactNativeを触って気付くのは、記法がなんか知っているのと違うぞ、というところです。ReactNativeの[Document](https://facebook.github.io/react-native/docs/tutorial.html#what-s-going-on-here)を見ると ES2015という今後スタンダードになる予定の記法によって書かれているということを知ります。ES2015については[ここ]()に詳しく仕様が書かれていて、興味深く読みました。とりあえず記法が過渡期だからモダンな書き方をしつつBabelで後方互換するって流れのようです。

## React(重要度☆☆☆☆)
https://facebook.github.io/react/
一通りReactNativeを触った後に、そもそもReactってなんだという話になります。で、Reactを見てみました。 UI Componentを作るのに特化したライブラリだとわかります。基本的な書き方は当然ReactNativeと同じです。ドキュメントを一通り目を通した結果、ImmutableなUI Componentを描画することでView側にステートを持たないようにするのがReactの思想なんだなーと理解しました。


## Redux(重要度☆☆☆☆)
http://redux.js.org/
ReactでView側でステートを持たないようにすることはわかった、じゃあどこでステートを管理するの?というところから、今度はReduxについて調べます。
ReduxはFluxというアーキテクチャをより簡潔にしたライブラリです。
[Flux](http://facebook.github.io/flux/)はデータのフローを一方方向にするという、Facebookで生まれた新しいアーキテクチャです。
FluxについてはFacebookのサイトみても割とよくわからなかったのですが、この[イラストでわかるFlux](
https://code-cartoons.com/a-cartoon-guide-to-flux-6157355ab207#.uitxpjgtm) は理解の手助けになりました。
どういうメリットがあるかというと、

- ステートの管理を一箇所(Store)にまとめることが可能となった
- View側からのActionとそのActionの結果を描画する部分が分離され、複数のViewの更新やデータの管理が容易になった

ReduxではReducerというactionに基いてstateを更新する役割が追加されています。

## awesome-react-native(重要度☆☆☆)
https://github.com/jondot/awesome-react-native
ReactNative関連のフレームワーク、ライブラリ、ドキュメントが集まったレポジトリ。読み物というよりは、ポータルサイト的な位置づけなのかと。
ココを見ると, ReactiveNative界隈の開発盛んさが見て取れます。Componentのライブラリが多すぎてどれをみたらよいかわからない時は、 [COACH.JSのReactNativeの項目](https://js.coach/react-native)を見ると今Hotなライブラリが確認できます。


#ツール
開発をスムーズに行うために導入したツールです。

##Nuclide(重要度☆☆☆☆☆)
[Nuclide](https://nuclide.io/docs/platforms/react-native/)はReactNativeにも対応したIDEプラグインのようなものです。Atomだとpackagesからインストールできます。Debug機能やAutoComplete機能を備えていて、恐らくこれがあれば万全なのかと思います。

##Flow(重要度☆☆☆)
https://flowtype.org/
Facebook製の型チェックツールです。型チェックだけでなく、Nullチェックも行ってくれます。最近だと型があるTypeScriptなんかがあるようですが、いわゆるJavascriptで記述する場合は型チェックは非常に役立ちますね。

```
// @flow
var str = 'hello world!';
console.log(str);
```

こんな感じでファイルの先頭に annotationをつけることで、リアルタイムで検証を行ってくれます。


#サンプル
サンプル、というかオープンになっているReactNativeのアプリに関して言えば、それはもう[山ほどある](https://github.com/jondot/awesome-react-native#open-source-apps)のですが、自分はReactNativeの総本山で作られたF8をまずは触ってみました。

##F8Appを触ってみる
F8AppはiOS, Android向けに作られたフルReactNativeなアプリです。
ソースコードおよび開発手法その他も公開されており、本格的なチュートリアルと言っても過言ではないです。

ソースコード: https://github.com/fbsamples/f8app
ドキュメント: [Building F8 App](http://makeitopen.com/)

どのような設計に基づいてF8のアプリがデザインされたかが書いてあり、大変勉強になります。
また、Android/iOSで開発する場合のディレクトリ構成も参考になりました。

ただしアプリのメンテナンスは夏頃から止まっている様子で、Android, iOSともにアプリのビルドには手間がかかります。
いずれもissueで報告が上がっていて、それで解決できました。グローバルレベルでのコミュニティの温度が高いのはReactNativeの良さの一つでもあるかもしれません。以下ビルドするまでに修正する点についてまとめました。



### Androidの場合
- Buildが失敗する
手順通りにbuildすると Manifest mergerにThemeがconflictしているよ、と怒られます。以下のように修正すれば、ビルドは通ります。

```
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -51,6 +51,7 @@
       </activity>
       <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
       <activity android:name="com.facebook.FacebookActivity"
+        tools:replace="android:theme"
           android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
           android:theme="@android:style/Theme.Translucent.NoTitleBar"
           android:label="@string/app_name" />
```

ref: [Build failed with an exception](https://github.com/fbsamples/f8app/issues/131)

- Login画面から次のスクリーンにいかない
Login画面を開いた後にクラッシュします。iOSもそうだったのですが、Login周りが若干古くて不具合があるようです。
Login画面を回避することで、動くようになります。(但しログインはできない)

```
+++ b/js/F8App.js
@@ -77,9 +77,9 @@ var F8App = React.createClass({
   },
 
   render: function() {
-    if (!this.props.isLoggedIn) {
-      return <LoginScreen />;
-    }
+    // if (!this.props.isLoggedIn) {
+    //   return <LoginScreen />;
+    // }
     return (
```

```
+++ b/js/setup.js
@@ -63,9 +63,9 @@ function setup(): ReactClass<{}> {
       };
     }
     render() {
-      if (this.state.isLoading) {
-        return null;
-      }
+      // if (this.state.isLoading) {
+      //   return null;
+      // }
       return (
```

ref:[Android After SKIPPED_LOGIN Action Error hasUnreadNotifications](https://github.com/fbsamples/f8app/issues/133)

### iOSの場合
手順通りビルドすると、以下のようなエラーが出ます。

```
/Users/tomoaki/Workspace/f8app/node_modules/react-native/node_modules/promise/lib/done.js:10
      throw err;
      ^

Error: Command failed: /usr/libexec/PlistBuddy -c Print:CFBundleIdentifier build/Build/Products/Debug-iphonesimulator/F8v2.app/Info.plist
Print: Entry, ":CFBundleIdentifier", Does Not Exist
```

Xcodeの互換性の問題のようです。7.3.1だとビルドがうまくいくのですが、最新のXcodeだとダメみたいです。
解決方法としては、F8v2.xcworkspace を開いてXcode上でビルドし、エラーを一個ずつ潰していくことみたいです。
podにある Facebookのライブラリの実装がちょっと古いようで、以下の様に直したところ動くようになりました。

```
- (void)setRefreshControl:(RCTRefreshControl *)refreshControl
{
  if (refreshControl) {
    [refreshControl removeFromSuperview];
  }
  refreshControl = refreshControl;
  [self addSubview:refreshControl];
}
```

ref: [iOS version is not working](https://github.com/fbsamples/f8app/issues/124)

- undefined is not an object
Loginがうまくできないので、xボタンで飛ばすと`undefined is not an object` というエラーが出てクラッシュします。
これはAppEventsLoggerが壊れているからのようです。 FBAppEventsLogger.js内で

```
logEvent(eventName: string, ...args: Array<number | Params>) {
  let valueToSum = 0;
  if (typeof args[0] === 'number') {
    valueToSum = args.shift();
  }
  let parameters = null;
  if (typeof args[0] === 'object') {
    parameters = args[0];
  }
  AppEventsLogger.logEvent(eventName, valueToSum, parameters);
},
```
をとりあえずコメントアウトすれば動きます。恐らく引数 argsのハンドリングが正しくないのですが自分のjs力では解決できませんでした。

#まとめ
"2週間でアプリ作ったよ"と聞いたので、ドキュメントをちょろっと読んだらさらさらっと出来るのかと思ってました。が、調べてみると期待に反して相当色々な考え方やフレームワークを理解していないとちゃんとしたアプリは作れないなぁという印象です。
Javascriptでネイティブに匹敵するレベルのアプリがAndroid/iOSで作れることは素晴らしいので、引き続き勉強を続けようと思います。