NextJS App Router模式
About 1100 wordsAbout 4 min
NextJSReactFullstackSSR
2025-07-07
App Router 引入了一套全新的、基于 React 服务器组件 (Server Components) 的数据获取和渲染范式,旨在简化和统一开发体验。
getStaticProps 的替代方案
:默认静态渲染 + fetch API 缓存getStaticPaths 的替代方案
:generateStaticParamsgetServerSideProps 的替代方案
:fetch API 结合 cache: 'no-store'
- getStaticProps的revalidata实现ISR,在App router模式下,通过fetch方法的第二个传参传入。
fetch('/api/data', {
next: {
revalidate: 60 //单位秒,可选,60s后刷新缓存。设置为0时,每次请求都会刷新缓存。
}
});
重要点
在app/目录及其子目录下创建的所有React组件,都将被视为服务器组件
,如需将其特殊标准为客户端组件,在文件最开始使用use client
申明
- 服务器组件可以导入和渲染客户端组件
- 客户端组件不能直接导入和渲染服务器组件
- 如果客户端组件需要服务器组件的内容,通常是将其作为 props 传递,或者将服务器组件作为客户端组件的 children 传递
默认情况下,所有组件都静态渲染,即构建时生成静态 HTML 页面。如下场景会触发动态渲染
- 导入了动态函数,比如
cookies
、headers
、connection
等
- 导入了动态函数,比如
- fetch方法指定了no-store缓存策略
- fetch方法指定了next.revalidate为0
- 依赖了URL中的查询参数
页面组件的参数传递是高度结构化的,完全由 URL 驱动
Layout
和Page
之间不支持直接传参(都是page组件)。
- 页面组件之间,通过各自调用开启缓存的fetch享数据、或者访问params、searchParams页面组件入参。
type PageProps = {
params: Array<{
lang: string; // 语言参数
[paramName: string]: any; // 动态路由段的入参,存储参数名、参数值
}>,
searchParamm: Record<string, string>, // 路由中的查询参数,存储参数名、参数值
}
- 典型的App router模式下的项目目录结构
my-nextjs-app/
├── app/
│ ├── layout.js # 根布局 (Root Layout) - 必须有,定义所有路由的共享 UI
│ ├── page.js # 根页面 (Root Page) - 站点的首页 '/'
│ │
│ ├── dashboard/ # 一个功能模块:仪表盘
│ │ ├── layout.js # 仪表盘特有的布局 (嵌套布局)
│ │ ├── page.js # 仪表盘首页 '/dashboard'
│ │ ├── settings/ # 仪表盘下的设置页面
│ │ │ ├── page.js # 设置页面 '/dashboard/settings'
│ │ │ ├── profile/
│ │ │ │ └── page.js # 个人资料设置页面 '/dashboard/settings/profile'
│ │ │ └── account/
│ │ │ └── page.js # 账户设置页面 '/dashboard/settings/account'
│ │ │
│ │ ├── analytics/
│ │ │ └── page.js # 仪表盘下的分析页面 '/dashboard/analytics'
│ │ │
│ │ ├── _components/ # 仪表盘私有组件 (以下划线开头,不会被路由)
│ │ │ ├── DashboardNav.js
│ │ │ └── UserCard.js
│ │ │
│ │ └── _utils.js # 仪表盘私有工具函数
│ │
│ ├── products/ # 另一个功能模块:产品
│ │ ├── page.js # 产品列表页 '/products'
│ │ ├── [productId]/ # 动态路由段:产品详情页 '/products/[productId]'
│ │ │ ├── page.js # 具体产品详情页面
│ │ │ ├── PhotoGallery.js # 与产品详情页共置的客户端组件 (可能需要 "use client")
│ │ │ ├── reviews/ # 嵌套路由:产品评论页 '/products/[productId]/reviews'
│ │ │ │ └── page.js
│ │ │ │
│ │ │ └── layout.js # 产品详情页特有的布局
│ │ │
│ │ └── _components/ # 产品模块私有组件
│ │ └── ProductCard.js
│ │
│ ├── api/ # API 路由 (API Routes)
│ │ ├── route.js # 根 API 路由 '/api' (GET, POST, etc.)
│ │ ├── users/
│ │ │ ├── route.js # 用户 API '/api/users'
│ │ │ └── [userId]/
│ │ │ └── route.js # 特定用户 API '/api/users/[userId]'
│ │ │
│ │ └── draft/
│ │ └── route.js # 预览模式激活 API (如之前讨论的)
│ │
│ ├── (marketing)/ # 路由组 (Route Group) - 不影响 URL 路径,用于组织路由
│ │ ├── about/
│ │ │ └── page.js # '/about'
│ │ └── contact/
│ │ └── page.js # '/contact'
│ │
│ ├── loading.js # 加载 UI 文件 - 为父级路由段提供加载状态
│ ├── error.js # 错误 UI 文件 - 为父级路由段捕获错误
│ ├── not-found.js # 404 UI 文件 - 为未找到的路由提供自定义 404 页面
│ ├── global-error.js # 全局错误捕获 (通常与 error.js 配合使用)
│ └── favicon.ico # 网站图标 (放置在 app 根目录)
│
├── public/ # 静态资源 (Static Assets) - 如图片、字体等,直接通过 / 访问
│ ├── images/
│ │ └── logo.png
│ └── robots.txt
│
├── components/ # 共享组件 (Shared Components) - 在多个功能模块中复用
│ ├── Header.js # 可能包含 "use client" 指令
│ ├── Footer.js # 可能包含 "use client" 指令
│ └── common/
│ └── Card.js
│
├── lib/ # 工具函数或数据获取层 (Utilities / Data Layer)
│ ├── db.js # 数据库连接
│ ├── api.js # 封装的外部 API 调用
│ └── utils.js # 通用工具函数
│
├── styles/ # 全局样式或 SCSS 变量 (通常在 layout.js 中导入)
│ └── global.css
│
├── README.md
├── package.json
├── next.config.js # Next.js 配置
├── tsconfig.json # TypeScript 配置 (如果使用 TypeScript)
└── .env.local # 环境变量
和Page Router一样,app下以_开头的目录或者文件,不会被路由,比如依赖于服务端数据的组件、工具函数、自定义hook等