状态变更后如何通过React Router向React组件传递props?
问题描述
我正在构建一个Web应用,其中包含一个带有多个score的下拉列表,每个score的代码如下:
<NavDropdown.Item key = {i} id = {score["scoreId"]} onClick = {(e) => { setScore(score) window.location.href = '/home/score' // do something to go to the score page }} > {score["scoreName"]} </NavDropdown.Item>
点击score时,我先使用setScore()将score状态设置为当前选中的score,然后跳转到/home/score页面,路由配置如下:
<Routes> <Route path="/score" element={<ScoreHome score={score}/>} /> </Routes>
遇到的问题:我需要将新设置的score传递给<ScoreHome />组件,但useState()是异步的,导致新页面的props.score为undefined。
我尝试用useEffect处理:
useEffect(() => { window.location.href = '/home/score' },[score])
但这会造成无限循环(浏览器持续跳转或刷新/home/score页面),请问最佳解决方法是什么?
最佳解决方法
方案1:通过路由参数传递scoreId,在目标页面获取完整数据
这是最可靠的方案,完全避开前端状态异步的问题:
- 修改下拉项的点击事件,跳转到带scoreId参数的路由:
<NavDropdown.Item key={i} id={score["scoreId"]} onClick={(e) => { window.location.href = `/home/score?scoreId=${score["scoreId"]}` }} > {score["scoreName"]} </NavDropdown.Item>
- 在
ScoreHome组件中,通过useSearchParams获取参数,再根据scoreId获取对应的score数据:
import { useSearchParams } from 'react-router-dom'; function ScoreHome() { const [searchParams] = useSearchParams(); const scoreId = searchParams.get('scoreId'); const [score, setScore] = useState(null); useEffect(() => { if (scoreId) { // 可通过接口请求数据,或从本地数据源中查找 const targetScore = scoreList.find(item => item.scoreId === scoreId); setScore(targetScore); } }, [scoreId]); if (!score) return <div>加载中...</div>; return ( {/* 渲染score内容 */} ); }
方案2:用React Router的navigate方法携带state
如果不想在URL中暴露参数,可以用这种方式传递数据:
- 在当前组件中引入并初始化
useNavigate:
import { useNavigate } from 'react-router-dom'; const navigate = useNavigate();
- 修改下拉项的点击事件:
<NavDropdown.Item key={i} id={score["scoreId"]} onClick={(e) => { navigate('/home/score', { state: { score: score } }); }} > {score["scoreName"]} </NavDropdown.Item>
- 在
ScoreHome组件中通过useLocation获取传递的state:
import { useLocation } from 'react-router-dom'; function ScoreHome() { const location = useLocation(); const score = location.state?.score; if (!score) return <div>无有效数据</div>; return ( {/* 渲染score内容 */} ); }
方案3:使用全局状态管理(Context API/Redux)
如果应用中多个组件需要共享score状态,可采用全局状态方案:
- 创建ScoreContext:
import { createContext, useContext, useState } from 'react'; const ScoreContext = createContext(); export function ScoreProvider({ children }) { const [currentScore, setCurrentScore] = useState(null); return ( <ScoreContext.Provider value={{ currentScore, setCurrentScore }}> {children} </ScoreContext.Provider> ); } export function useScore() { return useContext(ScoreContext); }
- 在根组件中用
ScoreProvider包裹路由:
<ScoreProvider> <Routes> <Route path="/score" element={<ScoreHome />} /> </Routes> </ScoreProvider>
- 修改下拉项的点击事件:
import { useScore } from './ScoreContext'; const { setCurrentScore } = useScore(); <NavDropdown.Item key={i} id={score["scoreId"]} onClick={(e) => { setCurrentScore(score); window.location.href = '/home/score'; }} > {score["scoreName"]} </NavDropdown.Item>
- 在
ScoreHome组件中获取全局状态:
import { useScore } from './ScoreContext'; function ScoreHome() { const { currentScore } = useScore(); if (!currentScore) return <div>无有效数据</div>; return ( {/* 渲染score内容 */} ); }
关于之前的无限循环问题
跳转后组件重新渲染,score状态的变化会再次触发useEffect的执行,进而再次跳转,形成循环,所以这种方式不可行。
内容的提问来源于stack exchange,提问作者Nathan
相关产品推荐
相关产品推荐

