(精华)2020年7月31日 React setstate原理详解
发布日期:2021-06-29 15:08:34
浏览次数:2
分类:技术文章
本文共 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 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
感谢大佬
[***.8.128.20]2024年04月13日 16时38分19秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
C++ inline 内联函数
2021-07-02
动态规划问题汇总
2021-07-02
C++ 面向对象程序设计:数据抽象、继承、多态
2021-07-02
Ubuntu软件安装&卸载
2021-07-02
Windows+Ubuntu双系统卸载 || 重新安装Ubuntu
2021-07-02
C++ Makefile / Cmake 构建工程 & GDB调试
2021-07-02
Ubuntu常用命令
2021-07-02
使用Opencv3运行Opencv2开发的程序遇到的bug
2021-07-02
Pytorch1.1版本pytorch模型转onnx的bug
2021-07-02
面试笔试易错知识点Java篇八
2021-07-02
逆波兰计算器
2021-07-02
简单数组对数器的实现
2021-07-02
百度搜索の黑话大全—那些不为人知的搜索引擎语法
2021-07-02
前任3:由圣经故事通天塔想到公司部门间沟通协作
2021-07-02
持续集成(持续构建)服务器luntbuild的一些配置细节
2021-07-02
数据库Scheme的版本控制——DB Migrations
2021-07-02
弹性事务框架ETF4J——面向Java微服务的交易最终一致性解决方案
2021-07-02
实时音视频聊天中超低延迟架构的思考与技术实践
2021-07-02
【Scala 教程】Scala 条件与循环语句
2021-07-02