Vue.jsとFirebaseを利用して、Cloud Firestore からデータを読み込んで初期表示させたかったが、上手く初期表示できず苦しんだのでメモ。
事象
データベース(Firebase)から取得したデータを、Vue.jsの"Test[0]"と"Test[1]"に入れて表示させたかったが、何故か表示がされなかった。コンソールで見るとちゃんとデータは取得出来ているのに、、謎。
取り敢えずv-ifのレンダリングで無理やり解決させた。データベースに保存した内容が表示される。
v-ifの再レンダリングで無理やり解決したコード
無理やり解決させた時の全体コードを書いておく。(あまり良くない解決の仕方ではあると思う。)
.html
<!DOCTYPE html>
<html lang="jp" >
<head>
<meta charset="UTF-8">
<title>Vuejs Rerender</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<!-- 全体をVue.js有効にする -->
<div id="app" v-if="Show === 1">
<input v-model="Test[0]">
<input v-model="Test[1]">
</div>
<script src='https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/firebase/8.0.1/firebase.js'></script>
<script>
// Your web app's Firebase configuration
var firebaseConfig = {
apiKey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
authDomain: "xxxx.firebaseapp.com",
databaseURL: "https://xxxx.firebaseio.com",
projectId: "xxxx",
storageBucket: "xxxx.appspot.com",
messagingSenderId: "999999999999",
appId: "1:999999999999:web:xxxxxxxxxxxxxxxxxxxxxx"
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
const db = firebase.firestore();
const app = new Vue({
el: '#app', // Vueが管理する一番外側のDOM要素
data: {
// Vue内部で利用する変数定義
Test: ["0000","1111"],
Show: 0, // 再レンダリング用
},
created: async function (){
// Firebaseから初期値を読み込み
await this.FirebaseSet();
console.log(`Test[0]:${this.Test[0]},Test[1]:${this.Test[1]}`);
// 上手いこと初期表示できないから無理やりレンダリング
this.Show = 1;
},
methods: {
// 関数はココに記述
FirebaseSet: async function() {
// CloudFirestoreからデータ取得
let docRef = db.collection("hpcaccede").doc("User01");
let me = this; // thisを関数内で使えないので変数に代入
await docRef.get().then(function(doc) {
if (doc.exists) {
me.Test[0] = doc.data().test1;
me.Test[1] = doc.data().test2;
} else {
console.log("No such Cloud Firestore document!");
}
});
},
},
});
</script>
</body>
</html>
ポイント
全体に対して、v-ifで再レンダリングさせる。
.html
<div id="app" v-if="Show === 1">
"Show"変数の初期値は"0"として非表示。
.js
const app = new Vue({
el: '#app',
data: {
Test: ["0000","1111"],
Show: 0, // 再レンダリング用
},});
"created"の最後に"this.Show"を"1"に更新して、再レンダリングさせる。
.js
created: async function (){
await this.FirebaseSet();
console.log(`Test[0]:${this.Test[0]},Test[1]:${this.Test[1]}`);
// 上手いこと初期表示できないから無理やりレンダリング
this.Show = 1;
},
原因と思われる個所を特定した
色々切り分けていくと、配列が悪さをしているっぽいことが判明。
vue.jsのルールなのか、私の書き方が悪いのかは知らんけど、Test配列を止めたら再レンダリングせずに上手く表示できた。(body要素内だけ記述しておく。)
.html
<body>
<!-- 全体をVue.js有効にする -->
<div id="app">
<input v-model="Test0">
<input v-model="Test1">
</div>
<script src='https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/firebase/8.0.1/firebase.js'></script>
<script>
// Your web app's Firebase configuration
var firebaseConfig = {
apiKey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
authDomain: "xxxx.firebaseapp.com",
databaseURL: "https://xxxx.firebaseio.com",
projectId: "xxxx",
storageBucket: "xxxx.appspot.com",
messagingSenderId: "999999999999",
appId: "1:999999999999:web:xxxxxxxxxxxxxxxxxxxxxx"
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
const db = firebase.firestore();
const app = new Vue({
el: '#app', // Vueが管理する一番外側のDOM要素
data: {
// Vue内部で利用する変数定義
Test0: "0000",
Test1: "1111",
//Show: 0, // 再レンダリング用
},
created: async function (){
// Firebaseから初期値を読み込み
await this.FirebaseSet();
//console.log(`Test[0]:${this.Test[0]},Test[1]:${this.Test[1]}`);
console.log(`Test0:${this.Test0},Test1:${this.Test1}`);
// 上手いこと初期表示できないから無理やりレンダリング
// this.Show = 1;
},
methods: {
// 関数はココに記述
FirebaseSet: async function() {
// CloudFirestoreからデータ取得
let docRef = db.collection("hpcaccede").doc("User01");
let me = this; // thisを関数内で使えないので変数に代入
await docRef.get().then(function(doc) {
if (doc.exists) {
// me.Test[0] = doc.data().test1;
// me.Test[1] = doc.data().test2;
me.Test0 = doc.data().test1;
me.Test1 = doc.data().test2;
} else {
console.log("No such Cloud Firestore document!");
}
});
},
},
});
</script>
</body>