React 事件处理函数绑定与事件对象
React 事件处理对象
React 元素采用了类似于 DOM0 标准中的事件属性定义方法。React 专门重新定义了事件对象SyntheticBaseEvent
(合成基础事件对象),这是 React 自己实现的一套事件体系。这个SyntheticBaseEvent
遵守了 W3C 事件对象规范,不存在任何的浏览器兼容性问题。
为什么事件处理函数要和元素写在一起
React 一直认为,事件处理和视图有程序上的直接关系。事件处理和视图写在一起,可以更加直观地表述视图和逻辑的关系,更加方便维护。
this 指向问题
在 React 中,默认事件处理函数的this
为undefined
。ES6 class 模块默认是不对事件处理函数进行this
的再绑定的。
解决 this 指向问题的办法
推荐使用bind
和class 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 中获取事件对象有两种方式:
- 通过回调函数显式传入事件对象
- 通过
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
指向问题,推荐使用bind
或class fields
语法来绑定this
。获取事件对象可以通过回调函数显式传入或bind
隐式传入的方式。合理使用这些技巧,可以让我们在 React 中优雅地处理各种事件。