I have a utility function that works fine as long as I keep it in my codebase. It takes a CollectionReference
and a document id as arguments.
When I move it to a shared library I get the following error:
FirebaseError: Expected first argument to collection() to be a CollectionReference, a DocumentReference or FirebaseFirestore
The collection reference fails the instanceof
check that is done internally by firebase/firestore.
The code exported from my library is clean ESM and I have made sure that all places import from firebase/firestore
and use the same versions. So I don’t know what else I can try.
Here is the code as it is exported by the library:
import { CollectionReference, doc, getDoc } from "firebase/firestore";
import { useEffect, useState } from "react";
function useDocumentDataOnce(collectionRef, documentId) {
const [data, setData] = useState();
useEffect(() => {
const fetchData = async () => {
if (!documentId) {
return;
}
console.log(
"+++ collectionRef instanceof CollectionReference?",
collectionRef instanceof CollectionReference
);
const ref = doc(collectionRef, documentId);
const snapshot = await getDoc(ref);
if (snapshot.exists()) {
setData(snapshot.data());
} else {
throw new Error(`No document at ${collectionRef.path}/${documentId}`);
}
};
fetchData().catch(console.error);
}, [collectionRef, documentId]);
return data;
}
If I use the exact same code, but imported from my codebase it works fine:
import { CollectionReference, doc, getDoc } from "firebase/firestore";
import { useEffect, useState } from "react";
export function useDocumentDataOnce<T>(
collectionRef: CollectionReference,
documentId?: string
) {
const [data, setData] = useState<T>();
useEffect(() => {
const fetchData = async () => {
if (!documentId) {
return;
}
console.log(
"+++ collectionRef instanceof CollectionReference?",
collectionRef instanceof CollectionReference
);
const ref = doc(collectionRef, documentId);
const snapshot = await getDoc(ref);
if (snapshot.exists()) {
setData(snapshot.data() as T);
} else {
throw new Error(`No document at ${collectionRef.path}/${documentId}`);
}
};
fetchData().catch(console.error);
}, [collectionRef, documentId]); // Add ref to the dependency array
return data;
}
Here’s how the code is used on a Next.js page:
"use client";
import { db, useUserId } from "@/lib/firebase";
import { useDocumentDataOnce } from "failurebase";
import { collection } from "firebase/firestore";
type User = {
displayName: string;
};
export default function UserProfilePage() {
const userId = useUserId();
const usersCollectionRef = collection(db, "users");
const user = useDocumentDataOnce<User>(usersCollectionRef, userId);
return <div>Hello {user?.displayName ?? "unknown"}</div>;
}
You can find the library code here. As you can see I have also made firebase a peer dependency, so nothing is bundled with my library code.
The library is also published on NPM. You can install it with failurebase@next
This is driving me nuts. Any idea what might be causing this?