React事件处理中this使用解决办法:箭头函数+class fields语法

前言

在React中,我们对事件命名采用小驼峰式(camelCase),而不是纯小写。
传统HTML、React中JSX写法:

// 传统html
<button onclick="handleClickBtn()">按钮</button>
// React JSX
<button onClick={handleClickBtn}>按钮</button>

在传统HTML写法里,onclick="handleClickBtn()",引号内部是js代码,当触发事件后执行该脚本;

而在React里使用{ }JSX的语法,onClick={handleClickBtn}这句代码React会帮我们添加了监听器,handleClickBtn是当前作用域下的一个指向方法的变量名,但是由于JS函数工作原理问题,在ES6 class语法定义组件中(函数组件则不需要,但它也不能提供状态功能的支持,本文仅讨论class组件),我们需要为它绑定this,否则handleClickBtn内部this的指向会出现异常,指向该函数的调用者(此处是undefined),完整代码:

class Btn extends React.Component {
  constructor(props) {
    super(props);
    // 为了在回调中使用 `this`,这个绑定是必不可少的
    this.handleClickBtn= this.handleClickBtn.bind(this);
  }

  handleClickBtn() {
   	// ...通过手动绑定this,this指向正常
  }

  render() {
    return (
      <button onClick={this.handleClickBtn}>
        按钮
      </button>
    );
  }
}

这样每次绑定都要在constructor构造函数里通过bind()方法绑定this的指向,当你的事件处理程序多了会很麻烦。

解决办法有两个:箭头函数,实验性public class fields语法(ES2022)。

一、箭头函数

箭头函数this是词法作用域,由上下文确定:

class Btn extends React.Component {
  constructor(props) {
    super(props);
    // 什么都不干,就不用写constructor了,一般对state初始化
  }

  handleClickBtn() {
   	// ...this指向由调用它的箭头函数的上下文决定
  }

  render() {
    return (
      <button onClick={() => this.handleClickBtn()}>
        按钮
      </button>
    );
  }
}

代码onClick={() => this.handleClickBtn()},通过箭头函数调动我们的事件处理方法,避免了this指向异常。

注意:
官方文档有提到这样每次渲染组件都会创建不同的回调函数,少数情况下(该回调函数作为prop传入子组件时),可能会进行额外的重新渲染。

二、实验性public class fields语法

详细内容可参考babeljs文档

也就是将事件处理函数的实现通过箭头函数赋值:handleClickBtn = () => {}

上面用例改写后:

class Btn extends React.Component {
  constructor(props) {
    super(props);
    // 什么都不干,就不用写constructor了,一般对state初始化
  }

  handleClickBtn = () => {
   	// ...this指向正常
  }

  render() {
    return (
      <button onClick={this.handleClickBtn}>
        按钮
      </button>
    );
  }
}

三、手动传参

值得一提的是,当我们需要手动传参时(非回调函数传参),如果你写成onClick={this.handleClickBtn(1)},在渲染后会立刻执行该方法!!!

1.为避免函数立即执行,需要在绑定事件处使用箭头函数了:

class Btn extends React.Component {
  constructor(props) {
    super(props);
    // 什么都不干,就不用写constructor了,一般对state初始化
  }

  handleClickBtn(num) {
   	// ...this指向正常
   	// 此处函数实现用class fields语法也行,不冲突
  }

  render() {
    return (
      <div>
		<button onClick={() => this.handleClickBtn(1)}>
          按钮1
        </button>
        <button onClick={() => this.handleClickBtn(2)}>
          按钮2
        </button>
	  </div>
    );
  }
}

此时事件处理函数实现用public class fields语法也行,不冲突。

2.在绑定事件处使用bind()传参

<button onClick={this.handleClickBtn(this, 1)}>
  按钮1
</button>

bind()绑定了this但并不会立刻执行函数,这样也可以。


版权声明:本文为weixin_43260489原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。