volpe’s diary

フリーランスじゃなくなったプログラマ volpe が日々便利だなぁと感じたことを中心に綴るブログです

Nuxt.js + Firebase で vuexfire を使って Cloud Firestore と連携する(データバインド編)

vuexfire を使ってデータ連携する方法。とりあえずデータバインドの設定まで。

前提

  • vuexfire 3.0.0-alpha.15
    • ※ alpha.14 から I/Fが変わっているので注意。まだまだ変わるかも。。

連携方法

基本的には こちら に書いてある方法の通りで動くはず。

ただ、今回は store をファイル単位でモジュール分割してみたので、その構成の実装方法を記す。

ファイル構成

Cloud Firestore 関連の処理は store の action に集約する構成とした。

store
├── index.js
└── projects.js

データバインド

index.js には vuexfire の vuexfireMutations を定義するのみ。

store/index.js

import { vuexfireMutations } from 'vuexfire'

export const mutations = {
  ...vuexfireMutations
}

次に projects のデータバインドを行うメソッド initStore を定義する。 名前はかなり迷ったが、呼び出し元から Cloud Firestore の機能を使っているのを意識した名前で呼びたく無いので bind は使わなかった。(この辺はまだまだ悩み中)

vuexfire の firestoreAction でコールバックの bindFirestoreRef() にバインドしたいデータの名前と collection への参照を渡すと state.projects に Cloud Firestore のデータがバインドされる。これ以降は Cloud Firestore の I/F を使ってデータの変更を行うと自動的に state.projects に反映される。

さらに同じデータを参照している全てのクライアントに変更通知が自動的に行われるため、socket.io を用いた broadcast と同じようなリアルタイム更新の挙動が実現できる。これは凄い。

projects はユーザに紐づいたデータのみ読み込みたいので payload に userId を渡して、 where 句で絞り込んだデータをバインドするようにした。

store/projects.js

import { firestoreAction } from 'vuexfire'
import firebase from '@/plugins/firebase'

const db = firebase.firestore()
const projects = db.collection('projects')

export const state = () => ({
  projects: []
})

export const actions = {
  initStore: firestoreAction(({ bindFirestoreRef }, payload) => {
    bindFirestoreRef('projects', projects.where('userId', '==', payload.userId))
  })
}

bindFirestoreRef の第2引数には collection の ref を渡すが、うっかり絞り込まずに projects をそのまま渡してしまうと別のユーザのデータも含めて全データをバインドしてしまうので注意が必要。

  • 良くない例) bindFirestoreRef('projects', projects)

さらに、セキュリティ的には Cloud Firetore の ルール でごにょごにょしないといけない気がするが、まだよく分かっていないので今後の課題とする。

上記で定義した initStore の呼び出しは、projects データを使用する page または component の creeate あたりで行う。

page/projects/index.vue

const user = firebase.auth().currentUser

        :

this.$store.dispatch('projects/initStore', {
  userId: this.user.uid  // store で uid で絞るために渡してあげる
})

バインドに関してはこのくらいの実装でサーバサイドの実装なしにリアルタイムな自動更新が実現できるのには驚いた。要件によってはリアルタイム系の SPA は socket.io を要らずで済みそうな予感がする。

長くなってきたので、データの参照・更新については別記事にする。