FirebaseのCloud Firestoreと連携して掲示板を作る【nuxt.js】

FirebaseとNuxt.jsで掲示板を作りました。削除ボタンが機能しなかったり未完成の部分があります。

この記事は

- **Firebase**を活用してみたい
- **Nuxt.js**でアプリ作ってみたい

という人向けに書いてみました。
**「こんな感じでやれば短時間でFirebaseと連携できます」**的なものを記事にしました。作っていく際に参考にした記事と躓いた点も書いていきます。中途半端な出来ですが初心者向けに書いてみました！

##Firebaseとは何？
Firebaseはリアルタイムでデータ同期ができるモバイルプラットフォームです。Firebaseを使うとサーバを立てたり、管理や保守がいらなくなるのでフロントサイドの作成に集中できます。

##NuxtJSとは何？
NuxtJSは、Vueファイルで記述できるフレームワークです。モジュール構造で拡張でき一部分から徐々に採用することが可能で、静的なページから複雑なwebアプリケーションまで、**あらゆるものの作成に使用できます。**

>以下[公式](https://ja.nuxtjs.org/guide/)から抜粋
>>本質的に汎用性があり、さまざまなターゲット（サーバー、サーバーレス、または静的）をサポートし、サーバーサイドのレンダリングは切り替えることができます。
>強力なモジュールエコシステムにより拡張可能で、REST や GraphQL エンドポイント、お気に入りの CMS や CSS フレームワークなどさまざまなものに簡単に接続できます。
NuxtJS は Vue.js プロジェクトのバックボーンであり、柔軟でありながら自信を持ってプロジェクトを構築するための構造を提供します。


#めちゃくちゃ簡易的な掲示板
##できたもの
実際に利用できます！コメントしてみてください！
http://keiziban.tk/about/

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">簡易的な掲示板を作ってみました！削除ボタンは飾りです。<a href="https://t.co/73cLQb3M8d">https://t.co/73cLQb3M8d</a><a href="https://twitter.com/hashtag/protoout?src=hash&amp;ref_src=twsrc%5Etfw">#protoout</a>　<a href="https://twitter.com/hashtag/JavaScript?src=hash&amp;ref_src=twsrc%5Etfw">#JavaScript</a>　<a href="https://twitter.com/hashtag/Firebase?src=hash&amp;ref_src=twsrc%5Etfw">#Firebase</a> <a href="https://t.co/Hu4AITFnL0">pic.twitter.com/Hu4AITFnL0</a></p>&mdash; Toshiki (@Hirasawa1987) <a href="https://twitter.com/Hirasawa1987/status/1303803686926262272?ref_src=twsrc%5Etfw">September 9, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>



##機能

名前、コメントの投稿がきる

#作成手順
任意のフォルダーに移動して`VScode`のTerminalより
`yarn`を使って以下のコマンドでNuxtプロジェクトを作成することができます。

```yarn create nuxt-app cloudfireTest```

を実行すると、UIフレームワークなどの機能が必要か聞かれるので選択していき、終了したら
```yarn run dev```で起動させます。無事に終了したら以下のアドレスにアクセスして実行されているか見ます。
`http://localhost:3000`

続いて

```
yarn add firebase
```
でインストールて完了です。
今回にUIフレームワークはBootstrapVueを選択したので、[こちら](https://bootstrap-vue.org/)でどのようなスタイルになるのかを調べました。

##フォルダ構造

以下のフォルダとファイルで構成されています。
[![Image from Gyazo](https://i.gyazo.com/a1d4b519b591f1c19413b49792cee113.png)](https://gyazo.com/a1d4b519b591f1c19413b49792cee113)

#pages
pagesディレクトリに`.vue`ファイルを作成するとページのルーティングができます、`index.vue`が`/`になり、`about.vue` が`/about`でアクセスできます

```about.vue
<template>
  <div class="container">
   <div class="jumbotron">
        <div class="container">
          <h1 class="display-3">掲示板</h1>
        </div>
      
      <div class="links">
        <client-only placeholder="Loading...">
        <Memo />
        </client-only>
      
      </div>
    </div>
  </div>
</template>

<script>

import Memo from '~/components/Memo.vue'


export default {
  components: {
    Memo
  }
}
</script>
```

以下の部分でComponents内に作る`Memo.vue`が呼び出されます。

```
<client-only placeholder="Loading...">
        <Memo />
        </client-only>
```

#Components
何度も利用可能な`.vue`で構成されています。今回のFirebaseとの連携はこちらに書いていきます。まずは`Components`に`Memo.vue`を追加。
[![Image from Gyazo](https://i.gyazo.com/1be0d367051ceaad0d0d8b585ea40af7.png)](https://gyazo.com/1be0d367051ceaad0d0d8b585ea40af7)

```Memo.vue
<template>
    <div>
         <p>
            <b-form-input v-model="name" placeholder="名前"></b-form-input>
            <b-form-textarea input v-model="age" placeholder="コメント" id="button"></b-form-textarea> 
            <b-button id="button" size="sm" variant="outline-success" v-on:click="post(); removetext()">投稿</b-button>
        </p>
        <ul v-for="(data, index) in allData" :key="data.id" class="menu-list" >

            <li>
               
                名前：{{data.name}} <br>
                コメント：{{data.age}}<br>
                <b-button size="sm" variant="outline-danger" class="delete" @click="switchDelateAlarm(); getIndex(index)">
                削除
                </b-button>

            </li>
            </ul>
            <div v-show="showDelateAlarm" id="overlay">
                <div id="delateAlarm">
                    <p>コメントを削除します</p>
                        <b-button size="sm" variant="outline-dark" v-on:click="closeModal">
                        戻る
                        </b-button>
                        <b-button  size="sm" variant="outline-danger" @click="switchDelateAlarm(); deleteItem(data.id)">
                        削除
                        </b-button>
                </div>
            </div>
    </div>
</template>

<script>
import firebase from "firebase/app";
import "firebase/firestore";



export default {
    components: {},

    data(){
        return{
            db: {},
            allData: [],
            name: '',
            age: '',
            showDelateAlarm: false,
            id: [],

        }
    },
    


    methods: {
        init: () => {
            const config = {
                apiKey: "",
                authDomain: "",
                databaseURL: "",
                projectId: "",
                storageBucket: "",
                messagingSenderId: "",
                appId: "",
                measurementId: ""
            };
            firebase.initializeApp(config);
        },

        post: function(){
            const testId = firebase.firestore().collection('memos').doc().id; //ユニークなIDを生成
            const docRef = firebase.firestore().collection('memos').doc(testId);
            const setAda = docRef.set({
                name: this.name,
                age: this.age,
                createdAt: new Date()
            });
            this.get();
        },

        get: function(){
            this.allData = [];
            firebase.firestore().collection('memos').get().then(snapshot => {
                snapshot.forEach(doc => {
                    this.id = doc.id;
                    console.log(this.id); 
                    const array = [];
                    console.log(array);
                    this.allData.push(doc.data());
                })
            });
            
        },
        getIndex: function() {
            console.log(firebase.firestore().collection('memos'));

        },
        deleteItem: function(deleteId, getIndex) {
            const db = firebase.firestore();
            db.collection("memos").doc(deleteId).delete().then(function() {
            console.log("Document successfully deleted!");
           
            }).catch(function(error) {
                console.error("Error removing document: ", error);
            });
            this.showDelateAlarm = false;
            this.get();
        },


        switchDelateAlarm: function() {
            this.showDelateAlarm = true
        },
        closeModal: function(){
           this.showDelateAlarm = false
        },
        removetext: function() {
       this.name = '';
       this.age = '';

    },
    },

    mounted(){
        this.init();
        this.get();
    },
        
        
}


</script>

<style>
#delateAlarm{
  z-index:2;
  width:50%;
  padding: 1em;
  background:#fff;
}

#overlay{
  /*　要素を重ねた時の順番　*/

  z-index:1;

  /*　画面全体を覆う設定　*/
  position:fixed;
  top:0;
  left:0;
  width:100%;
  height:100%;
  background-color:rgba(0,0,0,0.5);

  /*　画面の中央に要素を表示させる設定　*/
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 10%;

}
ul {
    display: block;
    margin-block-start: 1em;
    margin-block-end: 1em;
    margin-inline-start: 0px;
    margin-inline-end: 0px;
    padding: 0px;
    list-style: none;
}
#button {
    margin-top: 2px;
}

</style>


```
###Cloud Firestoreの設定

こちらの部分にファイヤーベースの設定→全般の下のほうにあるマイアプリ
からコピー＆ペーストします。
[![Image from Gyazo](https://i.gyazo.com/957cbf0de4c33d05c7d629de602d9cad.png)](https://gyazo.com/957cbf0de4c33d05c7d629de602d9cad)


```Memo.vue
const config = {
                apiKey: "",
                authDomain: "",
                databaseURL: "",
                projectId: "",
                storageBucket: "",
                messagingSenderId: "",
                appId: "",
                measurementId: ""
            };
```

今回はあらかじめCloud Firestoreのコレクションに`memos`作成しておきます。

[![Image from Gyazo](https://i.gyazo.com/cb357901085260e57e4882f165f1cb38.png)](https://gyazo.com/cb357901085260e57e4882f165f1cb38)

###設定


以下は`post`の部分を抜粋しています。

```Memo.vue
post: function(){
            const testId = firebase.firestore().collection('memos').doc().id; //ユニークなIDを生成
            const docRef = firebase.firestore().collection('memos').doc(testId);
            const setAda = docRef.set({
                name: this.name,
                age: this.age,
                createdAt: new Date()
            });
            this.get();
        },

```
#

[![Image from Gyazo](https://i.gyazo.com/1728e796a29a061d145d54edd9483498.png)](https://gyazo.com/1728e796a29a061d145d54edd9483498)

#躓いた部分
削除ボタンの実装に躓きました。ボタンに紐づいたドキュメントidが取得できずボタンは配置されていますが、機能しません。

#参考にした記事

- [ざっくりFirestore + Vue.jsの使い方](https://qiita.com/s_sh/items/53df1de1eb6a62b5d699)
- [【v2対応】Nuxt.jsとFirebaseを組み合わせて爆速でWebアプリケーションを構築する](https://qiita.com/potato4d/items/cfddeb8732fec63cb29c)
- [【Nuxt.js】todoアプリを作成してみた①](https://qiita.com/ayapon/items/d93807e7699434279531)
- [firestore, vue.jsでリアルタイム同期のチャットを実装してみる [チュートリアル形式]](https://qiita.com/ryo2132/items/2881d8223eb2ad3050a1) 
- [Vue.js おすすめライブラリ 21選（おまけ+1）](https://qiita.com/andmorefine/items/bec9cbe9a22c90bd6b43)

#終わりに
読んでいただきありがとうございました、よくわからん部分もあったと思います。私自身わかっていない部分が多いですが、とにかく一言いってやりたいという方！**是非[こちらで](https://twitter.com/Hirasawa1987)絡んで**やってください。