React - 为什么在这个例子中不需要绑定 this?

IT技术 reactjs binding
2021-05-05 06:33:40

试图弄清楚 React 的基础知识。

查看此页面上的第二个示例:https : //facebook.github.io/react/ 我看到 tick() 函数设置 Timer 类的状态,将先前的值加一。

class Timer extends React.Component {
  constructor(props) {
    super(props);
    this.state = {secondsElapsed: 0};
  }

  tick() {
    this.setState((prevState) => ({
      secondsElapsed: prevState.secondsElapsed + 1
    }));
  }

  componentDidMount() {
    this.interval = setInterval(() => this.tick(), 1000);
  }

  componentWillUnmount() {
    clearInterval(this.interval);
  }

  render() {
    return (
      <div>Seconds Elapsed: {this.state.secondsElapsed}</div>
    );
  }
}

ReactDOM.render(<Timer />, mountNode);

但是,当我尝试实现自己的简单 Counter 类时,它失败了,并且出现控制台错误,提示无法读取未定义的属性 setState。

class Counter extends React.Component {
    constructor(props) {
        super(props);
        this.state = {count: 0};
    }

    increment(prevState) {
        this.setState((prevState) => ({
            count: prevState.count + 1
        }));
    }

  render() {
    return (
            <div className="main">
                <button onClick={this.increment}>{this.state.count}</button>
            </div>
    )
  }
}

一些谷歌搜索表明我必须将它绑定到增量函数。但是为什么在我看到的第一个示例中不需要这样做?我将代码复制到 CodePen,它在 React 15.3.1 中运行良好,我在该示例中找不到任何类似于绑定的内容。只有在构造函数中添加绑定代码后,我的示例才开始工作。

class Counter extends React.Component {
    constructor(props) {
        super(props);
        this.state = {count: 0};

        // THIS ONE LINE FIXED THE ISSUE
        this.increment = this.increment.bind(this);
    }

    increment(prevState) {
        this.setState((prevState) => ({
      count: prevState.count + 1
    }));
    }

  render() {
    return (
            <div className="main">
                <button onClick={this.increment}>{this.state.count}</button>
            </div>
    )
  }
}
2个回答

回答您的问题:第一个示例使用arrow functions,自动执行上下文绑定从文档:

箭头函数不会创建自己的 this 上下文,因此 this 具有其封闭上下文的原始含义。

在 React 中确实有一些绑定方式:

1)你可以在你的构造函数中绑定所有函数,就像你说的:

constructor(props) {
    /* ... */
    this.increment = this.increment.bind(this);
}

2) 使用箭头函数调用回调:

<button onClick={(e) => this.increment(e)}>

3).bind每次将其设置为回调时,在方法引用的末尾追加,如下所示:

<button onClick={this.increment.bind(this)}>

4) 在你的类中,定义带有箭头函数的方法:

increment = (e) => {
  /* your class function defined as ES6 arrow function */
}

/* ... */

<button onClick={this.increment}>

为了在 babel 中使用此语法,您必须启用此插件或使用stage-2预设。

如果您仔细查看第tick()一个示例中函数的调用方式,您就会明白在使用arrow functions. 如果您对 increment 函数执行相同操作,它也将起作用。这些只是绑定函数的不同方式。

因此,正如所问的那样,并不是在第一个示例中没有指定绑定,而第二个示例需要绑定,而是在您的两种情况下,您都在绑定,只是两种情况的绑定方式不同。

class Counter extends React.Component {
    constructor(props) {
        super(props);
        this.state = {count: 0};

        
       
    }

    increment(prevState) {
        this.setState((prevState) => ({
      count: prevState.count + 1
    }));
    }

  render() {
    return (
            <div className="main">
                <button onClick={() => this.increment()}>{this.state.count}</button>
            </div>
    )
  }
}

ReactDOM.render(<Counter/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>