前言
我们知道,setState是react的一步操作,每次调用setState都会触发更新,异步操作是为了提高性能,将多个状态合并一起更新,减少re-render调用。
试想如果组件内执行这样一段代码:
for ( let i = 0; i < 100; i++ ) {
this.setState( { num: this.state.num + 1 } );
}
那么执行这段代码会导致这个组件被重新渲染100次,这对性能是一个非常大的负担。(以下均为伪代码,react底层不会这么简单的)
真正的React是怎么做的
React显然也遇到了这样的问题,所以针对setState做了一些特别的优化:React会将多个setState的调用合并成一个来执行,这意味着当调用setState时,state并不会立即更新,举个栗子:
class App extends Component {
constructor() {
super();
this.state = {
num: 0
}
}
componentDidMount() {
for ( let i = 0; i < 100; i++ ) {
this.setState( { num: this.state.num + 1 } );
console.log( this.state.num ); // 会输出什么?
}
}
render() {
return (
<div className="App">
<h1>{ this.state.num }</h1>
</div>
);
}
}
我们定义了一个App组件,在组件挂载后,会循环100次,每次让this.state.num增加1,我们用真正的React来渲染这个组件,看看结果:
组件渲染的结果是1,并且在控制台中输出了100次0,说明每个循环中,拿到的state仍然是更新之前的。
这是React的优化手段,但是显然它也会在导致一些不符合直觉的问题(就如上面这个例子),所以针对这种情况,React给出了一种解决方案:setState接收的参数还可以是一个函数,在这个函数中可以拿先前的状态,并通过这个函数的返回值得到下一个状态。
我们可以通过这种方式来修正App组件:
componentDidMount() {
for ( let i = 0; i < 100; i++ ) {
this.setState( prevState => {
console.log( prevState.num );
return {
num: prevState.num + 1
}
} );
}
}
现在来看看App组件的渲染结果:

现在终于能得到我们想要的结果了。
setState核心实现原理
参考
1、对React setState的一些思考与心得:https://www.jianshu.com/p/b38a7a4eda2b
2、react setState核心实现原理:https://zhuanlan.zhihu.com/p/44537887
前言
我们知道,setState是react的一步操作,每次调用setState都会触发更新,异步操作是为了提高性能,将多个状态合并一起更新,减少re-render调用。
试想如果组件内执行这样一段代码:
那么执行这段代码会导致这个组件被重新渲染100次,这对性能是一个非常大的负担。(以下均为伪代码,react底层不会这么简单的)
真正的React是怎么做的
React显然也遇到了这样的问题,所以针对setState做了一些特别的优化:React会将多个setState的调用合并成一个来执行,这意味着当调用setState时,state并不会立即更新,举个栗子:
我们定义了一个App组件,在组件挂载后,会循环100次,每次让this.state.num增加1,我们用真正的React来渲染这个组件,看看结果:
组件渲染的结果是1,并且在控制台中输出了100次0,说明每个循环中,拿到的state仍然是更新之前的。
这是React的优化手段,但是显然它也会在导致一些不符合直觉的问题(就如上面这个例子),所以针对这种情况,React给出了一种解决方案:setState接收的参数还可以是一个函数,在这个函数中可以拿先前的状态,并通过这个函数的返回值得到下一个状态。
我们可以通过这种方式来修正App组件:
现在来看看App组件的渲染结果:

现在终于能得到我们想要的结果了。
setState核心实现原理
参考
1、对React setState的一些思考与心得:https://www.jianshu.com/p/b38a7a4eda2b
2、react setState核心实现原理:https://zhuanlan.zhihu.com/p/44537887