当你使用 ES6 class 语法定义一个组件的时候,通常的做法是将事件处理函数声明为 class 中的方法。例如,下面的 Toggle 组件会渲染一个让用户切换开关状态的按钮:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>事件处理中this</title>
  <script src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
  <script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
  <!-- <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> -->
  <!-- <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script> 
</head>
<body>
  <div id="root"></div>
  <script type="text/babel">
    class Toggle extends React.Component {
      constructor(props) {
        super(props)
        this.state = { isToggleOn: false }
      }

      handleClick() {
        console.log(this) // undefined
        this.setState((state, props) => ({
          isToggleOn: !state.isToggleOn
        })) 
        // 大括号外需要加小括号
        // 原因:因为箭头函数写法()=>{}后面的大括号作为函数体,
        // 如果上面(state, props) => {isToggleOn: !state.isToggleOn}不加上()则大括号里面isToggleOn: !state.isToggleOn将作为函数体执行,明显里面内容不是执行语句。
        // 如果加上小括号,(state, props) => ({isToggleOn: !state.isToggleOn})的函数体就相当于返回一个{isToggleOn: !state.isToggleOn}对象
      }

      render() {
        return (
          <button onClick={this.handleClick}>
            {this.state.isToggleOn ? 'on' : 'off'}
          </button>
        )
      }
    }

    ReactDOM.render(
      <Toggle />,
      document.getElementById('root')
    )
  </script>
</body>
</html>

当浏览器执行上述脚本代码时会发生如下错误:
2.png
错误产生的原因是因为onClick={this.handleClick}仅仅传入了函数的引用,并没有绑定执行函数this指向,所以this值是undefinedthis.setState就找不到setState

既然没有绑定函数的this指向,我们有以下两种方式指定this

  • 1、使用bind绑定this
constructor(props) {
    super(props)
    this.state = { isToggleOn: false }
    this.handleClick = this.handleClick.bind(this)
}

或者

render() {
    return (
      <button onClick={this.handleClick.bind(this)}>
        {this.state.isToggleOn ? 'on' : 'off'}
      </button>
    )
}
  • 2、回调函数采用调用式
render() {
    return (
      <button onClick={() => this.handleClick()}>
        {this.state.isToggleOn ? 'on' : 'off'}
      </button>
    )
}

handleClick函数调用者是this(Toggle对象),所以函数内部this也指向Toggle对象


记得要微笑
1.9k 声望4.5k 粉丝

知不足而奋进,望远山而前行,卯足劲,不减热爱。