使用 ReactJS 在 ES6 类 中嵌套 "this" 绑定

Nested "this" binding in ES6 classes using ReactJS

阅读 React 文档时我遇到了 following piece of code:

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

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

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

  tick() {
    this.setState({
      date: new Date()
    });
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

ReactDOM.render(
  <Clock />,
  document.getElementById('root')
);

我的问题是:

componentDidMount() 中,箭头函数 () => this.tick() "captures" 封闭的 this 值,因此在 [=17= 上调用了正确的 tick 方法] 零件。

但是 tick 单独使用 this 随后调用 setState 方法。在没有任何绑定的情况下,这是如何工作的?换句话说,this.setState 是如何工作的?

谢谢

根据bind function documentationFunction.prototype.bind将创建一个与原函数具有相同主体和范围的新函数,但新函数范围内的this指的是传递给 bind 的参数。这意味着你可以传递一个变量,假设 newContext 进入 bind 函数,如:tick.bind(newContext),tick 内的每个 this 实例将被评估为 newContext.尽管 this 是一个引用范围上下文的关键字,但我们更改了范围的上下文,因此 this 具有不同的值。

箭头符号做类似的事情,并将值 tick 中的 this 替换为箭头函数范围上下文的值。这就是 tick 中的 this 关键字没有 undefined 值的原因。

我想 Rajesh 已经在评论中解释过了,我还是会尝试解释一下。

箭头函数不会创建自己的 this 上下文,因此 this 在封闭上下文中具有其原始含义,即从调用它的位置开始,在您的情况下是 componentDidMount

  componentDidMount() {
    // this refers to React.Component instance
    this.timerID = setInterval(
      () => this.tick(),  // <----------------Same this is available here
      1000
    );
  }

如果您使用绑定,您可以通过绑定设置上下文来实现类似的事情。

  componentDidMount() {
    // this refers to React.Component instance from inside cdm method
    this.timerID = setInterval(
      this.tick.bind(this),  // <----------------Same this is available here
     // We have set it react component instance via bind
      1000
    );
  }

毕竟那些只看这个方法声明的人 -

  tick() {
    this.setState({
      date: new Date()
    });
  }

到目前为止,我们无法确切地说出 tick 中的 this 的值是多少。 我们也不能说“setState”是否会在 this 上可用。

除非并且直到我们看到从哪里调用 tick 以及什么 执行上下文 将附加到 tick运行时间.

现在,如果我们看到从哪里调用 tick - componentDidMountcomponentDidMount 是 React 组件的生命周期方法,它(关联的上下文即 this)肯定有 setState 方法可用。

并且在 componentDidMount 中,我们通过箭头函数 () => {}bindthis 设置为 react-component 上下文。 这就是调用时 setStatetick 中可用并且您看不到任何错误的原因。

但是如果你不使用 arrow functionexplicit bind 你将在每次 setInterval 通过将全局 this 与 tick 相关联来调用 tick 函数。

  "message": "Uncaught TypeError: this.setState is not a function",

通过运行查看下面的代码片段,查看错误

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  componentDidMount() {
    // now this inside tick will be pointing to setIntervals execution context which could be global
    this.timerID = setInterval(
      this.tick,
      1000
    );
  }

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

  tick() {
    this.setState({
      date: new Date()
    });
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

ReactDOM.render(
  <Clock />,
  document.getElementById('root')
);
<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="root">
</div>