- React更新状态(state)的顺序与 setState的调用顺序是一致的,不管是在同一个组件(见代码段1)还是在不同的组件中(见代码段2),所以在代码段1和代码段2中不会出现 {a: false, b: true} 这种情况。也不论是否 setState 是否处于批处理(batch)中。
// 代码段1
class Container extends React.Component {
constructor(props) {
super(props);
this.state = { a: false, b: false };
}
render() {
return <Button onClick={this.handleClick}/>
}
handleClick = () => {
this.setState({ a: true });
this.setState({ b: true });
}
}
//代码段2
class SuperContainer extends React.Component {
constructor(props) {
super(props);
this.state = { a: false };
}
render() {
return <Container setParentState={this.setState.bind(this)}/>
}
}
class Container extends React.Component {
constructor(props) {
super(props);
this.state = { b: false };
}
render() {
return <Button onClick={this.handleClick}/>
}
handleClick = () => {
this.props.setParentState({ a: true });
this.setState({ b: true });
}
}
- 状态(state)更新的中间状态是否可见取决于 setState 是否处于批处理中。
React 16 及更早版本中, 只有 React 事件处理器(event handler)中的更新默认是批处理的。其他更新可通过React 目前提供的 ReactDOM.unstable_batchedUpdates API 来手动设置批处理。
因此如果 setState 在事件处理器之外,例如在 AJAX 请求的回调中,每个 setState 都会立即被处理(即 按照该 setState 指定内容去更新状态,然后立即进行重新渲染 re-render,而不再是批处理中将几个 setState 合并后只进行一次重新渲染)。
具体参考如下代码段,据 Dan Abramov 老哥说,React 在未来的 17 版本将会统一将 setState 默认批处理,无论其是否在事件处理器中,这样对多数应用情况而言更方便。(未来版本可能不再提供 unstable_batchedUpdates,其命名前缀也反映了这一点)。
promise.then(() => {
// 不在事件处理器中,因此重渲染独立进行
this.setState({a: true}); // Re-renders with {a: true, b: false }
this.setState({b: true}); // Re-renders with {a: true, b: true }
this.props.setParentState(); // Re-renders the parent
});
promise.then(() => {
// 强制批处理
ReactDOM.unstable_batchedUpdates(() => {
this.setState({a: true}); // Doesn't re-render yet
this.setState({b: true}); // Doesn't re-render yet
this.props.setParentState(); // Doesn't re-render yet
});
// 当退出 unstable_batchedUpdates 的时候,只进行一次 re-renders
});
- 猴子都知道 setState 是异步的,至少在效果上是这样,究其原因,look here
)