简体   繁体   English

setState在React中的行为

[英]Behaviour of setState in React

I'm fetching data for my component inside of componentDidMount method which looks like this: 我正在componentDidMount方法中获取组件的数据,如下所示:

componentDidMount() {
   this.getSomeData();
}

And here is getSomeData method itself: 这是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
   });
}

'option A' and 'option C' are working just fine, but 'option B' throws and error saying that 'updater' method can't be called on 'undefined' which means that meaning of 'this' context is wrong inside of setState. '选项A'和'选项C'正常工作,但是'选项B'抛出并出错,提示无法在'undefined'上调用'updater'方法,这意味着'this'上下文的含义在内部错误的setState。 Okay, in 'option C' the value of 'this' is bound and it works, but can somebody explain why does work 'option A' which is not bound? 好的,在“选项C”中,“ this”的值是受约束的并且可以工作,但是有人可以解释为什么在没有约束的“选项A”中工作吗? Thanks a lot! 非常感谢!

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
});

I hope that clears things up 我希望这可以清除一切

For option A, you stored a reference to the this context in the variable that , and then used that.setState , allowing you to get hold of the context without binding it anywhere. 对于选项A,您在变量that存储了this上下文的引用,然后使用that.setState ,使您可以保留上下文,而无需在任何位置绑定它。

Storing a reference to the context in another variable is a common solution to losing the context in callbacks. 在另一个变量中存储对上下文的引用是在回调中丢失上下文的常见解决方案。 This is a JavaScript general behavior not limited to React. 这是JavaScript的一般行为,不仅限于React。

Using arrow functions in ES6 , you can eliminate these binding "workarounds" because the this context will not be changed in the callback. 使用ES6中的箭头功能 ,您可以消除这些绑定“变通办法”,因为在回调中不会更改this上下文。

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

Option A: You're calling setState on that which was defined as the outer this -> So it's a closure inside the callback. 选择A:你呼吁的setState that其被定义为外this - >所以它的回调内部封闭。

Option B: setState2 is a reference to a function that no longer has its "context" - so it's unbound. 选项B: setState2是对不再具有其“上下文”的函数的引用-因此它是未绑定的。 Once the function is executed it has no idea of what this means (see example below) 一旦执行了函数,就不知道this意味着什么(请参见下面的示例)

Option C: setState3 is similar to setState2 , but it does know what this is, and it will make it accessible from within it. 选项C: setState3类似于setState2 ,但它不知道this是,这将使它从内部访问它。


Suggestions : 意见建议

  1. Use arrow functions : This will preserve the value of this , so you'll never have to reassign it ( var that = this ) 使用箭头函数 :这样可以保留this的值,因此您不必重新分配它( var that = this )。
  2. Declare your class methods as anonymous arrow functions, to also preserve access to this (especially useful in React components): 将类方法声明为匿名箭头函数,以保留对此方法的访问(在React组件中尤其有用):

     getSomeData = () => { // ... }; 

Example: 例:

 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(); 

If you look in your console you'll see: 如果您在控制台中查看,则会看到:

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!"}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM