建议配合官网文档 Handling Events 进行阅读。

Handling Events

React 元素的事件处理与 DOM 的事件处理十分类似,这里有一些语法上的不同:

  • React 事件使用小驼峰命名法,而不是全小写
  • JSX 语法要求事件接收的参数是函数,而不是字符串

举例来说,HTML:

<button onclick="activateLasers()">
  Active Lasers
</button>

和 React 有一些细微的不同:

<button onClick={activateLasers}>
  Active Lasers
</button>

另一个不同是,在 React 中无法通过返回false来阻止默认事件,而必须显式的调用preventDefault(),例如,在 HTML 中,你可以通过以下方式取消表单的默认提交:

<from onsubmit="cnosole.log('you clicked submit'); return false;">
  <button type="submit">Submit</button>
</form>

在 React 中,需要使用preventDefault()来组织默认事件的发生:

// From 组件
function From() {
  // 事件处理函数
  function handleSubmit(e) {
    e.preventDefault();
    console.log("You clicked submit");
  }
  // 返回 React 元素
  return (
    <from onSubmit={handleSubmit}>
      <button type="submit">Submit</button>
    </form>
  );
}

上面提到的e是合成事件,是React 根据W3C spec生成的。因此不必担心跨浏览器的兼容问题,React 事件和原生事件不完全相同,可以参考SyntheticEvent进行详细学习。

使用 React 时,不用使用addEventListener向已存在的 DOM 元素添加事件监听器,更常见的做法是在创建 React 时提供一个监听器。

当我们定义一个类组件时,常见的模式是将事件处理作为类的方法,例如下例中Toggle组件渲染了一个按钮,可以切换 ON /OFF 两种状态:

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isToggleOn: false,
    }
  }

  handleClick() {
    // 下一状态涉及到当前状态时,需要使用函数返回对象,而不是直接写对象
    this.setState(prevState => ({
      isToggleOn: !isToggleOn,
    )});
  }

  // This binding is necessary to make `this` work in the callback
  this.handleClick = this.handleClick.bind(this);

  render() {
    return (
      // 注意 JSX 中事件为小驼峰 onClick,而不是全小写 onclick
      <button onClick={this.handleClick}>
        {this.state.isToggleOn ? "ON" : "OFF"}
      </button>
    )
  }
}

ReactDOM.render(<Toggle />, document.getElementById('root'));

我们必须谨慎对待 JSX 回调函数中的this,在 JavaScript 中,类方法不会自动绑定this,所以我们必须手动进行绑定,即this.handleClick = this.handleClick.bind(this);

如果你不想绑定,那么这里有两个实验性功能可以供你使用:

  1. 在定义类方法时使用箭头函数:
    class LoggingButton extends React.Component {
    

// This syntax ensures this is bound within handleClick.
// Warning: this is experimental syntax.
handleClick = () => {
console.log(‘this is:’, this);
}
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
);
}
}:hexoPostRenderEscape–>
2. 在回调时,使用箭头函数包裹
<!–hexoPostRenderEscape:

class LoggingButton extends React.Component {
handleClick() {
console.log(‘this is:’, this);
}

render() {
// This syntax ensures this is bound within handleClick
return (
<button onClick={() => this.handleClick()}>
Click me
</button>
);
}
}:hexoPostRenderEscape–>
第二种方法根据其原理,可能会造成重复渲染的问题,会影响性能,因此推荐使用第一种方式,或者最初的手动绑定方法来解决。

Passing Arguments to Event Handlers

如果我们需要向事件处理函数中传入参数,一下任意两种方式都可以:

<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

上面这两种方式是等价的,分别使用了箭头函数arrow functionsFunction.prototype.bind
在这两种情况下,React 的事件对象 e 会被作为第二个参数传递。如果通过箭头函数的方式,事件对象必须显式的进行传递,而通过 bind 的方式,事件对象以及更多的参数将会被隐式的进行传递。