自从 v6.4 版本发布以来,有些人想知道 React Router 是否试图取代 React Query、useSwr 等库。
答案是“不!”。
React Router 的数据 API 是关于何时加载、修改和重新验证数据,而不是如何做。它是关于数据生命周期,而不是实际的数据获取、修改、存储和缓存实现。
考虑到 <a href>
和 <form action>
都是导航事件,并且都与数据相关联(显示什么数据或更改什么数据),因此客户端路由器可以帮助您处理这两个元素的导航状态是有道理的。但实际的数据实现由您决定。
这里的示例改编自 TkDodo 的博客,感谢您提供精彩的帖子!
您不需要在组件中加载数据,而是在加载器中使用您的数据抽象。请注意,此加载发生在 React 渲染生命周期之外,因此您无法使用 React Query 的 useQuery
等钩子,您需要直接使用查询客户端的方法。
import { queryClient } from "./query-client";
export const loader = ({ params }) => {
return queryClient.fetchQuery(queryKey, queryFn, {
staleTime: 10000,
});
};
如果查询客户端正确抛出错误,那么 React Router 的 errorElement
将以相同的方式工作。
当然,您可以使用数据库的所有功能,例如缓存。缓存您的数据可以确保当用户点击后退按钮返回到您已经看过的页面时,数据会立即从缓存中加载。有时缓存是正确的选择,有时您总是希望它新鲜,但这并不是 React Router 数据 API 范围内的决定。
React Router 仅保留当前页面的 loaderData。如果用户点击“后退”,所有加载器都会再次被调用。如果没有数据缓存库,例如 React Query(或您 JSON API 上的 HTTP 缓存头来使用浏览器的 HTTP 缓存),您的应用程序将再次重新获取所有数据。
这样,React Router 关注的是时间,而 React Query 关注的是缓存。
虽然 React Router 的 useLoaderData
返回您从加载器返回的任何内容,但您可以使用数据抽象的钩子来访问该包的完整功能集。
export default function SomeRouteComponent() {
- const data = useLoaderData();
+ const { data } = useQuery(someQueryKey);
}
因为大多数这些库都有一些缓存机制,所以您需要在某个时刻使这些缓存失效。
使这些缓存失效的最佳位置是在 React Router action 中。
import { queryClient } from "./query-client";
export const action = async ({ request, params }) => {
const formData = await request.formData();
const updates = Object.fromEntries(formData);
await updateContact(params.contactId, updates);
await queryClient.invalidateQueries(["contacts"]);
return redirect(`/contacts/${params.contactId}`);
};
defer
一起使用您也可以类似地利用延迟 API。
function loader() {
return defer({
// no await!
someData: queryClient.fetchQuery("someKey", fn),
});
}
function Comp() {
// *do* useLoaderData for promise
const { someData } = useLoaderData();
return (
<div>
<h1>Something</h1>
<Await
resolve={someData}
errorElement={<div>Oops!</div>}
>
<SomeView />
</Await>
</div>
);
}
function SomeView() {
// instead of accessing with useAsyncValue
// const someData = useAsyncValue();
// `useQuery` as usual
const { data } = useQuery("someKey");
// ...
}
像 useQuery
这样的钩子通常会返回您可以用来分支 UI 的待处理和错误状态。使用 React Router,您可以将所有这些分支从您的正常路径组件中分离出来,并依赖于 errorElement
、useNavigation
和 Await
。
通过所有这些 API 的协同工作,您现在可以使用 React Router 的 useNavigation
来构建待处理状态、乐观 UI 等等。使用 React Router 来控制数据加载、变异和导航状态的时间,然后使用 React Query 等库来实际实现加载、失效、存储和缓存。