大家好,我是程序员柏风,AI 最全的 Vibecoding 学习地图 http://coderoadmap.cn 作者。
事件处理
这一课你将能做到
- 正确书写
onClick/onChange,避免「渲染时就被调用」 - 在事件里调用
setState - 在表单
onSubmit里使用preventDefault
为什么要学
本站几乎所有按钮:切走法、提交「留一句」、打开抽屉,都是事件。
React 的事件写在 JSX 上:onClick={...}。
人话:你把「被点了要干什么」写成一个函数,交给按钮;用户点的时候 React 再帮你调用。
最常见事故:写成 onClick={handle()}——多了一个括号,渲染时就执行,而不是点击时。结果页面一出来就弹窗、请求已经发出去了。
先建立图像
用户点击 → React 调用你传入的函数 → 函数里 setState → 重新渲染
函数要用引用交给 onClick,不是把「调用的结果」交出去。
跟着做
步骤 1:正确 vs 错误(先刻在脑子里)
function handleClick() {
console.log("clicked");
}
export function Demo() {
return (
<>
{/* 正确:把函数交给 onClick */}
<button type="button" onClick={handleClick}>A</button>
<button type="button" onClick={() => handleClick()}>B</button>
{/* 错误:渲染时立刻执行,返回值还不是函数 */}
{/* <button type="button" onClick={handleClick()}>C</button> */}
</>
);
}
需要传参数时用箭头包一层,否则 remove(id) 会立刻跑:
<button type="button" onClick={() => remove(id)}>删除</button>
步骤 2:和 state 联动
import { useState } from "react";
function Like() {
const [n, setN] = useState(0);
return (
<button type="button" onClick={() => setN((x) => x + 1)}>
赞 {n}
</button>
);
}
点击 → 更新记忆 → React 再画按钮上的数字。不要在 onClick 里去改 button.textContent。
步骤 3:提交表单(整页刷新是默认行为)
浏览器里 <form> 点提交会导航/刷新。SPA 里通常要拦住:
import { useState } from "react";
function SearchBox() {
const [q, setQ] = useState("");
function onSubmit(e) {
e.preventDefault(); // 拦住默认刷新
alert("搜索:" + q);
}
return (
<form onSubmit={onSubmit}>
<label>
关键词
<input value={q} onChange={(e) => setQ(e.target.value)} />
</label>
<button type="submit">搜</button>
</form>
);
}
这里已经是受控输入雏形:输入框的值来自 state。表单课会加深校验和 disabled。
步骤 4:表单里的普通按钮
<form onSubmit={onSubmit}>
<button type="button" onClick={onCancel}>取消</button>
<button type="submit">保存</button>
</form>
取消按钮务必 type="button",否则有的浏览器会把它当提交。
步骤 5:传参不要提前调用
<button type="button" onClick={() => save(id)}>存</button>
// onClick={save(id)} // 渲染时就执行——错
讲清楚要点
- 命名:处理函数常叫
handleClick;作为 props 传下去的回调常叫onSave(父写onSave={handleSave})。 type="button":在表单里避免误提交。- 事件对象
e:需要时再接;e.target是触发元素,e.preventDefault()拦默认行为。 - 逻辑尽量放命名函数里,JSX 保持薄,好读、好测。
- React 合成事件:用法近似原生
click/change;入门按原生习惯写即可。
你可能会懵的地方
-
合成事件要现在背细节吗?
不必。知道「写法像 DOM 事件、驼峰命名」就够。 -
为何有的教程写
onClick={this.handle}?
class 组件还要绑this。函数组件用上面的方式即可。 -
onClick={handleClick}和onClick={() => handleClick()}哪个好?
不传参时前者短;要传参或包一层逻辑用后者。不要迷信「箭头一定慢」——先写对。 -
事件里
await可以吗?
可以,记得用saving状态锁按钮,避免连点(表单课)。 -
preventDefault何时要?
表单 submit、链接想拦跳转时。普通 button 用type="button"更干净。
错法对照
| 错法 | 问题 | 正解 |
|---|---|---|
onClick={fn()} | 渲染就跑 | onClick={fn} 或 () => fn(id) |
| 表单提交整页刷新 | 输入丢失、体验差 | preventDefault |
| 巨型内联箭头 30 行 | 难读 | 提出命名函数 |
| 表单里取消按钮无 type | 误提交 | type="button" |
用原生 onclick 字符串 | 不进 React 系统 | onClick 函数 |
| 在 handler 里直接改 DOM | 与 state 打架 | setState |
自测三问
onClick={fn}和onClick={fn()}差在哪?- 传参为什么常包一层箭头函数?
- 表单提交为什么要 preventDefault?取消按钮为什么要 type="button"?
小结一句话
把函数引用传给 onX;需要参数就包箭头;提交记得 preventDefault。
动手加深
给按钮加 type="button",在表单里验证:不写 type 时点击可能误提交整表。
跟着做(加厚 · react-events)
步骤:最小可运行对照
在 Vite 或 Next 练习页粘贴本课核心示例,改一个输入,确认屏幕变化符合预期。再故意写一个错法表里的写法,看控制台/界面如何坏,然后改回。
每个概念都问:state 在谁手里?UI 哪一块会因它重绘?
操作顺序:打开对应文件 → 改一处可观察点(文案、类型、className 或分支)→ 保存看结果 → 复原或留下有意义的小改动。
步骤:错法故意练一次
先按「用 jQuery 式直接改 DOM 冒充完成」做 30 秒(或在注释里写出若这样做会怎样),再改成「改数据(state/props)让 UI 推导出来」。 目的不是留坑,而是让失败现象进长期记忆。
你可能会懵的地方(加厚)
-
热更新后状态丢了?
正常:整树重挂会重置 state。用 key 或外提状态保留;开发期别被吓到。 -
和文档示例不一致?
以你锁的 React 大版本 + react.dev 为准;旧博客的 class 组件示例仅作历史阅读。 -
这课和前后课怎么接?
回看大纲上一课的小结一句、下一课标题;用自己的话写「本课产出什么可观察结果」。写不出来就重做跟着做。
错法对照(加厚)
| 错法 | 问题 | 正解 |
|---|---|---|
| 用 jQuery 式直接改 DOM 冒充完成 | 假完成/埋雷 | 改数据(state/props)让 UI 推导出来 |
| 只看不敲 | 第二天全忘 | 至少跑通本课步骤 |
| 跳过自测三问 | 以为会了 | 闭卷答再对稿 |
延伸
- react.dev Responding to Events
- 下一课:条件渲染与列表。