基本使用
-
React事件名采用
驼峰式
写法,而不是小写 -
React事件不能直接
rerurn false
来阻止默认行为,必须通过preventDefault
来阻止
handleClick = (e) =>{
e.preventDefault();
}
<a href="#" onClick={e => this.handleClick(e)}>click me</a>
这里e
是一个合成事件(SynthetiEvent)
,React根据W3C标准
来定义合成事件,所以不需要担心跨浏览器的兼容问题。与原生的浏览器事件拥有同样的接口,同样是支持事件的冒泡机制,可以使用stopPropagation()
和preventDefault()
来中断。
-
所有事件都
自动绑定到最外层
,而不是直接绑定到HTML元素上,React仅仅是借鉴了这种写法而已。如果需要访问原生事件对象,可以使用nativeEvent
属性。 -
当时使用
ES6 class
语法定义一个组件的时候,事件处理器会成为类的一个方法:
1.第一种回调函数中的this
绑定方式:构造器内声明,通过bind
class Toggle extends React.Component {
constructor(props){
super(props);
this.state = {}
// 类的默认方法是不会绑定this的,所以通过如下方式手动绑定this
this.handleClick = this.handleClick.bind(this);
}
handleClick(){
}
render(){
return <a href="#" onClick={this.handleClick}> click me</a>
}
}
2.第二种是使用属性初始化器语法
来正确的绑定回调函数的this
class Toggle extends React.Component {
constructor(props){
super(props);
this.state = {}
}
// This syntax ensures `this` is bound within handleClick.
// Warning: this is *experimental* syntax.
handleClick = () => {
}
render(){
return <a href="#" onClick={this.handleClick}> click me</a>
}
}
3.第三种是在回调函数中使用箭头函数
class Toggle extends React.Component {
constructor(props){
super(props);
this.state = {}
}
handleClick(){
}
render(){
return <a href="#" onClick={e => this.handleClick(e)}> click me</a>
}
}
向事件处理程序传递参数
有两种方式向事件处理程序传递参数
1.通过bind
方式this.eventHandler.bind(this,params)
,类组件中监听函数这样获取参数eventHandler(e, params){}
class Toggle extends React.Component {
constructor(props){
super(props);
this.state = {
id:1
}
}
handleClick(id, e){
}
render(){
return <a href="#" onClick={this.handleClick.bind(this,this.state.id)}> click me</a>
}
}
注意:通过bind
方式向函数传参,在类组件中定义的监听函数,事件对象e
要排在所有所传参数的最后
。
2.通过箭头函数
的方式onClick={(e) => this.handlerEvent(e,params)}
,类组件监听函数这样获取参数 handlerEvent = (e, params) => {}
class Toggle extends React.Component {
constructor(props){
super(props);
this.state = {
id:1
}
}
handleClick = (e, id) => {
}
render(){
return <a href="#" onClick={ e => this.handleClick(e,this.state.id)}> click me</a>
}
}
合成事件的实现机制
在React底层,主要对合成事件做了两件事:事件委派
和自动绑定
1.事件委派
[ React中的事件代理机制是:不会把事件处理函数直接绑定到真实节点上,而是把所有的事件绑定到结构的最外层,使用统一的事件监听器,这个事件监听器保存了一个所有组件内部的事件监听和处理函数的映射,当组件挂载或卸载时,只是在这个统一的事件监听器上插入或删除一些对象,当事件发生时,首先被统一的事件监听器处理,然后在映射里找到真正的事件处理函数并调用,这样做简化了事件处理和回收机制,效率也有很大提升。]
2.自动绑定
[ 在 React 组件中,每个方法的上下文都会指向该组件的实例,即自动绑定 this 为当前组件。
而且 React 还会对这种引用进行缓存,以达到 CPU 和内存的最优化。在使用 ES6 classes 或者纯
函数时,这种自动绑定就不复存在了,我们需要手动实现 this 的绑定。]
自动绑定的方式如上所示。
在React中使用原生事件
在React架构下依然是可以使用原生事件的,在componentDidMount中组件已经完成安装并在浏览器中存在真实的dom,这时就可以使用原生事件完成事件的绑定。
import React, { Component } from 'react';
class Tab extends Component {
componentDidMount() {
this.refs.button.addEventListener('click', e => {
this.handleClick(e);
});
}
handleClick(e) {
console.log(e);
}
componentWillUnmount() {
this.refs.button.removeEventListener('click');
}
render() {
return <button ref="button">Test</button>;
}
}
需要注意的是。使用原生事件时,在组件卸载时要手动移除事件,否则可能出现内存泄露。而使用合成事件不需要,因为React已经处理好了。
合成事件和原生事件混用
虽说合成事件系统好用,但是有时候也是需要原生事件的,比如点击一个按钮显示内容,点击空白处隐藏内容,如下示例:
import React, { Component } from 'react';
class demo extends Component {
constructor(props) {
super(props);
this.state = {
active: false,
};
componentDidMount() {
//组件已经安装完成并在浏览器中是真实的dom结构
document.body.addEventListener('click', e => {
if (e.target && e.target.matches('div.code')) {
return;
}
this.setState({
active: false,
});
});
}
componentWillUnmount() {
//组件卸载前要手动清掉原生事件
document.body.removeEventListener('click');
}
handleClick = () => {
this.setState({
active: !this.state.active,
});
}
handleClickQr = (e) => {
//点击要显示的组件的时候 阻止冒泡到body,就不会触发隐藏
e.stopPropagation();
}
render() {
return (
<div className="qr-wrapper">
<button className="qr" onClick={this.handleClick}>click me</button>
<div className="code" style={{ display: this.state.active ? 'block' : 'none' }} onClick={this.handleClickQr}>
<img src="qr.jpg" alt="qr" />
</div>
</div>
);
}
}
尽量避免在React中混用合成事件和原生事件,对于无法使用合成事件的场景,才需要用原生事件来完成。
React合成事件的事件类型是Javascript原生事件类型的一个子集,并未实现全部的事件类型。
参考
https://react.docschina.org/docs/handling-events.html
https://book.douban.com/subject/26918038/
网友评论