React Native for WebでReact Nativeのコンポーネントライブラリを動かしてみる

React Native for Web (RN Web)を使うと、React Native (RN)のコンポーネントをiOS/Android用だけでなくWeb用にも使い回せるようになります。

ですが実際のところ、巷にあるRN用のコンポーネントライブラリがRN Webでもすんなり動かせるものなのか、試してみました。

# [react-native-calendars](https://github.com/wix/react-native-calendars)

カレンダーのコンポーネントです。
カレンダーって、構成要素としては文字が並んだりしているだけですから、多分動くだろうと思って試してみました。
下記の様に`Calendar`というコンポーネントにPropsを渡して使います。

```jsx
<Calendar
  style={{
    borderWidth: 1,
  }}
  monthFormat={'yyyy MM'}
  onDayPress={({year, month, day}) => {console.log(`${year}年 ${month}月 ${day}日がクリックされた。`)}}
  onMonthChange={({year, month}) => {console.log(`${year}年 ${month}月に移動した。`)}}

  // 特定の日付に印をつけてみる。
  markedDates={{
    '2018-06-05': {selected: true},
    '2018-06-06': {marked: true},
  }}
/>
```

また、react-native-calendarsのコードをbabelに通すために、webpack.config.jsに以下の様に追記します。

```js:webpack.config.jsの抜粋
const babelLoaderConfiguration = {
  test: /\.js$/,
  include: [
    path.resolve(appDirectory, 'index.web.js'),
    path.resolve(appDirectory, 'src'),
    path.resolve(appDirectory, 'node_modules/react-native-uncompiled'),
    path.resolve(appDirectory, 'node_modules/react-native-calendars'), // この行を追記する。
  ],
  （以下略）
```

すると・・・

![image.png](https://qiita-image-store.s3.amazonaws.com/0/188748/00f4e6b7-655c-7bb8-2032-2006839bc8a0.png)

結構いい感じに動きました。が、月を移動する矢印の画像が表示されず、そこは残念。
ですがその部分をカスタマイズできるPropsが定義されているので、そこだけ自作可能です。
例はこちら。

```jsx
// renderArrowを指定すると、月を移動するボタンとして自前のコンポーネントを指定できる。
// 引数directionは、'left'または'right'。
// この例では、Textで '<' と '>' を表示させた。
renderArrow={(direction) => (<Text>{direction === 'left' ? '<' : '>'}</Text>)}
```

これで、無事に月移動の矢印が表示できました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/188748/1aad4f8d-bec8-2b9f-fd74-3cc63d1225b5.png)

# [react-native-gifted-chat](https://github.com/FaridSafi/react-native-gifted-chat)

続いてはチャット画面（Lineみたいなアレ）のコンポーネントです。
シンプルなカレンダーと比べると複雑そうで、そうそううまく動かないだろうという雰囲気が漂ってきます。
以下の様な感じでコンポーネントを書きます。

```jsx
<GiftedChat
  messages={[
    // ここに発言の配列
  ]}
  onSend={(message) => /* ここで発言時の処理をする。 */}
  user={{
    _id: 1,
  }}
  inverted={false}
/>
```

また、カレンダーの時と同様に、webpack.config.jsにbabel-loaderの設定を地道に追記していきます。
が、実際に動かしてみたら以下の様なエラーがブラウザのコンソールに・・・。

```
./node_modules/@expo/react-native-action-sheet/ActionSheetProvider.js
Module not found: Error: Can't resolve './ActionSheet' in ...
（以下略）
```

node_modulesの中身を見たところ、ActionSheetというコンポーネントがActionSheet.android.jsとActionSheet.ios.jsに分けて書かれていたことが原因でした。
RN Webの場合、androidでもiosでもなくwebになりますから、ActionSheet.jsまたはActionSheet.web.jsが存在しないと、ActionSheetをimportしている箇所でエラーが発生してしまうようです。

どうしても動かしたければプルリクを送ったりするしかないんだろうなと思っていたところ、webpack.config.jsに以下の様に設定を追加するとゴリ押し可能だというアドバイスをもらいました（[Lekoさん](https://qiita.com/L_e_k_o)に感謝）。

```js:webpack.config.jsの抜粋
resolve: {
  alias: {
    'react-native': 'react-native-web'
  },
  extensions: [
    '.android.js', // この行を追加する！ RN Webだけど .android.js のファイルをimportできるようにしちゃう。この例ではandroidとしたが、iosでも良いかも。
    '.web.js',
    '.js',
  ],
},
```

すると・・・

<img width="405" alt="スクリーンショット 2018-06-22 23.18.06.png" src="https://qiita-image-store.s3.amazonaws.com/0/188748/de879fc2-0c45-38fe-4c2f-d0e4e38c65d7.png">

おー、一応動きました。
ただ実用に耐えるレベルかどうかまではちょっと分からず。今回はとりあえず静的なものを表示するところまでできたという段階です。

# まとめ

2つだけの事例ですが、想像していたよりはRN Webでも動くことが確認できました。
今回はとりあえず表示できたというレベルの確認ですので、実用に耐えるかどうかまでは調べられていないものの、こんなこともできるんだなという可能性を垣間見ることができました。