跳到主要内容

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

React 事件处理对象

React 元素采用了类似于 DOM0 标准中的事件属性定义方法。React 专门重新定义了事件对象SyntheticBaseEvent(合成基础事件对象),这是 React 自己实现的一套事件体系。这个SyntheticBaseEvent遵守了 W3C 事件对象规范,不存在任何的浏览器兼容性问题。

为什么事件处理函数要和元素写在一起

React 一直认为,事件处理和视图有程序上的直接关系。事件处理和视图写在一起,可以更加直观地表述视图和逻辑的关系,更加方便维护。

this 指向问题

在 React 中,默认事件处理函数的thisundefined。ES6 class 模块默认是不对事件处理函数进行this的再绑定的。

解决 this 指向问题的办法

推荐使用bindclass fields语法来解决 this 指向问题。

使用bind绑定 this:

this.doSth.bind(this);

或者在 JSX 中直接绑定:

<button onClick={this.doSth.bind(this)}>click</button>

但是这种方式有一个缺点,就是当render函数每次执行的时候,都会创建新的回调函数,这样子组件每次都会接收一个新的函数,可能会触发子组件的不必要渲染。

下面这种写法,Title组件每次都会接受到新的引用值,就会造成子组件的重复渲染:

render() {
return (
<div>
<button onClick={() => this.doSth()}>click</button>
<Title fn={() => this.doSth()} />
</div>
);
}

使用class fields语法可以避免这个问题:

doSth = () => {
console.log(this);
}

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

如何获取事件对象

在 React 中获取事件对象有两种方式:

  1. 通过回调函数显式传入事件对象
  2. 通过bind隐式传入事件对象
class App extends React.Component {
// 事件对象都是在最后一个参数
// 回调函数显式传入事件对象
doSth(p1, p2, p3, p4, e) {
console.log(p1, p2, p3, p4, e);
}

// bind隐式传入事件对象
doSth2(p1, p2, p3, p4, e) {
console.log(p1, p2, p3, p4, e);
}

render() {
return (
<div>
{/* 两种方式是一致的 */}
<button onClick={(e) => this.doSth(1, 2, 3, 4, e)}>click</button>
<button onClick={this.doSth2.bind(this, 1, 2, 3, 4)}>click</button>
</div>
);
}
}

总之在 React 中处理事件时,要注意this指向问题,推荐使用bindclass fields语法来绑定this。获取事件对象可以通过回调函数显式传入或bind隐式传入的方式。合理使用这些技巧,可以让我们在 React 中优雅地处理各种事件。