坂本研のゼミ室

ReactでFirebase(Realtime Database)を使う

はじめに

今回は、FirebaseのデータをReactで取得し表示する方法を書きます
また、選択したIDのデータを表示、データの追加・削除も実装します

使ったもの

  • React
  • Firebase

Firebaseプロジェクトを作成

  • プロジェクト追加を選択(Web App)

f:id:TakaShinoda:20191016221628p:plain

  • プロジェクト名を入力し手順通りに進めていく

f:id:TakaShinoda:20191016222350p:plain

  • 設定情報を取得する

f:id:TakaShinoda:20191016221633p:plain

  • Databaseを選択する(今回はRealtime Database,テストモードを選択)

f:id:TakaShinoda:20191016223148p:plain

データベースを構築する

プロジェクト名:nullという右側の+ボタンをクリックして図のようなデータベースを構築しました
f:id:TakaShinoda:20191017020743p:plain

データを取得して表示する

  • Firebase APIをインストールする
npm install --save firebase
  • index.js (src/index.js)
import React from "react";
import ReactDOM from "react-dom";
import App from "./components/App";

ReactDOM.render(<App />, document.getElementById("root"));
  • App.js (src/components/App.js)
import React, { Component } from "react";
import List from "./List";
import firebase from "firebase";

// Firebaseの設定
//ここに先ほど作成したFirebaseプロジェクトの設定情報をかく
const firebaseConfig = {
  apiKey: "",
  authDomain: "",
  databaseURL: "",
  projectId: "",
  storageBucket: "",
  messagingSenderId: "",
  appId: "",
  measurementId: ""
};

// Firebaseの初期化
firebase.initializeApp(firebaseConfig);

class App extends Component {
  render() {
    return (
      <div>
        <h1>Sample</h1>
        <list />
      </div>
    );
  }
}

export default App;
  • List.js (src/components/List.js)

データベースにアクセスしてデータを取得、表示するコンポーネント

import React, { Component } from "react";
import firebase from "firebase";
import "firebase/storage";

class List extends Component {
  constructor(props) {
    super(props);
    this.state = {
      data: []
    };
    this.getFireData();
  }

  // Firebaseからのデータ取得
  getFireData() {
    let db = firebase.database();
    let ref = db.ref("sample/");
    let self = this;
    ref
      .orderByKey()
      .limitToFirst(10)
      .on("value", snapshot => {
        self.setState({
          data: snapshot.val()
        });
      });
  }

  // データ表示の生成
  getTableData() {
    let result = [];
    if (this.state.data == null || this.state.data.length == 0) {
      return [
        <tr key="0">
          <th>NO DATA</th>
        </tr>
      ];
    }
    for (let i in this.state.data) {
      result.push(
        <tr key={i}>
          <th>{this.state.data[i].ID}</th>
          <td>{this.state.data[i].name}</td>
          <td>{this.state.data[i].message}</td>
        </tr>
      );
    }
    return result;
  }

  render() {
    if (this.state.data.length == 0) {
      this.getFireData();
    }
    return (
      <table>
        <tbody>{this.getTableData()}</tbody>
      </table>
    );
  }
}

export default List;

database取得

let db = firebase.database();

参照オブジェクト、引数は取り出すデータのパス(今回はプロジェクト直下のsample)

let ref = db.ref("sample/");

データの取得処理、この3つのメソッドは連続して呼び出す

ref
 //並べ替えメソッド
 .orderByKey()
 //フィルターメソッド
 .limitToFirst(10)
 .on(.....略.....);

並べ替え、フィルターメソッドは他にもある

並べ替えメソッド  
orderByKey キー(項目名)によって並べ替える
orderByValue 値によって並べ替える
orderByChild 引数に指定した子ノードの値によって並べ替える
フィルターメソッド  
equalTo 引数の値と等しいものを取り出す
limitToFirst 最初から引数で指定した数だけ取り出す
limitToLast 最後から引数で指定した数だけ取り出す
startAt 引数で指定した値のデータから取り出す
endAt 引数で指定した値のデータまでを取り出す

onの処理

.on("value", snapshot => {
  self.setState({
    data: snapshot.val()
  });
});

第1引数 : 処理を割り当てるイベント名
第2引数 : snapshotはイベント時に受け取ったデータなどの情報をまとめたオブジェクト

実行結果
f:id:TakaShinoda:20191017043503p:plain

データを追加する

データのパスを取得して値をセットするコンポーネント
データの最後のIDを調べてその後に新規データをセットする

  • Add.js (src/components/Add.js)
import React, { Component } from "react";
import firebase from "firebase";
import "firebase/storage";

class Add extends Component {
  constructor(props) {
    super(props);
    this.state = {
      name_str: "",
      msg_str: "",
      lastID: -1,
      data: []
    };
    this.getLastID();
    this.doChangeName = this.doChangeName.bind(this);
    this.doChangeMsg = this.doChangeMsg.bind(this);
    this.doAction = this.doAction.bind(this);
  }

  doChangeName(e) {
    this.setState({
      name_str: e.target.value
    });
  }

  doChangeMsg(e) {
    this.setState({
      msg_str: e.target.value
    });
  }

  doAction(e) {
    this.addFireData();
  }

  getLastID() {
    let db = firebase.database();
    let ref = db.ref("sample/");
    let self = this;
    ref
      .orderByKey()
      .limitToLast(1)
      .on("value", snapshot => {
        let res = snapshot.val();
        for (let i in res) {
          self.setState({
            lastID: i
          });
          return;
        }
      });
  }

  addFireData() {
    if (this.state.lastID == -1) {
      return;
    }
    let id = this.state.lastID * 1 + 1;
    let db = firebase.database();
    let ref = db.ref("/sample/" + id);
    ref.set({
      ID: id,
      message: this.state.msg_str,
      name: this.state.name_str
    });
  }

  render() {
    if (this.state.lastID == -1) {
      this.getLastID();
    }
    return (
      <div>
        <input
          type="text"
          placeholder="your name."
          onChange={this.doChangeName}
          value={this.state.name_str}
        />
        <input
          type="text"
          placeholder="type message"
          onChange={this.doChangeMsg}
          value={this.state.msg_str}
        />
        <button onClick={this.doAction}>Add</button>
      </div>
    );
  }
}

export default Add;

データを削除する

削除したい項目のパスを指定してremove()を使って削除する

import React, { Component } from "react";
import firebase from "firebase";
import "firebase/storage";

class Delete extends Component {
  constructor(props) {
    super(props);
    this.state = {
      id_str: ""
    };
    this.doChange = this.doChange.bind(this);
    this.doAction = this.doAction.bind(this);
  }

  doChange(e) {
    this.setState({
      id_str: e.target.value
    });
  }

  doAction(e) {
    this.deleteFireData();
  }

  deleteFireData() {
    let id = this.state.id_str;
    let db = firebase.database();
    let ref = db.ref("sample/" + id);
    ref.remove();
  }

  render() {
    return (
      <div>
        <input
          type="text"
          placeholder="delete ID:"
          onChange={this.doChange}
          value={this.state.id_str}
        />
        <button onClick={this.doAction}>Delete</button>
      </div>
    );
  }
}

export default Delete;