React Native + Railsでチャットアプリを開発する


# 本記事の目標
- ReactNative+Railsにて簡単なチャットアプリの開発を行います。

# 実行環境
- Rails 5.1.6(APIサーバー)
- Ruby 2.4.1
- node 10.1.0
- react-native 2.0.1(フロントエンド)

# その他環境
- macOS
- Xcode(シミュレータ)
- Android Studio(シミュレーター)

# 1. アプリケーションの作成

- 構成案

```
react-native
├── ChatApp　　　　　　　　　　　　 　　　　　　　//react-native
│   ├──(以下省略)
│   
│   
│   
├── rails-api-server　　//Rails
    ├──(以下省略)
```
あらかじめreact-nativeディレクトリを作成していることを前提にスタートしていきます。

## 1-1. react-nativeの環境構築

公式サイト( http://facebook.github.io/react-native/docs/getting-started.html#content )を参考にreact-nati-cliを導入する。

```
brew install watchman //nodeは元々入れていたためwatchmanのみインストール
npm install -g react-native-cli //インストール後PATHが通っていなかったためパスを通した。
react-native init ChatApp //react-nativeアプリケーションを作成
```

- iOS

```
cd ChatApp
react-native run-ios
```

上記でiOSのシミュレータが公式のスクリーンショットのように起動できていることを確認できたらiOSの設定は以上になります。

- Android

Android Studioをインストールをしていない方はインストール、設定を行います。
(下のコマンドを実行する前にAVDを立ち上げておく必要があります。)

```
cd ChatApp
react-native run-android
```

上記でAndoridのシミュレーターが公式のスクリーンショットのように起動できていることを確認できたらAndoirdの設定は以上になります。

# 2. チャットUIを構築する

今回は自前ではなく既存のパッケージを利用し、チャットUIを構築したいと思います。

以下の記事を参考にさせていただきました。
( https://qiita.com/Yorinton/items/b029df0713a471d4569a )

使用するパッケージは以下の2つです。

- react-native-gifted-chat(チャットUIのパッケージ)
- react-native-router-flux(Router用パッケージ)

```
cd ChatApp
npm install react-native-gifted-chat --save
npm install react-native-router-flux --save
```
上記で準備完了です。

コードですが、以下の構成で作っていきたいと思います。

```
ChatApp　　
├── data
│   ├── message.js //メッセージの取得、チャットメッセージの作成
│
├── src
│   ├── component
│       ├── Chat.js //チャットUIのコンポーネント
│   
│   
├── App.js　　//既存のApp.jsに対してチャットUIコンポーネントを当てはめ開発する
```

コードですが、参考サイトを例にすればおそらくできると思いますのでここでは省略します。


# 3. チャットメッセージのPOST, GET

## 3-1. モデルの作成

チャットメッセージのGETとPOSTについてですが、サーバーからJSONでやり取りを行おうと思います。

2,ではユーザーの認証などなくrootでチャットルームにいるので(ユーザーの認証などはまだ未開発)なのでコメントを保持するだけにします。
以下が今回追加したschemaです。

```scheme.rb
ActiveRecord::Schema.define(version: 20180523061343) do

  create_table "rooms", force: :cascade do |t|
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.text "text" //ここにチャットUIのメッセージにあたる部分です。
  end

end
```

## 3-2. GET

再び、React-Nativeに戻ります。
React-Nativeでは、ajaxが使用できない(?)らしいのでURLからfetchを使用してJSONでやり取りを行おうと思います。


```Chat.js
・・・(略)・・・
componentWillMount() {
    var data = require('../../data/message');//requireしているコードは以下のコードを参照
    var msg = data.get();
    setTimeout(() => {
      this.setState((previousState) => {
        return {
          messages: GiftedChat.prepend(previousState.messages, msg.reverse()),
        };
      });
    }, 1000);
}
・・・(略)・・・
```

```message.js
module.exports = {
  get: function() {
    var data = [];
    fetch('http://localhost:3000/rooms') //今回は練習のため直にURLを入れています。
      .then((response) => response.json())
      .then((responseJson) =>
        responseJson.forEach(function(i) {
          data.push(createData(i.text));
        }),
      ).catch((error) => {
        console.error(error);
    });
    return data;
  },
}

function createData(message) {//以下でチャットメッセージを作成しています。
  return {
      _id: Math.round(Math.random() * 1000000),
      text: message,
      createdAt: new Date(),
      user: {
        _id: 1,
        name: 'Developer',
      },
      sent: true,
      received: true,
    }
}

```

## 3-3. POST

POSTもGET同様fetchでサーバーにJSON形式で送ります。

```Chat.js
・・・(略)・・・
onSend = (messages = []) => { //onSend => submitした時の処理
    fetch('http://localhost:3000/rooms', {
      method: 'POST',
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        messages
      }),
    });

    this.setState((previousState) => ({
      messages: GiftedChat.append(previousState.messages, messages),
    }));
}
・・・(略)・・・
```

# 4.現状

```
rails s(portは3000)
react-native run-ios
```

でシミュレーターを起動するとサーバーにあるjsonがgetされているのがわかると思います。
(ユーザー等の区別等は一切行なっていないのでメッセージが全て右に寄っています。)

シミュレーター
<img src="https://qiita-image-store.s3.amazonaws.com/0/226348/69f7f98c-2939-09e4-86f2-98716801a2bf.png" width="200">

サーバー
<img width="1276" alt="スクリーンショット 2018-05-25 17.42.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/226348/ad138faa-1bb8-e3fa-f819-117f6cbab62c.png">

# 5. 課題
## 5-1. ユーザー認証、メッセージのゆーざー情報の追加が欲しい。
- 3. でも少し触れましたが、ユーザーの情報などほぼ触っていないので、その辺りの設計を考慮して開発しなければいけない。

## 5-2. Andoridシミュレーターでは動かない。
- Andoridシミュレーターで起動しようとするとエラーになってしまう。(fetchできないようなことで怒られる。)

## 5-3.　リアルタイム通信ができていない。
- 現状ではリロードしないとメッセージが更新されない。
- React-Nativeでは、Websocketが使えるようだが、そこまでできなかった。(自分の勉強不足のところも多々あり...)

# 6.　補足
- RailsをAPIサーバーとしてReact-Nativeアプリで開発している記事が見当たらず参考になりそうなものは少ないと思われます。
- React-nativeでの開発に進めるにあたってはReactの事前知識があった方が良いと感じました。事前知識なしで開発に着手するのは危険だと思いました。

まだ開発途中のコードですが、以下のURLでGitHubに公開しています。
https://github.com/t-sato810/react-native
(今後、課題について取り組んでいきたいと思います。)


React-native, WebSocket等でうまくリアルタイム通信を行える方法など色々アドバイス頂けると幸いです。