import { commitUpdate , removeChild , resetTextContent , UpdatePayload , } from '../react-dom/ReactDOMHostConfig' ; import { Container } from '../react-dom/ReactDomRoot' ; import { BeforeMutationMask , ChildDeletion , ContentReset , MutationMask , NoFlags , PassiveMask , Placement , Update , Passive , PlacementAndUpdate , LayoutMask , } from './ReactFiberFlags' ; import { FunctionComponentUpdateQueue } from './ReactFiberHooks' ; import { appendChild , appendChildToContainer , commitTextUpdate , insertBefore , insertInContainerBefore , } from './ReactFiberHostConfig' ; import { Lanes } from './ReactFiberLane' ; import { HookFlags , HasEffect as HookHasEffect , Passive as HookPassive , Layout as HookLayout , NoFlags as NoHookEffect , } from './ReactHookEffectTags' ; import { Fiber , FiberRoot } from './ReactInternalTypes' ; import { FunctionComponent , HostComponent , HostRoot , HostText , SimpleMemoComponent , } from './ReactWorkTags' ; let nextEffect = null ; const ensureCorrectReturnPointer = ( fiber , expectedReturnFiber ) : void => { fiber . return = expectedReturnFiber ; } ; const commitBeforeMutationEffects_begin = ( ) => { while ( nextEffect !== null ) { const fiber = nextEffect ; const child = fiber . child ; if ( ( fiber . subtreeFlags & BeforeMutationMask ) !== NoFlags && child !== null ) { ensureCorrectReturnPointer ( child , fiber ) ; nextEffect = child ; } else { commitBeforeMutationEffects_complete ( ) ; } } } ; const commitBeforeMutationEffects_complete = ( ) => { while ( nextEffect !== null ) { const fiber = nextEffect ; commitBeforeMutationEffectsOnFiber ( fiber ) ; const sibling = fiber . sibling ; if ( sibling !== null ) { nextEffect = sibling ; return ; } nextEffect = fiber . return ; } } ; export const commitPassiveUnmountEffects = ( firstChild ) : void => { nextEffect = firstChild ; commitPassiveUnmountEffects_begin ( ) ; } ; const commitPassiveUnmountInsideDeletedTreeOnFiber = ( current , nearestMountedAncestor ) : void => { switch ( current . tag ) { case FunctionComponent : commitHookEffectListUnmount ( HookPassive , current ) ; break ; default : break ; } } ; const detachFiberAfterEffects = ( fiber ) => { const alternate = fiber . alternate ; if ( alternate !== null ) { fiber . alternate = null ; detachFiberAfterEffects ( alternate ) ; } fiber . child = null ; fiber . deletions = null ; fiber . memoizedProps = null ; fiber . memoizedState = null ; fiber . pendingProps = null ; fiber . sibling = null ; fiber . stateNode = null ; fiber . updateQueue = null ; } ; const commitPassiveUnmountEffectsInsideOfDeletedTree_complete = ( deletedSubtreeRoot ) => { while ( nextEffect !== null ) { const fiber = nextEffect ; const sibling = fiber . sibling ; const returnFiber = fiber . return ; if ( fiber === deletedSubtreeRoot ) { detachFiberAfterEffects ( fiber ) ; nextEffect = null ; return ; } if ( sibling !== null ) { ensureCorrectReturnPointer ( sibling , returnFiber ! ) ; nextEffect = sibling ; return ; } nextEffect = returnFiber ; } } ; const commitPassiveUnmountEffectsInsideOfDeletedTree_begin = ( deletedSubtreeRoot , nearestMountedAncestor ) => { while ( nextEffect !== null ) { const fiber = nextEffect ; commitPassiveUnmountInsideDeletedTreeOnFiber ( fiber , nearestMountedAncestor ) ; const child = fiber . child ; if ( child !== null ) { ensureCorrectReturnPointer ( child , fiber ) ; nextEffect = child ; } else { commitPassiveUnmountEffectsInsideOfDeletedTree_complete ( deletedSubtreeRoot ) ; } } } ; const commitPassiveUnmountEffects_begin = ( ) => { while ( nextEffect !== null ) { const fiber = nextEffect ; const child = fiber . child ; if ( ( nextEffect . flags & ChildDeletion ) !== NoFlags ) { const deletions = fiber . deletions ; if ( deletions !== null ) { for ( let i = 0 ; i < deletions . length ; ++ i ) { const fiberToDelete = deletions [ i ] ; nextEffect = fiberToDelete ; commitPassiveUnmountEffectsInsideOfDeletedTree_begin ( fiberToDelete , fiber ) ; } const previousFiber = fiber . alternate ; if ( previousFiber !== null ) { let detachedChild = previousFiber . child ; if ( detachedChild !== null ) { previousFiber . child = null ; do { const detachedSibling = detachedChild . sibling ; detachedChild . sibling = null ; detachedChild = detachedSibling ; } while ( detachedChild !== null ) ; } } nextEffect = fiber ; } if ( ( fiber . subtreeFlags & PassiveMask ) !== NoFlags && child !== null ) { ensureCorrectReturnPointer ( child , fiber ) ; nextEffect = child ; } else { commitPassiveUnmountEffects_complete ( ) ; } } if ( ( fiber . subtreeFlags & PassiveMask ) !== NoFlags && child !== null ) { ensureCorrectReturnPointer ( child , fiber ) ; nextEffect = child ; } else { commitPassiveUnmountEffects_complete ( ) ; } } } ; const commitPassiveUnmountEffects_complete = ( ) => { while ( nextEffect !== null ) { const fiber = nextEffect ; if ( ( fiber . flags & Passive ) !== NoFlags ) { commitPassiveUnmountOnFiber ( fiber ) ; } const sibling = fiber . sibling ; if ( sibling !== null ) { ensureCorrectReturnPointer ( sibling , fiber . return ! ) ; nextEffect = sibling ; return ; } nextEffect = fiber . return ; } } ; const commitHookEffectListUnmount = ( flags , finishedWork ) => { const updateQueue = finishedWork . updateQueue as any ; const lastEffect = updateQueue !== null ? updateQueue . lastEffect : null ; if ( lastEffect !== null ) { const firstEffect = lastEffect . next ; let effect = firstEffect ; do { if ( ( effect . tag & flags ) === flags ) { const destroy = effect . destroy ; effect . destroy = undefined ; if ( destroy !== undefined ) { destroy ( ) ; } } effect = effect . next ; } while ( effect !== firstEffect ) ; } } ; const commitPassiveUnmountOnFiber = ( finishedWork ) : void => { switch ( finishedWork . tag ) { case FunctionComponent : case SimpleMemoComponent : { commitHookEffectListUnmount ( HookHasEffect | HookPassive , finishedWork ) ; break ; } default : { throw new Error ( 'Not Implement' ) ; } } } ; const commitHookEffectListMount = ( tag , finishedWork ) : void => { const updateQueue = finishedWork . updateQueue as any ; const lastEffect = updateQueue !== null ? updateQueue . lastEffect : null ; if ( lastEffect !== null ) { const firstEffect = lastEffect . next ; let effect = firstEffect ; do { if ( ( effect . tag & tag ) === tag ) { const create = effect . create ; effect . destroy = create ( ) ; } effect = effect . next ; } while ( effect !== firstEffect ) ; } } ; const commitPassiveMountOnFiber = ( finishedRoot , finishedWork ) : void => { switch ( finishedWork . tag ) { case FunctionComponent : case SimpleMemoComponent : { commitHookEffectListMount ( HookPassive | HookHasEffect , finishedWork ) ; break ; } default : { throw new Error ( 'Not Implement' ) ; } } } ; const commitPassiveMountEffects_complete = ( subtreeRoot , root ) => { while ( nextEffect !== null ) { const fiber = nextEffect ; if ( ( fiber . flags & Passive ) !== NoFlags ) { commitPassiveMountOnFiber ( root , fiber ) ; } if ( fiber === subtreeRoot ) { nextEffect = null ; return ; } const sibling = fiber . sibling ; if ( sibling !== null ) { ensureCorrectReturnPointer ( sibling , fiber . return ! ) ; nextEffect = sibling ; return ; } nextEffect = fiber . return ; } } ; const commitPassiveMountEffects_begin = ( subtreeRoot , root ) : void => { while ( nextEffect !== null ) { const fiber = nextEffect ; const firstChild = fiber . child ; if ( ( fiber . subtreeFlags & PassiveMask ) !== NoFlags && firstChild !== null ) { ensureCorrectReturnPointer ( firstChild , fiber ) ; nextEffect = firstChild ; } else { commitPassiveMountEffects_complete ( subtreeRoot , root ) ; } } } ; export const commitPassiveMountEffects = ( root , finishedWork ) : void => { nextEffect = finishedWork ; commitPassiveMountEffects_begin ( finishedWork , root ) ; } ; const commitBeforeMutationEffectsOnFiber = ( finishedWork ) : void => { const current = finishedWork . alternate ; const flags = finishedWork . flags ; } ; param root param firstChild export const commitBeforeMutationEffects = ( root , firstChild ) : void => { nextEffect = firstChild ; commitBeforeMutationEffects_begin ( ) ; } ; param root param firstChild export const commitMutationEffects = ( root , firstChild ) : void => { nextEffect = firstChild ; commitMutationEffects_begin ( root ) ; } ; param finishedRoot param current param nearestMountedAncestor returns const commitUnmount = ( finishedRoot , current , nearestMountedAncestor ) : void => { switch ( current . tag ) { case FunctionComponent : { const updateQueue = current . updateQueue as any ; if ( updateQueue !== null ) { const lastEffect = updateQueue . lastEffect ; if ( lastEffect !== null ) { const firstEffect = lastEffect . next ; let effect = firstEffect ; do { const { destroy , tag } = effect ; if ( destroy !== undefined ) { if ( ( tag & HookLayout ) !== NoHookEffect ) { destroy ( ) ; } } } while ( effect !== firstEffect ) ; } } return ; } case HostComponent : { return ; } case HostText : { break ; } default : throw new Error ( 'Not Implement' ) ; } } ; param finishedRoot param root param nearestMountedAncestor returns const commitNestedUnmounts = ( finishedRoot , root , nearestMountedAncestor ) => { let node = root ; while ( true ) { commitUnmount ( finishedRoot , node , nearestMountedAncestor ) ; if ( node . child !== null ) { node . child . return = node ; node = node . child ; continue ; } if ( node === root ) return ; while ( node . sibling === null ) { if ( node . return === null || node . return === root ) { return ; } node = node . return ; } node . sibling . return = node . return ; node = node . sibling ; } } ; param finishedRoot param current param nearestMountedAncestor returns const unmountHostComponents = ( finishedRoot , current , nearestMountedAncestor ) : void => { let node = current ; let currentParentIsValid = false ; let currentParent ; let currentParentIsContainer ; while ( true ) { if ( ! currentParentIsValid ) { /**
             * 这里的逻辑只会在第一轮循环时进来一次
             * 在这里找到该待删除的子树的最近的上层dom节点
             * 考虑以下例子
             * function ChildToDelete() {
             *    return <div>ChildToDelete</div>
             * }
             *
             * function Wrapper({children}) {
             *    return children
             * }
             *
             * function Foo() {
             *   const [isShow, setIsShow] = useState(true)
             *
             *   return <div id="container">
             *        <Wrapper>
             *          {isShow ? <ChildToDelete /> : null}
             *        </Wrapper>
             *        <button onClick={() => setIsShow(!isShow)}>toggle</button>
             *    </div>
             * }
             * 当点击toggle按钮时ChildToDelete函数组件会被删除,此时会沿着ChildToDelete
             * 对应的fiber节点向上查找一个HostComponent类型的节点,不难看出要找的就是那个
             * id为container的div节点而不是Wrapper，因为Wrapper只在React中存在
             * 实际上ChildTODelete子树里面的dom节点是挂载在$('#container')上的
             *
             */ let parent = node . return ; findParent : while ( true ) { const parentStateNode = parent ?. stateNode ; switch ( parent ?. tag ) { case HostComponent : currentParent = parentStateNode ; currentParentIsContainer = false ; break findParent ; case HostRoot : currentParent = parentStateNode . containerInfo ; currentParentIsContainer = true ; break findParent ; } parent = parent ! . return ; } currentParentIsValid = true ; } if ( node . tag === HostComponent || node . tag === HostText ) { commitNestedUnmounts ( finishedRoot , node , nearestMountedAncestor ) ; if ( currentParentIsContainer ) { throw new Error ( 'Not Implement' ) ; } else { removeChild ( currentParent , node . stateNode ) ; } } else { commitUnmount ( finishedRoot , node , nearestMountedAncestor ) ; if ( node . child !== null ) { node . child . return = node ; node = node . child ; continue ; } } if ( node === current ) return ; while ( node . sibling === null ) { if ( node . return === null || node . return === current ) return ; node = node . return ; } node . sibling . return = node . return ; node = node . sibling ; } } ; const detachFiberMutation = ( fiber ) => { const alternate = fiber . alternate ; if ( alternate !== null ) { alternate . return = null ; } fiber . return = null ; } ; const commitDeletion = ( finishedRoot , current , nearestMountedAncestor ) : void => { unmountHostComponents ( finishedRoot , current , nearestMountedAncestor ) ; detachFiberMutation ( current ) ; } ; const isHostParent = ( fiber ) : boolean => { return fiber . tag === HostComponent || fiber . tag === HostRoot ; } ; const getHostParentFiber = ( fiber ) : Fiber => { let parent = fiber . return ; while ( parent !== null ) { if ( isHostParent ( parent ) ) { return parent ; } parent = parent . return ; } throw new Error ( 'Expected to find a host parent' ) ; } ; param fiber returns const getHostSibling = ( fiber ) : Element | null => { let node = fiber ; siblings : while ( true ) { while ( node . sibling === null ) { if ( node . return === null || isHostParent ( node . return ) ) return null ; node = node . return ; } node . sibling . return = node . return ; node = node . sibling ; while ( node . tag !== HostComponent ) { if ( node . flags & Placement ) { continue siblings ; } if ( node . child === null ) { continue siblings ; } else { node . child . return = node ; node = node . child ; } } if ( ! ( node . flags & Placement ) ) { return node . stateNode ; } } } ; const insertOrAppendPlacementNode = ( node , before , parent ) : void => { const { tag } = node ; const isHost = tag === HostComponent || tag === HostText ; if ( isHost ) { const stateNode = isHost ? node . stateNode : node . stateNode . instance ; if ( before ) { insertBefore ( parent , stateNode , before ) ; } else { appendChild ( parent , stateNode ) ; } } else { const child = node . child ; if ( child !== null ) { insertOrAppendPlacementNode ( child , before , parent ) ; let sibling = child . sibling ; while ( sibling !== null ) { insertOrAppendPlacementNode ( sibling , before , parent ) ; sibling = sibling . sibling ; } } } } ; const insertOrAppendPlacementNodeIntoContainer = ( node , before , parent ) : void => { const { tag } = node ; const isHost = tag === HostComponent || tag === HostText ; if ( isHost ) { const stateNode = node . stateNode ; if ( before ) { insertInContainerBefore ( parent , stateNode , before ) ; } else { appendChildToContainer ( parent , stateNode ) ; } } else { const child = node . child ; if ( child !== null ) { insertOrAppendPlacementNodeIntoContainer ( child , before , parent ) ; let sibling = child . sibling ; while ( sibling !== null ) { insertOrAppendPlacementNodeIntoContainer ( sibling , before , parent ) ; sibling = sibling . sibling ; } } } } ; const commitPlacement = ( finishedWork ) : void => { const parentFiber = getHostParentFiber ( finishedWork ) ; let parent ; let isContainer ; const parentStateNode = parentFiber . stateNode ; switch ( parentFiber . tag ) { case HostComponent : parent = parentStateNode ; isContainer = false ; break ; case HostRoot : parent = parentStateNode . containerInfo ; isContainer = true ; break ; default : { throw new Error ( 'Invalid host parent fiber' ) ; } } if ( parentFiber . flags & ContentReset ) { resetTextContent ( parent ) ; parentFiber . flags &= ~ ContentReset ; } const before = getHostSibling ( finishedWork ) ; if ( isContainer ) { insertOrAppendPlacementNodeIntoContainer ( finishedWork , before , parent ) ; } else { insertOrAppendPlacementNode ( finishedWork , before , parent ) ; } } ; const commitLayoutEffectOnFiber = ( finishedRoot , current , finishedWork , committedLanes ) : void => { if ( ( finishedWork . flags & Update ) !== NoFlags ) { switch ( finishedWork . tag ) { case FunctionComponent : { commitHookEffectListMount ( HookLayout | HookHasEffect , finishedWork ) ; break ; } case HostComponent : { break ; } case HostText : { break ; } default : throw new Error ( 'Not Implement' ) ; } } } ; const commitLayoutMountEffects_complete = ( subtreeRoot , root , committedLanes ) => { while ( nextEffect !== null ) { const fiber = nextEffect ; if ( ( fiber . flags & LayoutMask ) !== NoFlags ) { const current = fiber . alternate ; commitLayoutEffectOnFiber ( root , current , fiber , committedLanes ) ; } if ( fiber === subtreeRoot ) { nextEffect = null ; return ; } const sibling = fiber . sibling ; if ( sibling !== null ) { ensureCorrectReturnPointer ( sibling , fiber . return as any ) ; nextEffect = sibling ; return ; } nextEffect = fiber . return ; } } ; const commitLayoutEffects_begin = ( subtreeRoot , root , committedLanes ) => { while ( nextEffect !== null ) { const fiber = nextEffect ; const firstChild = fiber . child ; if ( ( fiber . subtreeFlags & LayoutMask ) !== NoFlags && firstChild !== null ) { ensureCorrectReturnPointer ( firstChild , fiber ) ; nextEffect = firstChild ; } else { commitLayoutMountEffects_complete ( subtreeRoot , root , committedLanes ) ; } } } ; export const commitLayoutEffects = ( finishedWork , root ) : void => { nextEffect = finishedWork ; commitLayoutEffects_begin ( finishedWork , root , 0 ) ; } ; param current param finishedWork returns const commitWork = ( current , finishedWork ) : void => { switch ( finishedWork . tag ) { case FunctionComponent : commitHookEffectListUnmount ( HookLayout | HookHasEffect , finishedWork ) ; return ; case HostComponent : { const instance = finishedWork . stateNode ; if ( instance ) { const newProps = finishedWork . memoizedProps ; const oldProps = current !== null ? current . memoizedProps : newProps ; const type = finishedWork . type ; const updatePayload = finishedWork . updateQueue as any ; finishedWork . updateQueue = null ; if ( updatePayload !== null ) { commitUpdate ( instance , updatePayload , type , oldProps , newProps , finishedWork ) ; } } } case HostText : { const textInstance = finishedWork . stateNode ; const newText = finishedWork . memoizedProps ; const oldText = current !== null ? current . memoizedProps : newText ; commitTextUpdate ( textInstance , oldText , newText ) ; return ; } default : { throw new Error ( 'Not Implement' ) ; } } } ; const commitMutationEffectsOnFiber = ( finishedWork , root ) : void => { const flags = finishedWork . flags ; if ( flags & ContentReset ) { throw new Error ( 'Not Implement' ) ; } const primaryFlags = flags & ( Placement | Update ) ; switch ( primaryFlags ) { case Placement : { commitPlacement ( finishedWork ) ; finishedWork . flags &= ~ Placement ; break ; } case 0 : { break ; } case PlacementAndUpdate : { commitPlacement ( finishedWork ) ; finishedWork . flags &= ~ Placement ; const current = finishedWork . alternate ; commitWork ( current , finishedWork ) ; break ; } case Update : { const current = finishedWork . alternate ; commitWork ( current , finishedWork ) ; break ; } default : { throw new Error ( 'Not Implement' ) ; } } } ; const commitMutationEffects_complete = ( root ) => { while ( nextEffect !== null ) { const fiber = nextEffect ; commitMutationEffectsOnFiber ( fiber , root ) ; const sibling = fiber . sibling ; if ( sibling !== null ) { ensureCorrectReturnPointer ( sibling , fiber . return ! ) ; nextEffect = sibling ; return ; } nextEffect = fiber . return ; } } ; const commitMutationEffects_begin = ( root ) : void => { while ( nextEffect !== null ) { const fiber = nextEffect ; const deletions = fiber . deletions ; if ( deletions !== null ) { for ( let i = 0 ; i < deletions . length ; ++ i ) { const childToDelete = deletions [ i ] ; commitDeletion ( root , childToDelete , fiber ) ; } } const child = fiber . child ; if ( ( fiber . subtreeFlags & MutationMask ) !== NoFlags && child !== null ) { ensureCorrectReturnPointer ( child , fiber ) ; nextEffect = child ; } else { commitMutationEffects_complete ( root ) ; } } } ;