如何将 Firestore 引用传递给本地链接的模块

问题描述 投票:0回答:1

我有一个实用函数,只要我将其保留在我的代码库中,它就可以正常工作。它需要一个

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

安装它

这让我抓狂。知道是什么原因造成的吗?

javascript firebase google-cloud-firestore
1个回答
0
投票

所以我发现如果我通过 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 的库。

检查似乎主要是为了警告用户方法的无效使用,所以我认为基于对象属性进行检查应该足够了。

© www.soinside.com 2019 - 2024. All rights reserved.