← FC Coder · HomePhase 03 · Lesson 34 · 60 min
Lesson34
Phase Three · Fullstack · Matchday 34 · Call Server Directly

Server Action
客户端直接调函数

Today's 3 Jobs · 今天这三件事
  1. 01
    squads 表 schema + push
    存阵容
  2. 02
    lib/actions.ts · use server · createSquad
    0 个 API endpoint
  3. 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

Chalk Board · 流程
"use server";
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 提交跳详情 = 算过。