使用 Loader
到目前为止,我们都是用 useEffect
来请求 BFF,加载联系人列表数据。
在启用 SSR 的情况下,useEffect
在服务器端是不会执行的,所以 SSR 过程中不会加载数据,这种 SSR 只能渲染很有限的 UI,是低价值的。
可以在当前项目中开启 SSR,看下这种效果。
"server": {
"ssr": true,
}
执行 pnpm run dev
,在 devtools 的 network 面板里查看 HTML 请求的 Preview 面板,可以看到 SSR 的渲染结果只有导航栏和 Pending... 字符,并没有联系人数据:
前面提到过,应用工程里的 SSR 实现是 Serverless SSR,不仅在部署、运维环节,在开发环节对 Server 也是无感的,项目里不需要专门写服务器的实现。
上述加载初始数据的业务逻辑,也不应该像传统模式一样,在客户端代码和服务器端代码中分别实现。
Modern.js 提供一个叫 useLoader
的 hooks API,在这种场景下替代 useEffect
,能自动在 SSR 环节做预加载,先获取足够的数据,再运行 app 代码渲染 HTML。
同时,在 CSR 环节中,自动检查当前 loader 需要的数据,如果在 SSR 环节中已经预加载,在客户端就不再重复执行 loader,直接用现成数据;反之就在客户端执行 loader(相当于一种 fallback)。
useLoader
的使用很简单,把当前项目中 Contacts
组件中的 useEffect
代码替换成:
useLoader(
async () => {
if (!items.length && !error && !pending) {
return actions.load();
}
return Promise.resolve();
},
{
params: 'contacts',
},
);
useLoader
API 要求返回一个 promise,用于判断这个 loader 是否完成。第二个参数是当前 Loader 的唯一标识。
同时,在文件顶部的导入 useLoader
:
import { useLoader } from '@modern-js/runtime';
重新执行 pnpm run dev
,查看 view-source:http://localhost:8080/contacts/
,或在 devtools 的 Network 面板里查看 HTML 请求的「 Preview 」,可以看到 SSR 渲染出来的 HTML 已经包含完整的 UI:
查看 http://localhost:8080/contacts/
,可以看到首屏是没有 pending 过程的。
本小节的代码可以在这里查看。