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

Firebase v9模块化迁移:读取映射数据时报错Cannot read properties of undefined

Firebase v8迁移v9后无法读取并映射订单数据

我将代码从Firebase v8迁移至v9模块化版本,目前可向Firestore写入数据,但无法读取并映射订单数据。数据库存储结构为:users >> user.uid >> orders >> paymentIntent.id,每个文档包含amount、购物车数据(basket data)、created字段。当前控制台报错:Cannot read properties of undefined (reading 'indexOf')。

旧代码(Firebase v8)

useEffect(() => {
    if (user) {
      db.collection("users")
        .doc(user?.uid)
        .collection("orders")
        .orderBy("created", "desc")
        .onSnapshot((snapshot) => {
          // console.log(snapshot);
          setOrders(
            snapshot.docs.map((doc, i) => ({
              key: { i },
              id: doc.id,
              data: doc.data(),
            }))
          );
        });
    } else {
      setOrders([]);
    }
  }, [user]);

Firestore数据结构

数据层级为:users集合 → 用户UID文档 → orders集合 → 以paymentIntent.id命名的文档,每个文档包含amount、购物车数据、created字段。

新代码(Firebase v9)

import { collection, doc, getDoc, getDocs, onSnapshot, orderBy, query } from 'firebase/firestore';
import React, { useEffect, useState } from 'react'
import { db } from './firebase';
import './Orders.css'
import { useStateValue } from './StateProvider';
import Order from './Order';

function Orders() {
  const [{ basket, user}, dispatch] = useStateValue();
  const [orders, setOrders] = useState([]);


useEffect(() => {
  const getDocs = async () => {
    try {
      const collRef = await getDocs(collection(db, "users", user?.id, "orders"));
      // const collRef = doc(db, "users", user?.id, "orders"));
      // const collRef = collection(db, "users", user?.id, "orders"));

      const orderedRef = query(collRef, orderBy("created", "desc"));
      const docSnap = onSnapshot(orderedRef, (snapshot) => {
        snapshot.map((doc) => ({
          id: doc.id,
          data: doc.data(),
        }));
        setOrders(docSnap);
      });
    } catch (err) {
      console.log(err.message);
    }
  };
  getDocs();
}, [user]);

  return (
    <div className="orders">
      <h3>Your Orders</h3>
      <div className="orders__order">
        {orders?.map((order, i) => (
          <Order key={i} order={order} />
        ))}
      </div>
    </div>
  );
}

export default Orders;

控制台报错

Cannot read properties of undefined (reading 'indexOf')


问题分析与修正代码

新代码存在几个核心问题:

  1. 错误将getDocs返回的查询快照传给query函数,query需要的是集合引用而非快照
  2. 用户ID字段使用user?.id,和旧代码的user?.uid不一致,导致找不到对应用户文档
  3. onSnapshot回调中直接对snapshot调用map,正确应该是snapshot.docs.map,且未将映射结果赋值给状态
  4. 未处理user为空的场景,且没有取消订阅的逻辑

修正后的代码

import { collection, onSnapshot, orderBy, query } from 'firebase/firestore';
import React, { useEffect, useState } from 'react'
import { db } from './firebase';
import './Orders.css'
import { useStateValue } from './StateProvider';
import Order from './Order';

function Orders() {
  const [{ basket, user}, dispatch] = useStateValue();
  const [orders, setOrders] = useState([]);

  useEffect(() => {
    let unsubscribe;
    if (user) {
      // 创建orders集合引用
      const ordersRef = collection(db, "users", user.uid, "orders");
      // 创建带排序规则的查询
      const orderedQuery = query(ordersRef, orderBy("created", "desc"));
      // 订阅快照更新,实时同步数据
      unsubscribe = onSnapshot(orderedQuery, (snapshot) => {
        const mappedOrders = snapshot.docs.map((doc, i) => ({
          key: i,
          id: doc.id,
          data: doc.data(),
        }));
        setOrders(mappedOrders);
      });
    } else {
      // 用户未登录时清空订单列表
      setOrders([]);
    }

    // 组件卸载时取消订阅,避免内存泄漏
    return () => unsubscribe && unsubscribe();
  }, [user]);

  return (
    <div className="orders">
      <h3>你的订单</h3>
      <div className="orders__order">
        {orders?.map((order) => (
          <Order key={order.id} order={order} />
        ))}
      </div>
    </div>
  );
}

export default Orders;

内容的提问来源于stack exchange,提问作者Faisal Nazir

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 03:45:42