vue.jsとFirebaseでSlackクローン構築(Firebase理解編)
vue.jsとFirebaseのRealtime DatabaseとAuthorization機能を利用したSlackクローンの構築方法について複数回にわけて説明を行います。1回目の本文書ではチャットのリアルタイム更新に重要な役割をもつFirebaseのRealtime Databaseの使用方法に重点をおいて説明を行っています。読み終えると下記を理解することができます。
- Vue.jsからのFirebaseのRealtime Databaseへの書き込み、読み込み
- Vue.jsとFirebaseのイベントを利用したリアルタイム更新機能の理解
本書を読んだだけでもFirebaseを利用することでリアルタイムのチャット機能を行えることががわかるはずです。リアルタイムのチャット機能のポイントはFirebaseのデータベースにデータが追加されるとFirebase側からVue.jsに伝える仕組みがあるかどうかです。そのためにFirebaseのイベント(valueイベントとchildaddイベント)を利用します。
vue.jsプロジェクトの作成
vue/cliパッケージのインストールが完了している場合はvue createコマンドでプロジェクトの作成を行います。vue/cliパッケージのインストールを行っていない場合はnpxコマンドを利用してプロジェクトの作成を行います。ここではプロジェクトの名前はvue_slack_cloneにしていますが任意の名前をつけてください。
vueコマンドでnpxコマンドのどちらでもvueのプロジェクトを作成することができます。
$ vue create vue_slack_clone
or
$ npx vue create vue_slack_clone
createコマンド実行後に表示されるManually select featuresではBabel, Router, Vuex, Linter / Formatterを選択して進めます。HistoryモードはYを選択してください。
インストールが完了したらプロジェクトディレクトリに移動してコンパイルを行います。
$ cd vue_slack_clone
$ npm run serve
ブラウザを起動してvue.jsの初期画面が表示されるか確認を行ってください。
Firebaseの設定
アカウントの登録
Firebaseのユーザアカウントがない人はFirebaseのアカウントの登録が必要になります。アカウントの登録については下記の文書の”アカウントの登録”を参考に行ってください。
プロジェクトの作成
アカウントの登録が完了したらFirebaseの管理画面からプロジェクトの作成を行う必要があります。
プロジェクトの作成ボタンをクリックしてください。
プロジェクトの名前を入力してください。ここではvue-slack-cloneという名前にしています。
Googleアナリティクスに関する設定ですが今回は動作確認用なので無効にしてください。無効後に”プロジェクトを作成”ボタンをクリックしてください。
プロジェクトの作成完了まで少し時間がかかります。完了すると”続行”ボタンが表示されるのでクリックしてください。
クリックすると以下のプロジェクトの概要画面が表示されます。
Realtime Databaseの作成
左側の開発メニューの2番目にあるDatabaseをクリックしてください。Realtime Databaseの画面が表示されるので”データベースを作成”ボタンをクリックしてください。
ロケーションの設定画面が表示されるので選択肢に日本はないのでそのまま次へボタンをクリックします。
Realtime Dabaseのセキュリティルールの設定画面が表示されますが動作確認を行いたいので読み取り書き込みがすべて許可されている”テストモードで開始”を選択して、”有効にする”をクリックしてください。
”有効にする”ボタンをクリックすると以下の画面が表示されます。データベースが作成され、名前はvue-slack-clone-7fecaでデータが何も入っていないのでnullと表示されています。データを保存するとこの画面に保存したデータが表示されます。
アプリケーションの追加
vue.jsなど外部のアプリケーションからFirebaseのデータベースに接続するためには接続情報が必要となります。
プロジェクトの概要画面に戻り画面中央の赤丸</>をクリックしてください。
アプリのニックネームを入力して”アプリを登録”ボタンをクリックしてください。ここではVue Slack Cloneという名前をつけています。
FirebaseのSDKが表示されます。このスクリプトをvue.jsプロジェクトのmain.jsファイルに貼り付ける必要があります。
下記のデータをそのまま貼り付けても動作しないので各自でFirebaseの管理画面からSDKの情報を取得してください。
import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
import firebase from "firebase/app";
Vue.config.productionTip = false;
var firebaseConfig = {
apiKey: "XXXXXXXXXXXXXXXXXXXXXXXXXX",
authDomain: "vue-slack-3796e.firebaseapp.com",
databaseURL: "https://vue-slack-3796e.firebaseio.com",
projectId: "vue-slack-3796e",
storageBucket: "vue-slack-3796e.appspot.com",
messagingSenderId: "896148090732",
appId: "XXXXXXXXXXXXXXXXXXXXXXXXXX9"
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
window.firebase = firebase;
new Vue({
router,
store,
render: h => h(App)
}).$mount("#app");
main.jsの上部でfirebaseをimportしていますがfirebaseライブラリをまだインストールしていないのでこれからfirebaseのライブラリのインストールを行います。インストールはnpmコマンドで行います。
$ npm install --save firebase
Firebaseの動作確認
データベースの初期設定が完了したのでvue.jsからのFirebaseのRealtime Databaseに対して読み書きを行う方法を確認していきます。
Firebaseのデータベースへの書き込み
vue.jsのプロジェクトのsrc¥viewsの下にあるHome.vueファイルを使ってデータベースへの書き込みの動作確認を行います。Firebaseにデータを書き込む方法はset, pushの2つがあります。両方の動作確認を行い違いを見ていきます。
setメソッドによるデータベースへの書き込み
etによるデータベースの書き込みは下記のように記述することで行うことができます。slack等の名前がでてきますがデータ登録後にこのslackがどこに対応するのかがわかるのでこのまま進めてください。
firebase.database().ref("slack")
.set({
content: this.message,
user: {
name: "John Doe"
}
}
Home.vueファイル内で実際にsetによる書き込み処理を追加したコードは下記のようになります。input要素にv-modelでmessageを設定し入力した値をFirebaseのデータベースに追加します。
<template>
<div>
<h1>Firebaseを使った読み書き確認</h1>
<input v-model="message" />
<button @click="addMessage">メッセージを追加</button>
</div>
</template>
<script>
import firebase from "firebase/app";
import "firebase/database";
export default {
name: "Home",
data() {
return {
message: "",
};
},
methods: {
addMessage() {
firebase.database().ref("slack")
.set({
content: this.message,
user: {
name: "John Doe"
}
});
}
}
};
</script>
実際にブラウザを使ってデータの追加を行います。input要素に”はじめてのメッセージ”を入力してメッセージを追加ボタンをクリックします。ボタンを押しても入力したメッセージは消えません。
Firebaseの管理画面でデータベースに入力されたデータを確認します。先程refの中で設定していたslackを確認することができます。そのslackの下にcontentとuser、さらにuserの下にnameとツリー構造になっていることが確認できます。
slackという名前に決まりはなくmessageなど他の名前についても問題ありません。contentやuserを含め任意の名前をつけることができます。
pushによるデータベースへの書き込み
pushメソッドによる書き込みも確認します。コードは先程のsetメソッドをpushメソッドに変更するだけです。
firebase.database().ref("slack")
.push({
content: this.message,
user: {
name: "John Doe"
}
}
setメソッドからpushメソッドに変更しただけなので入力画面は変わりません。
メッセージを追加後にFirebase管理画面でデータベースの中身を確認するとFirebase側で一意のキーが自動で付与されます。pushメソッドに変更することで一意のキーが付与されます。
setメソッドとは異なりpushメソッドでは、一意のキーによりメッセージを識別することができるのでここからはpushを利用してデータベースへのデータの登録を行っていきます。
setメソッドで書き込んだデータはFirebase管理画面から削除を行って行ってください。データの上にカーソルを乗せるとXが表示されるのでXをクリックして削除してください。
Firebaseのデータベースからの読み込み
Firebaseではイベントによりデータベースへのデータの追加や更新が行われるとその処理をブラウザにリアルタイムに反映させることができます。この機能のおかげでユーザがメッセージを追加すると別のブラウザを閲覧しているユーザにも追加したデータが即座に反映されます。この機能がSlackのようなチャットで重要な役割を持っています。
Firebaseからのデータの取得方法にも書き込みと同様にいくつか方法があるのでここではvalueイベントとchild_addedイベントを使ってデータの取得を行います。
valueイベントによるデータ取得
valueイベントを利用したデータベースからのデータ取得は下記のように記述します。onでvalueイベントを設定するとrefで指定したslack以下に登録されたすべてのデータを一括で取得することができます。一括取得は1回ではなくslackにデータが追加される度に一括でデータが取得されます。
firebase.database().ref("slack")
.on("value", snapshot => console.log(snapshot.val()));
}
vue.jsのライフサイクルフックのmountedにデータ取得のコードを追加することでブラウザでアクセスすると自動でFirebaseのデータベースからデータ取得を行います。
mounted() {
firebase.database().ref("slack")
.on("value", snapshot => console.log(snapshot.val()));
}
}
ブラウザでページにアクセスしてデベロッパーツールのコンソールを見るとデータベースから取得したデータを確認することができます。setメソッド、pushメソッドで登録したデータです。setメソッドで登録したデータを削除している場合はcontentとuserは表示されません。
user, contentとFirebaseの管理上から削除して、ブラウザ上からメッセージを2つ追加します。
ブラウザ上からメッセージの追加を行うと追加したデータを含めすべてのデータ(3件分)が取得されていることがわかります。
メッセージを追加した直後に自動でコンソールログに表示されます。
ここまでの動作確認によりvalueイベントではすべてのデータが一括で取得できることを理解しておいてください。
child_addedイベントによるデータ取得
valueイベントからchild_addedイベントに変更を行い動作確認を行います。child_addedと名前の通りchild(子)にadded(追加された)されたらイベントが発生しデータの取得が行われます。
mounted() {
firebase.database().ref("slack")
.on("child_added", snapshot => console.log(snapshot.val()));
}
}
ブラウザを開いて確認するとvalueとは異なりデータが1行ごとに分かれていることが確認できます。またすべてのデータ(3件)が取得させていることもわかります。
次にブラウザ上からデータの追加を行ってみましょう。valueイベントは異なりすべてのデータを追加の度に取得するのではなく追加した情報のみ取得していることがわかります。
child_addedイベントでは最初はすべてのデータを取得し、その後はデータが追加されると追加したデータのみ取得できることがわかりました。
v-forによる取得したデータの表示
valueイベント、child-addedイベントによりFirebaseのデータベースからデータが取得できることが確認できたので取得したデータをv-forディレクティブを利用してブラウザに表示させます。
valueイベント、child-addedイベントどちらでも実現できますがここではvalueイベントを利用して行います。
vue.jsのデータプロパティにmessagesを追加してデータベースから取得したデータをライフサイクルフックのmountedで挿入しています。messagesはv-forを利用して展開させています。各データに自動的に付与されているキーをindexで意図的に表示しています(通常は表示させる必要はありません)。このキーを利用することでデータの更新、削除を行うことができます。
<template>
<div>
<h1>Firebaseを使った読み書き確認</h1>
<input v-model="message" />
<button @click="addMessage">メッセージを追加</button>
<ul>
<li v-for="(message, index) in messages" :key="index">
{{ message.content }} index:{{ index }}
</li>
</ul>
</div>
</template>
<script>
import firebase from "firebase/app";
import "firebase/database";
export default {
name: "Home",
data() {
return {
message: "",
messages: []
};
},
methods: {
addMessage() {
firebase.database().ref("slack")
.push({
content: this.message,
user: {
name: "John Doe"
}
});
}
},
mounted() {
firebase.database().ref("slack")
.on("value", snapshot => (this.messages = snapshot.val()));
}
};
</script>
リアルタイムで追加されるメッセージの動作確認
データベースからの書き込みと読み込みの設定が完了すると複数のブラウザでリアルタイムにデータが追加される機能を確認することができます。
2つのブラウザを起動してください。片方のブラウザで下記のようにメッセージを追加しinput要素に記述しメッセージ追加ボタンをクリックしてください。
追加後に両方のブラウザで追加したメッセージが即座にブラウザ上に追加されることを確認してください。リアルタイムでの反映が行えることが確認できます。
データの削除方法
v-forで展開した際に表示したindexを利用してデータの削除方法も確認しておきます。各メッセージにspanタグを追加しクリックイベントでdeleteMessageメソッドを追加します。引数にはindexを設定します。
<ul>
<li v-for="(message, index) in messages" :key="index">
{{ message.content }} index:{{ index }}
<span @click="deleteMessage(index)">X</span>
</li>
</ul>
vue.js側の設定ではclickイベントで受け取ったindexを利用してFirebaseのデータベースからそのindexを持つデータを削除します。そのコードは下記の通りです。slackの子(child)で指定したindexを持つデータを指定してremoveで削除しています。
deleteMessage(index) {
firebase
.database()
.ref("slack")
.child(index)
.remove();
}
ブラウザ上でメッセージに右にあるXを押すとそのメッセージがブラウザ上から削除されることを確認してください。valueイベントでは削除後のすべてのデータを再度取得するためvue.js側でmessagesの削除処理を行う必要はありません。
更新を行ったHome.vueファイルの中身は下記の通りです。
<template>
<div>
<h1>Firebaseを使った読み書き確認</h1>
<input v-model="message" />
<button @click="addMessage">メッセージを追加</button>
<ul>
<li v-for="(message, index) in messages" :key="index">
{{ message.content }} index:{{ index }}
<span @click="deleteMessage(index)">X</span>
</li>
</ul>
</div>
</template>
<script>
import firebase from "firebase/app";
import "firebase/database";
export default {
name: "Home",
data() {
return {
message: "",
messages: []
};
},
methods: {
addMessage() {
firebase.database().ref("slack")
.push({
content: this.message,
user: {
name: "John Doe"
}
});
},
deleteMessage(index) {
firebase
.database()
.ref("slack")
.child(index)
.remove();
}
},
mounted() {
firebase.database().ref("slack")
.on("value", snapshot => (this.messages = snapshot.val()));
}
};
</script>
まとめ
vue.jsからFirebaseのRealtime Databaseへのデータの書き込み、読み込み、削除またブラウザを利用したリアルタイムでの更新を実現することができました。複数のブラウザを開いて実行すると片方のブラウザでの処理が即座に別のブラウザの画面の更新が行われたことからSlackのようなチャットアプリが作成できることがこの時点で理解できるかと思います。
続きは下記の文書で公開しています。