如何使用React + Firebase基于集合项ID创建动态路由?
解决React + Firebase动态路由与详情页面渲染问题
首先修正你代码里的小错误:Link的to属性里多了一个多余的闭合花括号,正确写法应该是:
<Link to={`/protocol/${item.id}`}>
接下来分三步实现动态路由和详情页渲染:
1. 配置动态路由
假设你用的是react-router-dom v6+,在路由配置文件(比如App.js或Routes.js)里添加动态路由规则:
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; import ProtocolList from './ProtocolList'; // 你的列表组件 import ProtocolDetail from './ProtocolDetail'; // 要创建的详情组件 function App() { return ( <Router> <Routes> <Route path="/" element={<ProtocolList />} /> {/* 动态路由,:id 是占位符,匹配任意值 */} <Route path="/protocol/:id" element={<ProtocolDetail />} /> </Routes> </Router> ); } export default App;
2. 创建详情组件并获取路由ID
创建ProtocolDetail.js组件,用useParams钩子提取路由里的ID,再从Firebase获取对应文档数据:
import { useState, useEffect } from 'react'; import { doc, getDoc } from 'firebase/firestore'; import { db } from './firebaseConfig'; // 你的Firebase配置文件 import { useParams } from 'react-router-dom'; function ProtocolDetail() { const { id } = useParams(); // 获取路由中的id参数 const [protocol, setProtocol] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { const fetchProtocol = async () => { try { // 根据ID从Firebase集合获取文档 const protocolDoc = await getDoc(doc(db, 'protocols', id)); if (protocolDoc.exists()) { setProtocol({ id: protocolDoc.id, ...protocolDoc.data() }); } else { console.log("找不到对应的协议文档"); } } catch (error) { console.error("获取数据失败:", error); } finally { setLoading(false); } }; if (id) { fetchProtocol(); } }, [id]); if (loading) return <div>加载中...</div>; if (!protocol) return <div>未找到该协议</div>; return ( <div className="container mx-auto p-4"> <h1 className="text-2xl font-bold mb-4">{protocol.name}</h1> {/* 渲染其他字段,比如protocol.description等 */} <p>{protocol.description}</p> </div> ); } export default ProtocolDetail;
3. 修正列表组件的Link写法
把你原来的列表组件里的Link错误修正后,完整代码示例:
import { Link } from 'react-router-dom'; function ProtocolList({ protocol }) { return ( <div> {protocol.map((item) => { return ( <div key={item.id} className="flex justify-start underline underline-offset-3"> <Link to={`/protocol/${item.id}`}> <div className="mt-2 hover:text-pink-600 duration-300">{item.name}</div> </Link> </div> ); })} </div> ); } export default ProtocolList;
补充说明
- 如果需要实时监听文档变化,可以把
getDoc换成onSnapshot,这样数据更新时页面会自动刷新:useEffect(() => { const unsubscribe = onSnapshot(doc(db, 'protocols', id), (doc) => { if (doc.exists()) { setProtocol({ id: doc.id, ...doc.data() }); } setLoading(false); }); // 组件卸载时取消监听 return () => unsubscribe(); }, [id]);
内容的提问来源于stack exchange,提问作者Fear of the dark
相关产品推荐
相关产品推荐

