Firebase + Vueでチャットをつくる

こんにちは。フリーランス・コンサルタント&エンジニアの 九保すこひ です。

さてさて、前回「Firebase + Vueでログイン機能をつくる」という記事ではFirebaseを使ったログイン機能をつくってみました。

これは、Authenticationというサービスを使ったものですが、実は他にもサービスがあるので、もう少し深堀りしてみました。

そして、今回紹介する内容は、

Firebaseのデータベース機能「Firestore」

です。

Firestoreは、MySQLのようなデータ管理をクラウド上で実現するサービスですが、今回はこの機能でリアルタイムなチャットをつくってみたいと思います。

ぜひ皆さんのお役に立てると嬉しいです😊✨

開発環境: Firebase JavaScript SDK 7.12.0

やりたいこと

ログインしてるユーザーだけがチャットに参加できるようにします。
また、メッセージ内容はリアルタイムで更新されるようにします。

では、実際にやっていきましょう❗

前提として

まずFirebaseでログインができることが前提です。
前回記事を参考にしてログインできるユーザーを作成しておいてください。

なお、テストで使うので、ユーザーは2人作っておいてください。

Firebaseの準備

データベースをつくる

では、Firebaseにログインしてデータベースをつくります。

メニューの「Database」をクリックして、「コレクションを開始」をクリックしてください。

コレクションのIDを入力して「次へ」ボタンをクリックします。
(今回はchatsにします)

次にデータベースのフィールドを3つ追加します。

フィールドの中身は以下のとおりです。

  • message ・・・ チャットのメッセージ
  • created ・・・ 作成日時(タイムスタンプ)
  • uid ・・・ 作成したユーザーのID

なお、本来チャットは名前を保存しておくべきですが、複雑になるので今回はuidだけ保存します。

そして、「保存」をクリックするとデータベースは完了です。

権限を設定する

先ほどデータベースをつくりましたが、実はこのままでは外部からアクセスできません。なぜなら権限が設定されていないからです。

Firestoreでは権限は「ルール」で変更します。
画面上部の「ルール」をクリックしてください。

そして、権限の中身を以下のように変更してください。

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /chats/{chatId} {
      allow read, create: if request.auth.uid != null;
    }
  }
}

意味としては、「chatsはログインしている人だけ読み書きOK👌」となります。

権限の設定もこれで完了です!

HTMLファイルをつくる

では、ここからは実際にコードを書いていく部分です。
前回と同じくHTMLファイルでOKです。

chat.html

<html>
<head>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
</head>
<body>
    <div id="app" class="container pt-5">
        <div class="row">
            <div class="col-md-4">
                <div class="input-group">
                    <input type="text" class="form-control" v-model="message">
                    <div class="input-group-append">
                        <button class="btn btn-primary" @click="addChat">送信</button>
                    </div>
                </div>
                <div class="bg-light p-3 my-2" v-if="chat.message" v-for="chat in chats">
                    <div v-text="chat.message"></div>
                    <small v-text="chat.uid"></small>
                </div>
            </div>
        </div>
    </div>
    <script src="https://www.gstatic.com/firebasejs/7.12.0/firebase-app.js"></script>
    <script src="https://www.gstatic.com/firebasejs/7.12.0/firebase-auth.js"></script>
    <script src="https://www.gstatic.com/firebasejs/7.12.0/firebase-firestore.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
    <script>

        new Vue({
            el: '#app',
            data: {
                message: '',
                chats: [],
                db: null
            },
            methods: {
                getChats() {

                    // チャットデータを取得 ・・・ ④
                    this.db.collection('chats')
                        .orderBy('created', 'desc') // 最新のものから取得
                        .limit(25)  // 最大25件まで
                        .get()
                        .then(querySnapshot => {

                            let chats = [];
                            querySnapshot.forEach(doc => {

                                const data = doc.data();
                                chats.push({
                                    uid: data.uid,
                                    message: data.message
                                });

                            });
                            this.chats = chats;

                        })
                        .catch(error => {

                            console.log(error);

                        });

                },
                addChat() {

                    if(this.message === '') {

                        alert('メッセージを入力してください。');
                        return;

                    }

                    // Firebaseに保存 ・・・ ③
                    this.db.collection('chats')
                        .add({
                            message: this.message,
                            uid: firebase.auth().currentUser.uid,  // ユーザーID
                            created: firebase.firestore.FieldValue.serverTimestamp()
                        })
                        .then(docRef => {

                            // const createdId = docRef.id;
                            this.message = '';

                        })
                        .catch(error => {

                            console.error('Error adding document: ', error);

                        });

                }
            },
            mounted() {

                // Firebaseの準備 ・・・ ①
                const firebaseConfig = {
                    apiKey: "**************************",
                    authDomain: "**************************",
                    databaseURL: "**************************",
                    projectId: "**************************",
                    storageBucket: "**************************",
                    messagingSenderId: "**************************",
                    appId: "**************************"
                }; 
                firebase.initializeApp(firebaseConfig);
                this.db = firebase.firestore();
                
                // 内容に変更があったら実行される ・・・ ②
                this.db.collection('chats')
                    .onSnapshot(() => {

                        this.getChats();

                    });

            }
        });

    </script>
</body>
</html>

では、番号順に説明していきます。

① Firebaseの準備

firebaseConfigは、前回記事で取得したものを使ってください。
つまり、環境によって中身が違います。

② 内容に変更があったら実行される

onSnapshot()は、データベースに変更があったら実行されます。
そして、重要なのはこのメソッドは自分以外の人が変更しても起動されるという部分です。

つまり、今回で言うと「自分以外のメッセージが投稿されたタイミングでも、チャット内容が最新のものになる」ということになります。

③ Firebaseに保存

保存するデータは以下のとおりです。

  • message ・・・ 入力した内容
  • uid ・・・ 現在ログインしている人のuid
  • created ・・・ 現在時間

④ チャットデータを取得

投稿されたチャットデータは、「最新のものから最大25件」取得するようにしています。

その後、取得されたデータはchatsに格納されVueで描画されることになります。

テストしてみる

では、実際にテストしてましょう!

2人のユーザーが必要なのでGoogle Chromeの通常のタブとプライベート・モードのタブでログインして実行してみます。

では、下側のブラウザから「テスト送信1」と投稿してみましょう。

すると、自動的に両方のブラウザにその内容が表示されました。

では今度は逆に、上のブラウザから「テスト送信2」と送信してみましょう。

すると、今回も両方のブラウザが更新され新しい順に表示されました。

成功です😊✨

開発のご依頼お待ちしております
開発のご依頼はこちらから: お問い合わせ
どうぞよろしくお願いいたします! by 九保すこひ

おわりに

ということで、今回はFirestoreを使ってリアルタイム・チャットシステムをつくってみました。

なお、今回の開発で少し残念だったのがFirestoreは投稿したユーザーの情報が取得できないということです。(つまり、各データに名前やuidを登録しておく必要があります)

また、FirestoreのIDは番号ではなくランダムな文字列なため、新着順でデータを取得するには自前で投稿日時を保存しておかないといけない点も少し不便でした。

ただ、今回のコード量でチャット機能を作れるのはとても魅力なので、このあたりの問題点が改善できれば、もっとFirebaseは使いやすいものになると思います😊✨

ぜひ、皆さんも一度試してみてくださいね。

ではでは〜!

このエントリーをはてなブックマークに追加       follow us in feedly