Firebase Realtime DatabaseをReactで使ってみる〜読み込み編〜

はじめに

Firebase Realtime DatabaseをReact使ってみた今日このごろ。
備忘録も兼ねて使い方をまとめておく。

まとめていたら思ったより長くなったので、今回は読み込みまでやる。

今回はReact(クライアント側)の設定だけで、Firebaseのプロジェクトの設定などは割愛する。
※一応やったことはWebUIポチポチしただけ。

TL;DR.

コード

Reactプロジェクト作成

create-react-appからスタートする。
サクッと用意。

$ npx create-react-app realtime-db-react --template typescript

Firebase周りの設定

プロジェクトの準備

FirebaseCLIを使って設定を進める。
設定は公式のリファレンス を見ながら行う。
また、プロジェクトは作ってある前提とする。

# ログインしていなければログインする
$ npx firebase login

# Firebaseプロジェクト初期化
$ npx firebase init
# 設定した内容は下記の通り
>? Which Firebase CLI features do you want to set up for this folder? Press Space to select features, then Enter to confirm your choices. 
❯◉ Database: Deploy Firebase Realtime Database Rules

? Please select an option: 
❯ Use an existing project

? Select a default Firebase project for this directory: 
❯ 作成しておいたプロジェクト

# デフォルトのまま
? What file should be used for Database Rules? database.rules.json

✔  Firebase initialization complete!

DBのルール変更

上記手順で作ったままではDBに読み書きできないようになっているので少し修正する。
生成されているdatabase.rules.jsonを下記のように修正。

{
  "rules": {
    // 読むのは誰でも可能
    ".read": true,
    // 書くのは認証済みの場合のみ
    ".write": "auth != null"
  }
}

ルール反映

json変えたではもちろん反映されないので、firebase deployコマンドを叩いて反映する。
反映できているかどうかは下記手順で確認できる。
表示されるURLからコンソールを表示
→左カラムにあるDatabaseを選択
→メインカラム上部のプルダウンからRealtime Databaseを選択
→ルールタブを表示

$ npx firebase deploy
# ↓が表示されればOK
✔  Deploy complete!
Project Console: https://console.firebase.google.com/project/hogehoge/overview

テスト用データ追加

確認用にWebUIからデータ追加しておく。
追加したのは↓の感じ。

{
  "sample": {
    "key1": "value1",
    "key2": "value2"
  }
}

実装

Firebase SDKとFirebase Admin SDKのインストール

アプリからFirebaseを使うために必要なライブラリをインストールする。
adminの方は認証がいる場合に必要なのでどちらも入れておく。

$ yarn add firebase firebase-admin

初期化周り

初期化に必要な情報をWebUIから取ってくる。
プロジェクトのページ左カラムにある歯車をクリック
→プロジェクトの設定をクリック
→Settingsページ、全般タブ下側にあるマイアプリにある</>マークをクリック
→ウェブアプリにFirebaseを追加のページに飛ぶので、お好みの名前を入れて登録をクリック(hostingはお好みで。今回はやらない)
→スクリプトが表示されるので、firebaseConfigの内容だけコピーする

必要な情報を取れたのでコードを書いていく。
初期化はこれでOK

import firebase from 'firebase/app';
// 認証周りやDB周りで必要なためimportしておく
import 'firebase/auth';
import 'firebase/database';

// コピーしてきたfirebaseConfigそのまま
// 元がvarで宣言されているので、constに変更
const firebaseConfig = {
  // コピペ
};

firebase.initializeApp(firebaseConfig);
export { firebase };

データベースに接続する

データのやり取りはfirebase.database.Referenceを通してやり取りされる。
今回は決まったパスのデータを取得したいので、パスを指定した上でメモ化しておく。

// カスタムフックにしておく
const useDatabase = () => {
  // 同じパスでは毎回同じ結果が得られるのでmemo化しておく
  return useMemo(() => firebase.database().ref('/sample'), []);
};

データを取得する

↑で作ったReferenceを受け取る関数を作成する。
Referenceのイベントをlistenすることでデータを取得できる。
指定したパスのデータに対する更新をすべて検知するにはvalueを指定すれば良い。

// hooksを使いたいのでカスタムhooksにしておく
const useFetchData = (ref: firebase.database.Reference) => {
  const [data, setData] = useState<{[key: string]: string}>();
  useEffect(() => {
    // イベントリスナーを追加するにはonを使う
    ref.on('value', snapshot => {
      // パスに対する全データを含むsnapshotが渡される
      // ない場合はnullが変えるので存在をチェックしておく
      if (snapshot?.val()) {
        setData(snapshot.val());
      }
    });
    return () => {
      ref.off();
    };
    // refの変更に応じて再取得する
  }, [ref]);
  // データを返却する
  return { data };
}

// 実際に呼び出す際はこちらを使う
export const useFetchAllData = () => {
  // refを取得して
  const ref = useDatabase();
  // ref渡してデータを取得する
  return useFetchData(ref);
};

Componentからデータ取得する

useFetchAllDataを使ってデータを取ってくるコンポーネントを作成する。
取得したデータはobject形式なので、list形式に変換してから表示する。

import React, { useMemo } from 'react';
import { useFetchAllData } from '../firebase/firebaseDB';

export const ListComponent: React.FC = () => {
  // dataを取ってくる
  const { data } = useFetchAllData();
  // object形式なので使いやすいように{key, value}形式のリストに変換する
  // また、データが変わらない限り結果は同じなのでメモ化しておく
  const dataList = useMemo(() => Object.entries(data || {}).map(([key, value]) => ({ key, value })), [data]);

  return <dl>{dataList.map(({ key, value }) =>
    <React.Fragment key={`${key}${value}`}>
      <dt>key: {key}</dt>
      <dt>value: {value}</dt>
    </React.Fragment>
  )}</dl>
};

起動した際に画像のようにデータを表示できればOK。 ss20200626

まとめ

今回はReactでFirebase Realtime Databaseを使ってデータの読み込みができるところまでやった。
最初にも書いたけど思ったより長くなったので今回はここまでにしておく。

参考サイト