(精华)2020年7月31日 React setstate原理详解
发布日期:2021-06-29 15:08:34
浏览次数:3
分类:技术文章
本文共 7903 字,大约阅读时间需要 26 分钟。
// partialState 部分stateReactComponent.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 batchedUpdateslet 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()); }}// 面向切片编程 AOPlet 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 ``; }}
转载地址:https://codeboy.blog.csdn.net/article/details/107704213 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
网站不错 人气很旺了 加油
[***.192.178.218]2024年04月15日 04时18分07秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
DRF框架---前言(简单使用)
2019-04-29
字符串外面是b“ “的转换 -亲测有效
2019-04-29
单通道和多通道卷积
2019-04-29
npy文件和pkl文件的保存和读取
2019-04-29
买卖股票的最佳时机
2019-04-29
AUC粗浅理解笔记记录
2019-04-29
torch 模型运行时间与forward没对应的可能原因
2019-04-29
JavaScript 的addEventListener() 事件监听详解!
2019-04-29
上传图片到阿里云OSS和获取上传图片的url的详解 !
2019-04-29
Kafka为什么这么快?
2019-04-29
Java 生产者和消费者面试题
2019-04-29
生产者消费者问题
2019-04-29
本机电脑连接虚拟机redis失败解决方法
2019-04-29
DM365 应用层gpio控制
2019-04-29
linux i2c子系统abc
2019-04-29
CSS3 帧动画(Sprite,直译叫雪碧图)
2019-04-29
Java 父线程与子线程相互通信的方法
2019-04-29
Redis 六种淘汰策略和三种删除策略
2019-04-29
Java LinkedHashMap
2019-04-29
JPA 多线程同时对一条数据进行Update的问题
2019-04-29