ReactNativeを既存アプリに組み込むのを断念したメモ

弊社のアプリはフルネイティブでswift/kotlinで書いているんだけど、どうしても同じ機能を作るときにまとめて作れないかとモヤモヤする。かといってクロスプラットフォームな開発はcordova/titaniumなどで辛酸を嘗めたのであまりやりたくない・・・

そこでReactNative（以下RN）が流行っいるしどうかなって考えた。

# 結論

既存のswift/kotlinで書かれたプロジェクトに組み込んで徐々にリプレイスを・・・などと考えたが甘かった。使うにあたって結論として**「タイミングが今じゃないな・・・諦めよう」**としました。
詳細は以下。

# 考えたこと

## 特定の画面をReactNativeで書いて共通化できる？

これは**全然できる**。
ネイティブからjsをコールする感じ、webview読み込むあの時代の仕組みに近い。 

https://qiita.com/mickamy/items/514fb36d409547fb4adb

この辺を参考にいただければ。
ざっくりいうと提供されている `RCTRootView ` を使って、RNのUIViewを呼び出す。Androidでも同様。やっていることは `react-native start` と内部的にやっていることと同じっぽい。これまでのWebViewで内部に静的に持ったhtml/jsなどを呼び出すのと違うところはWebViewとは異なり、RCTRootViewはRN専用なので俺俺なjs <--> swiftな実装をしないでいい。

[Passing properties from native to React Native](https://facebook.github.io/react-native/docs/communication-ios)

```App.swift

NSArray *imageList = @[@"http://foo.com/bar1.png",
                       @"http://foo.com/bar2.png"];

NSDictionary *props = @{@"images" : imageList};

RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
                                                 moduleName:@"ImageBrowserApp"
                                          initialProperties:props];
```

```App.js
import React from 'react';
import {
  AppRegistry,
  View,
  Image
} from 'react-native';

class ImageBrowserApp extends React.Component {
  renderImage(imgURI) {
    return (
      <Image source={{uri: imgURI}} />
    );
  }
  render() {
    return (
      <View>
        {this.props.images.map(this.renderImage)}
      </View>
    );
  }
}

AppRegistry.registerComponent('AwesomeProject', () => ImageBrowserApp);
```

これによってある程度のstaticな変数や関数をjsで再定義するような手間は省けそう。自前でのjs <--> swift実装は手間がかかる割にあまりいいことがないし脆弱性の温床なのでやめたい。（RNであれば問題ないかは別）

## レイアウトの懸念はアプリエンジニアでもわかるのか？

スタイルシステムがSASS/CSSだけになってくる懸念。
**実際は便利な仕組みが多々ありなんとかなりそう。**

### FlexBox

まずCSSはあまり得意じゃないので基本的な構造（ヘッダーがあってコンテンツがあって）を作るだけでも辟易しそうだったが `FlexBox` というのがある。

[レイアウトを整える【これからはじめるReact Native】](https://bagelee.com/programming/react-native/react-native-layout/)

```js
const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#fff',
        alignItems: 'center',
        justifyContent: 'center',
    },
});
```
これを各コンポーネントに当てる形で`CSS in JS`を使いレイアウトしていく。
直接記述するとこう。

```js
<View style={{flex: 1, backgroundColor: 'powderblue'}} />
<View style={{flex: 2, backgroundColor: 'skyblue'}} />
<View style={{flex: 3, backgroundColor: 'steelblue'}} />
```

**それぞれのレイアウトのサイズ割合を1,2,3にする**という意味になる。
整列やサイズ比の調整が楽そうなので細かいところはおいておいてなんとかなりそうという印象。

### ReactComponent Set

`ReactComponent Set`を使うという選択肢もある。CSS Frameworkみたいなものだろうか、私みたいなCSS弱者にはとても嬉しい。

[早く・それなりの UI を実現する React コンポーネントセット 16 選](https://qiita.com/kyrieleison/items/39ce30dd2d204791a9ea)


## デバッグ方法はどうなっているの？

[React Nativeのデバッグ方法](https://qiita.com/takaishota/items/96802dc7e522aeba058b)

特に**問題ない**ように見えます。

デバッグログについてはVisual Studio Codeで全部解決できそうだ。UIデバッグについてはReactの提供しているGUIがあるよう。ちょっと物足りないような気もする。

## リリースビルドはどうなっているの？

[expo.ioを使ってリアルタイムにReact Nativeアプリを開発する](https://blog.gmork.in/entry/2017/04/18/120000)

特に**問題ない**ように見えます。

社内配布のときは `expo.in`というのを使うとクライアントから配布できるようだ。
`exp`というツールでリリースビルドできるようだ。

プロビジョニングファイル系も全部expoがやってくれるらしい。コレは嬉しい。

## アーキテクチャ・構成どうしよう

この辺の理由が主に断念理由です。
**Web/Appそれぞれの別のアーキテクチャが混在することになり、アーキテクチャの統合に懸念があるためです。**

ネイティブ側はMVVM + Rxで実装されている。1プロジェクト内に複数のアーキテクチャは入れたくない。またReactである以上「FluxやReduxにしてView側はAtomic Designだ！！」という気持ちになる。

[Atomic Design を導入してみた話](https://moneyforward.com/engineers_blog/2018/01/24/atomic-design/)

[【iOSDC2017】MVC→MVP→MVVM→Fluxの実装の違いを比較してみる](https://qiita.com/marty-suzuki/items/5a4f680b10bb82501aa3#flux)

もしFluxにネイティブ側も合わせる場合、MVVM -> FluxはViewModelをDispatcher/Action/Storeにしていく作業が必要かと思い。やってやれないことはないですが、豊富に人材がいて、圧倒的モチベーションの元どちらも学んでくれるような人がいる環境であれば強気にコレにトライしてもいいでしょう、でもそうでない大多数のケースにおいてはだいぶ気合の求められる試みだと感じました。

# 結論

触ってみて

- まだどれだけサービスがスケールするか決まってない
- センサ類を多用しない
- 社内に担当がいる
- Android/iOS両方のリリースが求められる

というケースであればいいのかなーと感じました。

弊チームでは今は新メンバーがどんどん入ってきているし、もう少し採用が落ち着いたタイミングである程度web/Appのエンジニアをミックスしながら作ってみようと思います。:writing_hand: