先上张图
代码
// partialState 部分state
ReactComponent.prototype.setState = function (partialState, callback) {
invariant(
typeof partialState === 'object' ||
typeof partialState === 'function' ||
partialState == null,
'setState(...): takes an object of state variables to update or a ' +
'function which returns an object of state variables.',
);
this.updater.enqueueSetState(this, partialState);
if (callback) {
this.updater.enqueueCallback(this, callback, 'setState');
}
};
enqueueSetState: function (publicInstance, partialState) {
if (__DEV__) {
ReactInstrumentation.debugTool.onSetState();
warning(
partialState != null,
'setState(...): You passed an undefined or null state object; ' +
'instead, use forceUpdate().',
);
}
var internalInstance = getInternalInstanceReadyForUpdate(
publicInstance,
'setState',
);
if (!internalInstance) {
return;
}
var queue =
internalInstance._pendingStateQueue ||
(internalInstance._pendingStateQueue = []);
queue.push(partialState);
enqueueUpdate(internalInstance);
}
// 通过enqueueUpdate执行state的更新
function enqueueUpdate(component) {
ensureInjected();
// batchingStrategy批量更新的策略
// isBatchingUpdates是否处于批量更新 最开始是默认false
if (!batchingStrategy.isBatchingUpdates) {
batchingStrategy.batchedUpdates(enqueueUpdate, component);
return;
}
// 如果isBatchingUpdates为true的话 不进行state的更新操作 而是将需要更新的component添加到dirtyComponents数组中去
dirtyComponents.push(component);
if (component._updateBatchNumber == null) {
component._updateBatchNumber = updateBatchNumber + 1;
}
}
// _pendingStateQueue
// 会调用updateComponent方法
performUpdateIfNecessary: function (transaction) {
if (this._pendingElement != null) {
ReactReconciler.receiveComponent(
this,
this._pendingElement,
transaction,
this._context,
);
} else if (this._pendingStateQueue !== null || this._pendingForceUpdate) {
this.updateComponent(
transaction,
this._currentElement,
this._currentElement,
this._context,
this._context,
);
} else {
this._updateBatchNumber = null;
}
}
if (!batchingStrategy.isBatchingUpdates) {
batchingStrategy.batchedUpdates(enqueueUpdate, component);
return;
}
dirtyComponents.push(component);
if (component._updateBatchNumber == null) {
component._updateBatchNumber = updateBatchNumber + 1;
}
var ReactDefaultBatchingStrategy = {
isBatchingUpdates: false,
batchedUpdates: function (callback, a, b, c, d, e) {
var alreadyBatchingUpdates = ReactDefaultBatchingStrategy.isBatchingUpdates;
ReactDefaultBatchingStrategy.isBatchingUpdates = true;
if (alreadyBatchingUpdates) {
return callback(a, b, c, d, e);
} else {
return transaction.perform(callback, null, a, b, c, d, e);
}
}
}
{ // 会检测组件中的state和props是否发生变化,有变化才会进行更新;
// 如果shouldUpdateComponent函数中返回false则不会执行组件的更新
updateComponent: function (transaction,
prevParentElement,
nextParentElement,
prevUnmaskedContext,
nextUnmaskedContext, ) {
var inst = this._instance;
var nextState = this._processPendingState(nextProps, nextContext);
var shouldUpdate = true;
if (!this._pendingForceUpdate) {
if (inst.shouldComponentUpdate) {
if (__DEV__) {
shouldUpdate = measureLifeCyclePerf(
() => inst.shouldComponentUpdate(nextProps, nextState, nextContext),
this._debugID,
'shouldComponentUpdate',
);
} else {
shouldUpdate = inst.shouldComponentUpdate(
nextProps,
nextState,
nextContext,
);
}
} else {
if (this._compositeType === CompositeTypes.PureClass) {
shouldUpdate = !shallowEqual(prevProps, nextProps) ||
!shallowEqual(inst.state, nextState);
}
}
}
},
// 该方法会合并需要更新的state,然后加入到更新队列中
_processPendingState: function (props, context) {
var inst = this._instance;
var queue = this._pendingStateQueue;
var replace = this._pendingReplaceState;
this._pendingReplaceState = false;
this._pendingStateQueue = null;
if (!queue) {
return inst.state;
}
if (replace && queue.length === 1) {
return queue[0];
}
var nextState = Object.assign({}, replace ? queue[0] : inst.state);
for (var i = replace ? 1 : 0; i < queue.length; i++) {
var partial = queue[i];
Object.assign(
nextState,
typeof partial === 'function' ?
partial.call(inst, nextState, props, context) :
partial,
);
}
return nextState;
}
};
模拟实现
class Transaction {
constructor(wrappers) {
this.wrappers = wrappers;//{initialize,close}
}
perform(anyMethod) {
console.log("this.wrappers:", this.wrappers);
this.wrappers.forEach(wrapper => wrapper.initialize());
anyMethod.call();
this.wrappers.forEach(wrapper => wrapper.close());
}
}
//batchingStrategy.isBatchingUpdates batchedUpdates
let batchingStrategy = {
isBatchingUpdates: false,//默认是非批量更新模式
dirtyComponents: [],// 脏组件 就组件的状态和界面上显示的不一样
batchedUpdates() {
this.dirtyComponents.forEach(component => component.updateComponent());
}
}
class 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());
}
}
// 面向切片编程 AOP
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 + 2 });
console.log(this.state);//0
setTimeout(() => {
this.setState({ number: this.state.number + 3 });
console.log(this.state);//5
this.setState({ number: this.state.number + 4 });
console.log(this.state);//9
}, 1000);
}
render() {
return `<button οnclick="trigger(event,'add')">
${this.props.name}:${this.state.number}
</button>`;
}
}