LoginSignup
9
8

More than 3 years have passed since last update.

Laravel + Vue + Redisでいいねボタンコンポーネント作成

Posted at

環境など

Docker
laravel 5.8
npm 5.6.0
Redis latest

はじめに要件を明確化し、その後サーバーの実装、フロントの実装の順で書いていきます。

満たしたい要件

①ユーザーが投稿にいいねできる
②いいねは一人一度だけ。二回押すといいねが取り消される
③いいね数の増減が非同期で確認できる
④いいねした人を時系列で取得できるようにしておきたい

サーバー側の処理

今回はいいねした投稿とユーザーをRedisのzsetで管理します。

EloquentArticleRepository.php

//いいねした時の処理
public function like($articleId, $userId) 
{
        //unixtimeに変換
        $date = Carbon::now();
        $unixTime = $date->format('U');

        //未いいねの場合
        if(empty(Redis::zscore('article:'.$articleId, $userId))) {
            Redis::zadd('article:'.$articleId, $unixTime, $userId);
            $count = Redis::zcard('article:'.$articleId);

            return $count;

        }

        //いいね済みの場合
        Redis::zrem('article:'.$articleId, $userId);

        $count = Redis::zcard('article:'.$articleId);

        return $count;
}

//記事ごとにいいね数取得
public function getArticleLikes($articles)
{
        $likes = [];
        foreach($articles as $article) {
            $likes[$article->id] = Redis::zcard('article:'.$article->id);
        }

        return $likes;
}

unixtimeをscore, user_idをvalueとしてzsetに持たせることでいいねした人を時系列ソートして取得できるようにしておきました。zsetについては公式ドキュメントご覧ください。
https://redis.io/commands/zadd
非同期でいいね数更新するためにcountをreturnしています。

ArticleController.php
public function like(Request $request)
{
        return $this->article->like($request->article_id, $this->user->getAuth()->id);
}

このメソッドをpostでroute定義しておきます。

フロント側(Vueコンポーネント)の実装

LikeComponent.vue

<template>
<div>

<button v-on:click.prevent="like">
    いいね! 
</button>

{{ count }}

</div>


</template>
<script>
import axios from 'axios'

export default {
    name: 'app',
    props: {
        articleId: {
            type: Number,
            required: true,
            default: ''
        },
        count: {
            type: Number,
            required: true,
            default: ''
        }
    },
    data() {
        return {
            id: this.articleId,
            fav: this.count,
        };            
    },
    methods: {
        like() {
            axios.post('/articles/like', {
                article_id: this.id
            }).then((res) => {
                this.fav = res.data;
            })
        }
    }
}
</script>
index.blade.php
<div id="app">
@foreach($articles as $article)
    <div class="main-lists" id="fav">
        <img src="/article_images/{{ $article->id }}.jpg" alt="img" class="article-image">
        <div class="article-contents">
              {{ $article->title }}<br>
                    {{ $article->body }}<br>
                {{ Form::open(['route' => ['articles.show', $article->id], 'method' => 'get']) }}
                     {{ csrf_field() }}
                     {{ Form::input('hidden','article_id', $article->id) }}
                     {{ Form::submit('詳しく見る',["class"=>"button"]) }}
                {{ Form::close() }}
          </div>  
          <like-component :article-id="{{ $article->id }}" :count="{{ $likes[$article->id] }}">
     </div>  
@endforeach
</div>

axiosでapi叩いて、responseでいいね数受け取ってbindしてます。

最後に

Vue苦手だったんですけどいざ触ってみると楽で最高だー!となりました。これも30分くらいで実装できました。

9
8
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
9
8