← FC Coder · HomePhase 03 · Lesson 33 · 60 min
Lesson33
Phase Three · Fullstack · Matchday 33 · Read From Cabinet

Server 读 DB
0 个 API · 0 个 useState

Today's 3 Jobs · 今天这三件事
  1. 01
    app/players-db/page.tsx · async server · await db.select
    0 个 useState
  2. 02
    fantasy 拆 server + client board
    server 拿数据 · client 管 state
  3. 03
    🌟 验证 fantasy 还能用 · 但数据来自 DB
    JSON 退役

Server Component 直读 DB —— `await db.select().from(players)` 一行。fantasy 拆 server wrapper + client board:server 拿数据 · client 管状态。这是 Phase 3 关键 pattern · 反复见。

Concept · Server 拿 / Client 管

边界清晰 · 一个组件一种职责

Chalk Board · 数据流
// server
const rows = await db.select().from(players);
return <FantasyBoard initialPlayers={rows} />;
server
async function · await db.select()
client
use client · useState · onClick
server 传 initialPlayers prop 给 client

一个组件不能 async + useState。所以拆。

Half 2 · 在屏幕上

server 读 · fantasy 拆 · AI elite

01Server 读 DB 渲染
01Min

Cursor + pnpm dev

老三件套。
02Min

app/players-db/page.tsx (server)

import { db } from '@/lib/db'; import { players } from '@/lib/schema'; export default async function() { const rows = await db.select().from(players); return ...players.map(p => <PlayerCard player={p} />); }
03Min

访问 /players-db · 看 22 张卡(数据来自 DB)

DevTools Network 看 0 个 /api 请求。HTML 直接带数据。
02Fantasy 拆 server + client
04Min

app/fantasy/page.tsx · 改 server async wrapper

不标 use client。export default async function FantasyPage() { const rows = await db.select().from(players); return <FantasyBoard initialPlayers={rows} />; }
05Min

app/fantasy/fantasy-board.tsx · 标 use client · 收 props

把原 fantasy 内容搬这里。'use client'。export function FantasyBoard({ initialPlayers }: { initialPlayers: Player[] }) { ...原 useState/useLocalStorage 逻辑 ... }
06Min

刷新 /fantasy 验证 · 22 张卡 + 阵容板 + 化学度都对

数据来自 DB 但交互不变。这是 Phase 3 关键 pattern。
03AI 写 /players-elite
07Min

AI Supervised:写 /players-elite (rating >= 85)

Cmd+K · 'server 页面 · .where(gte(players.rating, 85)) · .orderBy(desc(rating))'。爸爸陪坐。
08Min

📸 截图 /players-db + /players-elite

Phase 3 第八张战利品。
讲给爸爸听

4 题 · Server / Client 分工

01为什么 server 能直 await db?Hint ↓

服务器能直连 DB · 安全。client 直连 DB 会暴露密码 / secrets。

02server 拿数据 + client 管状态边界?Hint ↓

Server 一次拿初始数据 · client 之后用 useState 操作。一个组件不能同时 async + useState。

03DB vs JSON import?Hint ↓

DB 能改 / 查 / 多用户 / 持久 · JSON 死的。Phase 34 起会写 DB。

04await db.select() 返回什么类型?Hint ↓

TS 自动推 Player[] · Drizzle 知道 schema。第 20 课 interface 心法延续。

温度计

给「Server 读 DB」打分

今天难度Difficulty
0
今天开心Fun
0
Final Whistle · 终场哨

数据真从档案柜出来 —— fantasy 升级到 DB driven。

还有 8 步没打勾。Step 3 看到 22 张卡 + Step 6 fantasy 验证通过 = 算过。