Skip to content

事件处理

在 React 中,事件处理是构建交互式用户界面的核心部分。React 使用合成事件(Synthetic Events),这是一种跨浏览器的事件系统,它将原生浏览器事件封装成统一的接口,使得开发者无需担心不同浏览器之间的差异。以下是关于 React 事件处理的一些关键概念和最佳实践:

合成事件 (Synthetic Events)

React 的合成事件系统为所有事件提供了一致的 API,无论是在哪个浏览器中运行。这意味着你不必担心不同浏览器之间存在的细微差别。例如,event.preventDefault()event.stopPropagation() 在所有浏览器中的行为都是一致的。

与 document 事件

说明

  1. React 中的事件,实际上是给 document 注册事件;
  2. 几乎所有的元素的事件处理,均在 document 的事件中处理;
  3. 在 document 的事件处理,React 会根据虚拟 DOM 树完成事件函数的调用;
  4. React 事件参数,并非真实 DOM 事件中的参数,是 React 的合成事件对象,该对象类似于真实 DOM 的事件对象;
  • stopPropagation():阻止事件在虚拟 DOM 中冒泡;
  • nativeEvent:获取原生事件对象;
  • 为了提高执行效率,React 使用事件对象池来处理事件对象;

注意事项

  1. 如果给真实 DOM 注册事件,阻止了事件冒泡,则会导致 React 相应的事件无法触发;
  2. 如果个真实 DOM 事件,事件会优先于 React 事件运行;
  3. 通过 React 事件中阻止事件冒泡,无法阻止真实 DOM 事件冒泡;
  4. 可以通过 nativeEvent.stopImmediatePropagation(),阻止 document 上剩余同类事件的执行;
  5. 在事件处理程序中,不要异步的使用事件对象,如果一定要使用,需要调用 persist 函数;

声明事件处理器

  1. 在标签绑定,使用属性方式;
  2. 事件是以组成,使用驼峰命名法;
  3. 事件的功能一般定义在外部,使用方式调用;
  4. 事件函数中,使用参数,获取事件对象;

在 JSX 中声明事件处理器时,使用驼峰命名法而不是小写字母。例如,onClick 而不是 onclick。此外,传递给事件处理器的是一个函数而不是字符串。

jsx
<button onClick={handleClick}>Click me</button>

事件处理器函数

类组件中的事件处理器

在类组件中,事件处理器通常是类的方法。为了确保 this 指向正确,你需要绑定这些方法到当前实例,或者使用箭头函数自动绑定 this

jsx
class MyComponent extends React.Component {
  handleClick = () => {
    console.log("This is:", this);
  };

  render() {
    return <button onClick={this.handleClick}>Click me</button>;
  }
}

函数组件中的事件处理器 (Hooks)

在函数组件中,你可以直接定义事件处理器作为普通函数,或者使用闭包来捕获当前作用域内的变量。

jsx
function MyComponent() {
  const handleClick = () => {
    console.log("Button clicked");
  };

  return <button onClick={handleClick}>Click me</button>;
}

传递参数给事件处理器

如果你想传递额外的参数给事件处理器,可以使用箭头函数或部分应用(bind)。

jsx
function MyComponent() {
  const handleClick = (id) => {
    console.log(`Clicked item with ID: ${id}`);
  };

  return (
    <div>
      <button onClick={() => handleClick(1)}>Click Item 1</button>
      <button onClick={handleClick.bind(null, 2)}>Click Item 2</button>
    </div>
  );
}

阻止默认行为和阻止冒泡

你可以像在普通的 JavaScript 中那样调用 event.preventDefault()event.stopPropagation() 来阻止默认行为或事件冒泡。

jsx
function MyComponent() {
  const handleClick = (event) => {
    event.preventDefault();
    console.log("Default prevented");
  };

  return (
    <a href="https://example.com" onClick={handleClick}>
      Click here
    </a>
  );
}

表单事件

对于表单元素(如 <input>, <textarea>, <select> 等),React 提供了 onChange 事件来响应用户的输入变化。通常情况下,你会结合状态(state)来管理表单数据。

jsx
function MyForm() {
  const [value, setValue] = React.useState("");

  const handleChange = (event) => {
    setValue(event.target.value);
  };

  return (
    <form>
      <label>
        Name:
        <input type="text" value={value} onChange={handleChange} />
      </label>
    </form>
  );
}

事件委托

虽然 React 不需要显式地实现事件委托,因为它的合成事件系统已经处理了很多底层细节,但在某些情况下,理解这个概念仍然有用。例如,在动态生成大量子元素的情况下,可以在父元素上监听事件并根据目标元素确定具体的处理逻辑。

性能优化

  • 避免频繁创建内联函数:如果事件处理器是内联定义的(即在 JSX 内部),那么每次渲染都会创建一个新的函数实例,这可能会导致不必要的性能开销。尽量将事件处理器定义为组件外部的函数。
  • 使用 useCallback Hook:在函数组件中,如果你需要确保事件处理器不会在每次渲染时都重新创建,可以使用 useCallback Hook。
jsx
function MyComponent() {
  const handleClick = useCallback(() => {
    console.log("Button clicked");
  }, []);

  return <button onClick={handleClick}>Click me</button>;
}

Released under the MIT License.