react setState不会更新我们预期的状态

时间:2017-03-30 15:56:01

标签: javascript reactjs

我有一个看起来像这样的反应组件:

class MyComponent extends Component {
  incrementQty = () => {
    // calls this.setState({....})
  }

  setQty (qty) => {
    for (....) {
      this.incrementQty()
    }
  }
}

我的问题是在循环中的最后一次调用之前状态不会更新,我知道setState是异步的,我不能在这里使用redux来在调度动作后重新渲染组件。

有没有人有解决方案,谢谢。

3 个答案:

答案 0 :(得分:2)

状态应该尽可能少地更新,如果你在循环中快速更新它将导致问题,因为它试图根据状态变化重新渲染。

如果您根据'incrementQty'中的当前状态更新状态,这也会导致问题,因为渲染周期尚未完成,并且每个循环都不会更新当前状态。

要解决此问题,请先计算新数量,然后再更新状态:

class MyComponent extends Component {
  setQty (qty) => {
    let newQuantity = 0; //or this.state.quantity?
    for (....) {
      newQuantity++;
    }
    this.setState({quantity:newQuantity}
  }
}

P.S。无论如何你似乎都要将数量传递给setQty,你确定你不只是想使用'this.setState({quantity:qty});'?

答案 1 :(得分:0)

内部状态变化不会同步发生,你是对的。在当前函数调用之后,对内部状态的任何更改都会排队,直到至少。所以正在发生的事情是你对setState的几次调用被合并为一个大的增量。

在重新渲染之前,您需要再次访问状态是什么?而不是仅仅增加数量,最好只在组件状态中设置数量,而不是使用for循环。如果您希望一次增加一个值,请使用生命周期方法 - 可能是componentDidUpdate - 在每次渲染时递增第二个计数器,直到达到qty的正确值。

答案 2 :(得分:0)

您可以使用原子setState的回调形式。 Demo Docs

this.setState((prevState, props) => {
  return {myInteger: prevState.myInteger + props.step};
});

它更新了状态" redux"方式,但没有减少。

class MyComponent extends Component {
  incrementQty = () => {
    this.setState((prevState) => {
       return {counter: prevState.counter + 1}
    })
  }

  setQty (qty) => {
    for (....) {
      this.incrementQty()
    }
  }
}

完整示例

const { Component } = React
const { render } = ReactDOM


class App extends Component {
  constructor(props, ctx) {
    super(props, ctx);

    this.state = {
      counter: 0
    }

    this.inc = this.inc.bind(this);
    this.dec = this.dec.bind(this);
  }

  // this works for multiple calls
  inc() {
    this.setState((prevState) => {
      return {
        counter: prevState.counter + 1
      }
    })
  }

  // this doesn't work on subsequent calls
  dec() {
    this.setState({
      counter: this.state.counter - 1
    })
  }

  up(qty) {   
    while(qty--) {
      this.inc()
    }
  }

  down(qty) {
    while(qty--) {
      this.dec()
    }
  } 

  render() {
    const { counter } = this.state

    return (
      <div>
        <div>
          <button type="button" onClick={() => this.up(10) }>+10</button>
          <button type="button" onClick={() => this.up(5) }>+5</button>
          <button type="button" onClick={this.inc}>+</button>
          <button type="button" onClick={this.dec}>-</button>
          <button type="button" onClick={() => this.down(5) }>-5</button>
          <button type="button" onClick={() => this.down(10) }>-10</button>
        </div>

        {counter}
      </div>
    )
  }
}


render(<App />, document.getElementById('content'))