第 12 章:最佳实践与项目结构组织
12.1 推荐的项目结构
Next.js 默认结构简洁,但项目增大后建议进行模块化管理:
bash
/project-root
├── public/ # 静态资源
├── pages/ # 页面入口(可拆分子模块)
│ ├── index.tsx
│ ├── about.tsx
│ └── blog/
│ ├── index.tsx
│ └── [slug].tsx
├── components/ # UI 组件
│ └── shared/
├── layouts/ # 页面布局(Layout)
├── hooks/ # 自定义 Hook
├── lib/ # 工具方法,如 fetcher、apiClient
├── services/ # 接口逻辑封装(如 REST、GraphQL 调用)
├── store/ # 状态管理(如 zustand、redux)
├── styles/ # 样式文件(CSS / SCSS / Tailwind 配置)
├── constants/ # 常量配置
├── types/ # 类型定义(TypeScript)
└── middleware.ts # 中间件(Edge Functions)
12.2 页面与组件分离
- ✅ 页面只负责布局与加载数据
- ✅ 将复用 UI 拆到
components/
中 - ✅ 将页面逻辑 Hook 拆到
hooks/
中 - ✅ 接口访问封装在
services/
中
这样做的好处:
- 更清晰的职责划分
- 更易测试和复用
- 更利于多人协作开发
12.3 布局管理 Layout 模式
可以为不同页面定义统一或动态布局。
✅ 方法 1:在 _app.tsx
中包裹 Layout
tsx
// pages/_app.tsx
export default function App({ Component, pageProps }) {
const getLayout = Component.getLayout || ((page) => <DefaultLayout>{page}</DefaultLayout>);
return getLayout(<Component {...pageProps} />);
}
✅ 页面中定义布局:
tsx
// pages/about.tsx
import { CustomLayout } from '@/layouts/CustomLayout';
function AboutPage() {
return <div>About Us</div>;
}
AboutPage.getLayout = function getLayout(page) {
return <CustomLayout>{page}</CustomLayout>;
};
export default AboutPage;
12.4 API 请求封装
推荐封装统一的 fetcher
或 API 客户端:
ts
// lib/fetcher.ts
export async function fetcher(url: string, options = {}) {
const res = await fetch(url, { ...options });
if (!res.ok) throw new Error('Network error');
return res.json();
}
结合 SWR:
tsx
const { data, error } = useSWR('/api/user', fetcher);
12.5 样式管理建议
技术栈 | 推荐用途 |
---|---|
Tailwind CSS | 推荐(可配置、响应式强) |
CSS Modules | 局部组件样式 |
SCSS | 如果已有习惯可以保留 |
styled-components / Emotion | 适合需要 JS-in-CSS 的项目 |
尽量避免:
- 全局样式过多
- 同时使用多种 CSS 方案导致冲突
12.6 状态管理最佳实践
-
🔸 小型应用优先使用 React 原生状态(
useState
,useContext
) -
🔹 中大型项目推荐使用:
- Zustand(轻量推荐)
- Redux Toolkit(需要全局状态同步)
- Jotai / Recoil(原子状态管理)
示例(Zustand):
ts
import { create } from 'zustand';
const useUserStore = create((set) => ({
user: null,
setUser: (user) => set({ user }),
}));
12.7 使用别名简化路径(推荐)
📄 jsconfig.json
或 tsconfig.json
:
json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/components/*": ["components/*"],
"@/hooks/*": ["hooks/*"],
"@/lib/*": ["lib/*"]
}
}
}
📦 组件中这样使用:
tsx
import Header from '@/components/Header';
12.8 国际化(i18n)支持(可选)
Next.js 原生支持多语言:
📄 next.config.js
中配置:
js
i18n: {
locales: ['en', 'zh'],
defaultLocale: 'zh',
}
📄 页面自动按语言路径加载:
bash
/en/about
/zh/about
12.9 安全 & 性能最佳实践
项目 | 建议 |
---|---|
环境变量 | 使用 .env.local 、避免暴露敏感值 |
SSR 缓存 | 配合 CDN 或 ISR |
图片优化 | 使用 <Image /> 自动压缩 |
防止 XSS | 使用 dangerouslySetInnerHTML 时注意清洗 |
懒加载 | 延迟加载大组件、图片资源 |
自动预加载 | <Link /> 默认开启 |
分包优化 | 利用动态导入 import('./BigComp') |
✅ 小结
内容 | 推荐实践 |
---|---|
项目结构 | 模块化 + 按功能组织 |
页面职责 | 分离视图、逻辑、服务 |
布局复用 | getLayout() + 多布局支持 |
状态管理 | 小用原生,大用 Zustand 等 |
请求封装 | lib/fetcher.ts + SWR |
样式管理 | Tailwind / CSS Modules 优先 |
安全性能 | 懒加载、XSS防护、缓存、路径别名 |