当前位置: 首页 > Web前端 > JavaScript

ReactHooks本质探索-useMemo,useEffect源码分析

时间:2023-03-27 01:09:12 JavaScript

useRef和useCallback是最容易理解的两个native用法:ReactHooks本质探索-ReactHooks源码详解探索本质ofreacthooks——useCallback源码分析都涉及到ReactCurrentDispatcher$1对象。这个对象到底是什么意思?详情看这里:(编辑)我们直接看useMemo和useEffect的源码:useMemo:function(create,deps){currentHookNameInDev='useMemo';//详情见ReactCurrentDispatchermountHookTypesDev();//很简单的函数:使用来确认deps是否为数组,如果不是则抛出错误checkDepsAreArrayDev(deps);//更新dispatch,详见ReactCurrentDispatcher//写到这里是怕create方法中使用use类的方法,这样会执行InvalidNestedhook方法。varprevDispatcher=ReactCurrentDispatcher$1.current;ReactCurrentDispatcher$1.current=InvalidNestedHooksDispatcherOnMountInDEV;尝试{returnmountMemo(create,deps);}最后{ReactCurrentDispatcher$1.current=prevDispatcher;}},useEffect:function(create,deps){currentHookNameInDev='useEffect';//详情见ReactCurrentDispatchermountHookTypesDev();//很简单的函数:用于确认deps是否为数组,如果不是则抛出错误checkDepsAreArrayDev(deps);returnmountEffect(create,deps);},两者唯一不同的是ReactCurrentDispatcher$1部分。为什么会有这种区别?因为useMemo是在渲染的时候执行的,而useEffect是在渲染之后执行的。基于这个区别,我们可以合理猜测只要ReactCurrentDispatcher$1部分有use,渲染时就会执行。只有这些使用在渲染中被执行:useMemo、useReducer、useState。接下来看mount和update时useMemo的源码(在源码中,这两个函数是连在一起的):varnextDeps=deps===未定义?空:部门;//nextCreate是我们在创建useMemo时传入的函数。varnextValue=nextCreate();//存储在钩子中,使用hook.memoizedState=[nextValue,nextDeps];returnnextValue;}functionupdateMemo(nextCreate,deps){varhook=updateWorkInProgressHook();varnextDeps=deps===未定义?空:部门;varprevState=hook.memoizedState;if(prevState!==null){//假设这些都已定义。如果不是,areHookInputsEqual将发出警告。if(nextDeps!==null){varprevDeps=prevState[1];//判断deps的值是否与上一个相同,如果相同则直接返回上一个值if(areHookInputsEqual(nextDeps,prevDeps)){returnprevState[0];}}}//这里一开始就是判断deps值不一样的情况。//包括前一个值或当前值为null的情况也被认为是不同的。varnextValue=nextCreate();hook.memoizedState=[nextValue,nextDeps];returnnextValue;}updateMemo函数的结构和useCallback的update非常相似:reacthooks本质探索-useCallback源码分析接下来看useEffect的挂载和更新:functionmountEffect(create,deps){{//这部分只跟jest有关,好像跟fiber有关,反正无所谓。//$FlowExpectedError-jest不是全局的,在测试之外无法识别if('undefined'!==typeofjest){warnIfNotCurrentlyActingEffectsInDEV(currentlyRenderingFiber$1);}}returnmountEffectImpl(Update|Passive,Passive$1,create,deps);}functionupdateEffect(create,deps){{//$FlowExpectedError-jest不是全局的,在测试之外无法识别if('undefined'!==typeofjest){warnIfNotCurrentlyActingEffectsInDEV(currentlyRenderingFiber$1);}}returnupdateEffectImpl(Update|Passive,Passive$1,create,deps);}关键是mountEffectImpl和updateEffectImpl:functionmountEffectImpl(fiberFlags,hookFlags,create,deps){varhook=mountWorkInProgressHook();varnextDeps=deps===未定义?空:部门;currentlyRenderingFiber$1.flags|=fiberFlags;//pushEffect应该是把当前effect放到一个漂染队中hook.memoizedState=pushEffect(HasEffect|hookFlags,create,undefined,nextDeps);}functionupdateEffectImpl(fiberFlags,hookFlags,create,deps){varhook=updateWorkInProgressHook();varnextDeps=deps===未定义?空:部门;vardestroy=undefined;if(currentHook!==null){varprevEffect=currentHook。记忆状态;destroy=prevEffect.destroy;if(nextDeps!==null){varprevDeps=prevEffect.deps;如果(areHookInputsEqual(nextDeps,prevDeps)){pushEffect(hookFlags,create,destroy,nextDeps);返回;}}}currentlyRenderingFiber$1.flags|=fiberFlags;hook.memoizedState=pushEffect(HasEffect|hookFlags,create,destroy,nextDeps);}这部分就不详细解释了,因为涉及的东西比较多,也简单理解,就是push到一个renderingqueue中,到外面render周期的