写在前面
React 中的事件绑定就是类似于 HTML 全局事件绑定属性,但是要注意的是事件属性的大写,如 onClick、onKeyPress等
1. 类组件的事件绑定
1.1 () => this.addN()(安全可靠)
<button onClick={() => this.addN()}>+1</button>
1.2 this.addN(错误)
<button onClick={ this.addN }>+1</button>
此种方式是错误的,此种方式是将 this.addN 这个函数赋值给了 onClick 变量,即 onClick 和 this.addN 指向同一个对象,变量存储的都是该对象的地址,因此在点击按钮调用 onClick 函数时,是 window 调用的 onClick 函数。 如果其里面有用到 this,则此时的 this 指向的是 window,而不是类组件,因此使用该种方式就会出错。
1.3 this.addN.bind(this)
这种方式是对于上述错误方式的纠正,使用函数的 bind 方法将函数里面的 this 始终绑定为当前 this,即类组件实例,这样在函数 onClick 调用时就不会出错
1.4 this._addN
针对于第一种方法,即 () => this.addN() 可以进一步改进,将该箭头函数单独抽离出来取个名字,再使用第二种的方式赋值,如
this._addN = () => this.addN();
addN(){
this.setState({n: this.state.n + 1});
}
<button onClick={ this._addN }>+1</button>
1.5 终极最优法
针对上一种方法,需要再额外想一个函数的名字 _addN ,而且 addN 这个函数声明了又被赋予了别的变量,可以不要中间这个过渡的 addN ,直接赋予该属性 addN 的功能语句,如
//要写在 constructor 中
constructor(){
super();
this.addN = ()=> this.setState({n: this.state.n + 1});//直接使用箭头函数,
//箭头函数不接受传递this
}
但是在 ES6 的新语法中,可以优化如下,相当于是 1.4 的语法糖,1.4 和 1.5 的写法等价。
constructor(){
super();
}
addN = ()=>{
this.setState({n: this.state.n + 1});
}//不必写在 constructor 中,也不要 this.addN
2. 函数组件的事件绑定
3. 进阶讨论 this
这一模块讨论下类组件的事件绑定方法中的 1.2(错误写法) 和 1.5(终极最优**法)**两种如此相似的方式怎么会得到完全不一样的效果。
1.2 和 1.5 都是将当前组件的函数对象直接赋值给 onClick 函数,当然是复制的地址。但是二者的定义的函数的方式完全不一样,1.2 是挂在类组件原型上的普通函数,1.5 是挂在类实例本身上的箭头函数,在类中如果以 addN(){ } 的方式定义函数,就等价于 function addN(){ },定义的普通函数,其在函数调用时的 this 是在调用时才确定的,在其调用时没有指明 this 时就是 window 调用的。
因此就想到用箭头函数,箭头函数不接受 this 传参,因此,其里面的 this 就是类组件实例本身,类定义中只能以 this.xxx = () => { } ,以私有属性的方式定义箭头函数(箭头函数全都是匿名函数,只能以语句赋值的方式定义),要不然会被当作普通函数的。由于箭头函数不支持 this,因此就相当于在箭头函数被定义时就自动绑定了函数里面的 this 是定义箭头函数的对象本身。
也就是说,一个箭头函数被定义时其 this 只能绑定一个当前对象,因此,为了生成多个实例时每个实例都有自己的箭头函数,就必须用私有属性的方式定义箭头函数。
一般来说,在类中定义私有属性,就是要写在 constructor 构造函数里,React 的组件提供了一个语法糖,就是直接将箭头函数的定义写在外面,不写前缀 this。
在类中的普通函数是具名函数时,是放在其原型里面的公有函数(方法)。
在类中的箭头函数的定义,是放在实例自身的私有函数(方法)
定义普通函数用 addN(){ }
定义箭头函数用语句 addN = ()=>{ }**