0%

已完成 0/29 关

教学模式

你可以随时调整。

此设置调整教师的教学方式,无需重新生成课程。

第 13 关 含代码 约 11 分钟

响应事件:事件处理函数、传参与阻止冒泡

响应事件:事件处理函数、传参与阻止冒泡

到目前为止,你学会了如何用组件和数据渲染静态的 UI。但一个真正有用的应用,必须能够倾听并响应用户的操作:点击按钮、键盘输入、鼠标滑动、表单提交。

在 React 中,你可以向 JSX 元素添加 事件处理函数(Event Handlers) 来响应这些用户交互。


1. 添加事件处理函数

添加事件处理函数只需两步:

  1. 在你的组件函数内部声明一个函数(通常命名为 handle 加上事件名称,比如 handleClick、handleChange);
  2. 将这个函数作为 prop 传递给对应的 JSX 元素(如 onClick)。
export default function Button() {
  function handleClick() {
    alert('你点击了我!');
  }

  return (
    <button onClick={handleClick}>
      点我
    </button>
  );
}

也可以使用简短的内联箭头函数直接写在 JSX 里:

<button onClick={() => {
  alert('你点击了我!');
}}>
  点我
</button>

2. 致命区别:传递函数 vs 调用函数

这是每个 React 初学者最常踩的一个坑!请仔细对比以下两行代码:

// ✅ 正确:传递函数
<button onClick={handleClick}>

// ❌ 错误:调用函数!
<button onClick={handleClick()}>

为什么加了小括号就会出大问题?

  • onClick={handleClick}(无小括号):这是在告诉 React:“请把这个函数保存起来,只有当用户真正点击按钮时,再去调用它!”;
  • onClick={handleClick()}(有小括号):小括号在 JavaScript 中代表立即执行函数!当组件在初次渲染时,代码一读到这里,handleClick() 就会在渲染期间当场执行(弹窗立刻弹出)。而且,如果该函数里有 setState,它会导致立刻触发重新渲染,然后再次立即执行,直接导致死循环崩溃!

记忆口诀:只把函数本身的名字交上去,不要在绑定时私自按下执行的小括号。


3. 在事件中传递自定义参数

如果你需要向处理函数中传入参数(例如当前项的 ID),必须用一个外层箭头函数把它包装起来:

// ❌ 错误:这会在渲染时立刻调用并传入 5
<button onClick={handleClick(5)}>

// ✅ 正确:定义一个箭头函数,点击时才调用 handleClick(5)
<button onClick={() => handleClick(5)}>

4. 事件传播(冒泡机制)与阻止冒泡

事件处理程序不仅会捕获直接子元素的交互,还会响应子元素深处冒上来的事件。这被称为 事件冒泡(Event Propagation / Bubbling)。

冒泡场景分析

观察下面的工具栏代码:

export default function Toolbar() {
  return (
    <div className="Toolbar" onClick={() => {
      alert('你点击了工具栏空白处!');
    }}>
      <button onClick={() => alert('正在播放电影!')}>
        播放电影
      </button>
      <button onClick={() => alert('正在上传图片!')}>
        上传图片
      </button>
    </div>
  );
}

如果你点击了“播放电影”按钮,你会发现屏幕上先后弹出了两个弹窗:

  1. 首先弹出“正在播放电影!”;
  2. 紧接着弹出“你点击了工具栏空白处!”。

因为按钮被点击后,事件顺着 DOM 树向上扩散给了它的父级 <div>!

使用 e.stopPropagation() 阻止冒泡

事件处理函数会收到一个浏览器事件对象,通常简写为 e。调用 e.stopPropagation() 可以命令事件“停在原地,不要再往上扩散了”:

function Button({ onClick, children }) {
  return (
    <button onClick={(e) => {
      e.stopPropagation(); // 阻止事件向上冒泡到父级 Toolbar!
      onClick();
    }}>
      {children}
    </button>
  );
}

现在,点击按钮时,只会触发按钮自身的行为,父级 Toolbar 的点击事件被完美隔离!


5. 阻止默认行为(e.preventDefault)

某些特定浏览器事件具有默认的网页行为。最典型的就是表单内部的提交按钮: 当点击带有 <form> 的提交按钮时,浏览器默认会刷新整个网页并提交表单数据。

如果你希望在单页应用里通过 Ajax/Fetch 自己处理提交,可以使用 e.preventDefault() 阻止这一默认行为:

export default function SignupForm() {
  function handleSubmit(e) {
    e.preventDefault(); // 阻止浏览器默认的整个网页刷新行为!
    alert('正在安全提交数据,无需刷新页面!');
  }

  return (
    <form onSubmit={handleSubmit}>
      <input placeholder="请输入用户名" />
      <button type="submit">注册</button>
    </form>
  );
}

总结

  • 通过形如 onClick、onSubmit 的驼峰属性绑定事件;
  • 始终传递函数本身(onClick={handleClick}),切勿写成立即执行(onClick={handleClick()});
  • 传递额外参数时使用内联箭头函数 onClick={() => handleClick(id)};
  • 使用 e.stopPropagation() 阻止点击事件向上层冒泡;
  • 使用 e.preventDefault() 阻止表单提交等浏览器默认行为。
下一站:State:组件的记忆与 useState Hook →
© 2026 React 官方教程