react-native-web はクロスプラットフォームを加速するのか

[A Glimpse Into The Future With React Native For Web](https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/) という記事を読み、[react-native-web](https://github.com/necolas/react-native-web)というプロジェクトを知りました。
本記事では、この技術の概要と自分の意見を書きます。

# react-native-webの概要
## より抽象化されたViewでWebアプリを書ける
React Nativeで書いたコードはiOS、Androidに対応する。
このコードがそのままWebで動くとよいのでは？という発想で作られたライブラリ。

*「ReactはもともとWebの技術じゃないか」*というなかれ。

`<div>`や`<p>`をそのままブラウザにマッピングするReactは、
`<View>`や`<Text>`をプラットフォームごとにマッピングし直すReact Nativeより、
抽象度が低い。
だから、`<View>`や`<Text>`をWeb用にマッピングし直して動かせるようにしたのがこのライブラリだ。

### 実は勢力拡大中だったReact Native
この発想は新しいものではない。すでにReact Nativeはその守備範囲をモバイルから広げている。

- [react-native-windows](https://github.com/ReactWindows/react-native-windows)
- [react-native-macos](https://github.com/ptmt/react-native-macos)

`Learn once, write anywhere`の思想はとどまるところを知らないようで、
このようにネイティブなデスクトップアプリを作成できるプロジェクトもある。どこまでも我々~~をハメようとしている~~に夢を見せてくれている。

Webに関しては、ViewのマッピングはDOMに落ちるだけなので、ネイティブ機能を呼び出すよりよっぽど単純なしくみで、これらに比べるとエラーも少ないだろう。

## CSS in JSを使える(強制的に使わされる)
Webの世界以外のViewは、CSSという劇薬の仕組みはないので、[CSS in JS](https://speakerdeck.com/vjeux/react-css-in-js)のように、インラインスタイルを各コンポーネントに反映させていく。この仕組みを強制することで、クロスプラットフォーム対応に加えてCSSの抱える諸問題について考えなくて済む。

## babel + webpackで開発できる
React Nativeは`React Native Packager`というbundlerでコードをまとめていた。内部ではbabelが利用されていたが、bundlerの自由度は高くない。またコードの変換は各モバイルデバイスの持つJavaScript実行エンジンさえ考慮していればよかったが、Webはそうもいかない。現在のベストプラクティスに近いbabel + webpackで普通に開発できる。

## ListViewを除く全コンポーネントが対応
ListViewは使えないので、個別対応が必要になるが、その他は移植できている。
React Nativeの書き方でコードを書き、それをWebで走らせることができるだろう。


# 私の考え
彼らも明言しているが、まだproductionに導入できる段階ではないと思う。
それを前提にしたうえで、メリットとデメリットについて述べる。

## 良い点
### モバイルWebに展開できる
Webアプリケーションをモバイル展開したいとき、アプリとモバイルWebのコードが共通化される。

### デバッグをWebで
React Nativeのデバッグのしやすさは本当に素晴らしいが、
Webに慣れたエンジニアの抵抗感という意味では、Viewロジック部の開発をWebで完結させてから、各プラットフォームで微調整&固有の機能開発、というのも良いかもしれない。
(と書いておいて、自分はきっとやらないだろう)

### Electronをクッションにしてネイティブ対応を待つ
抽象化されたViewでコーディングすると、裏側のView解釈部分はあとから選べるという利点がある。これを活かし、とりあえずWebレンダリングなelectronでreact-native-webを開発し、react-native-macos等が安定したら移行する、という開発方法を検討可能だ。(「安定したら」はやってこないのが世の常であるが)

## 微妙な点
### View Componentって使い回すものなのか？
モバイルWebでなければ、アプリとWebはUIが異なり、使い回すことは想定されにくい。
となると、`Learn once, write anywhere`の発想になり、
普通のReactに分があるように感じる。

### routingは環境依存
Webは**URLに状態を格納している**といえる。SPAもhistory APIによって、特定の状態の頭出しができるし、それはユーザーから求められた機能だ。一方アプリはエントリポイントがひとつ、文字列による頭出しのような操作はない。
RoutingというViewの上位に来る概念での本質的な違いがあるため、アプリ全体をひとつのコードにするということはできなそうだ。

### セマンティックWebはどうするのか
`<section>`や`<article>`、`<header>`などの意味付けされたタグへの翻訳は制限される。
が、これは無視してもいいかもしれない。この技術の関心領域は明らかに「アプリケーション」であり「ドキュメント」ではないからだ。ドキュメントであれば、クロールされてセマンティックに解釈されて、Webの世界のsearchablityに貢献するかもしれないが、その用途ではないことは明白だ。


## クロスプラットフォームについて思うこと

### Viewは個別に書いてもいい
React Nativeは、マルチプラットフォーム対応というビジネスニーズに迅速に応えるのに向いている技術だし、これからも良い方向に向かうと思う。
ただ、利用シーンが大きく異なるプラットフォーム間でのView Componentの共有は、DRYの利点よりも、結合が増えるデメリットのほうが大きいように感じる。
書き方が変わらないだけでも十分な恩恵だと思うし、それが`Learn once, write anywhere`だ。

### モデルこそ、DRYにしたらいい
一方、モデルやその状態管理については、プラットフォーム依存はないべきだ。
例えばReduxのような状態管理ライブラリとモデル部をuniversalに書いて、各プラットフォームで使い回すというのは、とても良いアプローチだ。
値のCRUD、サーバーとの同期、オンライン/オフライン処理など、アプリでデバッグしづらい部分をNodeで入念にテストして投入できる。もちろんHTTPは`fetch`を使えば勝手にuniversalになる。
(このあたりは、実践投入して知見を得たのであとで記事書きます。)

# まとめ
- react-native-web は、抽象化されたViewでWebアプリを書けるという選択肢をもたらした。
- mobileWebなどで、使い回す利点がありそう。
- 根本的にはViewはプラットフォームごとにあっていいと思う。
- モデルや状態管理の共有のほうがマルチプラットフォームのためには大事と思う。