React事件绑定中的this指向问题
当时如果这是我有一个需求,我点击以下按钮,来获取我们state中的数据。
btnfun(){
console.log(this);//undefined
console.log(this.state.data);//not undefined
}
这里为什么会出现这个问题呢?因为btnfun()函数并不是我们主动调用的,而是当触发button的事件时,react内部再去调用这个函数。而react的内部时不知道这里的this是指向哪里的。
为了解决这个问题,我们给出了三种解决方案:
方案一:使用bind为事件方法绑定this:
在使用事件方法时直接通过bind改变事件方法的指向,就像如下代码一样:
<button onClick={this.btnfun.bind(this)}>button</button>
btnfun(){
console.log(this);//undefined
console.log(this.state.data);//not undefined
}
这是当react内部调用我们的事件函数时,就可以得知函数中的this指向何处。
上面的写法是一解决方案,但是当我们有 若干个事件都要去执行这个函数怎么办呢?我们可以使用下面这种方式进行优化。
constructor(props) {
super(props),
this.state={
data:'message'
},
this.btnfun=this.btnfun.bind(this)
}
我们可以将为事件方法绑定this的操作放在构造器里,这样在后面使用时就直接使用this.btnfun
即可。
方案二:使用ES6的class fields语法
这种语法是给类定义属性的方法,称之为class field语法。因为这里在赋值时使用了箭头函数,而箭头函数的this在任何情况下都会去上一个作用域中查找,而我们事件方法的上一个作用域恰巧就是当前的对象。
btnfun=() => {
console.log(this);//当前对象
console.log(this.state.data);//正常输出
}
这里须知:
箭头函数体内的
this
对象,就是定义该函数时所在的作用域指向的对象,而不是使用时所在的作用域指向的对象。
方案三:事件监听时传入箭头函数(推荐)
这种方式其实就是当给onClick事件中直接传入一个箭头函数,然后在箭头函数中进行我们的操作,可以直接写在函数中,也可以调用外部的函数。这里的this也就是箭头函数中的this,指向的时上一个作用域的this,而这里也会发生隐式绑定,将this的指向变为我们想要的结果。
写法如下:
render() {
return (
<div>
<h2>React Demo</h2>
{/*<button onClick={this.btnfun}>button</button>*/}
<button onClick={() => this.btnfun()}>button</button>
</div>
)
}
btnfun() {
console.log(this);//undefined
console.log(this.state.data);//not undefined
}
事件参数传递
在处理事件时,有时候也会有一些需要传递的参数,最常见的就是event对象。在jsx中其实在我们的事件方法中默认就给我们传递了event对象
如下代码所示:
render() {
return (
<div>
<h2>React Demo</h2>
<button onClick={this.btnclick}>button</button>
</div>
)
}
btnclick(e){
console.log(e);//打印event对象
}
}
但是如果我们还想要传递一些其他的参数呢?还记得我们this绑定问题的方案3吗,我们可以使用此方法进行参数的传递,包括event对象(是箭头函数的参数)
看以下需求:我们想要输出一个列表,并且点击单个li标签,打印对象的item和index以及event对象。
class App extends React.Component {
constructor(props) {
super(props),
this.state = {
movies: ['A', 'B', 'C', 'D']
}
this.btnclick = this.btnclick.bind(this)
}
render() {
return (
<div>
<h2>React Demo</h2>
<ul>
{
this.state.movies.map((item, index) => {
return <li onClick={(e) => {
this.liclick(item, index,e)
}}>{item}</li>
})
}
</ul>
</div>
)
}
liclick(item, index,e) {
console.log('li发生了点击', item, index,e);
}
}