在React组件中多次使用this.setState会发生什么?

ale*_*der 85 javascript reactjs

我想检查多次使用this.setState时会发生什么(为讨论起见,这是2次).我认为该组件将呈现两次,但显然它只呈现一次.我的另一个期望是,对于setState的第二次调用可能会超过第一次,但你猜对了 - 工作正常.

链接到JSfiddle

var Hello = React.createClass({
  render: function() {
    return (
      <div>
        <div>Hello {this.props.name}</div>
        <CheckBox />
      </div>
    );
  }
});

var CheckBox = React.createClass({
  getInitialState: function() {
    return {
      alex: 0
    };
  },

  handleChange: function(event) {
    this.setState({
      value: event.target.value
    });
    this.setState({
      alex: 5
    });
  },

  render: function() {
    alert('render');
    return (
      <div>
        <label htmlFor="alex">Alex</label>
        <input type="checkbox" onChange={this.handleChange} name="alex" />
        <div>{this.state.alex}</div>
      </div>
    );
  }
});

ReactDOM.render(
  <Hello name="World" />,
  document.getElementById('container')
);
Run Code Online (Sandbox Code Playgroud)

正如您将看到的,每次渲染都会弹出一个"渲染"警告.

你有解释为什么它正常工作?

Chr*_*eau 100

React批处理事件处理程序和生命周期方法中发生的状态更新.因此,如果在<div onClick />处理程序中多次更新状态,React将在重新呈现之前等待事件处理完成.

需要说明的是,这仅适用于React控制的综合事件处理程序和生命周期方法.例如,状态更新不会在AJAX和setTimeout事件处理程序中进行批处理.

  • 由于React完全控制合成事件处理程序(如`<div onClick />`)和组件生命周期方法,因此它知道它可以在调用批处理状态更新期间安全地更改`setState`的行为并等待刷新.相比之下,在AJAX或`setTimeout`处理程序中,React无法知道我们的处理程序何时完成执行.从技术上讲,React在两种情况下都会对状态更新进行排队,但会立即在React控制的处理程序之外进行刷新. (11认同)
  • 谢谢,这是有道理的,知道它是如何在幕后完成的吗? (2认同)
  • @neurosnap 我认为文档没有对此进行过多详细说明。它在[状态和生命周期部分](https://facebook.github.io/react/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous)和[setState docs ](https://facebook.github.io/react/docs/react-component.html#setstate)。参见[ReactDefaultBatchingStrategy](https://github.com/facebook/react/blob/15-stable/src/renderers/shared/stack/reconciler/ReactDefaultBatchingStrategy.js#L52)的代码,目前唯一官方的batching战略。 (2认同)
  • @BenjaminToueg我相信你可以在React事件处理程序之外使用`ReactDOM.unstable_batchedUpdates(function)`批处理`setState`.顾名思义,您将使保修失效. (2认同)
  • 总是很高兴引用这个人 https://twitter.com/dan_abramov/status/887963264335872000?lang=en (2认同)
  • 同样由 ​​Dan Abramov 撰写,并从 setState 文档链接到:/sf/ask/3399455531/#48610973 (2认同)

小智 20

setState()方法不会立即更新组件的状态,它只是将更新放入队列中以便稍后处理.React可以将多个更新请求一起批处理,以提高渲染效率.因此,当您尝试根据组件的先前状态更新状态时,必须采取特殊预防措施.

例如,以下代码仅将状态值属性递增1,即使它被调用了4次:

 class Counter extends React.Component{
   constructor(props){
     super(props)
    //initial state set up
     this.state = {value:0}
   }
   componentDidMount(){
    //updating state
    this.setState({value:this.state.value+1})
    this.setState({value:this.state.value+1})
    this.setState({value:this.state.value+1})
    this.setState({value:this.state.value+1})
   }
   render(){
    return <div>Message:{this.state.value}</div>
   }
}
Run Code Online (Sandbox Code Playgroud)

为了在更新后使用状态,请执行回调参数中的所有逻辑:

//this.state.count is originally 0
this.setState({count:42}, () => {
  console.log(this.state.count)
//outputs 42
})
Run Code Online (Sandbox Code Playgroud)

setState(updater,[callback])方法可以将updater函数作为其第一个参数,以根据先前的状态和属性更新状态.updater函数的返回值将与先前的组件状态浅浅地合并.该方法异步更新状态,因此有一个选项回调,一旦状态完全更新将被调用.

例:

this.setState((prevState, props) => { 
return {attribute:"value"}
})
Run Code Online (Sandbox Code Playgroud)

以下是如何根据以前的状态更新状态的示例:

    class Counter extends React.Component{
      constructor(props) {
        super(props)
    //initial state set up
        this.state = {message:"initial message"}
    }
      componentDidMount() {
    //updating state
        this.setState((prevState, props) => {
          return {message: prevState.message + '!'}
        })
     }
     render(){
       return <div>Message:{this.state.message}</div>
     }
  }
Run Code Online (Sandbox Code Playgroud)

  • @Biboswan,嗨,我是 React 新手,想问你 CompountDidMount 方法中的所有四个 setState 是否都被合并,并且只有最后一个 setState 将被执行,而其他 3 个将被忽略? (2认同)