React NativeでFirebaseのRealtime Databaseを使う -その2-

# やりたいこと
React Nativeで実装したアプリでFirebaseのRealtime Databaseを使ってアプリデータの保存と同期をリアルタイムで行いたい。
今回はAndroidアプリについて実装します。
この記事は[その1](https://qiita.com/shioiyan/items/d8aa921f2736269382f1)の続きになっています。
その2では実際にアプリからRealtime Databaseにデータ保存と取得を行います。

# [react-native-firebase](https://github.com/invertase/react-native-firebase)の導入
Firebase SDKをReact Nativeで扱うためにreact-native-firebaseをインストールします。
このライブラリはドキュメントが充実しているので、つまづいた場合は読めばだいたい解決できます。
https://rnfirebase.io/

```
$ npm install --save react-native-firebase
$ react-native link react-native-firebase
```

# (native-baseの導入)
見た目をちょっと整えたいのでUIライブラリのnative-baseをインストールします。

```
$ npm install native-base --save
$ react-native link native-base
```

# 今回実装するもの
1. 入力フォームに入力されている値がRealtime Databaseの値と同期している
2. 入力フォームの値を書き換えて、更新ボタンを押すと、Realtime Databaseの値が更新される

というシンプルなアプリを実装します。

# コード
```App.js
import React, {Component} from 'react';
import {Container, Content, Form, Item, Input, Button, Text} from 'native-base';
import Firebase from 'react-native-firebase';

type Props = {};
export default class App extends Component<Props> {
    constructor() {
        super();
        this.state = {
            text: ''
        };
        // データベースのインスタンスを作成
        this.db = Firebase.database();
    }

    componentDidMount() {
        this.onValueChanged();
    }

    componentWillUnmount() {
        this.offValueChanged();
    }

    // messages以下のデータの変更の監視を開始
    onValueChanged() {
        this.db
            .ref(`messages`)
            .on("value", snapshot => {
                this.setState(
                    snapshot.val()
                );
            }).bind(this);
    }

    // textの変更をRealtime Databaseに送信
    updateText() {
        setTimeout(() => {
            this.db
                .ref(`messages`)
                .set({
                    text: this.state.text
                })
                .then(() => {
                    console.log("update ok");
                })
                .catch((error) => {
                    console.log(error);
                });
        }, 5000);
    }

    // messages以下のデータの変更のcallbackを削除
    offValueChanged() {
        if (this.db.ref((`messages`))) {
            this.db
                .ref((`messages`))
                .off();
        }
    }

    render() {
        return (
            <Container>
                <Content>
                    <Form>
                        <Item>
                            <Input placeholder="更新するTEXT"
                                   onChangeText={(text) => this.setState({text})}
                                   value={this.state.text}
                            />
                        </Item>
                    </Form>
                    <Button block light onPress={() => this.updateText()}>
                        <Text>REALTIME DATABASE更新</Text>
                    </Button>
                </Content>
            </Container>
        );
    }
}
```

Realtime Databaseを扱っている部分を解説します。
### `ref().on(eventType, callback)`
https://rnfirebase.io/docs/v4.3.x/database/reference/Reference#on
参照先の場所以下のデータの変更を監視します。
ここではmessages以下の値に変更があった場合に、stateに格納をしています。
`eventType`には`value`の他にも`child_added`(子が追加された時にだけ呼ばれる)などいくつかタイプがあります。

```js
    // messages以下のデータの変更の監視を開始
    onValueChanged() {
        this.db
            .ref(`messages`)
            .on("value", snapshot => {
                this.setState(
                    snapshot.val()
                );
            }).bind(this);
    }
```

### `ref().off(eventType, callback)`
https://rnfirebase.io/docs/v4.3.x/database/reference/Reference#off
`ref().on()`でアタッチされたcallbackを全て削除します。（指定したcallbackだけ削除することもできます）

```js
    // messages以下のデータの変更のcallbackを削除
    offValueChanged() {
        if (this.db.ref((`messages`))) {
            this.db
                .ref((`messages`))
                .off();
        }
    }
```

### `ref().set(value, onComplete)`
https://rnfirebase.io/docs/v4.3.x/database/reference/Reference#set
参照先にデータを書き込みます。
全て上書きされるため、うっかり親を書き換えると子が全て消えてしまうということもあるので注意が必要です。
ここでは`REALTIME DATABASE更新`というボタンを押した時に`messages/text`に入力フォームに入力された値を書き込んでいます。

```js
    // textの変更をRealtime Databaseに送信
    updateText() {
        setTimeout(() => {
            this.db
                .ref(`messages`)
                .set({
                    text: this.state.text
                })
                .then(() => {
                    console.log("update ok");
                })
                .catch((error) => {
                    console.log(error);
                });
        }, 5000);
    }
```

# 動作確認
FirebaseのコンソールとAndroidのエミュレータを同時に開いてリアルタイムにデータが同期していることを確認してみます。
![firebase-reactnative.gif](https://qiita-image-store.s3.amazonaws.com/0/217930/a850cf63-03e4-ed46-b586-a547e1f27127.gif)
アプリで更新処理を送るとコンソールの値が書き換わり、コンソールの値を書き換えるとアプリの値も同期して変更されることがわかります。
React Nativeで実装したアプリでFirebaseのRealtime Databaseを使ってアプリデータの保存と同期をリアルタイムで行うことができました。
iOSでも公式ドキュメント通りに導入していけばできると思います。
他にも便利なメソッドが色々実装されているので試してみたいです。