Skip to content
第 5 章 前端 ⏱ 12 分钟阅读

第 5 章:事件处理 ​

学习目标 ​

  • 掌握 React 事件的基本写法(驼峰、传函数)
  • 理解事件对象 SyntheticEvent
  • 学会传参的 3 种模式
  • 避开事件处理的 4 个常见坑

一、事件基础写法 ​

React 事件用驼峰命名,传函数引用而非字符串:

tsx
function Demo() {
  function handleClick(e: React.MouseEvent<HTMLButtonElement>) {
    console.log('点击了', e.currentTarget);
  }

  return (
    <button onClick={handleClick}>
      点我
    </button>
  );
}
原生 HTMLReact
onclick="handle()"onClick={handle}
onchange="..."onChange={...}
onmouseoveronMouseOver

⚠️ 坑 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/textarea
  • React.FormEvent<T> — form
  • React.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

动手练习 ​

  1. 表单提交:写 <form onSubmit> 阻止默认并打印数据
  2. 事件冒泡:写卡片 + 按钮,按钮点击只触发自己的事件(用 stopPropagation)
  3. 带参删除:渲染列表,每项有删除按钮,传 id 给处理函数
  4. 找坑:下面代码点按钮会怎样?
    tsx
    function App() {
      function handle() { console.log('hi'); }
      return <button onClick={handle()}>点</button>;
    }

下一章:第 6 章:条件与列表 →

本站基于 VitePress 构建 · 由 StackHub 团队维护