コンテンツにスキップ

shouldRevalidate

このコンテンツはまだ日本語訳がありません。

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 的设计已经优化了需要调用哪些加载器以及何时调用。使用此功能时,您的 UI 可能会与服务器不同步。请谨慎使用!

在客户端转换期间,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:

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
// app/routes/events.$slug.tsx
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。

下一个参数

对于导航,这些是用户请求的下一个位置的 URL 参数。有些重新验证不是导航,因此它将与 currentParams 相同。

下一个网址

在导航的情况下,这是用户请求的 URL。有些重新验证不是导航,因此它将与 currentUrl 相同。

formMethod

触发重新验证的表单提交所使用的方法(可能是 GETPOST)。

formAction 表单动作

触发重新验证的表单操作 (<Form action="/somewhere">)。

formData

与触发重新验证的表单一起提交的数据。

用例

永不重新加载根目录

根加载器通常会返回永不改变的数据,例如要发送到客户端应用的环境变量。在这些情况下,您无需再次调用根加载器。在这种情况下,您只需返回 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 可以过滤结果列表。可能看起来像这样:

// app/routes/$projectId.activity.tsx
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 加载器如下所示:

// app/routes/$projectId.tsx
export async function loader({
params,
}: LoaderFunctionArgs) {
const data = await fakedb.findProject(params.projectId);
return json(data);
}

有很多方法可以做到这一点,应用程序中的其余代码也很重要,但理想情况下,您不必考虑要优化的 UI(搜索参数会发生变化),而是查看加载程序关心的值。在我们的例子中,它只关心 projectId,因此我们可以检查两件事:

  • 参数是否保持不变?
  • 它是 GET 而不是突变吗?

如果参数没有改变,并且我们没有执行 POST,那么我们知道我们的加载器将返回与上次相同的数据,因此当子路由更改搜索参数时,我们可以选择退出重新验证。

// app/routes/$projectId.tsx
export function shouldRevalidate({
currentParams,
nextParams,
formMethod,
defaultShouldRevalidate,
}) {
if (
formMethod === "GET" &&
currentParams.projectId === nextParams.projectId
) {
return false;
}
return defaultShouldRevalidate;
}