質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Vue.js

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

Firebase

Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

Q&A

解決済

1回答

3134閲覧

【Vue+Firestore】データの変更をリアルタイムに表示

CoAT.Yuki

総合スコア12

Vue.js

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

Firebase

Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

0グッド

0クリップ

投稿2019/11/10 00:25

前提・実現したいこと

vueとfirestoreで、簡単なタスク管理システムを作っています。
主に下記のような機能があります。
0. ログイン
0. サインアップ
0. ログアウト
0. [問題箇所!] タスクリストのリアルタイム表示
0. 追加・削除

発生している問題

今回は4番目の機能に問題があり下記が大まかな流れです。
イメージ説明

ポイント:

  • 最初に表示されるデータは、問題なし
  • 追加 / 削除が実行されると、しっかりリアルタイムに反映される
  • だが追加 / 削除前のリストの状態も消えずに残る。。。

リアルタイム表示機能は主に2つのファイルから構成
0. projectList.vue:タスクリストを表示させるコンポーネント
0. projectCard.vue:各タスク情報を表示するコンポーネント

該当のソースコード:projectList.vue リストのリアルタイム表示

vue

1<template> 2 <div class="projectList"> 3 <button class="home-buttons" @click="newProject">Add project</button> 4 <div v-if="createNew"> 5 <projectAdd/> 6 </div> 7 <div v-show="loading"> 8 <Loader/> 9 </div> 10 <div v-show="!loading"> 11 12 <!--03 ここで取得したデータをprojectCard.vueへ渡し、リスト表示させます--> 13 <projectCard v-for="project in projects" :key="project.id" :project="project"/> 14 15 </div> 16 <p v-show="noproject">There is no project</p> 17 </div> 18 19</template> 20 21<script> 22import firebase from '@/firebase/firestore'; 23import Loader from '@/components/loading.vue'; 24import projectCard from '@/components/projectCard.vue'; 25import projectAdd from '@/components/addProject.vue'; 26 27export default { 28 components: { 29 projectCard, 30 Loader, 31 projectAdd, 32 }, 33 data() { 34 return { 35 userid: this.$route.params.userId, 36 37 //02 ここに取得したデータが格納されます 38 projects: [], 39 40 loading: true, 41 createNew: false, 42 }; 43 }, 44 created() { 45 //01 データをリアルタイムに取得し、projectsに渡す 46 const db = firebase.firestore() 47 .collection('user') 48 .doc(this.userid) //$route.params.userId 49 .collection('projects') 50 .orderBy('createdAt', 'desc'); 51 db 52 .onSnapshot((querySnapshot) => { 53 querySnapshot.forEach((doc) => { 54 this.projects.push(doc.data()); 55 }); 56 if (this.projects.length >= 0) { 57 this.loading = false; 58 } else if (this.projects.length <= 0) { 59 this.loading = false; 60 } 61 }); 62 }, 63 methods: { 64 newProject() { 65 if (this.createNew !== true) { 66 this.createNew = true; 67 } else { 68 this.createNew = false; 69 } 70 }, 71 }, 72}; 73</script> 74

該当のソースコード:projectCard.vue 各タスクデータの受け皿

vue

1<template> 2 <div class="projectCard"> 3 <div class="user-list"> 4 <div class="columns"> 5 <div class="column is-8"> 6 <h3>{{ project.projectname }}</h3> 7 <p>{{ project.slug }}</p> 8 <p>Why : {{ project.why }}</p> 9 <p>{{ project.phase }}</p> 10 </div> 11 <div class="column is-4 right"> 12 <router-link class="button is-primary" :to="{ name: 'viewproject', params: { projectId: project.slug }}"> 13 Find out more! 14 </router-link> 15 <button @click="deleteProject"> Delete </button> 16 </div> 17 </div> 18 </div> 19 </div> 20</template> 21 22<script> 23import firebase from '@/firebase/firestore'; 24 25export default { 26 name: 'ProjectCard', 27 props: { 28 // ここは親コンポーネントであるprojectList.vueから渡されたデータが格納されている(はず?) 29 project: Object, 30 }, 31 methods: { 32 //タスクの削除 33 deleteProject() { 34 firebase.firestore().collection('user').doc(this.project.userId) 35 .collection('projects') 36 .where('slug', '==', this.project.slug) 37 .get() 38 .then((snapshot) => { 39 snapshot.forEach((doc => { 40 console.log(doc.data().slug); 41 doc.ref.delete(); 42 alert('You have deleted the project!' + doc.data().slug); 43 })) 44 }) 45 }, 46 }, 47 48}; 49 50</script> 51 52<style lang="scss" scoped> 53 h1 { 54 font-size: 30px; 55 margin: 30px 0; 56 } 57 .user-list { 58 text-align: center; 59 margin-top: 30px; 60 background-color: rgb(252, 252, 252); 61 padding: 20px; 62 box-shadow: 0 0 5px 0 rgba(0,0,0,0.05); 63 .column { 64 height: 95px; 65 } 66 .inner { 67 .left { 68 width: 50%; 69 float: left; 70 text-align: left; 71 } 72 .right { 73 width: 50%; 74 float: left; 75 text-align: left; 76 p { 77 width: 100%; 78 text-align: left; 79 } 80 } 81 } 82 .right { 83 display: flex; 84 align-items: center; 85 justify-content: center; 86 button { 87 background: #4B75FF; 88 } 89 } 90 .user-list__header { 91 font-size: 20px; 92 font-weight: 700; 93 } 94 .user-list__sub { 95 font-size: 15px; 96 margin-top: 10px; 97 } 98 } 99</style> 100

試したこと

ページを手動でリフレッシュすれば、更新前の状態は消えて、タスクリストは正常に表示されます。
ですが、せっかくリアルタイムに反映させる機能を追加したのに、、、と思ってしまいます。。。
set Vue() new Vue()で解決できるという記事をみて試したのですが、うまく行かず。。。
どなたか、是非ご教授お願いいたします!

補足情報:タスク追加のソースコード

タスク追加は主に2つのファイルから構成
0. addProject.vue : projectList.vue内で表示
0. addProject.js

addProject.vue:追加するタスクを入力するコンポーネント

vue

1<template> 2 <div id="addProject"> 3 <div class="user-list"> 4 <div class="columns"> 5 <div class="column is-8"> 6 <form @submit.prevent="saveContact"> 7 <div class="field"> 8 <label class="label">Project Name</label> 9 <div class="control"> 10 <input v-model="projectname" class="input" type="text" placeholder="Project Name" required> 11 </div> 12 </div> 13 14 <div class="field"> 15 <label class="label">Why do you work on this?</label> 16 <div class="control"> 17 <textarea v-model="why" class="input" placeholder="Why?" required /> 18 </div> 19 </div> 20 21 <div class="field"> 22 <label class="label">Where are you at?</label> 23 <div class="control"> 24 <select v-model="phase" required> 25 <option disabled value=""> 26 Project Stage 27 </option> 28 <option>A</option> 29 <option>B</option> 30 <option>C</option> 31 </select> 32 </div> 33 </div> 34 <div class="field"> 35 <div class="control"> 36 <button @click="add"> 37 Add Project! 38 </button> 39 </div> 40 </div> 41 </form> 42 </div> 43 </div> 44 </div> 45 </div> 46</template> 47 48<script> 49import firebase from '@/firebase/firestore'; 50import addProject from '@/js/addProject.js'; 51 52export default { 53 name: 'NewProject', 54 data() { 55 return { 56 createdAt: new Date(), 57 userId: firebase.auth().currentUser.uid, 58 projectname: null, 59 why: null, 60 phase: null, 61 }; 62 }, 63 methods: { 64 add() { 65 addProject.addProject(this.createdAt, this.userId, this.projectname, this.why, this.phase); 66 }, 67 }, 68}; 69</script> 70 71<style lang="scss" scoped> 72#addProject{ 73 text-align: center; 74 margin-top: 65px; 75} 76h1 { 77 font-size: 30px; 78 margin: 30px 0; 79 } 80 .user-list { 81 text-align: center; 82 margin-top: 30px; 83 background-color: rgb(252, 252, 252); 84 padding: 20px; 85 box-shadow: 0 0 5px 0 rgba(0,0,0,0.05); 86 .column { 87 height: 195px; 88 } 89 .inner { 90 .left { 91 width: 50%; 92 float: left; 93 text-align: left; 94 } 95 .right { 96 width: 50%; 97 float: left; 98 text-align: left; 99 p { 100 width: 100%; 101 text-align: left; 102 } 103 } 104 } 105 .right { 106 display: flex; 107 align-items: center; 108 justify-content: center; 109 button { 110 background: #4B75FF; 111 } 112 } 113 .user-list__header { 114 font-size: 20px; 115 font-weight: 700; 116 } 117 .user-list__sub { 118 font-size: 15px; 119 margin-top: 10px; 120 } 121 } 122</style>

addProject.js:Firesotreに追加データを送る機能

js

1import firebase from '@/firebase/firestore'; 2 3export default { 4 addProject(createdAt, userId,projectname,why,phase){ 5 const db = firebase.firestore().collection("user") 6 .doc(userId).collection("projects"); // "Project"という名前のコレクションへの参照を作成 7 db.add({ 8 createdAt: createdAt, 9 userId: userId, 10 projectname: projectname, 11 why: why, 12 phase: phase, 13 slug: this.generateUUID(), 14 }) 15 .then(function (docRef) { 16 console.log('Document written with ID: ', docRef.id); 17 alert('Well done! You have created a new project!'); 18 }) 19 .catch(function (error) { 20 console.error('Error adding document: ', error); 21 }); 22 }, 23 generateUUID() { 24 let d = new Date().getTime(); 25 let uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { 26 let r = (d + Math.random() * 16) % 16 | 0; 27 d = Math.floor(d / 16); 28 return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16); 29 }); 30 return uuid; 31 }, 32};

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

自己解決

解決方法:スナップショット間の変更の表示

この問題は、リスナーがトリガーされるたびに、毎回 this.projects.push(doc.data()); がトリガーされ、projects = [];へ、最新のリストごと入れ替えではなく追加されていることが問題でした。

解決方法として、実際にあった変更ごとに、変更されたデータそのものを、そのまま表示する、という方法です。

参考:https://firebase.google.com/docs/firestore/query-data/listen#view_changes_between_snapshots

vue

1db 2 .onSnapshot((querySnapshot) => { 3 querySnapshot.docChanges().forEach((change) => { 4 if (change.type === "added") { 5 this.projects.push(change.doc.data()); 6 } 7 //.... 8 }); 9 //.... 10 });

投稿2019/11/11 01:36

CoAT.Yuki

総合スコア12

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問