React中setState的行为

时间:2017-06-15 14:14:59

标签: javascript reactjs

我在componentDidMount方法中获取组件的数据,如下所示:

componentDidMount() {
   this.getSomeData();
}

这是getSomeData方法本身:

getSomeData() {
   var that = this;
   var setState2 = this.setState;
   var setState3 = this.setState.bind(this);
   axios.get('/someurl').then(function(response) {
      that.setState({ data: response.data }); // option A
      setState2({ data: response.data }); // option B
      setState3({ data: response.data }); // option C
   });
}

'选项A'和'选项C'工作得很好,但是'选项B'抛出并且错误说'updater'方法不能在'undefined'上调用,这意味着'this'上下文的含义是setState里面错了。好的,在'选项C'中'this'的值是绑定的并且它可以工作,但有人可以解释为什么工作'选项A'不受约束?非常感谢!

3 个答案:

答案 0 :(得分:0)

var that = this;
var setState2 = this.setState;
var setState3 = this.setState.bind(this);
axios.get('/someurl').then(function(response) {
    // Here, you are invoking setState as a method of `that`, which
    // above was defined as `this`, creating a closure in this function
    that.setState({ data: response.data }); 

    // setState2 is an unbound function reference, as you assigned it to
    // the function setState directly above, but didn't call bind() on it
    // thus, this function has no idea of what `this` is and so it's undefined
    setState2({ data: response.data }); // option B

    // setState3 is a bound function. it has captured the value of `this` above, and so will provide it to the body of the function it has been bound to
    setState3({ data: response.data }); // option C
});

我希望能够解决问题

答案 1 :(得分:0)

对于选项A,您在变量this中存储了that上下文的引用,然后使用that.setState,允许您获取上下文而不将其绑定到任何位置。

在另一个变量中存储对上下文的引用是在回调中丢失上下文的常见解决方案。这是JavaScript的一般行为,不仅限于React。

使用arrow functions in ES6,您可以消除这些绑定“变通办法”,因为回调中不会更改this上下文。

axios.get('/someurl').then((response) => {
   this.setState({ data: response.data }); // option A
});

答案 2 :(得分:0)

选项A:您在that上调用了setState,该地址被定义为外部this - >所以它是回调中的一个闭包。

选项B: setState2是对不再具有" context"的函数的引用。 - 所以它没有约束力。执行该函数后,它不知道this的含义(参见下面的示例)

选项C: setState3setState2类似,但它确实知道this是什么,并且可以从中获取它。< / p>

<强>建议

  1. 使用arrow functions:这会保留this的值,因此您永远不必重新分配var that = this
  2. 将您的类方法声明为匿名箭头函数,以保持对此的访问(在React组件中特别有用):

    getSomeData = () => {
        // ...
    };
    
  3. 示例:

    &#13;
    &#13;
    class Test {
      constructor() {
        this.name = 'Test class';
      }
    
      setState(res) {
        console.log('this', this);
        try {
          console.log('Class: ', this.name);
          console.log('setState', res);
        } catch (e) {
          console.warn('Ups! Something went wrong', e);
        }
      }
    
      getSomeData() {
        var that = this;
        var setState2 = this.setState;
        var setState3 = this.setState.bind(this);
        var fakeResponse = {
          data: 'I came from the Internet!',
        };
    
        (function fakeAsync(response) {
          // option A
          console.group('Option A');
          that.setState({
            data: fakeResponse.data
          });
          console.groupEnd();
          // option B
          console.group('Option B');
          setState2({
            data: fakeResponse.data
          });
          console.groupEnd();
          // option C
          console.group('Option C');
          setState3({
            data: fakeResponse.data
          });
          console.groupEnd();
        })(fakeResponse);
      }
    }
    
    const test = new Test();
    
    test.getSomeData();
    &#13;
    &#13;
    &#13;

    如果你在控制台中查看,你会看到:

    Option A
      this Test {name: "Test class"}
      Class:  Test class
      setState Object {data: "I came from the Internet!"}
    Option B
      this undefined
      Ups! Something went wrong TypeError: Cannot read property 'name' of 
          undefined
        at setState (VM272:53)
        at fakeAsync (VM625:75)
        at Test.getSomeData (VM273:81)
        at window.onload (VM503:87)
    Option C
      this Test {name: "Test class"}
      Class:  Test class
      setState Object {data: "I came from the Internet!"}