添加 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