Espere hasta que firebase haya terminado de cargar datos (vue) / 'await' no funciona

Jan 11 2021

En mi aplicación vue, estoy obteniendo algunos datos de firebase en el created-hook. Quiero que el código se ejecute después de que los datos hayan terminado de cargarse. Pero no puedo hacer que funcione.

Aquí está mi código:

<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>

Pero primero 'Done with fetching Data'se muestra la consola, luego null(porque this.settingsestá quieta null) y solo después settingsse imprime el Objekt . Pero necesito this.settingsestar definido allí (y no nullmás) para trabajar allí.

Lo que probé hasta ahora:

  1. Poner en espera
  2. Agregar un cargado parameter
  3. Añadiendo el código posteriormente en un then()

Nada funcionó.

Respuestas

3 RenaudTarnec Jan 11 2021 at 00:56

El onSnapshot()método no es un método asincrónico. Como se explica en el documento, "adjunta un oyente para DocumentSnapshoteventos".

Por lo tanto, debe usarlo si desea establecer un oyente continuo para el documento de Firestore: si algo cambia en el documento (por ejemplo, un campo obtiene un nuevo valor), el oyente se activará. Tenga en cuenta que "una llamada inicial con la devolución de llamada que proporciona crea una instantánea del documento inmediatamente con el contenido actual del documento único" (consulte el documento ).

Obtiene los datos del documento de Firestore solo en la función de devolución de llamada a la que pasa onSnapshot(), de la siguiente manera:

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

Como mencionó Nilesh Patel, tenga en cuenta que debe usar una función de flecha para usar thisen esta devolución de llamada . También tenga en cuenta que la createdfunción NO necesita ser asíncrona .

Finalmente, tenga en cuenta que es una buena práctica llamar a la función de cancelación de suscripción devuelta por onSnapshot()cuando destruye el componente Vue.js. Utilice el beforeDestroygancho de la siguiente manera:

// ...
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();
  }
},

Por otro lado, si solo desea leer los datos del documento SOLO UNA VEZ en el enlace Vue.js creado, debe usar el get()método, de la siguiente manera:

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!");
    }
}

Tenga en cuenta que, en este caso, la createdfunción NECESITA ser async, ya que get()es asíncrona.


Más detalles sobre la diferencia entre get()y onSnapshot()en esta respuesta SO .

1 NileshPatel Jan 11 2021 at 00:46

intente usar la función de flecha

  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)
  },