How to use captureCommitPhaseError method in Playwright Internal

Best JavaScript code snippet using playwright-internal

ReactFiberCommitWork.new.js

Source:ReactFiberCommitWork.new.js Github

copy

Full Screen

...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....

Full Screen

Full Screen

ReactFiberCommitWork.old.js

Source:ReactFiberCommitWork.old.js Github

copy

Full Screen

...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,...

Full Screen

Full Screen

renderer.js

Source:renderer.js Github

copy

Full Screen

...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 }...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

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' +

Full Screen

Using AI Code Generation

copy

Full Screen

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})();

Full Screen

Using AI Code Generation

copy

Full Screen

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();

Full Screen

Using AI Code Generation

copy

Full Screen

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 '

Full Screen

Using AI Code Generation

copy

Full Screen

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})();

Full Screen

Using AI Code Generation

copy

Full Screen

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

Full Screen

Using AI Code Generation

copy

Full Screen

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();

Full Screen

Using AI Code Generation

copy

Full Screen

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});

Full Screen

Using AI Code Generation

copy

Full Screen

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);

Full Screen

Playwright tutorial

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.

Chapters:

  1. What is Playwright : Playwright is comparatively new but has gained good popularity. Get to know some history of the Playwright with some interesting facts connected with it.
  2. How To Install Playwright : Learn in detail about what basic configuration and dependencies are required for installing Playwright and run a test. Get a step-by-step direction for installing the Playwright automation framework.
  3. Playwright Futuristic Features: Launched in 2020, Playwright gained huge popularity quickly because of some obliging features such as Playwright Test Generator and Inspector, Playwright Reporter, Playwright auto-waiting mechanism and etc. Read up on those features to master Playwright testing.
  4. What is Component Testing: Component testing in Playwright is a unique feature that allows a tester to test a single component of a web application without integrating them with other elements. Learn how to perform Component testing on the Playwright automation framework.
  5. Inputs And Buttons In Playwright: Every website has Input boxes and buttons; learn about testing inputs and buttons with different scenarios and examples.
  6. Functions and Selectors in Playwright: Learn how to launch the Chromium browser with Playwright. Also, gain a better understanding of some important functions like “BrowserContext,” which allows you to run multiple browser sessions, and “newPage” which interacts with a page.
  7. Handling Alerts and Dropdowns in Playwright : Playwright interact with different types of alerts and pop-ups, such as simple, confirmation, and prompt, and different types of dropdowns, such as single selector and multi-selector get your hands-on with handling alerts and dropdown in Playright testing.
  8. Playwright vs Puppeteer: Get to know about the difference between two testing frameworks and how they are different than one another, which browsers they support, and what features they provide.
  9. Run Playwright Tests on LambdaTest: Playwright testing with LambdaTest leverages test performance to the utmost. You can run multiple Playwright tests in Parallel with the LammbdaTest test cloud. Get a step-by-step guide to run your Playwright test on the LambdaTest platform.
  10. Playwright Python Tutorial: Playwright automation framework support all major languages such as Python, JavaScript, TypeScript, .NET and etc. However, there are various advantages to Python end-to-end testing with Playwright because of its versatile utility. Get the hang of Playwright python testing with this chapter.
  11. Playwright End To End Testing Tutorial: Get your hands on with Playwright end-to-end testing and learn to use some exciting features such as TraceViewer, Debugging, Networking, Component testing, Visual testing, and many more.
  12. Playwright Video Tutorial: Watch the video tutorials on Playwright testing from experts and get a consecutive in-depth explanation of Playwright automation testing.

Run Playwright Internal automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful