You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React结合Firebase 9.x使用useEffect获取Firestore数据时的双重错误问题求助

解决React + Firebase 9页面白屏与destroy is not a function、forEach is not a function错误

问题根源分析

咱们一步步拆解你遇到的两个核心问题:

  1. Uncaught TypeError: destroy is not a function:
    这个错误是因为你直接把async函数作为useEffect的回调了。useEffect的回调要么返回一个清理函数(用于组件卸载/依赖更新时清理),要么返回undefined。而async函数默认返回Promise对象,React会把这个Promise当成清理函数去执行,自然就会报错“destroy is not a function”。

  2. Uncaught TypeError: querySnapshot.forEach is not a function:
    当你移除async/await后,getDocs是异步操作,直接调用会返回一个Promise,而不是Firestore的QuerySnapshot实例——Promise上没有forEach方法,所以报错。


分步解决方案

1. 修正useEffect的异步函数使用方式

不要直接把async作为useEffect的回调,而是在useEffect内部定义异步函数并调用:

useEffect(() => {
  // 内部创建异步函数
  const fetchSellerDetails = async () => {
    // 先判断postDetails是否存在,避免userId为undefined
    if (!postDetails?.userId) return;
    
    const usersRef = collection(firebase.firestore(), "users");
    const q = query(usersRef, where("id", "==", postDetails.userId));
    const querySnapshot = await getDocs(q);
    
    querySnapshot.forEach(doc => {
      console.log("Seller data:", doc.data());
      setUserDetails(doc.data());
    });
  };

  fetchSellerDetails(); // 调用异步函数
}, [postDetails, firebase]); // 添加依赖项

2. 修复依赖数组

之前你的依赖数组是空的[],但postDetails是从上下文获取的异步数据——如果页面初始化时postDetails还没加载完成,userId会是undefined,导致查询失败。把postDetails和firebase加入依赖数组,确保数据更新时重新执行查询。

3. 优化状态初始化与渲染安全

你初始化userDetails为空字符串"",第一次渲染时访问userDetails.username会报错(字符串没有username属性),这也是页面白屏的原因之一:

  • 把初始值改为null或空对象:
    const [userDetails, setUserDetails] = useState(null);
    
  • 渲染时用**可选链操作符?.**安全访问属性,同时添加加载提示:
    <div className="contactDetails">
      <p>Seller details</p>
      <p>{userDetails?.username || "Loading seller info..."}</p>
      <p>{userDetails?.phone || "Loading seller info..."}</p>
    </div>
    

4. 处理postDetails未加载的情况

如果postDetails是异步获取的,页面初始化时可能为undefined,直接渲染会导致postDetails.url等属性报错,所以添加加载状态:

if (!postDetails) {
  return <div className="viewParentDiv">Loading product details...</div>;
}

完整修改后的代码

import React, { useContext, useEffect, useState } from 'react';
import { FirebaseContext } from '../../store/Context';
import { collection, query, where, getDocs } from "firebase/firestore";
import './View.css';
import { PostContext } from '../../store/postContext';

function View() {
  const [userDetails, setUserDetails] = useState(null);
  const { postDetails } = useContext(PostContext);
  const { firebase } = useContext(FirebaseContext);

  useEffect(() => {
    const fetchSellerDetails = async () => {
      if (!postDetails?.userId) return;
      
      const usersRef = collection(firebase.firestore(), "users");
      const q = query(usersRef, where("id", "==", postDetails.userId));
      const querySnapshot = await getDocs(q);
      
      querySnapshot.forEach(doc => {
        setUserDetails(doc.data());
      });
    };

    fetchSellerDetails();
  }, [postDetails, firebase]);

  // 处理产品详情未加载的情况
  if (!postDetails) {
    return <div className="viewParentDiv">Loading product details...</div>;
  }

  return (
    <div className="viewParentDiv">
      <div className="imageShowDiv">
        <img src={postDetails.url} alt={postDetails.name} />
      </div>
      <div className="rightSection">
        <div className="productDetails">
          <p>&#x20B9; {postDetails.price}</p>
          <span>{postDetails.name}</span>
          <p>{postDetails.category}</p>
          <span>{postDetails.createdAt}</span>
        </div>
        <div className="contactDetails">
          <p>Seller details</p>
          <p>{userDetails?.username || "Loading seller info..."}</p>
          <p>{userDetails?.phone || "Loading seller info..."}</p>
        </div>
      </div>
    </div>
  );
}

export default View;

额外提示

  • 你导入的'firebase/compat/firestore'可以删掉,因为已经用了Firebase 9的模块化API,不需要兼容模式。
  • 确保Firestore中users集合的id字段和postDetails.userId完全匹配(比如都是字符串类型,值一致),否则查询会返回空结果。

内容的提问来源于stack exchange,提问作者Sojo C Johny

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 17:42:33