← FC Coder · HomePhase 02 · Lesson 16 · 60 min
Lesson16
Phase Two · Fantasy Builder · Matchday 16 · First Component

React 组件
给 JSX 起名字

Today's 3 Jobs · 今天这三件事
  1. 01
    新建 components/player-card/index.tsx
    把一坨 JSX 起名字
  2. 02
    sandbox 里 import + 用 <PlayerCard />
    首字母大写
  3. 03
    .map 简化 · 改组件文件看 22 张同步变
    改一处管一堆

Phase 1 你的 .map 里一坨 5-10 行 JSX。今天把那一坨起个名字 —— <PlayerCard />。Scratch 自定义积木 · EA FC 自定义战术 同一回事。React 组件 = 给一段 JSX 起名字。声明式 = 说要什么 · 不说怎么画。

Essence · 本质点

Declarative · 说要什么不说怎么画

教练说 4-3-3 · 球员自己跑位。React 的核心姿势。

Chalk Board · 命令式 vs 声明式
function PlayerCard() {
return ( ...JSX... );
}
命令式
画矩形 · 涂金 · 写字号 48 · ...
声明式
<PlayerCard />
React
用的就是声明式

你写 JSX 说「我要长这样」· React + 浏览器自己负责变成网页。Canvas 是命令式(Phase 4 见)· React 是声明式。

Essence · 改一处管一堆

组件 = UI 的 DRY

Phase 1 变量是数据的 DRY · 今天组件是 UI 的 DRY · 同一种思想。

Chalk Board · DRY 进化
改 PlayerCard 1 行22 张卡同步变
Phase 1 #9
变量 = 数据起名字
Phase 1 #14
函数 = 步骤起名字
今天
组件 = JSX 起名字

三个本质点都是「起名字 · 改一处管一堆」。代码越大 · 这一招越重要。

Roster · 今天 3 个新工具

组件 · 声明式 · 改一处管一堆

抄着用 · 看 22 张同步变是今天的「哇」。

  1. 01
    function PlayerCard() { return ... }
    给一段 JSX 起名字 —— Scratch 自定义积木 · EA FC 自定义战术。
    首字母必须大写。export 给外面用 · import 在别处用。
  2. 02
    <PlayerCard />
    声明式 · 说要什么不说怎么画 —— 教练说 4-3-3 · 不说哈兰德往左 3 米。
    React 的核心姿势。Phase 2 第 1 个本质点。
  3. 03
    改一处 · 管一堆
    组件最大的力 —— 改 PlayerCard 一行 · 22 张卡同步变。
    Phase 1 变量是数据的 DRY · 今天组件是 UI 的 DRY。
Half 2 · 在屏幕上

抽出第一个组件 · 见证「改一处管一堆」

做完一步就点 ✓。今天的 PlayerCard 写死哈兰德,下节课 props 让它接收数据。

01新建组件文件
01Min

Cursor + pnpm dev

老三件套。
02Min

components/ 右键 New Folder · player-card

然后 player-card/ 右键 New File · index.tsx · 空白打开。
03Min

写 export function PlayerCard() { return (...哈兰德卡...) }

export function PlayerCard() { return (<article className="..."><h1>哈兰德</h1>...</article>); }。注意首字母大写。保存。
02import + 调用 · 3 张哈兰德
04Min

sandbox 里 import { PlayerCard } from '@/components/player-card'

在 sandbox 顶部 import 区。保存 · 浏览器不变(还没用)。
05Min

<main> 里手动写 <PlayerCard /> × 3

把 .map 暂时注释。换成 <PlayerCard /><PlayerCard /><PlayerCard />。保存 · 3 张哈兰德。
03.map · 改一处 22 张同步
06Min

改成 {players.map((p, i) => <PlayerCard key={i} />)}

把 3 个手动改成 .map。保存 · 22 张哈兰德(全一样 · 因为组件内写死)。
07Min

对比:今天 .map 一行 · 13 课 5-10 行

.map(p => <PlayerCard key... />) vs Phase 1 第 13 课的 .map(p => (<article ...><h1>{p.name}</h1>...</article>))。今天的简洁多了。
08Min

🌟 改 PlayerCard className 加 rotate-1 · 22 张同步变

在 player-card/index.tsx 文件里 article className 加 rotate-1。保存 · 所有 22 张卡都旋转。改一处 · 管一堆。
09Min

改回去 · 移除 rotate-1

恢复正常。
04玩 · 截图
10Min

玩 5 分钟 · 在 PlayerCard 内加 emoji 头像 · 改样式

<p className="text-5xl">⚽</p> 等等。每改一下 22 张同步变。
11Min

📸 截图战利品

Mac Shift + Cmd + 4 · 存 2026-XX-XX-我的第一个组件.png · Phase 2 第一张战利品。
Half Time · 中场 · 讲给爸爸听

4 题 · 重点:组件 / declarative / 改一处管一堆

第 2 题用「教练 vs 球员」比喻最直接。

01什么是 React 组件?用 Scratch 自定义积木的比喻讲。Hint ↓

给一段 JSX 起名字。以后用名字代替整段。Scratch 自定义积木 / EA FC 自定义战术同一回事。

02Declarative 是什么意思?用「教练 vs 球员」的比喻。Hint ↓

声明式 = 说要什么不说怎么画。教练说 4-3-3 · 球员自己跑位。

03<PlayerCard /> 首字母为什么大写?Hint ↓

React 用大写区分组件 vs HTML 标签。小写会被当 HTML。

04改一个组件文件 · 22 张卡都变 —— 这种「改一处管一堆」是什么力量?Hint ↓

复用 / DRY。Phase 1 变量是数据的 DRY · 今天组件是 UI 的 DRY · 同一种思想。

Player Rating · 本课温度计

给 Phase 2 第一节打个分

说真话。爸爸会看到。

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

你抽出了第一个 React 组件 —— 22 张卡用一个名字管。

还有 11 步没打勾。Step 8 改组件 22 张同步变那一刻就是今天的核心 —— 其他下次补。