持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第29天,点击查看活动详情
前言
大家好,在上一篇文章组件的生命周期函数中我们学习了react中的state属性和两个生命周期函数componentDidMount和componentWillUnmount。借助这两个函数及state属性我们实现了在不重新渲染组件的情况下完成数据的动态实时更新。那么元素的渲染与数据的更新都已经实现了,接下来就是与页面的交互了,提到交互必不可少的就是事件了,接下来我们来看下react是如何处理事件的。
传统dom事件与react事件
提到事件相信大家并不陌生。所谓的事件其实可以简单理解为:通过控制元素的某种行为从而实现某种功能
。首先我们先来回顾下传统的html元素中的事件。在传统的HTML元素中,我们可以以元素属性的形式来使用事件,然后把一个方法名以字符串的形式赋值给事件,进而实现事件的绑定。比如按钮的click事件:
<button onclick="clickme()">click</button>
<!--事件名为小写,事件绑定的值是一个函数字符串-->
再来看我们即将要学习的react中的事件。其实React元素的事件处理和DOM元素的很相似,但也有一点语法上的不同:
- react事件的命名采用的是小驼峰(camelCase),不是纯小写,而dom中的事件都是小写形式的
- react中在给元素绑定事件时,是直接传入一个函数作为事件处理函数,而不是字符串,dom中是字符串的形式
- react事件中不能通过
return false
的方式来阻止元素的默认行为,而必须要通过显式调用preventDefault
来阻止
<!--事件名为小驼峰式,事件绑定的值就是一个函数,而不是字符串形式-->
<button onClick={clickme}>click</button>
另外上面我们还提到在react事件中不能通过return false 的方式来阻止元素的默认行为,例如在传统html的a标签中我们可以在onclick事件通过return false来阻止链接的跳转。如下代码中当我们点击clickme的时候页面并不会跳转,因为被return false 阻止了。
<a href="http://baidu.com" onclick="return false">
Click me
</a>
但是如果在react事件中直接这样写是无效的,链接还是会跳转,那么在react中我们必须要显式调用preventDefault来阻止默认行为,如下代码:
function ActionLink() {
function clickMe(e) {
e.preventDefault();//显示调用preventDefault来阻止
}
return (
<a href="#" onClick={clickMe}>
Click me
</a>
);
}
改变事件函数中的this指向
我们知道react中的组件分为类组件和函数组件,当使用我们使用ES6中的class语法定义一个类组件的时候,通常的做法是将事件处理函数声明为 class 中的方法。例如:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {};
// 为了在回调中使用 `this`,这个绑定是必不可少的
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(state => ({
//...
}));
}
render() {
return (
<button onClick={this.handleClick}>
</button>
);
}
}
仔细看上面的代码中,虽然我们在类中已经定义了一个handleClick方法,但在构造函数中又通过bind
进行了重新绑定,我们知道bind可以改变函数中的this指向,那么为什么要这么做呢?原因就在于:
- 在类组件的生命周期函数中,比如render、componentDidMount等,this默认指向的就是当前React组件的实例,我们可以直接使用this,因为React默认会去调用这些方法
- 然而在类组件中我们自己定义的方法中,this就不一定指向当前组件的实例了,这是因为:
我们自己定义的方法一般多为元素的事件绑定方法,而我们在给事件绑定这些方法时,并没有触发方法的执行,而是要等到元素被点击(或其它事件)后才会触发方法的执行,而这时调用方法的实际是这个被点击的元素而不是组件,所以这时this指向可能就不是React组件的实例了
如果我们非要让自定义方法中的this仍然指向当前组件的实例,有如下三种方法可以实现:
- 第一种就是想上面代码那样通过bind方法来改变this指向,如:
this.方法名.bind(this)
- 第二种就是在定义方法时直接使用用箭头函数的方式来定义,因为箭头函数中的this在定义时就已经确定了,如:
方法名 = ()=>{}
- 第三种跟第二种原理一样,就是在给元素绑定事件时先绑定一个箭头函数,然后在箭头函数中再调用自定义的方法执行,这时this也是指向的组件实例
下面我们用代码来一一演示一下:
- 自定义方法不通过bind绑定,那么handleClick中的this为undefined
class LoggingButton extends React.Component {
handleClick(){
console.log('this is:', this);//this为undefined
}
render() {
return (
<button onClick={this.handleClick}>Click me</button>
);
}
}
- 利用bind改变函数中的this指向,同时也可以传递其它参数
class LoggingButton extends React.Component {
handleClick(){
console.log('this is:', this);
}
render() {
return (
//这里利用bind改变this指向
<button onClick={this.handleClick.bind(this,arg1,arg2...)}>Click me</button>
);
}
}
- 直接将handleClick定义为箭头函数
class LoggingButton extends React.Component {
handleClick = () => {
console.log('this is:', this);//this指向当前组件的实例
}
render() {
return (
<button onClick={this.handleClick}> Click me </button>
);
}
}
- 先给元素绑定一个箭头函数,然后在箭头函数中调用方法执行
class LoggingButton extends React.Component {
handleClick(){
console.log('this is:', this);
}
render() {
return (
<button onClick={() => { this.handleClick() } }> Click me </button>
);
}
}
给事件函数传递参数
在日常项目开发中,我们除了给组件绑定事件外,那么还有可能会给事件的函数传递一些参数。比如在一个列表中我们想通过点击某一行中的删除按钮来删除当前行的数据,那么在做删除的时候我们肯定是要根据当前数据的id来操作,这时我们就可以id传给事件函数,然后在事件函数中进行相应的删除操作。如下代码两种方式都可以实现
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
这两种方式实现效果是一样的,但是如果在事件函数中需要用到事件对象e的话就要稍加注意了: 上面的两种实现方式中,事件对象 e 都会被作为第二个参数传递。但是我们发现:
- 如果使用的是箭头函数,那么事件对象必须显式的进行传递
- 而如果通过 bind 的方式进行绑定,则事件对象将会被隐式自动进行传递。
总结
本次分享我们学习了react中的事件处理及事件函数的传参,同时还对比了传统dom事件与react事件的异同。简单总结就是:
- react中的事件是以小驼峰的方式命名,在给事件绑定函数时直接绑定函数名而不是函数的字符串形式
- react中的事件不能通过return false的方式阻止元素的默认行为,必须要显式调用preventDefault
- 在类组件中定义事件函数时,需要注意函数中的this指向,必要时可通过bind函数或箭头函数来改变this指向
- 如果事件函数中需要用到事件对象并且事件函数是一个箭头函数,那么必须要显式的传递事件对象
本次分享就到这里了。