You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Component.prototype.setState=function(partialState,callback){!(typeofpartialState==='object'||typeofpartialState==='function'||partialState==null) ? invariant(false,'setState(...): takes an object of state variables to update or a function which returns an object of state variables.') : void0;this.updater.enqueueSetState(this,partialState,callback,'setState');};
functionwarnNoop(publicInstance,callerName){{// 实例的构造体var_constructor=publicInstance.constructor;varcomponentName=_constructor&&(_constructor.displayName||_constructor.name)||'ReactClass';// 组成一个key 组件名称+方法名(列如setState)varwarningKey=componentName+'.'+callerName;// 如果已经输出过警告了就不会再输出if(didWarnStateUpdateForUnmountedComponent[warningKey]){return;}// 在开发者工具的终端里输出警告日志 不能直接使用 component.setState来调用 warningWithoutStack$1(false,"Can't call %s on a component that is not yet mounted. "+'This is a no-op, but it might indicate a bug in your application. '+'Instead, assign to `this.state` directly or define a `state = {};` '+'class property with the desired state in the %s component.',callerName,componentName);didWarnStateUpdateForUnmountedComponent[warningKey]=true;}}
functionComponent(props,context,updater){this.props=props;this.context=context;// If a component has string refs, we will assign a different object later.this.refs=emptyObject;// We initialize the default updater but the real one gets injected by the// renderer.this.updater=updater||ReactNoopUpdateQueue;}
functionrequestWork(root,expirationTime){// 将需要渲染的root进行记录addRootToSchedule(root,expirationTime);if(isRendering){// Prevent reentrancy. Remaining work will be scheduled at the end of// the currently rendering batch.return;}if(isBatchingUpdates){// Flush work at the end of the batch.if(isUnbatchingUpdates){// ...unless we're inside unbatchedUpdates, in which case we should// flush it now.nextFlushedRoot=root;nextFlushedExpirationTime=Sync;performWorkOnRoot(root,Sync,true);}// 执行到这边直接return,此时setState()这个过程已经结束return;}// TODO: Get rid of Sync and use current time?if(expirationTime===Sync){performSyncWork();}else{scheduleCallbackWithExpirationTime(root,expirationTime);}}
functionapplyDerivedStateFromProps(workInProgress,ctor,getDerivedStateFromProps,nextProps){varprevState=workInProgress.memoizedState;{if(debugRenderPhaseSideEffects||debugRenderPhaseSideEffectsForStrictMode&&workInProgress.mode&StrictMode){// Invoke the function an extra time to help detect side-effects.getDerivedStateFromProps(nextProps,prevState);}}// 获取改变的statevarpartialState=getDerivedStateFromProps(nextProps,prevState);{// 对一些错误格式进行警告warnOnUndefinedDerivedState(ctor,partialState);}// Merge the partial state and the previous state.// 判断getDerivedStateFromProps返回的格式是否为空,如果不为空则将由原的state和它的返回值合并varmemoizedState=partialState===null||partialState===undefined ? prevState : _assign({},prevState,partialState);// 设置state// 一旦更新队列为空,将派生状态保留在基础状态当中workInProgress.memoizedState=memoizedState;// Once the update queue is empty, persist the derived state onto the// base state.varupdateQueue=workInProgress.updateQueue;if(updateQueue!==null&&workInProgress.expirationTime===NoWork){updateQueue.baseState=memoizedState;}}
/** * Attempt to create an observer instance for a value, * returns the new observer if successfully observed, * or the existing observer if the value already has one. */
export functionobserve(value: any,asRootData: ?boolean): Observer|void{if(!isObject(value)||valueinstanceofVNode){
return
}letob: Observer|voidif(hasOwn(value,'__ob__')&&value.__ob__instanceofObserver){ob=value.__ob__}elseif(shouldObserve&&!isServerRendering()&&(Array.isArray(value)||isPlainObject(value))&&Object.isExtensible(value)&&!value._isVue){// 创建observerob=newObserver(value)}if(asRootData&&ob){ob.vmCount++}returnob}
/*** Walk through each property and convert them into* getter/setters. This method should only be called when* value type is Object.*/walk(obj: Object){constkeys=Object.keys(obj)for(leti=0;i<keys.length;i++){defineReactive(obj,keys[i])}}
React 中
本地调试React代码的方法
yarn build
场景
假设有这样一个场景,父组件传递子组件一个A参数,子组件需要监听A参数的变化转换为state。
16之前
在React以前我们可以使用
componentWillReveiveProps
来监听props
的变换16之后
在最新版本的React中可以使用新出的
getDerivedStateFromProps
进行props的监听,getDerivedStateFromProps
可以返回null
或者一个对象,如果是对象,则会更新state
getDerivedStateFromProps触发条件
我们的目标就是找到
getDerivedStateFromProps
的 触发条件我们知道,只要调用
setState
就会触发getDerivedStateFromProps
,并且props
的值相同,也会触发getDerivedStateFromProps
(16.3版本之后)setState
在react.development.js
当中执行的是一个警告方法
看来
ReactNoopUpdateQueue
是一个抽象类,实际的方法并不是在这里实现的,同时我们看下最初updater
赋值的地方,初始化Component
时,会传入实际的updater
我们在组件的构造方法当中将
this
进行打印方法指向的是,在
react-dom.development.js
的classComponentUpdater
enqueueUpdate
就是将更新任务加入队列当中
我们看scheduleWork下
太过复杂,一些方法其实还没有看懂,但是根据断点可以把执行顺序先理一下,在
setState
之后会执行performSyncWork
,随后是如下的一个执行顺序performSyncWork => performWorkOnRoot => renderRoot => workLoop => performUnitOfWork => beginWork => applyDerivedStateFromProps
最终方法是执行
Vue
vue监听变量变化依靠的是
watch
,因此我们先从源码中看看,watch
是在哪里触发的。Watch触发条件
在
src/core/instance
中有initState()
/core/instance/state.js
在数据初始化时
initData()
,会将每vue的data注册到objerserver
中来看下
observer
的构造方法,不管是array还是obj,他们最终都会调用的是this.walk()
我们再来看下walk方法,walk方法就是将object中的执行
defineReactive()
方法,而这个方法实际就是改写set
和get
方法/core/observer/index.js
defineReactive
方法最为核心,它将set和get方法改写,如果我们重新对变量进行赋值,那么会判断变量的新值是否等于旧值,如果不相等,则会触发dep.notify()
从而回调watch中的方法。小程序
自定义Watch
小程序的data本身是不支持watch的,但是我们可以自行添加,我们参照
Vue
的写法自己写一个。watcher.js
使用
我们在执行watch回调前没有对新老赋值进行比较,原因是微信当中对data中的变量赋值,即使给引用变量赋值还是相同的值,也会因为引用地址不同,判断不相等。如果想对新老值进行比较就不能使用
===
,可以先对obj或者array转换为json字符串再比较。参考
广而告之
本文发布于薄荷前端周刊,欢迎Watch & Star ★,转载请注明出处。
欢迎讨论,点个赞再走吧 。◕‿◕。 ~
The text was updated successfully, but these errors were encountered: