在 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 批处理发生在事件处理程序和生命周期方法中的状态更新。因此,如果您在 <div onClick />
处理程序中多次更新状态,React 将在重新渲染之前等待事件处理完成。
需要明确的是,这只适用于 React 控制的合成事件处理程序和生命周期方法。例如,状态更新不会在 AJAX 和 setTimeout
事件处理程序中进行批处理。
【讨论】:
谢谢,有道理,知道它是如何在幕后完成的吗? 由于 React 完全控制合成事件处理程序(如<div onClick />
)和组件生命周期方法,它知道它可以在调用批处理状态更新期间安全地更改 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 方法?