volpe’s diary

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

Nuxt.js + Firebase で vuexfire を使って Cloud Firestore と連携する(データ参照・更新編)

vuexfire を使ってデータ連携する方法。 データ参照や更新については vuexfire はあまり関係なくて vuex の store と firestore の機能をそのまま使うだけ。

読み出し

データの参照としては、vuexfire で Cloud Firestore とデータバインディングすると store とデータが同期されるので基本的には store の getters にメソッドを定義して使用箇所で呼び出す。

store/projects.js

export const getters = {
  // バインドされた全 project データを取得
  projects: state => {
    return state.projects
  },
  // 'order' でソート済みの全 project データを取得
  orderedProjects: state => {
    return _.sortBy(state.projects, 'order')
  },
  // id 指定で project データを取得
  project: state => projectId => {
    return state.projects.filter(project => project.id === projectId)[0]
  }
}

使用方法としては page や component の computed メンバを定義して view とバインドするパターンが多い。

page/projects/index.vue

  computed: {
    projectList: {
      get() {
        return this.$store.getters['projects/orderedProjects']
      }
    }
  },

追加・更新

データの更新・追加は firestore の API を用いる。

以下の例では、 actions に set メソッドを定義して id の有無で更新または追加の Cloud Firestore のI/Fを呼び分ける構成とした。 これだとデータの種類によらず同じパターンで書けるので上手く抽象化できればコードの記述を省略することが出来そう。

ただ、更新時に payload に id を含めていると、Cloud Firestore 上に不要な id カラムが出来てしまうので、事前に削除している。この辺は呼び出し側で更新対象のデータにに id を含めないようにするなどデータの持ち方を工夫すれば解消できそうだが、Cloud Firestore のデータの持ち方の都合は store 層で面倒を見る方が良い気がしているので現状は以下の実装としている。

store/projects.js

set: (state, payload) => {
  if (payload.id) {
    // NOTE: id カラムは firestore 上では不要なので削除する
    delete payload.project.id
    return projects.doc(payload.id).update(payload.project)
  } else {
    return projects.add(payload.project)
  }
},

使用箇所

      const project = {
        id: projectId,
        order: 0,
        userId: user.uid,
        title: 'hoge project'
      }
      this.$store.dispatch('projects/set', {
        id: projectId,
        project: project
      })
  • set は Promise を返すので後処理を行いたい場合は、 .then(() => { ... }) でメソッドチェーンできる。 (async/await にもできそう)

削除

削除も同様に actions に定義した。 削除対象の id をもらって Cloud Firestore の delete() I/Fを呼び出す。

store/projects.js

delete: (state, payload) => {
  return projects.doc(payload.id).delete()
}

使用箇所

      this.$store.dispatch('projects/delete', {
        id: projectId,
      })
  • delete は Promise を返すので後処理を行いたい場合は、 .then(() => { ... }) でメソッドチェーンできる。 (async/await にもできそう)