React-Router+Redux嵌套组件<Link>返回报错,浏览器返回正常
兄弟,我之前也踩过类似嵌套组件+react-router+redux的坑,给你捋捋大概率的问题和解决办法:
先猜下你可能碰到的核心问题
从你描述的情况来看,从第3个组件回退到第2个时报错,大概率是路由参数没带全或者redux状态在回退时丢了——毕竟第2个组件的数据依赖第1个的选择,第3个依赖第2个,回退时很容易因为状态或参数不匹配炸锅。
具体排查&解决步骤
1. 先检查你的<Link>路径写对了吗?
比如第2个组件的路由是带参数的(比如/level1/:itemId/level2),那从第3个组件返回时,不能直接写<Link to="/level1/level2">,必须带上第1个组件选的那个itemId!不然第2个组件加载时拿不到参数,自然会因为缺数据报错。正确写法应该是:
// 假设你从redux或者路由参数里拿到了第1个组件选中的id const { itemId } = useParams(); // 或者从redux的state里取 <Link to={`/level1/${itemId}/level2`}>回到第2个组件</Link>
2. 看看Redux状态在回退时是不是丢了?
打开Redux DevTools,盯着从第3个组件点返回按钮的瞬间,看看第2个组件依赖的状态(比如selectedLevel1Item或者level2Data)是不是突然没了?
- 如果是,那你得检查是不是进入第3个组件时,不小心触发了清除状态的action(比如有些同学会在进入子路由时清掉父组件的状态,回退时就傻了)。
- 另外,第2个组件要确保在路由变化时重新拉数据,比如用
useEffect监听路由参数:useEffect(() => { const { itemId } = useParams(); if (itemId) { dispatch(fetchLevel2Data(itemId)); // 根据第1个的id重新拉第2个的数据 } }, [useParams().itemId, dispatch]); // 监听参数变化,参数变了就重新请求
3. 确认你的嵌套路由配置没毛病
要是路由配置不是嵌套的,回退时可能会把第2个组件卸载再重新挂载,这时候redux状态没跟上就会报错。比如React Router v6的正确嵌套写法应该是这样:
<Routes> <Route path="level1" element={<Level1 />}> <Route path=":itemId/level2" element={<Level2 />}> <Route path=":detailId/level3" element={<Level3 />} /> </Route> </Route> </Routes>
这样回退时,第2个组件不会被卸载,状态也能保留。
4. 别忘了解决异步请求的副作用
如果第3个组件里有异步请求,一定要在组件卸载时取消它!不然请求完成后dispatch的action可能会把redux状态搞乱,导致回退到第2个组件时状态异常。用AbortController就能搞定:
useEffect(() => { const controller = new AbortController(); dispatch(fetchLevel3Data({ signal: controller.signal })); return () => controller.abort(); // 组件卸载时取消请求 }, [dispatch]);
最后补个小技巧
要是还是找不到问题,把报错信息转成文字(比如是不是Cannot read property 'xxx' of undefined),然后检查第2个组件里有没有直接用可能为undefined的状态,记得加个空值判断,比如:
{level2Data && <div>{level2Data.name}</div>}
内容的提问来源于stack exchange,提问作者Dženis H.

