react基于Virtual DOM实现了一个SyntheticEvent(合成事件)层,我们所定义的事件处理会接收到一个SyntheticEvent对象的实例,它完全符合w3c标准,不会存在任何IE标准的兼容性问题。并且与原生的浏览器事件一样拥有同样的借口,同样支持事件的冒泡机制,我们可以使用stopPropagetion()和prenventDefault()来中断它。
所有事件都自动绑定到最外层上,如果需要访问原生事件对象,可以访问nativeEvent属性。
看一个小栗子即可:
import React from 'react'
class App extends React.Component{
constructor(props){
super(props)
this.state = {
val:0
}
this.handleClick = this.handleClick.bind(this)
}
handleClick(){
this.setState({val:this.state.val + 1})
}
render(){
return (
<div>
<div>{this.state.val}</div>
<button onClick={this.handleClick}>Add</button>
</div>
)
}
}
export default App
我们给按钮添加了一个点击事件,如上例子所示,所有事件都是由on加事件名,遵循驼峰的形式。
在react底层,主要对合成事件做了两件事:事件委派和自动绑定。
- 事件委派
react并不会把事件处理函数绑定到真实的节点上,而是把所有事件绑定到结构的最外层,使用一个统一的事件监听器,这个事件监听器维持了一个映射来保存所有组件内部的事件监听和处理函数。当组件卸载或挂载时,只是在这个统一的事件监听器上插入或删除一些对象;当事件发生的时候,首先被这个统一的事件监听器处理,然后在映射里找到真正的事件处理函数并调用。这样做就简化了事件处理和回收机制,效率也有很大的提升。
- 自动绑定
在react组件中,每个方法的上下文都会指向该组件的实例,即自动绑定this为当前组件。而且react还会对这种引用进行缓存,以达到cpu内存的最优化。在使用ES6 classes或者纯函数时,这种自动绑定就不复存在了,我么需要手动绑定。因此诞生了很多方法来绑定this
- 渲染时绑定
onClick={this.handleClick.bind(this)}
这种方法简明扼要,但是有一个潜在的性能问题:当组件每次重新渲染时,都会有一个新的函数创建。这听上去貌似是一个很大的问题,但是其实在真正的开发场景中,由此引发的性能问题往往不值一提(除非是大型组件消费类应用或游戏)。
- 箭头函数绑定
onClick={(e) => this.handleClick}
当然,也与第二种方法一样,它同样存在潜在的性能问题
- Constructor 内绑定
也是我上面那个示例写的代码,也是我最常用的写法,这种方式往往被推荐为“最佳实践”。
但是就我而言,我认为与前两种方法相比,constructor 内绑定在可读性和可维护性上也许有些欠缺。
同时,我们知道在 constructor 声明的方法不会存在实例的原型上,而属于实例本身的方法。每个实例都有同样一个 handleChange,这本身也是一种重复和浪费。
- Class 属性中使用 = 和箭头函数
handleClick = (e) => {
console.log(e)
this.setState({val:this.state.val + 1})
}
我们来总结一下这种方式的优点:
-
使用箭头函数,有效绑定了 this;
-
没有第1种方法和第2种方法的潜在性能问题;
-
避免了方法3的组件实例重复问题;
就目前而言,大多数情况还是推荐用最后两种方法来在事件中绑定this
参考链接:
网友评论