概要
Vue.jsを使用する際、外部の通信などでPromiseを使用することはあると思います。Promiseを使用する際に、callbackで事前にComponentで定義したメソッドを使おうとしたのですが、うまく呼び出せずにはまったのでメモとして残しておきます。
はまったこと
以下のようにfirebaseにクエリを投げて、取得した内容を事前に定義したメソッドで下記のようなイメージで処理します。この際に、定義したmethodのprocessDoc
がundefinedになってしまいます。
methods: {
getFirebaseData() {
const db = firebase.firestore();
// firestoreの最新情報の取得
const docRef = db.collection("test_collection").doc("test_doc_id");
docRef
.get()
.then(function(doc) {
// 受け取ったdocの処理
this.processDoc(doc);
})
.catch(function(error) {
console.log(error);
});
},
processDoc(doc) {
// ここでデータを処理
}
}
対応
how to call a method in the Promise in Vue componentによると、コールバックの処理時に、無名関数でなくアロー関数を使う対応が挙げられています。なお、無名関数を使う場合は、事前にPromiseの外側でthisの変数を定義してから関数を呼び出す形になるそうです。アロー関数を使って下記のように書き直すと、methodの呼び出しができました。
methods: {
getFirebaseData() {
const db = firebase.firestore();
// firestoreの最新情報の取得
const docRef = db.collection("test_collection").doc("test_doc_id");
docRef
.get()
.then((doc) => {
// 受け取ったdocの処理
this.processDoc(doc);
})
.catch((error) => {
console.log(error);
});
},
processDoc(doc) {
// ここでデータを処理
}
}
なぜか
Vue.jsに書いてある「アロー関数は、this が期待する Vue インスタンスではなく・・・」とは?に解説されていますが、無名関数とアロー関数で同じ機能と思いきやthisの取り扱いが変わってきます。従来の無名関数では、「それが何を指し示すかは文脈によって変化する」、「そのメソッドにアクセスしたオブジェクト(インスタンス)が、this」となるのに対し「アロー関数は呼び出された場所をthisとする」といった違いがあります。
Promiseのコールバックにおいては、無名関数だと指し示されるオブジェクトが自分自身なので、その外のmethodが参照できないです。アロー関数だと呼び出し元からthisのスコープが引き継がれるので、methodも参照ができるわけです。