LoginSignup
15
15

More than 5 years have passed since last update.

VuexでFirestore読み書き

Last updated at Posted at 2019-04-13

Nuxt.jsビギナーズガイドの4章(blog)を参考に、Firestore連携機能付きTODOサービスを作成しました。Firestore機能を実装する人の参考になれば幸いです。
ソースコード

プロジェクト作成

# project作成
# Element UI
$ yarn create nuxt-app nuxt-todo-service

# モジュール追加
$ yarn add moment universal-cookie lodash.clonedeep

Firebase設定

Firebaseのプロジェクトは事前に作成している前提です。
Cloud Firestore with Vue.jsで簡単なメモアプリを実装する - Qiita

$ yarn add firebase firebase-tools

# direnvを使ってAPI Keyなどを外部から設定
$ cat .envrc
export FIREBASE_APIKEY=APIキー
export FIREBASE_AUTHDOMAIN=
export FIREBASE_DATABASEURL=
export FIREBASE_PROJECTID=
export FIREBASE_STORAGEBUCKET=
export FIREBASE_MESSAGINGSENDERID=

# nuxt.conf.jsに追加
$ cat nuxt.conf.js
  env: {
    FIREBASE_APIKEY: process.env.FIREBASE_APIKEY,
    FIREBASE_AUTHDOMAIN: process.env.FIREBASE_AUTHDOMAIN,
    FIREBASE_DATABASEURL: process.env.FIREBASE_DATABASEURL,
    FIREBASE_PROJECTID: process.env.FIREBASE_PROJECTID,
    FIREBASE_STORAGEBUCKET: process.env.FIREBASE_STORAGEBUCKET,
    FIREBASE_MESSAGINGSENDERID: process.env.FIREBASE_MESSAGINGSENDERID
  },
plugin/firebase.js

firebaseはplugin化しておきます。

import firebase from 'firebase/app'
import 'firebase/auth'
import 'firebase/firestore'

if (!firebase.apps.length) { // 初期化が複数回実行されることを防ぐ
  firebase.initializeApp({
    apiKey: process.env.FIREBASE_APIKEY,
    authDomain: process.env.FIREBASE_AUTHDOMAIN,
    databaseURL: process.env.FIREBASE_DATABASEURL,
    projectId: process.env.FIREBASE_PROJECTID,
    storageBucket: process.env.FIREBASE_STORAGEBUCKET,
    messagingSenderId: process.env.FIREBASE_MESSAGINGSENDERID
  })
}

export default firebase

Firestoreデータ構造

TodoはUserのサブコレクションとして作成しました。
UserのドキュメントIDはuid、TodoのドキュメントIDは自動生成としました。
以下の記事が参考になりました。
Cloud Firestoreの勘所 パート2 — データ設計 – google-cloud-jp – Medium

Users(コレクション) User Todos(コレクション) Todo
uid title:文字列
displayName body:文字列
email created_at:文字列

画面一覧

起動画面

Google認証後、TODO一覧画面に遷移します。
FirebaseプロジェクトでGoogle認証を有効にしておく必要があります。
store(index.js)のactionに実装しましたが、画面(vue)でもOKです。

import firebase from '~/plugins/firebase'

const provider = new firebase.auth.GoogleAuthProvider()
firebase.auth().signInWithRedirect(provider)

signInWithRedirectを呼び出すと初回はGoogleの認証画面が表示されます。

画面表示時に、リスナー登録(onAuthStateChanged)しておくと、ユーザー情報を取得することができます。

firebase.auth().getRedirectResult()でも取得できますが、onAuthStateChangedの方が処理が早かったので使いました。

quickstart-js/google-redirect.html at master · firebase/quickstart-js

pages/index.vue

export default {
  async asyncData ({ redirect, store }) {
    firebase.auth().onAuthStateChanged(function(user) {
      if (user) {
        # ユーザー情報をstoreに登録
        const { uid, displayName, email } = user
        store.dispatch ('setUser', { user: { id: uid, name: displayName, email: email }})

        # クッキー登録
        const cookies = new Cookies()
        const cookie = {id: uid, name: displayName, email: email}
        cookies.set('user', JSON.stringify(cookie))
        redirect('/todos')
      }
    })
    return {
    }
  },
  ...
}

store/index.js

export const state = () => ({
  user: null,  // ログインユーザー
  todos: []    // ユーザーが登録したTODO一覧
})

export const mutations = {
  setUser (state, {user}) {
    state.user = user
  },
}
export const actions = {
  setUser({ commit }, { user }) {
    commit ('setUser', { user })
  },
}

TODO一覧画面

ユーザーのTODO一覧をFirestoreから取得します

pages/todos/index.vue

画面表示のタイミングでユーザーのTODO一覧を取得します。

TODO一覧データ(showTodos)を画面の要素(table)にマッピングします。

export default {
  async asyncData({ redirect, store }) {
    const user = store.getters['user']
    store.dispatch('getUserPosts', {user})
  },
  computed: {
    showTodos () {
      if (this.todos.length === 0) {
        return []
      }
      return this.todos.map (todo => {
        todo.created_at = moment(todo.created_at).format('YYYY/MM/DD HH:mm:ss')
        return todo
      })
    },
    ...mapGetters(['user', 'todos'])
  },

store/index.js

  getUserPosts({ commit }, { user }) {
    // TODO初期化
    commit ('initTodos', { })

    // TODO一覧取得
    const db = firebase.firestore()
    db.collection("users").doc(user.id).collection("todos")
      .get().then(function(querySnapshot) {
        querySnapshot.forEach(function(doc) {
          const id = doc.id // documentのIDをTodoデータのIDに設定
          const data = doc.data()
          const { title, body, created_at } = data
          commit ('addTodo', { todo: { id, title, body, created_at } })
      })
    })
  },

TODO作成画面

TODOをFirestoreに登録します。

store/index.js

  publishTodo({ commit }, { payload }) {
    const {userid, title, body} = payload
    const created_at = moment().format()
    const db = firebase.firestore()
    // IDは自動生成
    db.collection("users").doc(userid).collection("todos")
      .add({
        title: title,
        body: body,
        created_at: created_at
      })
  }

リンク

15
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
15