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')
问题分析与修正代码
新代码存在几个核心问题:
- 错误将
getDocs返回的查询快照传给query函数,query需要的是集合引用而非快照 - 用户ID字段使用
user?.id,和旧代码的user?.uid不一致,导致找不到对应用户文档 onSnapshot回调中直接对snapshot调用map,正确应该是snapshot.docs.map,且未将映射结果赋值给状态- 未处理
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
相关产品推荐
相关产品推荐

