使用Realtime Firebase、NextJs及AntD无法在[uid].js页面展示单个产品详情的问题排查请求
问题分析与解决方案
我仔细看了你的代码,发现几个核心问题导致单个产品详情无法正常加载,下面逐个拆解并给出修复方案:
1. Next.js路由参数获取错误
你在[uid].js里使用了react-router-dom的useParams,但Next.js有独立的路由系统,必须用next/router提供的useRouter来获取路由参数。另外你的详情页文件名是[uid].js,所以参数名应该是uid而非id。
错误代码片段:
import { useParams } from 'react-router-dom'; // ... const { id } = useParams();
修正后:
import { useRouter } from "next/router"; // ... const router = useRouter(); const { uid } = router.query; // 匹配文件名[uid].js的参数名
2. 状态初始化与加载判断不匹配
你把currentProduct初始化为空对象{},但加载判断条件却是currentProduct === null——这永远不会触发加载提示,因为初始值是对象而非null。更合理的方式是新增一个loading状态来控制加载逻辑,同时把currentProduct初始化为null方便判断产品是否存在。
修正后的状态逻辑:
const [currentProduct, setCurrentProduct] = useState(null); const [loading, setLoading] = useState(true); // 新增loading状态 useEffect(() => { if (!uid) return; // 避免uid未加载时发起无效请求 const unsub = onValue( ref(database, `products/${uid}`), // 使用导入的database实例,无需重复初始化 (snapshot) => { const productData = snapshot.val(); setCurrentProduct(productData); setLoading(false); // 请求完成后关闭加载状态 }, { onlyOnce: true } ); return unsub(); }, [uid]); // 加载状态判断 if (loading) { return <div>Loading the Product details...</div>; } // 产品不存在的情况 if (!currentProduct) { return <div>Product not found</div>; }
3. Firebase数据库引用重复初始化
你已经从../firebase/clientApp导入了database实例,没必要再调用getDatabase()重复初始化,直接使用导入的实例即可。
4. 确认Firebase数据路径正确性
请确保Firebase Realtime Database中,products节点下的每个产品的键(key)就是你从列表页传递的item.uid——如果你的产品是用push()添加的,自动生成的key就是你需要传递的uid值,要保证两者一致。
完整修正后的[uid].js代码
import { ref, onValue } from "firebase/database"; import React, { useState, useEffect } from 'react' import { database } from '../../firebase/clientApp'; import { useRouter } from "next/router"; import { Space } from 'antd'; const ProductDetails = () => { const [currentProduct, setCurrentProduct] = useState(null); const [loading, setLoading] = useState(true); const router = useRouter(); const { uid } = router.query; useEffect(() => { if (!uid) return; const unsubscribe = onValue( ref(database, `products/${uid}`), (snapshot) => { const productData = snapshot.val(); setCurrentProduct(productData); setLoading(false); }, { onlyOnce: true } ); return unsubscribe; }, [uid]); if (loading) { return <div>Loading the Product details...</div>; } if (!currentProduct) { return <div>Product not found</div>; } return ( <> <div className="site-layout-background" style={{ padding: 24, minHeight: 650 }} > <Space style={{ marginBottom: 15 }} /> <h1>Name - {currentProduct.name}</h1> </div> </> ) } export default ProductDetails;
额外小优化
列表页的seeMore函数里,e.preventDefault()可以去掉,因为按钮不是表单提交按钮,这个调用没有实际作用。
内容的提问来源于stack exchange,提问作者Innocent
相关产品推荐
相关产品推荐

