大家好,我是程序员柏风,AI 最全的 Vibecoding 学习地图 http://coderoadmap.cn 作者。
函数组件
这一课你将能做到
- 写出一个函数组件并在另一个组件里使用它
- 遵守「组件名大写」约定
- 理解:渲染阶段尽量保持「纯粹」(同样输入同样输出)
为什么要学
页面拆成页头、路径卡片、按钮,各自一块——就是组件。
现代 React 以函数组件为主:一个函数,返回 JSX。
人话:组件 = 可复用的自定义标签。你写 function PathCard(...),别人就能写 <PathCard />。
本站首页如果把「一张路径卡」和「整页导航」揉在一个 800 行函数里,改一处样式会怕牵全身。拆开后:改卡片只动卡片。这就是工程上要学组件的原因,不是为了显得「架构高级」。
先建立图像
function Welcome({ name }) {
return <h1>你好,{name}</h1>;
}
// 使用:像自定义标签
<Welcome name="同学" />
<Welcome /> 实际会让 React 去调用函数 Welcome,并把 name="同学" 变成参数(下一课叫 props)。
页面
├─ Header
├─ PathCard ← 可出现很多次
├─ PathCard
└─ Footer
跟着做(逻辑练习;在 Next/Vite 项目中粘贴)
步骤 1:最小组件
export function Hello() {
return <p>Hello React</p>;
}
export 是为了别的文件能 import { Hello } from "./Hello"。先在同一文件里用也可以。
步骤 2:组合(大的由小的拼)
function Avatar() {
return <span aria-hidden="true">🙂</span>;
}
function Hello() {
return <p>Hello React</p>;
}
export function HelloCard() {
return (
<section>
<Avatar />
<Hello />
</section>
);
}
组合的好处:改 Avatar 一处,所有用到它的卡片一起变。
坏处(拆过头):五个文件只有一行 JSX,跳来跳去更累。一块难懂再拆,不要为拆而拆。
步骤 3:想想「纯」——渲染时别搞副作用
渲染(函数被调用、准备 JSX)时尽量不要:
- 随便改全局变量
- 发
fetch(放到useEffect或框架的数据 API,后面学) - 用
Math.random()当列表 key 或关键业务 id(难复现、列表会乱)
能算出来的,在渲染里直接算:
function Price({ cents }) {
const yuan = (cents / 100).toFixed(2);
return <p>¥{yuan}</p>;
}
同样的 cents,永远得到同样的界面——这就是「纯」的直觉。
点击才改数据、请求才碰网络:那些是事件和 Effect 的事。
步骤 4:本站对照
打开任意 PathCard 一类文件:名字大写、返回一块 JSX、可能接收 title/href。
你现在的任务不是抄完整个站点,而是能指出:哪个函数是组件、谁嵌了谁。
步骤 5:组合优于继承
function Shell({ children }) {
return <section className="shell">{children}</section>;
}
function Page() {
return (
<Shell>
<h1>课名</h1>
</Shell>
);
}
用 children 插槽组合,而不是深继承树。
讲清楚要点
- 一个文件可导出多个组件;对外主组件常用
export function Xxx。 - props 下一课细讲:先把组件当成「可调用的 UI 函数」。
- 拆分原则:职责不清、文件太长、同一段 JSX 出现第三次 → 再拆。
- Client / Server:在 Next 里要绑定点击、用 Hooks 的文件顶上写
"use client"。纯展示的可以是服务端组件——Next 课展开;现在先记住「要交互就 client」。 - 不要在组件函数外面用 Hooks;也不要在循环/条件里调用 Hooks(规则课 hooks 会反复强调)。
你可能会懵的地方
-
组件是不是类?
老教程有class Xxx extends React.Component。新课以函数 + Hooks 为准。看到this.state就知道是旧文。 -
调用组件为何写标签而不是
Hello()?
JSX 约定。自己裸调Hello()会丢掉 React 的协调、key、生命周期语义。一律<Hello />。 -
必须 return 一个根吗?
是(或 Fragment<>...</>),与 JSX 课相同。 -
小写
div和大写Hello?
小写留给原生 HTML;大写表示你的组件。写错大小写是入门第一坑。 -
函数组件每次渲染都会重新执行?
会。所以不要在渲染里fetch,否则状态一变就狂请求。 -
组件名必须大写?
是。小写当作原生标签(如div)。
错法对照
| 错法 | 问题 | 正解 |
|---|---|---|
function hello() 小写当组件 | 被当成原生标签,界面空白 | Hello |
| 超长单文件组件 | 难测难改 | 按职责拆 |
渲染里 fetch | 次数失控、竞态 | Effect / 框架取数 |
| 为了「架构」拆 30 个文件 | 跳文件成本 | 先能读再抽 |
| 在组件里改 props | 单向数据流破坏 | 父级改数据再传入 |
| 一个文件三千行组件 | 难测 | 按 UI 块拆分 |
自测三问
- 为什么组件名要大写?
- 「纯渲染」大概指什么?举一个渲染里不该做的事。
- 组合组件的好处是什么?什么时候不该再拆?
小结一句话
函数组件 = 返回 JSX 的函数;大写命名、保持渲染单纯,用组合搭建页面。
打开本站任意卡片组件,用三句话标注:这个函数叫什么、它 return 了哪块 UI、它有没有再嵌套别的组件。标得出来,这一课就过关了。
动手加深
把「标题+摘要」拆成 TrackCard,父组件只传 props;确认子组件不自己 fetch(除非刻意设计)。
跟着做(加厚 · react-components)
步骤:最小可运行对照
在 Vite 或 Next 练习页粘贴本课核心示例,改一个输入,确认屏幕变化符合预期。再故意写一个错法表里的写法,看控制台/界面如何坏,然后改回。
每个概念都问:state 在谁手里?UI 哪一块会因它重绘?
操作顺序:打开对应文件 → 改一处可观察点(文案、类型、className 或分支)→ 保存看结果 → 复原或留下有意义的小改动。
步骤:错法故意练一次
先按「用 jQuery 式直接改 DOM 冒充完成」做 30 秒(或在注释里写出若这样做会怎样),再改成「改数据(state/props)让 UI 推导出来」。 目的不是留坑,而是让失败现象进长期记忆。
你可能会懵的地方(加厚)
-
热更新后状态丢了?
正常:整树重挂会重置 state。用 key 或外提状态保留;开发期别被吓到。 -
和文档示例不一致?
以你锁的 React 大版本 + react.dev 为准;旧博客的 class 组件示例仅作历史阅读。 -
这课和前后课怎么接?
回看大纲上一课的小结一句、下一课标题;用自己的话写「本课产出什么可观察结果」。写不出来就重做跟着做。
错法对照(加厚)
| 错法 | 问题 | 正解 |
|---|---|---|
| 用 jQuery 式直接改 DOM 冒充完成 | 假完成/埋雷 | 改数据(state/props)让 UI 推导出来 |
| 只看不敲 | 第二天全忘 | 至少跑通本课步骤 |
| 跳过自测三问 | 以为会了 | 闭卷答再对稿 |
延伸
- react.dev Your First Component
- 下一课:Props 与 State——参数与记忆。