Modern.js 数据获取机制深度解析
2025-07-08 06:39:37作者:侯霆垣
Modern.js 作为现代 Web 开发框架,提供了一套完善的数据获取解决方案。本文将深入探讨其数据获取机制,帮助开发者更好地理解和运用这一核心功能。
一、Modern.js 数据获取概览
Modern.js 的数据获取能力是其核心特性之一,它通过一系列精心设计的 API 帮助开发者高效管理应用数据。这些 API 并非直接发起请求的工具,而是提供了更高级的数据管理抽象,能够显著提升项目性能。
二、推荐方案:Data Loader
2.1 基本概念
Modern.js 推荐使用约定式路由进行路由管理。在这种模式下,每个路由组件(layout.ts
或 page.ts
)可以拥有一个同名的 data
文件(早期版本为 loader
文件)。该文件需要导出一个函数,在组件渲染前执行,为路由组件提供所需数据。
2.2 基础示例
典型的项目结构如下:
.
└── routes
├── layout.tsx
└── user
├── layout.tsx
├── layout.data.ts
├── page.tsx
└── page.data.ts
数据获取流程:
- 在
data
文件中定义数据获取逻辑 - 在路由组件中使用
useLoaderData
获取数据
// routes/user/page.tsx
import { useLoaderData } from '@modern-js/runtime/router';
import type { ProfileData } from './page.data.ts';
export default function UserPage() {
const profileData = useLoaderData() as ProfileData;
return <div>{profileData}</div>;
}
// routes/user/page.data.ts
export type ProfileData = {
/* 类型定义 */
};
export const loader = async (): Promise<ProfileData> => {
const res = await fetch('https://api/user/profile');
return await res.json();
};
2.3 执行环境差异
- CSR 环境:
loader
函数在客户端执行,可以使用浏览器 API - SSR 环境:无论是首屏渲染还是客户端导航,
loader
都只在服务端执行,可以调用任何 Node.js API
三、高级特性详解
3.1 loader 函数参数
loader
函数接收两个重要参数:
-
params
:动态路由参数export const loader = async ({ params }: LoaderFunctionArgs) => { const { id } = params; const res = await fetch(`https://api/user/${id}`); return res.json(); };
-
request
:Fetch Request 实例export const loader = async ({ request }: LoaderFunctionArgs) => { const url = new URL(request.url); const userId = url.searchParams.get('id'); return queryUser(userId); };
3.2 错误处理
Modern.js 提供了完善的错误处理机制:
export const loader = async () => {
const res = await fetch('https://api/user/profile');
if (!res.ok) {
throw res; // 触发 ErrorBoundary
}
return res.json();
}
配合 ErrorBoundary 组件可以实现优雅的错误展示:
const ErrorBoundary = () => {
const error = useRouteError() as Response;
return (
<div>
<h1>{error.status}</h1>
<h2>{error.statusText}</h2>
</div>
);
};
3.3 数据缓存策略
Modern.js 采用智能的数据缓存策略:
- 路由导航时,只加载变化部分的数据
- 触发数据更新的情况:
- 执行 Data Action 后
- URL 查询参数变化时
- 点击当前页面链接
shouldRevalidate
返回 true
3.4 客户端专用 Loader
在 SSR 项目中,可以通过 Client Loader 实现:
- SSR 降级时直接请求数据源
- 利用客户端缓存避免重复请求
// 启用客户端 loader
export const config = {
disableLoader: true
};
export const clientLoader = async () => {
// 客户端专用逻辑
}
四、最佳实践与常见问题
4.1 注意事项
- 数据可序列化:
loader
返回值必须是可序列化的 - 避免直接调用:不应手动调用
loader
函数 - 模块隔离:避免路由组件与
loader
文件间相互导入 - 服务端限制:避免在服务端代码中使用
__filename
等 Node 特有变量
4.2 常见问题解答
Q1:Data Loader 与 BFF 函数的关系?
- CSR 项目中:
loader
在客户端执行,可直接调用 BFF - SSR 项目中:
loader
可作为 BFF 的替代方案,减少转发层级
Q2:为何 SSR 项目中 Data Loader 只在服务端执行?
这种设计带来了多重优势:
- 简化使用方式
- 减少网络传输数据量
- 减小客户端包体积
- 提升主线程性能
五、总结
Modern.js 的数据获取机制通过精心设计的 API 和智能的缓存策略,为开发者提供了高效、灵活的数据管理方案。无论是简单的数据获取还是复杂的状态管理,都能通过这套机制优雅地实现。理解并合理运用这些特性,将显著提升应用的性能和开发效率。