13
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Firebaseで「いいね」機能実装してみた

Posted at

現時点、いいねを加えるところだけ実装しました。
公式のドキュメントがStarだったのでコードはstarですが、やってることは「いいね」です。
ぜひこの記事を読み始める前に、まずいいねを押してからみていただけると幸いです。

今回公式のドキュメントを解読した項目としては

・フィールドの数値に1を加算(いいねを+1)すること
・フィールドの配列に要素を追加すること
([0,1]→[0,1,2]みたいな)

環境
VueCLI

Postには、post_idが1から順に数字を振っています。便利。

前半では、postsコレクション内の指定したpost(実際にフロントでクリックするポスト)に対して、starCountを1増やすと言う処理になっています。

後半は、現在ログインしているユーザーのstarCountドキュメントに、starをつけたポストのID(数字)を配列にして入れます。

なぜ配列にするかというと、ドキュメントの読み込み数が減ると思ったからです。
こういう設計の点でのアドバイスは24時間マジで受け付けてます。よろしくお願いします。

store.js
actions: {
    addStarCount({ getters ,commit }, postId){
      if(getters.uid){
        firebase.firestore().collection("posts").where('post_id', '==', postId).get().then(doc => {
          var data = doc.docs[0].id;

          firebase.firestore().collection("posts").doc(data).update({
            starCount: firebase.firestore.FieldValue.increment(1)
          })

        })
        firebase.firestore().collection(`users/${getters.uid}/starCount`).doc("starCount").update({
          star_post_id: firebase.firestore.FieldValue.arrayUnion(postId)
        })
        commit('addStarCount')
      }

    },
}

*postIdにはコンポーネント側でポストのIDを渡します

ドキュメントを指定して、updateをする。

starCount: firebase.firestore.FieldValue.increment(1)

↑でデータベース上の数値に+1する。()内の数値が1億だったらアクションが発動するたびに1億加算される

star_post_id: firebase.firestore.FieldValue.arrayUnion(postId)

↑ユーザーがスターをつけたポストのIDが配列になってどんどん追加されていく。

post.vue
  data() {
    return {
    userStarCounts: [],
   }
 }

  created() {
      firebase.firestore().collection(`users/${this.$store.getters.uid}/starCount`).doc('starCount').get().then(doc => {
          this.userStarCounts = (doc.data().star_post_id)
        })

配列の呼び出しは上記のとおり。

良い名前が思いつかなかった。
userStarCountsに、現在ログイン中のユーザーが「いいね」したポストのIDが全て入っています。

次はいいねを消す処理。

store.js
    deleteStarCount({ getters, commit }, postId){
      if(getters.uid){
        firebase.firestore().collection("posts").where('post_id', '==', postId).get().then(doc => {
          var data = doc.docs[0].id;

          firebase.firestore().collection("posts").doc(data).update({
            starCount: firebase.firestore.FieldValue.increment(-1)
          })

        })
        firebase.firestore().collection(`users/${getters.uid}/starCount`).doc("starCount").update({
          star_post_id: firebase.firestore.FieldValue.arrayRemove(postId)
        })
        commit('deleteStarCount')
      }
    },//deleteStarCountここまで


starCount: firebase.firestore.FieldValue.increment(-1)

さっきは1だったのは−1にしてスターが減る

star_post_id: firebase.firestore.FieldValue.arrayRemove(postId)

arrayRemoveで、「数字が全く同じやつを配列から削除」できるようです。

ここで、完成したと思って一旦データベース削除してクリアな状態にしてからいいねを押してみたらエラーを吐いた。

##実は1ヶ所ダメなところあります。
どこでしょうか。

ユーザーのstarCountドキュメントにポストを配列でアップデートして追加していくのですがupdateはあくまで「更新」であって、作成とかは含まれないらしいのです。

そこで出てきたのが.setというやつ。

###じゃあそのまま.updateを.setにすると、追加ではなく新規にポストidが1個しかない配列に置き換わってしまう
のでした。

ということで、正解は

  firebase.firestore().collection(`users/${getters.uid}/starCount`).doc("starCount").set({
          star_post_id: firebase.firestore.FieldValue.arrayUnion(postId)
        },{ merge: true})

最後にmerge:trueをつけることにより、想定の通り「今の配列に追加」を実装することができます。

便利。

##フロント側の最善が思いつかなかった
ポストをそれぞれ子コンポーネントにすることによって、「いいね」の増減を子コンポーネントで実装してます。

postChild.vue

<template>
<div v-if="userStarCounts.includes(post.post_id)">
      <v-icon v-show="likedDrawer" color="pink accent-2grey" @click="deleteStar(post.post_id)">mdi-heart</v-icon>
      <v-icon v-show="!likedDrawer" color="grey lighten-2" @click="addStar(post.post_id)">mdi-heart</v-icon>
</div>
<div v-else>
      <v-icon v-show="likedDrawer" color="grey lighten-2" @click="addStar(post.post_id)">mdi-heart</v-icon>
      <v-icon v-show="!likedDrawer" color="pink accent-2grey" @click="deleteStar(post.post_id)">mdi-heart</v-icon>
</div>
</template>

  data() {
    return {
      starCount: 0,
      userStarCounts: [],
      likedDrawer: true,
    }
  },

  created() {
      firebase.firestore().collection(`users/${this.$store.getters.uid}/starCount`).doc('starCount').get().then(doc => {
          this.userStarCounts = (doc.data().star_post_id)
        })
},
  methods: {
    addStar(postId){
      this.addStarCount(postId)
      this.starCount ++
      this.likedDrawer = !this.likedDrawer
    },

    deleteStar(postId){
      if(confirm('削除しますか?')){
        this.deleteStarCount(postId)
        this.starCount --
        this.likedDrawer = !this.likedDrawer
      } else{
        alert("削除は取り消されました");
      }
    },
}

これで一応実装できました。

が、もっと良いコードが存在すると思います。

vuexだとstateが全てのポストに適用なので、配列とかフィールドとかをmutationsでコミットしないと実装できないので、今回はコンポーネントでゴリ押しました。

v-ifとv-showのところは伸び代しかないので、ご指導ご鞭撻よろしくお願いします。

13
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?