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
functionupdateWorkInProgressHook(): Hook{// 此函数用于 更新 和由 渲染阶段更新 触发的重新渲染。// 它假设有一个当前钩子可以克隆,或者有一个来自上一个渲染过程的正在进行的钩子可以用作基础。
let nextCurrentHook: null|Hook;if(currentHook===null){// 如果没有 例如这个hooks是组件内第一个hooks// 拿到currentconstcurrent=currentlyRenderingFiber.alternate;if(current!==null){// 更新阶段// 旧节点的memoizedState// wip.memoizedState已经被清空了,逻辑在renderWithHooksnextCurrentHook=current.memoizedState;}else{// 渲染阶段nextCurrentHook=null;}}else{// 说明不是第一次执行hook了,nextCurrentHook进一位nextCurrentHook=currentHook.next;}
let nextWorkInProgressHook: null|Hook;if(workInProgressHook===null){// workInProgress.memoizedState在函数组件每次渲染时都会被设置成null(在renderWithHooks中)// 同样说明这是第一次调用hooknextWorkInProgressHook=currentlyRenderingFiber.memoizedState;}else{// 说明hooks链表不为空,不是第一次执行hook了// nextWorkInProgressHook指向下一个hooknextWorkInProgressHook=workInProgressHook.next;}if(nextWorkInProgressHook!==null){// 说明已有hook链表,复用它,并且有下一个hook// 进一位,保证顺序workInProgressHook=nextWorkInProgressHook;nextWorkInProgressHook=workInProgressHook.next;// 更新currentHookcurrentHook=nextCurrentHook;}else{// 从currentHook克隆出一个if(nextCurrentHook===null){constcurrentFiber=currentlyRenderingFiber.alternate;if(currentFiber===null){// 在初始渲染时调用了更新阶段的hook。这可能是React中的一个错误。请提交问题。thrownewError("Update hook called on initial render. This is likely a bug in React. Please file an issue.");}else{// 渲染的hooks比上一次渲染时多。thrownewError("Rendered more hooks than during the previous render.");}}// 更新currentHookcurrentHook=nextCurrentHook;constnewHook: Hook={memoizedState: currentHook.memoizedState,baseState: currentHook.baseState,baseQueue: currentHook.baseQueue,queue: currentHook.queue,next: null,};if(workInProgressHook===null){// 更新当前fiber的memoizedState和当前hooks(workInProgressHook)currentlyRenderingFiber.memoizedState=workInProgressHook=newHook;}else{// 如果有就往后追加workInProgressHook=workInProgressHook.next=newHook;}}returnworkInProgressHook;}
如果两次 state 值一样,执行enqueueConcurrentHookUpdateAndEagerlyBailout,将 update 放进concurrentQueue并且将 update 排队,但是不调度更新
所以如果在上述例子里setCount(0)多次,并不会有任何重新渲染
requestUpdateLane
获取更新优先级
exportfunctionrequestUpdateLane(fiber: Fiber): Lane{// Special casesconstmode=fiber.mode;// 如果在并发模式下且disableLegacyMode为false,则返回SyncLane。if(!disableLegacyMode&&(mode&ConcurrentMode)===NoMode){return(SyncLane: Lane);}elseif((executionContext&RenderContext)!==NoContext&&workInProgressRootRenderLanes!==NoLanes){// 如果当前是渲染阶段的更新// 且workInProgressRootRenderLanes不为NoLanes,则返回当前渲染的lane中最高优先级。// This is a render phase update. These are not officially supported. The// old behavior is to give this the same "thread" (lanes) as// whatever is currently rendering. So if you call `setState` on a component// that happens later in the same render, it will flush. Ideally, we want to// remove the special case and treat them as if they came from an// interleaved event. Regardless, this pattern is not officially supported.// This behavior is only a fallback. The flag only exists until we can roll// out the setState warning, since existing code might accidentally rely on// the current behavior.returnpickArbitraryLane(workInProgressRootRenderLanes);}// transition相关 useTransition再将这部分consttransition=requestCurrentTransition();if(transition!==null){constactionScopeLane=peekEntangledActionLane();returnactionScopeLane!==NoLane
? // 我们在一个异步操作范围内。重复使用相同的laneactionScopeLane
: // 重新分配一个transition lanerequestTransitionLane(transition);}// resolveUpdatePriority会从事件中获取优先级returneventPriorityToLane(resolveUpdatePriority());}
useState
例子
mountState
mountStateImpl
mountWorkInProgressHook
总结
hook
对象,hook.queue
用来存储更新队列,dispatch
用来触发state
的更改和调度更新fiber.memoizedState
存放的是hook对象
,每个hook语句
都是一个hook
对象,通过执行顺序用next
链接hook.memoizedState
存放的是hook
相关的值,例如useState
的hook.memoizedState
是state
的值,useEffect
是effect
对象updateState / updateReducer
updateWorkInProgressHook
涉及到几个变量,说明一下
currentHook
和workInProgressHook
全局变量,分别代表新旧节点的当前hook
,在finishRenderingHooks
中都会被置为null
nextCurrentHook
和nextWorkInProgressHook
局部变量,分别代表新旧节点的下一个hook
总结
函数看着比较长,其实就做了一件事情,将旧节点的 hook 拷贝出来,组成 workInProgressHook 链表
updateReducerImpl
总结
函数比较长,但是主要的逻辑就是下面几步:
hook
中获取当前任务队列(queue.pending
),从hook
中获取上一次更新的任务队列(baseQueue
)baseQueue
!==null),将queue.pending
挂在baseQueue
之后,renderLanes
中来判断是否需要跳过当前更新,update
clone
出一个 update,放进newBaseQueue
中newBaseQueue
中没有任务,则计算newState
newBaseQueue
中有任务,也就是前面有低优先级的任务跳过了,那么这个本不该跳过的任务,将会被clone
出一个update
,这个update
的 lane 被赋值为NoLane
,保证下次一定不会跳过。update
的顺序,保证state
的正确性state
是否相等,如果不相等则didReceiveUpdate = true
表示有更新,如果是个Promise
则将它抛出didReceiveUpdate
会在updateComponents
结尾判断,如果是false
就会命中bailout
策略,如果子节点也没有任务,直接终止。state
dispatchSetState
总结
dispatchSetState
比较好理解,就是创建一个 update,然后将 update 放进concurrentQueue
,然后调度一个更新enqueueConcurrentHookUpdateAndEagerlyBailout
,将 update 放进concurrentQueue
并且将 update 排队,但是不调度更新setCount(0)
多次,并不会有任何重新渲染requestUpdateLane
resolveUpdatePriority
首先会去ReactDOMSharedInternals.p
中获取优先级,React
会监听原生事件,当事件触发时会通过不同事件给ReactDOMSharedInternals.p
赋值不同优先级The text was updated successfully, but these errors were encountered: