いいね機能って実際どうやって実装するんだろう
Lodashの具体的な使い方を知りたい!
こういった方に対して書きました!
この記事を書いている私(@Shoot58153748)は、
2020年2月現在メガベンチャーの社内スタートアップの部署でエンジニア(1年目)をしており、
プログラミング未経験からメガベンチャーへの転職を成功させた経験・ノウハウ
Webエンジニアになってから学んだこと
をブログにまとめています。
前回は、Vueでの無限スクロールを実装しました。
更に実践的なアプリに踏み込んでいきましょう。
今回から2記事(フロント側実装、API実装)にわたって、いいね機能の実装をしていきます!
ぜひAPI編も一緒に参考にしてください。
今回のポイント
- font awesomeの使用
- vueでハートボタン制御
- lodashでリクエスト制御
今までのLaravelでのWebアプリ開発記事もまとめていますので、
こちらも参考にしてください!
また、ブログでは最低限必要な(更新した)部分のみ掲載するので、
全体のソースコードをみたい場合は以下にあげてあります。
Github: https://github.com/Shuto-san/laravel-vue-docker
目次
lodashとは?
値の操作など、開発に役立つ便利な関数を提供してくれるJavaScriptのライブラリです。
便利な関数の1つにdebounce
があります。
今回はこのdebounce
というリクエスト制御できる関数を使用することで、
いいね機能のリクエストを送るタイミングをコントロールします。
さて、リクエスト制御とはどういうことか。
例えば、jsのイベントをシンプルに使うと(click)
サーバー側にリクエストを送るタイミングはハートボタンのクリック時ですよね?
相手が普通の優良ユーザーだったら何も問題ありません。
常識の範囲内でいいねボタンをクリックし、
「やっぱ違う。間違えた。」
と思ったらいいねボタンを再度クリックし取り消します。
しかし、ひたすら高速にボタン連打を繰り返す変なユーザーがいたとしたらどうでしょうか?
実践的なアプリを開発する場合、常に悪意のあるユーザーを想定しなければなりません。
そのため
リクエスト内容をまとめて送る、
一定時間対象の更新が止まったらリクエストを送る
などの工夫が必要になります。debounce
を使用して、いいねボタンのリクエスト送信を
クリック時ではなくいいねボタンの操作が止まった1秒後にリクエストを送るようにします!
つまり、いいねボタンを連打しても一生送信されません。
さて、さっそく開発していきましょう!
画面イメージ
いいね機能実装例(フロント側)
今回の制作物(実装内容)は以下になります。
- ライブラリインストール
- 画面
- SCSS
- Js
前準備としてライブラリのインストールから実行していきます。
ライブラリインストール
インストールするライブラリはfont awesome
とlodash
です。lodash
は前述の通り、リクエスト制御のために使いますが、font awesome
はハートなどのアイコンを無料で使うためのライブラリです。
サイトで使用したいアイコンを探して、指定されたタグとクラスを埋め込むだけで画面にアイコンを表示することができます。
今回は、いいねのアイコンをハートにします。
それでは以下のコマンドでnpm install
// font awesome, lodashをインストール
npm install @fortawesome/fontawesome-free —save
npm i --save lodash
あとは、JSファイルでインポートしてあげればよし。
先に画面のソースコードを載せます。
画面
ファイル名:resources/views/index.blade.php
<div class="contents">
<div class="tweet-timeline">
<div class="tweet-card" v-for="tweet in tweets" :key="tweet.id" v-cloak>
<div class="tweet-contents">
<div class="tweet-contents-tweet">
<div>@{{ tweet.tweet }}</div>
</div>
<div class="tweet-contents-footer">
<i v-if="tweet.is_liked" class="fas fa-heart" @click="pushLike(tweet)"></i>
<i v-else class="far fa-heart" @click="pushLike(tweet)"></i>
</div>
</div>
</div>
</div>
<infinite-loading @infinite="fetchTweets"></infinite-loading>
</div>
<i>
タグが今回のコアな部分です。<i class="fas fa-heart">
で、font awesome
のアイコン埋め込みv-if
とv-else
部分で、未いいねといいね済の出し分けをしています。tweet.id_liked
はサーバー側から受け取るデータ(後編で実装予定)で、
すでにいいねしたツイートに関してはtrue
値が渡され、
すでにいいねを押されている状態でツイートが表示されます。
そして、@click
でクリック時に指定のメソッドpushLike
にtweet
オブジェクトを渡して
イベントを実行します。
実行内容はJsに記載します。
SASS
ファイル名:resources/sass/_tweet_style.scss
.tweet{
&-card {
width: 400px;
height: 100px;
margin: 10px;
font-size: 16px;
background-color:#fff;
border-radius:5px;
-moz-box-shadow:0 2px 2px 0 rgba(0,0,0,0.2);
-webkit-box-shadow:0 2px 2px 0 rgba(0,0,0,0.2);
box-shadow:0 2px 2px 0 rgba(0,0,0,0.2);
}
&-contents {
width: 90%;
height: 90%;
margin: auto;
display: flex;
flex-direction: column;
&-tweet {
flex-basis: 80%;
}
&-footer {
flex-basis: 20%;
}
}
}
デザインを少しだけ整えました。
ツイッターカードのようなものでツイート内容を覆ってあげるようにしました。
コピペするなりして自分の好きなようにしてください。
JS
ファイル名:resources/js/tweet.js
window._ = require('lodash');
new Vue({
el: '#tweet',
data: {
userAction: {
like: {
list: [],
debouncedList: []
},
},
},
methods: {
pushLike(tweet) {
if (this.userAction.like.list.indexOf(tweet.id) == -1) {
this.userAction.like.list.push(tweet.id);
this.newPostLike(tweet.id);
}
this.userAction.like.debouncedList[tweet.id](tweet.id, !tweet.is_liked);
tweet.is_liked = !tweet.is_liked;
},
newPostLike(tweetId) {
this.userAction.like.debouncedList[tweetId] = _.debounce(this.postLike, 1000);
},
postLike(tweetId, likePushed) {
axios.post(window.location.origin + `/tweet/like`, {
tweetId: tweetId,
likePushed: likePushed
})
.then(response => {
console.log(response);
})
.catch(error => {
console.log(error);
});
},
1行目でインストールしたlodash
を読み込みuserAction.like
のlist
とdebouncedList
という変数を準備します。
前者はいいね!ボタンが押されたツイートIDのリストを格納し、
後者はdebounce
のインスタンス(_.debounce(this.postLike, 1000
))を格納するリストです。
それぞれのツイート(いいね!ボタン)に対してインスタンスを用意してあげないと、
どのツイートに対するイベントかがごちゃごちゃになってしまうので後者のリストは重要です。debounce
メソッドは、指定のメソッド呼び出しが行われる度にタイマーをセットできます。
今回の場合は、this.postLike
の呼び出しが停止した1秒後にリクエストが送信されます。
呼び出しが起きた時点で1秒がリセットされるので、連打されていた場合、一生リクエストが飛びません。
いいね!ボタンがクリックされた時の流れは、pushLike
が実行
(いいね!ボタンが押されていないツイートに関しては、)
→ツイートIDをリストに追加
→this.newPostLike
を呼び出しdebounceのインスタンスをリストに追加
→debouncedList
に格納されたインスタンスを実行
以降、リスト化されたdebounceのインスタンスが呼び出されたら
最後に呼び出されてから1秒後にリクエストをサーバー側にプッシュする
という流れになっています。
いいね!ボタンが押下される度にボタンの出し分けを判定する変数tweet.is_liked
がtrue, falseの値を取ることで
未いいね(中身が白)、いいね済(中身が黒)を制御しています。
少々複雑な実装になりましたが、_.debounce()
の使い方と、ツイート毎のリクエストインスタンスのリスト化が鍵になってきます!
最後にnpm run dev
でSASSとJSをビルドするのを忘れずに!!
まとめ:リクエスト制御にはlodashを使ってみよう
以上、like機能のフロント側の実装でした。
今回のポイントを振り返りましょう
- font awesomeの使用
- vueでハートボタン制御
- lodashでリクエスト制御
いずれもwebアプリ開発には、欠かせない知識です。
これを機に是非ともマスターしたいですね。
Lodashの実装は少々複雑でしたが、
例えばdebounce
をリスト化せずに実行したらどんな問題が起こってしまうのか想像する、または試してみるのも手ですね!
たぶん色々なツイートを1秒以内にいいねしまくったら色々とおかしなことが起きます。
さて、次回はいいね機能のコアであるAPI実装です!
いいね機能は頻繁に書き換えられるので、Redis(Key Value Store)というインメモリDBを用いてデータを管理する手法を学べます。
Redisは現在のwebアプリ開発では必須のスキルなので、
使いこなせれば大きくレベルアップできます。
楽しみにしていてください!
それではまた!
コメント