React Router Data Router 数据加载模式
React Router 的 Data Router 模式:用 loader 在路由级加载数据、用 action 处理 mutation、mutation 后自动重新验证 loader。
#type / concept
#status / growing
#tech / dev / frontend
#resource / react
[!info] related notes
- 前置: React Router 路由与权限
- 对比: TanStack Query 服务端状态
- 架构: 四层状态架构
- 迁移: 从 useState 迁移到 TanStack Query
React Router Data Router 数据加载模式
一句话定义
React Router 的 Data Router 让路由自己负责加载数据(loader)和处理变更(action),mutation 完成后自动重新验证 loader,保持 UI 和数据同步。
核心机制
loader — 路由级数据加载
export async function consultationLoader({ params }) {
const conversationId = params.id;
const conversations = await consultationApi.listConversations({ limit: 50 });
if (!conversationId || conversationId === 'new') {
return {
conversations,
conversation: null,
messages: [],
consultation: null,
};
}
const conversation = await consultationApi.getConversation(conversationId);
const consultation = await consultationApi.getConsultation(conversationId)
.catch(() => null);
return { conversations, conversation, consultation };
}
组件中:
const { conversations, conversation, consultation } =
useLoaderData<typeof consultationLoader>();
action — 路由级 mutation
export async function consultationAction({ request }) {
const formData = await request.formData();
const intent = formData.get('intent');
if (intent === 'deleteAll') {
await deleteAllConversations();
return redirect('/consultation');
}
return null;
}
action 完成后,页面上的 loader data 会自动重新验证。
自动重新验证
用户提交删除 → action 执行 → redirect('/consultation')
→ loader 自动重跑 → 页面得到空数据 → 自然显示空状态
不需要手动清空任何 state。
最小例子
// 路由定义
createBrowserRouter([
{
path: '/consultation/:id',
element: <ConsultationPage />,
loader: consultationLoader,
action: consultationAction,
},
]);
// 组件
function ConsultationPage() {
const data = useLoaderData();
return <div>{data.conversation?.title}</div>;
}
与 TanStack Query 的对比
| 维度 | React Router Loader/Action | TanStack Query |
|---|---|---|
| 数据加载 | 路由进入时自动触发 | 组件挂载时自动触发 |
| 缓存 | 路由级,切换路由可能重新加载 | queryKey 级,跨路由共享 |
| mutation | action + 自动重新验证 | useMutation + 手动 invalidate |
| 局部刷新 | 整个路由的 loader 重跑 | 只刷新指定 queryKey |
| 乐观更新 | 需要额外处理 | 内置 onMutate/onError/onSettled |
| streaming | 不直接支持 | 通过 setQueryData 增量更新 |
适用场景
React Router Loader 更适合:
- 进入页面前加载完整数据
- 提交表单后整体重新验证
- 页面数据强依赖路由
- 简单的 CRUD 页面
TanStack Query 更适合:
- 复杂的局部数据变化
- SSE 流式更新
- 跨路由缓存复用
- 乐观更新
- 需要精细控制 staleTime / refetch
边界与易混淆点
- Loader 在路由进入时执行,不是在组件渲染时。这意味着数据在组件挂载前就已经准备好了
- action 完成后的重新验证是自动的,但只重新验证当前路由及父路由的 loader
- Data Router 不是”不用 TanStack Query”的理由,两者可以共存:路由 loader 加载初始数据,TanStack Query 管理后续的缓存和更新