React Router v6.4+ Data API:Loader失败重试不显示错误实现方案
在React Router 6.21.1 Data API中实现Loader的错误重试与自动重新验证
需求回顾
你的看板页面需要24小时持续展示,每5分钟重新拉取数据;遇到请求失败时最多重试5次(保障至少30分钟可用),之前用useEffect实现了该逻辑,现在要迁移到React Router的Loader中。
实现方案
1. 封装带状态跟踪的Loader函数
利用sessionStorage缓存数据和重试次数(页面会话期间有效,符合24小时展示的需求),在Loader中处理请求、重试计数和缓存逻辑:
async function fetchDashboard() { const cacheKey = 'dashboard-data'; const retryKey = 'dashboard-retry-count'; // 从sessionStorage读取重试次数和缓存数据 let retryCount = parseInt(sessionStorage.getItem(retryKey)) || 0; const cachedData = sessionStorage.getItem(cacheKey); try { const response = await axios.get('dashboard'); // 请求成功:更新缓存并重置重试计数 sessionStorage.setItem(cacheKey, JSON.stringify(response.data)); sessionStorage.setItem(retryKey, '0'); return response.data; } catch (error) { if (retryCount < 5) { // 未达重试上限:更新计数,返回缓存数据(如果有) sessionStorage.setItem(retryKey, (retryCount + 1).toString()); if (cachedData) { return JSON.parse(cachedData); } // 首次加载无缓存时,直接抛出错误 throw error; } else { // 重试次数用尽:重置计数并抛出错误,触发ErrorElement sessionStorage.setItem(retryKey, '0'); throw error; } } }
2. 配置路由自动重新验证
在路由配置中添加revalidate选项,设置为300秒(5分钟),让React Router自动定时重新执行Loader:
const routes = [ { element: <RootWrapper/>, errorElement: <ErrorWrapper/>, children: [ {path: "/login?", element: <LoginWrapper/>}, {path: "/logout", element: <Logout/>}, { id: "AuthenticatedRoot", element: <AuthenticatedRoot/>, children: [ // ... { path: "/dashboard", element: <Dashboard/>, loader: fetchDashboard, revalidate: 300 // 每5分钟自动重新验证 }, ] } ] ]
3. 组件内可选手动触发重新验证
如果需要更精确的控制(比如组件挂载后立即启动定时),可以在Dashboard组件中用useRevalidator手动触发:
import { useLoaderData, useRevalidator } from 'react-router-dom'; import { useEffect } from 'react'; function Dashboard() { const data = useLoaderData(); const { revalidate } = useRevalidator(); // 组件挂载后每5分钟触发一次重新验证 useEffect(() => { const interval = setInterval(() => { revalidate(); }, 5 * 60 * 1000); return () => clearInterval(interval); }, [revalidate]); return ( <div> {/* 渲染看板内容 */} </div> ); }
4. 错误兜底处理
当重试次数用尽后,Loader抛出的错误会触发上级的errorElement,可以在ErrorWrapper中添加手动重试按钮:
import { useRouteError, useRevalidator } from 'react-router-dom'; function ErrorWrapper() { const error = useRouteError(); const { revalidate } = useRevalidator(); return ( <div className="error-container"> <h2>数据加载失败</h2> <p>{error.message}</p> <button onClick={() => revalidate()}>尝试重新加载</button> </div> ); }
逻辑说明
- 缓存机制:请求成功时更新缓存,失败时返回缓存数据,确保页面始终有内容展示。
- 重试计数:用
sessionStorage跟踪重试次数,每次失败递增,成功或用尽次数后重置。 - 自动重新验证:通过路由的
revalidate配置实现每5分钟自动拉取数据,无需手动维护定时器(组件内的定时器为可选增强)。
内容的提问来源于stack exchange,提问作者DivineSlayer
相关产品推荐
相关产品推荐

