主分支
分支
主分支 (6.23.1)开发分支
版本
6.23.1v4/5.xv3.x
lazy

lazy

为了保持应用程序包的大小并支持路由的代码拆分,每个路由都可以提供一个异步函数,该函数解析路由定义中不匹配路由的部分(loaderactionComponent/elementErrorBoundary/errorElement 等)。

延迟路由在初始加载以及导航或获取器调用期间的 loadingsubmitting 阶段解析。您不能延迟定义路由匹配属性(pathindexchildrencaseSensitive),因为我们只在匹配了已知路由后才会执行延迟路由函数。

此功能仅在使用数据路由器时有效,请参阅 选择路由器

每个 lazy 函数通常会返回动态导入的结果。

let routes = createRoutesFromElements(
  <Route path="/" element={<Layout />}>
    <Route path="a" lazy={() => import("./a")} />
    <Route path="b" lazy={() => import("./b")} />
  </Route>
);

然后在您的延迟路由模块中,导出您希望为路由定义的属性(loaderComponentErrorBoundary

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 不是路由对象上的有效键。这些文件通常只应导出您将在路由对象上定义的键,例如 loaderactionComponentErrorBoundary 等。所有导出将直接扩展到路由对象上,除非您从 lazy 手动返回一个对象。

静态定义的属性

在路由上静态定义的任何属性都不能被 lazy 函数覆盖,如果您尝试覆盖它们,您将收到一个控制台警告。

此外,作为一项优化,如果您静态定义了 loader/action,那么它将与 lazy 函数并行调用。如果您有精简的加载器,并且不介意将其放在关键捆绑包中,那么这很有用,并且您希望在组件下载的同时并行启动其数据获取。这与 Remix 处理获取的方式很接近,因为每个路由都是它自己的 API 路由。

let route = {
  path: "projects",
  loader: ({ request }) => fetchDataForUrl(request.url),
  lazy: () => import("./projects"),
};

这也允许您进行更细粒度的代码拆分。例如,您可以将 loaderComponent 拆分为不同的文件以进行并行下载。

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,
        };
      },
    },
  ],
};
文档和示例 CC 4.0