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:文字列 | ||
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
})
}