// partialState partialState
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);
}
// Update state via enqueueUpdate
function enqueueUpdate(component) {
ensureInjected();
// batchingStrategy Batch update strategy
// Whether isBatchingUpdates start with batch updates is false by default
if(! batchingStrategy.isBatchingUpdates) { batchingStrategy.batchedUpdates(enqueueUpdate, component);return;
}
// If isBatchingUpdates are true, state is not updated; instead, the component to be updated is added to the dirtyComponents array
dirtyComponents.push(component);
if (component._updateBatchNumber == null) {
component._updateBatchNumber = updateBatchNumber + 1; }}// _pendingStateQueue
// The updateComponent method is called
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); }}} {// Check whether the props and state of the component are changed.
// If the function shouldUpdateComponent returns false then the component update is not performed
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); }}}},// This method consolidates the states that need to be updated and adds them to the update queue
_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,
);
}
returnnextState; }};Copy the code
Analog implementation
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.// The default mode is non-batch update
dirtyComponents: [].// The state of the dirty component is different from that displayed on the interface
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);
}
// Convert a DOM template string into a real DOM element
createDOMFromDOMString() {
//this;
let htmlString = this.render();
let div = document.createElement('div');
div.innerHTML = htmlString;
this.domElement = div.children[0];
// Make the Component property of the BUTTONDOM node equal to the instance of the current Counter component
this.domElement.component = this;
//this.domElement.addEventListener('click',this.add.bind(this));
return this.domElement;
}
mount(container) {
container.appendChild(this.createDOMFromDOMString()); }}Slice-oriented programming AOP
let transaction = new Transaction([
{
initialize() {
batchingStrategy.isBatchingUpdates = true;// Start batch update mode
},
close() {
batchingStrategy.isBatchingUpdates = false;
batchingStrategy.batchedUpdates();// Perform batch updates to re-render all dirty components according to their state and properties}}]);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 &western nclick = "trigger (event, 'add')" >The ${this.props.name}:The ${this.state.number}
</button>`; }}Copy the code