React-query结合react-router-dom路由跳转页面空白问题求助
问题描述
使用react-router-dom进行页面跳转时,React-query出现异常返回undefined,具体场景与表现:
- 存在两个路由:Home 和 List
- 在Home组件中通过
navigate(/list/${list.id})跳转到List页面 - 问题现象:
- 跳转至List页面时页面空白,刷新后可正常加载
- 刷新List页面后返回Home,Home页面空白并报错:
Cannot read properties of undefined (reading 'length')
相关代码
Home组件代码
const lists = useQuery(["lists"], api.fetchLists); ... {lists.isLoading && ( <React.Fragment> <Skeleton /> </React.Fragment> )} ... {isEmpty()}
isEmpty()函数代码
if (lists.data) { return lists.data.lists.length ? ( {lists.data.lists?.map((list) => (
List组件代码
const { listId } = useParams(); const list = useQuery(["lists"], () => api.fetchList(listId)); ... {list.isLoading ? ( <Card style={{ padding: 30 }}> <div> <Skeleton /> </div> </Card> ) : ( {list.data} )}
原因分析
- 缓存Key冲突:Home和List组件的
useQuery使用了完全相同的缓存Key["lists"]。跳转List页面时,React-query会用api.fetchList返回的单个列表数据(结构为单个对象,无lists数组字段)覆盖原有缓存。当返回Home时,lists.data已经被替换成单个对象,此时读取lists.data.lists就会得到undefined,进而触发读取length的报错。 - 跳转时缓存更新导致渲染异常:跳转List页面时,新请求会更新缓存,但List组件渲染时缓存尚未完成更新,此时缓存中还是Home的数组数据或处于更新中的状态,导致页面空白;刷新List页面时,缓存重新初始化,请求的是单个列表数据,缓存内容匹配组件需求,因此显示正常。
解决方案
1. 给useQuery设置唯一缓存Key
修改List组件的缓存Key,加入listId做区分,彻底避免与Home的缓存冲突:
const { listId } = useParams(); // 缓存Key改为["list", listId],与Home的["lists"]完全区分 const list = useQuery(["list", listId], () => api.fetchList(listId));
2. 完善数据校验与状态处理
- 优化Home组件的
isEmpty()函数,增加多层空值校验,避免读取undefined属性:
function isEmpty() { // 用可选链确保每一层存在后再读取length if (lists.data?.lists?.length) { return lists.data.lists.map((list) => ( // 你的列表项渲染逻辑 )); } // 数据为空时返回空状态提示 return <div>暂无数据</div>; }
- 补充Home组件的错误状态处理,避免请求失败时出现报错:
{lists.isError && <div>加载失败,请重试</div>} {lists.isLoading && ( <React.Fragment> <Skeleton /> </React.Fragment> )} {!lists.isLoading && !lists.isError && isEmpty()}
3. 优化List组件渲染逻辑
补充错误状态处理,同时避免直接渲染原始的list.data(需根据数据结构渲染具体字段):
{list.isLoading ? ( <Card style={{ padding: 30 }}> <div> <Skeleton /> </div> </Card> ) : list.isError ? ( <div>列表加载失败</div> ) : ( <div> {/* 根据实际数据结构渲染,比如list.data.title、list.data.content等 */} {list.data.title} </div> )}
内容的提问来源于stack exchange,提问作者Daniel L
相关产品推荐
相关产品推荐

