はじめに
数回に分けてNuxt.jsプロジェクトでデータの永続化を行う方法を解説しています。これらの記事は上から順番に読んでいくことを想定しています。
- Nuxt.jsプロジェクトでFirestoreを利用したデータの永続化/取り出しの実装方法
- Nuxt.jsプロジェクトでいろいろな条件を指定してFirestoreからデータを取得する
- Nuxt.jsプロジェクトでFirestoreのデータを変更/削除する
- Nuxt.jsプロジェクトでFirebase Storageに画像ファイルをアップロードする
- Nuxt.jsプロジェクトでFirebase Storageにアップロードした画像を変更/削除する
これらの記事で作成したNuxt.jsプロジェクトは以下のGitHubリポジトリーで公開しています。
GitHub - whitia/nuxt-firebase-sample
前提
Nuxt.jsプロジェクトを作成していない場合は、以下の記事を参考にして作成してください。
Nuxt.jsプロジェクトの作成から動作確認までの手順 - AUTOVICE
Firebaseの登録、プロジェクト作成、アプリ作成については、以下のページを参照してください。
Firebase を JavaScript プロジェクトに追加する
「ステップ 3: Firebase SDK を追加して Firebase を初期化する」の「Firebase 構成オブジェクト」は、plugins/firebase.js
を以下の内容で作成してください。
import firebase from 'firebase'
if (!firebase.apps.length) {
firebase.initializeApp(
{
apiKey: "api-key",
authDomain: "project-id.firebaseapp.com",
databaseURL: "https://project-id.firebaseio.com",
projectId: "project-id",
storageBucket: "project-id.appspot.com",
messagingSenderId: "sender-id",
appID: "app-id",
}
)
}
export default firebase
ここで作成したプラグインはVuex(store/index.js
)でインポートして使います。
import firebase from '~/plugins/firebase'
概念図
データの永続化
データの永続化と難しく言っていますが、要するにデータベースのような領域に保存するということです。
(1) ブラウザからVuexに定義したアクションを呼び出します。このとき永続化したいデータを引数で渡します。
(2) 受け取ったデータをFirebaseのFirestoreに保存します。
データの取り出し
(1) Vuexに定義したアクションからFirestoreにデータを取りに行きます。
(2) Firestoreからデータを受け取ります。
(3) 受け取ったデータをVuexに保存します。
(4) ブラウザからVuexに保存されたデータを取りに行きます。
実装
今回はブラウザからユーザーを作成する処理を実装します。あらかじめFirestoreにusres
というコレクションを作成しておいてください。
データの永続化
処理の流れに沿って順番に実装していきます。UIフレームワークにBootstrap-Vueを使用していますので、適宜読み替えてください。Bootstrap-Vueについては以下を参照してください。
Nuxt.jsプロジェクトにBootstrap-Vueを追加する手順 - AUTOVICE
pages/users/create.vue
を新規作成し、以下のように実装します。
<template>
<b-form @submit.prevent="addUser">
<div class="container mt-5">
<div class="row justify-content-center mb-3">
<div class="col-12 col-sm-3">
<h2>Create user</h2>
</div>
</div>
<div class="row justify-content-center">
<div class="col-12 col-sm-3">
<b-form-group label="First name" label-for="first">
<b-form-input
id="first"
v-model="user.name.first"
required
placeholder="Jane"
></b-form-input>
</b-form-group>
</div>
</div>
<div class="row justify-content-center">
<div class="col-12 col-sm-3">
<b-form-group label="Last name" label-for="last">
<b-form-input
id="last"
v-model="user.name.last"
required
placeholder="Doe"
></b-form-input>
</b-form-group>
</div>
</div>
<div class="row justify-content-center">
<div class="col-12 col-sm-3">
<b-form-group label="Age" label-for="age">
<b-form-input
id="age"
v-model="user.age"
required
placeholder="20"
></b-form-input>
</b-form-group>
</div>
</div>
<div class="row justify-content-center mt-3">
<div class="col-12 col-sm-3">
<b-button block type="submit" variant="primary">Create</b-button>
</div>
</div>
</div>
</b-form>
</template>
<script>
export default {
data() {
return {
user: {
name: {
first: null,
last: null
},
age: null
}
}
},
methods: {
addUser() {
this.$store.dispatch('addUser', { user: this.user })
.then(() => {
this.user.name.first = null
this.user.name.last = null
this.user.age = null
alert('Successfully created user')
})
}
}
}
</script>
テンプレートに入力フォームを設置します。入力された内容はスクリプトのデータに格納されていきます。スクリプトから入力された内容を参照するときはthis.name.first
のように書くことで参照できます。
フォームの送信ボタンが押されたらVuexストアの処理を呼び出します。$store.dispatch
メソッドは、第1引数にVuexストアのactions
に定義したメソッド名を指定し、第2引数に呼び出すメソッドに渡す引数を指定します。
では次に、store/index.js
に呼び出されるメソッドを記述していきましょう。
import { v4 as uuidv4 } from 'uuid';
import firebase from '~/plugins/firebase'
const db = firebase.firestore()
const usersRef = db.collection('users')
export const actions = {
addUser({ commit }, payload) {
const user = {
id: uuidv4(),
name: payload.user.name,
age: payload.user.age,
created_at: firebase.firestore.FieldValue.serverTimestamp(),
updated_at: firebase.firestore.FieldValue.serverTimestamp()
}
return new Promise((resolve, reject) => {
usersRef.add(user)
.then(ref => {
resolve(true)
})
.catch(error => {
console.error('An error occurred in addUser(): ', error)
reject(error)
})
})
}
addUser
メソッドの中を順番に見ていきます。
const user = {
id: uuidv4(),
name: payload.user.name,
age: payload.user.age,
created_at: firebase.firestore.FieldValue.serverTimestamp(),
updated_at: firebase.firestore.FieldValue.serverTimestamp()
}
id
は一意な値をつけたいのでUUIDv4を使って生成した乱数をセットします。
created_at
とupdated_at
は、上記のようにFirebase組み込みのメソッドを使ってセットします。JavaScriptのDate型だと日付型として保存されないので注意してください。
入力フォームを入力して送信ボタンを押してみます。
Firestoreにデータが追加されました。
データの取り出し
pages/users/index.vue
を新規作成します。
<script>
export default {
created() {
this.$store.dispatch('fetchUsers')
}
}
</script>
created
にはDOMが作成された後に実行される処理を記述します。永続化のときと同じようにVuexストアの処理を呼び出します。
store/index.js
に以下の内容を追記します。
// インポートは変更なし
export const state = () => ({
users: []
})
export const actions = {
// addUserは変更なし
fetchUsers({ commit }) {
commit('initUsers')
return new Promise((resolve, reject) => {
usersRef.orderBy('created_at', 'desc').get()
.then(res => {
res.forEach((doc) => {
commit('addUsers', doc.data())
resolve(true)
})
})
.catch(error => {
console.error('An error occurred in fetchUsers(): ', error)
reject(error)
})
})
}
}
export const mutations = {
initUsers(state) {
state.users = []
},
addUsers(state, users) {
state.users.push(users)
}
}
export const getters = {
getUsers(state) {
return state.users
}
}
fetchUsers
メソッドではまずVuexストアのデータ領域を初期化(クリア)しています。これを行わないとFirestoreから取り出したデータがどんどんデータ領域に追加されていってしまいます。
実際の初期化(クリア)処理はmutations
内に定義します。Vuexストアのデータ領域は必ずmutations
に定義したメソッドを使用して操作(追加・変更・削除)する必要があります。
usersRef.orderBy('created_at', 'desc').get()
Firestoreのデータ取り出し時にソート順を指定しています。
state
はVuexストアのデータ領域です。Firestoreから取り出したデータをmutations
のaddUsers
メソッドを使ってstate
に格納しています。
getters
はstate
を参照するためのメソッドを定義します。
最後にpages/index.vue
に戻って、取り出したデータを表示します。
<template>
<div class="container mt-5">
<div class="row justify-content-center mb-3">
<div class="col-12 col-sm-3">
<h2>Users</h2>
</div>
</div>
<div class="row justify-content-center mb-3">
<div class="col-12 col-sm-2 font-weight-bold">Name</div>
<div class="col-12 col-sm-1 font-weight-bold">Age</div>
</div>
<div v-for="(user, key) in $store.getters.getUsers" :key="key"
class="row justify-content-center mb-3">
<div class="col-12 col-sm-2">
{{ user.name.first}} {{ user.name.last}}
</div>
<div class="col-12 col-sm-1">
{{ user.age}}
</div>
</div>
</div>
</template>
// スクリプトは変更なし
Vuexストアのデータ領域からユーザーデータを参照しています。画面を確認してみましょう。
データ永続化のときに追加したAlan Smitheeも含めてすべて取り出せています(データ部分が小さくてすみません...)。
まとめ
FirestoreはMySQLのような一般的なデータベースとは似て非なるものです。とはいえ、単にデータを永続化したいだけならデータベースとして使っても問題ないと思います。
Firestoreを使うときに注意しなければいけないことについては、また別の記事でまとめたいと思います。