理系公務員のプログラミング日記

Vue3でTwitterクローンを作る その1

タグ:
vue3
授業課題の解説

Twitterクローンを作ろう!

誰もが使ったことがある(はずの)Twitterのクローンアプリを作成して、Vue.jsの理解をより深めていきます。

TwitterのようなSNSはほどほどに複雑ですが、手を出せないほど難しいわけではありません。なので実力アップには最適だと思います。

最初はシンプルに1人のユーザーが独り言を呟くアプリという設定で作っていきます。

FormからAppにツイートのデータをオブジェクトとして渡す

App以外にFormとTweetsというコンポーネントを作り、Formで入力フォームからツイートを入力させます。

「ツイートする」ボタンを押すと、clickイベントにより$emitを動作させて、親コンポーネントのAppにツイートのデータを渡します。

ここで、ツイートのデータをTweetObjというオブジェクトに設定しました。こうすることで、後からユーザーのデータを追加したいなどの修正に対応しやすくなります。

TweetObjは最終的にバックエンド側でデータベースに接続することを念頭に主キーとなるtweet_idと ツイートの本文であるtweet_bodyを持たせました。

このほかにBootStrapが、public/index.htmlで読み込んであります。

App.vue

<template> <div class="wrapper"> <h2 class="text-success">Twitter-Vue3</h2> <div class="content"> <Form v-on:tweet-event="tweetAction" /> <Tweet /> </div> </div> </template> <script> import Form from "./components/Form.vue"; import Tweet from "./components/Tweet.vue"; export default { name: "App", components: { Form, Tweets, }, methods: { tweetAction(TweetObj){ console.log(TweetObj) } } }; </script> <style> .wrapper { width: 60%; margin: 20px auto; } .content { margin: 20px auto; width: 100%; } </style>

Form.vue

<template> <div class="form form-group"> <textarea name="form" id="" class="form-control" cols="60" rows="5" placeholder="いまなにしてる?" v-model="TweetObj.tweet_body" ></textarea> <br/> <button class="text-white bg-success" v-on:click="doTweet">ツイートする</button> </div> </template> <script> export default { name:"Form", data(){ return{ TweetObj:{ tweet_id:0, tweet_body:'' }, } }, methods: { doTweet(){ this.TweetObj.tweet_id += 1 this.$emit('tweet-event',this.TweetObj) }, }, } </script>

twittervue1

AppからTweetツイートのデータをオブジェクトの配列として渡す

AppコンポーネントにAllTweetという配列を作りました。Array.of()によって初回に表示するダミーデータを持った配列です。

Formコンポーネントから受け取るTweetObjをこの配列にpush()メソッドによって追加していきます。

また、この配列をv-forを使って分解し、子のTweetコンポーネントに渡していきます。

TweetコンポーネントではBootStrapを使って、idを上に本文を下に表示させています。

ただし、この実装では画像の通りバグがあります。

App.vue

<template> <div class="wrapper"> <h2 class="text-success">Twitter-Vue3</h2> <div class="content"> <Form v-on:tweet-event="tweetAction" /> <div style="margin-top:20px"> <Tweet v-for="Tweet in AllTweet" v-bind:TweetObj="Tweet" v-bind:key="Tweet.tweet_id" /> </div> </div> </div> </template> <script> import Form from "./components/Form.vue"; import Tweet from "./components/Tweet.vue"; export default { name: "App", components: { Form, Tweet, }, data() { return { AllTweet: Array.of({ tweet_id: 0, tweet_body: "はじめてのツイート", }), }; }, methods: { tweetAction(TweetObj) { this.AllTweet.push(TweetObj); }, }, }; </script> // 略

Tweets.vue

<template> <div class="card"> <div class="card-header"> {{ TweetObj.tweet_id }} </div> <div class="card-body"> <div class="card-text">{{ TweetObj.tweet_body }}</div> </div> </div> </template> <script> export default { name: "Tweet", props: { TweetObj: Object, }, }; </script>

twittervue2

オブジェクトの参照渡しを値渡しに変更する

画像の通り、新しい呟きを追加するとこれまでのデータも最新のものに置き換わってしまいます。

これはFormコンポーネントで親にオブジェクトをそのまま渡しているのが原因です。

これはオブジェクトの参照渡しという現象です。詳細は省きます。

オブジェクトを値渡しにするために、assign()というメソッドを使うようにFormコンポーネントを修正します。

Form.vue

// 略 methods: { doTweet(){ this.TweetObj.tweet_id += 1 // 値渡しするために、新しいオブジェクトを定義する const tweet = Object.assign({},this.TweetObj) this.$emit('tweet-event',tweet) }, },

twittervue3

続きます。