ReactとReactNativeは別物だけど, iOS, Android, Webのコードシェアリングをする
ReactとReactNative使えばiOS, Android, Web同時に開発できるんでしょ? 凄すぎでは? ちょっとやってみよう.
ということで最近ReactとReactNativeを始めた.
ReactNative経験者は多分この時点でおかしいと気づくのだろう.
ReactがWebで, ReactNativeがiOS, Androidで同じレイヤーの話なんだと, 始めた当初の私は大きな勘違いをしていた.
それはとても大きな間違いだったのだが, その説明と実際にiOS, Android, Webを極力同じコードで動かそうとすると, どういう構成になるのかについて書こうと思う.
Reactは「Viewの更新」をシンプル化するライブラリでしかない
Reactとはそもそも何ぞや? 個人的に見た中で一番納得したのがReduxの公式ページに書かれている文章である.
This complexity is difficult to handle as we’re mixing two concepts that are very hard for the human mind to reason about: mutation and asynchronicity. I call them Mentos and Coke. Both can be great in separation, but together they create a mess. Libraries like React attempt to solve this problem in the view layer by removing both asynchrony and direct DOM manipulation. However, managing the state of your data is left up to you. This is where Redux enters.
Reactに関連する部分を要約すると, 「値の変更が非同期に行われることはアプリケーションの複雑度を増加させる. それを非同期処理と直接的なDOM操作を廃することで, Viewの更新をシンプルにするライブラリ」みたいなことが書いてある. もちろん意訳だ.
どうやってこれを実現するかというと,
- JSX (≒XML)でComponent(≒View)の構造を定義
- Component.setState()に更新処理を集約して, 状態の更新のみを行わせる
- setState()が呼び出されたら, 再レンダリングによってViewの差分更新を行う
語弊を恐れずに単純に書くとこうなる.
より詳しく (もしくは正しく) 知りたい場合は公式のGettingStarted - MainConceptsの範囲を読むことを勧める.
ReactNativeのComponentはNativeViewである
ReactがComponentをhtmlのDOMで表現するのに対し, ReactNativeはNativeViewで表現する.
Build native mobile apps using JavaScript and React
React Native lets you build mobile apps using only JavaScript. It uses the same design as React, letting you compose a rich mobile UI from declarative components.
実際にトップにしっかりとJavaScriptとReactを使ってネイティブアプリを作成するライブラリだと書かれている. こちらの最小構成要素は,
- DOMの代替となる標準Component群 (Text, View, etc…)
- ReactNativeRenderer
実際のところはもっとあるが, この2つがあれば概ね問題なさそうだ.
ReactとReactNativeの関係
ではReactとReactNativeがどのような関係になるのか図に纏めよう.
React-DOMが唐突に出てきたが, facebook/reactにあるが, reactとは別のnpmパッケージになっている, Web版のRendererに相当する.
こんな感じにComponentはstateの更新処理が注入できるようになっているので, Rendererはこの更新処理の設定およびと描画を担う形だ.
さて, これでReactとReactNativeのレイヤーが異なることが分かると思う.
本題: WebとNativeを同じコードで動かす
react-native-webとreact-native-dom
ここまで来るとそのままではうまくいかないのは容易に想像できる. しかしそのような試みはいくつかあって,
この2つが現在取りえる選択肢のようだ.
前者はReactNativeが用意しているComponent (他にもあるが) 部分をWebでも使えるようにするもの. つまり図の最上段部分である.
後者については簡単に説明できなさそうなので, Web最新技術がてんこ盛りのreact-native-domから目が離せないの記事を参照して欲しい. とても丁寧に解説されている良記事だ.
今回は前者を使う. 単純に今のところこちらの方が一般的に使われているようだからだ.
react-nativeをreact-native-webにaliasで書き換えればReactNativeのアプリと大体同じコードが使えるようになる.
共存できないものはそれなりにある
そう. 大体なのである. いくつか互いに足りない部分がある.
- ネイティブにあってreact-native-webにはない
- webではできてネイティブではできない
- addEventListener()のようにReactNativeでpollyfillされていない物
これらが出てくると分岐が必要になる.
.native.jsと.web.jsを使い分けることでこれらは分岐することができるので, あとは必要に応じて分岐させれば良い.
当然entryPoint (index.js) も分ける必要があるので, ここも分岐させる. あとはWeb側に必要なWebpackの設定を書けば今度こそ終わりだ.
まだまだ模索中
実のところ, この構成はCreateReactNativeAppの–with-web-supportと, Code sharing between React and React Native applicationsの記事を参考にした.
そもそも論として, そこまで同じコードを使いたいのかという話もあり, 調べた限りではModelやStoreのみを共通化するのが一般的に感じた.
そこらへんはおいおい考えていきたい.
また, 実際のコードを確認したい場合は, soranoba/ReactNativeSkeltonを参照して欲しい.
おわり.
記事が気に入ったらチップを送ることができます!
You can give me a cup of coffee :)
Kyash ID: soranoba
Amazon: Wish List
GitHub Sponsor: github.com/sponsors/soranoba
PayPal.Me: paypal.me/soranoba
(Updated: )