我们知道,在 react 中,事件处理函数中的this很容易丢失,如:
class App extends React.Component {
handleClick() {
console.log(this);// undefined
}
render() {
return <div onClick={this.handleClick} >点我</div>;
}
}
有4种this指向的解决方案 , 如下:
- 箭头函数
- 构造函数中的 bind
- 事件绑定时的 bind
- 事件绑定时的匿名函数+箭头函数。
下边我们分别给出它们的实现
箭头函数
class App extends React.Component {
// 修改为箭头函数
handleClick = () => {
console.log(this);// 正常
}
render() {
return <div onClick={this.handleClick} >点击</div>;
}
}
构造函数中的bind
class App extends React.Component {
constructor(props) {
super();
// 通过bind 改写this指向并返回新的函数
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
console.log(this);// 正常
}
render() {
// bind
return <div onClick={this.handleClick} >点击</div>;
}
}
事件绑定时的bind
class App extends React.Component {
handleClick() {
console.log(this);// 正常
}
render() {
// bind
return <div onClick={this.handleClick.bind(this)} >点击</div>;
}
}
如需传递参数,如下:
class App extends React.Component {
handleClick(a, b, e) {
console.log(this);// 正常
console.log(a, b, e);// "aa","bb","事件对象"
}
render() {
return <>
<div onClick={this.handleClick.bind(this, "aa", "bb")} >点击</div>
</>
}
}
事件绑定时的匿名函数+箭头函数
class App extends React.Component {
handleClick(e) {
console.log(this);// 正常
}
render() {
// bind
return <div onClick={() => this.handleClick()} >点击</div>;
}
}
如需传递参数,如下:
class App extends React.Component {
handleClick(a, b, e) {
console.log(this);// 正常
console.log(a, b, e);// "aa","bb","事件对象"
}
render() {
// bind
return <div onClick={(e) => this.handleClick('aa', 'bb', e)} >点击</div>;
}
}
另外, 也可自定义属性,如下:
class App extends React.Component {
handleClick(e) {
console.log(this);// 正常
console.log(e.target.dataset.msg);// "aa"
}
render() {
return <>
<div data-msg="aa" onClick={this.handleClick.bind(this)} >点击</div>
</>
}
}
但是,如果从性能角度出发,只推荐一种: 事件绑定时的bind
this指向解决方案的性能比较
以下比较,主要从 实例成员函数能否得到复用触发,那么我们可以将其函数成员做对比,看哪种方式是共享内存。
class App extends React.Component {
constructor() {
super();
this.ref1 = React.createRef();
this.ref2 = React.createRef();
}
handleClick(e) {
console.log(this.ref1.current.showBtn === this.ref2.current.showBtn);
}
render() {
return <>
<div onClick={this.handleClick.bind(this)} >
<Btn ref={this.ref1} />
<Btn ref={this.ref2} />
</div>
</>
}
}
1. 箭头函数
class Btn extends React.Component {
showBtn = () => {
console.log(this);
}
render() {
return <button onClick={this.showBtn}>点击</button>;
}
}
结果如下:
handleClick(e) {
console.log(this.ref1.current.showBtn === this.ref2.current.showBtn);// false
}
说明:箭头函数不靠谱
2. 构造函数中的 bind
class Btn extends React.Component {
constructor() {
super();
this.showBtn = this.showBtn.bind(this);
}
showBtn() {
console.log(this);
}
render() {
return <button onClick={this.showBtn}>点击</button>;
}
}
结果如下:
handleClick(e) {
console.log(this.ref1.current.showBtn === this.ref2.current.showBtn); // false
}
说明:构造函数中的 bind不靠谱
3. 事件绑定时的 bind
class Btn extends React.Component {
showBtn() {
console.log(this);
}
render() {
return <button onClick={this.showBtn.bind(this)}>点击</button>;
}
}
结果如下:
handleClick(e) {
console.log(this.ref1.current.showBtn === this.ref2.current.showBtn); // true
}
说明:事件绑定时的 bind 靠谱!
**4. 事件绑定时的匿名函数+箭头函数 **
class Btn extends React.Component {
showBtn() {
console.log(this);
}
render() {
return <button onClick={() => this.showBtn()}>点击</button>;
}
}
结果如下:
handleClick(e) {
console.log(this.ref1.current.showBtn === this.ref2.current.showBtn); // true
}
说明: 事件绑定时的匿名函数+箭头函数 靠谱!
结论, 就推荐以下2种写法就行了:
1. 事件绑定时的 bind
class Btn extends React.Component {
showBtn() {
console.log(this);
}
render() {
return <button onClick={this.showBtn.bind(this)}>点击</button>;
}
}
2. 事件绑定时的匿名函数+箭头函数
class Btn extends React.Component {
showBtn() {
console.log(this);
}
render() {
return <button onClick={() => this.showBtn()}>点击</button>;
}
}