setState是同步还是异步?
如果是正常情况下 也就是没有使用Concurrent组件到的情况下 react的更新是同步的 但是! 不会立即获取到最新的state的值 因为正常情况下 调用setState只是单纯的将你 传进来的新的状态 放入一条链表中 等这个事件执行完毕之后 会触发一个回调函数 这个函数中 才会真正地执行react的更新状态以及渲染的流程 并且 是以完全同步的方式进行的
当使用了Concurrent组件的时候 这种情况下 才是真正的异步更新模式 同样的 无法在事件中 立即获取到最新的状态 并且在执行react的更新和渲染的流程中 使用了真正的异步方式(postMessage) 这个才是真正的异步
简单实现 setState
流程如下
- 初始化创建Updater实例,挂载在组件的
$updater上, $updater 上有两个属性,一个是当前的组件, 一个是存放更新的state 数组pendingStates是一个数组; - react 的默认更新策略
isBatchingUpdates是false; - 当点击时间触发调用setState时,调用$updater 的addState 方法,
详情在Transaction.perform, - react 的更新策略是
isBatchingUpdates是否批量更新在点击变成true, - 然后执行点击事件,调用
$updater的addState方法,会将 更新的 state 方法 pendingStates 这个数组中, 判断此时的isBatchingUpdates的值, 当为true时,将当前组件放入dirtyCommpnents中,当事件执行完毕状态会被修改为false, 此时调用batchingStrategy.batchedUpdates方法, 主要是为了更新操作; 为fasle时直接调用组件的updateCommponent方法. - 事件方法执行完成之后,再将react 的更新策略是
isBatchingUpdates是否批量更新在点击变成false
class Transaction{// 交易 封装一下 事件处理是个合成事件
constructor(wrappers){
this.wrappers = wrappers;//{initialize,close}
}
perform(anyMethod){
this.wrappers.forEach(wrapper=>wrapper.initialize()); //处理事件之前先修改策略
anyMethod.call(); //执行事件
this.wrappers.forEach(wrapper=>wrapper.close()); // 处理完事件之后恢复策略
}
}
//batchingStrategy.isBatchingUpdates batchedUpdates
let batchingStrategy = { // 更新策略
isBatchingUpdates:false,//默认是非批量更新模式
dirtyComponents:[],// 脏组件 就组件的状态和界面上显示的不一样
batchedUpdates(){
console.log(1111111)
this.dirtyComponents.forEach(component=>component.updateComponent());
}
}
class Updater{ // 更新类 updater 起到调度作用
constructor(component){
this.component = component;
this.pendingStates = [];
}
addState(partcialState){
this.pendingStates.push(partcialState);
batchingStrategy.isBatchingUpdates
?batchingStrategy.dirtyComponents.push(this.component)
:this.component.updateComponent()
}
}
class Component{
constructor(props){
this.props = props;
this.$updater = new Updater(this);
}
setState(partcialState){
this.$updater.addState(partcialState);
}
updateComponent(){
this.$updater.pendingStates.forEach(partcialState=>Object.assign(this.state,partcialState));
this.$updater.pendingStates.length = 0;
let oldElement = this.domElement;
let newElement = this.createDOMFromDOMString();
oldElement.parentElement.replaceChild(newElement,oldElement);
}
//把一个DOM模板字符串转成真实的DOM元素
createDOMFromDOMString(){
//this;
let htmlString = this.render();
let div = document.createElement('div');
div.innerHTML = htmlString;
this.domElement = div.children[0];
//让这个BUTTONDOM节点的component属性等于当前Counter组建的实例
this.domElement.component = this;
//this.domElement.addEventListener('click',this.add.bind(this));
return this.domElement;
}
mount(container){
container.appendChild(this.createDOMFromDOMString());
}
}
let transaction = new Transaction([
{
initialize(){
batchingStrategy.isBatchingUpdates = true;//开始批量更新模式
},
close(){
batchingStrategy.isBatchingUpdates = false;
batchingStrategy.batchedUpdates();//进行批量更新,把所有的脏组件根据自己的状态和属性重新渲染
}
}
]);
window.trigger = function(event,method){
let component = event.target.component;//event.target=this.domElement
transaction.perform(component[method].bind(component));
}
class Counter extends Component{
constructor(props){
super(props);
this.state = {number:0}
}
add(){
this.setState({number:this.state.number+1});
console.log(this.state);//0
this.setState({number:this.state.number+1});
console.log(this.state);//0
setTimeout(()=>{
this.setState({number:this.state.number+1});
console.log(this.state);//2
this.setState({number:this.state.number+1});
console.log(this.state);//3
},1000);
}
render(){
return `<button onclick="trigger(event,'add')">
${this.props.name}:${this.state.number}
</button>`;
}
}