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

Posted

技术标签:

【中文标题】在 React 组件中多次使用 this.setState 会发生啥?【英文标题】:What happens when using this.setState multiple times in React component?在 React 组件中多次使用 this.setState 会发生什么? 【发布时间】:2016-02-10 08:53:41 【问题描述】:

我想检查一下当您多次使用 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')
);

如您所见,每次渲染都会弹出一条提示“渲染”的提示。

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

【问题讨论】:

React 非常聪明,只有在需要渲染的状态发生变化时才会重新渲染。在您的渲染方法中,您只使用this.state.alex - 如果您添加一个也依赖于this.state.value 的元素会发生什么? @MartinWedvich 如果我依赖它,它会中断。为此,您可以使用“getInitialState”方法 - 设置默认值,这样您的应用就不会中断。 相关且有用:***.com/questions/48563650/… 【参考方案1】:

React 批处理发生在事件处理程序和生命周期方法中的状态更新。因此,如果您在 &lt;div onClick /&gt; 处理程序中多次更新状态,React 将在重新渲染之前等待事件处理完成。

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

【讨论】:

谢谢,有道理,知道它是如何在幕后完成的吗? 由于 React 完全控制合成事件处理程序(如 &lt;div onClick /&gt;)和组件生命周期方法,它知道它可以在调用批处理状态更新期间安全地更改 setState 的行为,并且等待冲洗。相比之下,在 AJAX 或 setTimeout 处理程序中,React 无法知道我们的处理程序何时完成执行。从技术上讲,React 在这两种情况下都会对状态更新进行排队,但会立即在 React 控制的处理程序之外刷新。 @neurosnap 我认为文档没有详细说明这一点。在State and Lifecycle section 和setState docs 中抽象地提到了它。见ReactDefaultBatchingStrategy的代码,这是目前官方唯一的批处理策略。 @BenjaminToueg 我相信您可以在 React 事件处理程序之外使用 ReactDOM.unstable_batchedUpdates(function) 批处理 setState。顾名思义,您的保修将失效。 总是很高兴推荐给这个人twitter.com/dan_abramov/status/887963264335872000?lang=en【参考方案2】:

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

例如,以下代码只会将 state value 属性增加 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>
   

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

//this.state.count is originally 0
this.setState(count:42, () => 
  console.log(this.state.count)
//outputs 42
)

setState(updater,[callback]) 方法可以接受一个更新函数作为它的第一个参数,以根据之前的状态和属性更新状态。 updater 函数的返回值将与之前的组件状态进行浅层合并。该方法异步更新状态,因此有一个选项回调,将在状态完全更新完成后调用。

例子:

this.setState((prevState, props) =>  
return attribute:"value"
)

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

    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>
     
  

【讨论】:

啊,我不知道setState(updater,[callback]),它就像一个不那么冗长的Object.assign,谢谢! @Biboswan,嗨,我是 React 新手,想问你,CompountDidMount 方法中的所有四个 setState 是否都已合并,并且只有最后一个 setState 将被执行,但其他 3 个将被执行忽略? 对我来说,关键是声明previousState 参数并在我的更新函数中使用它。 知道 React 如何决定是批量更新还是立即应用它?我说的是它在代码级别内部是如何做到这一点的。 @darKnight 它主要基于事件循环的概念,16ms 进入 1 帧(每秒 60 帧)。为了最好的讨论,我建议你在不和谐的 reactiflux 服务器的内部频道中提问。

以上是关于在 React 组件中多次使用 this.setState 会发生啥?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 React Native 的初始渲染中多次调用组件的 prop 方法?

React 组件表在更新状态后被多次渲染或复制

推送新 URL 时多次调用 React 组件渲染

React 路由组件多次调用函数

如何使用 react-hooks (useEffect) 缓冲流数据以便能够一次更新另一个组件以避免多次重新渲染?

在页面加载期间多次调用 React onChange 处理程序