在 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>
);
}
當元件被渲染時,它會被提供在 Route.ComponentProps
中定義的 props,React Router 將自動為您生成這些 props。這些 props 包括
loaderData
:從此路由模組中的 loader
函數返回的資料actionData
:從此路由模組中的 action
函數返回的資料params
:包含路由參數的物件(如果有的話)。matches
:目前路由樹中所有匹配項的陣列。您可以使用這些 props 來代替像 useLoaderData
或 useParams
這樣的 hook。這可能是更佳的選擇,因為它們將自動針對路由進行正確的類型定義。
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>
、useFetcher
和 useSubmit
調用時自動重新驗證頁面上的所有 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
路由 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;
}
下一步:渲染策略