如何在多页面展示Firebase Cloud Firestore数据并实现React页面间的数据传递
如何将Firestore的政客数据从列表页传递到详情页?
先看你的需求:点击列表页的政客卡片后,要把对应政客的真实Firestore数据展示在详情页里,不需要导入整个Polis组件,只需要复用Firebase配置或部分查询逻辑就行,这里给你两种实用方案:
先修正列表页的小问题(不影响核心功能,但更规范)
首先在Polis.js里,记得把Firestore文档的id加入到政客数据中(后续不管哪种方案都需要),同时修正样式写法和列表key的位置:
import React, { useEffect, useState } from 'react' import { Button, Card, Col, Form, FormLabel, Row } from 'react-bootstrap'; import app from '../firebase' import { BsChevronRight } from 'react-icons/bs' import { Link } from "react-router-dom"; function Polis() { const [politicians, setPolis] = useState([]); const [loading, setLoading] = useState(false); const ref = app.firestore().collection("politicians"); function getPolis() { setLoading(true); ref.onSnapshot((querySnapshot) => { const items = []; querySnapshot.forEach((doc) => { // 把Firestore文档ID加入数据,方便后续查询或传参 items.push({...doc.data(), id: doc.id}); }); setPolis(items); setLoading(false); }); } useEffect(() => { getPolis(); }, []); if (loading) { return <h1>Loading...</h1>; } return ( <div style={{minWidth: '100%'}}> {/* 修正之前的style语法错误 */} <h1>Nassau County Politicians</h1> <Card> <Card.Title> <Form> <FormLabel>Search</FormLabel> </Form> </Card.Title> </Card> <Row xs={2} md={5} lg={8}> {politicians.map((politician) => ( <Col key={politician.id}> {/* key放在列表根元素上更规范 */} <Card style={{ width: '15rem' }}> <Card.Img src={politician.img} /> <Card.Body> <Card.Title>{politician.name}</Card.Title> <Card.Text> <h6>{politician.position}</h6> <h6>{politician.party}</h6> {/* 这里的跳转链接会根据方案不同修改 */} <Link to={`/poliprofile/${politician.id}`}> <Button variant='primary'> <BsChevronRight /> </Button> </Link> </Card.Text> </Card.Body> </Card> </Col> ))} </Row> </div> ); } export default Polis;
方案一:通过路由传ID,详情页重新查询Firebase(推荐)
这种方式更适合数据可能实时更新的场景,只需要传递唯一标识,不需要传大量数据,而且能保证详情页拿到最新数据。
1. 修改列表页的跳转链接
把政客的文档ID作为路由参数传递:
<Link to={`/poliprofile/${politician.id}`}> <Button variant='primary'> <BsChevronRight /> </Button> </Link>
2. 改造详情页(PoliProfile.js)
用useParams获取路由里的ID,然后单独查询该政客的Firestore文档:
import React, { useEffect, useState } from "react"; import { Card, Spinner } from 'react-bootstrap'; import { useParams } from "react-router-dom"; import app from '../firebase'; // 只需要复用Firebase配置,不用导入Polis组件 function PoliProfile() { const { id } = useParams(); // 获取路由中的政客ID const [politician, setPolitician] = useState(null); const [loading, setLoading] = useState(true); // 指向单个政客的Firestore文档引用 const docRef = app.firestore().collection("politicians").doc(id); useEffect(() => { const getPolitician = async () => { try { const doc = await docRef.get(); if (doc.exists) { setPolitician(doc.data()); } else { console.log("未找到该政客的数据"); } } catch (error) { console.error("获取数据失败:", error); } finally { setLoading(false); } }; getPolitician(); }, [id]); if (loading) { return <Spinner animation="border" />; } if (!politician) { return <h2>该政客不存在</h2>; } return ( <Card style={{ width: '15rem' }} > <Card.Img src={politician.img || "https://static.vecteezy.com/system/resources/previews/002/318/271/non_2x/user-profile-icon-free-vector.jpg"} /> <Card.Body> <Card.Title>{politician.name}</Card.Title> <Card.Text> <h2>{politician.position}</h2> <h3>{politician.party}</h3> </Card.Text> </Card.Body> </Card> ); } export default PoliProfile;
方案二:通过路由state直接传递完整数据
如果数据不会频繁更新,也可以直接把政客的完整数据通过路由的state传递,详情页不需要再次请求Firebase。
1. 修改列表页的跳转链接
<Link to={{ pathname: "/poliprofile", state: { politician: politician } // 传递完整的政客数据 }}> <Button variant='primary'> <BsChevronRight /> </Button> </Link>
2. 改造详情页(PoliProfile.js)
用useLocation获取路由state里的数据:
import React from "react"; import { Card } from 'react-bootstrap'; import { useLocation } from "react-router-dom"; function PoliProfile() { const location = useLocation(); const politician = location.state?.politician; // 获取传递的政客数据 if (!politician) { return <h2>无法获取政客数据</h2>; } return ( <Card style={{ width: '15rem' }} > <Card.Img src={politician.img || "https://static.vecteezy.com/system/resources/previews/002/318/271/non_2x/user-profile-icon-free-vector.jpg"} /> <Card.Body> <Card.Title>{politician.name}</Card.Title> <Card.Text> <h2>{politician.position}</h2> <h3>{politician.party}</h3> </Card.Text> </Card.Body> </Card> ); } export default PoliProfile;
关于Firebase代码复用的小建议
- 不需要导入整个
Polis组件,只需要复用Firebase的初始化配置(app)即可。 - 如果多个组件都需要查询Firestore,可以把查询逻辑封装成自定义Hook(比如
useFirestoreDocument),减少重复代码。
内容的提问来源于stack exchange,提问作者key
相关产品推荐
相关产品推荐

