React路由页面刷新数据丢失问题排查求助
问题原因与解决方案
核心原因
异步请求时序与未处理空状态
刷新页面时,App组件重新挂载,API请求是异步操作,在请求完成前data保持初始空数组状态。ItemList组件直接执行data.filter(...)[0].items,当data为空时,filter返回空数组,取[0]得到undefined,访问undefined.items会抛出错误,导致组件渲染失败,表现为“数据消失”。缺失加载状态与数据校验
ItemList组件未利用传入的isLoading状态做加载判断,也没有对data是否存在、分类是否找到做校验,直接访问深层属性引发报错。
解决方案
1. 修复ItemList组件,增加状态判断与数据校验
修改ItemList组件,在数据未就绪、分类不存在时给出对应提示,避免直接访问undefined属性:
function ItemList({ name, data, isLoading }) { // 加载中状态处理 if (isLoading) { return <div>加载中...</div>; } // 数据为空时的提示 if (!data || data.length === 0) { return <div>暂无数据</div>; } // 查找对应分类,替代filter+[0]的写法,更直观 const targetCategory = data.find( (el) => name.toLowerCase() === el.name.toLowerCase() ); // 分类不存在时的提示 if (!targetCategory) { return <div>未找到指定分类</div>; } const items = targetCategory.items; return ( <ul className={styles.itemList}> {items.map((el) => ( <Item item={el} key={el.id} /> {/* 注意:用item的唯一ID作为key,避免使用随机UUID,提升渲染性能 */} ))} </ul> ); }
2. 确保App组件的状态初始值正确
确认data的初始状态为数组,避免类型错误:
const [data, setData] = useState([]);
3. 可选:用Context管理全局数据(优化props传递)
如果项目规模扩大,建议使用React Context封装数据请求与状态管理,避免props层层传递,同时保证刷新页面时数据能在全局共享:
// 创建DataContext.js import { createContext, useContext, useEffect, useState } from 'react'; import { BASE_URL } from './constants'; const DataContext = createContext(); export function DataProvider({ children }) { const [data, setData] = useState([]); const [isLoading, setIsLoading] = useState(false); useEffect(() => { async function fetchData() { try { setIsLoading(true); const res = await fetch(`${BASE_URL}/gahlot1999/fake-api/categories`); const fetchedData = await res.json(); setData(fetchedData); } catch { alert('加载数据出错'); } finally { setIsLoading(false); } } fetchData(); }, []); return ( <DataContext.Provider value={{ data, isLoading }}> {children} </DataContext.Provider> ); } export function useData() { return useContext(DataContext); }
然后在App组件中包裹Provider:
import { DataProvider } from './DataContext'; function App() { return ( <DataProvider> <BrowserRouter> <Routes> <Route path='/' element={<Home />} /> <Route path='/app' element={<AppLayout />} /> <Route path='app/:name' element={<Category />} /> </Routes> </BrowserRouter> </DataProvider> ); }
后续组件直接用useData获取数据,比如Category组件:
import { useData } from './DataContext'; function Category() { const { name } = useParams(); const { data, isLoading } = useData(); return ( <div className={styles.container}> <SideBar name={name} /> <ItemList name={name} data={data} isLoading={isLoading} /> </div> ); }
内容的提问来源于stack exchange,提问作者Ashish Gahlot
相关产品推荐
相关产品推荐

