自從 v6.4 版本釋出後,有人質疑 React Router 是否要取代 React Query、useSwr 等函式庫。
答案是「否!」
React Router 的資料 API 處理的是何時載入、異動和重新驗証資料,而不是如何執行這些動作。它處理的是資料生命週期,而不是取得資料、異動、儲存和快取的實際執行方式。
考量到 <a href>
和 <form action>
都是導覽事件,而且都與資料有關(要顯示什麼資料或要變更什麼資料),所以客戶端路由器可以協助您這兩個元素的導覽狀態。但是實際的資料執行方式則取決於您。
這裡的範例是根據 TkDodo's blog 改編的,感謝這篇精彩的文章!
您會在載入程式中使用資料抽象而不是在組件中載入資料。請注意,此載入發生在 React 渲染生命週期之外,因此您無法使用 React Query 的 useQuery
等 Hook,而必須直接使用查詢客戶端的方法。
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。如果使用者按一下「返回」,所有 loader 會再次呼叫。如果沒有使用 React Query 等資料快取程式庫(或沒有在 JSON API 中使用 HTTP 快取標頭,以使用瀏覽器自有的 HTTP 快取)來快取資料,你的應用程式會再次重新擷取所有資料。
從這個角度來看,React Router 著重於時機,而 React Query 則著重於快取。
React Router 的 useLoaderData
雖然會傳回 loader 傳回的任何資料,但你可以改用資料抽象化的 hooks 取得那個套件整套的功能。
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
等 HOOK 常常會傳回待處理和錯誤狀態,你可以用來分岔你的使用者介面。藉由 React Router,你可以讓所有這些分岔出快樂路徑元件,並改用 errorElement
、useNavigation
和 Await
。
藉由整合這些 API,你現在可以使用 React Router 的 useNavigation
來建立待處理狀態、樂觀使用者介面等等。使用 React Router 來處理資料載入、異動和導航狀態的時機,然後使用像是 React Query 的程式庫來實作載入、使資料失效、儲存和快取。