如何通过React Router向新组件传递对象或ID?及路由错误处理
解决React Router路由传参+Firebase数据传递问题
先给你解决眼前的警告错误,再讲两种实现数据传递的靠谱方案:
首先修复组件类型警告
你看到的Warning: Failed prop type: Invalid prop component of type object supplied to Route, expected function,原因有三个:
- React组件名必须首字母大写:你的
question组件要改成Question(比如import Question from './Question'),否则React会把它当成普通HTML标签,而非自定义组件。 - Route的component属性要传组件定义:确保传给Route的是组件本身(v6用
element={<Question />},v5用component={Question}),不是组件实例或其他对象。 - Link的路径格式错误:你写的
to={questions/:${question.id}}里的冒号是Route用来定义参数占位符的,Link里要传实际ID值,正确写法是to={/questions/${question.id}}。
方案一:通过URL参数ID重新查询Firebase
这是最稳妥的方式(即使用户直接刷新页面也能正常加载),步骤如下:
1. 配置路由和跳转链接
import { BrowserRouter as Router, Link, Routes, Route } from 'react-router-dom'; import Question from './Question'; // 确保组件首字母大写 // 在你的问题列表组件中: <Router> {/* 生成带实际ID的跳转链接 */} <Link to={`/questions/${question.id}`} style={{display: 'block', margin: 'auto'}} > Rozwiaz to zadanie kurwo </Link> {/* 用Routes包裹路由规则(v6写法,v5用Switch) */} <Routes> <Route path="/questions/:id" element={<Question />} /> </Routes> </Router>
2. 在目标组件中通过ID查询Firebase
在Question组件里,用useParams提取URL中的ID,再调用Firebase API查询对应数据:
import { useParams, useEffect, useState } from 'react'; import { db } from './firebaseConfig'; // 你的Firebase配置文件 import { doc, getDoc } from 'firebase/firestore'; function Question() { const { id } = useParams(); // 提取URL中的id参数 const [questionData, setQuestionData] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { // 定义异步查询函数 const fetchQuestion = async () => { try { // 假设你的问题数据存在名为"questions"的Firestore集合中 const docRef = doc(db, 'questions', id); const docSnap = await getDoc(docRef); if (docSnap.exists()) { setQuestionData(docSnap.data()); } else { console.log("找不到对应的问题文档!"); } } catch (err) { console.error("查询数据出错:", err); } finally { setLoading(false); } }; // 当ID存在时执行查询 if (id) fetchQuestion(); }, [id]); // ID变化时重新触发查询 if (loading) return <div>加载中...</div>; if (!questionData) return <div>未找到该问题</div>; // 渲染问题内容 return ( <div> <h2>{questionData.title}</h2> <p>{questionData.content}</p> {/* 其他问题相关内容 */} </div> ); } export default Question;
方案二:直接传递整个问题对象(无需重复查询)
如果已经在列表页拿到了完整的问题数据,不想再调用Firebase接口,可以用React Router的state属性传递对象:
1. 修改Link的跳转逻辑
<Link to={{ pathname: `/questions/${question.id}`, state: { question: question } // 把整个问题对象存入路由state }} style={{display: 'block', margin: 'auto'}} > Rozwiaz to zadanie kurwo </Link>
2. 在目标组件中获取state数据
import { useLocation, useParams } from 'react-router-dom'; function Question() { const location = useLocation(); const { id } = useParams(); // 从路由state中取出问题数据,加可选链防止state不存在 const questionData = location.state?.question; // 处理用户直接刷新页面的情况(此时state会丢失,建议 fallback 到方案一的查询逻辑) if (!questionData) { return <div>加载中...</div>; // 或者这里可以写跳转回列表页的逻辑,或者启动ID查询 } return ( <div> <h2>{questionData.title}</h2> <p>{questionData.content}</p> {/* 其他问题内容 */} </div> ); }
注意事项
- 如果使用
state传对象,用户刷新页面后state会丢失,所以一定要加fallback逻辑(比如用ID重新查询)。 - 确认你的React Router版本:上面的代码是v6的写法,如果是v5的话,Route要用
component={Question}代替element={<Question />},且用Switch包裹Route。
内容的提问来源于stack exchange,提问作者Alex Ironside
相关产品推荐
相关产品推荐

