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";
default
导出。这是因为 default
不是路由对象上的有效键。这些文件通常只应导出您将在路由对象上定义的键,例如 loader
、action
、Component
、ErrorBoundary
等。所有导出将直接扩展到路由对象上,除非您从 lazy
手动返回一个对象。在路由上静态定义的任何属性都不能被 lazy
函数覆盖,如果您尝试覆盖它们,您将收到一个控制台警告。
此外,作为一项优化,如果您静态定义了 loader
/action
,那么它将与 lazy
函数并行调用。如果您有精简的加载器,并且不介意将其放在关键捆绑包中,那么这很有用,并且您希望在组件下载的同时并行启动其数据获取。这与 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
通常可以与每个路由的异步 import()
一对一使用,但您可以自由地实现更高级的 lazy
函数,只需要返回您想要添加到该路由的属性。这开辟了一些有趣的机会。
例如,如果您想避免为嵌套路由加载多个块,您可以将它们全部存储在同一个文件中,并将它们返回给各个路由。现代捆绑器将锁定同一个 Promise 用于不同的 import()
调用。
// 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,
};
},
},
],
};