← FC Coder · HomePhase 03 · Lesson 34 · 60 min
Lesson34
Phase Three · Fullstack · Matchday 34 · Call Server Directly
Server Action
客户端直接调函数
Today's 3 Jobs · 今天这三件事
- 01squads 表 schema + push存阵容
- 02lib/actions.ts · use server · createSquad0 个 API endpoint
- 03🌟 form action={createSquad} · 提交 → DB → 跳详情一气呵成
写 DB 的开关在 client · 实际跑在 server。"use server" 标 + <form action={fn}> 提交 · Next.js 自动桥接 —— 0 个 API endpoint。本质点:Server Action = 客户端调函数。
Concept · Server Action
0 endpoint · 0 fetch · 0 useState
"use server";
export async function createSquad(formData: FormData) {
await db.insert(squads).values({ ... });
redirect(`/squads/${id}`);
}
export async function createSquad(formData: FormData) {
await db.insert(squads).values({ ... });
redirect(`/squads/${id}`);
}
标记
'use server'
调用
<form action={createSquad}>
返回
.returning() + redirect()
Next.js 帮你把 form POST → 路由 → 调函数。代码量比写 endpoint 少一半。
Half 2 · 在屏幕上
schema · action · form · 跳详情
01squads schema + push
01Min
Cursor + pnpm dev
老三件套。
02Min
lib/schema.ts 加 squads 表(id / name / playerIds / createdAt)
export const squads = sqliteTable('squads', { id: integer().primaryKey({autoIncrement:true}), name: text().notNull(), playerIds: text().notNull(), createdAt: integer().notNull().$defaultFn(() => Date.now()) });
03Min
pnpm drizzle-kit push
Drizzle 创建 squads 表。studio 验证。
02Server Action + form
04Min
新建 lib/actions.ts · 'use server' + createSquad(formData)
'use server'; import { db } from './db'; import { squads } from './schema'; import { redirect } from 'next/navigation'; export async function createSquad(formData) { const name = formData.get('name') as string; const [c] = await db.insert(squads).values({name, playerIds:'[]'}).returning(); redirect(`/squads/${c.id}`); }
05Min
app/squads/new/page.tsx · form action={createSquad}
<form action={createSquad}><input name='name' required/><button>创建</button></form>。
06Min
app/squads/[id]/page.tsx · server 读 detail
async function({ params }) { const { id } = await params; const [s] = await db.select().from(squads).where(eq(squads.id, Number(id))); return <h1>{s.name}</h1>; }
07Min
🌟 访问 /squads/new · 输 '我的梦之队' · 提交
自动跳到 /squads/1 · 显示标题。0 个 fetch · 0 个 endpoint。
08Min
再创一个 · 看 /squads/2
id 自增。
03AI 写 delete action
09Min
AI Supervised:加 deleteSquad action
Cmd+K · '加 deleteSquad(id: number) action · 删除后 redirect /squads'。爸爸陪坐。
10Min
📸 截图 squads 表 + 详情页
Phase 3 第九张战利品。
讲给爸爸听
4 题 · Server Action
01Server Action 和 API endpoint 差?Hint ↓
Action 是函数 · Next.js 自动桥 · 0 endpoint。代码少。
02use server 第一行?Hint ↓
文件顶 · 标记该文件函数跑在服务器。类比 use client。
03form action={createSquad}?Hint ↓
浏览器提交 form · 数据 POST · Next.js 调函数。
04.returning() 干什么?Hint ↓
insert 后立刻拿回新行 · 含自增 id。
温度计
给「客户端调函数」打分
今天难度Difficulty
0
今天开心Fun
0
Final Whistle · 终场哨
form 提交 → DB → 跳详情 · 一气呵成。
还有 10 步没打勾。Step 7 提交跳详情 = 算过。