lazy
為了讓應用程式小一點,並支援路由的程式碼分割,各個路由可以提供非路由比對部分的非同步函式,來定義你的路由(loader
、action
、Component
/element
、ErrorBoundary
/errorElement
等等)。
延遲路由會在初始載入時,以及導覽或取用器的 loading
或 submitting
階段解決。你無法延遲定義路由比對的屬性(path
、index
、children
、caseSensitive
),因為我們僅在你將已知路由比對完畢後,才會執行你的延遲路由函式。
每個 lazy
函式通常會傳回動態匯入的結果。
let routes = createRoutesFromElements(
<Route path="/" element={<Layout />}>
<Route path="a" lazy={() => import("./a")} />
<Route path="b" lazy={() => import("./b")} />
</Route>
);
然後在延遲路由模組中,匯出你想要定義於路由的屬性(loader
、Component
、ErrorBoundary
)
export async function loader({ request }) {
let data = await fetchData(request);
return json(data);
}
export function Component() {
let data = useLoaderData();
return (
<>
<h1>You made it!</h1>
<p>{data}</p>
</>
);
}
// If you want to customize the component display name in React dev tools:
Component.displayName = "SampleLazyRoute";
export function ErrorBoundary() {
let error = useRouteError();
return isRouteErrorResponse(error) ? (
<h1>
{error.status} {error.statusText}
</h1>
) : (
<h1>{error.message || error}</h1>
);
}
// If you want to customize the component display name in React dev tools:
ErrorBoundary.displayName = "SampleErrorBoundary";
在路由中靜態定義的任何屬性都無法被 lazy
函式覆寫,而且如果你嘗試覆寫它們,你會收到一個主控台警告。
此外,為了進行優化,如果你靜態定義一個 loader
/ action
,它將會與 lazy
函式平行呼叫。如果你有很多精簡的 loader,不在乎將它們放在關鍵軟體包中,而且想要在下載元件時並行執行它們的資料擷取,這將很有用。這接近 Remix 處理擷取的方式,因為每個路由都是它自己的 API 路由。
let route = {
path: "projects",
loader: ({ request }) => fetchDataForUrl(request.url),
lazy: () => import("./projects"),
};
這也允許你進行更細緻的程式碼拆分。例如,你可以將你的 loader
和 Component
拆分到不同的檔案中以便平行下載
let route = {
path: "projects",
async loader({ request, params }) {
let { loader } = await import("./projects-loader");
return loader({ request, params });
},
lazy: () => import("./projects-component"),
};
雖然 lazy
通常可以按照每個路由 1:1 的對應關係與非同步 import()
一起使用,但你可以自由實現更先進的 lazy
函式,唯一要做的就是傳回你想要新增到該路由的屬性。這開啟了一些有趣的可能性。
例如,如果你想要避免為巢狀路由載入多個區塊,你可以將它們全部儲存在同一個檔案中,並將它們傳回個別路由。現代的軟體包管理程式會捕捉不同 import()
呼叫的同一個 Promise。
// Assume pages/Dashboard.jsx has all of our loaders/components for multiple
// dashboard routes
let dashboardRoute = {
path: "dashboard",
async lazy() {
let { Layout } = await import("./pages/Dashboard");
return { Component: Layout };
},
children: [
{
index: true,
async lazy() {
let { Index } = await import("./pages/Dashboard");
return { Component: Index };
},
},
{
path: "messages",
async lazy() {
let { messagesLoader, Messages } = await import(
"./pages/Dashboard"
);
return {
loader: messagesLoader,
Component: Messages,
};
},
},
],
};