shouldRevalidate
此函式允許應用程式最佳化在動作後和客戶端導覽時,應重新載入哪些路由的資料。
import type { ShouldRevalidateFunction } from "@remix-run/react";
export const shouldRevalidate: ShouldRevalidateFunction = ({
actionResult,
currentParams,
currentUrl,
defaultShouldRevalidate,
formAction,
formData,
formEncType,
formMethod,
nextParams,
nextUrl,
}) => {
return true;
};
在客戶端轉換期間,Remix 會最佳化已呈現的路由重新載入,例如不重新載入沒有變更的版面配置路由。在其他情況下,例如表單提交或搜尋參數變更,Remix 不知道哪些路由需要重新載入,因此為了安全起見,它會重新載入所有路由。這可確保您的 UI 始終與伺服器上的狀態同步。
此函式允許應用程式在 Remix 即將重新載入路由時,透過傳回 false
來進一步最佳化。如果您在路由模組上定義此函式,Remix 將會在每次導覽和每次呼叫動作後重新驗證時,參考您的函式。同樣地,如果您操作不當,您的 UI 可能會與伺服器不同步,因此請務必小心。
fetcher.load
呼叫也會重新驗證,但由於它們載入特定的 URL,因此不必擔心路由參數或 URL 搜尋參數重新驗證。fetcher.load
預設僅在動作提交以及透過 useRevalidator
的明確重新驗證請求後才會重新驗證。
actionResult
當提交導致重新驗證時,這將是動作的結果 — 如果動作失敗,則為動作資料或錯誤。在動作結果中包含一些資訊以指示 shouldRevalidate
是否重新驗證是很常見的做法。
export async function action() {
await saveSomeStuff();
return { ok: true };
}
export function shouldRevalidate({
actionResult,
defaultShouldRevalidate,
}) {
if (actionResult?.ok) {
return false;
}
return defaultShouldRevalidate;
}
defaultShouldRevalidate
預設情況下,Remix 不會一直呼叫每個載入器。它預設可以進行可靠的最佳化。例如,只會呼叫具有變更參數的載入器。考慮從以下 URL 導覽到其下方的 URL
/projects/123/tasks/abc
/projects/123/tasks/def
Remix 只會呼叫 tasks/def
的載入器,因為 projects/123
的參數沒有變更。
在您完成特定的優化並回傳 false
之後,最安全的做法是始終回傳 defaultShouldRevalidate
,否則您的 UI 可能會與伺服器上的資料失去同步。
export function shouldRevalidate({
defaultShouldRevalidate,
}) {
if (whateverConditionsYouCareAbout) {
return false;
}
return defaultShouldRevalidate;
}
這樣做比較危險,但 YOLO (You Only Live Once,你只活一次)。
export function shouldRevalidate() {
return whateverConditionsYouCareAbout;
}
currentParams
這些是來自 URL 的URL 參數,可以與 nextParams
進行比較,以決定是否需要重新載入。也許您只使用參數的部分內容來載入資料,如果參數中多餘的部分發生變更,您就不需要重新驗證。
例如,考慮一個包含 id 和易讀標題的事件 slug
/events/blink-182-united-center-saint-paul--ae3f9
/events/blink-182-little-caesars-arena-detroit--e87ad
export async function loader({
params,
}: LoaderFunctionArgs) {
const id = params.slug.split("--")[1];
return loadEvent(id);
}
export function shouldRevalidate({
currentParams,
nextParams,
defaultShouldRevalidate,
}) {
const currentId = currentParams.slug.split("--")[1];
const nextId = nextParams.slug.split("--")[1];
if (currentId === nextId) {
return false;
}
return defaultShouldRevalidate;
}
currentUrl
這是導覽開始的 URL。
nextParams
在導覽的情況下,這些是使用者請求的下一個位置的URL 參數。有些重新驗證並非導覽,因此它會與 currentParams
相同。
nextUrl
在導覽的情況下,這是使用者請求的 URL。有些重新驗證並非導覽,因此它會與 currentUrl
相同。
formMethod
觸發重新驗證的表單提交所使用的方法 (可能是 "GET"
或 "POST"
)。
formAction
觸發重新驗證的表單動作 (<Form action="/somewhere">
)。
formData
隨著表單提交而觸發重新驗證的資料。
根目錄載入器通常會回傳永遠不會變更的資料,例如要傳送至客戶端應用程式的環境變數。在這些情況下,您永遠不需要再次呼叫根目錄載入器。對於這種情況,您可以簡單地 return false
。
export const loader = async () => {
return json({
ENV: {
CLOUDINARY_ACCT: process.env.CLOUDINARY_ACCT,
STRIPE_PUBLIC_KEY: process.env.STRIPE_PUBLIC_KEY,
},
});
};
export const shouldRevalidate = () => false;
設定完成後,Remix 不會再因為任何原因向您的根目錄載入器發出請求,不論是表單提交後還是搜尋參數變更後。
另一種常見的情況是,當您有巢狀路由,而子元件具有使用 URL 中的搜尋參數的功能時,例如搜尋頁面或一些具有您想要保留在搜尋參數中的狀態的索引標籤。
考慮這些路由
├── $projectId.tsx
└── $projectId.activity.tsx
假設 UI 看起來像這樣
+------------------------------+
| Project: Design Revamp |
+------------------------------+
| Tasks | Collabs | >ACTIVITY |
+------------------------------+
| Search: _____________ |
| |
| - Ryan added an image |
| |
| - Michael commented |
| |
+------------------------------+
$projectId.activity.tsx
載入器可以使用搜尋參數來篩選清單,因此造訪像 /projects/design-revamp/activity?search=image
這樣的 URL 可以篩選結果清單。也許它看起來像這樣
export async function loader({
params,
request,
}: LoaderFunctionArgs) {
const url = new URL(request.url);
return json(
await exampleDb.activity.findAll({
where: {
projectId: params.projectId,
name: {
contains: url.searchParams.get("search"),
},
},
})
);
}
這對於活動路由來說很好,但是 Remix 並不知道父載入器 $projectId.tsx
是否也在意搜尋參數。這就是為什麼當搜尋參數變更時,Remix 會執行最安全的操作並重新載入頁面上的所有路由。
在這種 UI 中,這對於使用者、您的伺服器和您的資料庫來說都是浪費頻寬,因為 $projectId.tsx
不使用搜尋參數。考慮到我們的 $projectId.tsx
載入器看起來像這樣
export async function loader({
params,
}: LoaderFunctionArgs) {
const data = await fakedb.findProject(params.projectId);
return json(data);
}
有很多方法可以做到這一點,而應用程式中的其餘程式碼也很重要,但理想情況下,您不會考慮您正在嘗試優化的 UI(搜尋參數變更),而是查看您的載入器關心的值。在我們的例子中,它只關心 projectId,因此我們可以檢查兩件事
GET
而不是變更嗎?如果參數沒有變更,而且我們沒有執行 POST
,那麼我們知道我們的載入器將回傳與上次相同的資料,因此當子路由變更搜尋參數時,我們可以選擇不重新驗證。
export function shouldRevalidate({
currentParams,
nextParams,
formMethod,
defaultShouldRevalidate,
}) {
if (
formMethod === "GET" &&
currentParams.projectId === nextParams.projectId
) {
return false;
}
return defaultShouldRevalidate;
}