主程式
分支
主程式 (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` 不是路由物件的有效鍵值。這些檔案通常僅應該匯出你會於路由物件中定義的鍵值,例如 `loader`、`action`、`Component`、`ErrorBoundary` 等等。除非你手動從 `lazy` 傳回物件,否則所有匯出將會直接散佈至路由物件。

靜態定義的屬性

在路由中靜態定義的任何屬性都無法被 lazy 函式覆寫,而且如果你嘗試覆寫它們,你會收到一個主控台警告。

此外,為了進行優化,如果你靜態定義一個 loader / action,它將會與 lazy 函式平行呼叫。如果你有很多精簡的 loader,不在乎將它們放在關鍵軟體包中,而且想要在下載元件時並行執行它們的資料擷取,這將很有用。這接近 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 通常可以按照每個路由 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,
        };
      },
    },
  ],
};