先上结论
我们知道,在 react
中,事件处理函数中的this很容易丢失,如
class App extends React.Component {
handleClick() {
console.log(this);// undefined
}
render() {
return <div onClick={this.handleClick} >点我</div>;
}
}
结合原生 JavaScript
的理解,我们有如下4种解决方案
bind
bind
下边我们分别给出它们的实现
写法上最简单
class App extends React.Component {
// 修改为箭头函数
handleClick = () => {
console.log(this);// 正常
}
render() {
return <div onClick={this.handleClick} >点我</div>;
}
}
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>;
}
}
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() {
console.log(this);// 正常
}
render() {
// bind
return <div onClick={() => this.handleClick()} >点我</div>;
}
}
虽然以上四种方案都可以解决 事件处理函数中this指向的问题,但是由于我们在开发时,往往还需要做事件传参。
因此还有以下4种事件传参写法
bind
dataset
bind 函数不但可以修改this指向返回新函数,还可以接收参数。写法相当灵活飘逸
class App extends React.Component {
handleClick(a, b, e) {
console.log(this);// 正常
console.log(a, b, e);// "过火","上火","事件对象"
}
render() {
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);// "过火","上火","事件对象"
}
render() {
return <>
<div onClick={(event) => this.handleClick("过火", "上火", event)} >点我</div>
</>
}
}
class App extends React.Component {
handleClick(e) {
console.log(this);// 正常
console.log(e.target.dataset.msg);// "过火"
}
render() {
return <>
<div data-msg="过火" onClick={this.handleClick.bind(this)} >点我</div>
</>
}
}
虽然 react
事件相关代码写法看起来多种多样,但是,如果从性能角度出发,写法就剩下以下一种。 事件绑定时的bind
以下比较,主要从 实例成员函数能否得到复用触发,因为 类组件也可以理解是个class,那么我们可以将其函数成员做对比,看哪种方式是共享内存。
class App extends React.Component {
constructor() {
super();
this.ref1 = React.createRef();
this.ref2 = React.createRef();
}
handleClick(e) {
// 比较 Btn 组件中的事件处理函数
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>
</>
}
}
没有处理this指向的问题
class Btn extends React.Component {
showBtn() {
console.log(this); // undefined
}
render() {
return <button onClick={this.showBtn}>按钮</button>;
}
}
这时 App
中
handleClick(e) {
// 比较 Btn 组件中的事件处理函数
console.log(this.ref1.current.showBtn === this.ref2.current.showBtn); // true
}
class Btn extends React.Component {
showBtn = () => {
console.log(this);
}
render() {
return <button onClick={this.showBtn}>按钮</button>;
}
}
这时 App
中
handleClick(e) {
// 比较 Btn 组件中的事件处理函数
console.log(this.ref1.current.showBtn === this.ref2.current.showBtn);// false
}
class Btn extends React.Component {
constructor() {
super();
this.showBtn = this.showBtn.bind(this);
}
showBtn() {
console.log(this);
}
render() {
return <button onClick={this.showBtn}>按钮</button>;
}
}
这时 App
中
handleClick(e) {
// 比较 Btn 组件中的事件处理函数
console.log(this.ref1.current.showBtn === this.ref2.current.showBtn); // false
}
class Btn extends React.Component {
showBtn() {
console.log(this);
}
render() {
return <button onClick={this.showBtn.bind(this)}>按钮</button>;
}
}
这时 App
中
handleClick(e) {
// 比较 Btn 组件中的事件处理函数
console.log(this.ref1.current.showBtn === this.ref2.current.showBtn); // true
}
class Btn extends React.Component {
showBtn() {
console.log(this);
}
render() {
return <button onClick={() => this.showBtn()}>按钮</button>;
}
}
这时 App
中
handleClick(e) {
// 比较 Btn 组件中的事件处理函数
console.log(this.ref1.current.showBtn === this.ref2.current.showBtn); // true
}
结合以上的对比分析,推荐react中,事件处理函数的写法有2种
class Btn extends React.Component {
showBtn() {
console.log(this);
}
render() {
return <button onClick={this.showBtn.bind(this)}>按钮</button>;
}
}
class Btn extends React.Component {
showBtn() {
console.log(this);
}
render() {
return <button onClick={() => this.showBtn()}>按钮</button>;
}
}