Best JavaScript code snippet using playwright-internal
ReactFiberCommitWork.new.js
Source:ReactFiberCommitWork.new.js
...191 instance,192 );193 if (hasCaughtError()) {194 const unmountError = clearCaughtError();195 captureCommitPhaseError(current, nearestMountedAncestor, unmountError);196 }197 } else {198 try {199 callComponentWillUnmountWithTimer(current, instance);200 } catch (unmountError) {201 captureCommitPhaseError(current, nearestMountedAncestor, unmountError);202 }203 }204}205/** @noinline */206function safelyDetachRef(current: Fiber, nearestMountedAncestor: Fiber) {207 const ref = current.ref;208 if (ref !== null) {209 if (typeof ref === 'function') {210 if (__DEV__) {211 if (212 enableProfilerTimer &&213 enableProfilerCommitHooks &&214 current.mode & ProfileMode215 ) {216 startLayoutEffectTimer();217 invokeGuardedCallback(null, ref, null, null);218 recordLayoutEffectDuration(current);219 } else {220 invokeGuardedCallback(null, ref, null, null);221 }222 if (hasCaughtError()) {223 const refError = clearCaughtError();224 captureCommitPhaseError(current, nearestMountedAncestor, refError);225 }226 } else {227 try {228 if (229 enableProfilerTimer &&230 enableProfilerCommitHooks &&231 current.mode & ProfileMode232 ) {233 try {234 startLayoutEffectTimer();235 ref(null);236 } finally {237 recordLayoutEffectDuration(current);238 }239 } else {240 ref(null);241 }242 } catch (refError) {243 captureCommitPhaseError(current, nearestMountedAncestor, refError);244 }245 }246 } else {247 ref.current = null;248 }249 }250}251export function safelyCallDestroy(252 current: Fiber,253 nearestMountedAncestor: Fiber | null,254 destroy: () => void,255) {256 if (__DEV__) {257 invokeGuardedCallback(null, destroy, null);258 if (hasCaughtError()) {259 const error = clearCaughtError();260 captureCommitPhaseError(current, nearestMountedAncestor, error);261 }262 } else {263 try {264 destroy();265 } catch (error) {266 captureCommitPhaseError(current, nearestMountedAncestor, error);267 }268 }269}270/** @noinline */271function commitHookEffectListUnmount(272 flags: HookFlags,273 finishedWork: Fiber,274 nearestMountedAncestor: Fiber | null,275) {276 const updateQueue: FunctionComponentUpdateQueue | null = (finishedWork.updateQueue: any);277 const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;278 if (lastEffect !== null) {279 const firstEffect = lastEffect.next;280 let effect = firstEffect;281 do {282 if ((effect.tag & flags) === flags) {283 // Unmount284 const destroy = effect.destroy;285 effect.destroy = undefined;286 if (destroy !== undefined) {287 safelyCallDestroy(finishedWork, nearestMountedAncestor, destroy);288 }289 }290 effect = effect.next;291 } while (effect !== firstEffect);292 }293}294/** @noinline */295function commitHookEffectListMount(flags: HookFlags, finishedWork: Fiber) {296 const updateQueue: FunctionComponentUpdateQueue | null = (finishedWork.updateQueue: any);297 const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;298 if (lastEffect !== null) {299 const firstEffect = lastEffect.next;300 let effect = firstEffect;301 do {302 if ((effect.tag & flags) === flags) {303 // Mount304 const create = effect.create;305 effect.destroy = create();306 if (__DEV__) {307 const destroy = effect.destroy;308 if (destroy !== undefined && typeof destroy !== 'function') {309 let addendum;310 if (destroy === null) {311 addendum =312 ' You returned null. If your effect does not require clean ' +313 'up, return undefined (or nothing).';314 } else if (typeof destroy.then === 'function') {315 addendum =316 '\n\nIt looks like you wrote useEffect(async () => ...) or returned a Promise. ' +317 'Instead, write the async function inside your effect ' +318 'and call it immediately:\n\n' +319 'useEffect(() => {\n' +320 ' async function fetchData() {\n' +321 ' // You can await here\n' +322 ' const response = await MyAPI.getData(someId);\n' +323 ' // ...\n' +324 ' }\n' +325 ' fetchData();\n' +326 `}, [someId]); // Or [] if effect doesn't need props or state\n\n` +327 'Learn more about data fetching with Hooks: https://reactjs.org/link/hooks-data-fetching';328 } else {329 addendum = ' You returned: ' + destroy;330 }331 console.error(332 'An effect function must not return anything besides a function, ' +333 'which is used for clean-up.%s',334 addendum,335 );336 }337 }338 }339 effect = effect.next;340 } while (effect !== firstEffect);341 }342}343function commitProfilerPassiveEffect(344 finishedRoot: FiberRoot,345 finishedWork: Fiber,346): void {347 if (enableProfilerTimer && enableProfilerCommitHooks) {348 switch (finishedWork.tag) {349 case Profiler: {350 const {passiveEffectDuration} = finishedWork.stateNode;351 const {id, onPostCommit} = finishedWork.memoizedProps;352 // This value will still reflect the previous commit phase.353 // It does not get reset until the start of the next commit phase.354 const commitTime = getCommitTime();355 if (typeof onPostCommit === 'function') {356 if (enableSchedulerTracing) {357 onPostCommit(358 id,359 finishedWork.alternate === null ? 'mount' : 'update',360 passiveEffectDuration,361 commitTime,362 finishedRoot.memoizedInteractions,363 );364 } else {365 onPostCommit(366 id,367 finishedWork.alternate === null ? 'mount' : 'update',368 passiveEffectDuration,369 commitTime,370 );371 }372 }373 break;374 }375 default:376 break;377 }378 }379}380let focusedInstanceHandle: null | Fiber = null;381let shouldFireAfterActiveInstanceBlur: boolean = false;382export function commitBeforeMutationEffects(383 root: FiberRoot,384 firstChild: Fiber,385) {386 focusedInstanceHandle = prepareForCommit(root.containerInfo);387 if (enableRecursiveCommitTraversal) {388 recursivelyCommitBeforeMutationEffects(firstChild);389 } else {390 nextEffect = firstChild;391 iterativelyCommitBeforeMutationEffects_begin();392 }393 // We no longer need to track the active instance fiber394 const shouldFire = shouldFireAfterActiveInstanceBlur;395 shouldFireAfterActiveInstanceBlur = false;396 focusedInstanceHandle = null;397 return shouldFire;398}399function recursivelyCommitBeforeMutationEffects(firstChild: Fiber) {400 let fiber = firstChild;401 while (fiber !== null) {402 // TODO: Should wrap this in flags check, too, as optimization403 if (fiber.deletions !== null) {404 commitBeforeMutationEffectsDeletions(fiber.deletions);405 }406 const child = fiber.child;407 if (fiber.subtreeFlags & BeforeMutationMask && child !== null) {408 recursivelyCommitBeforeMutationEffects(child);409 }410 if (__DEV__) {411 setCurrentDebugFiberInDEV(fiber);412 invokeGuardedCallback(413 null,414 commitBeforeMutationEffectsOnFiber,415 null,416 fiber,417 );418 if (hasCaughtError()) {419 const error = clearCaughtError();420 captureCommitPhaseError(fiber, fiber.return, error);421 }422 resetCurrentDebugFiberInDEV();423 } else {424 try {425 commitBeforeMutationEffectsOnFiber(fiber);426 } catch (error) {427 captureCommitPhaseError(fiber, fiber.return, error);428 }429 }430 fiber = fiber.sibling;431 }432}433function iterativelyCommitBeforeMutationEffects_begin() {434 while (nextEffect !== null) {435 const fiber = nextEffect;436 // TODO: Should wrap this in flags check, too, as optimization437 const deletions = fiber.deletions;438 if (deletions !== null) {439 commitBeforeMutationEffectsDeletions(deletions);440 }441 const child = fiber.child;442 if (443 (fiber.subtreeFlags & BeforeMutationMask) !== NoFlags &&444 child !== null445 ) {446 child.return = fiber;447 nextEffect = child;448 } else {449 iterativelyCommitBeforeMutationEffects_complete();450 }451 }452}453function iterativelyCommitBeforeMutationEffects_complete() {454 while (nextEffect !== null) {455 const fiber = nextEffect;456 if (__DEV__) {457 setCurrentDebugFiberInDEV(fiber);458 invokeGuardedCallback(459 null,460 commitBeforeMutationEffectsOnFiber,461 null,462 fiber,463 );464 if (hasCaughtError()) {465 const error = clearCaughtError();466 captureCommitPhaseError(fiber, fiber.return, error);467 }468 resetCurrentDebugFiberInDEV();469 } else {470 try {471 commitBeforeMutationEffectsOnFiber(fiber);472 } catch (error) {473 captureCommitPhaseError(fiber, fiber.return, error);474 }475 }476 const sibling = fiber.sibling;477 if (sibling !== null) {478 sibling.return = fiber.return;479 nextEffect = sibling;480 return;481 }482 nextEffect = fiber.return;483 }484}485/** @noinline */486function commitBeforeMutationEffectsOnFiber(finishedWork: Fiber) {487 const current = finishedWork.alternate;488 const flags = finishedWork.flags;489 if (!shouldFireAfterActiveInstanceBlur && focusedInstanceHandle !== null) {490 // Check to see if the focused element was inside of a hidden (Suspense) subtree.491 if (492 // TODO: Can optimize this further with separate Hide and Show flags. We493 // only care about Hide here.494 (flags & Visibility) !== NoFlags &&495 finishedWork.tag === SuspenseComponent &&496 isSuspenseBoundaryBeingHidden(current, finishedWork) &&497 doesFiberContain(finishedWork, focusedInstanceHandle)498 ) {499 shouldFireAfterActiveInstanceBlur = true;500 beforeActiveInstanceBlur(finishedWork);501 }502 }503 if ((flags & Snapshot) !== NoFlags) {504 setCurrentDebugFiberInDEV(finishedWork);505 switch (finishedWork.tag) {506 case FunctionComponent:507 case ForwardRef:508 case SimpleMemoComponent: {509 break;510 }511 case ClassComponent: {512 if (finishedWork.flags & Snapshot) {513 if (current !== null) {514 const prevProps = current.memoizedProps;515 const prevState = current.memoizedState;516 const instance = finishedWork.stateNode;517 // We could update instance props and state here,518 // but instead we rely on them being set during last render.519 // TODO: revisit this when we implement resuming.520 if (__DEV__) {521 if (522 finishedWork.type === finishedWork.elementType &&523 !didWarnAboutReassigningProps524 ) {525 if (instance.props !== finishedWork.memoizedProps) {526 console.error(527 'Expected %s props to match memoized props before ' +528 'getSnapshotBeforeUpdate. ' +529 'This might either be because of a bug in React, or because ' +530 'a component reassigns its own `this.props`. ' +531 'Please file an issue.',532 getComponentName(finishedWork.type) || 'instance',533 );534 }535 if (instance.state !== finishedWork.memoizedState) {536 console.error(537 'Expected %s state to match memoized state before ' +538 'getSnapshotBeforeUpdate. ' +539 'This might either be because of a bug in React, or because ' +540 'a component reassigns its own `this.state`. ' +541 'Please file an issue.',542 getComponentName(finishedWork.type) || 'instance',543 );544 }545 }546 }547 const snapshot = instance.getSnapshotBeforeUpdate(548 finishedWork.elementType === finishedWork.type549 ? prevProps550 : resolveDefaultProps(finishedWork.type, prevProps),551 prevState,552 );553 if (__DEV__) {554 const didWarnSet = ((didWarnAboutUndefinedSnapshotBeforeUpdate: any): Set<mixed>);555 if (556 snapshot === undefined &&557 !didWarnSet.has(finishedWork.type)558 ) {559 didWarnSet.add(finishedWork.type);560 console.error(561 '%s.getSnapshotBeforeUpdate(): A snapshot value (or null) ' +562 'must be returned. You have returned undefined.',563 getComponentName(finishedWork.type),564 );565 }566 }567 instance.__reactInternalSnapshotBeforeUpdate = snapshot;568 }569 }570 break;571 }572 case HostRoot: {573 if (supportsMutation) {574 if (finishedWork.flags & Snapshot) {575 const root = finishedWork.stateNode;576 clearContainer(root.containerInfo);577 }578 }579 break;580 }581 case HostComponent:582 case HostText:583 case HostPortal:584 case IncompleteClassComponent:585 // Nothing to do for these component types586 break;587 default:588 invariant(589 false,590 'This unit of work tag should not have side-effects. This error is ' +591 'likely caused by a bug in React. Please file an issue.',592 );593 }594 resetCurrentDebugFiberInDEV();595 }596}597/** @noinline */598function commitBeforeMutationEffectsDeletions(deletions: Array<Fiber>) {599 for (let i = 0; i < deletions.length; i++) {600 const fiber = deletions[i];601 // TODO (effects) It would be nice to avoid calling doesFiberContain()602 // Maybe we can repurpose one of the subtreeFlags positions for this instead?603 // Use it to store which part of the tree the focused instance is in?604 // This assumes we can safely determine that instance during the "render" phase.605 if (doesFiberContain(fiber, ((focusedInstanceHandle: any): Fiber))) {606 shouldFireAfterActiveInstanceBlur = true;607 beforeActiveInstanceBlur(fiber);608 }609 }610}611export function commitMutationEffects(612 firstChild: Fiber,613 root: FiberRoot,614 renderPriorityLevel: ReactPriorityLevel,615) {616 if (enableRecursiveCommitTraversal) {617 recursivelyCommitMutationEffects(firstChild, root, renderPriorityLevel);618 } else {619 nextEffect = firstChild;620 iterativelyCommitMutationEffects_begin(root, renderPriorityLevel);621 }622}623function recursivelyCommitMutationEffects(624 firstChild: Fiber,625 root: FiberRoot,626 renderPriorityLevel: ReactPriorityLevel,627) {628 let fiber = firstChild;629 while (fiber !== null) {630 const deletions = fiber.deletions;631 if (deletions !== null) {632 commitMutationEffectsDeletions(633 deletions,634 fiber,635 root,636 renderPriorityLevel,637 );638 }639 if (fiber.child !== null) {640 const mutationFlags = fiber.subtreeFlags & MutationMask;641 if (mutationFlags !== NoFlags) {642 recursivelyCommitMutationEffects(643 fiber.child,644 root,645 renderPriorityLevel,646 );647 }648 }649 if (__DEV__) {650 setCurrentDebugFiberInDEV(fiber);651 invokeGuardedCallback(652 null,653 commitMutationEffectsOnFiber,654 null,655 fiber,656 root,657 renderPriorityLevel,658 );659 if (hasCaughtError()) {660 const error = clearCaughtError();661 captureCommitPhaseError(fiber, fiber.return, error);662 }663 resetCurrentDebugFiberInDEV();664 } else {665 try {666 commitMutationEffectsOnFiber(fiber, root, renderPriorityLevel);667 } catch (error) {668 captureCommitPhaseError(fiber, fiber.return, error);669 }670 }671 fiber = fiber.sibling;672 }673}674function iterativelyCommitMutationEffects_begin(675 root: FiberRoot,676 renderPriorityLevel: ReactPriorityLevel,677) {678 while (nextEffect !== null) {679 const fiber = nextEffect;680 // TODO: Should wrap this in flags check, too, as optimization681 const deletions = fiber.deletions;682 if (deletions !== null) {683 commitMutationEffectsDeletions(684 deletions,685 fiber,686 root,687 renderPriorityLevel,688 );689 }690 const child = fiber.child;691 if ((fiber.subtreeFlags & MutationMask) !== NoFlags && child !== null) {692 child.return = fiber;693 nextEffect = child;694 } else {695 iterativelyCommitMutationEffects_complete(root, renderPriorityLevel);696 }697 }698}699function iterativelyCommitMutationEffects_complete(700 root: FiberRoot,701 renderPriorityLevel: ReactPriorityLevel,702) {703 while (nextEffect !== null) {704 const fiber = nextEffect;705 if (__DEV__) {706 setCurrentDebugFiberInDEV(fiber);707 invokeGuardedCallback(708 null,709 commitMutationEffectsOnFiber,710 null,711 fiber,712 root,713 renderPriorityLevel,714 );715 if (hasCaughtError()) {716 const error = clearCaughtError();717 captureCommitPhaseError(fiber, fiber.return, error);718 }719 resetCurrentDebugFiberInDEV();720 } else {721 try {722 commitMutationEffectsOnFiber(fiber, root, renderPriorityLevel);723 } catch (error) {724 captureCommitPhaseError(fiber, fiber.return, error);725 }726 }727 const sibling = fiber.sibling;728 if (sibling !== null) {729 sibling.return = fiber.return;730 nextEffect = sibling;731 return;732 }733 nextEffect = fiber.return;734 }735}736/** @noinline */737function commitMutationEffectsOnFiber(738 fiber: Fiber,739 root: FiberRoot,740 renderPriorityLevel,741) {742 const flags = fiber.flags;743 if (flags & ContentReset) {744 commitResetTextContent(fiber);745 }746 if (flags & Ref) {747 const current = fiber.alternate;748 if (current !== null) {749 commitDetachRef(current);750 }751 if (enableScopeAPI) {752 // TODO: This is a temporary solution that allowed us to transition away from React Flare on www.753 if (fiber.tag === ScopeComponent) {754 commitAttachRef(fiber);755 }756 }757 }758 // The following switch statement is only concerned about placement,759 // updates, and deletions. To avoid needing to add a case for every possible760 // bitmap value, we remove the secondary effects from the effect tag and761 // switch on that value.762 const primaryFlags = flags & (Placement | Update | Hydrating);763 switch (primaryFlags) {764 case Placement: {765 commitPlacement(fiber);766 // Clear the "placement" from effect tag so that we know that this is767 // inserted, before any life-cycles like componentDidMount gets called.768 // TODO: findDOMNode doesn't rely on this any more but isMounted does769 // and isMounted is deprecated anyway so we should be able to kill this.770 fiber.flags &= ~Placement;771 break;772 }773 case PlacementAndUpdate: {774 // Placement775 commitPlacement(fiber);776 // Clear the "placement" from effect tag so that we know that this is777 // inserted, before any life-cycles like componentDidMount gets called.778 fiber.flags &= ~Placement;779 // Update780 const current = fiber.alternate;781 commitWork(current, fiber);782 break;783 }784 case Hydrating: {785 fiber.flags &= ~Hydrating;786 break;787 }788 case HydratingAndUpdate: {789 fiber.flags &= ~Hydrating;790 // Update791 const current = fiber.alternate;792 commitWork(current, fiber);793 break;794 }795 case Update: {796 const current = fiber.alternate;797 commitWork(current, fiber);798 break;799 }800 }801}802/** @noinline */803function commitMutationEffectsDeletions(804 deletions: Array<Fiber>,805 nearestMountedAncestor: Fiber,806 root: FiberRoot,807 renderPriorityLevel,808) {809 for (let i = 0; i < deletions.length; i++) {810 const childToDelete = deletions[i];811 if (__DEV__) {812 invokeGuardedCallback(813 null,814 commitDeletion,815 null,816 root,817 childToDelete,818 nearestMountedAncestor,819 renderPriorityLevel,820 );821 if (hasCaughtError()) {822 const error = clearCaughtError();823 captureCommitPhaseError(childToDelete, nearestMountedAncestor, error);824 }825 } else {826 try {827 commitDeletion(828 root,829 childToDelete,830 nearestMountedAncestor,831 renderPriorityLevel,832 );833 } catch (error) {834 captureCommitPhaseError(childToDelete, nearestMountedAncestor, error);835 }836 }837 }838}839export function commitLayoutEffects(840 finishedWork: Fiber,841 finishedRoot: FiberRoot,842) {843 if (enableRecursiveCommitTraversal) {844 if (__DEV__) {845 setCurrentDebugFiberInDEV(finishedWork);846 invokeGuardedCallback(847 null,848 recursivelyCommitLayoutEffects,849 null,850 finishedWork,851 finishedRoot,852 );853 if (hasCaughtError()) {854 const error = clearCaughtError();855 captureCommitPhaseError(finishedWork, null, error);856 }857 resetCurrentDebugFiberInDEV();858 } else {859 try {860 recursivelyCommitLayoutEffects(finishedWork, finishedRoot);861 } catch (error) {862 captureCommitPhaseError(finishedWork, null, error);863 }864 }865 } else {866 nextEffect = finishedWork;867 iterativelyCommitLayoutEffects_begin(finishedWork, finishedRoot);868 }869}870function recursivelyCommitLayoutEffects(871 finishedWork: Fiber,872 finishedRoot: FiberRoot,873) {874 const {flags, tag} = finishedWork;875 switch (tag) {876 case Profiler: {877 let prevProfilerOnStack = null;878 if (enableProfilerTimer && enableProfilerCommitHooks) {879 prevProfilerOnStack = nearestProfilerOnStack;880 nearestProfilerOnStack = finishedWork;881 }882 let child = finishedWork.child;883 while (child !== null) {884 const primarySubtreeFlags = finishedWork.subtreeFlags & LayoutMask;885 if (primarySubtreeFlags !== NoFlags) {886 if (__DEV__) {887 const prevCurrentFiberInDEV = currentDebugFiberInDEV;888 setCurrentDebugFiberInDEV(child);889 invokeGuardedCallback(890 null,891 recursivelyCommitLayoutEffects,892 null,893 child,894 finishedRoot,895 );896 if (hasCaughtError()) {897 const error = clearCaughtError();898 captureCommitPhaseError(child, finishedWork, error);899 }900 if (prevCurrentFiberInDEV !== null) {901 setCurrentDebugFiberInDEV(prevCurrentFiberInDEV);902 } else {903 resetCurrentDebugFiberInDEV();904 }905 } else {906 try {907 recursivelyCommitLayoutEffects(child, finishedRoot);908 } catch (error) {909 captureCommitPhaseError(child, finishedWork, error);910 }911 }912 }913 child = child.sibling;914 }915 const primaryFlags = flags & (Update | Callback);916 if (primaryFlags !== NoFlags) {917 if (enableProfilerTimer) {918 if (__DEV__) {919 const prevCurrentFiberInDEV = currentDebugFiberInDEV;920 setCurrentDebugFiberInDEV(finishedWork);921 invokeGuardedCallback(922 null,923 commitLayoutEffectsForProfiler,924 null,925 finishedWork,926 finishedRoot,927 );928 if (hasCaughtError()) {929 const error = clearCaughtError();930 captureCommitPhaseError(finishedWork, finishedWork.return, error);931 }932 if (prevCurrentFiberInDEV !== null) {933 setCurrentDebugFiberInDEV(prevCurrentFiberInDEV);934 } else {935 resetCurrentDebugFiberInDEV();936 }937 } else {938 try {939 commitLayoutEffectsForProfiler(finishedWork, finishedRoot);940 } catch (error) {941 captureCommitPhaseError(finishedWork, finishedWork.return, error);942 }943 }944 }945 }946 if (enableProfilerTimer && enableProfilerCommitHooks) {947 // Propagate layout effect durations to the next nearest Profiler ancestor.948 // Do not reset these values until the next render so DevTools has a chance to read them first.949 if (prevProfilerOnStack !== null) {950 prevProfilerOnStack.stateNode.effectDuration +=951 finishedWork.stateNode.effectDuration;952 }953 nearestProfilerOnStack = prevProfilerOnStack;954 }955 break;956 }957 // case Offscreen: {958 // TODO: Fast path to invoke all nested layout effects when Offscren goes from hidden to visible.959 // break;960 // }961 default: {962 let child = finishedWork.child;963 while (child !== null) {964 const primarySubtreeFlags = finishedWork.subtreeFlags & LayoutMask;965 if (primarySubtreeFlags !== NoFlags) {966 if (__DEV__) {967 const prevCurrentFiberInDEV = currentDebugFiberInDEV;968 setCurrentDebugFiberInDEV(child);969 invokeGuardedCallback(970 null,971 recursivelyCommitLayoutEffects,972 null,973 child,974 finishedRoot,975 );976 if (hasCaughtError()) {977 const error = clearCaughtError();978 captureCommitPhaseError(child, finishedWork, error);979 }980 if (prevCurrentFiberInDEV !== null) {981 setCurrentDebugFiberInDEV(prevCurrentFiberInDEV);982 } else {983 resetCurrentDebugFiberInDEV();984 }985 } else {986 try {987 recursivelyCommitLayoutEffects(child, finishedRoot);988 } catch (error) {989 captureCommitPhaseError(child, finishedWork, error);990 }991 }992 }993 child = child.sibling;994 }995 const primaryFlags = flags & (Update | Callback);996 if (primaryFlags !== NoFlags) {997 switch (tag) {998 case FunctionComponent:999 case ForwardRef:1000 case SimpleMemoComponent: {1001 if (1002 enableProfilerTimer &&1003 enableProfilerCommitHooks &&1004 finishedWork.mode & ProfileMode1005 ) {1006 try {1007 startLayoutEffectTimer();1008 commitHookEffectListMount(1009 HookLayout | HookHasEffect,1010 finishedWork,1011 );1012 } finally {1013 recordLayoutEffectDuration(finishedWork);1014 }1015 } else {1016 commitHookEffectListMount(1017 HookLayout | HookHasEffect,1018 finishedWork,1019 );1020 }1021 break;1022 }1023 case ClassComponent: {1024 // NOTE: Layout effect durations are measured within this function.1025 commitLayoutEffectsForClassComponent(finishedWork);1026 break;1027 }1028 case HostRoot: {1029 commitLayoutEffectsForHostRoot(finishedWork);1030 break;1031 }1032 case HostComponent: {1033 commitLayoutEffectsForHostComponent(finishedWork);1034 break;1035 }1036 case SuspenseComponent: {1037 commitSuspenseHydrationCallbacks(finishedRoot, finishedWork);1038 break;1039 }1040 case FundamentalComponent:1041 case HostPortal:1042 case HostText:1043 case IncompleteClassComponent:1044 case LegacyHiddenComponent:1045 case OffscreenComponent:1046 case ScopeComponent:1047 case SuspenseListComponent: {1048 // We have no life-cycles associated with these component types.1049 break;1050 }1051 default: {1052 invariant(1053 false,1054 'This unit of work tag should not have side-effects. This error is ' +1055 'likely caused by a bug in React. Please file an issue.',1056 );1057 }1058 }1059 }1060 if (enableScopeAPI) {1061 // TODO: This is a temporary solution that allowed us to transition away from React Flare on www.1062 if (flags & Ref && tag !== ScopeComponent) {1063 commitAttachRef(finishedWork);1064 }1065 } else {1066 if (flags & Ref) {1067 commitAttachRef(finishedWork);1068 }1069 }1070 break;1071 }1072 }1073}1074function iterativelyCommitLayoutEffects_begin(1075 subtreeRoot: Fiber,1076 finishedRoot: FiberRoot,1077) {1078 while (nextEffect !== null) {1079 const finishedWork: Fiber = nextEffect;1080 const firstChild = finishedWork.child;1081 if (1082 (finishedWork.subtreeFlags & LayoutMask) !== NoFlags &&1083 firstChild !== null1084 ) {1085 if (1086 enableProfilerTimer &&1087 enableProfilerCommitHooks &&1088 finishedWork.tag === Profiler1089 ) {1090 const prevProfilerOnStack = nearestProfilerOnStack;1091 nearestProfilerOnStack = finishedWork;1092 let child = firstChild;1093 while (child !== null) {1094 nextEffect = child;1095 iterativelyCommitLayoutEffects_begin(child, finishedRoot);1096 child = child.sibling;1097 }1098 nextEffect = finishedWork;1099 if ((finishedWork.flags & LayoutMask) !== NoFlags) {1100 if (__DEV__) {1101 setCurrentDebugFiberInDEV(finishedWork);1102 invokeGuardedCallback(1103 null,1104 commitLayoutEffectsForProfiler,1105 null,1106 finishedWork,1107 finishedRoot,1108 );1109 if (hasCaughtError()) {1110 const error = clearCaughtError();1111 captureCommitPhaseError(finishedWork, finishedWork.return, error);1112 }1113 resetCurrentDebugFiberInDEV();1114 } else {1115 try {1116 commitLayoutEffectsForProfiler(finishedWork, finishedRoot);1117 } catch (error) {1118 captureCommitPhaseError(finishedWork, finishedWork.return, error);1119 }1120 }1121 }1122 // Propagate layout effect durations to the next nearest Profiler ancestor.1123 // Do not reset these values until the next render so DevTools has a chance to read them first.1124 if (prevProfilerOnStack !== null) {1125 prevProfilerOnStack.stateNode.effectDuration +=1126 finishedWork.stateNode.effectDuration;1127 }1128 nearestProfilerOnStack = prevProfilerOnStack;1129 if (finishedWork === subtreeRoot) {1130 nextEffect = null;1131 return;1132 }1133 const sibling = finishedWork.sibling;1134 if (sibling !== null) {1135 sibling.return = finishedWork.return;1136 nextEffect = sibling;1137 } else {1138 nextEffect = finishedWork.return;1139 iterativelyCommitLayoutEffects_complete(subtreeRoot, finishedRoot);1140 }1141 } else {1142 firstChild.return = finishedWork;1143 nextEffect = firstChild;1144 }1145 } else {1146 iterativelyCommitLayoutEffects_complete(subtreeRoot, finishedRoot);1147 }1148 }1149}1150function iterativelyCommitLayoutEffects_complete(1151 subtreeRoot: Fiber,1152 finishedRoot: FiberRoot,1153) {1154 while (nextEffect !== null) {1155 const fiber = nextEffect;1156 if ((fiber.flags & LayoutMask) !== NoFlags) {1157 if (__DEV__) {1158 setCurrentDebugFiberInDEV(fiber);1159 invokeGuardedCallback(1160 null,1161 commitLayoutEffectsOnFiber,1162 null,1163 finishedRoot,1164 fiber,1165 );1166 if (hasCaughtError()) {1167 const error = clearCaughtError();1168 captureCommitPhaseError(fiber, fiber.return, error);1169 }1170 resetCurrentDebugFiberInDEV();1171 } else {1172 try {1173 commitLayoutEffectsOnFiber(finishedRoot, fiber);1174 } catch (error) {1175 captureCommitPhaseError(fiber, fiber.return, error);1176 }1177 }1178 }1179 if (fiber === subtreeRoot) {1180 nextEffect = null;1181 return;1182 }1183 const sibling = fiber.sibling;1184 if (sibling !== null) {1185 sibling.return = fiber.return;1186 nextEffect = sibling;1187 return;1188 }1189 nextEffect = nextEffect.return;1190 }1191}1192function commitLayoutEffectsOnFiber(1193 finishedRoot: FiberRoot,1194 finishedWork: Fiber,1195) {1196 const tag = finishedWork.tag;1197 const flags = finishedWork.flags;1198 if ((flags & (Update | Callback)) !== NoFlags) {1199 switch (tag) {1200 case FunctionComponent:1201 case ForwardRef:1202 case SimpleMemoComponent: {1203 if (1204 enableProfilerTimer &&1205 enableProfilerCommitHooks &&1206 finishedWork.mode & ProfileMode1207 ) {1208 try {1209 startLayoutEffectTimer();1210 commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork);1211 } finally {1212 recordLayoutEffectDuration(finishedWork);1213 }1214 } else {1215 commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork);1216 }1217 break;1218 }1219 case ClassComponent: {1220 // NOTE: Layout effect durations are measured within this function.1221 commitLayoutEffectsForClassComponent(finishedWork);1222 break;1223 }1224 case HostRoot: {1225 commitLayoutEffectsForHostRoot(finishedWork);1226 break;1227 }1228 case HostComponent: {1229 commitLayoutEffectsForHostComponent(finishedWork);1230 break;1231 }1232 case Profiler: {1233 commitLayoutEffectsForProfiler(finishedWork, finishedRoot);1234 break;1235 }1236 case SuspenseComponent: {1237 commitSuspenseHydrationCallbacks(finishedRoot, finishedWork);1238 break;1239 }1240 case FundamentalComponent:1241 case HostPortal:1242 case HostText:1243 case IncompleteClassComponent:1244 case LegacyHiddenComponent:1245 case OffscreenComponent:1246 case ScopeComponent:1247 case SuspenseListComponent: {1248 // We have no life-cycles associated with these component types.1249 break;1250 }1251 default: {1252 invariant(1253 false,1254 'This unit of work tag should not have side-effects. This error is ' +1255 'likely caused by a bug in React. Please file an issue.',1256 );1257 }1258 }1259 }1260 if (enableScopeAPI) {1261 // TODO: This is a temporary solution that allowed us to transition away from React Flare on www.1262 if (flags & Ref && tag !== ScopeComponent) {1263 commitAttachRef(finishedWork);1264 }1265 } else {1266 if (flags & Ref) {1267 commitAttachRef(finishedWork);1268 }1269 }1270}1271/** @noinline */1272function commitLayoutEffectsForProfiler(1273 finishedWork: Fiber,1274 finishedRoot: FiberRoot,1275) {1276 if (enableProfilerTimer) {1277 const flags = finishedWork.flags;1278 const current = finishedWork.alternate;1279 const {onCommit, onRender} = finishedWork.memoizedProps;1280 const {effectDuration} = finishedWork.stateNode;1281 const commitTime = getCommitTime();1282 const OnRenderFlag = Update;1283 const OnCommitFlag = Callback;1284 if ((flags & OnRenderFlag) !== NoFlags && typeof onRender === 'function') {1285 if (enableSchedulerTracing) {1286 onRender(1287 finishedWork.memoizedProps.id,1288 current === null ? 'mount' : 'update',1289 finishedWork.actualDuration,1290 finishedWork.treeBaseDuration,1291 finishedWork.actualStartTime,1292 commitTime,1293 finishedRoot.memoizedInteractions,1294 );1295 } else {1296 onRender(1297 finishedWork.memoizedProps.id,1298 current === null ? 'mount' : 'update',1299 finishedWork.actualDuration,1300 finishedWork.treeBaseDuration,1301 finishedWork.actualStartTime,1302 commitTime,1303 );1304 }1305 }1306 if (enableProfilerCommitHooks) {1307 if (1308 (flags & OnCommitFlag) !== NoFlags &&1309 typeof onCommit === 'function'1310 ) {1311 if (enableSchedulerTracing) {1312 onCommit(1313 finishedWork.memoizedProps.id,1314 current === null ? 'mount' : 'update',1315 effectDuration,1316 commitTime,1317 finishedRoot.memoizedInteractions,1318 );1319 } else {1320 onCommit(1321 finishedWork.memoizedProps.id,1322 current === null ? 'mount' : 'update',1323 effectDuration,1324 commitTime,1325 );1326 }1327 }1328 }1329 }1330}1331/** @noinline */1332function commitLayoutEffectsForClassComponent(finishedWork: Fiber) {1333 const instance = finishedWork.stateNode;1334 const current = finishedWork.alternate;1335 if (finishedWork.flags & Update) {1336 if (current === null) {1337 // We could update instance props and state here,1338 // but instead we rely on them being set during last render.1339 // TODO: revisit this when we implement resuming.1340 if (__DEV__) {1341 if (1342 finishedWork.type === finishedWork.elementType &&1343 !didWarnAboutReassigningProps1344 ) {1345 if (instance.props !== finishedWork.memoizedProps) {1346 console.error(1347 'Expected %s props to match memoized props before ' +1348 'componentDidMount. ' +1349 'This might either be because of a bug in React, or because ' +1350 'a component reassigns its own `this.props`. ' +1351 'Please file an issue.',1352 getComponentName(finishedWork.type) || 'instance',1353 );1354 }1355 if (instance.state !== finishedWork.memoizedState) {1356 console.error(1357 'Expected %s state to match memoized state before ' +1358 'componentDidMount. ' +1359 'This might either be because of a bug in React, or because ' +1360 'a component reassigns its own `this.state`. ' +1361 'Please file an issue.',1362 getComponentName(finishedWork.type) || 'instance',1363 );1364 }1365 }1366 }1367 if (1368 enableProfilerTimer &&1369 enableProfilerCommitHooks &&1370 finishedWork.mode & ProfileMode1371 ) {1372 try {1373 startLayoutEffectTimer();1374 instance.componentDidMount();1375 } finally {1376 recordLayoutEffectDuration(finishedWork);1377 }1378 } else {1379 instance.componentDidMount();1380 }1381 } else {1382 const prevProps =1383 finishedWork.elementType === finishedWork.type1384 ? current.memoizedProps1385 : resolveDefaultProps(finishedWork.type, current.memoizedProps);1386 const prevState = current.memoizedState;1387 // We could update instance props and state here,1388 // but instead we rely on them being set during last render.1389 // TODO: revisit this when we implement resuming.1390 if (__DEV__) {1391 if (1392 finishedWork.type === finishedWork.elementType &&1393 !didWarnAboutReassigningProps1394 ) {1395 if (instance.props !== finishedWork.memoizedProps) {1396 console.error(1397 'Expected %s props to match memoized props before ' +1398 'componentDidUpdate. ' +1399 'This might either be because of a bug in React, or because ' +1400 'a component reassigns its own `this.props`. ' +1401 'Please file an issue.',1402 getComponentName(finishedWork.type) || 'instance',1403 );1404 }1405 if (instance.state !== finishedWork.memoizedState) {1406 console.error(1407 'Expected %s state to match memoized state before ' +1408 'componentDidUpdate. ' +1409 'This might either be because of a bug in React, or because ' +1410 'a component reassigns its own `this.state`. ' +1411 'Please file an issue.',1412 getComponentName(finishedWork.type) || 'instance',1413 );1414 }1415 }1416 }1417 if (1418 enableProfilerTimer &&1419 enableProfilerCommitHooks &&1420 finishedWork.mode & ProfileMode1421 ) {1422 try {1423 startLayoutEffectTimer();1424 instance.componentDidUpdate(1425 prevProps,1426 prevState,1427 instance.__reactInternalSnapshotBeforeUpdate,1428 );1429 } finally {1430 recordLayoutEffectDuration(finishedWork);1431 }1432 } else {1433 instance.componentDidUpdate(1434 prevProps,1435 prevState,1436 instance.__reactInternalSnapshotBeforeUpdate,1437 );1438 }1439 }1440 }1441 // TODO: I think this is now always non-null by the time it reaches the1442 // commit phase. Consider removing the type check.1443 const updateQueue: UpdateQueue<*> | null = (finishedWork.updateQueue: any);1444 if (updateQueue !== null) {1445 if (__DEV__) {1446 if (1447 finishedWork.type === finishedWork.elementType &&1448 !didWarnAboutReassigningProps1449 ) {1450 if (instance.props !== finishedWork.memoizedProps) {1451 console.error(1452 'Expected %s props to match memoized props before ' +1453 'processing the update queue. ' +1454 'This might either be because of a bug in React, or because ' +1455 'a component reassigns its own `this.props`. ' +1456 'Please file an issue.',1457 getComponentName(finishedWork.type) || 'instance',1458 );1459 }1460 if (instance.state !== finishedWork.memoizedState) {1461 console.error(1462 'Expected %s state to match memoized state before ' +1463 'processing the update queue. ' +1464 'This might either be because of a bug in React, or because ' +1465 'a component reassigns its own `this.state`. ' +1466 'Please file an issue.',1467 getComponentName(finishedWork.type) || 'instance',1468 );1469 }1470 }1471 }1472 // We could update instance props and state here,1473 // but instead we rely on them being set during last render.1474 // TODO: revisit this when we implement resuming.1475 commitUpdateQueue(finishedWork, updateQueue, instance);1476 }1477}1478/** @noinline */1479function commitLayoutEffectsForHostRoot(finishedWork: Fiber) {1480 // TODO: I think this is now always non-null by the time it reaches the1481 // commit phase. Consider removing the type check.1482 const updateQueue: UpdateQueue<*> | null = (finishedWork.updateQueue: any);1483 if (updateQueue !== null) {1484 let instance = null;1485 if (finishedWork.child !== null) {1486 switch (finishedWork.child.tag) {1487 case HostComponent:1488 instance = getPublicInstance(finishedWork.child.stateNode);1489 break;1490 case ClassComponent:1491 instance = finishedWork.child.stateNode;1492 break;1493 }1494 }1495 commitUpdateQueue(finishedWork, updateQueue, instance);1496 }1497}1498/** @noinline */1499function commitLayoutEffectsForHostComponent(finishedWork: Fiber) {1500 const instance: Instance = finishedWork.stateNode;1501 const current = finishedWork.alternate;1502 // Renderers may schedule work to be done after host components are mounted1503 // (eg DOM renderer may schedule auto-focus for inputs and form controls).1504 // These effects should only be committed when components are first mounted,1505 // aka when there is no current/alternate.1506 if (current === null && finishedWork.flags & Update) {1507 const type = finishedWork.type;1508 const props = finishedWork.memoizedProps;1509 commitMount(instance, type, props, finishedWork);1510 }1511}1512/** @noinline */1513function hideOrUnhideAllChildren(finishedWork, isHidden) {1514 if (supportsMutation) {1515 // We only have the top Fiber that was inserted but we need to recurse down its1516 // children to find all the terminal nodes.1517 let node: Fiber = finishedWork;1518 while (true) {1519 if (node.tag === HostComponent) {1520 const instance = node.stateNode;1521 if (isHidden) {1522 hideInstance(instance);1523 } else {1524 unhideInstance(node.stateNode, node.memoizedProps);1525 }1526 } else if (node.tag === HostText) {1527 const instance = node.stateNode;1528 if (isHidden) {1529 hideTextInstance(instance);1530 } else {1531 unhideTextInstance(instance, node.memoizedProps);1532 }1533 } else if (1534 (node.tag === OffscreenComponent ||1535 node.tag === LegacyHiddenComponent) &&1536 (node.memoizedState: OffscreenState) !== null &&1537 node !== finishedWork1538 ) {1539 // Found a nested Offscreen component that is hidden. Don't search1540 // any deeper. This tree should remain hidden.1541 } else if (node.child !== null) {1542 node.child.return = node;1543 node = node.child;1544 continue;1545 }1546 if (node === finishedWork) {1547 return;1548 }1549 while (node.sibling === null) {1550 if (node.return === null || node.return === finishedWork) {1551 return;1552 }1553 node = node.return;1554 }1555 node.sibling.return = node.return;1556 node = node.sibling;1557 }1558 }1559}1560export function commitPassiveMountEffects(1561 root: FiberRoot,1562 firstChild: Fiber,1563): void {1564 if (enableRecursiveCommitTraversal) {1565 recursivelyCommitPassiveMountEffects(root, firstChild);1566 } else {1567 nextEffect = firstChild;1568 iterativelyCommitPassiveMountEffects_begin(firstChild, root);1569 }1570}1571function recursivelyCommitPassiveMountEffects(1572 root: FiberRoot,1573 firstChild: Fiber,1574): void {1575 let fiber = firstChild;1576 while (fiber !== null) {1577 let prevProfilerOnStack = null;1578 if (enableProfilerTimer && enableProfilerCommitHooks) {1579 if (fiber.tag === Profiler) {1580 prevProfilerOnStack = nearestProfilerOnStack;1581 nearestProfilerOnStack = fiber;1582 }1583 }1584 const primarySubtreeFlags = fiber.subtreeFlags & PassiveMask;1585 if (fiber.child !== null && primarySubtreeFlags !== NoFlags) {1586 recursivelyCommitPassiveMountEffects(root, fiber.child);1587 }1588 if ((fiber.flags & Passive) !== NoFlags) {1589 if (__DEV__) {1590 setCurrentDebugFiberInDEV(fiber);1591 invokeGuardedCallback(1592 null,1593 commitPassiveMountOnFiber,1594 null,1595 root,1596 fiber,1597 );1598 if (hasCaughtError()) {1599 const error = clearCaughtError();1600 captureCommitPhaseError(fiber, fiber.return, error);1601 }1602 resetCurrentDebugFiberInDEV();1603 } else {1604 try {1605 commitPassiveMountOnFiber(root, fiber);1606 } catch (error) {1607 captureCommitPhaseError(fiber, fiber.return, error);1608 }1609 }1610 }1611 if (enableProfilerTimer && enableProfilerCommitHooks) {1612 if (fiber.tag === Profiler) {1613 // Bubble times to the next nearest ancestor Profiler.1614 // After we process that Profiler, we'll bubble further up.1615 if (prevProfilerOnStack !== null) {1616 prevProfilerOnStack.stateNode.passiveEffectDuration +=1617 fiber.stateNode.passiveEffectDuration;1618 }1619 nearestProfilerOnStack = prevProfilerOnStack;1620 }1621 }1622 fiber = fiber.sibling;1623 }1624}1625function iterativelyCommitPassiveMountEffects_begin(1626 subtreeRoot: Fiber,1627 root: FiberRoot,1628) {1629 while (nextEffect !== null) {1630 const fiber = nextEffect;1631 const firstChild = fiber.child;1632 if ((fiber.subtreeFlags & PassiveMask) !== NoFlags && firstChild !== null) {1633 if (1634 enableProfilerTimer &&1635 enableProfilerCommitHooks &&1636 fiber.tag === Profiler1637 ) {1638 const prevProfilerOnStack = nearestProfilerOnStack;1639 nearestProfilerOnStack = fiber;1640 let child = firstChild;1641 while (child !== null) {1642 nextEffect = child;1643 iterativelyCommitPassiveMountEffects_begin(child, root);1644 child = child.sibling;1645 }1646 nextEffect = fiber;1647 if ((fiber.flags & PassiveMask) !== NoFlags) {1648 if (__DEV__) {1649 setCurrentDebugFiberInDEV(fiber);1650 invokeGuardedCallback(1651 null,1652 commitProfilerPassiveEffect,1653 null,1654 root,1655 fiber,1656 );1657 if (hasCaughtError()) {1658 const error = clearCaughtError();1659 captureCommitPhaseError(fiber, fiber.return, error);1660 }1661 resetCurrentDebugFiberInDEV();1662 } else {1663 try {1664 commitProfilerPassiveEffect(root, fiber);1665 } catch (error) {1666 captureCommitPhaseError(fiber, fiber.return, error);1667 }1668 }1669 }1670 // Bubble times to the next nearest ancestor Profiler.1671 // After we process that Profiler, we'll bubble further up.1672 if (prevProfilerOnStack !== null) {1673 prevProfilerOnStack.stateNode.passiveEffectDuration +=1674 fiber.stateNode.passiveEffectDuration;1675 }1676 nearestProfilerOnStack = prevProfilerOnStack;1677 if (fiber === subtreeRoot) {1678 nextEffect = null;1679 return;1680 }1681 const sibling = fiber.sibling;1682 if (sibling !== null) {1683 sibling.return = fiber.return;1684 nextEffect = sibling;1685 } else {1686 nextEffect = fiber.return;1687 iterativelyCommitPassiveMountEffects_complete(subtreeRoot, root);1688 }1689 } else {1690 firstChild.return = fiber;1691 nextEffect = firstChild;1692 }1693 } else {1694 iterativelyCommitPassiveMountEffects_complete(subtreeRoot, root);1695 }1696 }1697}1698function iterativelyCommitPassiveMountEffects_complete(1699 subtreeRoot: Fiber,1700 root: FiberRoot,1701) {1702 while (nextEffect !== null) {1703 const fiber = nextEffect;1704 if ((fiber.flags & Passive) !== NoFlags) {1705 if (__DEV__) {1706 setCurrentDebugFiberInDEV(fiber);1707 invokeGuardedCallback(1708 null,1709 commitPassiveMountOnFiber,1710 null,1711 root,1712 fiber,1713 );1714 if (hasCaughtError()) {1715 const error = clearCaughtError();1716 captureCommitPhaseError(fiber, fiber.return, error);1717 }1718 resetCurrentDebugFiberInDEV();1719 } else {1720 try {1721 commitPassiveMountOnFiber(root, fiber);1722 } catch (error) {1723 captureCommitPhaseError(fiber, fiber.return, error);1724 }1725 }1726 }1727 if (fiber === subtreeRoot) {1728 nextEffect = null;1729 return;1730 }1731 const sibling = fiber.sibling;1732 if (sibling !== null) {1733 sibling.return = fiber.return;1734 nextEffect = sibling;1735 return;1736 }1737 nextEffect = fiber.return;1738 }1739}1740export function commitPassiveUnmountEffects(firstChild: Fiber): void {1741 if (enableRecursiveCommitTraversal) {1742 recursivelyCommitPassiveUnmountEffects(firstChild);1743 } else {1744 nextEffect = firstChild;1745 iterativelyCommitPassiveUnmountEffects_begin();1746 }1747}1748function recursivelyCommitPassiveUnmountEffects(firstChild: Fiber): void {1749 let fiber = firstChild;1750 while (fiber !== null) {1751 const deletions = fiber.deletions;1752 if (deletions !== null) {1753 for (let i = 0; i < deletions.length; i++) {1754 const fiberToDelete = deletions[i];1755 recursivelyCommitPassiveUnmountEffectsInsideOfDeletedTree(1756 fiberToDelete,1757 fiber,1758 );1759 // Now that passive effects have been processed, it's safe to detach lingering pointers.1760 detachFiberAfterEffects(fiberToDelete);1761 }1762 }1763 const child = fiber.child;1764 if (child !== null) {1765 // If any children have passive effects then traverse the subtree.1766 // Note that this requires checking subtreeFlags of the current Fiber,1767 // rather than the subtreeFlags/effectsTag of the first child,1768 // since that would not cover passive effects in siblings.1769 const passiveFlags = fiber.subtreeFlags & PassiveMask;1770 if (passiveFlags !== NoFlags) {1771 recursivelyCommitPassiveUnmountEffects(child);1772 }1773 }1774 const primaryFlags = fiber.flags & Passive;1775 if (primaryFlags !== NoFlags) {1776 setCurrentDebugFiberInDEV(fiber);1777 commitPassiveUnmountOnFiber(fiber);1778 resetCurrentDebugFiberInDEV();1779 }1780 fiber = fiber.sibling;1781 }1782}1783function iterativelyCommitPassiveUnmountEffects_begin() {1784 while (nextEffect !== null) {1785 const fiber = nextEffect;1786 const child = fiber.child;1787 // TODO: Should wrap this in flags check, too, as optimization1788 const deletions = fiber.deletions;1789 if (deletions !== null) {1790 for (let i = 0; i < deletions.length; i++) {1791 const fiberToDelete = deletions[i];1792 nextEffect = fiberToDelete;1793 iterativelyCommitPassiveUnmountEffectsInsideOfDeletedTree_begin(1794 fiberToDelete,1795 fiber,1796 );1797 // Now that passive effects have been processed, it's safe to detach lingering pointers.1798 detachFiberAfterEffects(fiberToDelete);1799 }1800 nextEffect = fiber;1801 }1802 if ((fiber.subtreeFlags & PassiveMask) !== NoFlags && child !== null) {1803 child.return = fiber;1804 nextEffect = child;1805 } else {1806 iterativelyCommitPassiveUnmountEffects_complete();1807 }1808 }1809}1810function iterativelyCommitPassiveUnmountEffects_complete() {1811 while (nextEffect !== null) {1812 const fiber = nextEffect;1813 if ((fiber.flags & Passive) !== NoFlags) {1814 setCurrentDebugFiberInDEV(fiber);1815 commitPassiveUnmountOnFiber(fiber);1816 resetCurrentDebugFiberInDEV();1817 }1818 const sibling = fiber.sibling;1819 if (sibling !== null) {1820 sibling.return = fiber.return;1821 nextEffect = sibling;1822 return;1823 }1824 nextEffect = fiber.return;1825 }1826}1827function recursivelyCommitPassiveUnmountEffectsInsideOfDeletedTree(1828 fiberToDelete: Fiber,1829 nearestMountedAncestor: Fiber,1830): void {1831 if ((fiberToDelete.subtreeFlags & PassiveStatic) !== NoFlags) {1832 // If any children have passive effects then traverse the subtree.1833 // Note that this requires checking subtreeFlags of the current Fiber,1834 // rather than the subtreeFlags/effectsTag of the first child,1835 // since that would not cover passive effects in siblings.1836 let child = fiberToDelete.child;1837 while (child !== null) {1838 recursivelyCommitPassiveUnmountEffectsInsideOfDeletedTree(1839 child,1840 nearestMountedAncestor,1841 );1842 child = child.sibling;1843 }1844 }1845 if ((fiberToDelete.flags & PassiveStatic) !== NoFlags) {1846 setCurrentDebugFiberInDEV(fiberToDelete);1847 commitPassiveUnmountInsideDeletedTreeOnFiber(1848 fiberToDelete,1849 nearestMountedAncestor,1850 );1851 resetCurrentDebugFiberInDEV();1852 }1853}1854function iterativelyCommitPassiveUnmountEffectsInsideOfDeletedTree_begin(1855 deletedSubtreeRoot: Fiber,1856 nearestMountedAncestor: Fiber,1857) {1858 while (nextEffect !== null) {1859 const fiber = nextEffect;1860 const child = fiber.child;1861 if ((fiber.subtreeFlags & PassiveStatic) !== NoFlags && child !== null) {1862 child.return = fiber;1863 nextEffect = child;1864 } else {1865 iterativelyCommitPassiveUnmountEffectsInsideOfDeletedTree_complete(1866 deletedSubtreeRoot,1867 nearestMountedAncestor,1868 );1869 }1870 }1871}1872function iterativelyCommitPassiveUnmountEffectsInsideOfDeletedTree_complete(1873 deletedSubtreeRoot: Fiber,1874 nearestMountedAncestor: Fiber,1875) {1876 while (nextEffect !== null) {1877 const fiber = nextEffect;1878 if ((fiber.flags & PassiveStatic) !== NoFlags) {1879 setCurrentDebugFiberInDEV(fiber);1880 commitPassiveUnmountInsideDeletedTreeOnFiber(1881 fiber,1882 nearestMountedAncestor,1883 );1884 resetCurrentDebugFiberInDEV();1885 }1886 if (fiber === deletedSubtreeRoot) {1887 nextEffect = null;1888 return;1889 }1890 const sibling = fiber.sibling;1891 if (sibling !== null) {1892 sibling.return = fiber.return;1893 nextEffect = sibling;1894 return;1895 }1896 nextEffect = fiber.return;1897 }1898}1899function detachFiberAfterEffects(fiber: Fiber): void {1900 // Null out fields to improve GC for references that may be lingering (e.g. DevTools).1901 // Note that we already cleared the return pointer in detachFiberMutation().1902 fiber.child = null;1903 fiber.deletions = null;1904 fiber.dependencies = null;1905 fiber.memoizedProps = null;1906 fiber.memoizedState = null;1907 fiber.pendingProps = null;1908 fiber.sibling = null;1909 fiber.stateNode = null;1910 fiber.updateQueue = null;1911 if (__DEV__) {1912 fiber._debugOwner = null;1913 }1914}1915function commitAttachRef(finishedWork: Fiber) {1916 const ref = finishedWork.ref;1917 if (ref !== null) {1918 const instance = finishedWork.stateNode;1919 let instanceToUse;1920 switch (finishedWork.tag) {1921 case HostComponent:1922 instanceToUse = getPublicInstance(instance);1923 break;1924 default:1925 instanceToUse = instance;1926 }1927 // Moved outside to ensure DCE works with this flag1928 if (enableScopeAPI && finishedWork.tag === ScopeComponent) {1929 instanceToUse = instance;1930 }1931 if (typeof ref === 'function') {1932 if (1933 enableProfilerTimer &&1934 enableProfilerCommitHooks &&1935 finishedWork.mode & ProfileMode1936 ) {1937 try {1938 startLayoutEffectTimer();1939 ref(instanceToUse);1940 } finally {1941 recordLayoutEffectDuration(finishedWork);1942 }1943 } else {1944 ref(instanceToUse);1945 }1946 } else {1947 if (__DEV__) {1948 if (!ref.hasOwnProperty('current')) {1949 console.error(1950 'Unexpected ref object provided for %s. ' +1951 'Use either a ref-setter function or React.createRef().',1952 getComponentName(finishedWork.type),1953 );1954 }1955 }1956 ref.current = instanceToUse;1957 }1958 }1959}1960function commitDetachRef(current: Fiber) {1961 const currentRef = current.ref;1962 if (currentRef !== null) {1963 if (typeof currentRef === 'function') {1964 if (1965 enableProfilerTimer &&1966 enableProfilerCommitHooks &&1967 current.mode & ProfileMode1968 ) {1969 try {1970 startLayoutEffectTimer();1971 currentRef(null);1972 } finally {1973 recordLayoutEffectDuration(current);1974 }1975 } else {1976 currentRef(null);1977 }1978 } else {1979 currentRef.current = null;1980 }1981 }1982}1983// User-originating errors (lifecycles and refs) should not interrupt1984// deletion, so don't let them throw. Host-originating errors should1985// interrupt deletion, so it's okay1986function commitUnmount(1987 finishedRoot: FiberRoot,1988 current: Fiber,1989 nearestMountedAncestor: Fiber,1990 renderPriorityLevel: ReactPriorityLevel,1991): void {1992 onCommitUnmount(current);1993 switch (current.tag) {1994 case FunctionComponent:1995 case ForwardRef:1996 case MemoComponent:1997 case SimpleMemoComponent: {1998 const updateQueue: FunctionComponentUpdateQueue | null = (current.updateQueue: any);1999 if (updateQueue !== null) {2000 const lastEffect = updateQueue.lastEffect;2001 if (lastEffect !== null) {2002 const firstEffect = lastEffect.next;2003 let effect = firstEffect;2004 do {2005 const {destroy, tag} = effect;2006 if (destroy !== undefined) {2007 if ((tag & HookLayout) !== NoHookEffect) {2008 if (2009 enableProfilerTimer &&2010 enableProfilerCommitHooks &&2011 current.mode & ProfileMode2012 ) {2013 startLayoutEffectTimer();2014 safelyCallDestroy(current, nearestMountedAncestor, destroy);2015 recordLayoutEffectDuration(current);2016 } else {2017 safelyCallDestroy(current, nearestMountedAncestor, destroy);2018 }2019 }2020 }2021 effect = effect.next;2022 } while (effect !== firstEffect);2023 }2024 }2025 return;2026 }2027 case ClassComponent: {2028 safelyDetachRef(current, nearestMountedAncestor);2029 const instance = current.stateNode;2030 if (typeof instance.componentWillUnmount === 'function') {2031 safelyCallComponentWillUnmount(2032 current,2033 instance,2034 nearestMountedAncestor,2035 );2036 }2037 return;2038 }2039 case HostComponent: {2040 safelyDetachRef(current, nearestMountedAncestor);2041 return;2042 }2043 case HostPortal: {2044 // TODO: this is recursive.2045 // We are also not using this parent because2046 // the portal will get pushed immediately.2047 if (supportsMutation) {2048 unmountHostComponents(2049 finishedRoot,2050 current,2051 nearestMountedAncestor,2052 renderPriorityLevel,2053 );2054 } else if (supportsPersistence) {2055 emptyPortalContainer(current);2056 }2057 return;2058 }2059 case FundamentalComponent: {2060 if (enableFundamentalAPI) {2061 const fundamentalInstance = current.stateNode;2062 if (fundamentalInstance !== null) {2063 unmountFundamentalComponent(fundamentalInstance);2064 current.stateNode = null;2065 }2066 }2067 return;2068 }2069 case DehydratedFragment: {2070 if (enableSuspenseCallback) {2071 const hydrationCallbacks = finishedRoot.hydrationCallbacks;2072 if (hydrationCallbacks !== null) {2073 const onDeleted = hydrationCallbacks.onDeleted;2074 if (onDeleted) {2075 onDeleted((current.stateNode: SuspenseInstance));2076 }2077 }2078 }2079 return;2080 }2081 case ScopeComponent: {2082 if (enableScopeAPI) {2083 safelyDetachRef(current, nearestMountedAncestor);2084 }2085 return;2086 }2087 }2088}2089function commitNestedUnmounts(2090 finishedRoot: FiberRoot,2091 root: Fiber,2092 nearestMountedAncestor: Fiber,2093 renderPriorityLevel: ReactPriorityLevel,2094): void {2095 // While we're inside a removed host node we don't want to call2096 // removeChild on the inner nodes because they're removed by the top2097 // call anyway. We also want to call componentWillUnmount on all2098 // composites before this host node is removed from the tree. Therefore2099 // we do an inner loop while we're still inside the host node.2100 let node: Fiber = root;2101 while (true) {2102 commitUnmount(2103 finishedRoot,2104 node,2105 nearestMountedAncestor,2106 renderPriorityLevel,2107 );2108 // Visit children because they may contain more composite or host nodes.2109 // Skip portals because commitUnmount() currently visits them recursively.2110 if (2111 node.child !== null &&2112 // If we use mutation we drill down into portals using commitUnmount above.2113 // If we don't use mutation we drill down into portals here instead.2114 (!supportsMutation || node.tag !== HostPortal)2115 ) {2116 node.child.return = node;2117 node = node.child;2118 continue;2119 }2120 if (node === root) {2121 return;2122 }2123 while (node.sibling === null) {2124 if (node.return === null || node.return === root) {2125 return;2126 }2127 node = node.return;2128 }2129 node.sibling.return = node.return;2130 node = node.sibling;2131 }2132}2133function detachFiberMutation(fiber: Fiber) {2134 // Cut off the return pointer to disconnect it from the tree.2135 // This enables us to detect and warn against state updates on an unmounted component.2136 // It also prevents events from bubbling from within disconnected components.2137 //2138 // Ideally, we should also clear the child pointer of the parent alternate to let this2139 // get GC:ed but we don't know which for sure which parent is the current2140 // one so we'll settle for GC:ing the subtree of this child.2141 // This child itself will be GC:ed when the parent updates the next time.2142 //2143 // Note that we can't clear child or sibling pointers yet.2144 // They're needed for passive effects and for findDOMNode.2145 // We defer those fields, and all other cleanup, to the passive phase (see detachFiberAfterEffects).2146 const alternate = fiber.alternate;2147 if (alternate !== null) {2148 alternate.return = null;2149 fiber.alternate = null;2150 }2151 fiber.return = null;2152}2153function emptyPortalContainer(current: Fiber) {2154 if (!supportsPersistence) {2155 return;2156 }2157 const portal: {2158 containerInfo: Container,2159 pendingChildren: ChildSet,2160 ...2161 } = current.stateNode;2162 const {containerInfo} = portal;2163 const emptyChildSet = createContainerChildSet(containerInfo);2164 replaceContainerChildren(containerInfo, emptyChildSet);2165}2166function commitContainer(finishedWork: Fiber) {2167 if (!supportsPersistence) {2168 return;2169 }2170 switch (finishedWork.tag) {2171 case ClassComponent:2172 case HostComponent:2173 case HostText:2174 case FundamentalComponent: {2175 return;2176 }2177 case HostRoot:2178 case HostPortal: {2179 const portalOrRoot: {2180 containerInfo: Container,2181 pendingChildren: ChildSet,2182 ...2183 } = finishedWork.stateNode;2184 const {containerInfo, pendingChildren} = portalOrRoot;2185 replaceContainerChildren(containerInfo, pendingChildren);2186 return;2187 }2188 }2189 invariant(2190 false,2191 'This unit of work tag should not have side-effects. This error is ' +2192 'likely caused by a bug in React. Please file an issue.',2193 );2194}2195function getHostParentFiber(fiber: Fiber): Fiber {2196 let parent = fiber.return;2197 while (parent !== null) {2198 if (isHostParent(parent)) {2199 return parent;2200 }2201 parent = parent.return;2202 }2203 invariant(2204 false,2205 'Expected to find a host parent. This error is likely caused by a bug ' +2206 'in React. Please file an issue.',2207 );2208}2209function isHostParent(fiber: Fiber): boolean {2210 return (2211 fiber.tag === HostComponent ||2212 fiber.tag === HostRoot ||2213 fiber.tag === HostPortal2214 );2215}2216function getHostSibling(fiber: Fiber): ?Instance {2217 // We're going to search forward into the tree until we find a sibling host2218 // node. Unfortunately, if multiple insertions are done in a row we have to2219 // search past them. This leads to exponential search for the next sibling.2220 // TODO: Find a more efficient way to do this.2221 let node: Fiber = fiber;2222 siblings: while (true) {2223 // If we didn't find anything, let's try the next sibling.2224 while (node.sibling === null) {2225 if (node.return === null || isHostParent(node.return)) {2226 // If we pop out of the root or hit the parent the fiber we are the2227 // last sibling.2228 return null;2229 }2230 node = node.return;2231 }2232 node.sibling.return = node.return;2233 node = node.sibling;2234 while (2235 node.tag !== HostComponent &&2236 node.tag !== HostText &&2237 node.tag !== DehydratedFragment2238 ) {2239 // If it is not host node and, we might have a host node inside it.2240 // Try to search down until we find one.2241 if (node.flags & Placement) {2242 // If we don't have a child, try the siblings instead.2243 continue siblings;2244 }2245 // If we don't have a child, try the siblings instead.2246 // We also skip portals because they are not part of this host tree.2247 if (node.child === null || node.tag === HostPortal) {2248 continue siblings;2249 } else {2250 node.child.return = node;2251 node = node.child;2252 }2253 }2254 // Check if this host node is stable or about to be placed.2255 if (!(node.flags & Placement)) {2256 // Found it!2257 return node.stateNode;2258 }2259 }2260}2261function commitPlacement(finishedWork: Fiber): void {2262 if (!supportsMutation) {2263 return;2264 }2265 // Recursively insert all host nodes into the parent.2266 const parentFiber = getHostParentFiber(finishedWork);2267 // Note: these two variables *must* always be updated together.2268 let parent;2269 let isContainer;2270 const parentStateNode = parentFiber.stateNode;2271 switch (parentFiber.tag) {2272 case HostComponent:2273 parent = parentStateNode;2274 isContainer = false;2275 break;2276 case HostRoot:2277 parent = parentStateNode.containerInfo;2278 isContainer = true;2279 break;2280 case HostPortal:2281 parent = parentStateNode.containerInfo;2282 isContainer = true;2283 break;2284 case FundamentalComponent:2285 if (enableFundamentalAPI) {2286 parent = parentStateNode.instance;2287 isContainer = false;2288 }2289 // eslint-disable-next-line-no-fallthrough2290 default:2291 invariant(2292 false,2293 'Invalid host parent fiber. This error is likely caused by a bug ' +2294 'in React. Please file an issue.',2295 );2296 }2297 if (parentFiber.flags & ContentReset) {2298 // Reset the text content of the parent before doing any insertions2299 resetTextContent(parent);2300 // Clear ContentReset from the effect tag2301 parentFiber.flags &= ~ContentReset;2302 }2303 const before = getHostSibling(finishedWork);2304 // We only have the top Fiber that was inserted but we need to recurse down its2305 // children to find all the terminal nodes.2306 if (isContainer) {2307 insertOrAppendPlacementNodeIntoContainer(finishedWork, before, parent);2308 } else {2309 insertOrAppendPlacementNode(finishedWork, before, parent);2310 }2311}2312function insertOrAppendPlacementNodeIntoContainer(2313 node: Fiber,2314 before: ?Instance,2315 parent: Container,2316): void {2317 const {tag} = node;2318 const isHost = tag === HostComponent || tag === HostText;2319 if (isHost || (enableFundamentalAPI && tag === FundamentalComponent)) {2320 const stateNode = isHost ? node.stateNode : node.stateNode.instance;2321 if (before) {2322 insertInContainerBefore(parent, stateNode, before);2323 } else {2324 appendChildToContainer(parent, stateNode);2325 }2326 } else if (tag === HostPortal) {2327 // If the insertion itself is a portal, then we don't want to traverse2328 // down its children. Instead, we'll get insertions from each child in2329 // the portal directly.2330 } else {2331 const child = node.child;2332 if (child !== null) {2333 insertOrAppendPlacementNodeIntoContainer(child, before, parent);2334 let sibling = child.sibling;2335 while (sibling !== null) {2336 insertOrAppendPlacementNodeIntoContainer(sibling, before, parent);2337 sibling = sibling.sibling;2338 }2339 }2340 }2341}2342function insertOrAppendPlacementNode(2343 node: Fiber,2344 before: ?Instance,2345 parent: Instance,2346): void {2347 const {tag} = node;2348 const isHost = tag === HostComponent || tag === HostText;2349 if (isHost || (enableFundamentalAPI && tag === FundamentalComponent)) {2350 const stateNode = isHost ? node.stateNode : node.stateNode.instance;2351 if (before) {2352 insertBefore(parent, stateNode, before);2353 } else {2354 appendChild(parent, stateNode);2355 }2356 } else if (tag === HostPortal) {2357 // If the insertion itself is a portal, then we don't want to traverse2358 // down its children. Instead, we'll get insertions from each child in2359 // the portal directly.2360 } else {2361 const child = node.child;2362 if (child !== null) {2363 insertOrAppendPlacementNode(child, before, parent);2364 let sibling = child.sibling;2365 while (sibling !== null) {2366 insertOrAppendPlacementNode(sibling, before, parent);2367 sibling = sibling.sibling;2368 }2369 }2370 }2371}2372function unmountHostComponents(2373 finishedRoot: FiberRoot,2374 current: Fiber,2375 nearestMountedAncestor: Fiber,2376 renderPriorityLevel: ReactPriorityLevel,2377): void {2378 // We only have the top Fiber that was deleted but we need to recurse down its2379 // children to find all the terminal nodes.2380 let node: Fiber = current;2381 // Each iteration, currentParent is populated with node's host parent if not2382 // currentParentIsValid.2383 let currentParentIsValid = false;2384 // Note: these two variables *must* always be updated together.2385 let currentParent;2386 let currentParentIsContainer;2387 while (true) {2388 if (!currentParentIsValid) {2389 let parent = node.return;2390 findParent: while (true) {2391 invariant(2392 parent !== null,2393 'Expected to find a host parent. This error is likely caused by ' +2394 'a bug in React. Please file an issue.',2395 );2396 const parentStateNode = parent.stateNode;2397 switch (parent.tag) {2398 case HostComponent:2399 currentParent = parentStateNode;2400 currentParentIsContainer = false;2401 break findParent;2402 case HostRoot:2403 currentParent = parentStateNode.containerInfo;2404 currentParentIsContainer = true;2405 break findParent;2406 case HostPortal:2407 currentParent = parentStateNode.containerInfo;2408 currentParentIsContainer = true;2409 break findParent;2410 case FundamentalComponent:2411 if (enableFundamentalAPI) {2412 currentParent = parentStateNode.instance;2413 currentParentIsContainer = false;2414 }2415 }2416 parent = parent.return;2417 }2418 currentParentIsValid = true;2419 }2420 if (node.tag === HostComponent || node.tag === HostText) {2421 commitNestedUnmounts(2422 finishedRoot,2423 node,2424 nearestMountedAncestor,2425 renderPriorityLevel,2426 );2427 // After all the children have unmounted, it is now safe to remove the2428 // node from the tree.2429 if (currentParentIsContainer) {2430 removeChildFromContainer(2431 ((currentParent: any): Container),2432 (node.stateNode: Instance | TextInstance),2433 );2434 } else {2435 removeChild(2436 ((currentParent: any): Instance),2437 (node.stateNode: Instance | TextInstance),2438 );2439 }2440 // Don't visit children because we already visited them.2441 } else if (enableFundamentalAPI && node.tag === FundamentalComponent) {2442 const fundamentalNode = node.stateNode.instance;2443 commitNestedUnmounts(2444 finishedRoot,2445 node,2446 nearestMountedAncestor,2447 renderPriorityLevel,2448 );2449 // After all the children have unmounted, it is now safe to remove the2450 // node from the tree.2451 if (currentParentIsContainer) {2452 removeChildFromContainer(2453 ((currentParent: any): Container),2454 (fundamentalNode: Instance),2455 );2456 } else {2457 removeChild(2458 ((currentParent: any): Instance),2459 (fundamentalNode: Instance),2460 );2461 }2462 } else if (2463 enableSuspenseServerRenderer &&2464 node.tag === DehydratedFragment2465 ) {2466 if (enableSuspenseCallback) {2467 const hydrationCallbacks = finishedRoot.hydrationCallbacks;2468 if (hydrationCallbacks !== null) {2469 const onDeleted = hydrationCallbacks.onDeleted;2470 if (onDeleted) {2471 onDeleted((node.stateNode: SuspenseInstance));2472 }2473 }2474 }2475 // Delete the dehydrated suspense boundary and all of its content.2476 if (currentParentIsContainer) {2477 clearSuspenseBoundaryFromContainer(2478 ((currentParent: any): Container),2479 (node.stateNode: SuspenseInstance),2480 );2481 } else {2482 clearSuspenseBoundary(2483 ((currentParent: any): Instance),2484 (node.stateNode: SuspenseInstance),2485 );2486 }2487 } else if (node.tag === HostPortal) {2488 if (node.child !== null) {2489 // When we go into a portal, it becomes the parent to remove from.2490 // We will reassign it back when we pop the portal on the way up.2491 currentParent = node.stateNode.containerInfo;2492 currentParentIsContainer = true;2493 // Visit children because portals might contain host components.2494 node.child.return = node;2495 node = node.child;2496 continue;2497 }2498 } else {2499 commitUnmount(2500 finishedRoot,2501 node,2502 nearestMountedAncestor,2503 renderPriorityLevel,2504 );2505 // Visit children because we may find more host components below.2506 if (node.child !== null) {2507 node.child.return = node;2508 node = node.child;2509 continue;2510 }2511 }2512 if (node === current) {2513 return;2514 }2515 while (node.sibling === null) {2516 if (node.return === null || node.return === current) {2517 return;2518 }2519 node = node.return;2520 if (node.tag === HostPortal) {2521 // When we go out of the portal, we need to restore the parent.2522 // Since we don't keep a stack of them, we will search for it.2523 currentParentIsValid = false;2524 }2525 }2526 node.sibling.return = node.return;2527 node = node.sibling;2528 }2529}2530function commitDeletion(2531 finishedRoot: FiberRoot,2532 current: Fiber,2533 nearestMountedAncestor: Fiber,2534 renderPriorityLevel: ReactPriorityLevel,2535): void {2536 if (supportsMutation) {2537 // Recursively delete all host nodes from the parent.2538 // Detach refs and call componentWillUnmount() on the whole subtree.2539 unmountHostComponents(2540 finishedRoot,2541 current,2542 nearestMountedAncestor,2543 renderPriorityLevel,2544 );2545 } else {2546 // Detach refs and call componentWillUnmount() on the whole subtree.2547 commitNestedUnmounts(2548 finishedRoot,2549 current,2550 nearestMountedAncestor,2551 renderPriorityLevel,2552 );2553 }2554 const alternate = current.alternate;2555 detachFiberMutation(current);2556 if (alternate !== null) {2557 detachFiberMutation(alternate);2558 }2559}2560function commitWork(current: Fiber | null, finishedWork: Fiber): void {2561 if (!supportsMutation) {2562 switch (finishedWork.tag) {2563 case FunctionComponent:2564 case ForwardRef:2565 case MemoComponent:2566 case SimpleMemoComponent: {2567 // Layout effects are destroyed during the mutation phase so that all2568 // destroy functions for all fibers are called before any create functions.2569 // This prevents sibling component effects from interfering with each other,2570 // e.g. a destroy function in one component should never override a ref set2571 // by a create function in another component during the same commit.2572 if (2573 enableProfilerTimer &&2574 enableProfilerCommitHooks &&2575 finishedWork.mode & ProfileMode2576 ) {2577 try {2578 startLayoutEffectTimer();2579 commitHookEffectListUnmount(2580 HookLayout | HookHasEffect,2581 finishedWork,2582 finishedWork.return,2583 );2584 } finally {2585 recordLayoutEffectDuration(finishedWork);2586 }2587 } else {2588 commitHookEffectListUnmount(2589 HookLayout | HookHasEffect,2590 finishedWork,2591 finishedWork.return,2592 );2593 }2594 return;2595 }2596 case Profiler: {2597 return;2598 }2599 case SuspenseComponent: {2600 commitSuspenseComponent(finishedWork);2601 attachSuspenseRetryListeners(finishedWork);2602 return;2603 }2604 case SuspenseListComponent: {2605 attachSuspenseRetryListeners(finishedWork);2606 return;2607 }2608 case HostRoot: {2609 if (supportsHydration) {2610 const root: FiberRoot = finishedWork.stateNode;2611 if (root.hydrate) {2612 // We've just hydrated. No need to hydrate again.2613 root.hydrate = false;2614 commitHydratedContainer(root.containerInfo);2615 }2616 }2617 break;2618 }2619 case OffscreenComponent:2620 case LegacyHiddenComponent: {2621 return;2622 }2623 }2624 commitContainer(finishedWork);2625 return;2626 }2627 switch (finishedWork.tag) {2628 case FunctionComponent:2629 case ForwardRef:2630 case MemoComponent:2631 case SimpleMemoComponent: {2632 // Layout effects are destroyed during the mutation phase so that all2633 // destroy functions for all fibers are called before any create functions.2634 // This prevents sibling component effects from interfering with each other,2635 // e.g. a destroy function in one component should never override a ref set2636 // by a create function in another component during the same commit.2637 if (2638 enableProfilerTimer &&2639 enableProfilerCommitHooks &&2640 finishedWork.mode & ProfileMode2641 ) {2642 try {2643 startLayoutEffectTimer();2644 commitHookEffectListUnmount(2645 HookLayout | HookHasEffect,2646 finishedWork,2647 finishedWork.return,2648 );2649 } finally {2650 recordLayoutEffectDuration(finishedWork);2651 }2652 } else {2653 commitHookEffectListUnmount(2654 HookLayout | HookHasEffect,2655 finishedWork,2656 finishedWork.return,2657 );2658 }2659 return;2660 }2661 case ClassComponent: {2662 return;2663 }2664 case HostComponent: {2665 const instance: Instance = finishedWork.stateNode;2666 if (instance != null) {2667 // Commit the work prepared earlier.2668 const newProps = finishedWork.memoizedProps;2669 // For hydration we reuse the update path but we treat the oldProps2670 // as the newProps. The updatePayload will contain the real change in2671 // this case.2672 const oldProps = current !== null ? current.memoizedProps : newProps;2673 const type = finishedWork.type;2674 // TODO: Type the updateQueue to be specific to host components.2675 const updatePayload: null | UpdatePayload = (finishedWork.updateQueue: any);2676 finishedWork.updateQueue = null;2677 if (updatePayload !== null) {2678 commitUpdate(2679 instance,2680 updatePayload,2681 type,2682 oldProps,2683 newProps,2684 finishedWork,2685 );2686 }2687 }2688 return;2689 }2690 case HostText: {2691 invariant(2692 finishedWork.stateNode !== null,2693 'This should have a text node initialized. This error is likely ' +2694 'caused by a bug in React. Please file an issue.',2695 );2696 const textInstance: TextInstance = finishedWork.stateNode;2697 const newText: string = finishedWork.memoizedProps;2698 // For hydration we reuse the update path but we treat the oldProps2699 // as the newProps. The updatePayload will contain the real change in2700 // this case.2701 const oldText: string =2702 current !== null ? current.memoizedProps : newText;2703 commitTextUpdate(textInstance, oldText, newText);2704 return;2705 }2706 case HostRoot: {2707 if (supportsHydration) {2708 const root: FiberRoot = finishedWork.stateNode;2709 if (root.hydrate) {2710 // We've just hydrated. No need to hydrate again.2711 root.hydrate = false;2712 commitHydratedContainer(root.containerInfo);2713 }2714 }2715 return;2716 }2717 case Profiler: {2718 return;2719 }2720 case SuspenseComponent: {2721 commitSuspenseComponent(finishedWork);2722 attachSuspenseRetryListeners(finishedWork);2723 return;2724 }2725 case SuspenseListComponent: {2726 attachSuspenseRetryListeners(finishedWork);2727 return;2728 }2729 case IncompleteClassComponent: {2730 return;2731 }2732 case FundamentalComponent: {2733 if (enableFundamentalAPI) {2734 const fundamentalInstance = finishedWork.stateNode;2735 updateFundamentalComponent(fundamentalInstance);2736 return;2737 }2738 break;2739 }2740 case ScopeComponent: {2741 if (enableScopeAPI) {2742 const scopeInstance = finishedWork.stateNode;2743 prepareScopeUpdate(scopeInstance, finishedWork);2744 return;2745 }2746 break;2747 }2748 case OffscreenComponent:2749 case LegacyHiddenComponent: {2750 const newState: OffscreenState | null = finishedWork.memoizedState;2751 const isHidden = newState !== null;2752 hideOrUnhideAllChildren(finishedWork, isHidden);2753 return;2754 }2755 }2756 invariant(2757 false,2758 'This unit of work tag should not have side-effects. This error is ' +2759 'likely caused by a bug in React. Please file an issue.',2760 );2761}2762function commitSuspenseComponent(finishedWork: Fiber) {2763 const newState: SuspenseState | null = finishedWork.memoizedState;2764 if (newState !== null) {2765 markCommitTimeOfFallback();2766 if (supportsMutation) {2767 // Hide the Offscreen component that contains the primary children. TODO:2768 // Ideally, this effect would have been scheduled on the Offscreen fiber2769 // itself. That's how unhiding works: the Offscreen component schedules an2770 // effect on itself. However, in this case, the component didn't complete,2771 // so the fiber was never added to the effect list in the normal path. We2772 // could have appended it to the effect list in the Suspense component's2773 // second pass, but doing it this way is less complicated. This would be2774 // simpler if we got rid of the effect list and traversed the tree, like2775 // we're planning to do.2776 const primaryChildParent: Fiber = (finishedWork.child: any);2777 hideOrUnhideAllChildren(primaryChildParent, true);2778 }2779 }2780 if (enableSuspenseCallback && newState !== null) {2781 const suspenseCallback = finishedWork.memoizedProps.suspenseCallback;2782 if (typeof suspenseCallback === 'function') {2783 const wakeables: Set<Wakeable> | null = (finishedWork.updateQueue: any);2784 if (wakeables !== null) {2785 suspenseCallback(new Set(wakeables));2786 }2787 } else if (__DEV__) {2788 if (suspenseCallback !== undefined) {2789 console.error('Unexpected type for suspenseCallback.');2790 }2791 }2792 }2793}2794/** @noinline */2795function commitSuspenseHydrationCallbacks(2796 finishedRoot: FiberRoot,2797 finishedWork: Fiber,2798) {2799 if (!supportsHydration) {2800 return;2801 }2802 const newState: SuspenseState | null = finishedWork.memoizedState;2803 if (newState === null) {2804 const current = finishedWork.alternate;2805 if (current !== null) {2806 const prevState: SuspenseState | null = current.memoizedState;2807 if (prevState !== null) {2808 const suspenseInstance = prevState.dehydrated;2809 if (suspenseInstance !== null) {2810 commitHydratedSuspenseInstance(suspenseInstance);2811 if (enableSuspenseCallback) {2812 const hydrationCallbacks = finishedRoot.hydrationCallbacks;2813 if (hydrationCallbacks !== null) {2814 const onHydrated = hydrationCallbacks.onHydrated;2815 if (onHydrated) {2816 onHydrated(suspenseInstance);2817 }2818 }2819 }2820 }2821 }2822 }2823 }2824}2825function attachSuspenseRetryListeners(finishedWork: Fiber) {2826 // If this boundary just timed out, then it will have a set of wakeables.2827 // For each wakeable, attach a listener so that when it resolves, React2828 // attempts to re-render the boundary in the primary (pre-timeout) state.2829 const wakeables: Set<Wakeable> | null = (finishedWork.updateQueue: any);2830 if (wakeables !== null) {2831 finishedWork.updateQueue = null;2832 let retryCache = finishedWork.stateNode;2833 if (retryCache === null) {2834 retryCache = finishedWork.stateNode = new PossiblyWeakSet();2835 }2836 wakeables.forEach(wakeable => {2837 // Memoize using the boundary fiber to prevent redundant listeners.2838 let retry = resolveRetryWakeable.bind(null, finishedWork, wakeable);2839 if (!retryCache.has(wakeable)) {2840 if (enableSchedulerTracing) {2841 if (wakeable.__reactDoNotTraceInteractions !== true) {2842 retry = Schedule_tracing_wrap(retry);2843 }2844 }2845 retryCache.add(wakeable);2846 wakeable.then(retry, retry);2847 }2848 });2849 }2850}2851// This function detects when a Suspense boundary goes from visible to hidden.2852// It returns false if the boundary is already hidden.2853// TODO: Use an effect tag.2854function isSuspenseBoundaryBeingHidden(2855 current: Fiber | null,2856 finishedWork: Fiber,2857): boolean {2858 if (current !== null) {2859 const oldState: SuspenseState | null = current.memoizedState;2860 if (oldState === null || oldState.dehydrated !== null) {2861 const newState: SuspenseState | null = finishedWork.memoizedState;2862 return newState !== null && newState.dehydrated === null;2863 }2864 }2865 return false;2866}2867function commitResetTextContent(current: Fiber): void {2868 if (!supportsMutation) {2869 return;2870 }2871 resetTextContent(current.stateNode);2872}2873function commitPassiveUnmountOnFiber(finishedWork: Fiber): void {2874 switch (finishedWork.tag) {2875 case FunctionComponent:2876 case ForwardRef:2877 case SimpleMemoComponent: {2878 if (2879 enableProfilerTimer &&2880 enableProfilerCommitHooks &&2881 finishedWork.mode & ProfileMode2882 ) {2883 startPassiveEffectTimer();2884 commitHookEffectListUnmount(2885 HookPassive | HookHasEffect,2886 finishedWork,2887 finishedWork.return,2888 );2889 recordPassiveEffectDuration(finishedWork);2890 } else {2891 commitHookEffectListUnmount(2892 HookPassive | HookHasEffect,2893 finishedWork,2894 finishedWork.return,2895 );2896 }2897 break;2898 }2899 }2900}2901function commitPassiveUnmountInsideDeletedTreeOnFiber(2902 current: Fiber,2903 nearestMountedAncestor: Fiber | null,2904): void {2905 switch (current.tag) {2906 case FunctionComponent:2907 case ForwardRef:2908 case SimpleMemoComponent: {2909 if (2910 enableProfilerTimer &&2911 enableProfilerCommitHooks &&2912 current.mode & ProfileMode2913 ) {2914 startPassiveEffectTimer();2915 commitHookEffectListUnmount(2916 HookPassive,2917 current,2918 nearestMountedAncestor,2919 );2920 recordPassiveEffectDuration(current);2921 } else {2922 commitHookEffectListUnmount(2923 HookPassive,2924 current,2925 nearestMountedAncestor,2926 );2927 }2928 break;2929 }2930 }2931}2932function commitPassiveMountOnFiber(2933 finishedRoot: FiberRoot,2934 finishedWork: Fiber,2935): void {2936 switch (finishedWork.tag) {2937 case FunctionComponent:2938 case ForwardRef:2939 case SimpleMemoComponent: {2940 if (2941 enableProfilerTimer &&2942 enableProfilerCommitHooks &&2943 finishedWork.mode & ProfileMode2944 ) {2945 startPassiveEffectTimer();2946 try {2947 commitHookEffectListMount(HookPassive | HookHasEffect, finishedWork);2948 } finally {2949 recordPassiveEffectDuration(finishedWork);2950 }2951 } else {2952 commitHookEffectListMount(HookPassive | HookHasEffect, finishedWork);2953 }2954 break;2955 }2956 case Profiler: {2957 commitProfilerPassiveEffect(finishedRoot, finishedWork);2958 break;2959 }2960 }2961}2962function invokeLayoutEffectMountInDEV(fiber: Fiber): void {2963 if (__DEV__ && enableDoubleInvokingEffects) {2964 // We don't need to re-check for legacy roots here.2965 // This function will not be called within legacy roots.2966 switch (fiber.tag) {2967 case FunctionComponent:2968 case ForwardRef:2969 case SimpleMemoComponent: {2970 invokeGuardedCallback(2971 null,2972 commitHookEffectListMount,2973 null,2974 HookLayout | HookHasEffect,2975 fiber,2976 );2977 if (hasCaughtError()) {2978 const mountError = clearCaughtError();2979 captureCommitPhaseError(fiber, fiber.return, mountError);2980 }2981 break;2982 }2983 case ClassComponent: {2984 const instance = fiber.stateNode;2985 invokeGuardedCallback(null, instance.componentDidMount, instance);2986 if (hasCaughtError()) {2987 const mountError = clearCaughtError();2988 captureCommitPhaseError(fiber, fiber.return, mountError);2989 }2990 break;2991 }2992 }2993 }2994}2995function invokePassiveEffectMountInDEV(fiber: Fiber): void {2996 if (__DEV__ && enableDoubleInvokingEffects) {2997 // We don't need to re-check for legacy roots here.2998 // This function will not be called within legacy roots.2999 switch (fiber.tag) {3000 case FunctionComponent:3001 case ForwardRef:3002 case SimpleMemoComponent: {3003 invokeGuardedCallback(3004 null,3005 commitHookEffectListMount,3006 null,3007 HookPassive | HookHasEffect,3008 fiber,3009 );3010 if (hasCaughtError()) {3011 const mountError = clearCaughtError();3012 captureCommitPhaseError(fiber, fiber.return, mountError);3013 }3014 break;3015 }3016 }3017 }3018}3019function invokeLayoutEffectUnmountInDEV(fiber: Fiber): void {3020 if (__DEV__ && enableDoubleInvokingEffects) {3021 // We don't need to re-check for legacy roots here.3022 // This function will not be called within legacy roots.3023 switch (fiber.tag) {3024 case FunctionComponent:3025 case ForwardRef:3026 case SimpleMemoComponent: {3027 invokeGuardedCallback(3028 null,3029 commitHookEffectListUnmount,3030 null,3031 HookLayout | HookHasEffect,3032 fiber,3033 fiber.return,3034 );3035 if (hasCaughtError()) {3036 const unmountError = clearCaughtError();3037 captureCommitPhaseError(fiber, fiber.return, unmountError);3038 }3039 break;3040 }3041 case ClassComponent: {3042 const instance = fiber.stateNode;3043 if (typeof instance.componentWillUnmount === 'function') {3044 safelyCallComponentWillUnmount(fiber, instance, fiber.return);3045 }3046 break;3047 }3048 }3049 }3050}3051function invokePassiveEffectUnmountInDEV(fiber: Fiber): void {3052 if (__DEV__ && enableDoubleInvokingEffects) {3053 // We don't need to re-check for legacy roots here.3054 // This function will not be called within legacy roots.3055 switch (fiber.tag) {3056 case FunctionComponent:3057 case ForwardRef:3058 case SimpleMemoComponent: {3059 invokeGuardedCallback(3060 null,3061 commitHookEffectListUnmount,3062 null,3063 HookPassive | HookHasEffect,3064 fiber,3065 fiber.return,3066 );3067 if (hasCaughtError()) {3068 const unmountError = clearCaughtError();3069 captureCommitPhaseError(fiber, fiber.return, unmountError);3070 }3071 break;3072 }3073 }3074 }3075}3076// TODO: Convert this to iteration instead of recursion, too. Leaving this for3077// a follow up because the flag is off.3078export function commitDoubleInvokeEffectsInDEV(3079 fiber: Fiber,3080 hasPassiveEffects: boolean,3081) {3082 if (__DEV__ && enableDoubleInvokingEffects) {3083 // Never double-invoke effects for legacy roots....
ReactFiberCommitWork.old.js
Source:ReactFiberCommitWork.old.js
...192 current,193 );194 if (hasCaughtError()) {195 const unmountError = clearCaughtError();196 captureCommitPhaseError(current, nearestMountedAncestor, unmountError);197 }198 } else {199 try {200 commitHookEffectListMount(HookLayout, current);201 } catch (unmountError) {202 captureCommitPhaseError(current, nearestMountedAncestor, unmountError);203 }204 }205}206// Capture errors so they don't interrupt unmounting.207function safelyCallComponentWillUnmount(208 current: Fiber,209 nearestMountedAncestor: Fiber | null,210 instance: any,211) {212 if (__DEV__) {213 invokeGuardedCallback(214 null,215 callComponentWillUnmountWithTimer,216 null,217 current,218 instance,219 );220 if (hasCaughtError()) {221 const unmountError = clearCaughtError();222 captureCommitPhaseError(current, nearestMountedAncestor, unmountError);223 }224 } else {225 try {226 callComponentWillUnmountWithTimer(current, instance);227 } catch (unmountError) {228 captureCommitPhaseError(current, nearestMountedAncestor, unmountError);229 }230 }231}232// Capture errors so they don't interrupt mounting.233function safelyCallComponentDidMount(234 current: Fiber,235 nearestMountedAncestor: Fiber | null,236 instance: any,237) {238 if (__DEV__) {239 invokeGuardedCallback(null, instance.componentDidMount, instance);240 if (hasCaughtError()) {241 const unmountError = clearCaughtError();242 captureCommitPhaseError(current, nearestMountedAncestor, unmountError);243 }244 } else {245 try {246 instance.componentDidMount();247 } catch (unmountError) {248 captureCommitPhaseError(current, nearestMountedAncestor, unmountError);249 }250 }251}252// Capture errors so they don't interrupt mounting.253function safelyAttachRef(current: Fiber, nearestMountedAncestor: Fiber | null) {254 if (__DEV__) {255 invokeGuardedCallback(null, commitAttachRef, null, current);256 if (hasCaughtError()) {257 const unmountError = clearCaughtError();258 captureCommitPhaseError(current, nearestMountedAncestor, unmountError);259 }260 } else {261 try {262 commitAttachRef(current);263 } catch (unmountError) {264 captureCommitPhaseError(current, nearestMountedAncestor, unmountError);265 }266 }267}268function safelyDetachRef(current: Fiber, nearestMountedAncestor: Fiber | null) {269 const ref = current.ref;270 if (ref !== null) {271 if (typeof ref === 'function') {272 if (__DEV__) {273 if (274 enableProfilerTimer &&275 enableProfilerCommitHooks &&276 current.mode & ProfileMode277 ) {278 startLayoutEffectTimer();279 invokeGuardedCallback(null, ref, null, null);280 recordLayoutEffectDuration(current);281 } else {282 invokeGuardedCallback(null, ref, null, null);283 }284 if (hasCaughtError()) {285 const refError = clearCaughtError();286 captureCommitPhaseError(current, nearestMountedAncestor, refError);287 }288 } else {289 try {290 if (291 enableProfilerTimer &&292 enableProfilerCommitHooks &&293 current.mode & ProfileMode294 ) {295 try {296 startLayoutEffectTimer();297 ref(null);298 } finally {299 recordLayoutEffectDuration(current);300 }301 } else {302 ref(null);303 }304 } catch (refError) {305 captureCommitPhaseError(current, nearestMountedAncestor, refError);306 }307 }308 } else {309 ref.current = null;310 }311 }312}313function safelyCallDestroy(314 current: Fiber,315 nearestMountedAncestor: Fiber | null,316 destroy: () => void,317) {318 if (__DEV__) {319 invokeGuardedCallback(null, destroy, null);320 if (hasCaughtError()) {321 const error = clearCaughtError();322 captureCommitPhaseError(current, nearestMountedAncestor, error);323 }324 } else {325 try {326 destroy();327 } catch (error) {328 captureCommitPhaseError(current, nearestMountedAncestor, error);329 }330 }331}332let focusedInstanceHandle: null | Fiber = null;333let shouldFireAfterActiveInstanceBlur: boolean = false;334export function commitBeforeMutationEffects(335 root: FiberRoot,336 firstChild: Fiber,337) {338 focusedInstanceHandle = prepareForCommit(root.containerInfo);339 nextEffect = firstChild;340 commitBeforeMutationEffects_begin();341 // We no longer need to track the active instance fiber342 const shouldFire = shouldFireAfterActiveInstanceBlur;343 shouldFireAfterActiveInstanceBlur = false;344 focusedInstanceHandle = null;345 return shouldFire;346}347function commitBeforeMutationEffects_begin() {348 while (nextEffect !== null) {349 const fiber = nextEffect;350 // TODO: Should wrap this in flags check, too, as optimization351 const deletions = fiber.deletions;352 if (deletions !== null) {353 for (let i = 0; i < deletions.length; i++) {354 const deletion = deletions[i];355 commitBeforeMutationEffectsDeletion(deletion);356 }357 }358 const child = fiber.child;359 if (360 (fiber.subtreeFlags & BeforeMutationMask) !== NoFlags &&361 child !== null362 ) {363 ensureCorrectReturnPointer(child, fiber);364 nextEffect = child;365 } else {366 commitBeforeMutationEffects_complete();367 }368 }369}370function commitBeforeMutationEffects_complete() {371 while (nextEffect !== null) {372 const fiber = nextEffect;373 if (__DEV__) {374 setCurrentDebugFiberInDEV(fiber);375 invokeGuardedCallback(376 null,377 commitBeforeMutationEffectsOnFiber,378 null,379 fiber,380 );381 if (hasCaughtError()) {382 const error = clearCaughtError();383 captureCommitPhaseError(fiber, fiber.return, error);384 }385 resetCurrentDebugFiberInDEV();386 } else {387 try {388 commitBeforeMutationEffectsOnFiber(fiber);389 } catch (error) {390 captureCommitPhaseError(fiber, fiber.return, error);391 }392 }393 const sibling = fiber.sibling;394 if (sibling !== null) {395 ensureCorrectReturnPointer(sibling, fiber.return);396 nextEffect = sibling;397 return;398 }399 nextEffect = fiber.return;400 }401}402function commitBeforeMutationEffectsOnFiber(finishedWork: Fiber) {403 const current = finishedWork.alternate;404 const flags = finishedWork.flags;405 if (!shouldFireAfterActiveInstanceBlur && focusedInstanceHandle !== null) {406 // Check to see if the focused element was inside of a hidden (Suspense) subtree.407 // TODO: Move this out of the hot path using a dedicated effect tag.408 if (409 finishedWork.tag === SuspenseComponent &&410 isSuspenseBoundaryBeingHidden(current, finishedWork) &&411 doesFiberContain(finishedWork, focusedInstanceHandle)412 ) {413 shouldFireAfterActiveInstanceBlur = true;414 beforeActiveInstanceBlur(finishedWork);415 }416 }417 if ((flags & Snapshot) !== NoFlags) {418 setCurrentDebugFiberInDEV(finishedWork);419 switch (finishedWork.tag) {420 case FunctionComponent:421 case ForwardRef:422 case SimpleMemoComponent: {423 break;424 }425 case ClassComponent: {426 if (current !== null) {427 const prevProps = current.memoizedProps;428 const prevState = current.memoizedState;429 const instance = finishedWork.stateNode;430 // We could update instance props and state here,431 // but instead we rely on them being set during last render.432 // TODO: revisit this when we implement resuming.433 if (__DEV__) {434 if (435 finishedWork.type === finishedWork.elementType &&436 !didWarnAboutReassigningProps437 ) {438 if (instance.props !== finishedWork.memoizedProps) {439 console.error(440 'Expected %s props to match memoized props before ' +441 'getSnapshotBeforeUpdate. ' +442 'This might either be because of a bug in React, or because ' +443 'a component reassigns its own `this.props`. ' +444 'Please file an issue.',445 getComponentNameFromFiber(finishedWork) || 'instance',446 );447 }448 if (instance.state !== finishedWork.memoizedState) {449 console.error(450 'Expected %s state to match memoized state before ' +451 'getSnapshotBeforeUpdate. ' +452 'This might either be because of a bug in React, or because ' +453 'a component reassigns its own `this.state`. ' +454 'Please file an issue.',455 getComponentNameFromFiber(finishedWork) || 'instance',456 );457 }458 }459 }460 const snapshot = instance.getSnapshotBeforeUpdate(461 finishedWork.elementType === finishedWork.type462 ? prevProps463 : resolveDefaultProps(finishedWork.type, prevProps),464 prevState,465 );466 if (__DEV__) {467 const didWarnSet = ((didWarnAboutUndefinedSnapshotBeforeUpdate: any): Set<mixed>);468 if (snapshot === undefined && !didWarnSet.has(finishedWork.type)) {469 didWarnSet.add(finishedWork.type);470 console.error(471 '%s.getSnapshotBeforeUpdate(): A snapshot value (or null) ' +472 'must be returned. You have returned undefined.',473 getComponentNameFromFiber(finishedWork),474 );475 }476 }477 instance.__reactInternalSnapshotBeforeUpdate = snapshot;478 }479 break;480 }481 case HostRoot: {482 if (supportsMutation) {483 const root = finishedWork.stateNode;484 clearContainer(root.containerInfo);485 }486 break;487 }488 case HostComponent:489 case HostText:490 case HostPortal:491 case IncompleteClassComponent:492 // Nothing to do for these component types493 break;494 default: {495 invariant(496 false,497 'This unit of work tag should not have side-effects. This error is ' +498 'likely caused by a bug in React. Please file an issue.',499 );500 }501 }502 resetCurrentDebugFiberInDEV();503 }504}505function commitBeforeMutationEffectsDeletion(deletion: Fiber) {506 // TODO (effects) It would be nice to avoid calling doesFiberContain()507 // Maybe we can repurpose one of the subtreeFlags positions for this instead?508 // Use it to store which part of the tree the focused instance is in?509 // This assumes we can safely determine that instance during the "render" phase.510 if (doesFiberContain(deletion, ((focusedInstanceHandle: any): Fiber))) {511 shouldFireAfterActiveInstanceBlur = true;512 beforeActiveInstanceBlur(deletion);513 }514}515function commitHookEffectListUnmount(516 flags: HookFlags,517 finishedWork: Fiber,518 nearestMountedAncestor: Fiber | null,519) {520 const updateQueue: FunctionComponentUpdateQueue | null = (finishedWork.updateQueue: any);521 const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;522 if (lastEffect !== null) {523 const firstEffect = lastEffect.next;524 let effect = firstEffect;525 do {526 if ((effect.tag & flags) === flags) {527 // Unmount528 const destroy = effect.destroy;529 effect.destroy = undefined;530 if (destroy !== undefined) {531 safelyCallDestroy(finishedWork, nearestMountedAncestor, destroy);532 }533 }534 effect = effect.next;535 } while (effect !== firstEffect);536 }537}538function commitHookEffectListMount(tag: number, finishedWork: Fiber) {539 const updateQueue: FunctionComponentUpdateQueue | null = (finishedWork.updateQueue: any);540 const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;541 if (lastEffect !== null) {542 const firstEffect = lastEffect.next;543 let effect = firstEffect;544 do {545 if ((effect.tag & tag) === tag) {546 // Mount547 const create = effect.create;548 effect.destroy = create();549 if (__DEV__) {550 const destroy = effect.destroy;551 if (destroy !== undefined && typeof destroy !== 'function') {552 let addendum;553 if (destroy === null) {554 addendum =555 ' You returned null. If your effect does not require clean ' +556 'up, return undefined (or nothing).';557 } else if (typeof destroy.then === 'function') {558 addendum =559 '\n\nIt looks like you wrote useEffect(async () => ...) or returned a Promise. ' +560 'Instead, write the async function inside your effect ' +561 'and call it immediately:\n\n' +562 'useEffect(() => {\n' +563 ' async function fetchData() {\n' +564 ' // You can await here\n' +565 ' const response = await MyAPI.getData(someId);\n' +566 ' // ...\n' +567 ' }\n' +568 ' fetchData();\n' +569 `}, [someId]); // Or [] if effect doesn't need props or state\n\n` +570 'Learn more about data fetching with Hooks: https://reactjs.org/link/hooks-data-fetching';571 } else {572 addendum = ' You returned: ' + destroy;573 }574 console.error(575 'An effect function must not return anything besides a function, ' +576 'which is used for clean-up.%s',577 addendum,578 );579 }580 }581 }582 effect = effect.next;583 } while (effect !== firstEffect);584 }585}586export function commitPassiveEffectDurations(587 finishedRoot: FiberRoot,588 finishedWork: Fiber,589): void {590 if (enableProfilerTimer && enableProfilerCommitHooks) {591 // Only Profilers with work in their subtree will have an Update effect scheduled.592 if ((finishedWork.flags & Update) !== NoFlags) {593 switch (finishedWork.tag) {594 case Profiler: {595 const {passiveEffectDuration} = finishedWork.stateNode;596 const {id, onPostCommit} = finishedWork.memoizedProps;597 // This value will still reflect the previous commit phase.598 // It does not get reset until the start of the next commit phase.599 const commitTime = getCommitTime();600 let phase = finishedWork.alternate === null ? 'mount' : 'update';601 if (enableProfilerNestedUpdatePhase) {602 if (isCurrentUpdateNested()) {603 phase = 'nested-update';604 }605 }606 if (typeof onPostCommit === 'function') {607 if (enableSchedulerTracing) {608 onPostCommit(609 id,610 phase,611 passiveEffectDuration,612 commitTime,613 finishedRoot.memoizedInteractions,614 );615 } else {616 onPostCommit(id, phase, passiveEffectDuration, commitTime);617 }618 }619 // Bubble times to the next nearest ancestor Profiler.620 // After we process that Profiler, we'll bubble further up.621 let parentFiber = finishedWork.return;622 outer: while (parentFiber !== null) {623 switch (parentFiber.tag) {624 case HostRoot:625 const root = parentFiber.stateNode;626 root.passiveEffectDuration += passiveEffectDuration;627 break outer;628 case Profiler:629 const parentStateNode = parentFiber.stateNode;630 parentStateNode.passiveEffectDuration += passiveEffectDuration;631 break outer;632 }633 parentFiber = parentFiber.return;634 }635 break;636 }637 default:638 break;639 }640 }641 }642}643function commitLayoutEffectOnFiber(644 finishedRoot: FiberRoot,645 current: Fiber | null,646 finishedWork: Fiber,647 committedLanes: Lanes,648): void {649 if ((finishedWork.flags & (Update | Callback)) !== NoFlags) {650 switch (finishedWork.tag) {651 case FunctionComponent:652 case ForwardRef:653 case SimpleMemoComponent: {654 // At this point layout effects have already been destroyed (during mutation phase).655 // This is done to prevent sibling component effects from interfering with each other,656 // e.g. a destroy function in one component should never override a ref set657 // by a create function in another component during the same commit.658 if (659 enableProfilerTimer &&660 enableProfilerCommitHooks &&661 finishedWork.mode & ProfileMode662 ) {663 try {664 startLayoutEffectTimer();665 commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork);666 } finally {667 recordLayoutEffectDuration(finishedWork);668 }669 } else {670 commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork);671 }672 break;673 }674 case ClassComponent: {675 const instance = finishedWork.stateNode;676 if (finishedWork.flags & Update) {677 if (current === null) {678 // We could update instance props and state here,679 // but instead we rely on them being set during last render.680 // TODO: revisit this when we implement resuming.681 if (__DEV__) {682 if (683 finishedWork.type === finishedWork.elementType &&684 !didWarnAboutReassigningProps685 ) {686 if (instance.props !== finishedWork.memoizedProps) {687 console.error(688 'Expected %s props to match memoized props before ' +689 'componentDidMount. ' +690 'This might either be because of a bug in React, or because ' +691 'a component reassigns its own `this.props`. ' +692 'Please file an issue.',693 getComponentNameFromFiber(finishedWork) || 'instance',694 );695 }696 if (instance.state !== finishedWork.memoizedState) {697 console.error(698 'Expected %s state to match memoized state before ' +699 'componentDidMount. ' +700 'This might either be because of a bug in React, or because ' +701 'a component reassigns its own `this.state`. ' +702 'Please file an issue.',703 getComponentNameFromFiber(finishedWork) || 'instance',704 );705 }706 }707 }708 if (709 enableProfilerTimer &&710 enableProfilerCommitHooks &&711 finishedWork.mode & ProfileMode712 ) {713 try {714 startLayoutEffectTimer();715 instance.componentDidMount();716 } finally {717 recordLayoutEffectDuration(finishedWork);718 }719 } else {720 instance.componentDidMount();721 }722 } else {723 const prevProps =724 finishedWork.elementType === finishedWork.type725 ? current.memoizedProps726 : resolveDefaultProps(finishedWork.type, current.memoizedProps);727 const prevState = current.memoizedState;728 // We could update instance props and state here,729 // but instead we rely on them being set during last render.730 // TODO: revisit this when we implement resuming.731 if (__DEV__) {732 if (733 finishedWork.type === finishedWork.elementType &&734 !didWarnAboutReassigningProps735 ) {736 if (instance.props !== finishedWork.memoizedProps) {737 console.error(738 'Expected %s props to match memoized props before ' +739 'componentDidUpdate. ' +740 'This might either be because of a bug in React, or because ' +741 'a component reassigns its own `this.props`. ' +742 'Please file an issue.',743 getComponentNameFromFiber(finishedWork) || 'instance',744 );745 }746 if (instance.state !== finishedWork.memoizedState) {747 console.error(748 'Expected %s state to match memoized state before ' +749 'componentDidUpdate. ' +750 'This might either be because of a bug in React, or because ' +751 'a component reassigns its own `this.state`. ' +752 'Please file an issue.',753 getComponentNameFromFiber(finishedWork) || 'instance',754 );755 }756 }757 }758 if (759 enableProfilerTimer &&760 enableProfilerCommitHooks &&761 finishedWork.mode & ProfileMode762 ) {763 try {764 startLayoutEffectTimer();765 instance.componentDidUpdate(766 prevProps,767 prevState,768 instance.__reactInternalSnapshotBeforeUpdate,769 );770 } finally {771 recordLayoutEffectDuration(finishedWork);772 }773 } else {774 instance.componentDidUpdate(775 prevProps,776 prevState,777 instance.__reactInternalSnapshotBeforeUpdate,778 );779 }780 }781 }782 // TODO: I think this is now always non-null by the time it reaches the783 // commit phase. Consider removing the type check.784 const updateQueue: UpdateQueue<785 *,786 > | null = (finishedWork.updateQueue: any);787 if (updateQueue !== null) {788 if (__DEV__) {789 if (790 finishedWork.type === finishedWork.elementType &&791 !didWarnAboutReassigningProps792 ) {793 if (instance.props !== finishedWork.memoizedProps) {794 console.error(795 'Expected %s props to match memoized props before ' +796 'processing the update queue. ' +797 'This might either be because of a bug in React, or because ' +798 'a component reassigns its own `this.props`. ' +799 'Please file an issue.',800 getComponentNameFromFiber(finishedWork) || 'instance',801 );802 }803 if (instance.state !== finishedWork.memoizedState) {804 console.error(805 'Expected %s state to match memoized state before ' +806 'processing the update queue. ' +807 'This might either be because of a bug in React, or because ' +808 'a component reassigns its own `this.state`. ' +809 'Please file an issue.',810 getComponentNameFromFiber(finishedWork) || 'instance',811 );812 }813 }814 }815 // We could update instance props and state here,816 // but instead we rely on them being set during last render.817 // TODO: revisit this when we implement resuming.818 commitUpdateQueue(finishedWork, updateQueue, instance);819 }820 break;821 }822 case HostRoot: {823 // TODO: I think this is now always non-null by the time it reaches the824 // commit phase. Consider removing the type check.825 const updateQueue: UpdateQueue<826 *,827 > | null = (finishedWork.updateQueue: any);828 if (updateQueue !== null) {829 let instance = null;830 if (finishedWork.child !== null) {831 switch (finishedWork.child.tag) {832 case HostComponent:833 instance = getPublicInstance(finishedWork.child.stateNode);834 break;835 case ClassComponent:836 instance = finishedWork.child.stateNode;837 break;838 }839 }840 commitUpdateQueue(finishedWork, updateQueue, instance);841 }842 break;843 }844 case HostComponent: {845 const instance: Instance = finishedWork.stateNode;846 // Renderers may schedule work to be done after host components are mounted847 // (eg DOM renderer may schedule auto-focus for inputs and form controls).848 // These effects should only be committed when components are first mounted,849 // aka when there is no current/alternate.850 if (current === null && finishedWork.flags & Update) {851 const type = finishedWork.type;852 const props = finishedWork.memoizedProps;853 commitMount(instance, type, props, finishedWork);854 }855 break;856 }857 case HostText: {858 // We have no life-cycles associated with text.859 break;860 }861 case HostPortal: {862 // We have no life-cycles associated with portals.863 break;864 }865 case Profiler: {866 if (enableProfilerTimer) {867 const {onCommit, onRender} = finishedWork.memoizedProps;868 const {effectDuration} = finishedWork.stateNode;869 const commitTime = getCommitTime();870 let phase = current === null ? 'mount' : 'update';871 if (enableProfilerNestedUpdatePhase) {872 if (isCurrentUpdateNested()) {873 phase = 'nested-update';874 }875 }876 if (typeof onRender === 'function') {877 if (enableSchedulerTracing) {878 onRender(879 finishedWork.memoizedProps.id,880 phase,881 finishedWork.actualDuration,882 finishedWork.treeBaseDuration,883 finishedWork.actualStartTime,884 commitTime,885 finishedRoot.memoizedInteractions,886 );887 } else {888 onRender(889 finishedWork.memoizedProps.id,890 phase,891 finishedWork.actualDuration,892 finishedWork.treeBaseDuration,893 finishedWork.actualStartTime,894 commitTime,895 );896 }897 }898 if (enableProfilerCommitHooks) {899 if (typeof onCommit === 'function') {900 if (enableSchedulerTracing) {901 onCommit(902 finishedWork.memoizedProps.id,903 phase,904 effectDuration,905 commitTime,906 finishedRoot.memoizedInteractions,907 );908 } else {909 onCommit(910 finishedWork.memoizedProps.id,911 phase,912 effectDuration,913 commitTime,914 );915 }916 }917 // Schedule a passive effect for this Profiler to call onPostCommit hooks.918 // This effect should be scheduled even if there is no onPostCommit callback for this Profiler,919 // because the effect is also where times bubble to parent Profilers.920 enqueuePendingPassiveProfilerEffect(finishedWork);921 // Propagate layout effect durations to the next nearest Profiler ancestor.922 // Do not reset these values until the next render so DevTools has a chance to read them first.923 let parentFiber = finishedWork.return;924 outer: while (parentFiber !== null) {925 switch (parentFiber.tag) {926 case HostRoot:927 const root = parentFiber.stateNode;928 root.effectDuration += effectDuration;929 break outer;930 case Profiler:931 const parentStateNode = parentFiber.stateNode;932 parentStateNode.effectDuration += effectDuration;933 break outer;934 }935 parentFiber = parentFiber.return;936 }937 }938 }939 break;940 }941 case SuspenseComponent: {942 commitSuspenseHydrationCallbacks(finishedRoot, finishedWork);943 break;944 }945 case SuspenseListComponent:946 case IncompleteClassComponent:947 case ScopeComponent:948 case OffscreenComponent:949 case LegacyHiddenComponent:950 break;951 default:952 invariant(953 false,954 'This unit of work tag should not have side-effects. This error is ' +955 'likely caused by a bug in React. Please file an issue.',956 );957 }958 }959 if (enableScopeAPI) {960 // TODO: This is a temporary solution that allowed us to transition away961 // from React Flare on www.962 if (finishedWork.flags & Ref && finishedWork.tag !== ScopeComponent) {963 commitAttachRef(finishedWork);964 }965 } else {966 if (finishedWork.flags & Ref) {967 commitAttachRef(finishedWork);968 }969 }970}971function hideOrUnhideAllChildren(finishedWork, isHidden) {972 // Suspense layout effects semantics don't change for legacy roots.973 const isModernRoot = (finishedWork.mode & ConcurrentMode) !== NoMode;974 const current = finishedWork.alternate;975 const wasHidden = current !== null && current.memoizedState !== null;976 if (supportsMutation) {977 // We only have the top Fiber that was inserted but we need to recurse down its978 // children to find all the terminal nodes.979 let node: Fiber = finishedWork;980 while (true) {981 if (node.tag === HostComponent) {982 const instance = node.stateNode;983 if (isHidden) {984 hideInstance(instance);985 } else {986 unhideInstance(node.stateNode, node.memoizedProps);987 }988 if (enableSuspenseLayoutEffectSemantics && isModernRoot) {989 // This method is called during mutation; it should detach refs within a hidden subtree.990 // Attaching refs should be done elsewhere though (during layout).991 if ((node.flags & RefStatic) !== NoFlags) {992 if (isHidden) {993 safelyDetachRef(node, finishedWork);994 }995 }996 if (997 (node.subtreeFlags & (RefStatic | LayoutStatic)) !== NoFlags &&998 node.child !== null999 ) {1000 node.child.return = node;1001 node = node.child;1002 continue;1003 }1004 }1005 } else if (node.tag === HostText) {1006 const instance = node.stateNode;1007 if (isHidden) {1008 hideTextInstance(instance);1009 } else {1010 unhideTextInstance(instance, node.memoizedProps);1011 }1012 } else if (1013 (node.tag === OffscreenComponent ||1014 node.tag === LegacyHiddenComponent) &&1015 (node.memoizedState: OffscreenState) !== null &&1016 node !== finishedWork1017 ) {1018 // Found a nested Offscreen component that is hidden.1019 // Don't search any deeper. This tree should remain hidden.1020 } else if (enableSuspenseLayoutEffectSemantics && isModernRoot) {1021 // When a mounted Suspense subtree gets hidden again, destroy any nested layout effects.1022 if ((node.flags & (RefStatic | LayoutStatic)) !== NoFlags) {1023 switch (node.tag) {1024 case FunctionComponent:1025 case ForwardRef:1026 case MemoComponent:1027 case SimpleMemoComponent: {1028 // Note that refs are attached by the useImperativeHandle() hook, not by commitAttachRef()1029 if (isHidden && !wasHidden) {1030 if (1031 enableProfilerTimer &&1032 enableProfilerCommitHooks &&1033 node.mode & ProfileMode1034 ) {1035 try {1036 startLayoutEffectTimer();1037 commitHookEffectListUnmount(HookLayout, node, finishedWork);1038 } finally {1039 recordLayoutEffectDuration(node);1040 }1041 } else {1042 commitHookEffectListUnmount(HookLayout, node, finishedWork);1043 }1044 }1045 break;1046 }1047 case ClassComponent: {1048 if (isHidden && !wasHidden) {1049 if ((node.flags & RefStatic) !== NoFlags) {1050 safelyDetachRef(node, finishedWork);1051 }1052 const instance = node.stateNode;1053 if (typeof instance.componentWillUnmount === 'function') {1054 safelyCallComponentWillUnmount(node, finishedWork, instance);1055 }1056 }1057 break;1058 }1059 }1060 }1061 if (node.child !== null) {1062 node.child.return = node;1063 node = node.child;1064 continue;1065 }1066 } else if (node.child !== null) {1067 node.child.return = node;1068 node = node.child;1069 continue;1070 }1071 if (node === finishedWork) {1072 return;1073 }1074 while (node.sibling === null) {1075 if (node.return === null || node.return === finishedWork) {1076 return;1077 }1078 node = node.return;1079 }1080 node.sibling.return = node.return;1081 node = node.sibling;1082 }1083 }1084}1085function commitAttachRef(finishedWork: Fiber) {1086 const ref = finishedWork.ref;1087 if (ref !== null) {1088 const instance = finishedWork.stateNode;1089 let instanceToUse;1090 switch (finishedWork.tag) {1091 case HostComponent:1092 instanceToUse = getPublicInstance(instance);1093 break;1094 default:1095 instanceToUse = instance;1096 }1097 // Moved outside to ensure DCE works with this flag1098 if (enableScopeAPI && finishedWork.tag === ScopeComponent) {1099 instanceToUse = instance;1100 }1101 if (typeof ref === 'function') {1102 if (1103 enableProfilerTimer &&1104 enableProfilerCommitHooks &&1105 finishedWork.mode & ProfileMode1106 ) {1107 try {1108 startLayoutEffectTimer();1109 ref(instanceToUse);1110 } finally {1111 recordLayoutEffectDuration(finishedWork);1112 }1113 } else {1114 ref(instanceToUse);1115 }1116 } else {1117 if (__DEV__) {1118 if (!ref.hasOwnProperty('current')) {1119 console.error(1120 'Unexpected ref object provided for %s. ' +1121 'Use either a ref-setter function or React.createRef().',1122 getComponentNameFromFiber(finishedWork),1123 );1124 }1125 }1126 ref.current = instanceToUse;1127 }1128 }1129}1130function commitDetachRef(current: Fiber) {1131 const currentRef = current.ref;1132 if (currentRef !== null) {1133 if (typeof currentRef === 'function') {1134 if (1135 enableProfilerTimer &&1136 enableProfilerCommitHooks &&1137 current.mode & ProfileMode1138 ) {1139 try {1140 startLayoutEffectTimer();1141 currentRef(null);1142 } finally {1143 recordLayoutEffectDuration(current);1144 }1145 } else {1146 currentRef(null);1147 }1148 } else {1149 currentRef.current = null;1150 }1151 }1152}1153// User-originating errors (lifecycles and refs) should not interrupt1154// deletion, so don't let them throw. Host-originating errors should1155// interrupt deletion, so it's okay1156function commitUnmount(1157 finishedRoot: FiberRoot,1158 current: Fiber,1159 nearestMountedAncestor: Fiber,1160): void {1161 onCommitUnmount(current);1162 switch (current.tag) {1163 case FunctionComponent:1164 case ForwardRef:1165 case MemoComponent:1166 case SimpleMemoComponent: {1167 const updateQueue: FunctionComponentUpdateQueue | null = (current.updateQueue: any);1168 if (updateQueue !== null) {1169 const lastEffect = updateQueue.lastEffect;1170 if (lastEffect !== null) {1171 const firstEffect = lastEffect.next;1172 let effect = firstEffect;1173 do {1174 const {destroy, tag} = effect;1175 if (destroy !== undefined) {1176 if ((tag & HookLayout) !== NoHookEffect) {1177 if (1178 enableProfilerTimer &&1179 enableProfilerCommitHooks &&1180 current.mode & ProfileMode1181 ) {1182 startLayoutEffectTimer();1183 safelyCallDestroy(current, nearestMountedAncestor, destroy);1184 recordLayoutEffectDuration(current);1185 } else {1186 safelyCallDestroy(current, nearestMountedAncestor, destroy);1187 }1188 }1189 }1190 effect = effect.next;1191 } while (effect !== firstEffect);1192 }1193 }1194 return;1195 }1196 case ClassComponent: {1197 safelyDetachRef(current, nearestMountedAncestor);1198 const instance = current.stateNode;1199 if (typeof instance.componentWillUnmount === 'function') {1200 safelyCallComponentWillUnmount(1201 current,1202 nearestMountedAncestor,1203 instance,1204 );1205 }1206 return;1207 }1208 case HostComponent: {1209 safelyDetachRef(current, nearestMountedAncestor);1210 return;1211 }1212 case HostPortal: {1213 // TODO: this is recursive.1214 // We are also not using this parent because1215 // the portal will get pushed immediately.1216 if (supportsMutation) {1217 unmountHostComponents(finishedRoot, current, nearestMountedAncestor);1218 } else if (supportsPersistence) {1219 emptyPortalContainer(current);1220 }1221 return;1222 }1223 case DehydratedFragment: {1224 if (enableSuspenseCallback) {1225 const hydrationCallbacks = finishedRoot.hydrationCallbacks;1226 if (hydrationCallbacks !== null) {1227 const onDeleted = hydrationCallbacks.onDeleted;1228 if (onDeleted) {1229 onDeleted((current.stateNode: SuspenseInstance));1230 }1231 }1232 }1233 return;1234 }1235 case ScopeComponent: {1236 if (enableScopeAPI) {1237 safelyDetachRef(current, nearestMountedAncestor);1238 }1239 return;1240 }1241 }1242}1243function commitNestedUnmounts(1244 finishedRoot: FiberRoot,1245 root: Fiber,1246 nearestMountedAncestor: Fiber,1247): void {1248 // While we're inside a removed host node we don't want to call1249 // removeChild on the inner nodes because they're removed by the top1250 // call anyway. We also want to call componentWillUnmount on all1251 // composites before this host node is removed from the tree. Therefore1252 // we do an inner loop while we're still inside the host node.1253 let node: Fiber = root;1254 while (true) {1255 commitUnmount(finishedRoot, node, nearestMountedAncestor);1256 // Visit children because they may contain more composite or host nodes.1257 // Skip portals because commitUnmount() currently visits them recursively.1258 if (1259 node.child !== null &&1260 // If we use mutation we drill down into portals using commitUnmount above.1261 // If we don't use mutation we drill down into portals here instead.1262 (!supportsMutation || node.tag !== HostPortal)1263 ) {1264 node.child.return = node;1265 node = node.child;1266 continue;1267 }1268 if (node === root) {1269 return;1270 }1271 while (node.sibling === null) {1272 if (node.return === null || node.return === root) {1273 return;1274 }1275 node = node.return;1276 }1277 node.sibling.return = node.return;1278 node = node.sibling;1279 }1280}1281function detachFiberMutation(fiber: Fiber) {1282 // Cut off the return pointer to disconnect it from the tree.1283 // This enables us to detect and warn against state updates on an unmounted component.1284 // It also prevents events from bubbling from within disconnected components.1285 //1286 // Ideally, we should also clear the child pointer of the parent alternate to let this1287 // get GC:ed but we don't know which for sure which parent is the current1288 // one so we'll settle for GC:ing the subtree of this child.1289 // This child itself will be GC:ed when the parent updates the next time.1290 //1291 // Note that we can't clear child or sibling pointers yet.1292 // They're needed for passive effects and for findDOMNode.1293 // We defer those fields, and all other cleanup, to the passive phase (see detachFiberAfterEffects).1294 //1295 // Don't reset the alternate yet, either. We need that so we can detach the1296 // alternate's fields in the passive phase. Clearing the return pointer is1297 // sufficient for findDOMNode semantics.1298 const alternate = fiber.alternate;1299 if (alternate !== null) {1300 alternate.return = null;1301 }1302 fiber.return = null;1303}1304function detachFiberAfterEffects(fiber: Fiber) {1305 const alternate = fiber.alternate;1306 if (alternate !== null) {1307 fiber.alternate = null;1308 detachFiberAfterEffects(alternate);1309 }1310 // Note: Defensively using negation instead of < in case1311 // `deletedTreeCleanUpLevel` is undefined.1312 if (!(deletedTreeCleanUpLevel >= 2)) {1313 // This is the default branch (level 0).1314 fiber.child = null;1315 fiber.deletions = null;1316 fiber.dependencies = null;1317 fiber.memoizedProps = null;1318 fiber.memoizedState = null;1319 fiber.pendingProps = null;1320 fiber.sibling = null;1321 fiber.stateNode = null;1322 fiber.updateQueue = null;1323 if (__DEV__) {1324 fiber._debugOwner = null;1325 }1326 } else {1327 // Clear cyclical Fiber fields. This level alone is designed to roughly1328 // approximate the planned Fiber refactor. In that world, `setState` will be1329 // bound to a special "instance" object instead of a Fiber. The Instance1330 // object will not have any of these fields. It will only be connected to1331 // the fiber tree via a single link at the root. So if this level alone is1332 // sufficient to fix memory issues, that bodes well for our plans.1333 fiber.child = null;1334 fiber.deletions = null;1335 fiber.sibling = null;1336 // The `stateNode` is cyclical because on host nodes it points to the host1337 // tree, which has its own pointers to children, parents, and siblings.1338 // The other host nodes also point back to fibers, so we should detach that1339 // one, too.1340 if (fiber.tag === HostComponent) {1341 const hostInstance: Instance = fiber.stateNode;1342 if (hostInstance !== null) {1343 detachDeletedInstance(hostInstance);1344 }1345 }1346 fiber.stateNode = null;1347 // I'm intentionally not clearing the `return` field in this level. We1348 // already disconnect the `return` pointer at the root of the deleted1349 // subtree (in `detachFiberMutation`). Besides, `return` by itself is not1350 // cyclical â it's only cyclical when combined with `child`, `sibling`, and1351 // `alternate`. But we'll clear it in the next level anyway, just in case.1352 if (__DEV__) {1353 fiber._debugOwner = null;1354 }1355 if (deletedTreeCleanUpLevel >= 3) {1356 // Theoretically, nothing in here should be necessary, because we already1357 // disconnected the fiber from the tree. So even if something leaks this1358 // particular fiber, it won't leak anything else1359 //1360 // The purpose of this branch is to be super aggressive so we can measure1361 // if there's any difference in memory impact. If there is, that could1362 // indicate a React leak we don't know about.1363 fiber.return = null;1364 fiber.dependencies = null;1365 fiber.memoizedProps = null;1366 fiber.memoizedState = null;1367 fiber.pendingProps = null;1368 fiber.stateNode = null;1369 // TODO: Move to `commitPassiveUnmountInsideDeletedTreeOnFiber` instead.1370 fiber.updateQueue = null;1371 }1372 }1373}1374function emptyPortalContainer(current: Fiber) {1375 if (!supportsPersistence) {1376 return;1377 }1378 const portal: {1379 containerInfo: Container,1380 pendingChildren: ChildSet,1381 ...1382 } = current.stateNode;1383 const {containerInfo} = portal;1384 const emptyChildSet = createContainerChildSet(containerInfo);1385 replaceContainerChildren(containerInfo, emptyChildSet);1386}1387function commitContainer(finishedWork: Fiber) {1388 if (!supportsPersistence) {1389 return;1390 }1391 switch (finishedWork.tag) {1392 case ClassComponent:1393 case HostComponent:1394 case HostText: {1395 return;1396 }1397 case HostRoot:1398 case HostPortal: {1399 const portalOrRoot: {1400 containerInfo: Container,1401 pendingChildren: ChildSet,1402 ...1403 } = finishedWork.stateNode;1404 const {containerInfo, pendingChildren} = portalOrRoot;1405 replaceContainerChildren(containerInfo, pendingChildren);1406 return;1407 }1408 }1409 invariant(1410 false,1411 'This unit of work tag should not have side-effects. This error is ' +1412 'likely caused by a bug in React. Please file an issue.',1413 );1414}1415function getHostParentFiber(fiber: Fiber): Fiber {1416 let parent = fiber.return;1417 while (parent !== null) {1418 if (isHostParent(parent)) {1419 return parent;1420 }1421 parent = parent.return;1422 }1423 invariant(1424 false,1425 'Expected to find a host parent. This error is likely caused by a bug ' +1426 'in React. Please file an issue.',1427 );1428}1429function isHostParent(fiber: Fiber): boolean {1430 return (1431 fiber.tag === HostComponent ||1432 fiber.tag === HostRoot ||1433 fiber.tag === HostPortal1434 );1435}1436function getHostSibling(fiber: Fiber): ?Instance {1437 // We're going to search forward into the tree until we find a sibling host1438 // node. Unfortunately, if multiple insertions are done in a row we have to1439 // search past them. This leads to exponential search for the next sibling.1440 // TODO: Find a more efficient way to do this.1441 let node: Fiber = fiber;1442 siblings: while (true) {1443 // If we didn't find anything, let's try the next sibling.1444 while (node.sibling === null) {1445 if (node.return === null || isHostParent(node.return)) {1446 // If we pop out of the root or hit the parent the fiber we are the1447 // last sibling.1448 return null;1449 }1450 node = node.return;1451 }1452 node.sibling.return = node.return;1453 node = node.sibling;1454 while (1455 node.tag !== HostComponent &&1456 node.tag !== HostText &&1457 node.tag !== DehydratedFragment1458 ) {1459 // If it is not host node and, we might have a host node inside it.1460 // Try to search down until we find one.1461 if (node.flags & Placement) {1462 // If we don't have a child, try the siblings instead.1463 continue siblings;1464 }1465 // If we don't have a child, try the siblings instead.1466 // We also skip portals because they are not part of this host tree.1467 if (node.child === null || node.tag === HostPortal) {1468 continue siblings;1469 } else {1470 node.child.return = node;1471 node = node.child;1472 }1473 }1474 // Check if this host node is stable or about to be placed.1475 if (!(node.flags & Placement)) {1476 // Found it!1477 return node.stateNode;1478 }1479 }1480}1481function commitPlacement(finishedWork: Fiber): void {1482 if (!supportsMutation) {1483 return;1484 }1485 // Recursively insert all host nodes into the parent.1486 const parentFiber = getHostParentFiber(finishedWork);1487 // Note: these two variables *must* always be updated together.1488 let parent;1489 let isContainer;1490 const parentStateNode = parentFiber.stateNode;1491 switch (parentFiber.tag) {1492 case HostComponent:1493 parent = parentStateNode;1494 isContainer = false;1495 break;1496 case HostRoot:1497 parent = parentStateNode.containerInfo;1498 isContainer = true;1499 break;1500 case HostPortal:1501 parent = parentStateNode.containerInfo;1502 isContainer = true;1503 break;1504 // eslint-disable-next-line-no-fallthrough1505 default:1506 invariant(1507 false,1508 'Invalid host parent fiber. This error is likely caused by a bug ' +1509 'in React. Please file an issue.',1510 );1511 }1512 if (parentFiber.flags & ContentReset) {1513 // Reset the text content of the parent before doing any insertions1514 resetTextContent(parent);1515 // Clear ContentReset from the effect tag1516 parentFiber.flags &= ~ContentReset;1517 }1518 const before = getHostSibling(finishedWork);1519 // We only have the top Fiber that was inserted but we need to recurse down its1520 // children to find all the terminal nodes.1521 if (isContainer) {1522 insertOrAppendPlacementNodeIntoContainer(finishedWork, before, parent);1523 } else {1524 insertOrAppendPlacementNode(finishedWork, before, parent);1525 }1526}1527function insertOrAppendPlacementNodeIntoContainer(1528 node: Fiber,1529 before: ?Instance,1530 parent: Container,1531): void {1532 const {tag} = node;1533 const isHost = tag === HostComponent || tag === HostText;1534 if (isHost) {1535 const stateNode = node.stateNode;1536 if (before) {1537 insertInContainerBefore(parent, stateNode, before);1538 } else {1539 appendChildToContainer(parent, stateNode);1540 }1541 } else if (tag === HostPortal) {1542 // If the insertion itself is a portal, then we don't want to traverse1543 // down its children. Instead, we'll get insertions from each child in1544 // the portal directly.1545 } else {1546 const child = node.child;1547 if (child !== null) {1548 insertOrAppendPlacementNodeIntoContainer(child, before, parent);1549 let sibling = child.sibling;1550 while (sibling !== null) {1551 insertOrAppendPlacementNodeIntoContainer(sibling, before, parent);1552 sibling = sibling.sibling;1553 }1554 }1555 }1556}1557function insertOrAppendPlacementNode(1558 node: Fiber,1559 before: ?Instance,1560 parent: Instance,1561): void {1562 const {tag} = node;1563 const isHost = tag === HostComponent || tag === HostText;1564 if (isHost) {1565 const stateNode = node.stateNode;1566 if (before) {1567 insertBefore(parent, stateNode, before);1568 } else {1569 appendChild(parent, stateNode);1570 }1571 } else if (tag === HostPortal) {1572 // If the insertion itself is a portal, then we don't want to traverse1573 // down its children. Instead, we'll get insertions from each child in1574 // the portal directly.1575 } else {1576 const child = node.child;1577 if (child !== null) {1578 insertOrAppendPlacementNode(child, before, parent);1579 let sibling = child.sibling;1580 while (sibling !== null) {1581 insertOrAppendPlacementNode(sibling, before, parent);1582 sibling = sibling.sibling;1583 }1584 }1585 }1586}1587function unmountHostComponents(1588 finishedRoot: FiberRoot,1589 current: Fiber,1590 nearestMountedAncestor: Fiber,1591): void {1592 // We only have the top Fiber that was deleted but we need to recurse down its1593 // children to find all the terminal nodes.1594 let node: Fiber = current;1595 // Each iteration, currentParent is populated with node's host parent if not1596 // currentParentIsValid.1597 let currentParentIsValid = false;1598 // Note: these two variables *must* always be updated together.1599 let currentParent;1600 let currentParentIsContainer;1601 while (true) {1602 if (!currentParentIsValid) {1603 let parent = node.return;1604 findParent: while (true) {1605 invariant(1606 parent !== null,1607 'Expected to find a host parent. This error is likely caused by ' +1608 'a bug in React. Please file an issue.',1609 );1610 const parentStateNode = parent.stateNode;1611 switch (parent.tag) {1612 case HostComponent:1613 currentParent = parentStateNode;1614 currentParentIsContainer = false;1615 break findParent;1616 case HostRoot:1617 currentParent = parentStateNode.containerInfo;1618 currentParentIsContainer = true;1619 break findParent;1620 case HostPortal:1621 currentParent = parentStateNode.containerInfo;1622 currentParentIsContainer = true;1623 break findParent;1624 }1625 parent = parent.return;1626 }1627 currentParentIsValid = true;1628 }1629 if (node.tag === HostComponent || node.tag === HostText) {1630 commitNestedUnmounts(finishedRoot, node, nearestMountedAncestor);1631 // After all the children have unmounted, it is now safe to remove the1632 // node from the tree.1633 if (currentParentIsContainer) {1634 removeChildFromContainer(1635 ((currentParent: any): Container),1636 (node.stateNode: Instance | TextInstance),1637 );1638 } else {1639 removeChild(1640 ((currentParent: any): Instance),1641 (node.stateNode: Instance | TextInstance),1642 );1643 }1644 // Don't visit children because we already visited them.1645 } else if (1646 enableSuspenseServerRenderer &&1647 node.tag === DehydratedFragment1648 ) {1649 if (enableSuspenseCallback) {1650 const hydrationCallbacks = finishedRoot.hydrationCallbacks;1651 if (hydrationCallbacks !== null) {1652 const onDeleted = hydrationCallbacks.onDeleted;1653 if (onDeleted) {1654 onDeleted((node.stateNode: SuspenseInstance));1655 }1656 }1657 }1658 // Delete the dehydrated suspense boundary and all of its content.1659 if (currentParentIsContainer) {1660 clearSuspenseBoundaryFromContainer(1661 ((currentParent: any): Container),1662 (node.stateNode: SuspenseInstance),1663 );1664 } else {1665 clearSuspenseBoundary(1666 ((currentParent: any): Instance),1667 (node.stateNode: SuspenseInstance),1668 );1669 }1670 } else if (node.tag === HostPortal) {1671 if (node.child !== null) {1672 // When we go into a portal, it becomes the parent to remove from.1673 // We will reassign it back when we pop the portal on the way up.1674 currentParent = node.stateNode.containerInfo;1675 currentParentIsContainer = true;1676 // Visit children because portals might contain host components.1677 node.child.return = node;1678 node = node.child;1679 continue;1680 }1681 } else {1682 commitUnmount(finishedRoot, node, nearestMountedAncestor);1683 // Visit children because we may find more host components below.1684 if (node.child !== null) {1685 node.child.return = node;1686 node = node.child;1687 continue;1688 }1689 }1690 if (node === current) {1691 return;1692 }1693 while (node.sibling === null) {1694 if (node.return === null || node.return === current) {1695 return;1696 }1697 node = node.return;1698 if (node.tag === HostPortal) {1699 // When we go out of the portal, we need to restore the parent.1700 // Since we don't keep a stack of them, we will search for it.1701 currentParentIsValid = false;1702 }1703 }1704 node.sibling.return = node.return;1705 node = node.sibling;1706 }1707}1708function commitDeletion(1709 finishedRoot: FiberRoot,1710 current: Fiber,1711 nearestMountedAncestor: Fiber,1712): void {1713 if (supportsMutation) {1714 // Recursively delete all host nodes from the parent.1715 // Detach refs and call componentWillUnmount() on the whole subtree.1716 unmountHostComponents(finishedRoot, current, nearestMountedAncestor);1717 } else {1718 // Detach refs and call componentWillUnmount() on the whole subtree.1719 commitNestedUnmounts(finishedRoot, current, nearestMountedAncestor);1720 }1721 detachFiberMutation(current);1722}1723function commitWork(current: Fiber | null, finishedWork: Fiber): void {1724 if (!supportsMutation) {1725 switch (finishedWork.tag) {1726 case FunctionComponent:1727 case ForwardRef:1728 case MemoComponent:1729 case SimpleMemoComponent: {1730 // Layout effects are destroyed during the mutation phase so that all1731 // destroy functions for all fibers are called before any create functions.1732 // This prevents sibling component effects from interfering with each other,1733 // e.g. a destroy function in one component should never override a ref set1734 // by a create function in another component during the same commit.1735 if (1736 enableProfilerTimer &&1737 enableProfilerCommitHooks &&1738 finishedWork.mode & ProfileMode1739 ) {1740 try {1741 startLayoutEffectTimer();1742 commitHookEffectListUnmount(1743 HookLayout | HookHasEffect,1744 finishedWork,1745 finishedWork.return,1746 );1747 } finally {1748 recordLayoutEffectDuration(finishedWork);1749 }1750 } else {1751 commitHookEffectListUnmount(1752 HookLayout | HookHasEffect,1753 finishedWork,1754 finishedWork.return,1755 );1756 }1757 return;1758 }1759 case Profiler: {1760 return;1761 }1762 case SuspenseComponent: {1763 commitSuspenseComponent(finishedWork);1764 attachSuspenseRetryListeners(finishedWork);1765 return;1766 }1767 case SuspenseListComponent: {1768 attachSuspenseRetryListeners(finishedWork);1769 return;1770 }1771 case HostRoot: {1772 if (supportsHydration) {1773 const root: FiberRoot = finishedWork.stateNode;1774 if (root.hydrate) {1775 // We've just hydrated. No need to hydrate again.1776 root.hydrate = false;1777 commitHydratedContainer(root.containerInfo);1778 }1779 }1780 break;1781 }1782 case OffscreenComponent:1783 case LegacyHiddenComponent: {1784 return;1785 }1786 }1787 commitContainer(finishedWork);1788 return;1789 }1790 switch (finishedWork.tag) {1791 case FunctionComponent:1792 case ForwardRef:1793 case MemoComponent:1794 case SimpleMemoComponent: {1795 // Layout effects are destroyed during the mutation phase so that all1796 // destroy functions for all fibers are called before any create functions.1797 // This prevents sibling component effects from interfering with each other,1798 // e.g. a destroy function in one component should never override a ref set1799 // by a create function in another component during the same commit.1800 if (1801 enableProfilerTimer &&1802 enableProfilerCommitHooks &&1803 finishedWork.mode & ProfileMode1804 ) {1805 try {1806 startLayoutEffectTimer();1807 commitHookEffectListUnmount(1808 HookLayout | HookHasEffect,1809 finishedWork,1810 finishedWork.return,1811 );1812 } finally {1813 recordLayoutEffectDuration(finishedWork);1814 }1815 } else {1816 commitHookEffectListUnmount(1817 HookLayout | HookHasEffect,1818 finishedWork,1819 finishedWork.return,1820 );1821 }1822 return;1823 }1824 case ClassComponent: {1825 return;1826 }1827 case HostComponent: {1828 const instance: Instance = finishedWork.stateNode;1829 if (instance != null) {1830 // Commit the work prepared earlier.1831 const newProps = finishedWork.memoizedProps;1832 // For hydration we reuse the update path but we treat the oldProps1833 // as the newProps. The updatePayload will contain the real change in1834 // this case.1835 const oldProps = current !== null ? current.memoizedProps : newProps;1836 const type = finishedWork.type;1837 // TODO: Type the updateQueue to be specific to host components.1838 const updatePayload: null | UpdatePayload = (finishedWork.updateQueue: any);1839 finishedWork.updateQueue = null;1840 if (updatePayload !== null) {1841 commitUpdate(1842 instance,1843 updatePayload,1844 type,1845 oldProps,1846 newProps,1847 finishedWork,1848 );1849 }1850 }1851 return;1852 }1853 case HostText: {1854 invariant(1855 finishedWork.stateNode !== null,1856 'This should have a text node initialized. This error is likely ' +1857 'caused by a bug in React. Please file an issue.',1858 );1859 const textInstance: TextInstance = finishedWork.stateNode;1860 const newText: string = finishedWork.memoizedProps;1861 // For hydration we reuse the update path but we treat the oldProps1862 // as the newProps. The updatePayload will contain the real change in1863 // this case.1864 const oldText: string =1865 current !== null ? current.memoizedProps : newText;1866 commitTextUpdate(textInstance, oldText, newText);1867 return;1868 }1869 case HostRoot: {1870 if (supportsHydration) {1871 const root: FiberRoot = finishedWork.stateNode;1872 if (root.hydrate) {1873 // We've just hydrated. No need to hydrate again.1874 root.hydrate = false;1875 commitHydratedContainer(root.containerInfo);1876 }1877 }1878 return;1879 }1880 case Profiler: {1881 return;1882 }1883 case SuspenseComponent: {1884 commitSuspenseComponent(finishedWork);1885 attachSuspenseRetryListeners(finishedWork);1886 return;1887 }1888 case SuspenseListComponent: {1889 attachSuspenseRetryListeners(finishedWork);1890 return;1891 }1892 case IncompleteClassComponent: {1893 return;1894 }1895 case ScopeComponent: {1896 if (enableScopeAPI) {1897 const scopeInstance = finishedWork.stateNode;1898 prepareScopeUpdate(scopeInstance, finishedWork);1899 return;1900 }1901 break;1902 }1903 case OffscreenComponent:1904 case LegacyHiddenComponent: {1905 const newState: OffscreenState | null = finishedWork.memoizedState;1906 const isHidden = newState !== null;1907 hideOrUnhideAllChildren(finishedWork, isHidden);1908 return;1909 }1910 }1911 invariant(1912 false,1913 'This unit of work tag should not have side-effects. This error is ' +1914 'likely caused by a bug in React. Please file an issue.',1915 );1916}1917function commitSuspenseComponent(finishedWork: Fiber) {1918 const newState: SuspenseState | null = finishedWork.memoizedState;1919 if (newState !== null) {1920 markCommitTimeOfFallback();1921 if (supportsMutation) {1922 // Hide the Offscreen component that contains the primary children. TODO:1923 // Ideally, this effect would have been scheduled on the Offscreen fiber1924 // itself. That's how unhiding works: the Offscreen component schedules an1925 // effect on itself. However, in this case, the component didn't complete,1926 // so the fiber was never added to the effect list in the normal path. We1927 // could have appended it to the effect list in the Suspense component's1928 // second pass, but doing it this way is less complicated. This would be1929 // simpler if we got rid of the effect list and traversed the tree, like1930 // we're planning to do.1931 const primaryChildParent: Fiber = (finishedWork.child: any);1932 hideOrUnhideAllChildren(primaryChildParent, true);1933 }1934 }1935 if (enableSuspenseCallback && newState !== null) {1936 const suspenseCallback = finishedWork.memoizedProps.suspenseCallback;1937 if (typeof suspenseCallback === 'function') {1938 const wakeables: Set<Wakeable> | null = (finishedWork.updateQueue: any);1939 if (wakeables !== null) {1940 suspenseCallback(new Set(wakeables));1941 }1942 } else if (__DEV__) {1943 if (suspenseCallback !== undefined) {1944 console.error('Unexpected type for suspenseCallback.');1945 }1946 }1947 }1948}1949function commitSuspenseHydrationCallbacks(1950 finishedRoot: FiberRoot,1951 finishedWork: Fiber,1952) {1953 if (!supportsHydration) {1954 return;1955 }1956 const newState: SuspenseState | null = finishedWork.memoizedState;1957 if (newState === null) {1958 const current = finishedWork.alternate;1959 if (current !== null) {1960 const prevState: SuspenseState | null = current.memoizedState;1961 if (prevState !== null) {1962 const suspenseInstance = prevState.dehydrated;1963 if (suspenseInstance !== null) {1964 commitHydratedSuspenseInstance(suspenseInstance);1965 if (enableSuspenseCallback) {1966 const hydrationCallbacks = finishedRoot.hydrationCallbacks;1967 if (hydrationCallbacks !== null) {1968 const onHydrated = hydrationCallbacks.onHydrated;1969 if (onHydrated) {1970 onHydrated(suspenseInstance);1971 }1972 }1973 }1974 }1975 }1976 }1977 }1978}1979function attachSuspenseRetryListeners(finishedWork: Fiber) {1980 // If this boundary just timed out, then it will have a set of wakeables.1981 // For each wakeable, attach a listener so that when it resolves, React1982 // attempts to re-render the boundary in the primary (pre-timeout) state.1983 const wakeables: Set<Wakeable> | null = (finishedWork.updateQueue: any);1984 if (wakeables !== null) {1985 finishedWork.updateQueue = null;1986 let retryCache = finishedWork.stateNode;1987 if (retryCache === null) {1988 retryCache = finishedWork.stateNode = new PossiblyWeakSet();1989 }1990 wakeables.forEach(wakeable => {1991 // Memoize using the boundary fiber to prevent redundant listeners.1992 let retry = resolveRetryWakeable.bind(null, finishedWork, wakeable);1993 if (!retryCache.has(wakeable)) {1994 if (enableSchedulerTracing) {1995 if (wakeable.__reactDoNotTraceInteractions !== true) {1996 retry = Schedule_tracing_wrap(retry);1997 }1998 }1999 retryCache.add(wakeable);2000 if (enableUpdaterTracking) {2001 if (isDevToolsPresent) {2002 if (inProgressLanes !== null && inProgressRoot !== null) {2003 // If we have pending work still, associate the original updaters with it.2004 restorePendingUpdaters(inProgressRoot, inProgressLanes);2005 } else {2006 throw Error(2007 'Expected finished root and lanes to be set. This is a bug in React.',2008 );2009 }2010 }2011 }2012 wakeable.then(retry, retry);2013 }2014 });2015 }2016}2017// This function detects when a Suspense boundary goes from visible to hidden.2018// It returns false if the boundary is already hidden.2019// TODO: Use an effect tag.2020export function isSuspenseBoundaryBeingHidden(2021 current: Fiber | null,2022 finishedWork: Fiber,2023): boolean {2024 if (current !== null) {2025 const oldState: SuspenseState | null = current.memoizedState;2026 if (oldState === null || oldState.dehydrated !== null) {2027 const newState: SuspenseState | null = finishedWork.memoizedState;2028 return newState !== null && newState.dehydrated === null;2029 }2030 }2031 return false;2032}2033function commitResetTextContent(current: Fiber) {2034 if (!supportsMutation) {2035 return;2036 }2037 resetTextContent(current.stateNode);2038}2039export function commitMutationEffects(2040 root: FiberRoot,2041 firstChild: Fiber,2042 committedLanes: Lanes,2043) {2044 inProgressLanes = committedLanes;2045 inProgressRoot = root;2046 nextEffect = firstChild;2047 commitMutationEffects_begin(root);2048 inProgressLanes = null;2049 inProgressRoot = null;2050}2051function commitMutationEffects_begin(root: FiberRoot) {2052 while (nextEffect !== null) {2053 const fiber = nextEffect;2054 // TODO: Should wrap this in flags check, too, as optimization2055 const deletions = fiber.deletions;2056 if (deletions !== null) {2057 for (let i = 0; i < deletions.length; i++) {2058 const childToDelete = deletions[i];2059 if (__DEV__) {2060 invokeGuardedCallback(2061 null,2062 commitDeletion,2063 null,2064 root,2065 childToDelete,2066 fiber,2067 );2068 if (hasCaughtError()) {2069 const error = clearCaughtError();2070 captureCommitPhaseError(childToDelete, fiber, error);2071 }2072 } else {2073 try {2074 commitDeletion(root, childToDelete, fiber);2075 } catch (error) {2076 captureCommitPhaseError(childToDelete, fiber, error);2077 }2078 }2079 }2080 }2081 const child = fiber.child;2082 if ((fiber.subtreeFlags & MutationMask) !== NoFlags && child !== null) {2083 ensureCorrectReturnPointer(child, fiber);2084 nextEffect = child;2085 } else {2086 commitMutationEffects_complete(root);2087 }2088 }2089}2090function commitMutationEffects_complete(root: FiberRoot) {2091 while (nextEffect !== null) {2092 const fiber = nextEffect;2093 if (__DEV__) {2094 setCurrentDebugFiberInDEV(fiber);2095 invokeGuardedCallback(2096 null,2097 commitMutationEffectsOnFiber,2098 null,2099 fiber,2100 root,2101 );2102 if (hasCaughtError()) {2103 const error = clearCaughtError();2104 captureCommitPhaseError(fiber, fiber.return, error);2105 }2106 resetCurrentDebugFiberInDEV();2107 } else {2108 try {2109 commitMutationEffectsOnFiber(fiber, root);2110 } catch (error) {2111 captureCommitPhaseError(fiber, fiber.return, error);2112 }2113 }2114 const sibling = fiber.sibling;2115 if (sibling !== null) {2116 ensureCorrectReturnPointer(sibling, fiber.return);2117 nextEffect = sibling;2118 return;2119 }2120 nextEffect = fiber.return;2121 }2122}2123function commitMutationEffectsOnFiber(finishedWork: Fiber, root: FiberRoot) {2124 const flags = finishedWork.flags;2125 if (flags & ContentReset) {2126 commitResetTextContent(finishedWork);2127 }2128 if (flags & Ref) {2129 const current = finishedWork.alternate;2130 if (current !== null) {2131 commitDetachRef(current);2132 }2133 if (enableScopeAPI) {2134 // TODO: This is a temporary solution that allowed us to transition away2135 // from React Flare on www.2136 if (finishedWork.tag === ScopeComponent) {2137 commitAttachRef(finishedWork);2138 }2139 }2140 }2141 // The following switch statement is only concerned about placement,2142 // updates, and deletions. To avoid needing to add a case for every possible2143 // bitmap value, we remove the secondary effects from the effect tag and2144 // switch on that value.2145 const primaryFlags = flags & (Placement | Update | Hydrating);2146 outer: switch (primaryFlags) {2147 case Placement: {2148 commitPlacement(finishedWork);2149 // Clear the "placement" from effect tag so that we know that this is2150 // inserted, before any life-cycles like componentDidMount gets called.2151 // TODO: findDOMNode doesn't rely on this any more but isMounted does2152 // and isMounted is deprecated anyway so we should be able to kill this.2153 finishedWork.flags &= ~Placement;2154 break;2155 }2156 case PlacementAndUpdate: {2157 // Placement2158 commitPlacement(finishedWork);2159 // Clear the "placement" from effect tag so that we know that this is2160 // inserted, before any life-cycles like componentDidMount gets called.2161 finishedWork.flags &= ~Placement;2162 // Update2163 const current = finishedWork.alternate;2164 commitWork(current, finishedWork);2165 break;2166 }2167 case Hydrating: {2168 finishedWork.flags &= ~Hydrating;2169 break;2170 }2171 case HydratingAndUpdate: {2172 finishedWork.flags &= ~Hydrating;2173 // Update2174 const current = finishedWork.alternate;2175 commitWork(current, finishedWork);2176 break;2177 }2178 case Update: {2179 const current = finishedWork.alternate;2180 commitWork(current, finishedWork);2181 break;2182 }2183 }2184}2185export function commitLayoutEffects(2186 finishedWork: Fiber,2187 root: FiberRoot,2188 committedLanes: Lanes,2189): void {2190 inProgressLanes = committedLanes;2191 inProgressRoot = root;2192 nextEffect = finishedWork;2193 commitLayoutEffects_begin(finishedWork, root, committedLanes);2194 inProgressLanes = null;2195 inProgressRoot = null;2196}2197function commitLayoutEffects_begin(2198 subtreeRoot: Fiber,2199 root: FiberRoot,2200 committedLanes: Lanes,2201) {2202 // Suspense layout effects semantics don't change for legacy roots.2203 const isModernRoot = (subtreeRoot.mode & ConcurrentMode) !== NoMode;2204 while (nextEffect !== null) {2205 const fiber = nextEffect;2206 const firstChild = fiber.child;2207 if (enableSuspenseLayoutEffectSemantics && isModernRoot) {2208 // Keep track of the current Offscreen stack's state.2209 if (fiber.tag === OffscreenComponent) {2210 const current = fiber.alternate;2211 const wasHidden = current !== null && current.memoizedState !== null;2212 const isHidden = fiber.memoizedState !== null;2213 const newOffscreenSubtreeIsHidden =2214 isHidden || offscreenSubtreeIsHidden;2215 const newOffscreenSubtreeWasHidden =2216 wasHidden || offscreenSubtreeWasHidden;2217 if (2218 newOffscreenSubtreeIsHidden !== offscreenSubtreeIsHidden ||2219 newOffscreenSubtreeWasHidden !== offscreenSubtreeWasHidden2220 ) {2221 const prevOffscreenSubtreeIsHidden = offscreenSubtreeIsHidden;2222 const prevOffscreenSubtreeWasHidden = offscreenSubtreeWasHidden;2223 // Traverse the Offscreen subtree with the current Offscreen as the root.2224 offscreenSubtreeIsHidden = newOffscreenSubtreeIsHidden;2225 offscreenSubtreeWasHidden = newOffscreenSubtreeWasHidden;2226 commitLayoutEffects_begin(2227 fiber, // New root; bubble back up to here and stop.2228 root,2229 committedLanes,2230 );2231 // Restore Offscreen state and resume in our-progress traversal.2232 nextEffect = fiber;2233 offscreenSubtreeIsHidden = prevOffscreenSubtreeIsHidden;2234 offscreenSubtreeWasHidden = prevOffscreenSubtreeWasHidden;2235 commitLayoutMountEffects_complete(subtreeRoot, root, committedLanes);2236 continue;2237 }2238 }2239 }2240 if ((fiber.subtreeFlags & LayoutMask) !== NoFlags && firstChild !== null) {2241 ensureCorrectReturnPointer(firstChild, fiber);2242 nextEffect = firstChild;2243 } else {2244 if (enableSuspenseLayoutEffectSemantics && isModernRoot) {2245 const visibilityChanged =2246 !offscreenSubtreeIsHidden && offscreenSubtreeWasHidden;2247 if (2248 visibilityChanged &&2249 (fiber.subtreeFlags & LayoutStatic) !== NoFlags &&2250 firstChild !== null2251 ) {2252 // We've just shown or hidden a Offscreen tree that contains layout effects.2253 // We only enter this code path for subtrees that are updated,2254 // because newly mounted ones would pass the LayoutMask check above.2255 ensureCorrectReturnPointer(firstChild, fiber);2256 nextEffect = firstChild;2257 continue;2258 }2259 }2260 commitLayoutMountEffects_complete(subtreeRoot, root, committedLanes);2261 }2262 }2263}2264function commitLayoutMountEffects_complete(2265 subtreeRoot: Fiber,2266 root: FiberRoot,2267 committedLanes: Lanes,2268) {2269 // Suspense layout effects semantics don't change for legacy roots.2270 const isModernRoot = (subtreeRoot.mode & ConcurrentMode) !== NoMode;2271 while (nextEffect !== null) {2272 const fiber = nextEffect;2273 if (2274 enableSuspenseLayoutEffectSemantics &&2275 isModernRoot &&2276 offscreenSubtreeWasHidden &&2277 !offscreenSubtreeIsHidden2278 ) {2279 // Inside of an Offscreen subtree that changed visibility during this commit.2280 // If this subtree was hidden, layout effects will have already been destroyed (during mutation phase)2281 // but if it was just shown, we need to (re)create the effects now.2282 if ((fiber.flags & LayoutStatic) !== NoFlags) {2283 switch (fiber.tag) {2284 case FunctionComponent:2285 case ForwardRef:2286 case SimpleMemoComponent: {2287 if (2288 enableProfilerTimer &&2289 enableProfilerCommitHooks &&2290 fiber.mode & ProfileMode2291 ) {2292 try {2293 startLayoutEffectTimer();2294 safelyCallCommitHookLayoutEffectListMount(fiber, fiber.return);2295 } finally {2296 recordLayoutEffectDuration(fiber);2297 }2298 } else {2299 safelyCallCommitHookLayoutEffectListMount(fiber, fiber.return);2300 }2301 break;2302 }2303 case ClassComponent: {2304 const instance = fiber.stateNode;2305 safelyCallComponentDidMount(fiber, fiber.return, instance);2306 break;2307 }2308 }2309 }2310 if ((fiber.flags & RefStatic) !== NoFlags) {2311 switch (fiber.tag) {2312 case ClassComponent:2313 case HostComponent:2314 safelyAttachRef(fiber, fiber.return);2315 break;2316 }2317 }2318 } else if ((fiber.flags & LayoutMask) !== NoFlags) {2319 const current = fiber.alternate;2320 if (__DEV__) {2321 setCurrentDebugFiberInDEV(fiber);2322 invokeGuardedCallback(2323 null,2324 commitLayoutEffectOnFiber,2325 null,2326 root,2327 current,2328 fiber,2329 committedLanes,2330 );2331 if (hasCaughtError()) {2332 const error = clearCaughtError();2333 captureCommitPhaseError(fiber, fiber.return, error);2334 }2335 resetCurrentDebugFiberInDEV();2336 } else {2337 try {2338 commitLayoutEffectOnFiber(root, current, fiber, committedLanes);2339 } catch (error) {2340 captureCommitPhaseError(fiber, fiber.return, error);2341 }2342 }2343 }2344 if (fiber === subtreeRoot) {2345 nextEffect = null;2346 return;2347 }2348 const sibling = fiber.sibling;2349 if (sibling !== null) {2350 ensureCorrectReturnPointer(sibling, fiber.return);2351 nextEffect = sibling;2352 return;2353 }2354 nextEffect = fiber.return;2355 }2356}2357export function commitPassiveMountEffects(2358 root: FiberRoot,2359 finishedWork: Fiber,2360): void {2361 nextEffect = finishedWork;2362 commitPassiveMountEffects_begin(finishedWork, root);2363}2364function commitPassiveMountEffects_begin(subtreeRoot: Fiber, root: FiberRoot) {2365 while (nextEffect !== null) {2366 const fiber = nextEffect;2367 const firstChild = fiber.child;2368 if ((fiber.subtreeFlags & PassiveMask) !== NoFlags && firstChild !== null) {2369 ensureCorrectReturnPointer(firstChild, fiber);2370 nextEffect = firstChild;2371 } else {2372 commitPassiveMountEffects_complete(subtreeRoot, root);2373 }2374 }2375}2376function commitPassiveMountEffects_complete(2377 subtreeRoot: Fiber,2378 root: FiberRoot,2379) {2380 while (nextEffect !== null) {2381 const fiber = nextEffect;2382 if ((fiber.flags & Passive) !== NoFlags) {2383 if (__DEV__) {2384 setCurrentDebugFiberInDEV(fiber);2385 invokeGuardedCallback(2386 null,2387 commitPassiveMountOnFiber,2388 null,2389 root,2390 fiber,2391 );2392 if (hasCaughtError()) {2393 const error = clearCaughtError();2394 captureCommitPhaseError(fiber, fiber.return, error);2395 }2396 resetCurrentDebugFiberInDEV();2397 } else {2398 try {2399 commitPassiveMountOnFiber(root, fiber);2400 } catch (error) {2401 captureCommitPhaseError(fiber, fiber.return, error);2402 }2403 }2404 }2405 if (fiber === subtreeRoot) {2406 nextEffect = null;2407 return;2408 }2409 const sibling = fiber.sibling;2410 if (sibling !== null) {2411 ensureCorrectReturnPointer(sibling, fiber.return);2412 nextEffect = sibling;2413 return;2414 }2415 nextEffect = fiber.return;2416 }2417}2418function commitPassiveMountOnFiber(2419 finishedRoot: FiberRoot,2420 finishedWork: Fiber,2421): void {2422 switch (finishedWork.tag) {2423 case FunctionComponent:2424 case ForwardRef:2425 case SimpleMemoComponent: {2426 if (2427 enableProfilerTimer &&2428 enableProfilerCommitHooks &&2429 finishedWork.mode & ProfileMode2430 ) {2431 startPassiveEffectTimer();2432 try {2433 commitHookEffectListMount(HookPassive | HookHasEffect, finishedWork);2434 } finally {2435 recordPassiveEffectDuration(finishedWork);2436 }2437 } else {2438 commitHookEffectListMount(HookPassive | HookHasEffect, finishedWork);2439 }2440 break;2441 }2442 }2443}2444export function commitPassiveUnmountEffects(firstChild: Fiber): void {2445 nextEffect = firstChild;2446 commitPassiveUnmountEffects_begin();2447}2448function commitPassiveUnmountEffects_begin() {2449 while (nextEffect !== null) {2450 const fiber = nextEffect;2451 const child = fiber.child;2452 if ((nextEffect.flags & ChildDeletion) !== NoFlags) {2453 const deletions = fiber.deletions;2454 if (deletions !== null) {2455 for (let i = 0; i < deletions.length; i++) {2456 const fiberToDelete = deletions[i];2457 nextEffect = fiberToDelete;2458 commitPassiveUnmountEffectsInsideOfDeletedTree_begin(2459 fiberToDelete,2460 fiber,2461 );2462 }2463 if (deletedTreeCleanUpLevel >= 1) {2464 // A fiber was deleted from this parent fiber, but it's still part of2465 // the previous (alternate) parent fiber's list of children. Because2466 // children are a linked list, an earlier sibling that's still alive2467 // will be connected to the deleted fiber via its `alternate`:2468 //2469 // live fiber2470 // --alternate--> previous live fiber2471 // --sibling--> deleted fiber2472 //2473 // We can't disconnect `alternate` on nodes that haven't been deleted2474 // yet, but we can disconnect the `sibling` and `child` pointers.2475 const previousFiber = fiber.alternate;2476 if (previousFiber !== null) {2477 let detachedChild = previousFiber.child;2478 if (detachedChild !== null) {2479 previousFiber.child = null;2480 do {2481 const detachedSibling = detachedChild.sibling;2482 detachedChild.sibling = null;2483 detachedChild = detachedSibling;2484 } while (detachedChild !== null);2485 }2486 }2487 }2488 nextEffect = fiber;2489 }2490 }2491 if ((fiber.subtreeFlags & PassiveMask) !== NoFlags && child !== null) {2492 ensureCorrectReturnPointer(child, fiber);2493 nextEffect = child;2494 } else {2495 commitPassiveUnmountEffects_complete();2496 }2497 }2498}2499function commitPassiveUnmountEffects_complete() {2500 while (nextEffect !== null) {2501 const fiber = nextEffect;2502 if ((fiber.flags & Passive) !== NoFlags) {2503 setCurrentDebugFiberInDEV(fiber);2504 commitPassiveUnmountOnFiber(fiber);2505 resetCurrentDebugFiberInDEV();2506 }2507 const sibling = fiber.sibling;2508 if (sibling !== null) {2509 ensureCorrectReturnPointer(sibling, fiber.return);2510 nextEffect = sibling;2511 return;2512 }2513 nextEffect = fiber.return;2514 }2515}2516function commitPassiveUnmountOnFiber(finishedWork: Fiber): void {2517 switch (finishedWork.tag) {2518 case FunctionComponent:2519 case ForwardRef:2520 case SimpleMemoComponent: {2521 if (2522 enableProfilerTimer &&2523 enableProfilerCommitHooks &&2524 finishedWork.mode & ProfileMode2525 ) {2526 startPassiveEffectTimer();2527 commitHookEffectListUnmount(2528 HookPassive | HookHasEffect,2529 finishedWork,2530 finishedWork.return,2531 );2532 recordPassiveEffectDuration(finishedWork);2533 } else {2534 commitHookEffectListUnmount(2535 HookPassive | HookHasEffect,2536 finishedWork,2537 finishedWork.return,2538 );2539 }2540 break;2541 }2542 }2543}2544function commitPassiveUnmountEffectsInsideOfDeletedTree_begin(2545 deletedSubtreeRoot: Fiber,2546 nearestMountedAncestor: Fiber | null,2547) {2548 while (nextEffect !== null) {2549 const fiber = nextEffect;2550 // Deletion effects fire in parent -> child order2551 // TODO: Check if fiber has a PassiveStatic flag2552 setCurrentDebugFiberInDEV(fiber);2553 commitPassiveUnmountInsideDeletedTreeOnFiber(fiber, nearestMountedAncestor);2554 resetCurrentDebugFiberInDEV();2555 const child = fiber.child;2556 // TODO: Only traverse subtree if it has a PassiveStatic flag. (But, if we2557 // do this, still need to handle `deletedTreeCleanUpLevel` correctly.)2558 if (child !== null) {2559 ensureCorrectReturnPointer(child, fiber);2560 nextEffect = child;2561 } else {2562 commitPassiveUnmountEffectsInsideOfDeletedTree_complete(2563 deletedSubtreeRoot,2564 );2565 }2566 }2567}2568function commitPassiveUnmountEffectsInsideOfDeletedTree_complete(2569 deletedSubtreeRoot: Fiber,2570) {2571 while (nextEffect !== null) {2572 const fiber = nextEffect;2573 const sibling = fiber.sibling;2574 const returnFiber = fiber.return;2575 if (deletedTreeCleanUpLevel >= 2) {2576 // Recursively traverse the entire deleted tree and clean up fiber fields.2577 // This is more aggressive than ideal, and the long term goal is to only2578 // have to detach the deleted tree at the root.2579 detachFiberAfterEffects(fiber);2580 if (fiber === deletedSubtreeRoot) {2581 nextEffect = null;2582 return;2583 }2584 } else {2585 // This is the default branch (level 0). We do not recursively clear all2586 // the fiber fields. Only the root of the deleted subtree.2587 if (fiber === deletedSubtreeRoot) {2588 detachFiberAfterEffects(fiber);2589 nextEffect = null;2590 return;2591 }2592 }2593 if (sibling !== null) {2594 ensureCorrectReturnPointer(sibling, returnFiber);2595 nextEffect = sibling;2596 return;2597 }2598 nextEffect = returnFiber;2599 }2600}2601function commitPassiveUnmountInsideDeletedTreeOnFiber(2602 current: Fiber,2603 nearestMountedAncestor: Fiber | null,2604): void {2605 switch (current.tag) {2606 case FunctionComponent:2607 case ForwardRef:2608 case SimpleMemoComponent: {2609 if (2610 enableProfilerTimer &&2611 enableProfilerCommitHooks &&2612 current.mode & ProfileMode2613 ) {2614 startPassiveEffectTimer();2615 commitHookEffectListUnmount(2616 HookPassive,2617 current,2618 nearestMountedAncestor,2619 );2620 recordPassiveEffectDuration(current);2621 } else {2622 commitHookEffectListUnmount(2623 HookPassive,2624 current,2625 nearestMountedAncestor,2626 );2627 }2628 break;2629 }2630 }2631}2632let didWarnWrongReturnPointer = false;2633function ensureCorrectReturnPointer(fiber, expectedReturnFiber) {2634 if (__DEV__) {2635 if (!didWarnWrongReturnPointer && fiber.return !== expectedReturnFiber) {2636 didWarnWrongReturnPointer = true;2637 console.error(2638 'Internal React error: Return pointer is inconsistent ' +2639 'with parent.',2640 );2641 }2642 }2643 // TODO: Remove this assignment once we're confident that it won't break2644 // anything, by checking the warning logs for the above invariant2645 fiber.return = expectedReturnFiber;2646}2647function invokeLayoutEffectMountInDEV(fiber: Fiber): void {2648 if (__DEV__ && enableStrictEffects) {2649 // We don't need to re-check StrictEffectsMode here.2650 // This function is only called if that check has already passed.2651 switch (fiber.tag) {2652 case FunctionComponent:2653 case ForwardRef:2654 case SimpleMemoComponent: {2655 invokeGuardedCallback(2656 null,2657 commitHookEffectListMount,2658 null,2659 HookLayout | HookHasEffect,2660 fiber,2661 );2662 if (hasCaughtError()) {2663 const mountError = clearCaughtError();2664 captureCommitPhaseError(fiber, fiber.return, mountError);2665 }2666 break;2667 }2668 case ClassComponent: {2669 const instance = fiber.stateNode;2670 invokeGuardedCallback(null, instance.componentDidMount, instance);2671 if (hasCaughtError()) {2672 const mountError = clearCaughtError();2673 captureCommitPhaseError(fiber, fiber.return, mountError);2674 }2675 break;2676 }2677 }2678 }2679}2680function invokePassiveEffectMountInDEV(fiber: Fiber): void {2681 if (__DEV__ && enableStrictEffects) {2682 // We don't need to re-check StrictEffectsMode here.2683 // This function is only called if that check has already passed.2684 switch (fiber.tag) {2685 case FunctionComponent:2686 case ForwardRef:2687 case SimpleMemoComponent: {2688 invokeGuardedCallback(2689 null,2690 commitHookEffectListMount,2691 null,2692 HookPassive | HookHasEffect,2693 fiber,2694 );2695 if (hasCaughtError()) {2696 const mountError = clearCaughtError();2697 captureCommitPhaseError(fiber, fiber.return, mountError);2698 }2699 break;2700 }2701 }2702 }2703}2704function invokeLayoutEffectUnmountInDEV(fiber: Fiber): void {2705 if (__DEV__ && enableStrictEffects) {2706 // We don't need to re-check StrictEffectsMode here.2707 // This function is only called if that check has already passed.2708 switch (fiber.tag) {2709 case FunctionComponent:2710 case ForwardRef:2711 case SimpleMemoComponent: {2712 invokeGuardedCallback(2713 null,2714 commitHookEffectListUnmount,2715 null,2716 HookLayout | HookHasEffect,2717 fiber,2718 fiber.return,2719 );2720 if (hasCaughtError()) {2721 const unmountError = clearCaughtError();2722 captureCommitPhaseError(fiber, fiber.return, unmountError);2723 }2724 break;2725 }2726 case ClassComponent: {2727 const instance = fiber.stateNode;2728 if (typeof instance.componentWillUnmount === 'function') {2729 invokeGuardedCallback(2730 null,2731 safelyCallComponentWillUnmount,2732 null,2733 fiber,2734 fiber.return,2735 instance,2736 );2737 if (hasCaughtError()) {2738 const unmountError = clearCaughtError();2739 captureCommitPhaseError(fiber, fiber.return, unmountError);2740 }2741 }2742 break;2743 }2744 }2745 }2746}2747function invokePassiveEffectUnmountInDEV(fiber: Fiber): void {2748 if (__DEV__ && enableStrictEffects) {2749 // We don't need to re-check StrictEffectsMode here.2750 // This function is only called if that check has already passed.2751 switch (fiber.tag) {2752 case FunctionComponent:2753 case ForwardRef:2754 case SimpleMemoComponent: {2755 invokeGuardedCallback(2756 null,2757 commitHookEffectListUnmount,2758 null,2759 HookPassive | HookHasEffect,2760 fiber,2761 fiber.return,2762 );2763 if (hasCaughtError()) {2764 const unmountError = clearCaughtError();2765 captureCommitPhaseError(fiber, fiber.return, unmountError);2766 }2767 break;2768 }2769 }2770 }2771}2772export {2773 commitResetTextContent,2774 commitPlacement,2775 commitDeletion,2776 commitWork,2777 commitAttachRef,2778 commitDetachRef,2779 invokeLayoutEffectMountInDEV,...
renderer.js
Source:renderer.js
...122 try{123 commitMutationEffects(root, renderPriorityLevel);124 } catch(error) {125 invariant(nextEffect !== null, 'Should be working on an effect.');126 captureCommitPhaseError(nextEffect, error);127 nextEffect = nextEffect.nextEffect;128 }129 } while (nextEffect !== null)130 // mutationé¶æ®µæ ¸å¿131 function commitMutationEffects(){132 root: FiberRoot, 133 renderPriorityLevel134 } {135 // éåeffectList136 while(nextEffect !== null) {137 const effectTag = nextEffect.effectTag;138 // æ ¹æ®ContentReset effectTagéç½®æåèç¹139 if(effectTag & ContentReset){140 commitResetTextContent(nextEffect);141 }142 // æ´æ°ref143 if(effectTag & Ref){144 const current = nextEffect.alternate;145 if(current !== null){146 commitDetachRef(current);147 }148 }149 // æ ¹æ®effectTagåå«å¤ç150 const primaryEffectTag = effectTag & (Placement | Update | Deletion | Hydrating)151 switch (primaryEffectTag) {152 // æå
¥DOM153 case Placement: {154 commitPlacement(nextEffect);155 nextEffect.effectTag &= ~Placement; // è®°å½æ§è¡åçç¶æ156 break;157 }158 // æå
¥DOM并æ´æ°DOM159 case PlacementAndUpdate: {160 commitPlacement(nextEffect);161 nextEffect.effectTag &= ~Placement;162 // æ´æ°DOM163 const current = nextEffect.alternate;164 commitWork(current, nextEffect);165 break;166 }167 // SSRç¸å
³æä½ ...ç¥168 case Update: {169 // æ´æ°DOM170 const current = nextEffect.alternate;171 commitWork(current, nextEffect);172 break;173 }174 case Deletion: {175 // å é¤DOM176 commitDeletion(root, nextEffect, renderPriortyLevel);177 break;178 }179 }180 nextEffect = nextEffect.nextEffect;181 }182 }183 function commitPlacement(nextEffect){184 // è·åç¶çº§DOMèç¹ãå
¶ä¸finishedWorkä¸ºä¼ å
¥çFiberèç¹185 const parentFiber = getHostParentFiber(finishedWork);186 // ç¶çº§DOMèç¹187 const parentStateNode = parentFiber.stateNode;188 // è·åFiberèç¹çDOMå
å¼èç¹189 const before = getHostSibling(finishedWork);190 // æ ¹æ®å
å¼èç¹æ¯å¦åå¨å³å®è°ç¨ parentNode.insertBefore æ parentNode.appendChildæ§è¡DOMæå
¥æä½191 if(isContainer){192 insertOrAppendPlacementNodeIntoContainer(finishedWork, before, parent);193 } else {194 insertOrAppendPlacementNode(finishedWork, before, parent)195 }196 }197 function commitUpdate() {198 // æ ¹æ®Fiber.Tagåå«å¤ç199 // tag为FunctionComponentçæ
åµ200 // 该æ¹æ³ä¼éåeffectList æ§è¡ææuseLayoutEffect hookçéæ¯å½æ°201 commitHookEffectListUnmonut()202 // tag为HostComponentçæ
åµ203 for(let i = 0; i < updatePayload.length; i += 2){204 const propKey = updatePayload[i];205 const propValue = updatePayload[i + 1];206 // å¤ç style207 if(propKey === STYLE){208 setValueForStyles(domElement, propValue);209 } else if (propKey === DANGEROUSLY_SET_INNER_HTML){210 setInnerHtml(domElement, propValue);211 } else if (propKey === CHILDREN) {212 setTextContent(domElement, propValue)213 } else {214 // å¤çå©ä½props215 setValueForProperty(domElement, propKey, propValuem, isCustomComponentTag);216 }217 }218 }219 function commitDeletion() {220 /**221 * éå½è°ç¨ClassComponentçcomponentWillUnmountï¼ä»é¡µé¢ç§»é¤DOM222 * 解ç»ref223 * è°åº¦useEffectçéæ¯å½æ°224 */225 }226 // layout é¶æ®µ227 /**228 * è¿ä¸ªé¶æ®µæ¯å¨DOMå·²ç»æ¸²æå®æåæ§è¡çï¼å¨è¿ä¸ªé¶æ®µè§¦åççå½å¨æåhookå¯ä»¥ç´æ¥è®¿é®å·²æ¹åçDOM229 */230 root.current = finishedWork;231 nextEffect = firstEffect;232 do{233 try{234 commitLayoutEffects(root, lanes);235 } catch(error) {236 invariant(nextEffect !== null, "Should be working on an effect.");237 captureCommitPhaseError(nextEffect, error);238 nextEffect = nextEffect.nextEffect;239 }240 } while (nextEffect !== null);241 nextEffect = null;242 function commitLayoutEffects(root: FiberRoot, committedLanes: Lanes){243 while(nextEffect !== null){244 const effectTag = nextEffect.effectTag;245 // è°ç¨çå½å¨æé©ååhook246 if(effectTag & (Update | Callback)){247 const current = nextEffect.alternate;248 commitLayoutEffectOnFiber(root, current, nextEffect, committedLanes);249 }250 // èµå¼ref251 if(effectTag & Ref) {252 commitAttachRef(nextEffect);253 }254 nextEffect = nextEffect.nextEffect255 }256 }257 function commitLayoutEffectOnFiber() {258 // æ ¹æ®fiber.tag对ä¸åç±»åèç¹åå«å¤ç259 // 对äºClassComponentï¼ ä¼éè¿current === null åºåæ¯mountè¿æ¯updateï¼è°ç¨componentDidMount æcomponentDidUpdate260 // 触åç¶ææ´æ°çthis.setStateå¦æèµå¼äºç¬¬äºä¸ªåæ°åè°å½æ°ï¼ä¹ä¼å¨æ¤æ¶è°ç¨ã261 // 对äºFunctionCompnentåç¸å
³ç±»å262 switch (finishedWork.tag) {263 // 以ä¸é½æ¯FunctionComponentåç¸å
³ç±»å264 case FunctionComponent:265 case ForwardRef:266 case SimpleMemoComponent:267 case Block: {268 // æ§è¡useLayoutEffectçåè°å½æ°269 commmitHookEffectListMount(HookLayout | HookHasEffect, finishedWork);270 // è°åº¦useEffectçéæ¯å½æ°ä¸åè°å½æ°271 schedulePassiveEffects(finishedWork);272 return;273 }274 }275 }276 // æ·±å
¥flushPassiveEffects ï¼ä¸æææ为ï¼æ¸
æ´è¢«å¨ææï¼277 // flushPassiveEffectså
é¨ä¼è®¾ç½®ä¼å
级ï¼å¹¶æ§è¡flushPassiveEffectsImplï¼Implçæææ¯å®ç°ï¼å³implementationçç®å278 /**279 * flushPassiveEffectsImpl主è¦åä¸ä»¶äº280 * 1. è°ç¨è¯¥useEffectå¨ä¸ä¸æ¬¡renderæ¶çéæ¯å½æ°281 * 2. è°ç¨è¯¥useEffectå¨æ¬æ¬¡renderæ¶çåè°å½æ°282 * 3. å¦æåå¨åæ¥ä»»å¡ï¼ä¸éè¦çå¾
ä¸æ¬¡äºä»¶å¾ªç¯çå®ä»»å¡ï¼æåæ§è¡283 * 1,2两æ¥ä¼å¨layouté¶æ®µä¹åå¼æ¥æ§è¡284 */285// é¶æ®µä¸ï¼éæ¯å½æ°çæ§è¡286/**287 * useEffectä¼ä¿è¯å¨æ§è¡å®å
¨é¨çéæ¯å½æ°ä¹åï¼åæ§è¡åè°å½æ°288 */289// pendingPassiveHookEffectsUnmountä¸ä¿åäºææéè¦æ§è¡éæ¯çuseEffect290const unmountEffects = pendingPassiveHookEffectsUnmount;291pendingPassiveHookEffectsUnmount = [];292for (let i = 0; i < unmountEffects.length; i += 2) {293 const effect = ((unmountEffects[i]: any): HookEffect);294 const fiber = ((unmountEffects[i + 1]: any): Fiber);295 const distroy = effect.distroy;296 effect.distroy = undefined;297 if(typeof destroy == 'function') {298 // éæ¯å½æ°åå¨åæ§è¡299 try {300 destroy();301 } catch (error) {302 captureCommitPhaseError(fiber, error);303 }304 }305}306function schedulePassiveEffects(finishedWork: Fiber) {307 const updateQueue: FunctionComponentUpdateQueue | null = (finishedWork.updateQueue: any);308 const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;309 if(lastEffect !== null) {310 const firstEffect = lastEffect.next;311 let effect = firstEffect;312 do {313 const { next, tag } = effect;314 if(315 (tag & HookPassive) !== NoHookEffect &&316 (tag & HookHasEffect) !== NoHookEffect317 ) {318 // åpendingPassiveHookEffectsUnmountæ°ç»å
pushè¦éæ¯çeffect319 enqueuePendingPassiveHookEffectUnmount(finishedWork, effect);320 // åpendingPassiveHookEffectMountæ°ç»å
pushè¦æ§è¡åè°çeffect321 enqueuePendingPassiveHookEffectMount(finishedWork, effect);322 }323 effect = next;324 } while ( effect !== firstEffect );325 }326}327// é¶æ®µäºï¼ åè°å½æ°çæ§è¡328const mountEffects = pendingPassiveHookEffectsMount;329pendingPassiveHookEffectsMount = [];330for(let i = 0; i < mountEffects.length; i += 2) {331 const effect = ((mountEffects[i]: any): HookEffect);332 const fiber = ((mountEffects[i + 1]: any): Fiber);333 try {334 const create = effect.create;335 effect.distroy = create();336 } catch (error) {337 captureCommitPhaseError(fiber, error);338 }...
Using AI Code Generation
1const { chromium } = require('playwright');2const { captureCommitPhaseError } = require('playwright/lib/server/supplements/recorder/recorderSupplement.js');3(async () => {4 const browser = await chromium.launch();5 const context = await browser.newContext();6 const page = await context.newPage();7 captureCommitPhaseError((error) => {8 console.log(error);9 });10 await browser.close();11})();12{13 ' at dispatchError (/Users/raghavendra/Downloads/playwright-test/node_modules/playwright/lib/server/supplements/recorder/recorderSupplement.js:40:27)\n' +14 ' at dispatchError (/Users/raghavendra/Downloads/playwright-test/node_modules/playwright/lib/server/supplements/recorder/recorderSupplement.js:40:27)\n' +15 ' at dispatchError (/Users/raghavendra/Downloads/playwright-test/node_modules/playwright/lib/server/supplements/recorder/recorderSupplement.js:40:27)\n' +
Using AI Code Generation
1const { captureCommitPhaseError } = require('playwright/lib/server/trace/recorder');2const { chromium } = require('playwright');3(async () => {4 const browser = await chromium.launch();5 const page = await browser.newPage();6 captureCommitPhaseError(new Error('Custom Error'));7 await browser.close();8})();
Using AI Code Generation
1const playwright = require('playwright');2const { captureCommitPhaseError } = require('playwright-core/lib/server/supplements/recorder/recorderSupplement');3const { chromium } = require('playwright-chromium');4(async () => {5 const browser = await chromium.launch();6 const page = await browser.newPage();
Using AI Code Generation
1const { captureCommitPhaseError } = require('@playwright/test/lib/server/trace/recorder/recorderApp');2const { chromium } = require('playwright');3const { test } = require('@playwright/test');4test('test', async ({ page }) => {5 await captureCommitPhaseError(page);6});7const { chromium } = require('playwright');8const { captureCommitPhaseError } = require('@playwright/test/lib/server/trace/recorder/recorderApp');9module.exports = {10 {11 use: {12 launchOptions: {13 },14 },15 async beforeEach({ page }) {16 await captureCommitPhaseError(page);17 },18 },19};20import { chromium } from 'playwright';21import { captureCommitPhaseError } from '@playwright/test/lib/server/trace/recorder/recorderApp';22export default {23 use: {24 launchOptions: {25 },26 },27 async beforeEach({ page }) {28 await captureCommitPhaseError(page);29 },30};31const { chromium } = require('playwright');32const { captureCommitPhaseError } = require('@playwright/test/lib/server/trace/recorder/recorderApp');33module.exports = {34 use: {35 launchOptions: {36 },37 },38 async beforeEach({ page }) {39 await captureCommitPhaseError(page);40 },41};42import { chromium } from '
Using AI Code Generation
1const { chromium } = require('playwright');2(async () => {3 const browser = await chromium.launch();4 const page = await browser.newPage();5 await page.click('text=Learn React');6 await page.click('text=Hello World');7 await browser.close();8})();9const { chromium } = require('playwright');10(async () => {11 const browser = await chromium.launch();12 const page = await browser.newPage();13 await page.click('text=Learn React');14 await page.click('text=Hello World');15 await browser.close();16})();
Using AI Code Generation
1const { captureCommitPhaseError } = require('playwright/lib/server/supplements/utils/stackTrace');2const { captureCommitPhaseError } = require('playwright/lib/server/supplements/utils/stackTrace');3const { captureCommitPhaseError } = require('playwright/lib/server/supplements/utils/stackTrace');4const { captureCommitPhaseError } = require('playwright/lib/server/supplements/utils/stackTrace');5const { captureCommitPhaseError } = require('playwright/lib/server/supplements/utils/stackTrace');6const { captureCommitPhaseError } = require('playwright/lib/server/supplements/utils/stackTrace');7const { captureCommitPhaseError } = require('playwright/lib/server/supplements/utils/stackTrace');8const { captureCommitPhaseError } = require('playwright/lib/server
Using AI Code Generation
1const playwright = require('playwright');2const { captureCommitPhaseError } = playwright.internal;3const { Page } = require('playwright/lib/server/page');4Page.prototype._onBindingCalled = function (source, payload, ...args) {5 if (source === '__playwright__commit__') {6 const error = captureCommitPhaseError(payload);7 if (error) {8 console.log(error);9 }10 }11};12const { chromium } = require('playwright');13(async () => {14 const browser = await chromium.launch();
Using AI Code Generation
1const playwright = require('playwright');2const { captureCommitPhaseError } = require('playwright/lib/protocol/protocol');3const { chromium } = require('playwright');4const { assert } = require('chai');5const { test, expect } = require('@playwright/test');6test('capture error from commit phase', async ({}) => {7 const browser = await chromium.launch();8 const page = await browser.newPage();9 await page.click('text=Click Me');10 const error = await captureCommitPhaseError(page);11 assert.equal(error, 'Error: Error from commit phase');12 await browser.close();13});14const { test, expect } = require('@playwright/test');15test('capture error from commit phase', async ({}) => {16 const page = await context.newPage();17 await page.click('text=Click Me');18 const error = await page.evaluate(() => {19 return window.error;20 });21 expect(error).toBe('Error: Error from commit phase');22});
Using AI Code Generation
1const { captureCommitPhaseError } = window['playwright'];2const error = captureCommitPhaseError();3console.log(error);4const { captureCommitPhaseError } = window['playwright'];5const error = captureCommitPhaseError();6console.log(error);7const { captureCommitPhaseError } = window['playwright'];8const error = captureCommitPhaseError();9console.log(error);10const { captureCommitPhaseError } = window['playwright'];11const error = captureCommitPhaseError();12console.log(error);13const { captureCommitPhaseError } = window['playwright'];14const error = captureCommitPhaseError();15console.log(error);16const { captureCommitPhaseError } = window['playwright'];17const error = captureCommitPhaseError();18console.log(error);19const { captureCommitPhaseError } = window['playwright'];20const error = captureCommitPhaseError();21console.log(error);22const { captureCommitPhaseError } = window['playwright'];23const error = captureCommitPhaseError();24console.log(error);25const { captureCommitPhaseError } = window['playwright'];26const error = captureCommitPhaseError();27console.log(error);
LambdaTest’s Playwright tutorial will give you a broader idea about the Playwright automation framework, its unique features, and use cases with examples to exceed your understanding of Playwright testing. This tutorial will give A to Z guidance, from installing the Playwright framework to some best practices and advanced concepts.
Get 100 minutes of automation test minutes FREE!!