Firebase加载场景下页面刷新后购物车数据丢失问题求助
问题:页面刷新后购物车数据无法显示(Firebase加载延迟导致)
从Firebase加载数据时,页面刷新会出现加载延迟,导致购物车无法展示已添加的商品数据。但用相同流程存储用户数据时功能正常,控制台能正常获取注册用户信息,需要解决购物车数据刷新后不显示的问题。
商品添加到购物车的组件代码
import { motion } from "framer-motion"; import React, { useEffect, useRef, useState } from "react"; import { MdShoppingBasket } from "react-icons/md"; import { actionType } from "../context/reducer"; import { useGlobalState } from "../context/stateProvider"; import NotFound from "../img/NotFound.svg"; const RowContainer = ({ flag, data, scrollValue }) => { const [{ cartItems }, dispatch] = useGlobalState(); const [items, setItems] = useState([]); const rowContainer = useRef(); const addToCart = () => { dispatch({ type: actionType.SET_CARTITEMS, cartItems: items, }); localStorage.setItem("cartItems", JSON.stringify(items)); }; useEffect(() => { addToCart(); }, [items]); useEffect(() => { rowContainer.current.scrollLeft += scrollValue; }, [scrollValue]); return ( <div ref={rowContainer} className={`w-full my-12 flex items-center ${ flag ? "overflow-x-scroll scrollbar-none scroll-smooth" : "overflow-x-hidden flex-wrap justify-center" }`} > {data && data.length > 0 ? ( data.map((item) => { const { id, price, imageURL, calories, title } = item; return ( <div key={id} className="w-350 min-w-[300px] md:min-w-[380px] md:my-10 backdrop-blur-lg mx-1 my-2 lg:mx-2 " > <div className="w-full flex flex-row items-center justify-between bg-white rounded-lg drop-shadow-lg py-2 px-4 hover:bg-whiteAlpha min-h-[150px]"> <motion.img whileHover={{ scale: 1.2 }} src={imageURL} alt="img" className="w-30 max-h-40 -mt-8 duration-100 drop-shadow-2xl" /> <div className="flex flex-col items-end justify-end gap-4"> <motion.div whileTap={{ scale: 0.75 }} className="w-8 h-8 rounded-md bg-orange-500 hover:bg-orange-600 " onClick={() => setItems([...new Set(cartItems), item])} > <MdShoppingBasket className="text-white text-2xl m-1" /> </motion.div> <div className=" w-full"> <p className="text-gray-800 md:text-lg text-base text-right"> {title} </p> <p className="text-sm text-gray-500 text-right"> <span className="text-orange-600">$</span> {price} </p> </div> </div> </div> </div> ); }) ) : ( <div className="w-full flex flex-col items-center justify-center"> <img src={NotFound} className="h-340" alt="" /> <p className="text-center my-2 text-xl text-red-500">No data found</p> </div> )} </div> ); }; export default RowContainer;
获取购物车数据的代码
export const fetchCart = () => { const cartInfo = localStorage.getItem("cartItems") !== "undefined" ? JSON.parse(localStorage.getItem("cartItems")) : localStorage.clear(); return cartInfo ? cartInfo : []; };
问题分析与修复方案
核心问题
- 全局状态未优先读取本地存储:页面刷新时,全局购物车状态初始为空,没有先加载localStorage里的缓存数据,Firebase加载延迟期间购物车自然无内容。
- 添加逻辑冗余且存在错误:依赖
items状态触发更新,初始为空时会覆盖本地已有数据;用Set去重对对象无效(对象引用不同),无法正确避免重复添加。 - fetchCart函数逻辑漏洞:判断条件错误,当localStorage无
cartItems键时返回null,不会等于字符串"undefined",导致错误执行localStorage.clear()清空所有本地数据。
具体修复步骤
- 修正全局状态初始化
在全局状态的初始值中直接调用fetchCart(),确保页面刷新后先加载本地缓存的购物车数据:
// stateProvider.js 示例代码 import { fetchCart } from './对应路径'; const initialState = { cartItems: fetchCart(), // 其他状态... };
- 修复fetchCart函数
修改判断逻辑,正确处理本地存储无数据的情况:
export const fetchCart = () => { const cartInfo = localStorage.getItem("cartItems"); return cartInfo ? JSON.parse(cartInfo) : []; };
- 重构添加购物车逻辑
去掉冗余的items状态和依赖它的副作用,直接在点击时更新全局状态和本地存储,同时通过商品id实现正确去重:
// RowContainer组件修改后的核心代码 const RowContainer = ({ flag, data, scrollValue }) => { const [{ cartItems }, dispatch] = useGlobalState(); const rowContainer = useRef(); const handleAddToCart = (item) => { // 通过id判断商品是否已存在 const isExist = cartItems.some(cartItem => cartItem.id === item.id); if (!isExist) { const updatedCart = [...cartItems, item]; // 更新全局状态 dispatch({ type: actionType.SET_CARTITEMS, cartItems: updatedCart, }); // 同步到本地存储 localStorage.setItem("cartItems", JSON.stringify(updatedCart)); } }; useEffect(() => { rowContainer.current.scrollLeft += scrollValue; }, [scrollValue]); // 组件返回部分修改点击事件 return ( // ...原JSX结构 <motion.div whileTap={{ scale: 0.75 }} className="w-8 h-8 rounded-md bg-orange-500 hover:bg-orange-600 " onClick={() => handleAddToCart(item)} > <MdShoppingBasket className="text-white text-2xl m-1" /> </motion.div> // ...原JSX结构 ); };
- Firebase数据同步补充
如果需要从Firebase同步用户云端购物车,要在组件挂载时先保留本地数据,再合并云端数据,避免覆盖:
// 示例:在购物车页面或全局状态中同步Firebase数据 useEffect(() => { const syncFirebaseCart = async () => { const currentUser = /* 获取当前登录用户 */; if (currentUser) { const cartDoc = await firebase.firestore().collection('carts').doc(currentUser.uid).get(); if (cartDoc.exists) { const cloudCart = cartDoc.data().items; // 合并本地与云端数据,优先保留本地新增商品 const mergedCart = [...new Map([...cartItems, ...cloudCart].map(item => [item.id, item])).values()]; dispatch({ type: actionType.SET_CARTITEMS, cartItems: mergedCart, }); localStorage.setItem("cartItems", JSON.stringify(mergedCart)); } } }; syncFirebaseCart(); }, []);
内容的提问来源于stack exchange,提问作者Riaz Bappy
相关产品推荐
相关产品推荐

