如何使用setState在内部更新为内部状态?

时间:2019-09-10 08:56:58

标签: javascript reactjs

在React中,我们使用setState来更新组件的状态。 setState是一个异步过程,因此如果我们在同一函数中有多个setState,则为componentDidMount

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


场景1:

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"))的for循环中更新状态,但执行周期相同。

<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>
componentDidMount


方案2:

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"))中的for循环中更新状态,但是在不同的执行周期中进行。

<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>
getImageSize(url){
      var img = new Image()
      img.src = url
      img.onload = function(){
        return [img.width, img.height]
      }
    } 
    getImageUrl(obj){
      let vm = this
      let reader = new FileReader()
      reader.readAsDataURL(obj)
      reader.onload =  function() {
        return reader.result
      }

    }
    async getImageSize(imgObj){
      let base64URI = await this.getImageUrl(imgObj)
      let size = await this.getImageSize(base64URI)
      return size
    }

   beforeuploadImage(event){
      let imgsize = this.getImageSize(imgObj)
      imgsize  = imgsize.split(",")
      console.log(imgsize[0], imgsize[1])
   }


如果您注意到方案1和2,则在方案1中仅执行2次更新(假定1为初始更新,而其他为final )。但是,在方案2中,状态会针对每个setState进行更改/更新。

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

2 个答案:

答案 0 :(得分:4)

  

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

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

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

答案 1 :(得分:0)

如果要使用setState进行batchUpdate,则应使用同步setState。有一种预定义的方法可以使我们的setState同步。

我对您的解释很困​​惑,但是根据react文档的说法,我们不应该将多个状态设置为一个函数。因为它将导致每次重新渲染。但这不是一个好方法。

所以这是您要设置的计数状态,但要以同步方式进行。 那么您可能更喜欢

this.setState(prevState=>{
const {count}=prevState;
//perform any action with this count state and at the end 
return {...prevState,count};})

希望这种方法可能对您有所帮助。