1. 开篇:为什么我建议你认真学一次 Next.js
过去几年,前端圈子里框架更替的速度快得让人疲惫。但如果你注意观察就会发现,Next.js 的热度不仅没有消退,反而逐渐从一个“React 之上的 SSR 框架”长成了全栈默认选择。很多团队新项目立项时的技术选型会议,最后都变成了同一个答案——就用 Next.js。
这篇文章我想从一个实际做项目的角度,聊聊 Next.js 到底解决了什么问题、从零开始怎么学、以及真正上手一个完整项目时会遇到哪些课本里不会写的坑。不管你是刚学完 React 基础、准备找一个框架做毕设或作品集的在校生,还是团队里需要独立搭建 B 端或 C 端应用的开发者,这篇文章都适合你。
需要提前说明的是,这一篇不是框架文档的翻译,而是我基于实际项目体验梳理出来的“Next.js 认知地图”。从环境搭建、路由心智、数据获取、渲染策略,到完整实战和一个以 Payload CMS 为代表的内容层集成,我尽量用讲人话的方式把每个关键决策背后的理由说清楚。这样你学完的不只是 API 怎么调,而是遇到类似场景时知道为什么选这条路。
2. Next.js 的核心心智:重新理解“全栈”这件事
2.1 它不是又一个 React 脚手架
很多初学者会有一个误解:Next.js 就是帮 React 做服务端渲染的工具。这个理解不算错,但严重低估了它的设计意图。
你可以把 Next.js 理解成一套“前后端一体”的应用框架。传统 React 项目里,前端代码只负责在浏览器里跑,数据要靠你单独写一个 Node 服务或者对接现成的后端。这种模式最大的问题是:你不得不在“前端工程化”和“后端服务”之间维护两条平行的代码路径,部署、联调、权限校验都要两头操心。
Next.js 把这件事压缩了。你在同一个项目里既能写页面组件,也能写 API 路由,还能在服务端组件里直接读取数据库或调用内部接口。这种模式在社区里有个形象的说法,叫“单体应用”(BFF 也是其中一种形态)。它的好处不是代码少写几行这么简单,而是你可以在一个代码库里完成“从数据库到浏览器”的完整链路,心智负担大幅下降。
2.2 约定式路由:少写代码,多写业务
Next.js 还有一个很“固执”的设计哲学:用文件系统来定义路由。也就是说,你不需要像 React Router 那样在代码里手动配置 route 表,只要在app目录下创建一个文件夹,路径就自动对应一个 URL 地址。
这个设计刚接触时可能会觉得“不自由”,但用久了会发现它特别适合团队协作。因为路由的层级关系直接从文件夹结构里就能看出来,新成员接手项目时,打开目录树就能快速定位到某个页面对应的代码文件。这一点在多人协作的项目里价值极高,比任何文档都直观。
另外一个容易被忽略的设计是“文件约定”。比如page.tsx代表页面组件,layout.tsx代表布局组件,loading.tsx代表加载状态,error.tsx代表错误边界。这些命名是强约定的,Next.js 会自动识别并按需渲染。你只需要把文件放到正确的位置,框架帮你处理了大部分样板代码。
2.3 渲染策略:同一套代码,多种运行方式
Next.js 最核心的能力模型,是它支持多种渲染方式:静态生成(SSG)、服务端渲染(SSR)、客户端渲染(CSR)、增量静态再生(ISR)。关键在于,这些策略不是割裂的,你可以在一个项目里混用。
比如一个电商网站,商品详情页可以用 SSG + ISR 提升首屏速度和 SEO,购物车页面用 CSR 保证用户交互的实时性,个人中心页面用 SSR 确保用户数据是最新的。这种“按页面、按场景”自由选择的能力,就是用 Next.js 做全栈项目的最大红利。
我后面会用一整节来讲这个部分,因为这是新手最容易踩坑的区域——“为什么我页面数据一直不更新”“为什么部署后首屏那么慢”,追根溯源都和渲染策略选择有关。
3. 从零开始:环境搭建与项目结构拆解
3.1 五分钟跑通一个 Next.js 项目
如果你已经有 Node.js 环境(建议 18.18 或更高版本,20 更稳),创建项目非常简单。在终端里执行:
npx create-next-app@latest my-app执行过程中会有几个交互式选项,我的建议是:
TypeScript? Yes ESLint? Yes Tailwind CSS? 看项目需求 src/ directory? Yes App Router? Yes(除非你维护的是旧版 Pages Router 项目) import alias? 默认即可- TypeScript 建议默认选上。Next.js 对 TypeScript 的支持非常完善,路由参数、API 上下文、组件 props 都有完整类型提示。虽然起步时会多花一点时间写类型,但项目一旦跨过千行规模,类型带来的收益是几何级增长的。
- src 目录结构,建议选 Yes。它能把组件、页面和应用配置分开,目录层级更干净。
- App Router是新项目默认选项,也是 Next.js 13.4 之后的绝对主线。Pages Router 目前还有大量存量项目在跑,但新项目不用犹豫,直接上 App Router。
跑起来之后,执行npm run dev,打开http://localhost:3000,你就拥有了一个带热更新的 Next.js 应用。
3.2 项目目录:每个文件夹是干什么的
一个典型的 App Router 项目长这样:
my-app/ ├── app/ │ ├── layout.tsx # 根布局,所有页面共享 │ ├── page.tsx # 首页 │ ├── globals.css # 全局样式 │ ├── api/ # API 路由(可选) │ └── blog/ │ ├── layout.tsx # blog 板块的局部布局 │ └── [slug]/ │ └── page.tsx # 动态路由:/blog/[slug] ├── components/ # 可复用组件 ├── lib/ # 工具函数、数据请求封装 ├── public/ # 静态资源 └── next.config.js # Next.js 配置文件刚开始不用急着弄懂所有文件,重点先理解layout和page的区别。
layout.tsx是布局组件,它会在页面切换时保持状态不重置。比如导航栏、页脚这类全局 UI,就应该放进layout。page.tsx则是具体的页面内容,每个 URL 对应一个。你可以把布局想象成相框,页面是相框里不断替换的照片。
这个机制带来的一个直接好处是:多页面应用不需要自己维护“哪些组件是公共的”,布局文件从结构上就定义好了层级关系。
3.3 不理解 App Router 和 Pages Router 的差异,后面会吃亏
这里特别提醒一下:如果你在网上搜索 Next.js 教程,会搜到大量基于 Pages Router 的旧文章。两者虽然共用组件概念,但数据获取方式和路由组织的思维完全不同。
Pages Router 采用的是“页面级数据获取”,通过getServerSideProps或getStaticProps在页面组件外部取数。App Router 则把取数逻辑下放到组件层级,在服务端组件里可以直接async配合await去拿数据。
如果你基于旧教程学习,然后去写 App Router 项目,很容易出现“代码逻辑对不上”的困惑。建议认准app/目录和next.config.js里的相关配置作为判断标准。你的项目里只要看到了app/目录,就是新架构。
重要提示:不要用 Vercel 的在线教程代码直接粘贴。他们更新太快,很多示例会默认你已经了解前置知识。
4. 路由系统与页面架构:从静态页面到动态路由
4.1 文件系统路由的完整使用场景
我用一个实际的内容型项目来演示文件系统路由是怎么组织页面的。
假设你要搭建一个博客,你的 URL 结构大概是这样:
/ # 首页,展示文章列表 /blog # 博客列表页 /blog/[slug] # 文章详情页 /tags/[tag] # 按标签筛选 /about # 关于页对应的目录结构是:
app/ ├── page.tsx # 首页 ├── blog/ │ ├── page.tsx # /blog │ └── [slug]/ │ └── page.tsx # /blog/xxx ├── tags/ │ └── [tag]/ │ └── page.tsx # /tags/xxx └── about/ └── page.tsx # /about这里的[slug]就是动态路由的写法。文件夹名字用方括号包起来,就代表这个位置可以匹配任意路径。在页面组件里,你可以通过params拿到这个值:
// app/blog/[slug]/page.tsx export default async function BlogPostPage({ params, }: { params: { slug: string }; }) { const post = await getPostBySlug(params.slug); return <article>{post.title}</article>; }4.2 布局系统的正确打开方式
布局系统的价值在内容型站点里体现得特别明显。还是以博客为例,你可能希望:
- 首页和博客列表页共用一个顶栏。
- 博客文章详情页在顶栏下方有一个“上一篇文章/下一篇文章”的导航。
- 后台管理页面完全不用顶栏,用独立侧边栏。
如果用纯 React 写,这些需求需要在组件层面做大量条件渲染。而 Next.js 的布局嵌套天然支持这种层级关系:
app/ ├── layout.tsx # 全局布局:顶栏 + 底部版权 ├── blog/ │ ├── layout.tsx # 博客局部布局:加一个推荐文章模块 │ └── [slug]/ │ └── page.tsx # 详情页内容 ├── admin/ │ └── layout.tsx # 管理后台独立布局:侧边栏子目录里的layout.tsx会自动包裹对应目录下的所有页面。这意味着你在app/blog/layout.tsx里放一个“热门文章推荐”模块,/blog和/blog/任何一篇文章都会自动带上这个模块,且切换文章时该布局不会重新渲染,页面切换体验非常顺滑。
4.3 并行路由与拦截路由:用得好的都是高手
这两个是 App Router 的进阶功能,新手期不必深究,但建议知道它们的存在,因为遇到特定场景会很救命。
- 并行路由:一个页面可以同时渲染多个独立区块,每个区块可以有自己的加载状态和错误状态。典型场景是仪表盘页面,比如同时展示订单数据和用户数据,两个区块互不阻塞。
- 拦截路由:在保留当前页面的情况下,预览另一个页面内容。典型场景是点击图片列表中的缩略图时,弹出一个详情模态框,URL 变成
/photo/123,但如果直接复制这个 URL 打开,则展示完整详情页。
这两个功能的核心思路是一致的:让 URL 和 UI 呈现解耦。理解了它们,你做复杂交互时会有更多灵活的筹码。
5. 数据获取与渲染策略:性能与体验的分水岭
5.1 服务端组件:Next.js 性能优势的基石
App Router 架构下,所有组件默认都是 Server Components(服务端组件)。这意味着组件代码在服务器上执行,用户拿到的 HTML 中已经包含渲染完成的内容。
这个机制带来了两个直接影响:
- 首屏加载更快:浏览器不需要等待 JS bundle 下载并执行后才看到内容,HTML 里已经有了内容,用户感知到的加载时间大幅缩短。
- SEO 更友好:搜索引擎可以直接从 HTML 中读取关键内容,不需要执行 JavaScript 才能爬取页面信息。
要注意的是,服务端组件不能使用useState、useEffect等浏览器端钩子。当你需要这些交互能力时,在组件文件的顶部加上"use client"标记,就可以把它变成客户端组件。这个设计一开始可能让人觉得麻烦,但它其实是刻意为之的——强制你思考,哪些交互真的需要发生在浏览器里。
5.2 四种渲染策略,一次讲清楚
| 渲染策略 | 数据更新时机 | 适用场景 | 缺点 |
|---|---|---|---|
| 静态生成(SSG) | 构建时 | 博客文章、营销页、文档站点 | 内容更新需要重新构建 |
| 服务端渲染(SSR) | 每次请求 | 个性化页面、实时数据仪表盘 | 服务端压力大、无缓存时慢 |
| 增量静态再生(ISR) | 按设定间隔 | 电商价格、新闻列表 | 间隔期内数据不是绝对最新 |
| 客户端渲染(CSR) | 浏览器加载后 | 用户交互复杂的应用 | 首屏慢、SEO 弱 |
在 App Router 里面,实现这些策略非常直接,多数情况下你不需要写繁琐的配置代码,而是通过控制“数据请求的地方和方式”来决定渲染策略。
举个例子,在服务端组件里不加任何缓存配置的fetch,默认就是 SSR:
// 每次请求都会执行 const res = await fetch("https://api.example.com/data", { cache: "no-store", });而带cache: "force-cache"的请求,在构建时就会取一次数据,之后一直复用,这就是 SSG。加上next: { revalidate: 60 },页面每 60 秒后台重新验证一次数据,这就是 ISR:
const res = await fetch("https://api.example.com/data", { next: { revalidate: 60 }, });5.3 新手最容易踩的缓存问题
我在社区里看到最多的问题就是:“我明明更新了数据库,为什么页面上还是旧数据?”
答案几乎都和缓存策略有关。默认情况下,Next.js 会对使用fetch且未指定cache的请求做静态缓存(App Router 中默认驱动是静态优先),也就是说,在开发环境你改一次数据可能看到新结果,但生产环境网站会一直用构建时的数据。
解决思路有几个,按实用度排序:
- 明确指定缓存策略,不要依赖默认值。
- 实时性要求高的页面,用
cache: "no-store"或设置export const dynamic = "force-dynamic"。 - 定期更新的页面,用
revalidate做 ISR,兼顾速度和新鲜度。
另外还有一个容易忽略的点:如果你的页面从 URL 参数里读取数据(比如搜索关键词),在服务端组件里读取searchParams时,Next.js 会强制该页面为动态渲染。这其实是正确行为,但你得有这个心理预期,不要以为是 bug。
5.4 API 路由:前后端一体化的落地
Next.js 的 API 路由允许你在app/api/目录下创建接口。
// app/api/subscribe/route.ts import { NextResponse } from "next/server"; export async function POST(request: Request) { const body = await request.json(); const email = body.email; if (!email || !email.includes("@")) { return NextResponse.json({ error: "邮箱格式不正确" }, { status: 400 }); } // 这里可以写数据库存储逻辑 return NextResponse.json({ success: true }); }这里的核心价值不是“能写接口”,而是你可以和前端共用同一套类型定义和工具函数。在大型项目里,前后端类型同步是一个不小的成本,Next.js 从架构上抹平了这个问题。
我个人的经验是:API 路由适合做轻量级的业务接口,比如表单提交、鉴权回调、Webhook 接收。如果业务逻辑复杂、需要后台任务队列或复杂数据库查询,还是应该拆出独立后端服务,不要让 API 路由承载过重的逻辑。
6. 项目实战:从 0 到 1 搭建一个内容型全栈应用
6.1 实战项目选型:内容型站点是最佳练手场景
我建议你的第一个 Next.js 实战项目,选择“内容型应用”——比如个人博客、作品集、文档站,或者一个小型企业官网。
原因有三:第一,它对数据获取和渲染策略的组合要求比较典型,能练到核心知识;第二,内容型应用的 SEO 需求能倒逼你理解服务端渲染的价值;第三,它不需要复杂的用户系统和权限逻辑,入门门槛适中。
下面我用一个具体的例子串一遍整个流程。假设我们要做一个面向团队内部的技术博客,功能包括:文章列表、文章详情、按标签筛选,以及一个最基础的管理后台(发布文章)。这个项目规模适中,但涵盖了 Next.js 的绝大多数核心能力。
6.2 用 Payload CMS 作为内容层:为什么这么选
动手之前,先聊一下内容管理。如果要做一个内容型项目,“内容存在哪里”是第一件要想清楚的事。你可以选择,用 Markdown 文件管理和配 Next.js 的静态生成,或者用传统无头 CMS(比如 Strapi、Sanity)。
我要多提一个选项:Payload CMS。它和 Next.js 的集成体验在近几年做得相当出色,而且因为它是 TypeScript 原生的,数据模型、API 接口和前端类型可以保持完整同步。你不需要额外维护一份 API 文档,改一个字段类型,从前端到后端自动生效。这一点在项目演进时性价比极高。
在 Next.js 项目中集成 Payload,流程大致是:
- 在项目中安装
payload和@payloadcms/next。 - 通过配置文件定义内容模型,比如“文章”字段包含标题、副标题、正文、标签、封面图。
- 在
app/api下挂载 Payload 的路由处理逻辑。 - 在服务端组件里通过 Payload 的本地 API 拉取文章列表和详情。
与直接调用 REST API 不同,Payload 在 Next.js 环境里可以走本地 API 调用,数据不需要经过 HTTP 网络请求,在性能和开发体验上都有明显优势。以代码来直观感受一下:
import { getPayload } from "payload"; import config from "@payload-config"; export default async function HomePage() { const payload = await getPayload({ config }); const posts = await payload.find({ collection: "posts", sort: "-createdAt", limit: 10, }); return ( <div> {posts.docs.map((post) => ( <h2 key={post.id}>{post.title}</h2> ))} </div> ); }如果你不想引入 CMS 这么重的体系,纯粹用本地 Markdown 文件也可以,思路是一样的——在服务端组件中读文件、解析 frontmatter、返回内容即可。区别只是:CMS 帮你解决了后台编辑和媒体管理的 UI,Markdown 方案则更轻、完全可控。
6.3 核心页面实现细节
下面列出实战项目里最核心的几个页面,以及它们的实现要点。
文章列表页
列表页的关键是分页和标签筛选。在 App Router 中,用 URL 参数来表达筛选条件是最规范的做法,这样筛选结果可以分享给其他人。
// app/blog/page.tsx interface Props { searchParams: { page?: string; tag?: string }; } export default async function BlogPage({ searchParams }: Props) { const page = Number(searchParams.page) || 1; const tag = searchParams.tag; const posts = await getPosts({ page, tag }); return ( <div> {posts.map((post) => ( <article key={post.id}> <Link href={`/blog/${post.slug}`}>{post.title}</Link> </article> ))} </div> ); }注意:服务端组件里读取
searchParams会让页面变成动态渲染。如果列表数据变化不频繁,建议在列表页使用 ISR,缓存周期设短一点即可。
文章详情页
详情页的重点是静态路径生成。对于构建时就能确定所有文章的场景,可以用generateStaticParams一次性生成所有详情页,站点性能极好:
// app/blog/[slug]/page.tsx export function generateStaticParams() { return [{ slug: "hello-world" }, { slug: "nextjs-guide" }]; }如果文章数量很大,可以只预生成一页部分文章,其余页面按需构建,配合 ISR 同样能实现接近静态页的体验。
后台发布页
后台是一个典型的客户端组件场景。发布表单需要实时校验、预览、图片上传交互,这些必须在浏览器里执行。用'use client'标记组件,然后调用 API 路由把数据写入 Payload 即可。
6.4 环境变量与安全问题
前后端一体的项目里,环境变量的管理要比纯前端项目更谨慎。所有放在NEXT_PUBLIC_前缀下的变量都会暴露到浏览器端,只适合放站点地址、公开地图 key 之类的不敏感信息。
数据库连接串、CMS 密钥、鉴权 token 这类变量,一律不加前缀,只能在服务端读取。Next.js 会自动在服务端组件中替换这些值,但你要注意不要把它们通过 props 传给子组件,传给客户端组件会被打包进浏览器 bundle。
我见过有人把数据库地址直接写在NEXT_PUBLIC_变量里提交到 Git,这个事故级错误值得反复强调:上线前用代码扫描工具过一遍环境变量是最基本的操作。
7. 常见问题与排查技巧实录
7.1 Hydration 错误:组件在服务端和浏览器端渲染结果不一致
这是 Next.js 新手必遇到的问题。报错信息通常类似:
Hydration failed because the initial UI does not match what was rendered on the server.原因是:服务端渲染出来的 HTML 和浏览器端首次渲染时的 HTML 不一致。最常见的触发源是组件里用了Date.now()、Math.random()这类会在每次渲染产生不同结果的值,或者读取了浏览器专属 API。
排查思路:
- 看报错信息中给出的组件路径,定位到具体文件。
- 检查组件里是否有随机数或时间相关逻辑,把它移到
useEffect里执行。 - 或者用
suppressHydrationWarning属性跳过特定元素的校验(不推荐大面积使用)。
7.2 页面数据迟迟不更新
开发环境下,你可能觉得“我改了内容,页面怎么没反应”。生产环境下,这种情况通常与缓存策略有关。
我建议的排查路径是:
- 检查
fetch请求的缓存配置是不是no-store。 - 确认页面是否被
generateStaticParams生成为静态页。 - 查看你的路由是不是属于动态渲染,可以通过在页面里临时加一行
export const dynamic = "force-dynamic"来验证。
这种问题的难点不是修复,而是判断到底该用哪种策略。数据新鲜度和性能之间永远需要权衡,没有“一键永远最新且极快”的方案。
7.3 部署之后的静态资源加载慢
把 Next.js 应用部署到自建服务器时,最容易忽略的是next/image组件的图片优化功能。这个组件默认会请求一个图片优化 API 端点,它需要 Node.js 服务端支持。如果你把next start放在非 Node 环境,或者部署在静态托管平台而不是服务器环境,图片会无法加载或一直转圈。
解决方案就是按部署环境调整images配置项,使用 Cloudinary 或云厂商的图片 CDN,关闭本地优化。
// next.config.js module.exports = { images: { unoptimized: true, // 静态托管时使用 }, };这个配置是在好几种真实部署场景里都会碰到,属于那种“文档里一笔带过、但实际操作里绕不开”的细节。
7.4 常见问题速查表
| 现象 | 可能原因 | 检查方向 |
|---|---|---|
| 页面内容不更新 | 缓存策略过于静态 | fetch cache、ISR revalidate 配置 |
| 首屏白屏 | 客户端组件逻辑过重 | 把非交互部分迁移到服务端组件 |
| 图片加载失败 | 图片优化 API 不可用 | next.config 中的 images 配置 |
| Hydration 报错 | 服务端/浏览器渲染不一致 | 排查随机值、时间、浏览器 API |
| 环境变量在浏览器端泄露 | 使用了 NEXT_PUBLIC_ 前缀 | 检查环境变量命名和提交历史 |
| 构建失败但本地正常 | Node 版本不一致 | Vercel/服务器环境变量未设置完整 |
7.5 几个值得养成的习惯
用 Next.js 做项目时间久了,我总结出几个可以明显少踩坑的习惯:
- 默认优先服务端组件。刚开始可能觉得客户端组件写起来顺手,但服务端组件带来的性能收益越大越明显,而且它会倒逼你思考“这个数据真的需要发到浏览器吗”。
- 接口返回数据也建类型。Next.js 的 API 路由和页面共用一个代码库,类型定义应该成为你和后端(或者未来的自己)之间的契约。
- 用 Vercel 部署不代表终点。如果你未来的目标是大规模生产环境,尽早了解 Docker 部署、Nginx 反代、Node 进程管理,这些知识在你的项目流量上来后都会派上用场。
8. 性能优化与工程化进阶:从“能跑”到“能打”
8.1 字体与图片:容易被忽视的首屏瓶颈
Next.js 提供了两个内置组件,我用下来觉得它们比任何第三方优化库都值得优先使用:next/font和next/image。
next/font会自动做字体子集化,也就是说浏览器只需要下载页面实际用到了的那几十个字符,而不是一整份几 MB 的字库文件。中文字体文件特别大,如果你做中文站,这个优化几乎是必须做的。配置方式很直观:
import { Inter } from "next/font/google"; const inter = Inter({ subsets: ["latin"] });next/image则提供了响应式图片、懒加载、占位图等能力。它最大的好处是:开发者只需要声明图片的用途(宽度、优先级),框架自动帮你生成适配不同屏幕的尺寸,浏览器按需加载。这能省掉大量手写srcset的工作量。
8.2 缓存策略的精细化管理
在实际项目中,你会发现“全局一套缓存策略”是行不通的,还是要按模块做精细化管理。
我在一个资讯类项目里的做法是:
| 数据类型 | 策略 | 原因 |
|---|---|---|
| 文章列表 | ISR,revalidate 600 秒 | 内容更新频率不高,但允许延迟 |
| 文章详情 | ISR,revalidate 3600 秒 | 详情页流量大,尽量静态化 |
| 用户登录态 | 不缓存,动态渲染 | 数据实时性要求高 |
| 站点配置 | SSG,构建时生成 | 几乎不变,直接静态 |
这套配置的好处是,不同模块的性能和实时性得到差异化满足。第一次做的话不用追求完美,先跑通再逐步调优。
8.3 开发时的本地 HTTPS 与高级调试
还有一个细节:如果你的项目需要调用摄像头、地理位置等浏览器 API,本地开发环境需要 HTTPS。Next.js 的开发服务器支持通过next dev --experimental-https快速开启本地 HTTPS,省得自己折腾自签名证书,这算是一个不太为人知的小技巧。
另外,打开浏览器的 React DevTools,可以看到组件树中哪些实际渲染在服务端、哪些在客户端,按此调整组件边界是最直观的。
9. 从项目实战到知识体系:我的最后几点体会
如果让我总结一条学习 Next.js 的核心路径,那会是:先理解“为什么要有服务端组件”,再理解“渲染策略是数据决定的”,最后理解“文件系统路由不是限制,而是结构化的引导”。
这套框架的上手难度其实比很多人想象中低,难的是转变思维方式——从一个纯前端开发者的视角,切换到“全栈应用工程师”的视角。你不再只是把组件渲染出来就结束了,你还需要考虑数据在哪里取、在哪里缓存、在哪里运行、如何部署。但恰恰是因为要考虑这些,你的技术能力才会有一个肉眼可见的跃升。
我在实际项目中最大的体会是:不要被框架的“新概念”吓住。App Router、服务端组件、RSC、ISR,听起来是一大堆名词,但剥开看,它们都是在回答几个朴素的问题:数据在哪里跑最合适?页面怎么做到又新又快?代码怎么组织最清晰?
等你把上面这条路径完整走一遍,你会发现,Next.js 不仅是一个框架,也是一套关于“现代 Web 应用应该怎么构建”的参考答案。希望这篇内容能帮你少走一些弯路,更快地走进 Next.js 的世界里去动手试一试。