Skip to content

Instantly share code, notes, and snippets.

@kenmori
Last active September 16, 2019 12:19
Show Gist options
  • Save kenmori/e2f939efc51821006f98186d666b4a3b to your computer and use it in GitHub Desktop.
Save kenmori/e2f939efc51821006f98186d666b4a3b to your computer and use it in GitHub Desktop.
初めてReactNative for WebでReactNative案件をやってみた感想、順序、理解したこと等

初めてReactNative for Webで実装してみて

更新日時: 2018/7/25

ReactNative-for-web

対象

  • Reactは知っている
  • ReactNative(以下RN)を触ったことがなく、ReactNative for Web(以下RNW)で実装したい

この記事の概要

RN、RNWを「初めて」実装するにあたり、

必要な知識と、解決方法を記している

CreateReactApp(以下CRA)から作るかCreateReactNativeApp(以下CRNA)から作るのか私感と、

実装していて思ったことをつらつらと書いている

Index

  • 0.前提
  • 1.フォルダ構成
  • 2.RNW
  • 3.RNWを実装するにあたりCRNAとCRA、どちらで作ったほうがいいか
  • 4.実装を始める前に
  • 5.WebとNativeでの分岐方法
  • 6.開発方法の違い
  • 7.使えるコンポーネント
  • 8.Android開発
  • 9.デバッグ
  • 10.困ったこと解決したこと
  • 11.その他
  • 参照記事
  • 謝辞
  • author

0. 前提

node 8.11.1 npm 5.6
yarn install
json-server db.json
yarn ios or yarn web

expoがインストールされていること
実機確認
- AppStore でExpo Client or expoと検索。ダウンロード

0-1 RN周辺の登場人物

0-1-1 Expo

JavaScriptでnativeをビルドできるライブラリとサービスのセットツール

0-1-2 ExpoSDK

ExpoSDKは参照を提供する。コンポーネントのようなイメージ。

カメラやソーシャルログインなどの機能的なシステムへ参照。

SDKはexpo(npm package)によって提供され、

npm install --save expoでインストールされる

