Intro
setState() enqueues changes to the component state and tells React that this component and its children need to be re-rendered with the updated state.
setState方法将组件状态的改变添加到队列中,同时通知React重新渲染该组件及其子组件。
React does not guarantee that the state changes are applied immediately.
React(在同调用场景中)无法确保状态是立即更新的。
features特点
批量更新:batchUpdate,调用多个setState会进行合并,放在一个队列中先保存起来,再一次执行状态合并:只能曾/改,不能删减异步执行:立刻执行,eg:setTiemout
- 如果不通过
setState改变的状态,不会引起组件的更新
state = { numer: 0 };
mergeAdd = () => {
this.setState({ number: this.state.number + 1 });
this.setState({ number: this.state.number + 1 });
this.setState({ number: this.state.number + 1 });
console.log(this.state.number);
// 打印0
// 三次调用的setState会放在队列中执行,且只有最后一个触发了state改变
// 此时 batchUpdate = true
}
asyncAdd = () => {
setTimeout(() => {
this.setState({ number: 1 });
this.setState({ number: 2 });
this.setState({ number: 3 });
console.log(this.state.number);
// 打印6
// 异步调用的时候,三个setState会依次立即触发,并不会放在队列中,延时触发
// 此时batchUpdate = false
})
}
调用方式
- 传入要改变的状态对象
this.setState({ number: this.state.stateProp + 1 })
- 传入两个回调函数,拿到上一次改变后的状态
this.setState( prevState => ({ stateProp: prevState.stateProp }), () => {/* to something... */} )
实现原理
class Component{
state = { number: 1, name: 'stella' };
updateQueue = [];
callbackQueue = [];
batchUpdate = false;
setState(partialState, callback) {
if (this.batchUpdate) { // 批量更新
this.updateQueue.push(partialState);
callback && this.callbackQueue.push(callback);
} else { // 异步更新状态时 立即更新
this.state = typeof partialState === 'function' ?
partialState(this.state) :
partialState;
}
}
flushUpdate() {
let state = this.state,;
for (let i = 0; i < this.updateQueue; i++){
let updateState = this.updateQueue[i];
let partialState = typeof updateState === 'function' ?
updateState(state) :
updateState;
state = { ...state, ...partialState }; // 状态合并
// 注意updateState()调用传参是当前state, 不能是this.state,
// 实现每一次调用setState都能拿到上一次传入的值
}
this.state = state;
this.callbackQueue.forEach(callback => callback());
this.batchUpdate = false; // 关闭批量更新模式
}
add() {
this.batchUpdate = true; // 开启批量更新模式
this.setState({ number: this.state.number + 1 });
this.setState(
prevState => ({ number: prevState.number + 1 }),
() => console.log(this.state)
);
this.flushUpdate();
}
}