反应:this.state vs this.setState

时间:2019-04-12 00:18:36

标签: javascript reactjs

方案1:

const { foo } = this.state;

方案2:

this.setState(({ foo }) => { ... });

在这两种情况下,foo是否保证相同?还是setState会异步运行并根据其他setState返回不同的值?

3 个答案:

答案 0 :(得分:2)

当您使用this.setState后立即访问状态时,状态可能是状态,因为this.setStateasync

如果需要基于更新的状态(即,在调用this.state之后进行计算),则可以将方法的第二个参数用作该方法,该方法是在提交状态更改后触发的回调。 / p>

this.setState(updateState, () => {
   const { foo } = this.state;

   console.log(foo); // updated foo
});

function updatedState({ foo }) { 
    // you can be sure that `foo`
    // is from the previous state 
    // before setState is called
}

答案 1 :(得分:2)

React docs所述:

  

setState()并不总是立即更新组件。它可能   批处理或将更新推迟到以后。这使得阅读this.state   在调用setState()之后立即发生潜在的陷阱。相反,使用   componentDidUpdate或setState回调(setState(updater,   回调)),保证在更新后都会触发   已应用。

因此,我们可以使用 setState 的第二个参数来传递回调,在该回调中我们执行逻辑,这取决于具有foo的更新值。但是,您最初的问题是const { foo } = this.state;中foo的值和this.setState(({ foo }) => { ... });中foo的值是否相同。

为了对此进行检查,我们可以比较执行 setState ,然后执行 this.state.foo setState 后跟另一个 setState (第二个将仅记录foo的值而不是对其进行突变)。请参考以下代码段:

class Example extends React.Component {
  constructor() {
    super();
    this.state = {
      foo: 0,
      boo: 0
    }
  }
  
  handleClickSetState = () => {
    this.setState(({foo}) => ({foo: foo+1}));
    this.setState(({foo}) => console.log("inside setState. foo: ", foo));
  }
  
  handleClickState = () => {
    this.setState(({boo}) => ({boo: boo+1}));
    console.log("outside setState. boo: ", this.state.boo)
  }
  
  render() {
    return <React.Fragment>
      <button onClick={this.handleClickState}>Test state</button>
      <button onClick={this.handleClickSetState}>Test setState</button>
    </React.Fragment>
  }
}

ReactDOM.render(<Example />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

我们可以看到“状态案例”落后1,这是我们期望的,因为 setState 是异步的(而且我们没有使用的第二个参数setState )。但是,“ setState情况”表明,即使我们未在setState中使用第二个参数回调,也始终显示正确的值。

最后,const { foo } = this.state;始终会为您提供foo的立即值,而与挂起状态合并无关,而this.setState(({ foo }) => { ... });似乎将在执行回调之前首先完成挂起的更新,这意味着foo将始终具有最新值。

答案 2 :(得分:1)

setState是异步的,从setState中使用状态取值是潜在的错误源。 setState可以接受多个参数。它可以只接受新状态,接受旧状态+道具并返回新状态,新状态和设置新状态后要运行的函数的回调,或组合使用。示例:

this.setState(
  // function taking previous state + props,
  // which should return updated state.
  // this could also just be an object with
  // the new state, if you don't need to rely
  // on previous state.
  (previousState, props) => {
    if (previousState.something) {
      return { something: somethingElse }
    } else {
      return { something: anotherThing }
    }
  }, () => {
    // safe to use new state here,
    // since state has been updated.
    // but it's recommended to use
    // componentDidUpdate instead!
  })