import {Contacts} from 'expo'
or
import Expo form 'expo'`

ExpoSDKモジュールをインポートできる

ローカルデベロップツール。プロジェクトをこちらから作ったり、ビルドやパブリッシュするために使う。

XDEでもプロジェクトを作るとreact、react-native、expoをインストールする。

0-1-4 expo

XDEの代替ができるコマンドラインcli。

いくつかのExpoの機能はこれを使うことを必須としている。

0-1-5 ExpoClient

開発したアプリをデバイス上でopenするツール。

シュミレータとエミュレータにはインストールしないでいい。

XDEかexpoでプロジェクトをサーブするとExpoClientでプレビューできるURLを生成する。

AndroidではExpoClientはexpo.io上の他のprojectも描画できたりする

ExppoClientはデバイス上、シュミレータ、エミュレータ上で動く。

CRNAはプロジェクトに設定されたExpoClientによってサポートされたRNの最新バージョンをサポートする

ExpoClientはRNがバージョンアップされた1週間後ぐらいにそのバージョンをサポートする

0-1-6 Genymotion

Andoriodエミュレータ。

仮想デバイスを作り出す。ドキュメントではNuxus5、バージョンは任意がオススメとされている。

オラクルvirtualBoxを利用していて、もしまだインストールしていなければ使う際にインストールする必要がある

1.フォルダ構成

今回の実装

1-1 camera-with-native

  • 以下の1-2を元にカメラロールで写真選択、サムネ表示、POST処理を実装したプロジェクト

1-2 hybrid-app-native

  • CRNAから作られた基盤(react-router,redux,redux-saga等)だけの雛形

1-3 hybrid-app

  • CRAから作られた基盤(react-router,redux,redux-saga等)だけの雛形

Web対応する際は設定が必要

  • package.json内

  • jest-expo

  • react-native-scripts(Webからnativeのコードを実行するためのmodule)

  • mainの記述変更(mainはnativeのentryポイントを渡す)

  • react-nativeを動かすためのpackage(互換性のあるバージョンで指定している。バージョンをあげる際は慎重に) ・expo@^25.0.0(app.jsonに記載) react-native@0.52.0 react-native-web バージョンを合わせる必要がある

  • .watchmanconfigを追加 コードからシュミレータへの即時反映を提供している

  • app.jsonを追加(app.jsonは、コードに属していないアプリケーションの部分を設定するためのもの。)

  • src内

  • プロジェクト直下にApp.test.jsを追加(RNのエントリーポイントテスト。名前は変えないこと)

//package.json内でmainに渡しているファイル内
//react-native-scripts/src/bin/crna-entry.js

import Expo from 'expo';
import App from '../../../../App';
import React, { Component } from 'react';
import { View } from 'react-native';

if (process.env.NODE_ENV === 'development') {
  Expo.KeepAwake.activate();
}
Expo.registerRootComponent(App);//Expoに対してmainコンポーネントを設定している

Expoに対してAppをroot登録している(native側のエントリーポイントの名前を変えない理由)

2.RNW

RNのコンポーネントとAPIをReactDOMを使ってWeb上で利用できるようにしたもの

  • 書いたコンポーネントはプラットフォームを選ばない
  • ベンダープレフィクスのサポート
  • touch,mouse,keyboradなどのインプットモードをサポート
  • ReactDevToolsによる開発
  • RTL(Right-to-Left)アラビア系言語のサポート

使えるComponentとAPI

サポートしているブラウザ

Chrome, Firefox, Edge, Safari 7+, IE 10+.

hoge.web.js内でRNが提供しているものを使う場合

RNWが提供しているコンポーネントしか使えない。

つまりRN <- RNW <- 共通のところでjsで使えるもしくはweb.jsで使える。

多くはView、Textになると思う。

ViewやTextはブラウザ描画でdevやspanに置き換わる

共通のコンポーネント内でもPlatformで分岐すればいいので、あまりこだわらないでいい

それよりはexpoのコンポーネントがどこまで実装したい機能として使えるのか、

ネイティブの機能がどこまで使えるのかを知ることの方が

大事な印象。

なぜならそれによってネイティブエンジニアのアサインが必要になるかもしれないし

Webは別機能で、別ライブラリで近いことを実装しましょうで解決できる気がするから。(今回のカメラロールとドロップファイルのように)

開発するにあたっての学習コストの使い方は

Native開発の知識 > RNの知識 > RNWの知識

という順番な印象

特定のタグにしたい場合

<View accessibilityRole="article" /> => <article role="article" />
<Text accessibilityRole="link" /> => <a role="link" />

と書く必要がある

共通化しているところ(containerなど)では下記のことが注意する必要がある。

  • div、pなどは使えない
  • Text > Link はエラー。 Link > Text
  • ul > li は FlatListのdata、renderItem(propsにmap)で表現する
Link
//work web, but don't work Native
<Link>Hoge</Link>

//ok
<Link><Text>Hoge</Text></Link>
text

//error 「text cannot be used outside of a <Text>...
<View>
  {count}
</View>

//ok
<View>
  <Text>
     {count}
  </Text>
</View>
  • RNでhtmlタグを記述する場合createElementを使ってtagを作ることができる

感想

  • 共通化しなければRNWはそんなに気にしなくていい。 web.js内で分けて記述すればいい。
  • こっちではエラー、こっちでは表示されているみたいなことが多い→RNのコンポーネントがwebに対応しているか、

Webの記述をnative記述に置き換える修正ul -> FlatList など

2-0

styleはRNで定義されている

View Style

例えば

  <Button
  style={styles.buttonColor}
  />

const styles = StyleSheet.create({
  buttonColor: {
    backgroundColor: "red",
    color: "#fff"
  }
});

これは効かない Buttonに渡せるpropsを確認する

Color of the text (iOS), or background color of the button (Android)

なので

colorはiosだとtextに、androidだとbackgroundにスタイルされる

<Button
color="#2196f3"
/>

とする必要があるし 何かRNのコンポーネントでスタイルしたい場合、 Viewでラップしてスタイルする 例えば、

<View style={style.some}>
<Button
color="#2196f3"
/>
</View>

2-1

RNWはCRAとCRNAでデフォルトで対応されている

CRNAのhybrid-app-nativeではwebpack.config.jsL1120にある'react-native': 'react-native-web'

nativeの処理をwebに渡している(react-nativeのコンポーネントをimportすればract-native-webのそれをimportしたことになる)

CRAでは同じことをnode_modules/react-scripts/のconfig。webpack.config内でやっている

実装ではあまり設定を気にすることはない

3.RNWを実装するにあたりCRNAとCRA、どちらで作ったほうがいいか

CRNA。 CRAより設定の手間がない。

4.実装を始める前に

どのような機能を持ったWebAppを作りたいかが重要

ネイティブコードをいじる可能性があるならexpoに頼らずxcode、AndroidStudioで作ることになるので

用意が変わってくる

RNWは前述のようにRNのコンポーネントを使えたら使えるようにするだけなので

どちらかというとRNでの開発経験やネイティブの知識が重要になってくることがわかる

5.WebとNativeでの分岐方法

分岐の方法は2種類で

・ファイル拡張子を変える

・コード上で分岐する がある

Moduleを共通化したい場合

react-native-web/#compatibility-with-react-native

を参照して、どのModuleが共通化できるか確認する必要がある

CameraRollの場合RNWとRNで互換性はないので共通化できないので分岐する必要があることがわかる

分岐の方法は以下。

5-1.ファイル拡張子で分岐

hybrid-app-native/src/common/Routing.native.js

Routing.web.js

のように

拡張子をnativeとwebで分けることによって

プラットフォームがそれぞれ実行時に適切なファイルを見る そのwebpackが解決している箇所は下記

webpack.config.js extensions: ['.web.js', '.js']

注意点は、

exportする際のオブジェクト名を同じにしてimport時に同じ名前を呼び出すこと

例えば共通のものを親Componentで呼ぶ際には

import { Timer, Clock } from '../common/Timer'

とimportして

Timer.web.js

Timer.native.js

内で同じ名前Timerexportすること

今回react-router-nativereact-router-domがそれをしている

5-2.コード上で分岐

Platformを使う

import { Platform, View, Text, StyleSheet, Button } from "react-native";
<Text>{Platform.OS === "web" && "web is here"}</Text>
<Text>{Platform.OS === "ios" && "ios is here"}</Text>

RNのカメラはimage-pickerのライブラリがあるが、 それはexpo配下では使えないため(nativeコードをいじる必要がある) expoが提供しているAPIを使うことになる

6.開発方法の違い

ざっくり3つの道がある。

CRNAにはexpoがデフォルトで入っている。 expoはRNで使われている開発やビルドを助けるツール。

expoに乗っ取って作るかexpoをejectするかでその先の開発でできることが変わる

6-1.expoで作る

  • expoを通してクラウド上でビルドできる
  • すぐにデプロイできる
  • ホットリロードで開発できる。
  • ExpoプロジェクトはiosやAndroidフォルダがなく 100%JavaScript。これは自分自身でビルドすることはできないことを 意味している
  • Expoのオープンソースコンポーネントが使える
  • ExpoAppはhostアプリケーションの中で実行され、 app storeから独立して更新をpushできる 新しいビルドを行うことなくコードを公開することを意味する
  • AppleDeveloperAccount($99/year)なしにテストできる

6-2.expoをejectしてNaitive(ejecting)で作る

react-native initで作られるprojectのことと同じ方法になる

  • iOSとAndroidのプロジェクトをフォルダに含む
  • XcodeやAndroidStudioでビルドできる
  • JavaScriptでかけるがカスタムする際はnativeCodeをいじる
  • 利用可能な多くのコンポーネントを使用できる

eject後も、Expokitというライブラリで必要なcomponentを使うことができ、

全てnativeComponentに置き換えることはしないでもいいし完全にnativeに行くこともできる

6-3. 最初からRN init で作り、for Webにも対応させる

Sharing Code between React Web and Native Apps

npm install -g react-native-cli
react-native init [AppName]

後、トップレベルにweb階層を作る。

create-react-native iniitをした後expoをejectして作った方が楽そう

expoはどのように実行しているのか

RNはJSで実行しているコンパイル済みのアプリ。

RNプロジェクトをbuildし、実行すると、PakagerがMetroという名前で起動する。

packagerは下のことをする

  • 1.全てのJSコードを一つのファイルに結合し、デバイスが解析できないJSXや新しいJS構文を変換する
  • 2.Imageコンポーネントによって描画できるようにassetsをオブジェクトに変換する

Expoを使わない場合

react-native start

Expoを通すと

exp start

これらはpakagerを立ち上げている 違いは exp startはExpo Development Serverというものを呼び出す。 このサーバーはRNのpackager(Metro)によって作られたJavaScriptバンドルを取得し、 Expo appのsimulator上で実行するプロセスを実行します。

expoで作るAppをpublishする

ユーザーはexpoをダウンロードして 、その中で作られたアプリを実行する 提供されて作ったアプリのurlを介して

exp publish

7.使えるコンポーネントの選び方

実装している最中にこの機能が使いたいと思い、

それはRNWでできるのかexpoのコンポーネントなのか、RNから引っ張ってくるのか選択するケースがある

その場合注意しなくてはいけないのが、

react-native-linkのこと。

7-1.react-native-link

react-native-link

ReactNativeライブラリで使いたいライブラリがnativeコードに依存しているものもあるので

それを使いたい場合linkコマンドを打つ必要がある。

その場合expoをejectしなければならない。

具体的にいうと RNで使える全てのライブラリは

ここ

にあるが、

いくつかのライブラリは純粋なJavaScriptだがいくつかのライブラリはネイティブコードに依存している。

そのライブラリを使う場合、

react-native link [packagename]

を打ち、

アプリケーションにインストールする必要がある

参照:"react-native link" は何をするか

(linkコマンドはnativeプロジェクトの中にインストールされたnode packageをinstallするコマンド。それはNativeProjectでのみ起こすことができる)

例としてある人は、

AppleMapかGoogleMapをiOS上で使えるreact-native-mapsを使いたかったが

linkコマンドを実行しなくてはいけなかった。

この場合ejectする必要がある

機能を追加する際はその仕様がExpoだけでいけるのかnativeもいじることになるのかを

先に調べて実装する必要がある

8.Android開発

AndroidSDKとgenymotionを使って開発する or 実機にexpoをインストールして開発する

8-1 AndroidSDKとgenymotionを使って開発する

AndroidStudio から AndroidStudioをダウンロード

AndroidStudio -> Configure -> SDKmanager

でAndroid Locationのパスを確認 多くの場合下記

/Users/{username}/Library/Android/sdk

使っているshellにそのパスを通す 自分の場合.zshrcに以下を追加

export PATH="$PATH:/Users/moritakenji/Library/Android/sdk/platform-tools"

更新

source ~/.zshrc

adb(AndroidDebugBridge)をターミナル上で確認

adb

次に genymotion(Androidエミュレータ)をdownload、連携させる

こちらはからダウンロード genymotion

genymotionにAndroidStudioToolsの先ほどのパスを認識させる

genymotion > setting > ADB

adb-serverのバージョンとSDKのバージョンが合っていないとエラーになるので注意

8-2 実機にexpoをインストールして開発する

googlePlayからexpoをダウンロード yarn androidでexpoのQRコードスキャンで確認する。

9.デバッグ

9-1 react-devtoolsを使う

react-devtools

npm install -g react-devtools

run

react-devtools

もしWaiting for React to connectが出てきたら

ここをコピペして

index.htmlにぺ

sumilator上でcmd + d, reload bundle

出てきます

9-2 simulatorが立ち上がった状態でchrome devtoolsと併せてデバッグする

simulatoreが立ち上がっている状態で

Cmd + D

Debug Remote JS

開発ツールを立ち上げて 該当のソースを参照する

10.困ったことと解決したこと

10-0 コードを変更したのにsimulatorのexpo上でhot-reloadされない

cmd + d でReload JS Bundle

その画面上部のRefreshを押下

10-1 Invariant Violation: View config not found for name input

どちらのプラットフォームにも気を使いながら開発する WebとRN同時に開発していると コードを変更した際に当然Webとnativeプラットフォームも更新されます。

例えばWebでinputタグを使っていても

RN側では静かにエラーになっています

Invariant Violation: View config not found for name input

この場合、View configの中にinputという名前のものはないよといわれています。 また

This error is located at:
in input (at Photo.js: 10)

とあるのでそこで互換性のない記述がされているかもしれません

今回の場合 inputがtype属性がtextならTextInputをreact-nativeから呼んで使うことで解決します

10-2 Remote debugger is in a background tag which may...

デバッガーを立ち上げた際にでる

Remote debugger is in a background tag which may cause apps to perform slowly.
Fix this by foregrounding the tab

いくつかのlocalhostを開いているタブを閉じてください`

10-3 Runtime is not ready for debugging. Make sure Packager server is running

Reload JSを押下 or yarn ios(serverをたちあげる)

10-4 Uncaugt RefferenceError: regeneratorRuntime is not defined

node -v
v6.10.2

だと出るエラーnvm use --ltsで最新のnodeを使ってください

10-5 App could not be found

Unable to resolve ../../../../App" from ".//node_modules/react-native-scripts/build/bin/crna-entry.js`: The module `../../../../App` could not be found"

立ち上がっているsimulator上でcmd + d, Reload JS Bundleしてみる

10-6 There was a problem loading the requested app.

simuratorを立ち上げる前にyarn iosするとでる(これは期待しない)

terminalでもエラーになっている

Failed to start simulator:
Error: Process exited with non-zero code: 60
Exiting...

もう一度yarn ios すればとりあえず治る

10-7 実機expoが同期してくれない

PCのIPアドレスと実機のIPアドレスの相違を疑う

https://qiita.com/noraworld/items/264d944f3ac8074e454d

10-8 console.error: "uncaugt at check, "call: argument fn is undefined"

yield call(post, formData)//call内のpostが適切か確認

10-9 adb server version (39) doesn't match this client (40); killing...

AndroidSDKとadbのバージョンが合っていない

10-10 Error running adb: No Android device found. Please connect a device and follow the instructions here to enable USB debugging:

