首页 > 解决方案 > 使用 setState 在内部更新状态如何反应?

问题描述

在 React 中,我们使用setState来更新组件的状态。setState是一个异步进程,所以如果我们setState在同一个函数中有多个。

问题:内部如何处理更新的批处理?


场景一:

componentDidMount在同一执行周期中更新 for 循环中的状态。

class TodoApp extends React.Component {
  constructor(props) {
    super(props)
    var state = { count: 0 };
    Object.defineProperty(this, 'state', {
    	set: function(value) { console.log('called', value.count); state = value },
      get: function() { return state; }
    })
  }
  
  test() {
  	for (let i = 0; i< 1000; i++) {
      this.setState({ count: i });
    }
  }
  
  componentDidMount() {   
    this.test();
  }
  
  render() {
    return (
      <div>
        { this.state.count }
      </div>
    )
  }
}

ReactDOM.render(<TodoApp />, document.querySelector("#app"))
<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="app"></div>


场景二:

在 for 循环中更新状态,componentDidMount但在不同的执行周期中。

class TodoApp extends React.Component {
  constructor(props) {
    super(props)
    var state = { count: 0 };
    Object.defineProperty(this, 'state', {
    	set: function(value) { console.log('called', value.count); state = value },
      get: function() { return state; }
    })
  }
  
  test() {
  	for (let i = 0; i< 1000; i++) {
      this.setState({ count: i });
    }
  }
  
  componentDidMount() {   
    setTimeout(this.test.bind(this), 0);
  }
  
  render() {
    return (
      <div>
        { this.state.count }
      </div>
    )
  }
}

ReactDOM.render(<TodoApp />, document.querySelector("#app"))
<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="app"></div>


如果您注意到场景 1 和 2,则在场景 1 中仅执行 2 次更新(假设 1 用于初始更新,其他用于最终更新)。但是,在场景 2 中,每个 setState 的状态都会发生变化/更新。

那么异步更新是如何工作的呢?什么定义了批量更新操作?

标签: javascriptreactjs

解决方案


如果您在 React 事件处理程序中,它们将被一起批处理。React 批处理在 React 事件处理程序期间完成的所有 setState,并在退出其自己的浏览器事件处理程序之前应用它们。

setTimeout 不是 React 事件处理程序,因此 React 不会在 setTimeout 回调中批处理状态更新(场景 2)。

参考:https ://github.com/facebook/react/issues/10231#issuecomment-316644950


推荐阅读