Firebase Firestore setDoc() Promise无法解析问题求助
问题描述
按照Firestore官方文档搭建并使用Firestore,在Next.js框架下调用createProductEntry函数后,代码中的两个console.log()均无输出,数据库也没有新增数据,表现为Promise既不解析也不拒绝。
相关代码
product.firebase.ts
import { doc, getFirestore, setDoc } from 'firebase/firestore'; import { initialize } from '@/lib/firebase.lib'; import { randomString } from '../utils'; export interface IFirebaseProduct { name: string; } export function isFirebaseProduct(obj: any): obj is IFirebaseProduct { return "name" in obj; } export async function createProductEntry(entry: IFirebaseProduct){ const app = initialize(); const db = getFirestore(app); const id: string = randomString(20, 'a'); await setDoc(doc(db, 'products', id), entry).then(() => console.log("Added item: ", entry)); }
page.tsx
"use client"; import { IFirebaseProduct, createProductEntry, } from "@/lib/firebase/product.firebase"; import { useState } from "react"; export default function AddProduct() { const [input, setInput] = useState<string>(""); const sendData = (entry: IFirebaseProduct) => { try { createProductEntry(entry).then(() => console.log("Added item: ", entry)); } catch (error) { console.log(error); } }; return ( <> <input type="text" placeholder="name" onChange={(e) => { setInput(e.target.value); console.log(input); }} ></input> <button onClick={() => sendData({ name: input })}>Submit</button> </> ); }
initialize函数(firebase.lib.ts)
export function initialize() { const app = initializeApp(firebaseConfig); if (typeof window !== "undefined") { // Enable analytics if ("measurementId" in firebaseConfig && app.options.projectId) { getAnalytics(app); getPerformance(app); } } console.log("Firebase succesfully initialized."); return app; }
问题原因及解决方案
1. Firebase重复初始化导致未捕获错误
每次调用createProductEntry都会执行initialize(),而initialize()每次都会调用initializeApp(firebaseConfig)。Firebase不允许重复初始化同名(默认是[DEFAULT])的应用,这会抛出Firebase: Firebase App named '[DEFAULT]' already exists错误,但该错误没有被正确捕获,导致后续的setDoc代码无法执行,Promise处于未处理的拒绝状态,因此没有任何输出。
解决方案:修改initialize()为单例模式,先检查是否已存在应用实例,再决定是否初始化:
import { initializeApp, getApps, getApp } from "firebase/app"; export function initialize() { // 检查是否已有初始化的App实例 if (!getApps().length) { const app = initializeApp(firebaseConfig); if (typeof window !== "undefined") { if ("measurementId" in firebaseConfig && app.options.projectId) { getAnalytics(app); getPerformance(app); } } console.log("Firebase successfully initialized."); return app; } // 返回已存在的App实例 return getApp(); }
2. 异步错误未被正确捕获
sendData函数中使用try/catch包裹createProductEntry的调用,但createProductEntry是异步函数,直接调用而不使用await的话,try/catch无法捕获其内部的异步错误,错误只能通过.catch()方法捕获。
解决方案:改用await配合try/catch处理异步错误:
const sendData = async (entry: IFirebaseProduct) => { try { await createProductEntry(entry); console.log("Added item: ", entry); } catch (error) { console.error("Error adding product:", error); } };
或者在.then()后添加.catch()捕获错误:
const sendData = (entry: IFirebaseProduct) => { createProductEntry(entry) .then(() => console.log("Added item: ", entry)) .catch(error => console.error("Error adding product:", error)); };
3. 额外提示:React状态更新的异步性
onChange事件中的console.log(input)输出的是更新前的旧值,因为setState是异步操作。如果需要查看最新的输入值,可以直接打印e.target.value:
onChange={(e) => { setInput(e.target.value); console.log(e.target.value); // 输出最新值 }}
总结
核心问题是Firebase应用重复初始化导致未捕获的错误,以及异步错误处理不当。修复这两个问题后,数据写入和日志输出应该能正常工作。
内容的提问来源于stack exchange,提问作者stealing_society