もしGenymotionを使っている場合、 SDKへのパスをGenymotionのABDへ渡すか、実機で検証する

10-11 もしsimulatorの動作が遅かったら

debug -> Slow Animationsのチェックを外す

11.その他

11-1 コマンド一発で雛形web,nativeを作ってくれるツールはないのか

create-react-native-web-app

11-2 htmlを文字列として書いてViewするライブラリ

react-native-htmlview

RNがどのようにコンポーネントをレンダリングするか

抽象的なレイヤーである「Bridge」を使ってnative widgetsとしてレンダリングする

Bridgeとは・・・ホストプラットホーム上のレンダリングAPIによって実行される

RNはメインスレッドをブロックすることなく、

プラットホームのJSエンジンを使用して、

別スレッドでアプリケーションを実行するレイヤー

[参照](https://www.logicroom.co/react-native-architecture-explained/)

11-3 expoをFirebase上におく

expoで認証機能を作るとなるときついことがあるらしい。FireBaseなら簡単らしい

参照

11-4 実装が難しくなったらアプリ上からWebBrowserを開かせるAPI

WebBrowser

11-5 expoでこんなことできるよのまとめ

awesome-expo

11-6 ReactNativeでできること

【React Native】良さげなコンポーネント紹介

参照記事

謝辞

これを公開するにあたり株式会社 m-Labさんに御礼申し上げます

author

Twitter

github

ブログ

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment