Skip to content

事件处理

  • React 的事件命名采用驼峰命名
  • 处理事件的响应函数要以对象形式赋值给事件属性

React 事件是合成事件,并不是原生 DOM 事件。在 React 事件中必须显式调用事件对象的 preventDefault 方法来阻止事件的默认行为。

在 React 组件中处理事件最容易出错的是事件处理函数中 this 指向问题,因为 ES6 Class 不会为方法自动绑定到当前对象。

  1. 使用箭头函数

箭头函数的 this 指向的是函数定义时的对象,可保证 this 总是指向当前组件的实例对象。 直接在 render 方法为元素事件定义事件处理函数,最大问题是每次 render 调用时都会重新创建一个新的事件处理函数,带来额外的性能开销,组件所处层级越低,开销就越大

jsx
class Child extends Component {
  handleClick(e) {
    console.log(e.target);
  }

  render() {
    return (
      <div>
        <button onClick={e => this.handleClick(e)} />
      </div>
    );
  }
}
  1. 使用组件方法

直接将组件的方法赋值给元素的事件属性,同时在类的构造函数中,将这个方法的 this 绑定当当前对象

jsx
class Child extends Component {
  constructor() {
    super();
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick(e) {
    console.log(e.target);
  }

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

好处是每次 render 不会重新创建一个回调函数,没有额外的性能损失。但模版较为繁琐,还有下一种改良:

jsx
class Child extends Component {
  handleClick(e) {
    console.log(e.target);
  }

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

使用 bind 会创建一个新函数,因此该写法毅然存在每次 render 都会创建一个新函数问题

3. 属性初始化语法 property initializer syntax

使用 ES7 的 property initializers 会自动为 class 中定义的方法绑定 this:

jsx
class Child extends Component {
  constructor(props) {
    super(props);
    this.state = { num: 0 };
  }
  // ES7的属性初始化方法,实际上也是使用了箭头函数
  handleClick = e => {
    const num = ++this.state.num;
    this.setState({
      num,
    });
  };
  render() {
    return (
      <div>
        <p>{this.state.num}</p>
        <button onClick={this.handleClick}>click</button>
      </div>
    );
  }
}

这种方式既不需要在构造函数中手动绑定 this,也不需要担心组件重复渲染导致的函数重复创建问题。

共 20 个模块,1301 篇 Markdown 文档。