事件处理函数的绑定与事件对象

React 事件处理

DOM事件处理 addEventListener onclick = function() {}

<button onclick="doSth'></button> 纯小写属性 onclick

React 元素也采用了类似于 DOM 标准中的事件属性定义的方法

JSX <button onClick={ this.doSth }>click</button> 小驼峰 onClick

React的事件对象

SyntheticBaseEvent(合成基础事件对象 React重新定义的)

这个 SBE 是遵守 W3C 事件对象的规范的,不存在任何的浏览器兼容性问题

/**
 * 为什么 React 要将事件处理直接在 React 元素上绑定?
 * React 一直认为事件处理跟视图是有程序上的直接关系的
 * 事件处理和视图写在一起可以更加直观的表述视图与逻辑的关系
 * 更加好维护
 */

this 指向问题

/**
 * 解决 this 指向的办法
 *  1. bind(this) => 构造器中(推荐)
 *  2. bind(this) => 视图标记中(推荐)
 *  3. 利用 回调 + 箭头函数
 *    存在的问题: render 函数每次执行的时候 -> 都会生成新的回调
 *    如果传递给子组件回调函数,子组件每次都会接受一个新的函数,从而触发子组件的 render
 *    这种情况可以用 doSth: () => {} 箭头函数解决
 */
class App extends React.Component {
  constructor(props) {
    super(props)
    // 1. bind(this) => 构造器中
    this.doSth = this.doSth.bind(this) // 最推荐的方案
  }
  doSth() {
    console.log(this); // 默认 undefined
    // 绑定 this 后为 App 对象
  }
	// 3.2 利用 回调 + 箭头函数(改良版)
  doSth2 = () => {
    console.log(this);
  }
  render() {
    return (
      <div>
        {/* 1. bind(this) => 构造器中 */}
        {/* <button onClick={ this.doSth }>click</button> */}

        {/* 2. bind(this) => 视图标记中 */}
        {/* <button onClick={ this.doSth.bind(this) }>click</button> */}

        {/* 3.1 利用 回调 + 箭头函数 */}
        {/* <button onClick={ () => this.doSth() }>click</button> */}
        {/* 3.2 利用 回调 + 箭头函数(改良版) */}
        <button onClick={ this.doSth2 }>click</button>
      </div>
    )
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('app')
)

如何传入、获取事件对象

  1. 回调 显式传入事件对象,在最后一个参数中
  2. bind 隐式传入事件对象,也在最后一个参数中
class App extends React.Component {
  constructor(props) {
    super(props);
  }
  // 回调 显式传入事件对象,在最后一个参数中
  doSth(p1, p2, p3, e) {
    console.log(p1, p2, p3, e);
  }
  // bind 隐式传入事件对象,也在最后一个参数中
  doSth2(p1, p2, p3, e) {
    console.log(p1, p2, p3, e);
  }
  render() {
    return (
      <div>
        <button onClick={ (e) => this.doSth(1, 2, 3, e) }>Click</button>
        <button onClick={ this.doSth2.bind(this, 1, 2, 3) }>Click</button>
      </div>
    )
  }
}

ReactDOM.render(<App/>, document.getElementById('app'))