I have implemented a Vue composable feature that utilizes a Firebase onSnapshot
listener to track data changes.
The goal is to update a ref
called documentsArray
whenever there is a change detected by the listener.
Interestingly, when I log the contents of documentsArray
from within the onSnapshot
function, it appears to be functioning correctly as it holds an array of values. However, the issue arises when I try to log the same outside the onSnapshot
function – the array turns out to be empty.
This discrepancy raises the question: Why does the array only contain values inside the onSnapshot
function but not outside?
Ideally, the console.log statement outside the onSnapshot
function should also display the array's values.
Below is a snippet of my TypeScript Vue composable:
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;