路由模組
本頁面內容

路由模組

routes.ts 中引用的檔案稱為路由模組。

route("teams/:teamId", "./team.tsx"),
//           route module ^^^^^^^^

路由模組是 React Router 框架功能的基礎,它們定義了

  • 自動程式碼分割
  • 資料載入
  • 動作
  • 重新驗證
  • 錯誤邊界
  • 以及更多

本指南快速概述了每個路由模組的功能。其餘的入門指南將更詳細地介紹這些功能。

元件 (default)

路由模組中的 default export 定義了當路由匹配時將渲染的元件。

export default function MyRouteComponent() {
  return (
    <div>
      <h1>Look ma!</h1>
      <p>
        I'm still using React Router after like 10 years.
      </p>
    </div>
  );
}

傳遞給元件的 Props

當元件被渲染時,它會被提供在 Route.ComponentProps 中定義的 props,React Router 將自動為您生成這些 props。這些 props 包括

  1. loaderData:從此路由模組中的 loader 函數返回的資料
  2. actionData:從此路由模組中的 action 函數返回的資料
  3. params:包含路由參數的物件(如果有的話)。
  4. matches:目前路由樹中所有匹配項的陣列。

您可以使用這些 props 來代替像 useLoaderDatauseParams 這樣的 hook。這可能是更佳的選擇,因為它們將自動針對路由進行正確的類型定義。

使用 props

import type { Route } from "./+types/route-name";

export default function MyRouteComponent({
  loaderData,
  actionData,
  params,
  matches,
}: Route.ComponentProps) {
  return (
    <div>
      <h1>Welcome to My Route with Props!</h1>
      <p>Loader Data: {JSON.stringify(loaderData)}</p>
      <p>Action Data: {JSON.stringify(actionData)}</p>
      <p>Route Parameters: {JSON.stringify(params)}</p>
      <p>Matched Routes: {JSON.stringify(matches)}</p>
    </div>
  );
}

loader

路由 loader 在路由元件渲染之前為其提供資料。它們僅在伺服器端渲染時或在使用預先渲染進行建置期間在伺服器上調用。

export async function loader() {
  return { message: "Hello, world!" };
}

export default function MyRoute({ loaderData }) {
  return <h1>{loaderData.message}</h1>;
}

另請參閱

clientLoader

僅在瀏覽器中調用,路由 client loader 除了路由 loader 之外或代替路由 loader 為路由元件提供資料。

export async function clientLoader({ serverLoader }) {
  // call the server loader
  const serverData = await serverLoader();
  // And/or fetch data on the client
  const data = getDataFromClient();
  // Return the data to expose through useLoaderData()
  return data;
}

Client loader 可以透過設定函數上的 hydrate 屬性來參與伺服器渲染頁面的初始頁面載入 hydration

export async function clientLoader() {
  // ...
}
clientLoader.hydrate = true as const;

透過使用 as const,TypeScript 將推斷 clientLoader.hydrate 的類型為 true 而不是 boolean。這樣,React Router 可以根據 clientLoader.hydrate 的值推導出 loaderData 的類型。

另請參閱

action

路由 action 允許伺服器端資料變更,並在從 <Form>useFetcheruseSubmit 調用時自動重新驗證頁面上的所有 loader 資料。

// route("/list", "./list.tsx")
import { Form } from "react-router";
import { TodoList } from "~/components/TodoList";

// this data will be loaded after the action completes...
export async function loader() {
  const items = await fakeDb.getItems();
  return { items };
}

// ...so that the list here is updated automatically
export default function Items({ loaderData }) {
  return (
    <div>
      <List items={loaderData.items} />
      <Form method="post" navigate={false} action="/list">
        <input type="text" name="title" />
        <button type="submit">Create Todo</button>
      </Form>
    </div>
  );
}

export async function action({ request }) {
  const data = await request.formData();
  const todo = await fakeDb.addItem({
    title: data.get("title"),
  });
  return { ok: true };
}

clientAction

類似於路由 action,但僅在瀏覽器中調用。

export async function clientAction({ serverAction }) {
  fakeInvalidateClientSideCache();
  // can still call the server action if needed
  const data = await serverAction();
  return data;
}

另請參閱

ErrorBoundary

當其他路由模組 API 拋出錯誤時,路由模組 ErrorBoundary 將會渲染,而不是路由元件。

import {
  isRouteErrorResponse,
  useRouteError,
} from "react-router";

export function ErrorBoundary() {
  const error = useRouteError();

  if (isRouteErrorResponse(error)) {
    return (
      <div>
        <h1>
          {error.status} {error.statusText}
        </h1>
        <p>{error.data}</p>
      </div>
    );
  } else if (error instanceof Error) {
    return (
      <div>
        <h1>Error</h1>
        <p>{error.message}</p>
        <p>The stack trace is:</p>
        <pre>{error.stack}</pre>
      </div>
    );
  } else {
    return <h1>Unknown Error</h1>;
  }
}

HydrateFallback

在初始頁面載入時,路由元件僅在 client loader 完成後才渲染。如果導出 HydrateFallback,它可以立即渲染以代替路由元件。

export async function clientLoader() {
  const data = await fakeLoadLocalGameData();
  return data;
}

export function HydrateFallback() {
  return <p>Loading Game...</p>;
}

export default function Component({ loaderData }) {
  return <Game data={loaderData} />;
}

headers

路由 headers 定義了在伺服器端渲染時與響應一起發送的 HTTP 標頭。

export function headers() {
  return {
    "X-Stretchy-Pants": "its for fun",
    "Cache-Control": "max-age=300, s-maxage=3600",
  };
}

handle

路由 handle 允許應用程式在 useMatches 中向路由匹配項添加任何內容,以建立抽象概念(例如麵包屑導航等)。

export const handle = {
  its: "all yours",
};

路由 links 定義了要渲染在文件 <head> 中的 <link> 元素

export function links() {
  return [
    {
      rel: "icon",
      href: "/favicon.png",
      type: "image/png",
    },
    {
      rel: "stylesheet",
      href: "https://example.com/some/styles.css",
    },
    {
      rel: "preload",
      href: "/images/banner.jpg",
      as: "image",
    },
  ];
}

所有路由 links 將被聚合並通過 <Links /> 元件渲染,通常渲染在您的應用程式根目錄中

import { Links } from "react-router";

export default function Root() {
  return (
    <html>
      <head>
        <Links />
      </head>

      <body />
    </html>
  );
}

meta

路由 meta 定義了要渲染在文件的 <head> 中的 meta 標籤。

export function meta() {
  return [
    { title: "Very cool app" },
    {
      property: "og:title",
      content: "Very cool app",
    },
    {
      name: "description",
      content: "This app is the best",
    },
  ];
}

所有路由的 meta 將被聚合並通過 <Meta /> 元件渲染,通常渲染在您的應用程式根目錄中

import { Meta } from "react-router";

export default function Root() {
  return (
    <html>
      <head>
        <Meta />
      </head>

      <body />
    </html>
  );
}

另請參閱

shouldRevalidate

預設情況下,所有路由在 action 後都會重新驗證。此函數允許路由選擇退出對不影響其資料的 action 進行重新驗證。

import type { ShouldRevalidateFunctionArgs } from "react-router";

export function shouldRevalidate(
  arg: ShouldRevalidateFunctionArgs
) {
  return true;
}

下一步:渲染策略

文件和範例 CC 4.0