我有一个实用函数,只要我将其保留在我的代码库中,它就可以正常工作。它需要一个
CollectionReference
和一个文档 ID 作为参数。
当我将其移动到共享库时,出现以下错误:
FirebaseError:预计 collection() 的第一个参数是 CollectionReference、DocumentReference 或 FirebaseFirestore
集合引用未通过 firebase/firestore 内部完成的
instanceof
检查。
从我的库导出的代码是干净的 ESM,并且我已确保所有位置都从
firebase/firestore
导入并使用相同的版本。所以我不知道我还能尝试什么。
这是库导出的代码:
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;
}
如果我使用完全相同的代码,但从我的代码库导入它工作正常:
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;
}
以下是在 Next.js 页面上使用代码的方式:
"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>;
}
“使用客户端”指令使该页面仅在浏览器中的客户端运行。
错误来自
useDocumentDataOnce
中的这一行:
const ref = doc(collectionRef, documentId);
在 firebase-js-sdk 库中,它归结为对 reference.ts 第 578 行的检查:
if (
!(parent instanceof DocumentReference) &&
!(parent instanceof CollectionReference)
) {
throw new FirestoreError(
Code.INVALID_ARGUMENT,
'Expected first argument to collection() to be a CollectionReference, ' +
'a DocumentReference or FirebaseFirestore'
);
}
您可以在此处找到库代码。正如您所看到的,我还使 firebase 成为对等依赖项,因此我的库代码中没有捆绑任何内容。
该库也发布在 NPM 上。您可以使用
failurebase@next
安装它
这让我抓狂。知道是什么原因造成的吗?
所以我发现如果我通过 NPM 发布并安装我的模块,它就可以工作。
问题并非 Firebase 特有,而是本地开发模块时 P(NPM) 链接的工作方式。如果您使用正常链接,Firebase 内部使用的
instanceof
检查将会失败。
我将一个
CollectionReference
实例穿过模块边界传递给 doc()
,并且该函数的检查失败,因为两个模块都引用了不同的类原型。
我尝试过
(p)npm link
以及 (p)npm add ../path/to/local/module
,它在 package.json 中创建了 file:
链接。通过这两种方法,instanceof
都会返回false
。
解决方案是使用yalc,幸运的是这很简单。
另一个解决方案是 Firebase 团队将
instanceof
检查替换为对对象属性的基本检查。我认为这是更好的选择,因为它可以让人们更轻松地开发基于 Firebase 的库。
检查似乎主要是为了警告用户方法的无效使用,所以我认为基于对象属性进行检查应该足够了。