React class 组件在方法上异常绑定

React class component unusual this binding on methods

例如下面的 class 组件:

class Todo extends Component {
  state = {
    list: ["First Todo"],
    text: ""
  };

  handleSubmit(e) {
    e.preventDefault();
    if (this && this.setState) {
      console.log("this present in handleSubmit");
      this.setState(prevState => ({
        list: prevState.list.concat(this.state.text),
        text: ""
      }));
    } else {
      console.log("this not present in handleSubmit");
    }
  }

  handleChange(e) {
    if (this && this.setState) {
      console.log("this present in handleChange");
      this.setState({
        text: e.target.value
      });
    } else {
      console.log("this not present in handleChange");
    }
  }

  removeItem(index) {
    if (!this || !this.setState) {
      console.log("this not present in removeItem");
    }
    console.log("this present in removeItem");
    const list = this.state.list;
    list.splice(index, 1);
    this.setState({ list });
  }

  render() {
    return (
      <div>
        <h1>TODO LIST</h1>
        <form onSubmit={this.handleSubmit}>
          <input value={this.state.text} onChange={e => this.handleChange(e)} />
          <button>Add</button>
          <ol>
            {this.state.list.map((item, index) => {
              return (
                <li key={index}>
                  {item}
                  <button onClick={() => this.removeItem(index)}>Delete</button>
                </li>
              );
            })}
          </ol>
        </form>
      </div>
    );
  }
}

this 绑定到 class 方法的行为不一致。

使用组件我们会发现,handleChangeremoveItem 具有正确的 this 上下文,而 handleSubmit 具有 this 上下文undefined.

两个具有正确 this 上下文的函数在 jsx 中表示为箭头函数。如下所示:

<input value={this.state.text} onChange={e => this.handleChange(e)} />

handleSubmit 作为函数本身传递。如下所示:

<form onSubmit={this.handleSubmit}>

但是,我真的不知道为什么会这样。因为,根据我的理解,函数的传递方式应该无关紧要,即作为函数本身或上面的箭头表示。

箭头函数有词法 this。这意味着 its value is determined by the surrounding scope。因此,当您使用它而不是 class methods 时,this 值将映射到实例。但是当您调用 this.onSubmit 时,this 将引用本地范围而不是实例本身。要解决它,请使用 arrow functionsbind 构造函数中的 onSubmit 方法。

constructor(props){
   super(props)
   this.onSubmit = this.onSubmit.bind(this)
}

In my understanding, it should not have mattered how the function was passed...

所以这里有新东西要学

传递 onChange={e => this.handleChange(e)} 与在构造函数中使用 .bind 或传递引用并使用 .bind.

相同

在 render 方法中将其作为箭头函数传递时,它将获取组件的 this 而不是方法的 this。

您应该注意到 onChange={e => this.handleChange(e)} 不是一个好的做法,因为在每次渲染时您都会创建一个新函数。