name: frontend-nextjs-app-router description: | 用于处理Next.js App Router相关任务 - 在/app/目录下创建页面、设置动态路由([id]/page.tsx)、实现嵌套布局/模板(layout.tsx)、优化服务器/客户端组件、或构建ERP角色页面(管理员/教师/学生仪表板)。自动用于所有/app/目录操作、动态路由和App Router特定功能。
Next.js App Router专家
概述
Next.js App Router开发专家指导,包括页面创建、动态路由、嵌套布局、服务器/客户端组件优化和ERP角色仪表板。
核心能力
1. 页面创建 (/app/.../page.tsx)
规则:
- 默认使用服务器组件(无’use client’指令)
- 使用
fetch()或ORM查询直接进行异步数据获取 - 初始数据加载不使用
useEffect - 使用
Suspense边界处理加载状态 - 通过
generateMetadata()设置SEO元数据
模板:
// app/dashboard/page.tsx
import { Suspense } from 'react';
import { TaskList } from '@/components/TaskList';
import { TaskListSkeleton } from '@/components/TaskListSkeleton';
export const metadata = {
title: '仪表板',
description: '您的任务管理仪表板',
};
export default async function DashboardPage() {
const tasks = await fetchTasks();
return (
<main className="p-4">
<h1>仪表板</h1>
<Suspense fallback={<TaskListSkeleton />}>
<TaskList initialTasks={tasks} />
</Suspense>
</main>
);
}
2. 动态路由 ([slug]/page.tsx)
使用场景:
- 学生档案:
app/students/[studentId]/page.tsx - 任务详情:
app/tasks/[taskId]/page.tsx - 课程页面:
app/courses/[courseId]/page.tsx
规则:
- 从
params属性提取参数(只读) - 使用
generateMetadata()进行SEO优化 - 使用
not-found.tsx处理404
模板:
// app/students/[studentId]/page.tsx
import { notFound } from 'next/navigation';
type Params = Promise<{ studentId: string }>;
export async function generateMetadata({ params }: { params: Params }) {
const { studentId } = await params;
const student = await getStudent(studentId);
if (!student) return { title: '学生未找到' };
return {
title: `${student.name} - 学生档案`,
};
}
export default async function StudentProfile({ params }: { params: Params }) {
const { studentId } = await params;
const student = await getStudent(studentId);
if (!student) notFound();
return <StudentProfileView student={student} />;
}
3. 并行路由 (@folder)
使用场景:
- 仪表板变体:
app/dashboard@(admin|teacher)/page.tsx - 拆分布局:
app/settings@(user|organization)/layout.tsx
模板:
// app/dashboard/@admin/page.tsx - 管理员仪表板
export default function AdminDashboard() {
return <AdminPanel />;
}
// app/dashboard/@teacher/page.tsx - 教师仪表板
export default function TeacherDashboard() {
return <TeacherPanel />;
}
4. 布局与模板
根布局 (app/layout.tsx):
import { Providers } from '@/components/Providers';
import './globals.css';
export const metadata = {
title: 'Todo Evolution',
description: '教育任务管理',
};
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="zh-CN">
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}
嵌套布局 (app/dashboard/layout.tsx):
import { DashboardNav } from '@/components/DashboardNav';
export default function DashboardLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<div className="flex min-h-screen">
<DashboardNav />
<main className="flex-1 p-6">{children}</main>
</div>
);
}
模板 (app/tasks/template.tsx):
// 导航时重新执行,保留表单状态
export default function TasksTemplate({ children }: { children: React.ReactNode }) {
return (
<div className="bg-gray-50 min-h-screen">
<header className="bg-white shadow">
<h1>任务</h1>
</header>
{children}
</div>
);
}
5. 服务器与客户端组件
服务器组件用于:
- 数据获取
- 直接数据库查询
- 静态内容
- 仅服务器操作
客户端组件 ('use client') 用于:
- 浏览器API (
window,localStorage) - 事件处理程序 (
onClick,onSubmit) - React钩子 (
useState,useEffect) - 状态管理 (Zustand, Redux)
- 交互性
// 服务器组件(默认)
export default async function TaskList() {
const tasks = await fetchTasks(); // 直接数据库查询
return <div>{tasks.map(/* ... */)}</div>;
}
// 客户端组件
'use client';
import { useTaskStore } from '@/store/tasks';
export function TaskFilter() {
const { filter, setFilter } = useTaskStore();
return <button onClick={() => setFilter('all')}>所有任务</button>;
}
6. ERP角色页面
角色守卫:
// app/admin/page.tsx
import { requireRole } from '@/lib/auth';
import { redirect } from 'next/navigation';
export default async function AdminPage() {
const session = await getSession();
if (session?.role !== 'admin') {
redirect('/unauthorized');
}
return <AdminDashboard />;
}
KPI仪表板 (Recharts):
'use client';
import { BarChart, Bar, XAxis, YAxis, Tooltip } from 'recharts';
export function TaskKPIChart({ data }: { data: TaskStats[] }) {
return (
<BarChart width={600} height={300} data={data}>
<XAxis dataKey="date" />
<YAxis />
<Tooltip />
<Bar dataKey="completed" fill="#22c55e" />
</BarChart>
);
}
7. 错误与加载状态
错误边界 (error.tsx):
'use client';
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
return (
<div>
<h2>出错了!</h2>
<button onClick={reset}>重试</button>
</div>
);
}
加载状态 (loading.tsx):
export default function Loading() {
return <div className="animate-pulse">加载中...</div>;
}
// 或使用Suspense:
export default async function Page() {
return (
<Suspense fallback={<Loading />}>
<Content />
</Suspense>
);
}
8. shadcn/ui集成
安装:
npx shadcn@latest add button card input dialog
在服务器组件中使用:
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader } from '@/components/ui/card';
export default async function TaskPage() {
const tasks = await getTasks();
return (
<Card>
<CardHeader>任务</CardHeader>
<CardContent>
{tasks.map(task => (
<div key={task.id}>{task.title}</div>
))}
</CardContent>
</Card>
);
}
工作流决策树
用户请求 → 分析 → 实施路径
-
“创建仪表板/管理员页面” → 使用服务器组件的
page.tsx→ 异步数据获取 → 如需导航则添加layout.tsx -
“动态学生档案” → 创建
[studentId]/page.tsx→ 提取参数 → 添加generateMetadata()→ 如需则创建not-found.tsx -
“添加共享布局” → 在目标文件夹创建
layout.tsx→ 如需则用Providers包装 → 保持子组件渲染 -
“添加表单” →
'use client'组件 → 使用useState管理表单数据 → 使用服务器操作提交或API路由 -
“KPI图表/分析” →
'use client'用于Recharts → 服务器组件父级进行数据获取 → 通过props传递数据
质量检查清单
任务完成前检查:
- [ ] TypeScript严格模式已启用
- [ ] 默认使用服务器组件
- [ ] 仅在必要时使用
'use client' - [ ] 使用
generateMetadata()进行SEO优化 - [ ] 异步数据使用Suspense边界
- [ ] 需要时使用错误边界(
error.tsx) - [ ] 无水合不匹配
- [ ] 性能优化(无阻塞渲染)
- [ ] 移动优先响应式设计
- [ ] 可访问性(ARIA标签,键盘导航)
常见模式
模式1:服务器组件 + 客户端组件混合
// 服务器组件
export default async function Page() {
const tasks = await fetchTasks();
return <TaskList tasks={tasks} />; // 客户端组件用于交互性
}
'use client';
function TaskList({ tasks }: { tasks: Task[] }) {
const [filter, setFilter] = useState('all');
const filtered = tasks.filter(/* ... */);
return <div>{filtered.map(/* ... */)}</div>;
}
模式2:路由组组织
app/
(marketing)/ # 组:无URL段
about/page.tsx
contact/page.tsx
(dashboard)/ # 组:无URL段
layout.tsx
page.tsx
模式3:API路由(路由处理器)
// app/api/tasks/route.ts
import { NextResponse } from 'next/server';
export async function GET() {
const tasks = await db.query.tasks.findMany();
return NextResponse.json(tasks);
}
export async function POST(request: Request) {
const body = await request.json();
const task = await createTask(body);
return NextResponse.json(task, { status: 201 });
}
触发示例
- “创建仪表板页面” → 生成带服务器组件的
app/dashboard/page.tsx - “动态学生档案路由” → 带参数和元数据的
app/students/[studentId]/page.tsx - “添加共享布局” → 带子组件的
app/dashboard/layout.tsx - “带图表的管理面板” → 服务器组件 + 客户端图表组件
- “创建登录页面” →
'use client'表单组件 + API路由 - “自定义404页面” →
app/not-found.tsx - “错误处理” →
app/dashboard/error.tsx
参考
高级模式请参阅references/app-router-patterns.md,路由处理器示例请参阅references/api-routes.md。