react 中事件处理函数中this指向问题

我们知道,在 react 中,事件处理函数中的this很容易丢失,如:

class App extends React.Component {
  handleClick() {
    console.log(this);// undefined 
  }
  render() {
    return <div onClick={this.handleClick} >点我</div>;
  }
}

有4种this指向的解决方案 , 如下:

  1. 箭头函数
  2. 构造函数中的 bind
  3. 事件绑定时的 bind
  4. 事件绑定时的匿名函数+箭头函数。

下边我们分别给出它们的实现

箭头函数

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>;
  }
}
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容