第 5 章:事件处理
学习目标
- 掌握 React 事件的基本写法(驼峰、传函数)
- 理解事件对象
SyntheticEvent - 学会传参的 3 种模式
- 避开事件处理的 4 个常见坑
一、事件基础写法
React 事件用驼峰命名,传函数引用而非字符串:
tsx
function Demo() {
function handleClick(e: React.MouseEvent<HTMLButtonElement>) {
console.log('点击了', e.currentTarget);
}
return (
<button onClick={handleClick}>
点我
</button>
);
}| 原生 HTML | React |
|---|---|
onclick="handle()" | onClick={handle} |
onchange="..." | onChange={...} |
onmouseover | onMouseOver |
⚠️ 坑 1:必须是函数引用,不是函数调用!
onClick={handleClick}✅,onClick={handleClick()}❌(立即执行)。
二、SyntheticEvent 合成事件
React 把原生事件包装成 SyntheticEvent,接口统一,跨浏览器一致。
tsx
function Form() {
function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault(); // ⚠️ 阻止默认行为(页面跳转)
console.log('提交');
}
return <form onSubmit={handleSubmit}><button>提交</button></form>;
}常用事件类型:
React.MouseEvent<T>— 鼠标React.ChangeEvent<T>— input/select/textareaReact.FormEvent<T>— formReact.KeyboardEvent<T>— 键盘React.FocusEvent<T>— 焦点
三、传参的 3 种写法
写法 1:箭头函数包裹(最清晰)
tsx
function List() {
function handleDelete(id: number) {
console.log('删', id);
}
return (
<ul>
{items.map(item => (
<button key={item.id} onClick={() => handleDelete(item.id)}>
删 {item.name}
</button>
))}
</ul>
);
}写法 2:bind
tsx
<button onClick={handleDelete.bind(null, item.id)}>删</button>写法 3:data-attribute(取自 currentTarget)
tsx
<button data-id={item.id} onClick={handleDelete}>删</button>;
function handleDelete(e: React.MouseEvent<HTMLButtonElement>) {
const id = Number(e.currentTarget.dataset.id);
}⚠️ 坑 2:
onClick={handleDelete(item.id)}会立即执行handleDelete并把返回值传给 onClick,直接渲染时就触发。
四、阻止冒泡与默认行为
tsx
function Card() {
function handleDivClick() {
console.log('div');
}
function handleBtnClick(e: React.MouseEvent) {
e.stopPropagation(); // ⚠️ 阻止冒泡
console.log('btn');
}
return (
<div onClick={handleDivClick}>
<button onClick={handleBtnClick}>点我只触发 btn</button>
</div>
);
}默认行为例子:
<a>点击跳转 →e.preventDefault()- 表单提交跳转 →
e.preventDefault() - 拖拽 →
e.preventDefault()才能触发drop
五、事件委托(React 已自动处理)
React 17+ 把事件挂到根节点而非 document,所以不用手动 event.stopPropagation 阻断原生事件监听。
⚠️ 坑 3:用了第三方原生事件库(如 jQuery)时,React 的合成事件不会触发原生监听器,要小心事件链断裂。
六、useCallback 优化(可选)
每次渲染都创建新箭头函数会导致子组件重渲染,用 useCallback 缓存:
tsx
const handleClick = useCallback(() => {
console.log(count);
}, [count]); // 依赖变化才更新函数引用性能优化见第 11 章。
七、this 绑定(类组件遗留)
函数组件没有 this 问题,但如果你还在写类组件:
tsx
class Demo extends React.Component {
constructor(props: any) {
super(props);
this.handleClick = this.handleClick.bind(this); // ⚠️ 构造函数中 bind
}
handleClick() {
console.log(this.props.name);
}
render() {
return <button onClick={this.handleClick}>点</button>;
}
}⚠️ 坑 4:类组件里不 bind 就把方法传给 onClick,
this会是undefined。
八、本章小结
| 要点 | 关键 |
|---|---|
| 事件名 | 驼峰,传函数引用 |
| 事件对象 | SyntheticEvent,类型用 React.XxxEvent<T> |
| 传参 | 箭头函数包裹(首选) |
| 阻止默认 | e.preventDefault() |
| 阻止冒泡 | e.stopPropagation() |
| React 17+ | 事件委托到根节点,不再到 document |
动手练习
- 表单提交:写
<form onSubmit>阻止默认并打印数据 - 事件冒泡:写卡片 + 按钮,按钮点击只触发自己的事件(用 stopPropagation)
- 带参删除:渲染列表,每项有删除按钮,传
id给处理函数 - 找坑:下面代码点按钮会怎样?tsx
function App() { function handle() { console.log('hi'); } return <button onClick={handle()}>点</button>; }
下一章:第 6 章:条件与列表 →