写在前面:上篇我们把"为什么"讲透了------SPA 体验虽好但 SEO 是短板,SSR 把 React 组件搬到服务器渲染,爬虫就能读到完整内容。这篇进入"怎么做":一条命令创建全栈项目、App Router 约定大于一切、
layout.tsx布局 +metadata做 SEO、'use client'声明强交互页面、水合(hydration)激活交互,最后用一个 Todos 全栈 demo 把前后端串起来。上篇讲思想,这篇全是干货,开干!
五、create-next-app:开箱即用的全栈框架
5.1 一条命令,全家桶配齐
bash
npx create-next-app@latest
选择默认配置,一路回车。它已经把全家桶给你配好了:
| 组件 | 作用 |
|---|---|
react / react-dom |
React 界面 |
typescript |
类型安全 |
tailwindcss |
样式 |
eslint |
代码风格规范 |
老师说:
"next.js 是给react 开发者的开箱即用的利器。"
Next.js 是 React 全栈框架(Nuxt 是 Vue 全栈框架),能写页面(前端),也能写 API(后端)。背靠 Vercel,SEO 做得非常棒,很多 AI 产品用它做官网。
5.2 约定大于一切:App Router
最颠覆认知的一点:
"约定大于一切" "不需要建,文件就是路由,嵌套路由 建立文件夹" "page.tsx 就是页面" "nav 共用的,layout.js 布局文件"
不需要建路由配置文件,文件本身就是路由! 这就是 App Router:
bash
app/
├── layout.tsx # 根布局:全站共用的导航
├── page.tsx # 首页:/ → Hello World
├── about/
│ └── page.tsx # /about → About Us
├── dashboard/
│ ├── layout.tsx # 嵌套布局:后台自己的导航
│ ├── page.tsx # /dashboard → Hello Dashboard
│ └── settings/
│ └── page.tsx # /dashboard/settings → Hello Setting
├── todos/
│ ├── page.tsx # /todos → 待办事项
│ └── types.ts # Todo 类型定义
└── api/
└── todos/
└── route.ts # /api/todos → JSON 接口
六、布局与路由:layout.tsx + page.tsx
6.1 根布局与 metadata
渲染规则是这样的:
"先到layout.tsx 布局 - page.tsx"
先渲染布局,再渲染页面。根布局里挂全站导航,用 next/link 的 Link 做前端跳转:
tsx
import type { Metadata } from "next";
import Link from "next/link";
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({ children }: LayoutProps<"/">) {
return (
<html lang="en" className="h-full antialiased">
<body className="min-h-full flex flex-col">
<nav>
<ul>
<li><Link href="/">首页</Link></li>
<li><Link href="/about">关于</Link></li>
<li><Link href="/dashboard">后台</Link></li>
<li><Link href="/todos">Todos</Link></li>
</ul>
</nav>
{children}
</body>
</html>
);
}
注意 metadata------上篇讲的 SEO 三件套里的 <title> 和 <description>,Next.js 直接让你用 TypeScript 写在组件里。这就是"为了 SEO 而生的框架"。
6.2 嵌套路由与嵌套布局
后台管理系统有自己独立的导航,用嵌套布局:
tsx
import Link from 'next/link'
export default function DashboardLayout({children}) {
return (
<div>
<nav>Nav
<Link href="/dashboard/settings">settings</Link>
</nav>
{children}
</div>
)
}
/dashboard 的页面先套「后台专用」布局,再套根布局,层层嵌套,像俄罗斯套娃。页面本身朴素得像个招牌:
tsx
// 服务器端组件
// 在服务器端 react node 的运行方式
// jsx -> html
export default function Home() {
return (
<h1>Hello World</h1>
);
}
七、服务端组件与客户端组件
7.1 默认都是服务端组件
老师说:
"next.js 将react server component 带到服务器端渲染,ssr开发模式" "jsx -> html seo"
Next.js 把 React Server Component 带到了服务端渲染里:默认情况下组件都是服务端组件,在服务器上编译成 HTML,为了 SEO。
7.2 'use client':强交互页面
那交互怎么办?总不能让用户点按钮就刷新页面吧?
老师说:
"有些页面 强交互" "'use client' 声明" "不是只在浏览器渲染, 先在服务器端把能渲染的渲染完,再去客户端渲染。"
需要强交互的页面,在文件顶部写一行 'use client' 声明即可:
tsx
// react 可以在后端运行
'use client';
// 组件在前端渲染的标记
// 添加事件,useEffect,调用后端接口 csr next.js 也支持
// React Server Component
7.3 水合(hydration):水饺理论
老师讲 hydration 的时候打了个极其生动的比方,我直接引用原话:
"包好了水饺,冻上,给你送过来" "水煮 水和" "水合(hydration):浏览器拿到静态 HTML 之后,挂载客户端 js、绑定点击事激活交互;"
服务器先"包好水饺、冻上"(渲染成静态 HTML 发过来),浏览器拿到之后"下水煮"------挂载客户端 JS、绑定点击事件激活交互,这就是水合(hydration)。
所以:
"csr 组件 会执行两次,1次载服务器,第二次是在客户端,打补丁,"
客户端组件其实执行两次:第一次在服务器(速冻发货),第二次在客户端(下水煮开、打补丁)。你拿到的不是生面团,是熟的、能直接下锅的饺子。
八、全栈 Demo:Todos
理论讲完,直接上老师的实战 demo:一个全栈待办事项(Todos),类型、API、页面一条龙。
8.1 类型定义:types.ts
ts
export type Todo = {
id: number;
content: string;
completed: boolean;
}
8.2 API 接口:route.ts
Next.js 里除了带 'use client' 的文件都是后端,API 接口也遵守 App Router 约定:
ts
// next.js 除了 use client 都是后端
// api 数据接口 仍然满足 app router 约定
// route.ts 返回json 数据接口的
import { type Todo } from '../../todos/types';
let todos: Todo[] = [
{ id: 1, content: "学习AppRouter", completed: false },
{ id: 2, content: "Next.js 个人官网开发", completed: false },
]
// /api/todos get 请求 restful
export async function GET() {
// 返回json 数据接口 next.js 封装好了Response
return Response.json(todos);
}
export async function POST(req:Request) {
const body = await req.json();
const newTodo: Todo = {
id: +Date.now(),
content: body.content,
completed: false,
}
todos.push(newTodo);
return Response.json(newTodo);
}
GET 和 POST 就是两个导出的异步函数,Response.json() 帮你把 JSON 封装好了------RESTful 接口就是这么简单。id: +Date.now() 那个 + 号是把时间戳字符串转成数字,老师的偷懒神器。
8.3 前端页面:page.tsx
带 'use client' 的交互组件,useState 管状态、useEffect 拉数据、fetch 调接口:
tsx
export default function TodosPage() {
const [todos, setTodos] = useState<Todo[]>([]);
const [ text, setText ] = useState<string>('');
const fetchTodos = async() => {
const res = await fetch("/api/todos");
const data: Todo[] = await res.json();
setTodos(data);
}
const handleAdd = async() => {
if (!text.trim()) return
await fetch("/api/todos", {
method: "POST",
headers: {"Content-Type":"application/json"},
body:JSON.stringify({content:text})
})
}
useEffect(() => {
fetchTodos();
}, [])
return (
<div style={{marginTop: '12px'}}>
<h1>待办事项</h1>
<input value={text} onChange={
(e) => setText(e.target.value)}
placeholder="请输入新的待办任务"
/>
<button onClick={handleAdd} style={{marginLeft:"8px"}}>添加</button>
<ul style={{paddingLeft: "0", listStyle: "none"}}>
{
todos.map((item) => (
<li key={item.id} style={{
margin:"8px 0", display:"flex",
gap:"10px"
}}>
<span style={{
textDecoration: item.completed ? "line-through" : "none",
cursor:"pointer"
}}>
{item.content}
</span>
<button>删除</button>
</li>
))
}
</ul>
</div>
)
}
这就是一整套全栈闭环:前端页面 fetch("/api/todos") → Next.js 后端 route.ts 处理 → 返回 JSON → 前端渲染。之前学 React 前后端分离,要开两个项目;现在 Next.js 一个项目全搞定。
九、总结:大前端手里的 Next.js
| 概念 | 说明 |
|---|---|
| Next.js | React 全栈框架,能写页面也能写 API,背靠 Vercel,SEO 极佳 |
| App Router | 约定大于一切,文件就是路由 |
| layout.tsx | 布局文件,先渲染布局再渲染页面 |
| page.tsx | 页面组件,编译成 HTML |
| route.ts | API 接口,返回 JSON |
| 'use client' | 强交互页面声明,先在服务器渲染再去客户端水合 |
| 水合(hydration) | 服务器包好速冻水饺,浏览器下水煮激活交互 |
Next.js 是给 React 开发者的开箱即用利器:App Router 约定式路由、layout 布局 + metadata SEO、服务端组件默认 SSR、route.ts 直接写 API,一套代码打通全栈。
写在最后(下篇)
今天最大的收获,是亲手搭出了第一个全栈项目。以前觉得"SEO 优化"是运营的事,现在发现前端就能解决------用 Next.js 把 React 组件搬到服务器渲染,爬虫看到的就不再是空 #root,而是完整的内容。很多 AI 产品官网都用 Next.js,不是没有道理的:SEO 好、能全栈、背靠 Vercel 部署方便。老师说后面还有一章 Next.js 的内容,估计是数据获取、动态路由这些更进阶的玩法,学完继续更!
下次面试官问你:"Next.js 的 App Router 是什么?'use client' 是干嘛的?怎么用 Next.js 写 API?"
你可以淡定地说:
"Next.js 的 App Router 约定大于一切:不需要建路由配置文件,文件本身就是路由,page.tsx 就是页面、layout.tsx 是布局、route.ts 是 API 接口,嵌套路由直接建文件夹。默认情况下组件都是服务端组件,在服务器上编译成 HTML,为了 SEO;强交互页面在文件顶部写 'use client' 声明,组件会先在服务器渲染一遍、再到客户端水合(hydration)激活交互------就像包好的速冻水饺,服务器发货,浏览器拿回家下水煮。写 API 也很简单,route.ts 里导出 GET、POST 异步函数,Response.json() 直接返回 JSON,前端页面 fetch 自己的接口就能形成全栈闭环。"
然后看着面试官满意的表情,心里默念:这波,又稳了。
本文所有代码示例均来自课堂学习资料,真实可运行。