添加 Loader

上一章节中,我们学习了如何添加客户端路由。

这一章节中,我们将会学习如何为路由组件添加 Loader

到目前为止,我们都是通过硬编码的方式,为组件提供数据。如果要从远端获取数据,通常情况下会使用 useEffect 来做。但在启用 SSR 的情况下,useEffect 是不会在服务端执行的,所以这种 SSR 只能渲染很有限的 UI。

Modern.js 为提供了 Data Loader 的能力,支持同构的在组件中获取数据,让 SSR 的价值最大化。

下面我们演示如何为路由组件添加 Data Loader,并模拟远端数据获取。我们使用 faker 来 mock 需要的数据,首先安装依赖:

pnpm add faker@5
pnpm add @types/faker@5 -D

创建 src/routes/page.data.ts

import { name, internet } from 'faker';

export type LoaderData = {
  code: number;
  data: {
    name: string;
    avatar: string;
    email: string;
  }[];
};

export const loader = async (): Promise<LoaderData> => {
  const data = new Array(20).fill(0).map(() => {
    const firstName = name.firstName();
    return {
      name: firstName,
      avatar: `https://api.dicebear.com/7.x/pixel-art/svg?seed=${firstName}`,
      email: internet.email(),
    };
  });

  return {
    code: 200,
    data,
  };
};
NOTE

Data Loader 并非只为 SSR 工作。在 CSR 项目中,Data Loader 也可以避免数据获取依赖 UI 渲染,解决请求瀑布流的问题。未来,Modern.js 也会为这一特性添加更多能力,例如预获取、数据缓存等。

Modern.js 也提供了一个叫 useLoaderData 的 hooks API,我们修改 src/routes/page.tsx 导出的组件:

1import { useLoaderData } from '@modern-js/runtime/router';
2import type { LoaderData } from './page.data';
3
4function Index() {
5  const { data } = useLoaderData() as LoaderData;
6
7  return (
8    <div className="container lg mx-auto">
9      <Helmet>
10        <title>All</title>
11      </Helmet>
12      <List
13        dataSource={data}
14        renderItem={info => <Item key={info.name} info={info} />}
15      />
16    </div>
17  );
18}
19
20export default Index;

重新执行 pnpm run dev,查看 view-source:http://localhost:8080/,或在 devtools 的 Network 面板里查看 HTML 请求的「 Preview 」,可以看到 SSR 渲染出来的 HTML 已经包含完整的 UI:

display6