Home > OS >  How to update a Vue "ref" with Firebase "onSnapshot" listener values?
How to update a Vue "ref" with Firebase "onSnapshot" listener values?

Time:12-06

I have a Vue composable that uses a Firebase onSnapshot listener.

When data changes on that listener I want it to update a ref named documentsArray.

When I console.log the documentsArray inside the onSnapshot function it seems to be working because it contains an array of values. But when I console.log outside the onSnapshot function the array is empty.

Why is this happening?

The console.log outside the onSnapshot function should also contain the array of values.

Here is my composable (I am using TypeScript):

import { ref, Ref, watchEffect } from "vue";
import { projectFirestore } from "@/firebase/config";
import {
  collection,
  query,
  orderBy,
  onSnapshot,
  DocumentData,
  Timestamp,
} from "firebase/firestore";

interface Document {
  id: string;
  message: string;
  name: string;
  createdAt: Timestamp;
}

const getCollection = (
  collectionString: string
): {
  documentsArray: Ref<Document[] | null>;
  error: Ref<string | null>;
} => {
  const documentsArray = ref<Document[] | null>(null);
  const error = ref<string | null>(null);
  const colRef = collection(projectFirestore, collectionString);
  const colRefOrdered = query(colRef, orderBy("createdAt"));

  const unsubscribe = onSnapshot(
    colRefOrdered,
    (snap) => {
      const results: Document[] = [];
      snap.docs.forEach((doc: DocumentData) => {
        doc.data().createdAt && //Ensures the server timestamp has been added
          results.push({
            ...doc.data(),
            id: doc.id,
          });
      });
      documentsArray.value = results;
      console.log("documentsArray.value inside snapshot", documentsArray.value); //<-- This works. It prints an array of documents.
      error.value = null;
    },
    (err) => {
      console.log(err.message);
      documentsArray.value = null;
      error.value = "could not fetch data";
    }
  );
  watchEffect((onInvalidate) => {
    onInvalidate(() => {
      unsubscribe();
    });
  });
  console.log("documentsArray.value outside snapshot", documentsArray.value); //<-- This does not work. It prints an empty array.
  return { documentsArray, error };
};

export default getCollection;

CodePudding user response:

The code inside the onSnapshot callback is run asynchronously (after running the code outside the callback), in order to see the changes outside function you've to create a watcher to see that changes:

import import { ref, Ref, watchEffect, watch } from "vue";

....
  const unsubscribe = onSnapshot(
    colRefOrdered,
    (snap) => {
      ...
  );

watch(documentsArray,(newVal,oldVal){
  console.log("documentsArray.value outside snapshot", documentsArray.value);

},{deep:true})
  • Related