【问题标题】:continuous setState doesn't work as expected连续的 setState 不能按预期工作
【发布时间】:2018-06-29 14:32:09
【问题描述】:

我有以下代码 -

class Sum extends React.Component {
    constructor(props) {
      super(props)
      this.state = { a : 0 }
    }

    // let's call this ADD-1
    add = () => {
      this.setState({ a: this.state.a + 1 })
      this.setState({ a: this.state.a + 2 })
      this.setState({ a: this.state.a + 3 })
    } 

    render() {
      return (<div>
        <button onClick={this.add}> click me  </button>
        <div> sum  {this.state.a} </div>
      </div>)
    }
}

这会在点击按钮时呈现

sum = 3

我希望它会在哪里呈现 sum = 6 即 1 + 2 + 3

另外,如果我将我的 add 方法更改为适应 prevState 竞争条件的方法 -

  // let's call this ADD-2
  add = () => {
    this.setState({ a: this.state.a + 1 })
    this.setState({ a: this.state.a + 2 })
    this.setState(prevState => ({ a: prevState.a + 1 }))
    this.setState(prevState => ({ a: prevState.a + 4 }))
  }

它呈现sum = 7,而我希望得到sum = 8,即(1 + 2 + 1 + 4)

现在我想到了两个问题:-

1) 为什么我们看到的结果是上面提到的,而不是我所期望的?

2) 为什么我在 UI 中看不到添加的过渡? 假设我们考虑标记为ADD-1 的方法,我应该看到类似sum = 1 然后sum = 3 然后sum = 6。是因为批处理更新,但批处理将它们置于执行队列中,我认为它不会覆盖任何内容。

【问题讨论】:

  • setState 是异步的,所有这些都被一次“基本上”调用。这意味着最后一个是将状态设置为 0 + 3。 setState 方法有一个回调,如果你想等待它更新然后调用你的另一个 setState。 this.setState({value: value+1}, () => { this.setState({value: value + 2})}) medium.com/@wereHamster/…

标签: javascript reactjs setstate


【解决方案1】:

状态更新可能是异步的。检查这个answer

在 Dan abramov 的 answer 中,声明一个事件调用中的状态更新只会在事件结束时产生一次重新渲染。

无论你在多少个组件中调用了多少个 setState() 在 React 事件处理程序中,它们只会产生一个 在事件结束时重新渲染。

而且批处理仅发生在 React 事件处理程序中的状态更新,即批处理不会发生在 AJAX 调用中

promise.then(() => {
  // We're not in an event handler, so these are flushed separately.
  this.setState({a: true}); // Re-renders with {a: true, b: false }
  this.setState({b: true}); // Re-renders with {a: true, b: true }
  this.props.setParentState(); // Re-renders the parent
});

但是您可以通过将回调传递给setState 方法来实现您想要的目标

add = () => {
      this.setState({ a: this.state.a + 1 },
        () => {
        this.setState({ a: this.state.a + 2 },
          () => {
          this.setState({ a: this.state.a + 3 })
        })
      })    
    }

以上将返回 sum = 6。

何时不在 setState 中使用回调:

PureComponentshouldComponentUpdate 可用于调整 组件的性能。它们通过阻止生命周期方法来工作 在 props 和 state 没有改变时触发。

无论shouldComponentUpdate 是什么,都会触发setState 回调 返回。所以,setState 回调会触发,即使状态还没有 改变了。

【讨论】:

    【解决方案2】:

    当您的更新依赖于当前状态时,请确保将函数传递给setState,这样它就不会被后续的setState 覆盖。

    示例

    class App extends React.Component {
      state = { a: 0 };
    
      add = () => {
        this.setState(previousState => {
          return { a: previousState.a + 1 };
        });
        this.setState(previousState => {
          return { a: previousState.a + 2 };
        });
        this.setState(previousState => {
          return { a: previousState.a + 3 };
        });
      };
    
      render() {
        return (
          <div>
            <button onClick={this.add}> click me </button>
            <div> sum {this.state.a} </div>
          </div>
        );
      }
    }
    

    【讨论】:

      【解决方案3】:

      “为了提高性能,React 可以将多个 setState() 调用批处理到单个更新中。”

      来自Docs

      【讨论】:

        【解决方案4】:

        状态变化只能通过 setState 发生,但如果你在 setState (this.state.a + 1) 之前访问和修改 this.state,它不会反映。所以每次你访问 this.state.a 时它都会得到 0 即初始值。

        add = () => {
          this.setState({ a: this.state.a + 1 }) // 0 + 1
          this.setState({ a: this.state.a + 2 }) // 0 + 2
          this.setState({ a: this.state.a + 3 }) // 0 + 3
        } 
        
        this.setState((previousState) => { // change state using previousState} );
        

        这是必须更新状态的方式

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-06-26
          • 2013-05-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多