Подождите, пока firebase завершит загрузку данных (vue) / 'await' не работает

Jan 11 2021

В моем приложении vue я получаю некоторые данные из firebase в created-hook. Я хочу, чтобы код выполнялся после того, как данные были загружены. Но я не могу заставить его работать.

Вот мой код:

<template>
    <div>
        <h1>Test 2</h1>
    </div>
</template>

<script>
import { institutesCollection } from '../firebase';
export default {
    name: 'Test2',
    data() {
        return {
            settings: null,
        }
    },
    async created() {
        await institutesCollection.doc('FbdYJ5FzQ0QVcQEk1KOU').onSnapshot(
            await function(doc) {
                this.settings = doc.data();
                console.log(this.settings);
            }
        )
        console.log('Done with fetching Data');
        console.log(this.settings)
    },
    methods: {
        
    }
}
</script>

Но сначала 'Done with fetching Data'отображается консоль, затем null(потому что this.settingsпо-прежнему null) и только после этого settingsпечатается объект . Но мне нужно this.settingsбыть там определенным (а не nullбольше), чтобы работать с ним.

Что я пробовал до сих пор:

  1. В ожидании
  2. Добавление загруженного parameter
  3. Добавление кода впоследствии в then()

Ничего не получилось.

Ответы

3 RenaudTarnec Jan 11 2021 at 00:56

Этот onSnapshot()метод не является асинхронным. Как объясняется в документе, он «присоединяет слушателя к DocumentSnapshotсобытиям».

Таким образом, вы должны использовать его, если хотите установить непрерывный прослушиватель для документа Firestore: если что-то изменится в документе (например, поле получит новое значение), прослушиватель будет запущен. Обратите внимание , что «первоначальный вызов , используя функцию обратного вызова , которую Вы предоставили создает документ снимок сразу с текущим содержимым отдельного документа» (см документ ).

Вы получаете данные документа Firestore только в функции обратного вызова, которую вы передаете onSnapshot(), как показано ниже:

created() {
    institutesCollection.doc('FbdYJ5FzQ0QVcQEk1KOU').onSnapshot(doc => {
           this.settings = doc.data();
           console.log(this.settings);
      });
}

Как упомянул Нилеш Патель, обратите внимание, что вам нужно использовать стрелочную функцию для использования thisв этом обратном вызове . Также обратите внимание, что createdфункция НЕ должна быть асинхронной .

Наконец, обратите внимание, что рекомендуется вызывать функцию onSnapshot()отмены подписки, возвращаемую при уничтожении компонента Vue.js. Используйте beforeDestroyкрючок следующим образом:

// ...
data() {
    return {
        settings: null,
        firestoreListener: null
    }
},
created() {
    this.firestoreListener  = institutesCollection.doc('FbdYJ5FzQ0QVcQEk1KOU').onSnapshot(doc => {
           this.settings = doc.data();
           console.log(this.settings);
      });
},
beforeDestroy() {
  if (this.firestoreListener) {
    this.firestoreListener();
  }
},

С другой стороны, если вы просто хотите прочитать данные документа ТОЛЬКО ОДИН РАЗ в созданном хуке Vue.js, вы должны использовать этот get()метод следующим образом:

async created() {
    const doc = await institutesCollection.doc('FbdYJ5FzQ0QVcQEk1KOU').get();
    if (doc.exists) {
             this.settings = doc.data();
    } else {
             // doc.data() will be undefined in this case
             console.log("No such document!");
    }
}

Обратите внимание , что в этом случае createdфункция ПОТРЕБНОСТЕЙ быть async, так как get()асинхронный.


Подробнее о разнице между get()и onSnapshot()в этом SO-ответе .

1 NileshPatel Jan 11 2021 at 00:46

попробуйте использовать функцию стрелки

  async created() {
        await institutesCollection.doc('FbdYJ5FzQ0QVcQEk1KOU').onSnapshot(
            doc => {
                this.settings = doc.data();
                console.log(this.settings);
            }
        )
        console.log('Done with fetching Data');
        console.log(this.settings)
  },