遇到的问题
最近想试一下React,之前一直用Vue在写东西。稍微看了几篇教程后,就开始写,能够基本运行起来,可能是因为项目比较简单吧。但是也遇到了几个问题,首先就是React的事件绑定问题:
我第一次的写法是:
1 | handleEvent(){ |
这样普通的点击事件是能够正常触发的。
this的指向问题
但是当我要使用this
时,这种写法就出了问题。
1 | handleEvent(){ |
这样就会报错this为undefined的。于是我就想起了之前看过的文章以及结合之前对JavaScript的函数的this分析。就明白此时函数在调用时不是被react对象直接调用的。所以该函数的this的指向为undefined。所以要想使用react对象的方法,只有将函数的this指向为react。根据之前文章对this的分析,要想绑定this,可以使用:
call(一次绑定并调用)
apply (一次绑定并调用)
bind(永久绑定)
箭头函数 () => {}永久绑定
但是事件是要多次调用并且不是绑定时就调用,而是事件被触发时才调用,所以排除call与apply方法。所以选择bind与箭头函数为最佳(后来看官方文档时发现官方也是推荐了这两种方法来绑定this)。
所以有以下方法:
在构造函数中绑定函数的this指向
1
2
3
4
5
6
7
8
9
10constructor(props){
super(props)
this.handleEvent = this.handleEvent.bind(this)
}
handleEvent(){
console.log(this) //此时指向react对象
}
<Button onClick={handleEvent}></Button>在事件绑定时绑定函数this
1
2
3
4
5handleEvent(){
console.log(this) //此时指向react对象
}
<Button onClick={this.handleEvent.bind(this)}></Button>
至此,this的指向问题基本解决。
函数传参的问题
接下来遇到需要传参的函数。我使用了与Vue与原始HTML同样的写法
1 | handleEvent = (para) => { |
当我尝试触发事件时,发现事件触发不成功,并且在打开控制面板时发现在页面初始化时,该事件被自动触发了3次,点击按钮无法触发。于是我不禁思考JSX的语法,让我想到了EL表达式
,EL表达式
中的代码会被直接运行,该位置会被填充为运行后的结果。再来看这个问题就发现自己的问题了。
{}内的代码在JSX模板编译时被当成代码直接运行,而tihs.handleEvent("123")
在JavaScript中不就是直接运行函数吗,所以函数在模板编译时直接被运行了,而onClick的事件则被绑定为函数的返回值,但是这个函数没有返回值,所以事件绑定失败。
所以如何解决这个问题就很简单了,只要在事件绑定的位置放置一个函数而不是函数的调用就行了,方法也有两个:
bind方法传参
1
2
3
4
5handleEvent = (para) => {
console.log(para)
}
<Button onClick={this.handleEvent.bind(this,"123")}></Button>箭头函数
1
2
3
4
5handleEvent = (para) => {
console.log(para)
}
<Button onClick={() => {this.handleEvent(123)}}></Button>折腾一下
在看到箭头函数时我又思考能不能不用箭头函数,直接用匿名函数实现函数的调用。像这样:
1
2
3
4
5handleEvent = (para) => {
console.log(para)
}
<Button onClick={function(para){this.handleEvent(para)}}></Button>再一想发现好想更不行,匿名函数没有绑定this指向。所以也就拿不到
this.handleEvent()
函数了。那就试试绑定一下匿名函数的this指向,像这样:1
2
3
4
5handleEvent = (para) => {
console.log(para)
}
<Button onClick={function(){this.handleEvent(123)}.bind(this)}></Button>OK,事件成功绑定,但是转念一想,这么搞还不如直接bind原函数,也避开了使用箭头函数。纯属折腾吧。
获取事件对象event
在Vue或者原生HTML中,event被存储在window下的event对象中,在绑定事件时将event对象传入即可获得点击事件对象。
但在React中,我们可以这么做:
当我们不需要为这个函数传参时,event对象会自动传入该函数,我们通过第一个参数获取event对象
当我们需要传参时,我们需要手动传入event对象
1
2
3
4
5
6
7
8handleEvent = (para,e) => {
console.log(para)
console.log(e)
}
<Button onClick={(e) => {this.handleEvent(123,e)}}></Button>
//或者这样
<Button onClick={this.handleEvent(123,e)}></Button>
Last
至此,React中的函数事件绑定基本可以搞定。写了一段时间的React,感觉相较于Vue,更灵活。刚入手的话,习惯了Vue模板文件的 <template>
<style>
<script>
这种分明的设计,React中的JSX写起来感觉有点复杂。在对比anted与elemenui,感觉elementui的api简直太简单了。后期在多体验看看吧!