How to use resolveRetryWakeable method in Playwright Internal

Best JavaScript code snippet using playwright-internal

ReactFiberCommitWork.js

Source:ReactFiberCommitWork.js Github

copy

Full Screen

1/**2 * Copyright (c) Facebook, Inc. and its affiliates.3 *4 * This source code is licensed under the MIT license found in the5 * LICENSE file in the root directory of this source tree.6 *7 * @flow8 */9import type {10 Instance,11 TextInstance,12 SuspenseInstance,13 Container,14 ChildSet,15 UpdatePayload,16} from './ReactFiberHostConfig';17import type {Fiber} from './ReactFiber';18import type {FiberRoot} from './ReactFiberRoot';19import type {ExpirationTime} from './ReactFiberExpirationTime';20import type {SuspenseState} from './ReactFiberSuspenseComponent';21import type {FunctionComponentUpdateQueue} from './ReactFiberHooks';22import type {Wakeable} from 'shared/ReactTypes';23import type {ReactPriorityLevel} from './SchedulerWithReactIntegration';24import {unstable_wrap as Schedule_tracing_wrap} from 'scheduler/tracing';25import {26 deferPassiveEffectCleanupDuringUnmount,27 enableSchedulerTracing,28 enableProfilerTimer,29 enableProfilerCommitHooks,30 enableSuspenseServerRenderer,31 enableDeprecatedFlareAPI,32 enableFundamentalAPI,33 enableSuspenseCallback,34 enableScopeAPI,35 runAllPassiveEffectDestroysBeforeCreates,36 enableUseEventAPI,37} from 'shared/ReactFeatureFlags';38import {39 FunctionComponent,40 ForwardRef,41 ClassComponent,42 HostRoot,43 HostComponent,44 HostText,45 HostPortal,46 Profiler,47 SuspenseComponent,48 DehydratedFragment,49 IncompleteClassComponent,50 MemoComponent,51 SimpleMemoComponent,52 SuspenseListComponent,53 FundamentalComponent,54 ScopeComponent,55 Block,56} from './ReactWorkTags';57import {58 invokeGuardedCallback,59 hasCaughtError,60 clearCaughtError,61} from 'shared/ReactErrorUtils';62import {63 NoEffect,64 ContentReset,65 Placement,66 Snapshot,67 Update,68 Passive,69} from './ReactSideEffectTags';70import getComponentName from 'shared/getComponentName';71import invariant from 'shared/invariant';72import {onCommitUnmount} from './ReactFiberDevToolsHook';73import {getStackByFiberInDevAndProd} from './ReactCurrentFiber';74import {resolveDefaultProps} from './ReactFiberLazyComponent';75import {76 getCommitTime,77 recordLayoutEffectDuration,78 recordPassiveEffectDuration,79 startLayoutEffectTimer,80 startPassiveEffectTimer,81} from './ReactProfilerTimer';82import {ProfileMode} from './ReactTypeOfMode';83import {commitUpdateQueue} from './ReactUpdateQueue';84import {85 getPublicInstance,86 supportsMutation,87 supportsPersistence,88 supportsHydration,89 commitMount,90 commitUpdate,91 resetTextContent,92 commitTextUpdate,93 appendChild,94 appendChildToContainer,95 insertBefore,96 insertInContainerBefore,97 removeChild,98 removeChildFromContainer,99 clearSuspenseBoundary,100 clearSuspenseBoundaryFromContainer,101 replaceContainerChildren,102 createContainerChildSet,103 hideInstance,104 hideTextInstance,105 unhideInstance,106 unhideTextInstance,107 unmountFundamentalComponent,108 updateFundamentalComponent,109 commitHydratedContainer,110 commitHydratedSuspenseInstance,111 beforeRemoveInstance,112} from './ReactFiberHostConfig';113import {114 captureCommitPhaseError,115 resolveRetryWakeable,116 markCommitTimeOfFallback,117 enqueuePendingPassiveHookEffectMount,118 enqueuePendingPassiveHookEffectUnmount,119 enqueuePendingPassiveProfilerEffect,120} from './ReactFiberWorkLoop';121import {122 NoEffect as NoHookEffect,123 HasEffect as HookHasEffect,124 Layout as HookLayout,125 Passive as HookPassive,126} from './ReactHookEffectTags';127import {didWarnAboutReassigningProps} from './ReactFiberBeginWork';128import {runWithPriority, NormalPriority} from './SchedulerWithReactIntegration';129import {130 updateDeprecatedEventListeners,131 unmountDeprecatedResponderListeners,132} from './ReactFiberDeprecatedEvents';133let didWarnAboutUndefinedSnapshotBeforeUpdate: Set<mixed> | null = null;134if (__DEV__) {135 didWarnAboutUndefinedSnapshotBeforeUpdate = new Set();136}137const PossiblyWeakSet = typeof WeakSet === 'function' ? WeakSet : Set;138const callComponentWillUnmountWithTimer = function(current, instance) {139 instance.props = current.memoizedProps;140 instance.state = current.memoizedState;141 if (142 enableProfilerTimer &&143 enableProfilerCommitHooks &&144 current.mode & ProfileMode145 ) {146 try {147 startLayoutEffectTimer();148 instance.componentWillUnmount();149 } finally {150 recordLayoutEffectDuration(current);151 }152 } else {153 instance.componentWillUnmount();154 }155};156// Capture errors so they don't interrupt unmounting.157function safelyCallComponentWillUnmount(current, instance) {158 if (__DEV__) {159 invokeGuardedCallback(160 null,161 callComponentWillUnmountWithTimer,162 null,163 current,164 instance,165 );166 if (hasCaughtError()) {167 const unmountError = clearCaughtError();168 captureCommitPhaseError(current, unmountError);169 }170 } else {171 try {172 callComponentWillUnmountWithTimer(current, instance);173 } catch (unmountError) {174 captureCommitPhaseError(current, unmountError);175 }176 }177}178function safelyDetachRef(current: Fiber) {179 const ref = current.ref;180 if (ref !== null) {181 if (typeof ref === 'function') {182 if (__DEV__) {183 invokeGuardedCallback(null, ref, null, null);184 if (hasCaughtError()) {185 const refError = clearCaughtError();186 captureCommitPhaseError(current, refError);187 }188 } else {189 try {190 ref(null);191 } catch (refError) {192 captureCommitPhaseError(current, refError);193 }194 }195 } else {196 ref.current = null;197 }198 }199}200function safelyCallDestroy(current, destroy) {201 if (__DEV__) {202 invokeGuardedCallback(null, destroy, null);203 if (hasCaughtError()) {204 const error = clearCaughtError();205 captureCommitPhaseError(current, error);206 }207 } else {208 try {209 destroy();210 } catch (error) {211 captureCommitPhaseError(current, error);212 }213 }214}215function commitBeforeMutationLifeCycles(216 current: Fiber | null,217 finishedWork: Fiber,218): void {219 switch (finishedWork.tag) {220 case FunctionComponent:221 case ForwardRef:222 case SimpleMemoComponent:223 case Block: {224 return;225 }226 case ClassComponent: {227 if (finishedWork.effectTag & Snapshot) {228 if (current !== null) {229 const prevProps = current.memoizedProps;230 const prevState = current.memoizedState;231 const instance = finishedWork.stateNode;232 // We could update instance props and state here,233 // but instead we rely on them being set during last render.234 // TODO: revisit this when we implement resuming.235 if (__DEV__) {236 if (237 finishedWork.type === finishedWork.elementType &&238 !didWarnAboutReassigningProps239 ) {240 if (instance.props !== finishedWork.memoizedProps) {241 console.error(242 'Expected %s props to match memoized props before ' +243 'getSnapshotBeforeUpdate. ' +244 'This might either be because of a bug in React, or because ' +245 'a component reassigns its own `this.props`. ' +246 'Please file an issue.',247 getComponentName(finishedWork.type) || 'instance',248 );249 }250 if (instance.state !== finishedWork.memoizedState) {251 console.error(252 'Expected %s state to match memoized state before ' +253 'getSnapshotBeforeUpdate. ' +254 'This might either be because of a bug in React, or because ' +255 'a component reassigns its own `this.state`. ' +256 'Please file an issue.',257 getComponentName(finishedWork.type) || 'instance',258 );259 }260 }261 }262 const snapshot = instance.getSnapshotBeforeUpdate(263 finishedWork.elementType === finishedWork.type264 ? prevProps265 : resolveDefaultProps(finishedWork.type, prevProps),266 prevState,267 );268 if (__DEV__) {269 const didWarnSet = ((didWarnAboutUndefinedSnapshotBeforeUpdate: any): Set<mixed>);270 if (snapshot === undefined && !didWarnSet.has(finishedWork.type)) {271 didWarnSet.add(finishedWork.type);272 console.error(273 '%s.getSnapshotBeforeUpdate(): A snapshot value (or null) ' +274 'must be returned. You have returned undefined.',275 getComponentName(finishedWork.type),276 );277 }278 }279 instance.__reactInternalSnapshotBeforeUpdate = snapshot;280 }281 }282 return;283 }284 case HostRoot:285 case HostComponent:286 case HostText:287 case HostPortal:288 case IncompleteClassComponent:289 // Nothing to do for these component types290 return;291 }292 invariant(293 false,294 'This unit of work tag should not have side-effects. This error is ' +295 'likely caused by a bug in React. Please file an issue.',296 );297}298function commitHookEffectListUnmount(tag: number, finishedWork: Fiber) {299 const updateQueue: FunctionComponentUpdateQueue | null = (finishedWork.updateQueue: any);300 const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;301 if (lastEffect !== null) {302 const firstEffect = lastEffect.next;303 let effect = firstEffect;304 do {305 if ((effect.tag & tag) === tag) {306 // Unmount307 const destroy = effect.destroy;308 effect.destroy = undefined;309 if (destroy !== undefined) {310 destroy();311 }312 }313 effect = effect.next;314 } while (effect !== firstEffect);315 }316}317function commitHookEffectListMount(tag: number, finishedWork: Fiber) {318 const updateQueue: FunctionComponentUpdateQueue | null = (finishedWork.updateQueue: any);319 const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;320 if (lastEffect !== null) {321 const firstEffect = lastEffect.next;322 let effect = firstEffect;323 do {324 if ((effect.tag & tag) === tag) {325 // Mount326 const create = effect.create;327 effect.destroy = create();328 if (__DEV__) {329 const destroy = effect.destroy;330 if (destroy !== undefined && typeof destroy !== 'function') {331 let addendum;332 if (destroy === null) {333 addendum =334 ' You returned null. If your effect does not require clean ' +335 'up, return undefined (or nothing).';336 } else if (typeof destroy.then === 'function') {337 addendum =338 '\n\nIt looks like you wrote useEffect(async () => ...) or returned a Promise. ' +339 'Instead, write the async function inside your effect ' +340 'and call it immediately:\n\n' +341 'useEffect(() => {\n' +342 ' async function fetchData() {\n' +343 ' // You can await here\n' +344 ' const response = await MyAPI.getData(someId);\n' +345 ' // ...\n' +346 ' }\n' +347 ' fetchData();\n' +348 `}, [someId]); // Or [] if effect doesn't need props or state\n\n` +349 'Learn more about data fetching with Hooks: https://fb.me/react-hooks-data-fetching';350 } else {351 addendum = ' You returned: ' + destroy;352 }353 console.error(354 'An effect function must not return anything besides a function, ' +355 'which is used for clean-up.%s%s',356 addendum,357 getStackByFiberInDevAndProd(finishedWork),358 );359 }360 }361 }362 effect = effect.next;363 } while (effect !== firstEffect);364 }365}366function schedulePassiveEffects(finishedWork: Fiber) {367 if (runAllPassiveEffectDestroysBeforeCreates) {368 const updateQueue: FunctionComponentUpdateQueue | null = (finishedWork.updateQueue: any);369 const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;370 if (lastEffect !== null) {371 const firstEffect = lastEffect.next;372 let effect = firstEffect;373 do {374 const {next, tag} = effect;375 if (376 (tag & HookPassive) !== NoHookEffect &&377 (tag & HookHasEffect) !== NoHookEffect378 ) {379 enqueuePendingPassiveHookEffectUnmount(finishedWork, effect);380 enqueuePendingPassiveHookEffectMount(finishedWork, effect);381 }382 effect = next;383 } while (effect !== firstEffect);384 }385 }386}387export function commitPassiveHookEffects(finishedWork: Fiber): void {388 if ((finishedWork.effectTag & Passive) !== NoEffect) {389 switch (finishedWork.tag) {390 case FunctionComponent:391 case ForwardRef:392 case SimpleMemoComponent:393 case Block: {394 // TODO (#17945) We should call all passive destroy functions (for all fibers)395 // before calling any create functions. The current approach only serializes396 // these for a single fiber.397 if (398 enableProfilerTimer &&399 enableProfilerCommitHooks &&400 finishedWork.mode & ProfileMode401 ) {402 try {403 startPassiveEffectTimer();404 commitHookEffectListUnmount(405 HookPassive | HookHasEffect,406 finishedWork,407 );408 commitHookEffectListMount(409 HookPassive | HookHasEffect,410 finishedWork,411 );412 } finally {413 recordPassiveEffectDuration(finishedWork);414 }415 } else {416 commitHookEffectListUnmount(417 HookPassive | HookHasEffect,418 finishedWork,419 );420 commitHookEffectListMount(HookPassive | HookHasEffect, finishedWork);421 }422 break;423 }424 default:425 break;426 }427 }428}429export function commitPassiveEffectDurations(430 finishedRoot: FiberRoot,431 finishedWork: Fiber,432): void {433 if (enableProfilerTimer && enableProfilerCommitHooks) {434 // Only Profilers with work in their subtree will have an Update effect scheduled.435 if ((finishedWork.effectTag & Update) !== NoEffect) {436 switch (finishedWork.tag) {437 case Profiler: {438 const {passiveEffectDuration} = finishedWork.stateNode;439 const {id, onPostCommit} = finishedWork.memoizedProps;440 // This value will still reflect the previous commit phase.441 // It does not get reset until the start of the next commit phase.442 const commitTime = getCommitTime();443 if (typeof onPostCommit === 'function') {444 if (enableSchedulerTracing) {445 onPostCommit(446 id,447 finishedWork.alternate === null ? 'mount' : 'update',448 passiveEffectDuration,449 commitTime,450 finishedRoot.memoizedInteractions,451 );452 } else {453 onPostCommit(454 id,455 finishedWork.alternate === null ? 'mount' : 'update',456 passiveEffectDuration,457 commitTime,458 );459 }460 }461 // Bubble times to the next nearest ancestor Profiler.462 // After we process that Profiler, we'll bubble further up.463 let parentFiber = finishedWork.return;464 while (parentFiber !== null) {465 if (parentFiber.tag === Profiler) {466 const parentStateNode = parentFiber.stateNode;467 parentStateNode.passiveEffectDuration += passiveEffectDuration;468 break;469 }470 parentFiber = parentFiber.return;471 }472 break;473 }474 default:475 break;476 }477 }478 }479}480function commitLifeCycles(481 finishedRoot: FiberRoot,482 current: Fiber | null,483 finishedWork: Fiber,484 committedExpirationTime: ExpirationTime,485): void {486 switch (finishedWork.tag) {487 case FunctionComponent:488 case ForwardRef:489 case SimpleMemoComponent:490 case Block: {491 // At this point layout effects have already been destroyed (during mutation phase).492 // This is done to prevent sibling component effects from interfering with each other,493 // e.g. a destroy function in one component should never override a ref set494 // by a create function in another component during the same commit.495 if (496 enableProfilerTimer &&497 enableProfilerCommitHooks &&498 finishedWork.mode & ProfileMode499 ) {500 try {501 startLayoutEffectTimer();502 commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork);503 } finally {504 recordLayoutEffectDuration(finishedWork);505 }506 } else {507 commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork);508 }509 if (runAllPassiveEffectDestroysBeforeCreates) {510 schedulePassiveEffects(finishedWork);511 }512 return;513 }514 case ClassComponent: {515 const instance = finishedWork.stateNode;516 if (finishedWork.effectTag & Update) {517 if (current === null) {518 // We could update instance props and state here,519 // but instead we rely on them being set during last render.520 // TODO: revisit this when we implement resuming.521 if (__DEV__) {522 if (523 finishedWork.type === finishedWork.elementType &&524 !didWarnAboutReassigningProps525 ) {526 if (instance.props !== finishedWork.memoizedProps) {527 console.error(528 'Expected %s props to match memoized props before ' +529 'componentDidMount. ' +530 'This might either be because of a bug in React, or because ' +531 'a component reassigns its own `this.props`. ' +532 'Please file an issue.',533 getComponentName(finishedWork.type) || 'instance',534 );535 }536 if (instance.state !== finishedWork.memoizedState) {537 console.error(538 'Expected %s state to match memoized state before ' +539 'componentDidMount. ' +540 'This might either be because of a bug in React, or because ' +541 'a component reassigns its own `this.state`. ' +542 'Please file an issue.',543 getComponentName(finishedWork.type) || 'instance',544 );545 }546 }547 }548 if (549 enableProfilerTimer &&550 enableProfilerCommitHooks &&551 finishedWork.mode & ProfileMode552 ) {553 try {554 startLayoutEffectTimer();555 instance.componentDidMount();556 } finally {557 recordLayoutEffectDuration(finishedWork);558 }559 } else {560 instance.componentDidMount();561 }562 } else {563 const prevProps =564 finishedWork.elementType === finishedWork.type565 ? current.memoizedProps566 : resolveDefaultProps(finishedWork.type, current.memoizedProps);567 const prevState = current.memoizedState;568 // We could update instance props and state here,569 // but instead we rely on them being set during last render.570 // TODO: revisit this when we implement resuming.571 if (__DEV__) {572 if (573 finishedWork.type === finishedWork.elementType &&574 !didWarnAboutReassigningProps575 ) {576 if (instance.props !== finishedWork.memoizedProps) {577 console.error(578 'Expected %s props to match memoized props before ' +579 'componentDidUpdate. ' +580 'This might either be because of a bug in React, or because ' +581 'a component reassigns its own `this.props`. ' +582 'Please file an issue.',583 getComponentName(finishedWork.type) || 'instance',584 );585 }586 if (instance.state !== finishedWork.memoizedState) {587 console.error(588 'Expected %s state to match memoized state before ' +589 'componentDidUpdate. ' +590 'This might either be because of a bug in React, or because ' +591 'a component reassigns its own `this.state`. ' +592 'Please file an issue.',593 getComponentName(finishedWork.type) || 'instance',594 );595 }596 }597 }598 if (599 enableProfilerTimer &&600 enableProfilerCommitHooks &&601 finishedWork.mode & ProfileMode602 ) {603 try {604 startLayoutEffectTimer();605 instance.componentDidUpdate(606 prevProps,607 prevState,608 instance.__reactInternalSnapshotBeforeUpdate,609 );610 } finally {611 recordLayoutEffectDuration(finishedWork);612 }613 } else {614 instance.componentDidUpdate(615 prevProps,616 prevState,617 instance.__reactInternalSnapshotBeforeUpdate,618 );619 }620 }621 }622 const updateQueue = finishedWork.updateQueue;623 if (updateQueue !== null) {624 if (__DEV__) {625 if (626 finishedWork.type === finishedWork.elementType &&627 !didWarnAboutReassigningProps628 ) {629 if (instance.props !== finishedWork.memoizedProps) {630 console.error(631 'Expected %s props to match memoized props before ' +632 'processing the update queue. ' +633 'This might either be because of a bug in React, or because ' +634 'a component reassigns its own `this.props`. ' +635 'Please file an issue.',636 getComponentName(finishedWork.type) || 'instance',637 );638 }639 if (instance.state !== finishedWork.memoizedState) {640 console.error(641 'Expected %s state to match memoized state before ' +642 'processing the update queue. ' +643 'This might either be because of a bug in React, or because ' +644 'a component reassigns its own `this.state`. ' +645 'Please file an issue.',646 getComponentName(finishedWork.type) || 'instance',647 );648 }649 }650 }651 // We could update instance props and state here,652 // but instead we rely on them being set during last render.653 // TODO: revisit this when we implement resuming.654 commitUpdateQueue(finishedWork, updateQueue, instance);655 }656 return;657 }658 case HostRoot: {659 const updateQueue = finishedWork.updateQueue;660 if (updateQueue !== null) {661 let instance = null;662 if (finishedWork.child !== null) {663 switch (finishedWork.child.tag) {664 case HostComponent:665 instance = getPublicInstance(finishedWork.child.stateNode);666 break;667 case ClassComponent:668 instance = finishedWork.child.stateNode;669 break;670 }671 }672 commitUpdateQueue(finishedWork, updateQueue, instance);673 }674 return;675 }676 case HostComponent: {677 const instance: Instance = finishedWork.stateNode;678 // Renderers may schedule work to be done after host components are mounted679 // (eg DOM renderer may schedule auto-focus for inputs and form controls).680 // These effects should only be committed when components are first mounted,681 // aka when there is no current/alternate.682 if (current === null && finishedWork.effectTag & Update) {683 const type = finishedWork.type;684 const props = finishedWork.memoizedProps;685 commitMount(instance, type, props, finishedWork);686 }687 return;688 }689 case HostText: {690 // We have no life-cycles associated with text.691 return;692 }693 case HostPortal: {694 // We have no life-cycles associated with portals.695 return;696 }697 case Profiler: {698 if (enableProfilerTimer) {699 const {onCommit, onRender} = finishedWork.memoizedProps;700 const {effectDuration} = finishedWork.stateNode;701 const commitTime = getCommitTime();702 if (typeof onRender === 'function') {703 if (enableSchedulerTracing) {704 onRender(705 finishedWork.memoizedProps.id,706 current === null ? 'mount' : 'update',707 finishedWork.actualDuration,708 finishedWork.treeBaseDuration,709 finishedWork.actualStartTime,710 commitTime,711 finishedRoot.memoizedInteractions,712 );713 } else {714 onRender(715 finishedWork.memoizedProps.id,716 current === null ? 'mount' : 'update',717 finishedWork.actualDuration,718 finishedWork.treeBaseDuration,719 finishedWork.actualStartTime,720 commitTime,721 );722 }723 }724 if (enableProfilerCommitHooks) {725 if (typeof onCommit === 'function') {726 if (enableSchedulerTracing) {727 onCommit(728 finishedWork.memoizedProps.id,729 current === null ? 'mount' : 'update',730 effectDuration,731 commitTime,732 finishedRoot.memoizedInteractions,733 );734 } else {735 onCommit(736 finishedWork.memoizedProps.id,737 current === null ? 'mount' : 'update',738 effectDuration,739 commitTime,740 );741 }742 }743 // Schedule a passive effect for this Profiler to call onPostCommit hooks.744 // This effect should be scheduled even if there is no onPostCommit callback for this Profiler,745 // because the effect is also where times bubble to parent Profilers.746 enqueuePendingPassiveProfilerEffect(finishedWork);747 // Propagate layout effect durations to the next nearest Profiler ancestor.748 // Do not reset these values until the next render so DevTools has a chance to read them first.749 let parentFiber = finishedWork.return;750 while (parentFiber !== null) {751 if (parentFiber.tag === Profiler) {752 const parentStateNode = parentFiber.stateNode;753 parentStateNode.effectDuration += effectDuration;754 break;755 }756 parentFiber = parentFiber.return;757 }758 }759 }760 return;761 }762 case SuspenseComponent: {763 commitSuspenseHydrationCallbacks(finishedRoot, finishedWork);764 return;765 }766 case SuspenseListComponent:767 case IncompleteClassComponent:768 case FundamentalComponent:769 case ScopeComponent:770 return;771 }772 invariant(773 false,774 'This unit of work tag should not have side-effects. This error is ' +775 'likely caused by a bug in React. Please file an issue.',776 );777}778function hideOrUnhideAllChildren(finishedWork, isHidden) {779 if (supportsMutation) {780 // We only have the top Fiber that was inserted but we need to recurse down its781 // children to find all the terminal nodes.782 let node: Fiber = finishedWork;783 while (true) {784 if (node.tag === HostComponent) {785 const instance = node.stateNode;786 if (isHidden) {787 hideInstance(instance);788 } else {789 unhideInstance(node.stateNode, node.memoizedProps);790 }791 } else if (node.tag === HostText) {792 const instance = node.stateNode;793 if (isHidden) {794 hideTextInstance(instance);795 } else {796 unhideTextInstance(instance, node.memoizedProps);797 }798 } else if (799 node.tag === SuspenseComponent &&800 node.memoizedState !== null &&801 node.memoizedState.dehydrated === null802 ) {803 // Found a nested Suspense component that timed out. Skip over the804 // primary child fragment, which should remain hidden.805 const fallbackChildFragment: Fiber = (node.child: any).sibling;806 fallbackChildFragment.return = node;807 node = fallbackChildFragment;808 continue;809 } else if (node.child !== null) {810 node.child.return = node;811 node = node.child;812 continue;813 }814 if (node === finishedWork) {815 return;816 }817 while (node.sibling === null) {818 if (node.return === null || node.return === finishedWork) {819 return;820 }821 node = node.return;822 }823 node.sibling.return = node.return;824 node = node.sibling;825 }826 }827}828function commitAttachRef(finishedWork: Fiber) {829 const ref = finishedWork.ref;830 if (ref !== null) {831 const instance = finishedWork.stateNode;832 let instanceToUse;833 switch (finishedWork.tag) {834 case HostComponent:835 instanceToUse = getPublicInstance(instance);836 break;837 default:838 instanceToUse = instance;839 }840 // Moved outside to ensure DCE works with this flag841 if (enableScopeAPI && finishedWork.tag === ScopeComponent) {842 instanceToUse = instance.methods;843 }844 if (typeof ref === 'function') {845 ref(instanceToUse);846 } else {847 if (__DEV__) {848 if (!ref.hasOwnProperty('current')) {849 console.error(850 'Unexpected ref object provided for %s. ' +851 'Use either a ref-setter function or React.createRef().%s',852 getComponentName(finishedWork.type),853 getStackByFiberInDevAndProd(finishedWork),854 );855 }856 }857 ref.current = instanceToUse;858 }859 }860}861function commitDetachRef(current: Fiber) {862 const currentRef = current.ref;863 if (currentRef !== null) {864 if (typeof currentRef === 'function') {865 currentRef(null);866 } else {867 currentRef.current = null;868 }869 }870}871// User-originating errors (lifecycles and refs) should not interrupt872// deletion, so don't let them throw. Host-originating errors should873// interrupt deletion, so it's okay874function commitUnmount(875 finishedRoot: FiberRoot,876 current: Fiber,877 renderPriorityLevel: ReactPriorityLevel,878): void {879 onCommitUnmount(current);880 switch (current.tag) {881 case FunctionComponent:882 case ForwardRef:883 case MemoComponent:884 case SimpleMemoComponent:885 case Block: {886 const updateQueue: FunctionComponentUpdateQueue | null = (current.updateQueue: any);887 if (updateQueue !== null) {888 const lastEffect = updateQueue.lastEffect;889 if (lastEffect !== null) {890 const firstEffect = lastEffect.next;891 if (892 deferPassiveEffectCleanupDuringUnmount &&893 runAllPassiveEffectDestroysBeforeCreates894 ) {895 let effect = firstEffect;896 do {897 const {destroy, tag} = effect;898 if (destroy !== undefined) {899 if ((tag & HookPassive) !== NoHookEffect) {900 enqueuePendingPassiveHookEffectUnmount(current, effect);901 } else {902 if (903 enableProfilerTimer &&904 enableProfilerCommitHooks &&905 current.mode & ProfileMode906 ) {907 startLayoutEffectTimer();908 safelyCallDestroy(current, destroy);909 recordLayoutEffectDuration(current);910 } else {911 safelyCallDestroy(current, destroy);912 }913 }914 }915 effect = effect.next;916 } while (effect !== firstEffect);917 } else {918 // When the owner fiber is deleted, the destroy function of a passive919 // effect hook is called during the synchronous commit phase. This is920 // a concession to implementation complexity. Calling it in the921 // passive effect phase (like they usually are, when dependencies922 // change during an update) would require either traversing the923 // children of the deleted fiber again, or including unmount effects924 // as part of the fiber effect list.925 //926 // Because this is during the sync commit phase, we need to change927 // the priority.928 //929 // TODO: Reconsider this implementation trade off.930 const priorityLevel =931 renderPriorityLevel > NormalPriority932 ? NormalPriority933 : renderPriorityLevel;934 runWithPriority(priorityLevel, () => {935 let effect = firstEffect;936 do {937 const {destroy, tag} = effect;938 if (destroy !== undefined) {939 if (940 enableProfilerTimer &&941 enableProfilerCommitHooks &&942 current.mode & ProfileMode943 ) {944 if ((tag & HookPassive) !== NoHookEffect) {945 safelyCallDestroy(current, destroy);946 } else {947 startLayoutEffectTimer();948 safelyCallDestroy(current, destroy);949 recordLayoutEffectDuration(current);950 }951 } else {952 safelyCallDestroy(current, destroy);953 }954 }955 effect = effect.next;956 } while (effect !== firstEffect);957 });958 }959 }960 }961 return;962 }963 case ClassComponent: {964 safelyDetachRef(current);965 const instance = current.stateNode;966 if (typeof instance.componentWillUnmount === 'function') {967 safelyCallComponentWillUnmount(current, instance);968 }969 return;970 }971 case HostComponent: {972 if (enableDeprecatedFlareAPI) {973 unmountDeprecatedResponderListeners(current);974 }975 if (enableDeprecatedFlareAPI || enableUseEventAPI) {976 beforeRemoveInstance(current.stateNode);977 }978 safelyDetachRef(current);979 return;980 }981 case HostPortal: {982 // TODO: this is recursive.983 // We are also not using this parent because984 // the portal will get pushed immediately.985 if (supportsMutation) {986 unmountHostComponents(finishedRoot, current, renderPriorityLevel);987 } else if (supportsPersistence) {988 emptyPortalContainer(current);989 }990 return;991 }992 case FundamentalComponent: {993 if (enableFundamentalAPI) {994 const fundamentalInstance = current.stateNode;995 if (fundamentalInstance !== null) {996 unmountFundamentalComponent(fundamentalInstance);997 current.stateNode = null;998 }999 }1000 return;1001 }1002 case DehydratedFragment: {1003 if (enableSuspenseCallback) {1004 const hydrationCallbacks = finishedRoot.hydrationCallbacks;1005 if (hydrationCallbacks !== null) {1006 const onDeleted = hydrationCallbacks.onDeleted;1007 if (onDeleted) {1008 onDeleted((current.stateNode: SuspenseInstance));1009 }1010 }1011 }1012 return;1013 }1014 case ScopeComponent: {1015 if (enableDeprecatedFlareAPI) {1016 unmountDeprecatedResponderListeners(current);1017 }1018 if (enableScopeAPI) {1019 safelyDetachRef(current);1020 }1021 return;1022 }1023 }1024}1025function commitNestedUnmounts(1026 finishedRoot: FiberRoot,1027 root: Fiber,1028 renderPriorityLevel: ReactPriorityLevel,1029): void {1030 // While we're inside a removed host node we don't want to call1031 // removeChild on the inner nodes because they're removed by the top1032 // call anyway. We also want to call componentWillUnmount on all1033 // composites before this host node is removed from the tree. Therefore1034 // we do an inner loop while we're still inside the host node.1035 let node: Fiber = root;1036 while (true) {1037 commitUnmount(finishedRoot, node, renderPriorityLevel);1038 // Visit children because they may contain more composite or host nodes.1039 // Skip portals because commitUnmount() currently visits them recursively.1040 if (1041 node.child !== null &&1042 // If we use mutation we drill down into portals using commitUnmount above.1043 // If we don't use mutation we drill down into portals here instead.1044 (!supportsMutation || node.tag !== HostPortal)1045 ) {1046 node.child.return = node;1047 node = node.child;1048 continue;1049 }1050 if (node === root) {1051 return;1052 }1053 while (node.sibling === null) {1054 if (node.return === null || node.return === root) {1055 return;1056 }1057 node = node.return;1058 }1059 node.sibling.return = node.return;1060 node = node.sibling;1061 }1062}1063function detachFiber(current: Fiber) {1064 const alternate = current.alternate;1065 // Cut off the return pointers to disconnect it from the tree. Ideally, we1066 // should clear the child pointer of the parent alternate to let this1067 // get GC:ed but we don't know which for sure which parent is the current1068 // one so we'll settle for GC:ing the subtree of this child. This child1069 // itself will be GC:ed when the parent updates the next time.1070 current.return = null;1071 current.child = null;1072 current.memoizedState = null;1073 current.updateQueue = null;1074 current.dependencies = null;1075 current.alternate = null;1076 current.firstEffect = null;1077 current.lastEffect = null;1078 current.pendingProps = null;1079 current.memoizedProps = null;1080 current.stateNode = null;1081 if (alternate !== null) {1082 detachFiber(alternate);1083 }1084}1085function emptyPortalContainer(current: Fiber) {1086 if (!supportsPersistence) {1087 return;1088 }1089 const portal: {1090 containerInfo: Container,1091 pendingChildren: ChildSet,1092 ...1093 } = current.stateNode;1094 const {containerInfo} = portal;1095 const emptyChildSet = createContainerChildSet(containerInfo);1096 replaceContainerChildren(containerInfo, emptyChildSet);1097}1098function commitContainer(finishedWork: Fiber) {1099 if (!supportsPersistence) {1100 return;1101 }1102 switch (finishedWork.tag) {1103 case ClassComponent:1104 case HostComponent:1105 case HostText:1106 case FundamentalComponent: {1107 return;1108 }1109 case HostRoot:1110 case HostPortal: {1111 const portalOrRoot: {1112 containerInfo: Container,1113 pendingChildren: ChildSet,1114 ...1115 } = finishedWork.stateNode;1116 const {containerInfo, pendingChildren} = portalOrRoot;1117 replaceContainerChildren(containerInfo, pendingChildren);1118 return;1119 }1120 }1121 invariant(1122 false,1123 'This unit of work tag should not have side-effects. This error is ' +1124 'likely caused by a bug in React. Please file an issue.',1125 );1126}1127function getHostParentFiber(fiber: Fiber): Fiber {1128 let parent = fiber.return;1129 while (parent !== null) {1130 if (isHostParent(parent)) {1131 return parent;1132 }1133 parent = parent.return;1134 }1135 invariant(1136 false,1137 'Expected to find a host parent. This error is likely caused by a bug ' +1138 'in React. Please file an issue.',1139 );1140}1141function isHostParent(fiber: Fiber): boolean {1142 return (1143 fiber.tag === HostComponent ||1144 fiber.tag === HostRoot ||1145 fiber.tag === HostPortal1146 );1147}1148function getHostSibling(fiber: Fiber): ?Instance {1149 // We're going to search forward into the tree until we find a sibling host1150 // node. Unfortunately, if multiple insertions are done in a row we have to1151 // search past them. This leads to exponential search for the next sibling.1152 // TODO: Find a more efficient way to do this.1153 let node: Fiber = fiber;1154 siblings: while (true) {1155 // If we didn't find anything, let's try the next sibling.1156 while (node.sibling === null) {1157 if (node.return === null || isHostParent(node.return)) {1158 // If we pop out of the root or hit the parent the fiber we are the1159 // last sibling.1160 return null;1161 }1162 node = node.return;1163 }1164 node.sibling.return = node.return;1165 node = node.sibling;1166 while (1167 node.tag !== HostComponent &&1168 node.tag !== HostText &&1169 node.tag !== DehydratedFragment1170 ) {1171 // If it is not host node and, we might have a host node inside it.1172 // Try to search down until we find one.1173 if (node.effectTag & Placement) {1174 // If we don't have a child, try the siblings instead.1175 continue siblings;1176 }1177 // If we don't have a child, try the siblings instead.1178 // We also skip portals because they are not part of this host tree.1179 if (node.child === null || node.tag === HostPortal) {1180 continue siblings;1181 } else {1182 node.child.return = node;1183 node = node.child;1184 }1185 }1186 // Check if this host node is stable or about to be placed.1187 if (!(node.effectTag & Placement)) {1188 // Found it!1189 return node.stateNode;1190 }1191 }1192}1193function commitPlacement(finishedWork: Fiber): void {1194 if (!supportsMutation) {1195 return;1196 }1197 // Recursively insert all host nodes into the parent.1198 const parentFiber = getHostParentFiber(finishedWork);1199 // Note: these two variables *must* always be updated together.1200 let parent;1201 let isContainer;1202 const parentStateNode = parentFiber.stateNode;1203 switch (parentFiber.tag) {1204 case HostComponent:1205 parent = parentStateNode;1206 isContainer = false;1207 break;1208 case HostRoot:1209 parent = parentStateNode.containerInfo;1210 isContainer = true;1211 break;1212 case HostPortal:1213 parent = parentStateNode.containerInfo;1214 isContainer = true;1215 break;1216 case FundamentalComponent:1217 if (enableFundamentalAPI) {1218 parent = parentStateNode.instance;1219 isContainer = false;1220 }1221 // eslint-disable-next-line-no-fallthrough1222 default:1223 invariant(1224 false,1225 'Invalid host parent fiber. This error is likely caused by a bug ' +1226 'in React. Please file an issue.',1227 );1228 }1229 if (parentFiber.effectTag & ContentReset) {1230 // Reset the text content of the parent before doing any insertions1231 resetTextContent(parent);1232 // Clear ContentReset from the effect tag1233 parentFiber.effectTag &= ~ContentReset;1234 }1235 const before = getHostSibling(finishedWork);1236 // We only have the top Fiber that was inserted but we need to recurse down its1237 // children to find all the terminal nodes.1238 if (isContainer) {1239 insertOrAppendPlacementNodeIntoContainer(finishedWork, before, parent);1240 } else {1241 insertOrAppendPlacementNode(finishedWork, before, parent);1242 }1243}1244function insertOrAppendPlacementNodeIntoContainer(1245 node: Fiber,1246 before: ?Instance,1247 parent: Container,1248): void {1249 const {tag} = node;1250 const isHost = tag === HostComponent || tag === HostText;1251 if (isHost || (enableFundamentalAPI && tag === FundamentalComponent)) {1252 const stateNode = isHost ? node.stateNode : node.stateNode.instance;1253 if (before) {1254 insertInContainerBefore(parent, stateNode, before);1255 } else {1256 appendChildToContainer(parent, stateNode);1257 }1258 } else if (tag === HostPortal) {1259 // If the insertion itself is a portal, then we don't want to traverse1260 // down its children. Instead, we'll get insertions from each child in1261 // the portal directly.1262 } else {1263 const child = node.child;1264 if (child !== null) {1265 insertOrAppendPlacementNodeIntoContainer(child, before, parent);1266 let sibling = child.sibling;1267 while (sibling !== null) {1268 insertOrAppendPlacementNodeIntoContainer(sibling, before, parent);1269 sibling = sibling.sibling;1270 }1271 }1272 }1273}1274function insertOrAppendPlacementNode(1275 node: Fiber,1276 before: ?Instance,1277 parent: Instance,1278): void {1279 const {tag} = node;1280 const isHost = tag === HostComponent || tag === HostText;1281 if (isHost || (enableFundamentalAPI && tag === FundamentalComponent)) {1282 const stateNode = isHost ? node.stateNode : node.stateNode.instance;1283 if (before) {1284 insertBefore(parent, stateNode, before);1285 } else {1286 appendChild(parent, stateNode);1287 }1288 } else if (tag === HostPortal) {1289 // If the insertion itself is a portal, then we don't want to traverse1290 // down its children. Instead, we'll get insertions from each child in1291 // the portal directly.1292 } else {1293 const child = node.child;1294 if (child !== null) {1295 insertOrAppendPlacementNode(child, before, parent);1296 let sibling = child.sibling;1297 while (sibling !== null) {1298 insertOrAppendPlacementNode(sibling, before, parent);1299 sibling = sibling.sibling;1300 }1301 }1302 }1303}1304function unmountHostComponents(1305 finishedRoot,1306 current,1307 renderPriorityLevel,1308): void {1309 // We only have the top Fiber that was deleted but we need to recurse down its1310 // children to find all the terminal nodes.1311 let node: Fiber = current;1312 // Each iteration, currentParent is populated with node's host parent if not1313 // currentParentIsValid.1314 let currentParentIsValid = false;1315 // Note: these two variables *must* always be updated together.1316 let currentParent;1317 let currentParentIsContainer;1318 while (true) {1319 if (!currentParentIsValid) {1320 let parent = node.return;1321 findParent: while (true) {1322 invariant(1323 parent !== null,1324 'Expected to find a host parent. This error is likely caused by ' +1325 'a bug in React. Please file an issue.',1326 );1327 const parentStateNode = parent.stateNode;1328 switch (parent.tag) {1329 case HostComponent:1330 currentParent = parentStateNode;1331 currentParentIsContainer = false;1332 break findParent;1333 case HostRoot:1334 currentParent = parentStateNode.containerInfo;1335 currentParentIsContainer = true;1336 break findParent;1337 case HostPortal:1338 currentParent = parentStateNode.containerInfo;1339 currentParentIsContainer = true;1340 break findParent;1341 case FundamentalComponent:1342 if (enableFundamentalAPI) {1343 currentParent = parentStateNode.instance;1344 currentParentIsContainer = false;1345 }1346 }1347 parent = parent.return;1348 }1349 currentParentIsValid = true;1350 }1351 if (node.tag === HostComponent || node.tag === HostText) {1352 commitNestedUnmounts(finishedRoot, node, renderPriorityLevel);1353 // After all the children have unmounted, it is now safe to remove the1354 // node from the tree.1355 if (currentParentIsContainer) {1356 removeChildFromContainer(1357 ((currentParent: any): Container),1358 (node.stateNode: Instance | TextInstance),1359 );1360 } else {1361 removeChild(1362 ((currentParent: any): Instance),1363 (node.stateNode: Instance | TextInstance),1364 );1365 }1366 // Don't visit children because we already visited them.1367 } else if (enableFundamentalAPI && node.tag === FundamentalComponent) {1368 const fundamentalNode = node.stateNode.instance;1369 commitNestedUnmounts(finishedRoot, node, renderPriorityLevel);1370 // After all the children have unmounted, it is now safe to remove the1371 // node from the tree.1372 if (currentParentIsContainer) {1373 removeChildFromContainer(1374 ((currentParent: any): Container),1375 (fundamentalNode: Instance),1376 );1377 } else {1378 removeChild(1379 ((currentParent: any): Instance),1380 (fundamentalNode: Instance),1381 );1382 }1383 } else if (1384 enableSuspenseServerRenderer &&1385 node.tag === DehydratedFragment1386 ) {1387 if (enableSuspenseCallback) {1388 const hydrationCallbacks = finishedRoot.hydrationCallbacks;1389 if (hydrationCallbacks !== null) {1390 const onDeleted = hydrationCallbacks.onDeleted;1391 if (onDeleted) {1392 onDeleted((node.stateNode: SuspenseInstance));1393 }1394 }1395 }1396 // Delete the dehydrated suspense boundary and all of its content.1397 if (currentParentIsContainer) {1398 clearSuspenseBoundaryFromContainer(1399 ((currentParent: any): Container),1400 (node.stateNode: SuspenseInstance),1401 );1402 } else {1403 clearSuspenseBoundary(1404 ((currentParent: any): Instance),1405 (node.stateNode: SuspenseInstance),1406 );1407 }1408 } else if (node.tag === HostPortal) {1409 if (node.child !== null) {1410 // When we go into a portal, it becomes the parent to remove from.1411 // We will reassign it back when we pop the portal on the way up.1412 currentParent = node.stateNode.containerInfo;1413 currentParentIsContainer = true;1414 // Visit children because portals might contain host components.1415 node.child.return = node;1416 node = node.child;1417 continue;1418 }1419 } else {1420 commitUnmount(finishedRoot, node, renderPriorityLevel);1421 // Visit children because we may find more host components below.1422 if (node.child !== null) {1423 node.child.return = node;1424 node = node.child;1425 continue;1426 }1427 }1428 if (node === current) {1429 return;1430 }1431 while (node.sibling === null) {1432 if (node.return === null || node.return === current) {1433 return;1434 }1435 node = node.return;1436 if (node.tag === HostPortal) {1437 // When we go out of the portal, we need to restore the parent.1438 // Since we don't keep a stack of them, we will search for it.1439 currentParentIsValid = false;1440 }1441 }1442 node.sibling.return = node.return;1443 node = node.sibling;1444 }1445}1446function commitDeletion(1447 finishedRoot: FiberRoot,1448 current: Fiber,1449 renderPriorityLevel: ReactPriorityLevel,1450): void {1451 if (supportsMutation) {1452 // Recursively delete all host nodes from the parent.1453 // Detach refs and call componentWillUnmount() on the whole subtree.1454 unmountHostComponents(finishedRoot, current, renderPriorityLevel);1455 } else {1456 // Detach refs and call componentWillUnmount() on the whole subtree.1457 commitNestedUnmounts(finishedRoot, current, renderPriorityLevel);1458 }1459 detachFiber(current);1460}1461function commitWork(current: Fiber | null, finishedWork: Fiber): void {1462 if (!supportsMutation) {1463 switch (finishedWork.tag) {1464 case FunctionComponent:1465 case ForwardRef:1466 case MemoComponent:1467 case SimpleMemoComponent:1468 case Block: {1469 // Layout effects are destroyed during the mutation phase so that all1470 // destroy functions for all fibers are called before any create functions.1471 // This prevents sibling component effects from interfering with each other,1472 // e.g. a destroy function in one component should never override a ref set1473 // by a create function in another component during the same commit.1474 if (1475 enableProfilerTimer &&1476 enableProfilerCommitHooks &&1477 finishedWork.mode & ProfileMode1478 ) {1479 try {1480 startLayoutEffectTimer();1481 commitHookEffectListUnmount(1482 HookLayout | HookHasEffect,1483 finishedWork,1484 );1485 } finally {1486 recordLayoutEffectDuration(finishedWork);1487 }1488 } else {1489 commitHookEffectListUnmount(HookLayout | HookHasEffect, finishedWork);1490 }1491 return;1492 }1493 case Profiler: {1494 return;1495 }1496 case SuspenseComponent: {1497 commitSuspenseComponent(finishedWork);1498 attachSuspenseRetryListeners(finishedWork);1499 return;1500 }1501 case SuspenseListComponent: {1502 attachSuspenseRetryListeners(finishedWork);1503 return;1504 }1505 case HostRoot: {1506 if (supportsHydration) {1507 const root: FiberRoot = finishedWork.stateNode;1508 if (root.hydrate) {1509 // We've just hydrated. No need to hydrate again.1510 root.hydrate = false;1511 commitHydratedContainer(root.containerInfo);1512 }1513 }1514 break;1515 }1516 }1517 commitContainer(finishedWork);1518 return;1519 }1520 switch (finishedWork.tag) {1521 case FunctionComponent:1522 case ForwardRef:1523 case MemoComponent:1524 case SimpleMemoComponent:1525 case Block: {1526 // Layout effects are destroyed during the mutation phase so that all1527 // destroy functions for all fibers are called before any create functions.1528 // This prevents sibling component effects from interfering with each other,1529 // e.g. a destroy function in one component should never override a ref set1530 // by a create function in another component during the same commit.1531 if (1532 enableProfilerTimer &&1533 enableProfilerCommitHooks &&1534 finishedWork.mode & ProfileMode1535 ) {1536 try {1537 startLayoutEffectTimer();1538 commitHookEffectListUnmount(HookLayout | HookHasEffect, finishedWork);1539 } finally {1540 recordLayoutEffectDuration(finishedWork);1541 }1542 } else {1543 commitHookEffectListUnmount(HookLayout | HookHasEffect, finishedWork);1544 }1545 return;1546 }1547 case ClassComponent: {1548 return;1549 }1550 case HostComponent: {1551 const instance: Instance = finishedWork.stateNode;1552 if (instance != null) {1553 // Commit the work prepared earlier.1554 const newProps = finishedWork.memoizedProps;1555 // For hydration we reuse the update path but we treat the oldProps1556 // as the newProps. The updatePayload will contain the real change in1557 // this case.1558 const oldProps = current !== null ? current.memoizedProps : newProps;1559 const type = finishedWork.type;1560 // TODO: Type the updateQueue to be specific to host components.1561 const updatePayload: null | UpdatePayload = (finishedWork.updateQueue: any);1562 finishedWork.updateQueue = null;1563 if (updatePayload !== null) {1564 commitUpdate(1565 instance,1566 updatePayload,1567 type,1568 oldProps,1569 newProps,1570 finishedWork,1571 );1572 }1573 if (enableDeprecatedFlareAPI) {1574 const prevListeners = oldProps.DEPRECATED_flareListeners;1575 const nextListeners = newProps.DEPRECATED_flareListeners;1576 if (prevListeners !== nextListeners) {1577 updateDeprecatedEventListeners(nextListeners, finishedWork, null);1578 }1579 }1580 }1581 return;1582 }1583 case HostText: {1584 invariant(1585 finishedWork.stateNode !== null,1586 'This should have a text node initialized. This error is likely ' +1587 'caused by a bug in React. Please file an issue.',1588 );1589 const textInstance: TextInstance = finishedWork.stateNode;1590 const newText: string = finishedWork.memoizedProps;1591 // For hydration we reuse the update path but we treat the oldProps1592 // as the newProps. The updatePayload will contain the real change in1593 // this case.1594 const oldText: string =1595 current !== null ? current.memoizedProps : newText;1596 commitTextUpdate(textInstance, oldText, newText);1597 return;1598 }1599 case HostRoot: {1600 if (supportsHydration) {1601 const root: FiberRoot = finishedWork.stateNode;1602 if (root.hydrate) {1603 // We've just hydrated. No need to hydrate again.1604 root.hydrate = false;1605 commitHydratedContainer(root.containerInfo);1606 }1607 }1608 return;1609 }1610 case Profiler: {1611 return;1612 }1613 case SuspenseComponent: {1614 commitSuspenseComponent(finishedWork);1615 attachSuspenseRetryListeners(finishedWork);1616 return;1617 }1618 case SuspenseListComponent: {1619 attachSuspenseRetryListeners(finishedWork);1620 return;1621 }1622 case IncompleteClassComponent: {1623 return;1624 }1625 case FundamentalComponent: {1626 if (enableFundamentalAPI) {1627 const fundamentalInstance = finishedWork.stateNode;1628 updateFundamentalComponent(fundamentalInstance);1629 return;1630 }1631 break;1632 }1633 case ScopeComponent: {1634 if (enableScopeAPI) {1635 const scopeInstance = finishedWork.stateNode;1636 scopeInstance.fiber = finishedWork;1637 if (enableDeprecatedFlareAPI) {1638 const newProps = finishedWork.memoizedProps;1639 const oldProps = current !== null ? current.memoizedProps : newProps;1640 const prevListeners = oldProps.DEPRECATED_flareListeners;1641 const nextListeners = newProps.DEPRECATED_flareListeners;1642 if (prevListeners !== nextListeners || current === null) {1643 updateDeprecatedEventListeners(nextListeners, finishedWork, null);1644 }1645 }1646 return;1647 }1648 break;1649 }1650 }1651 invariant(1652 false,1653 'This unit of work tag should not have side-effects. This error is ' +1654 'likely caused by a bug in React. Please file an issue.',1655 );1656}1657function commitSuspenseComponent(finishedWork: Fiber) {1658 const newState: SuspenseState | null = finishedWork.memoizedState;1659 let newDidTimeout;1660 let primaryChildParent = finishedWork;1661 if (newState === null) {1662 newDidTimeout = false;1663 } else {1664 newDidTimeout = true;1665 primaryChildParent = finishedWork.child;1666 markCommitTimeOfFallback();1667 }1668 if (supportsMutation && primaryChildParent !== null) {1669 hideOrUnhideAllChildren(primaryChildParent, newDidTimeout);1670 }1671 if (enableSuspenseCallback && newState !== null) {1672 const suspenseCallback = finishedWork.memoizedProps.suspenseCallback;1673 if (typeof suspenseCallback === 'function') {1674 const wakeables: Set<Wakeable> | null = (finishedWork.updateQueue: any);1675 if (wakeables !== null) {1676 suspenseCallback(new Set(wakeables));1677 }1678 } else if (__DEV__) {1679 if (suspenseCallback !== undefined) {1680 console.error('Unexpected type for suspenseCallback.');1681 }1682 }1683 }1684}1685function commitSuspenseHydrationCallbacks(1686 finishedRoot: FiberRoot,1687 finishedWork: Fiber,1688) {1689 if (!supportsHydration) {1690 return;1691 }1692 const newState: SuspenseState | null = finishedWork.memoizedState;1693 if (newState === null) {1694 const current = finishedWork.alternate;1695 if (current !== null) {1696 const prevState: SuspenseState | null = current.memoizedState;1697 if (prevState !== null) {1698 const suspenseInstance = prevState.dehydrated;1699 if (suspenseInstance !== null) {1700 commitHydratedSuspenseInstance(suspenseInstance);1701 if (enableSuspenseCallback) {1702 const hydrationCallbacks = finishedRoot.hydrationCallbacks;1703 if (hydrationCallbacks !== null) {1704 const onHydrated = hydrationCallbacks.onHydrated;1705 if (onHydrated) {1706 onHydrated(suspenseInstance);1707 }1708 }1709 }1710 }1711 }1712 }1713 }1714}1715function attachSuspenseRetryListeners(finishedWork: Fiber) {1716 // If this boundary just timed out, then it will have a set of wakeables.1717 // For each wakeable, attach a listener so that when it resolves, React1718 // attempts to re-render the boundary in the primary (pre-timeout) state.1719 const wakeables: Set<Wakeable> | null = (finishedWork.updateQueue: any);1720 if (wakeables !== null) {1721 finishedWork.updateQueue = null;1722 let retryCache = finishedWork.stateNode;1723 if (retryCache === null) {1724 retryCache = finishedWork.stateNode = new PossiblyWeakSet();1725 }1726 wakeables.forEach(wakeable => {1727 // Memoize using the boundary fiber to prevent redundant listeners.1728 let retry = resolveRetryWakeable.bind(null, finishedWork, wakeable);1729 if (!retryCache.has(wakeable)) {1730 if (enableSchedulerTracing) {1731 if (wakeable.__reactDoNotTraceInteractions !== true) {1732 retry = Schedule_tracing_wrap(retry);1733 }1734 }1735 retryCache.add(wakeable);1736 wakeable.then(retry, retry);1737 }1738 });1739 }1740}1741function commitResetTextContent(current: Fiber) {1742 if (!supportsMutation) {1743 return;1744 }1745 resetTextContent(current.stateNode);1746}1747export {1748 commitBeforeMutationLifeCycles,1749 commitResetTextContent,1750 commitPlacement,1751 commitDeletion,1752 commitWork,1753 commitLifeCycles,1754 commitAttachRef,1755 commitDetachRef,...

Full Screen

Full Screen

ReactFiberCommitWork.new.js

Source:ReactFiberCommitWork.new.js Github

copy

Full Screen

1/**2 * Copyright (c) Facebook, Inc. and its affiliates.3 *4 * This source code is licensed under the MIT license found in the5 * LICENSE file in the root directory of this source tree.6 *7 * @flow8 */9import type {10 Instance,11 TextInstance,12 SuspenseInstance,13 Container,14 ChildSet,15 UpdatePayload,16} from './ReactFiberHostConfig';17import type {Fiber} from './ReactInternalTypes';18import type {FiberRoot} from './ReactInternalTypes';19import type {Lanes} from './ReactFiberLane.new';20import type {SuspenseState} from './ReactFiberSuspenseComponent.new';21import type {UpdateQueue} from './ReactUpdateQueue.new';22import type {FunctionComponentUpdateQueue} from './ReactFiberHooks.new';23import type {Wakeable} from 'shared/ReactTypes';24import type {ReactPriorityLevel} from './ReactInternalTypes';25import type {OffscreenState} from './ReactFiberOffscreenComponent';26import {unstable_wrap as Schedule_tracing_wrap} from 'scheduler/tracing';27import {28 enableSchedulerTracing,29 enableProfilerTimer,30 enableProfilerCommitHooks,31 enableProfilerNestedUpdatePhase,32 enableSuspenseServerRenderer,33 enableFundamentalAPI,34 enableSuspenseCallback,35 enableScopeAPI,36} from 'shared/ReactFeatureFlags';37import {38 FunctionComponent,39 ForwardRef,40 ClassComponent,41 HostRoot,42 HostComponent,43 HostText,44 HostPortal,45 Profiler,46 SuspenseComponent,47 DehydratedFragment,48 IncompleteClassComponent,49 MemoComponent,50 SimpleMemoComponent,51 SuspenseListComponent,52 FundamentalComponent,53 ScopeComponent,54 OffscreenComponent,55 LegacyHiddenComponent,56} from './ReactWorkTags';57import {58 invokeGuardedCallback,59 hasCaughtError,60 clearCaughtError,61} from 'shared/ReactErrorUtils';62import {63 NoFlags,64 ContentReset,65 Placement,66 Snapshot,67 Update,68} from './ReactFiberFlags';69import getComponentName from 'shared/getComponentName';70import invariant from 'shared/invariant';71import {onCommitUnmount} from './ReactFiberDevToolsHook.new';72import {resolveDefaultProps} from './ReactFiberLazyComponent.new';73import {74 isCurrentUpdateNested,75 getCommitTime,76 recordLayoutEffectDuration,77 startLayoutEffectTimer,78} from './ReactProfilerTimer.new';79import {ProfileMode} from './ReactTypeOfMode';80import {commitUpdateQueue} from './ReactUpdateQueue.new';81import {82 getPublicInstance,83 supportsMutation,84 supportsPersistence,85 supportsHydration,86 commitMount,87 commitUpdate,88 resetTextContent,89 commitTextUpdate,90 appendChild,91 appendChildToContainer,92 insertBefore,93 insertInContainerBefore,94 removeChild,95 removeChildFromContainer,96 clearSuspenseBoundary,97 clearSuspenseBoundaryFromContainer,98 replaceContainerChildren,99 createContainerChildSet,100 hideInstance,101 hideTextInstance,102 unhideInstance,103 unhideTextInstance,104 unmountFundamentalComponent,105 updateFundamentalComponent,106 commitHydratedContainer,107 commitHydratedSuspenseInstance,108 clearContainer,109 prepareScopeUpdate,110} from './ReactFiberHostConfig';111import {112 captureCommitPhaseError,113 resolveRetryWakeable,114 markCommitTimeOfFallback,115 enqueuePendingPassiveHookEffectMount,116 enqueuePendingPassiveHookEffectUnmount,117 enqueuePendingPassiveProfilerEffect,118} from './ReactFiberWorkLoop.new';119import {120 NoFlags as NoHookEffect,121 HasEffect as HookHasEffect,122 Layout as HookLayout,123 Passive as HookPassive,124} from './ReactHookEffectTags';125import {didWarnAboutReassigningProps} from './ReactFiberBeginWork.new';126let didWarnAboutUndefinedSnapshotBeforeUpdate: Set<mixed> | null = null;127if (__DEV__) {128 didWarnAboutUndefinedSnapshotBeforeUpdate = new Set();129}130const PossiblyWeakSet = typeof WeakSet === 'function' ? WeakSet : Set;131const callComponentWillUnmountWithTimer = function(current, instance) {132 instance.props = current.memoizedProps;133 instance.state = current.memoizedState;134 if (135 enableProfilerTimer &&136 enableProfilerCommitHooks &&137 current.mode & ProfileMode138 ) {139 try {140 startLayoutEffectTimer();141 instance.componentWillUnmount();142 } finally {143 recordLayoutEffectDuration(current);144 }145 } else {146 instance.componentWillUnmount();147 }148};149// Capture errors so they don't interrupt unmounting.150function safelyCallComponentWillUnmount(current: Fiber, instance: any) {151 if (__DEV__) {152 invokeGuardedCallback(153 null,154 callComponentWillUnmountWithTimer,155 null,156 current,157 instance,158 );159 if (hasCaughtError()) {160 const unmountError = clearCaughtError();161 captureCommitPhaseError(current, unmountError);162 }163 } else {164 try {165 callComponentWillUnmountWithTimer(current, instance);166 } catch (unmountError) {167 captureCommitPhaseError(current, unmountError);168 }169 }170}171function safelyDetachRef(current: Fiber) {172 const ref = current.ref;173 if (ref !== null) {174 if (typeof ref === 'function') {175 if (__DEV__) {176 if (177 enableProfilerTimer &&178 enableProfilerCommitHooks &&179 current.mode & ProfileMode180 ) {181 startLayoutEffectTimer();182 invokeGuardedCallback(null, ref, null, null);183 recordLayoutEffectDuration(current);184 } else {185 invokeGuardedCallback(null, ref, null, null);186 }187 if (hasCaughtError()) {188 const refError = clearCaughtError();189 captureCommitPhaseError(current, refError);190 }191 } else {192 try {193 if (194 enableProfilerTimer &&195 enableProfilerCommitHooks &&196 current.mode & ProfileMode197 ) {198 try {199 startLayoutEffectTimer();200 ref(null);201 } finally {202 recordLayoutEffectDuration(current);203 }204 } else {205 ref(null);206 }207 } catch (refError) {208 captureCommitPhaseError(current, refError);209 }210 }211 } else {212 ref.current = null;213 }214 }215}216function safelyCallDestroy(current: Fiber, destroy: () => void) {217 if (__DEV__) {218 invokeGuardedCallback(null, destroy, null);219 if (hasCaughtError()) {220 const error = clearCaughtError();221 captureCommitPhaseError(current, error);222 }223 } else {224 try {225 destroy();226 } catch (error) {227 captureCommitPhaseError(current, error);228 }229 }230}231function commitBeforeMutationLifeCycles(232 current: Fiber | null,233 finishedWork: Fiber,234): void {235 switch (finishedWork.tag) {236 case FunctionComponent:237 case ForwardRef:238 case SimpleMemoComponent: {239 return;240 }241 case ClassComponent: {242 if (finishedWork.flags & Snapshot) {243 if (current !== null) {244 const prevProps = current.memoizedProps;245 const prevState = current.memoizedState;246 const instance = finishedWork.stateNode;247 // We could update instance props and state here,248 // but instead we rely on them being set during last render.249 // TODO: revisit this when we implement resuming.250 if (__DEV__) {251 if (252 finishedWork.type === finishedWork.elementType &&253 !didWarnAboutReassigningProps254 ) {255 if (instance.props !== finishedWork.memoizedProps) {256 console.error(257 'Expected %s props to match memoized props before ' +258 'getSnapshotBeforeUpdate. ' +259 'This might either be because of a bug in React, or because ' +260 'a component reassigns its own `this.props`. ' +261 'Please file an issue.',262 getComponentName(finishedWork.type) || 'instance',263 );264 }265 if (instance.state !== finishedWork.memoizedState) {266 console.error(267 'Expected %s state to match memoized state before ' +268 'getSnapshotBeforeUpdate. ' +269 'This might either be because of a bug in React, or because ' +270 'a component reassigns its own `this.state`. ' +271 'Please file an issue.',272 getComponentName(finishedWork.type) || 'instance',273 );274 }275 }276 }277 const snapshot = instance.getSnapshotBeforeUpdate(278 finishedWork.elementType === finishedWork.type279 ? prevProps280 : resolveDefaultProps(finishedWork.type, prevProps),281 prevState,282 );283 if (__DEV__) {284 const didWarnSet = ((didWarnAboutUndefinedSnapshotBeforeUpdate: any): Set<mixed>);285 if (snapshot === undefined && !didWarnSet.has(finishedWork.type)) {286 didWarnSet.add(finishedWork.type);287 console.error(288 '%s.getSnapshotBeforeUpdate(): A snapshot value (or null) ' +289 'must be returned. You have returned undefined.',290 getComponentName(finishedWork.type),291 );292 }293 }294 instance.__reactInternalSnapshotBeforeUpdate = snapshot;295 }296 }297 return;298 }299 case HostRoot: {300 if (supportsMutation) {301 if (finishedWork.flags & Snapshot) {302 const root = finishedWork.stateNode;303 clearContainer(root.containerInfo);304 }305 }306 return;307 }308 case HostComponent:309 case HostText:310 case HostPortal:311 case IncompleteClassComponent:312 // Nothing to do for these component types313 return;314 }315 invariant(316 false,317 'This unit of work tag should not have side-effects. This error is ' +318 'likely caused by a bug in React. Please file an issue.',319 );320}321function commitHookEffectListUnmount(tag: number, finishedWork: Fiber) {322 const updateQueue: FunctionComponentUpdateQueue | null = (finishedWork.updateQueue: any);323 const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;324 if (lastEffect !== null) {325 const firstEffect = lastEffect.next;326 let effect = firstEffect;327 do {328 if ((effect.tag & tag) === tag) {329 // Unmount330 const destroy = effect.destroy;331 effect.destroy = undefined;332 if (destroy !== undefined) {333 destroy();334 }335 }336 effect = effect.next;337 } while (effect !== firstEffect);338 }339}340function commitHookEffectListMount(tag: number, finishedWork: Fiber) {341 const updateQueue: FunctionComponentUpdateQueue | null = (finishedWork.updateQueue: any);342 const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;343 if (lastEffect !== null) {344 const firstEffect = lastEffect.next;345 let effect = firstEffect;346 do {347 if ((effect.tag & tag) === tag) {348 // Mount349 const create = effect.create;350 effect.destroy = create();351 if (__DEV__) {352 const destroy = effect.destroy;353 if (destroy !== undefined && typeof destroy !== 'function') {354 let addendum;355 if (destroy === null) {356 addendum =357 ' You returned null. If your effect does not require clean ' +358 'up, return undefined (or nothing).';359 } else if (typeof destroy.then === 'function') {360 addendum =361 '\n\nIt looks like you wrote useEffect(async () => ...) or returned a Promise. ' +362 'Instead, write the async function inside your effect ' +363 'and call it immediately:\n\n' +364 'useEffect(() => {\n' +365 ' async function fetchData() {\n' +366 ' // You can await here\n' +367 ' const response = await MyAPI.getData(someId);\n' +368 ' // ...\n' +369 ' }\n' +370 ' fetchData();\n' +371 `}, [someId]); // Or [] if effect doesn't need props or state\n\n` +372 'Learn more about data fetching with Hooks: https://reactjs.org/link/hooks-data-fetching';373 } else {374 addendum = ' You returned: ' + destroy;375 }376 console.error(377 'An effect function must not return anything besides a function, ' +378 'which is used for clean-up.%s',379 addendum,380 );381 }382 }383 }384 effect = effect.next;385 } while (effect !== firstEffect);386 }387}388function schedulePassiveEffects(finishedWork: Fiber) {389 const updateQueue: FunctionComponentUpdateQueue | null = (finishedWork.updateQueue: any);390 const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;391 if (lastEffect !== null) {392 const firstEffect = lastEffect.next;393 let effect = firstEffect;394 do {395 const {next, tag} = effect;396 if (397 (tag & HookPassive) !== NoHookEffect &&398 (tag & HookHasEffect) !== NoHookEffect399 ) {400 enqueuePendingPassiveHookEffectUnmount(finishedWork, effect);401 enqueuePendingPassiveHookEffectMount(finishedWork, effect);402 }403 effect = next;404 } while (effect !== firstEffect);405 }406}407export function commitPassiveEffectDurations(408 finishedRoot: FiberRoot,409 finishedWork: Fiber,410): void {411 if (enableProfilerTimer && enableProfilerCommitHooks) {412 // Only Profilers with work in their subtree will have an Update effect scheduled.413 if ((finishedWork.flags & Update) !== NoFlags) {414 switch (finishedWork.tag) {415 case Profiler: {416 const {passiveEffectDuration} = finishedWork.stateNode;417 const {id, onPostCommit} = finishedWork.memoizedProps;418 // This value will still reflect the previous commit phase.419 // It does not get reset until the start of the next commit phase.420 const commitTime = getCommitTime();421 let phase = finishedWork.alternate === null ? 'mount' : 'update';422 if (enableProfilerNestedUpdatePhase) {423 if (isCurrentUpdateNested()) {424 phase = 'nested-update';425 }426 }427 if (typeof onPostCommit === 'function') {428 if (enableSchedulerTracing) {429 onPostCommit(430 id,431 phase,432 passiveEffectDuration,433 commitTime,434 finishedRoot.memoizedInteractions,435 );436 } else {437 onPostCommit(id, phase, passiveEffectDuration, commitTime);438 }439 }440 // Bubble times to the next nearest ancestor Profiler.441 // After we process that Profiler, we'll bubble further up.442 let parentFiber = finishedWork.return;443 while (parentFiber !== null) {444 if (parentFiber.tag === Profiler) {445 const parentStateNode = parentFiber.stateNode;446 parentStateNode.passiveEffectDuration += passiveEffectDuration;447 break;448 }449 parentFiber = parentFiber.return;450 }451 break;452 }453 default:454 break;455 }456 }457 }458}459function commitLifeCycles(460 finishedRoot: FiberRoot,461 current: Fiber | null,462 finishedWork: Fiber,463 committedLanes: Lanes,464): void {465 switch (finishedWork.tag) {466 case FunctionComponent:467 case ForwardRef:468 case SimpleMemoComponent: {469 // At this point layout effects have already been destroyed (during mutation phase).470 // This is done to prevent sibling component effects from interfering with each other,471 // e.g. a destroy function in one component should never override a ref set472 // by a create function in another component during the same commit.473 if (474 enableProfilerTimer &&475 enableProfilerCommitHooks &&476 finishedWork.mode & ProfileMode477 ) {478 try {479 startLayoutEffectTimer();480 commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork);481 } finally {482 recordLayoutEffectDuration(finishedWork);483 }484 } else {485 commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork);486 }487 schedulePassiveEffects(finishedWork);488 return;489 }490 case ClassComponent: {491 const instance = finishedWork.stateNode;492 if (finishedWork.flags & Update) {493 if (current === null) {494 // We could update instance props and state here,495 // but instead we rely on them being set during last render.496 // TODO: revisit this when we implement resuming.497 if (__DEV__) {498 if (499 finishedWork.type === finishedWork.elementType &&500 !didWarnAboutReassigningProps501 ) {502 if (instance.props !== finishedWork.memoizedProps) {503 console.error(504 'Expected %s props to match memoized props before ' +505 'componentDidMount. ' +506 'This might either be because of a bug in React, or because ' +507 'a component reassigns its own `this.props`. ' +508 'Please file an issue.',509 getComponentName(finishedWork.type) || 'instance',510 );511 }512 if (instance.state !== finishedWork.memoizedState) {513 console.error(514 'Expected %s state to match memoized state before ' +515 'componentDidMount. ' +516 'This might either be because of a bug in React, or because ' +517 'a component reassigns its own `this.state`. ' +518 'Please file an issue.',519 getComponentName(finishedWork.type) || 'instance',520 );521 }522 }523 }524 if (525 enableProfilerTimer &&526 enableProfilerCommitHooks &&527 finishedWork.mode & ProfileMode528 ) {529 try {530 startLayoutEffectTimer();531 instance.componentDidMount();532 } finally {533 recordLayoutEffectDuration(finishedWork);534 }535 } else {536 instance.componentDidMount();537 }538 } else {539 const prevProps =540 finishedWork.elementType === finishedWork.type541 ? current.memoizedProps542 : resolveDefaultProps(finishedWork.type, current.memoizedProps);543 const prevState = current.memoizedState;544 // We could update instance props and state here,545 // but instead we rely on them being set during last render.546 // TODO: revisit this when we implement resuming.547 if (__DEV__) {548 if (549 finishedWork.type === finishedWork.elementType &&550 !didWarnAboutReassigningProps551 ) {552 if (instance.props !== finishedWork.memoizedProps) {553 console.error(554 'Expected %s props to match memoized props before ' +555 'componentDidUpdate. ' +556 'This might either be because of a bug in React, or because ' +557 'a component reassigns its own `this.props`. ' +558 'Please file an issue.',559 getComponentName(finishedWork.type) || 'instance',560 );561 }562 if (instance.state !== finishedWork.memoizedState) {563 console.error(564 'Expected %s state to match memoized state before ' +565 'componentDidUpdate. ' +566 'This might either be because of a bug in React, or because ' +567 'a component reassigns its own `this.state`. ' +568 'Please file an issue.',569 getComponentName(finishedWork.type) || 'instance',570 );571 }572 }573 }574 if (575 enableProfilerTimer &&576 enableProfilerCommitHooks &&577 finishedWork.mode & ProfileMode578 ) {579 try {580 startLayoutEffectTimer();581 instance.componentDidUpdate(582 prevProps,583 prevState,584 instance.__reactInternalSnapshotBeforeUpdate,585 );586 } finally {587 recordLayoutEffectDuration(finishedWork);588 }589 } else {590 instance.componentDidUpdate(591 prevProps,592 prevState,593 instance.__reactInternalSnapshotBeforeUpdate,594 );595 }596 }597 }598 // TODO: I think this is now always non-null by the time it reaches the599 // commit phase. Consider removing the type check.600 const updateQueue: UpdateQueue<601 *,602 > | null = (finishedWork.updateQueue: any);603 if (updateQueue !== null) {604 if (__DEV__) {605 if (606 finishedWork.type === finishedWork.elementType &&607 !didWarnAboutReassigningProps608 ) {609 if (instance.props !== finishedWork.memoizedProps) {610 console.error(611 'Expected %s props to match memoized props before ' +612 'processing the update queue. ' +613 'This might either be because of a bug in React, or because ' +614 'a component reassigns its own `this.props`. ' +615 'Please file an issue.',616 getComponentName(finishedWork.type) || 'instance',617 );618 }619 if (instance.state !== finishedWork.memoizedState) {620 console.error(621 'Expected %s state to match memoized state before ' +622 'processing the update queue. ' +623 'This might either be because of a bug in React, or because ' +624 'a component reassigns its own `this.state`. ' +625 'Please file an issue.',626 getComponentName(finishedWork.type) || 'instance',627 );628 }629 }630 }631 // We could update instance props and state here,632 // but instead we rely on them being set during last render.633 // TODO: revisit this when we implement resuming.634 commitUpdateQueue(finishedWork, updateQueue, instance);635 }636 return;637 }638 case HostRoot: {639 // TODO: I think this is now always non-null by the time it reaches the640 // commit phase. Consider removing the type check.641 const updateQueue: UpdateQueue<642 *,643 > | null = (finishedWork.updateQueue: any);644 if (updateQueue !== null) {645 let instance = null;646 if (finishedWork.child !== null) {647 switch (finishedWork.child.tag) {648 case HostComponent:649 instance = getPublicInstance(finishedWork.child.stateNode);650 break;651 case ClassComponent:652 instance = finishedWork.child.stateNode;653 break;654 }655 }656 commitUpdateQueue(finishedWork, updateQueue, instance);657 }658 return;659 }660 case HostComponent: {661 const instance: Instance = finishedWork.stateNode;662 // Renderers may schedule work to be done after host components are mounted663 // (eg DOM renderer may schedule auto-focus for inputs and form controls).664 // These effects should only be committed when components are first mounted,665 // aka when there is no current/alternate.666 if (current === null && finishedWork.flags & Update) {667 const type = finishedWork.type;668 const props = finishedWork.memoizedProps;669 commitMount(instance, type, props, finishedWork);670 }671 return;672 }673 case HostText: {674 // We have no life-cycles associated with text.675 return;676 }677 case HostPortal: {678 // We have no life-cycles associated with portals.679 return;680 }681 case Profiler: {682 if (enableProfilerTimer) {683 const {onCommit, onRender} = finishedWork.memoizedProps;684 const {effectDuration} = finishedWork.stateNode;685 const commitTime = getCommitTime();686 let phase = current === null ? 'mount' : 'update';687 if (enableProfilerNestedUpdatePhase) {688 if (isCurrentUpdateNested()) {689 phase = 'nested-update';690 }691 }692 if (typeof onRender === 'function') {693 if (enableSchedulerTracing) {694 onRender(695 finishedWork.memoizedProps.id,696 phase,697 finishedWork.actualDuration,698 finishedWork.treeBaseDuration,699 finishedWork.actualStartTime,700 commitTime,701 finishedRoot.memoizedInteractions,702 );703 } else {704 onRender(705 finishedWork.memoizedProps.id,706 phase,707 finishedWork.actualDuration,708 finishedWork.treeBaseDuration,709 finishedWork.actualStartTime,710 commitTime,711 );712 }713 }714 if (enableProfilerCommitHooks) {715 if (typeof onCommit === 'function') {716 if (enableSchedulerTracing) {717 onCommit(718 finishedWork.memoizedProps.id,719 phase,720 effectDuration,721 commitTime,722 finishedRoot.memoizedInteractions,723 );724 } else {725 onCommit(726 finishedWork.memoizedProps.id,727 phase,728 effectDuration,729 commitTime,730 );731 }732 }733 // Schedule a passive effect for this Profiler to call onPostCommit hooks.734 // This effect should be scheduled even if there is no onPostCommit callback for this Profiler,735 // because the effect is also where times bubble to parent Profilers.736 enqueuePendingPassiveProfilerEffect(finishedWork);737 // Propagate layout effect durations to the next nearest Profiler ancestor.738 // Do not reset these values until the next render so DevTools has a chance to read them first.739 let parentFiber = finishedWork.return;740 while (parentFiber !== null) {741 if (parentFiber.tag === Profiler) {742 const parentStateNode = parentFiber.stateNode;743 parentStateNode.effectDuration += effectDuration;744 break;745 }746 parentFiber = parentFiber.return;747 }748 }749 }750 return;751 }752 case SuspenseComponent: {753 commitSuspenseHydrationCallbacks(finishedRoot, finishedWork);754 return;755 }756 case SuspenseListComponent:757 case IncompleteClassComponent:758 case FundamentalComponent:759 case ScopeComponent:760 case OffscreenComponent:761 case LegacyHiddenComponent:762 return;763 }764 invariant(765 false,766 'This unit of work tag should not have side-effects. This error is ' +767 'likely caused by a bug in React. Please file an issue.',768 );769}770function hideOrUnhideAllChildren(finishedWork, isHidden) {771 if (supportsMutation) {772 // We only have the top Fiber that was inserted but we need to recurse down its773 // children to find all the terminal nodes.774 let node: Fiber = finishedWork;775 while (true) {776 if (node.tag === HostComponent) {777 const instance = node.stateNode;778 if (isHidden) {779 hideInstance(instance);780 } else {781 unhideInstance(node.stateNode, node.memoizedProps);782 }783 } else if (node.tag === HostText) {784 const instance = node.stateNode;785 if (isHidden) {786 hideTextInstance(instance);787 } else {788 unhideTextInstance(instance, node.memoizedProps);789 }790 } else if (791 (node.tag === OffscreenComponent ||792 node.tag === LegacyHiddenComponent) &&793 (node.memoizedState: OffscreenState) !== null &&794 node !== finishedWork795 ) {796 // Found a nested Offscreen component that is hidden. Don't search797 // any deeper. This tree should remain hidden.798 } else if (node.child !== null) {799 node.child.return = node;800 node = node.child;801 continue;802 }803 if (node === finishedWork) {804 return;805 }806 while (node.sibling === null) {807 if (node.return === null || node.return === finishedWork) {808 return;809 }810 node = node.return;811 }812 node.sibling.return = node.return;813 node = node.sibling;814 }815 }816}817function commitAttachRef(finishedWork: Fiber) {818 const ref = finishedWork.ref;819 if (ref !== null) {820 const instance = finishedWork.stateNode;821 let instanceToUse;822 switch (finishedWork.tag) {823 case HostComponent:824 instanceToUse = getPublicInstance(instance);825 break;826 default:827 instanceToUse = instance;828 }829 // Moved outside to ensure DCE works with this flag830 if (enableScopeAPI && finishedWork.tag === ScopeComponent) {831 instanceToUse = instance;832 }833 if (typeof ref === 'function') {834 if (835 enableProfilerTimer &&836 enableProfilerCommitHooks &&837 finishedWork.mode & ProfileMode838 ) {839 try {840 startLayoutEffectTimer();841 ref(instanceToUse);842 } finally {843 recordLayoutEffectDuration(finishedWork);844 }845 } else {846 ref(instanceToUse);847 }848 } else {849 if (__DEV__) {850 if (!ref.hasOwnProperty('current')) {851 console.error(852 'Unexpected ref object provided for %s. ' +853 'Use either a ref-setter function or React.createRef().',854 getComponentName(finishedWork.type),855 );856 }857 }858 ref.current = instanceToUse;859 }860 }861}862function commitDetachRef(current: Fiber) {863 const currentRef = current.ref;864 if (currentRef !== null) {865 if (typeof currentRef === 'function') {866 if (867 enableProfilerTimer &&868 enableProfilerCommitHooks &&869 current.mode & ProfileMode870 ) {871 try {872 startLayoutEffectTimer();873 currentRef(null);874 } finally {875 recordLayoutEffectDuration(current);876 }877 } else {878 currentRef(null);879 }880 } else {881 currentRef.current = null;882 }883 }884}885// User-originating errors (lifecycles and refs) should not interrupt886// deletion, so don't let them throw. Host-originating errors should887// interrupt deletion, so it's okay888function commitUnmount(889 finishedRoot: FiberRoot,890 current: Fiber,891 renderPriorityLevel: ReactPriorityLevel,892): void {893 onCommitUnmount(current);894 switch (current.tag) {895 case FunctionComponent:896 case ForwardRef:897 case MemoComponent:898 case SimpleMemoComponent: {899 const updateQueue: FunctionComponentUpdateQueue | null = (current.updateQueue: any);900 if (updateQueue !== null) {901 const lastEffect = updateQueue.lastEffect;902 if (lastEffect !== null) {903 const firstEffect = lastEffect.next;904 let effect = firstEffect;905 do {906 const {destroy, tag} = effect;907 if (destroy !== undefined) {908 if ((tag & HookPassive) !== NoHookEffect) {909 enqueuePendingPassiveHookEffectUnmount(current, effect);910 } else {911 if (912 enableProfilerTimer &&913 enableProfilerCommitHooks &&914 current.mode & ProfileMode915 ) {916 startLayoutEffectTimer();917 safelyCallDestroy(current, destroy);918 recordLayoutEffectDuration(current);919 } else {920 safelyCallDestroy(current, destroy);921 }922 }923 }924 effect = effect.next;925 } while (effect !== firstEffect);926 }927 }928 return;929 }930 case ClassComponent: {931 safelyDetachRef(current);932 const instance = current.stateNode;933 if (typeof instance.componentWillUnmount === 'function') {934 safelyCallComponentWillUnmount(current, instance);935 }936 return;937 }938 case HostComponent: {939 safelyDetachRef(current);940 return;941 }942 case HostPortal: {943 // TODO: this is recursive.944 // We are also not using this parent because945 // the portal will get pushed immediately.946 if (supportsMutation) {947 unmountHostComponents(finishedRoot, current, renderPriorityLevel);948 } else if (supportsPersistence) {949 emptyPortalContainer(current);950 }951 return;952 }953 case FundamentalComponent: {954 if (enableFundamentalAPI) {955 const fundamentalInstance = current.stateNode;956 if (fundamentalInstance !== null) {957 unmountFundamentalComponent(fundamentalInstance);958 current.stateNode = null;959 }960 }961 return;962 }963 case DehydratedFragment: {964 if (enableSuspenseCallback) {965 const hydrationCallbacks = finishedRoot.hydrationCallbacks;966 if (hydrationCallbacks !== null) {967 const onDeleted = hydrationCallbacks.onDeleted;968 if (onDeleted) {969 onDeleted((current.stateNode: SuspenseInstance));970 }971 }972 }973 return;974 }975 case ScopeComponent: {976 if (enableScopeAPI) {977 safelyDetachRef(current);978 }979 return;980 }981 }982}983function commitNestedUnmounts(984 finishedRoot: FiberRoot,985 root: Fiber,986 renderPriorityLevel: ReactPriorityLevel,987): void {988 // While we're inside a removed host node we don't want to call989 // removeChild on the inner nodes because they're removed by the top990 // call anyway. We also want to call componentWillUnmount on all991 // composites before this host node is removed from the tree. Therefore992 // we do an inner loop while we're still inside the host node.993 let node: Fiber = root;994 while (true) {995 commitUnmount(finishedRoot, node, renderPriorityLevel);996 // Visit children because they may contain more composite or host nodes.997 // Skip portals because commitUnmount() currently visits them recursively.998 if (999 node.child !== null &&1000 // If we use mutation we drill down into portals using commitUnmount above.1001 // If we don't use mutation we drill down into portals here instead.1002 (!supportsMutation || node.tag !== HostPortal)1003 ) {1004 node.child.return = node;1005 node = node.child;1006 continue;1007 }1008 if (node === root) {1009 return;1010 }1011 while (node.sibling === null) {1012 if (node.return === null || node.return === root) {1013 return;1014 }1015 node = node.return;1016 }1017 node.sibling.return = node.return;1018 node = node.sibling;1019 }1020}1021function detachFiberMutation(fiber: Fiber) {1022 // Cut off the return pointers to disconnect it from the tree. Ideally, we1023 // should clear the child pointer of the parent alternate to let this1024 // get GC:ed but we don't know which for sure which parent is the current1025 // one so we'll settle for GC:ing the subtree of this child. This child1026 // itself will be GC:ed when the parent updates the next time.1027 // Note: we cannot null out sibling here, otherwise it can cause issues1028 // with findDOMNode and how it requires the sibling field to carry out1029 // traversal in a later effect. See PR #16820. We now clear the sibling1030 // field after effects, see: detachFiberAfterEffects.1031 //1032 // Don't disconnect stateNode now; it will be detached in detachFiberAfterEffects.1033 // It may be required if the current component is an error boundary,1034 // and one of its descendants throws while unmounting a passive effect.1035 fiber.alternate = null;1036 fiber.child = null;1037 fiber.dependencies = null;1038 fiber.firstEffect = null;1039 fiber.lastEffect = null;1040 fiber.memoizedProps = null;1041 fiber.memoizedState = null;1042 fiber.pendingProps = null;1043 fiber.return = null;1044 fiber.updateQueue = null;1045 if (__DEV__) {1046 fiber._debugOwner = null;1047 }1048}1049function emptyPortalContainer(current: Fiber) {1050 if (!supportsPersistence) {1051 return;1052 }1053 const portal: {1054 containerInfo: Container,1055 pendingChildren: ChildSet,1056 ...1057 } = current.stateNode;1058 const {containerInfo} = portal;1059 const emptyChildSet = createContainerChildSet(containerInfo);1060 replaceContainerChildren(containerInfo, emptyChildSet);1061}1062function commitContainer(finishedWork: Fiber) {1063 if (!supportsPersistence) {1064 return;1065 }1066 switch (finishedWork.tag) {1067 case ClassComponent:1068 case HostComponent:1069 case HostText:1070 case FundamentalComponent: {1071 return;1072 }1073 case HostRoot:1074 case HostPortal: {1075 const portalOrRoot: {1076 containerInfo: Container,1077 pendingChildren: ChildSet,1078 ...1079 } = finishedWork.stateNode;1080 const {containerInfo, pendingChildren} = portalOrRoot;1081 replaceContainerChildren(containerInfo, pendingChildren);1082 return;1083 }1084 }1085 invariant(1086 false,1087 'This unit of work tag should not have side-effects. This error is ' +1088 'likely caused by a bug in React. Please file an issue.',1089 );1090}1091function getHostParentFiber(fiber: Fiber): Fiber {1092 let parent = fiber.return;1093 while (parent !== null) {1094 if (isHostParent(parent)) {1095 return parent;1096 }1097 parent = parent.return;1098 }1099 invariant(1100 false,1101 'Expected to find a host parent. This error is likely caused by a bug ' +1102 'in React. Please file an issue.',1103 );1104}1105function isHostParent(fiber: Fiber): boolean {1106 return (1107 fiber.tag === HostComponent ||1108 fiber.tag === HostRoot ||1109 fiber.tag === HostPortal1110 );1111}1112function getHostSibling(fiber: Fiber): ?Instance {1113 // We're going to search forward into the tree until we find a sibling host1114 // node. Unfortunately, if multiple insertions are done in a row we have to1115 // search past them. This leads to exponential search for the next sibling.1116 // TODO: Find a more efficient way to do this.1117 let node: Fiber = fiber;1118 siblings: while (true) {1119 // If we didn't find anything, let's try the next sibling.1120 while (node.sibling === null) {1121 if (node.return === null || isHostParent(node.return)) {1122 // If we pop out of the root or hit the parent the fiber we are the1123 // last sibling.1124 return null;1125 }1126 node = node.return;1127 }1128 node.sibling.return = node.return;1129 node = node.sibling;1130 while (1131 node.tag !== HostComponent &&1132 node.tag !== HostText &&1133 node.tag !== DehydratedFragment1134 ) {1135 // If it is not host node and, we might have a host node inside it.1136 // Try to search down until we find one.1137 if (node.flags & Placement) {1138 // If we don't have a child, try the siblings instead.1139 continue siblings;1140 }1141 // If we don't have a child, try the siblings instead.1142 // We also skip portals because they are not part of this host tree.1143 if (node.child === null || node.tag === HostPortal) {1144 continue siblings;1145 } else {1146 node.child.return = node;1147 node = node.child;1148 }1149 }1150 // Check if this host node is stable or about to be placed.1151 if (!(node.flags & Placement)) {1152 // Found it!1153 return node.stateNode;1154 }1155 }1156}1157function commitPlacement(finishedWork: Fiber): void {1158 if (!supportsMutation) {1159 return;1160 }1161 // Recursively insert all host nodes into the parent.1162 const parentFiber = getHostParentFiber(finishedWork);1163 // Note: these two variables *must* always be updated together.1164 let parent;1165 let isContainer;1166 const parentStateNode = parentFiber.stateNode;1167 switch (parentFiber.tag) {1168 case HostComponent:1169 parent = parentStateNode;1170 isContainer = false;1171 break;1172 case HostRoot:1173 parent = parentStateNode.containerInfo;1174 isContainer = true;1175 break;1176 case HostPortal:1177 parent = parentStateNode.containerInfo;1178 isContainer = true;1179 break;1180 case FundamentalComponent:1181 if (enableFundamentalAPI) {1182 parent = parentStateNode.instance;1183 isContainer = false;1184 }1185 // eslint-disable-next-line-no-fallthrough1186 default:1187 invariant(1188 false,1189 'Invalid host parent fiber. This error is likely caused by a bug ' +1190 'in React. Please file an issue.',1191 );1192 }1193 if (parentFiber.flags & ContentReset) {1194 // Reset the text content of the parent before doing any insertions1195 resetTextContent(parent);1196 // Clear ContentReset from the effect tag1197 parentFiber.flags &= ~ContentReset;1198 }1199 const before = getHostSibling(finishedWork);1200 // We only have the top Fiber that was inserted but we need to recurse down its1201 // children to find all the terminal nodes.1202 if (isContainer) {1203 insertOrAppendPlacementNodeIntoContainer(finishedWork, before, parent);1204 } else {1205 insertOrAppendPlacementNode(finishedWork, before, parent);1206 }1207}1208function insertOrAppendPlacementNodeIntoContainer(1209 node: Fiber,1210 before: ?Instance,1211 parent: Container,1212): void {1213 const {tag} = node;1214 const isHost = tag === HostComponent || tag === HostText;1215 if (isHost || (enableFundamentalAPI && tag === FundamentalComponent)) {1216 const stateNode = isHost ? node.stateNode : node.stateNode.instance;1217 if (before) {1218 insertInContainerBefore(parent, stateNode, before);1219 } else {1220 appendChildToContainer(parent, stateNode);1221 }1222 } else if (tag === HostPortal) {1223 // If the insertion itself is a portal, then we don't want to traverse1224 // down its children. Instead, we'll get insertions from each child in1225 // the portal directly.1226 } else {1227 const child = node.child;1228 if (child !== null) {1229 insertOrAppendPlacementNodeIntoContainer(child, before, parent);1230 let sibling = child.sibling;1231 while (sibling !== null) {1232 insertOrAppendPlacementNodeIntoContainer(sibling, before, parent);1233 sibling = sibling.sibling;1234 }1235 }1236 }1237}1238function insertOrAppendPlacementNode(1239 node: Fiber,1240 before: ?Instance,1241 parent: Instance,1242): void {1243 const {tag} = node;1244 const isHost = tag === HostComponent || tag === HostText;1245 if (isHost || (enableFundamentalAPI && tag === FundamentalComponent)) {1246 const stateNode = isHost ? node.stateNode : node.stateNode.instance;1247 if (before) {1248 insertBefore(parent, stateNode, before);1249 } else {1250 appendChild(parent, stateNode);1251 }1252 } else if (tag === HostPortal) {1253 // If the insertion itself is a portal, then we don't want to traverse1254 // down its children. Instead, we'll get insertions from each child in1255 // the portal directly.1256 } else {1257 const child = node.child;1258 if (child !== null) {1259 insertOrAppendPlacementNode(child, before, parent);1260 let sibling = child.sibling;1261 while (sibling !== null) {1262 insertOrAppendPlacementNode(sibling, before, parent);1263 sibling = sibling.sibling;1264 }1265 }1266 }1267}1268function unmountHostComponents(1269 finishedRoot: FiberRoot,1270 current: Fiber,1271 renderPriorityLevel: ReactPriorityLevel,1272): void {1273 // We only have the top Fiber that was deleted but we need to recurse down its1274 // children to find all the terminal nodes.1275 let node: Fiber = current;1276 // Each iteration, currentParent is populated with node's host parent if not1277 // currentParentIsValid.1278 let currentParentIsValid = false;1279 // Note: these two variables *must* always be updated together.1280 let currentParent;1281 let currentParentIsContainer;1282 while (true) {1283 if (!currentParentIsValid) {1284 let parent = node.return;1285 findParent: while (true) {1286 invariant(1287 parent !== null,1288 'Expected to find a host parent. This error is likely caused by ' +1289 'a bug in React. Please file an issue.',1290 );1291 const parentStateNode = parent.stateNode;1292 switch (parent.tag) {1293 case HostComponent:1294 currentParent = parentStateNode;1295 currentParentIsContainer = false;1296 break findParent;1297 case HostRoot:1298 currentParent = parentStateNode.containerInfo;1299 currentParentIsContainer = true;1300 break findParent;1301 case HostPortal:1302 currentParent = parentStateNode.containerInfo;1303 currentParentIsContainer = true;1304 break findParent;1305 case FundamentalComponent:1306 if (enableFundamentalAPI) {1307 currentParent = parentStateNode.instance;1308 currentParentIsContainer = false;1309 }1310 }1311 parent = parent.return;1312 }1313 currentParentIsValid = true;1314 }1315 if (node.tag === HostComponent || node.tag === HostText) {1316 commitNestedUnmounts(finishedRoot, node, renderPriorityLevel);1317 // After all the children have unmounted, it is now safe to remove the1318 // node from the tree.1319 if (currentParentIsContainer) {1320 removeChildFromContainer(1321 ((currentParent: any): Container),1322 (node.stateNode: Instance | TextInstance),1323 );1324 } else {1325 removeChild(1326 ((currentParent: any): Instance),1327 (node.stateNode: Instance | TextInstance),1328 );1329 }1330 // Don't visit children because we already visited them.1331 } else if (enableFundamentalAPI && node.tag === FundamentalComponent) {1332 const fundamentalNode = node.stateNode.instance;1333 commitNestedUnmounts(finishedRoot, node, renderPriorityLevel);1334 // After all the children have unmounted, it is now safe to remove the1335 // node from the tree.1336 if (currentParentIsContainer) {1337 removeChildFromContainer(1338 ((currentParent: any): Container),1339 (fundamentalNode: Instance),1340 );1341 } else {1342 removeChild(1343 ((currentParent: any): Instance),1344 (fundamentalNode: Instance),1345 );1346 }1347 } else if (1348 enableSuspenseServerRenderer &&1349 node.tag === DehydratedFragment1350 ) {1351 if (enableSuspenseCallback) {1352 const hydrationCallbacks = finishedRoot.hydrationCallbacks;1353 if (hydrationCallbacks !== null) {1354 const onDeleted = hydrationCallbacks.onDeleted;1355 if (onDeleted) {1356 onDeleted((node.stateNode: SuspenseInstance));1357 }1358 }1359 }1360 // Delete the dehydrated suspense boundary and all of its content.1361 if (currentParentIsContainer) {1362 clearSuspenseBoundaryFromContainer(1363 ((currentParent: any): Container),1364 (node.stateNode: SuspenseInstance),1365 );1366 } else {1367 clearSuspenseBoundary(1368 ((currentParent: any): Instance),1369 (node.stateNode: SuspenseInstance),1370 );1371 }1372 } else if (node.tag === HostPortal) {1373 if (node.child !== null) {1374 // When we go into a portal, it becomes the parent to remove from.1375 // We will reassign it back when we pop the portal on the way up.1376 currentParent = node.stateNode.containerInfo;1377 currentParentIsContainer = true;1378 // Visit children because portals might contain host components.1379 node.child.return = node;1380 node = node.child;1381 continue;1382 }1383 } else {1384 commitUnmount(finishedRoot, node, renderPriorityLevel);1385 // Visit children because we may find more host components below.1386 if (node.child !== null) {1387 node.child.return = node;1388 node = node.child;1389 continue;1390 }1391 }1392 if (node === current) {1393 return;1394 }1395 while (node.sibling === null) {1396 if (node.return === null || node.return === current) {1397 return;1398 }1399 node = node.return;1400 if (node.tag === HostPortal) {1401 // When we go out of the portal, we need to restore the parent.1402 // Since we don't keep a stack of them, we will search for it.1403 currentParentIsValid = false;1404 }1405 }1406 node.sibling.return = node.return;1407 node = node.sibling;1408 }1409}1410function commitDeletion(1411 finishedRoot: FiberRoot,1412 current: Fiber,1413 renderPriorityLevel: ReactPriorityLevel,1414): void {1415 if (supportsMutation) {1416 // Recursively delete all host nodes from the parent.1417 // Detach refs and call componentWillUnmount() on the whole subtree.1418 unmountHostComponents(finishedRoot, current, renderPriorityLevel);1419 } else {1420 // Detach refs and call componentWillUnmount() on the whole subtree.1421 commitNestedUnmounts(finishedRoot, current, renderPriorityLevel);1422 }1423 const alternate = current.alternate;1424 detachFiberMutation(current);1425 if (alternate !== null) {1426 detachFiberMutation(alternate);1427 }1428}1429function commitWork(current: Fiber | null, finishedWork: Fiber): void {1430 if (!supportsMutation) {1431 switch (finishedWork.tag) {1432 case FunctionComponent:1433 case ForwardRef:1434 case MemoComponent:1435 case SimpleMemoComponent: {1436 // Layout effects are destroyed during the mutation phase so that all1437 // destroy functions for all fibers are called before any create functions.1438 // This prevents sibling component effects from interfering with each other,1439 // e.g. a destroy function in one component should never override a ref set1440 // by a create function in another component during the same commit.1441 if (1442 enableProfilerTimer &&1443 enableProfilerCommitHooks &&1444 finishedWork.mode & ProfileMode1445 ) {1446 try {1447 startLayoutEffectTimer();1448 commitHookEffectListUnmount(1449 HookLayout | HookHasEffect,1450 finishedWork,1451 );1452 } finally {1453 recordLayoutEffectDuration(finishedWork);1454 }1455 } else {1456 commitHookEffectListUnmount(HookLayout | HookHasEffect, finishedWork);1457 }1458 return;1459 }1460 case Profiler: {1461 return;1462 }1463 case SuspenseComponent: {1464 commitSuspenseComponent(finishedWork);1465 attachSuspenseRetryListeners(finishedWork);1466 return;1467 }1468 case SuspenseListComponent: {1469 attachSuspenseRetryListeners(finishedWork);1470 return;1471 }1472 case HostRoot: {1473 if (supportsHydration) {1474 const root: FiberRoot = finishedWork.stateNode;1475 if (root.hydrate) {1476 // We've just hydrated. No need to hydrate again.1477 root.hydrate = false;1478 commitHydratedContainer(root.containerInfo);1479 }1480 }1481 break;1482 }1483 case OffscreenComponent:1484 case LegacyHiddenComponent: {1485 return;1486 }1487 }1488 commitContainer(finishedWork);1489 return;1490 }1491 switch (finishedWork.tag) {1492 case FunctionComponent:1493 case ForwardRef:1494 case MemoComponent:1495 case SimpleMemoComponent: {1496 // Layout effects are destroyed during the mutation phase so that all1497 // destroy functions for all fibers are called before any create functions.1498 // This prevents sibling component effects from interfering with each other,1499 // e.g. a destroy function in one component should never override a ref set1500 // by a create function in another component during the same commit.1501 if (1502 enableProfilerTimer &&1503 enableProfilerCommitHooks &&1504 finishedWork.mode & ProfileMode1505 ) {1506 try {1507 startLayoutEffectTimer();1508 commitHookEffectListUnmount(HookLayout | HookHasEffect, finishedWork);1509 } finally {1510 recordLayoutEffectDuration(finishedWork);1511 }1512 } else {1513 commitHookEffectListUnmount(HookLayout | HookHasEffect, finishedWork);1514 }1515 return;1516 }1517 case ClassComponent: {1518 return;1519 }1520 case HostComponent: {1521 const instance: Instance = finishedWork.stateNode;1522 if (instance != null) {1523 // Commit the work prepared earlier.1524 const newProps = finishedWork.memoizedProps;1525 // For hydration we reuse the update path but we treat the oldProps1526 // as the newProps. The updatePayload will contain the real change in1527 // this case.1528 const oldProps = current !== null ? current.memoizedProps : newProps;1529 const type = finishedWork.type;1530 // TODO: Type the updateQueue to be specific to host components.1531 const updatePayload: null | UpdatePayload = (finishedWork.updateQueue: any);1532 finishedWork.updateQueue = null;1533 if (updatePayload !== null) {1534 commitUpdate(1535 instance,1536 updatePayload,1537 type,1538 oldProps,1539 newProps,1540 finishedWork,1541 );1542 }1543 }1544 return;1545 }1546 case HostText: {1547 invariant(1548 finishedWork.stateNode !== null,1549 'This should have a text node initialized. This error is likely ' +1550 'caused by a bug in React. Please file an issue.',1551 );1552 const textInstance: TextInstance = finishedWork.stateNode;1553 const newText: string = finishedWork.memoizedProps;1554 // For hydration we reuse the update path but we treat the oldProps1555 // as the newProps. The updatePayload will contain the real change in1556 // this case.1557 const oldText: string =1558 current !== null ? current.memoizedProps : newText;1559 commitTextUpdate(textInstance, oldText, newText);1560 return;1561 }1562 case HostRoot: {1563 if (supportsHydration) {1564 const root: FiberRoot = finishedWork.stateNode;1565 if (root.hydrate) {1566 // We've just hydrated. No need to hydrate again.1567 root.hydrate = false;1568 commitHydratedContainer(root.containerInfo);1569 }1570 }1571 return;1572 }1573 case Profiler: {1574 return;1575 }1576 case SuspenseComponent: {1577 commitSuspenseComponent(finishedWork);1578 attachSuspenseRetryListeners(finishedWork);1579 return;1580 }1581 case SuspenseListComponent: {1582 attachSuspenseRetryListeners(finishedWork);1583 return;1584 }1585 case IncompleteClassComponent: {1586 return;1587 }1588 case FundamentalComponent: {1589 if (enableFundamentalAPI) {1590 const fundamentalInstance = finishedWork.stateNode;1591 updateFundamentalComponent(fundamentalInstance);1592 return;1593 }1594 break;1595 }1596 case ScopeComponent: {1597 if (enableScopeAPI) {1598 const scopeInstance = finishedWork.stateNode;1599 prepareScopeUpdate(scopeInstance, finishedWork);1600 return;1601 }1602 break;1603 }1604 case OffscreenComponent:1605 case LegacyHiddenComponent: {1606 const newState: OffscreenState | null = finishedWork.memoizedState;1607 const isHidden = newState !== null;1608 hideOrUnhideAllChildren(finishedWork, isHidden);1609 return;1610 }1611 }1612 invariant(1613 false,1614 'This unit of work tag should not have side-effects. This error is ' +1615 'likely caused by a bug in React. Please file an issue.',1616 );1617}1618function commitSuspenseComponent(finishedWork: Fiber) {1619 const newState: SuspenseState | null = finishedWork.memoizedState;1620 if (newState !== null) {1621 markCommitTimeOfFallback();1622 if (supportsMutation) {1623 // Hide the Offscreen component that contains the primary children. TODO:1624 // Ideally, this effect would have been scheduled on the Offscreen fiber1625 // itself. That's how unhiding works: the Offscreen component schedules an1626 // effect on itself. However, in this case, the component didn't complete,1627 // so the fiber was never added to the effect list in the normal path. We1628 // could have appended it to the effect list in the Suspense component's1629 // second pass, but doing it this way is less complicated. This would be1630 // simpler if we got rid of the effect list and traversed the tree, like1631 // we're planning to do.1632 const primaryChildParent: Fiber = (finishedWork.child: any);1633 hideOrUnhideAllChildren(primaryChildParent, true);1634 }1635 }1636 if (enableSuspenseCallback && newState !== null) {1637 const suspenseCallback = finishedWork.memoizedProps.suspenseCallback;1638 if (typeof suspenseCallback === 'function') {1639 const wakeables: Set<Wakeable> | null = (finishedWork.updateQueue: any);1640 if (wakeables !== null) {1641 suspenseCallback(new Set(wakeables));1642 }1643 } else if (__DEV__) {1644 if (suspenseCallback !== undefined) {1645 console.error('Unexpected type for suspenseCallback.');1646 }1647 }1648 }1649}1650function commitSuspenseHydrationCallbacks(1651 finishedRoot: FiberRoot,1652 finishedWork: Fiber,1653) {1654 if (!supportsHydration) {1655 return;1656 }1657 const newState: SuspenseState | null = finishedWork.memoizedState;1658 if (newState === null) {1659 const current = finishedWork.alternate;1660 if (current !== null) {1661 const prevState: SuspenseState | null = current.memoizedState;1662 if (prevState !== null) {1663 const suspenseInstance = prevState.dehydrated;1664 if (suspenseInstance !== null) {1665 commitHydratedSuspenseInstance(suspenseInstance);1666 if (enableSuspenseCallback) {1667 const hydrationCallbacks = finishedRoot.hydrationCallbacks;1668 if (hydrationCallbacks !== null) {1669 const onHydrated = hydrationCallbacks.onHydrated;1670 if (onHydrated) {1671 onHydrated(suspenseInstance);1672 }1673 }1674 }1675 }1676 }1677 }1678 }1679}1680function attachSuspenseRetryListeners(finishedWork: Fiber) {1681 // If this boundary just timed out, then it will have a set of wakeables.1682 // For each wakeable, attach a listener so that when it resolves, React1683 // attempts to re-render the boundary in the primary (pre-timeout) state.1684 const wakeables: Set<Wakeable> | null = (finishedWork.updateQueue: any);1685 if (wakeables !== null) {1686 finishedWork.updateQueue = null;1687 let retryCache = finishedWork.stateNode;1688 if (retryCache === null) {1689 retryCache = finishedWork.stateNode = new PossiblyWeakSet();1690 }1691 wakeables.forEach(wakeable => {1692 // Memoize using the boundary fiber to prevent redundant listeners.1693 let retry = resolveRetryWakeable.bind(null, finishedWork, wakeable);1694 if (!retryCache.has(wakeable)) {1695 if (enableSchedulerTracing) {1696 if (wakeable.__reactDoNotTraceInteractions !== true) {1697 retry = Schedule_tracing_wrap(retry);1698 }1699 }1700 retryCache.add(wakeable);1701 wakeable.then(retry, retry);1702 }1703 });1704 }1705}1706// This function detects when a Suspense boundary goes from visible to hidden.1707// It returns false if the boundary is already hidden.1708// TODO: Use an effect tag.1709export function isSuspenseBoundaryBeingHidden(1710 current: Fiber | null,1711 finishedWork: Fiber,1712): boolean {1713 if (current !== null) {1714 const oldState: SuspenseState | null = current.memoizedState;1715 if (oldState === null || oldState.dehydrated !== null) {1716 const newState: SuspenseState | null = finishedWork.memoizedState;1717 return newState !== null && newState.dehydrated === null;1718 }1719 }1720 return false;1721}1722function commitResetTextContent(current: Fiber) {1723 if (!supportsMutation) {1724 return;1725 }1726 resetTextContent(current.stateNode);1727}1728export {1729 commitBeforeMutationLifeCycles,1730 commitResetTextContent,1731 commitPlacement,1732 commitDeletion,1733 commitWork,1734 commitLifeCycles,1735 commitAttachRef,1736 commitDetachRef,...

Full Screen

Full Screen

ReactFiberCommitWork.old.js

Source:ReactFiberCommitWork.old.js Github

copy

Full Screen

1/**2 * Copyright (c) Facebook, Inc. and its affiliates.3 *4 * This source code is licensed under the MIT license found in the5 * LICENSE file in the root directory of this source tree.6 *7 * 8 */9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26import {unstable_wrap as Schedule_tracing_wrap} from 'scheduler/tracing';27import {28 enableSchedulerTracing,29 enableProfilerTimer,30 enableProfilerCommitHooks,31 enableSuspenseServerRenderer,32 enableFundamentalAPI,33 enableSuspenseCallback,34 enableScopeAPI,35} from 'shared/ReactFeatureFlags';36import {37 FunctionComponent,38 ForwardRef,39 ClassComponent,40 HostRoot,41 HostComponent,42 HostText,43 HostPortal,44 Profiler,45 SuspenseComponent,46 DehydratedFragment,47 IncompleteClassComponent,48 MemoComponent,49 SimpleMemoComponent,50 SuspenseListComponent,51 FundamentalComponent,52 ScopeComponent,53 Block,54 OffscreenComponent,55 LegacyHiddenComponent,56} from './ReactWorkTags';57import {58 invokeGuardedCallback,59 hasCaughtError,60 clearCaughtError,61} from 'shared/ReactErrorUtils';62import {63 NoFlags,64 ContentReset,65 Placement,66 Snapshot,67 Update,68} from './ReactFiberFlags';69import getComponentName from 'shared/getComponentName';70import invariant from 'shared/invariant';71import {onCommitUnmount} from './ReactFiberDevToolsHook.old';72import {resolveDefaultProps} from './ReactFiberLazyComponent.old';73import {74 getCommitTime,75 recordLayoutEffectDuration,76 startLayoutEffectTimer,77} from './ReactProfilerTimer.old';78import {ProfileMode} from './ReactTypeOfMode';79import {commitUpdateQueue} from './ReactUpdateQueue.old';80import {81 getPublicInstance,82 supportsMutation,83 supportsPersistence,84 supportsHydration,85 commitMount,86 commitUpdate,87 resetTextContent,88 commitTextUpdate,89 appendChild,90 appendChildToContainer,91 insertBefore,92 insertInContainerBefore,93 removeChild,94 removeChildFromContainer,95 clearSuspenseBoundary,96 clearSuspenseBoundaryFromContainer,97 replaceContainerChildren,98 createContainerChildSet,99 hideInstance,100 hideTextInstance,101 unhideInstance,102 unhideTextInstance,103 unmountFundamentalComponent,104 updateFundamentalComponent,105 commitHydratedContainer,106 commitHydratedSuspenseInstance,107 clearContainer,108 prepareScopeUpdate,109} from './ReactFiberHostConfig';110import {111 captureCommitPhaseError,112 resolveRetryWakeable,113 markCommitTimeOfFallback,114 enqueuePendingPassiveHookEffectMount,115 enqueuePendingPassiveHookEffectUnmount,116 enqueuePendingPassiveProfilerEffect,117} from './ReactFiberWorkLoop.old';118import {119 NoFlags as NoHookEffect,120 HasEffect as HookHasEffect,121 Layout as HookLayout,122 Passive as HookPassive,123} from './ReactHookEffectTags';124import {didWarnAboutReassigningProps} from './ReactFiberBeginWork.old';125let didWarnAboutUndefinedSnapshotBeforeUpdate = null;126if (__DEV__) {127 didWarnAboutUndefinedSnapshotBeforeUpdate = new Set();128}129const PossiblyWeakSet = typeof WeakSet === 'function' ? WeakSet : Set;130const callComponentWillUnmountWithTimer = function(current, instance) {131 instance.props = current.memoizedProps;132 instance.state = current.memoizedState;133 if (134 enableProfilerTimer &&135 enableProfilerCommitHooks &&136 current.mode & ProfileMode137 ) {138 try {139 startLayoutEffectTimer();140 instance.componentWillUnmount();141 } finally {142 recordLayoutEffectDuration(current);143 }144 } else {145 instance.componentWillUnmount();146 }147};148// Capture errors so they don't interrupt unmounting.149function safelyCallComponentWillUnmount(current , instance ) {150 if (__DEV__) {151 invokeGuardedCallback(152 null,153 callComponentWillUnmountWithTimer,154 null,155 current,156 instance,157 );158 if (hasCaughtError()) {159 const unmountError = clearCaughtError();160 captureCommitPhaseError(current, unmountError);161 }162 } else {163 try {164 callComponentWillUnmountWithTimer(current, instance);165 } catch (unmountError) {166 captureCommitPhaseError(current, unmountError);167 }168 }169}170function safelyDetachRef(current ) {171 const ref = current.ref;172 if (ref !== null) {173 if (typeof ref === 'function') {174 if (__DEV__) {175 invokeGuardedCallback(null, ref, null, null);176 if (hasCaughtError()) {177 const refError = clearCaughtError();178 captureCommitPhaseError(current, refError);179 }180 } else {181 try {182 ref(null);183 } catch (refError) {184 captureCommitPhaseError(current, refError);185 }186 }187 } else {188 ref.current = null;189 }190 }191}192function safelyCallDestroy(current , destroy ) {193 if (__DEV__) {194 invokeGuardedCallback(null, destroy, null);195 if (hasCaughtError()) {196 const error = clearCaughtError();197 captureCommitPhaseError(current, error);198 }199 } else {200 try {201 destroy();202 } catch (error) {203 captureCommitPhaseError(current, error);204 }205 }206}207function commitBeforeMutationLifeCycles(208 current ,209 finishedWork ,210) {211 switch (finishedWork.tag) {212 case FunctionComponent:213 case ForwardRef:214 case SimpleMemoComponent:215 case Block: {216 return;217 }218 case ClassComponent: {219 if (finishedWork.flags & Snapshot) {220 if (current !== null) {221 const prevProps = current.memoizedProps;222 const prevState = current.memoizedState;223 const instance = finishedWork.stateNode;224 // We could update instance props and state here,225 // but instead we rely on them being set during last render.226 // TODO: revisit this when we implement resuming.227 if (__DEV__) {228 if (229 finishedWork.type === finishedWork.elementType &&230 !didWarnAboutReassigningProps231 ) {232 if (instance.props !== finishedWork.memoizedProps) {233 console.error(234 'Expected %s props to match memoized props before ' +235 'getSnapshotBeforeUpdate. ' +236 'This might either be because of a bug in React, or because ' +237 'a component reassigns its own `this.props`. ' +238 'Please file an issue.',239 getComponentName(finishedWork.type) || 'instance',240 );241 }242 if (instance.state !== finishedWork.memoizedState) {243 console.error(244 'Expected %s state to match memoized state before ' +245 'getSnapshotBeforeUpdate. ' +246 'This might either be because of a bug in React, or because ' +247 'a component reassigns its own `this.state`. ' +248 'Please file an issue.',249 getComponentName(finishedWork.type) || 'instance',250 );251 }252 }253 }254 const snapshot = instance.getSnapshotBeforeUpdate(255 finishedWork.elementType === finishedWork.type256 ? prevProps257 : resolveDefaultProps(finishedWork.type, prevProps),258 prevState,259 );260 if (__DEV__) {261 const didWarnSet = ((didWarnAboutUndefinedSnapshotBeforeUpdate ) );262 if (snapshot === undefined && !didWarnSet.has(finishedWork.type)) {263 didWarnSet.add(finishedWork.type);264 console.error(265 '%s.getSnapshotBeforeUpdate(): A snapshot value (or null) ' +266 'must be returned. You have returned undefined.',267 getComponentName(finishedWork.type),268 );269 }270 }271 instance.__reactInternalSnapshotBeforeUpdate = snapshot;272 }273 }274 return;275 }276 case HostRoot: {277 if (supportsMutation) {278 if (finishedWork.flags & Snapshot) {279 const root = finishedWork.stateNode;280 clearContainer(root.containerInfo);281 }282 }283 return;284 }285 case HostComponent:286 case HostText:287 case HostPortal:288 case IncompleteClassComponent:289 // Nothing to do for these component types290 return;291 }292 invariant(293 false,294 'This unit of work tag should not have side-effects. This error is ' +295 'likely caused by a bug in React. Please file an issue.',296 );297}298function commitHookEffectListUnmount(tag , finishedWork ) {299 const updateQueue = (finishedWork.updateQueue );300 const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;301 if (lastEffect !== null) {302 const firstEffect = lastEffect.next;303 let effect = firstEffect;304 do {305 if ((effect.tag & tag) === tag) {306 // Unmount307 const destroy = effect.destroy;308 effect.destroy = undefined;309 if (destroy !== undefined) {310 destroy();311 }312 }313 effect = effect.next;314 } while (effect !== firstEffect);315 }316}317function commitHookEffectListMount(tag , finishedWork ) {318 const updateQueue = (finishedWork.updateQueue );319 const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;320 if (lastEffect !== null) {321 const firstEffect = lastEffect.next;322 let effect = firstEffect;323 do {324 if ((effect.tag & tag) === tag) {325 // Mount326 const create = effect.create;327 effect.destroy = create();328 if (__DEV__) {329 const destroy = effect.destroy;330 if (destroy !== undefined && typeof destroy !== 'function') {331 let addendum;332 if (destroy === null) {333 addendum =334 ' You returned null. If your effect does not require clean ' +335 'up, return undefined (or nothing).';336 } else if (typeof destroy.then === 'function') {337 addendum =338 '\n\nIt looks like you wrote useEffect(async () => ...) or returned a Promise. ' +339 'Instead, write the async function inside your effect ' +340 'and call it immediately:\n\n' +341 'useEffect(() => {\n' +342 ' async function fetchData() {\n' +343 ' // You can await here\n' +344 ' const response = await MyAPI.getData(someId);\n' +345 ' // ...\n' +346 ' }\n' +347 ' fetchData();\n' +348 `}, [someId]); // Or [] if effect doesn't need props or state\n\n` +349 'Learn more about data fetching with Hooks: https://reactjs.org/link/hooks-data-fetching';350 } else {351 addendum = ' You returned: ' + destroy;352 }353 console.error(354 'An effect function must not return anything besides a function, ' +355 'which is used for clean-up.%s',356 addendum,357 );358 }359 }360 }361 effect = effect.next;362 } while (effect !== firstEffect);363 }364}365function schedulePassiveEffects(finishedWork ) {366 const updateQueue = (finishedWork.updateQueue );367 const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;368 if (lastEffect !== null) {369 const firstEffect = lastEffect.next;370 let effect = firstEffect;371 do {372 const {next, tag} = effect;373 if (374 (tag & HookPassive) !== NoHookEffect &&375 (tag & HookHasEffect) !== NoHookEffect376 ) {377 enqueuePendingPassiveHookEffectUnmount(finishedWork, effect);378 enqueuePendingPassiveHookEffectMount(finishedWork, effect);379 }380 effect = next;381 } while (effect !== firstEffect);382 }383}384export function commitPassiveEffectDurations(385 finishedRoot ,386 finishedWork ,387) {388 if (enableProfilerTimer && enableProfilerCommitHooks) {389 // Only Profilers with work in their subtree will have an Update effect scheduled.390 if ((finishedWork.flags & Update) !== NoFlags) {391 switch (finishedWork.tag) {392 case Profiler: {393 const {passiveEffectDuration} = finishedWork.stateNode;394 const {id, onPostCommit} = finishedWork.memoizedProps;395 // This value will still reflect the previous commit phase.396 // It does not get reset until the start of the next commit phase.397 const commitTime = getCommitTime();398 if (typeof onPostCommit === 'function') {399 if (enableSchedulerTracing) {400 onPostCommit(401 id,402 finishedWork.alternate === null ? 'mount' : 'update',403 passiveEffectDuration,404 commitTime,405 finishedRoot.memoizedInteractions,406 );407 } else {408 onPostCommit(409 id,410 finishedWork.alternate === null ? 'mount' : 'update',411 passiveEffectDuration,412 commitTime,413 );414 }415 }416 // Bubble times to the next nearest ancestor Profiler.417 // After we process that Profiler, we'll bubble further up.418 let parentFiber = finishedWork.return;419 while (parentFiber !== null) {420 if (parentFiber.tag === Profiler) {421 const parentStateNode = parentFiber.stateNode;422 parentStateNode.passiveEffectDuration += passiveEffectDuration;423 break;424 }425 parentFiber = parentFiber.return;426 }427 break;428 }429 default:430 break;431 }432 }433 }434}435function commitLifeCycles(436 finishedRoot ,437 current ,438 finishedWork ,439 committedLanes ,440) {441 switch (finishedWork.tag) {442 case FunctionComponent:443 case ForwardRef:444 case SimpleMemoComponent:445 case Block: {446 // At this point layout effects have already been destroyed (during mutation phase).447 // This is done to prevent sibling component effects from interfering with each other,448 // e.g. a destroy function in one component should never override a ref set449 // by a create function in another component during the same commit.450 if (451 enableProfilerTimer &&452 enableProfilerCommitHooks &&453 finishedWork.mode & ProfileMode454 ) {455 try {456 startLayoutEffectTimer();457 commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork);458 } finally {459 recordLayoutEffectDuration(finishedWork);460 }461 } else {462 commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork);463 }464 schedulePassiveEffects(finishedWork);465 return;466 }467 case ClassComponent: {468 const instance = finishedWork.stateNode;469 if (finishedWork.flags & Update) {470 if (current === null) {471 // We could update instance props and state here,472 // but instead we rely on them being set during last render.473 // TODO: revisit this when we implement resuming.474 if (__DEV__) {475 if (476 finishedWork.type === finishedWork.elementType &&477 !didWarnAboutReassigningProps478 ) {479 if (instance.props !== finishedWork.memoizedProps) {480 console.error(481 'Expected %s props to match memoized props before ' +482 'componentDidMount. ' +483 'This might either be because of a bug in React, or because ' +484 'a component reassigns its own `this.props`. ' +485 'Please file an issue.',486 getComponentName(finishedWork.type) || 'instance',487 );488 }489 if (instance.state !== finishedWork.memoizedState) {490 console.error(491 'Expected %s state to match memoized state before ' +492 'componentDidMount. ' +493 'This might either be because of a bug in React, or because ' +494 'a component reassigns its own `this.state`. ' +495 'Please file an issue.',496 getComponentName(finishedWork.type) || 'instance',497 );498 }499 }500 }501 if (502 enableProfilerTimer &&503 enableProfilerCommitHooks &&504 finishedWork.mode & ProfileMode505 ) {506 try {507 startLayoutEffectTimer();508 instance.componentDidMount();509 } finally {510 recordLayoutEffectDuration(finishedWork);511 }512 } else {513 instance.componentDidMount();514 }515 } else {516 const prevProps =517 finishedWork.elementType === finishedWork.type518 ? current.memoizedProps519 : resolveDefaultProps(finishedWork.type, current.memoizedProps);520 const prevState = current.memoizedState;521 // We could update instance props and state here,522 // but instead we rely on them being set during last render.523 // TODO: revisit this when we implement resuming.524 if (__DEV__) {525 if (526 finishedWork.type === finishedWork.elementType &&527 !didWarnAboutReassigningProps528 ) {529 if (instance.props !== finishedWork.memoizedProps) {530 console.error(531 'Expected %s props to match memoized props before ' +532 'componentDidUpdate. ' +533 'This might either be because of a bug in React, or because ' +534 'a component reassigns its own `this.props`. ' +535 'Please file an issue.',536 getComponentName(finishedWork.type) || 'instance',537 );538 }539 if (instance.state !== finishedWork.memoizedState) {540 console.error(541 'Expected %s state to match memoized state before ' +542 'componentDidUpdate. ' +543 'This might either be because of a bug in React, or because ' +544 'a component reassigns its own `this.state`. ' +545 'Please file an issue.',546 getComponentName(finishedWork.type) || 'instance',547 );548 }549 }550 }551 if (552 enableProfilerTimer &&553 enableProfilerCommitHooks &&554 finishedWork.mode & ProfileMode555 ) {556 try {557 startLayoutEffectTimer();558 instance.componentDidUpdate(559 prevProps,560 prevState,561 instance.__reactInternalSnapshotBeforeUpdate,562 );563 } finally {564 recordLayoutEffectDuration(finishedWork);565 }566 } else {567 instance.componentDidUpdate(568 prevProps,569 prevState,570 instance.__reactInternalSnapshotBeforeUpdate,571 );572 }573 }574 }575 // TODO: I think this is now always non-null by the time it reaches the576 // commit phase. Consider removing the type check.577 const updateQueue 578 579 = (finishedWork.updateQueue );580 if (updateQueue !== null) {581 if (__DEV__) {582 if (583 finishedWork.type === finishedWork.elementType &&584 !didWarnAboutReassigningProps585 ) {586 if (instance.props !== finishedWork.memoizedProps) {587 console.error(588 'Expected %s props to match memoized props before ' +589 'processing the update queue. ' +590 'This might either be because of a bug in React, or because ' +591 'a component reassigns its own `this.props`. ' +592 'Please file an issue.',593 getComponentName(finishedWork.type) || 'instance',594 );595 }596 if (instance.state !== finishedWork.memoizedState) {597 console.error(598 'Expected %s state to match memoized state before ' +599 'processing the update queue. ' +600 'This might either be because of a bug in React, or because ' +601 'a component reassigns its own `this.state`. ' +602 'Please file an issue.',603 getComponentName(finishedWork.type) || 'instance',604 );605 }606 }607 }608 // We could update instance props and state here,609 // but instead we rely on them being set during last render.610 // TODO: revisit this when we implement resuming.611 commitUpdateQueue(finishedWork, updateQueue, instance);612 }613 return;614 }615 case HostRoot: {616 // TODO: I think this is now always non-null by the time it reaches the617 // commit phase. Consider removing the type check.618 const updateQueue 619 620 = (finishedWork.updateQueue );621 if (updateQueue !== null) {622 let instance = null;623 if (finishedWork.child !== null) {624 switch (finishedWork.child.tag) {625 case HostComponent:626 instance = getPublicInstance(finishedWork.child.stateNode);627 break;628 case ClassComponent:629 instance = finishedWork.child.stateNode;630 break;631 }632 }633 commitUpdateQueue(finishedWork, updateQueue, instance);634 }635 return;636 }637 case HostComponent: {638 const instance = finishedWork.stateNode;639 // Renderers may schedule work to be done after host components are mounted640 // (eg DOM renderer may schedule auto-focus for inputs and form controls).641 // These effects should only be committed when components are first mounted,642 // aka when there is no current/alternate.643 if (current === null && finishedWork.flags & Update) {644 const type = finishedWork.type;645 const props = finishedWork.memoizedProps;646 commitMount(instance, type, props, finishedWork);647 }648 return;649 }650 case HostText: {651 // We have no life-cycles associated with text.652 return;653 }654 case HostPortal: {655 // We have no life-cycles associated with portals.656 return;657 }658 case Profiler: {659 if (enableProfilerTimer) {660 const {onCommit, onRender} = finishedWork.memoizedProps;661 const {effectDuration} = finishedWork.stateNode;662 const commitTime = getCommitTime();663 if (typeof onRender === 'function') {664 if (enableSchedulerTracing) {665 onRender(666 finishedWork.memoizedProps.id,667 current === null ? 'mount' : 'update',668 finishedWork.actualDuration,669 finishedWork.treeBaseDuration,670 finishedWork.actualStartTime,671 commitTime,672 finishedRoot.memoizedInteractions,673 );674 } else {675 onRender(676 finishedWork.memoizedProps.id,677 current === null ? 'mount' : 'update',678 finishedWork.actualDuration,679 finishedWork.treeBaseDuration,680 finishedWork.actualStartTime,681 commitTime,682 );683 }684 }685 if (enableProfilerCommitHooks) {686 if (typeof onCommit === 'function') {687 if (enableSchedulerTracing) {688 onCommit(689 finishedWork.memoizedProps.id,690 current === null ? 'mount' : 'update',691 effectDuration,692 commitTime,693 finishedRoot.memoizedInteractions,694 );695 } else {696 onCommit(697 finishedWork.memoizedProps.id,698 current === null ? 'mount' : 'update',699 effectDuration,700 commitTime,701 );702 }703 }704 // Schedule a passive effect for this Profiler to call onPostCommit hooks.705 // This effect should be scheduled even if there is no onPostCommit callback for this Profiler,706 // because the effect is also where times bubble to parent Profilers.707 enqueuePendingPassiveProfilerEffect(finishedWork);708 // Propagate layout effect durations to the next nearest Profiler ancestor.709 // Do not reset these values until the next render so DevTools has a chance to read them first.710 let parentFiber = finishedWork.return;711 while (parentFiber !== null) {712 if (parentFiber.tag === Profiler) {713 const parentStateNode = parentFiber.stateNode;714 parentStateNode.effectDuration += effectDuration;715 break;716 }717 parentFiber = parentFiber.return;718 }719 }720 }721 return;722 }723 case SuspenseComponent: {724 commitSuspenseHydrationCallbacks(finishedRoot, finishedWork);725 return;726 }727 case SuspenseListComponent:728 case IncompleteClassComponent:729 case FundamentalComponent:730 case ScopeComponent:731 case OffscreenComponent:732 case LegacyHiddenComponent:733 return;734 }735 invariant(736 false,737 'This unit of work tag should not have side-effects. This error is ' +738 'likely caused by a bug in React. Please file an issue.',739 );740}741function hideOrUnhideAllChildren(finishedWork, isHidden) {742 if (supportsMutation) {743 // We only have the top Fiber that was inserted but we need to recurse down its744 // children to find all the terminal nodes.745 let node = finishedWork;746 while (true) {747 if (node.tag === HostComponent) {748 const instance = node.stateNode;749 if (isHidden) {750 hideInstance(instance);751 } else {752 unhideInstance(node.stateNode, node.memoizedProps);753 }754 } else if (node.tag === HostText) {755 const instance = node.stateNode;756 if (isHidden) {757 hideTextInstance(instance);758 } else {759 unhideTextInstance(instance, node.memoizedProps);760 }761 } else if (762 (node.tag === OffscreenComponent ||763 node.tag === LegacyHiddenComponent) &&764 (node.memoizedState ) !== null &&765 node !== finishedWork766 ) {767 // Found a nested Offscreen component that is hidden. Don't search768 // any deeper. This tree should remain hidden.769 } else if (node.child !== null) {770 node.child.return = node;771 node = node.child;772 continue;773 }774 if (node === finishedWork) {775 return;776 }777 while (node.sibling === null) {778 if (node.return === null || node.return === finishedWork) {779 return;780 }781 node = node.return;782 }783 node.sibling.return = node.return;784 node = node.sibling;785 }786 }787}788function commitAttachRef(finishedWork ) {789 const ref = finishedWork.ref;790 if (ref !== null) {791 const instance = finishedWork.stateNode;792 let instanceToUse;793 switch (finishedWork.tag) {794 case HostComponent:795 instanceToUse = getPublicInstance(instance);796 break;797 default:798 instanceToUse = instance;799 }800 // Moved outside to ensure DCE works with this flag801 if (enableScopeAPI && finishedWork.tag === ScopeComponent) {802 instanceToUse = instance;803 }804 if (typeof ref === 'function') {805 ref(instanceToUse);806 } else {807 if (__DEV__) {808 if (!ref.hasOwnProperty('current')) {809 console.error(810 'Unexpected ref object provided for %s. ' +811 'Use either a ref-setter function or React.createRef().',812 getComponentName(finishedWork.type),813 );814 }815 }816 ref.current = instanceToUse;817 }818 }819}820function commitDetachRef(current ) {821 const currentRef = current.ref;822 if (currentRef !== null) {823 if (typeof currentRef === 'function') {824 currentRef(null);825 } else {826 currentRef.current = null;827 }828 }829}830// User-originating errors (lifecycles and refs) should not interrupt831// deletion, so don't let them throw. Host-originating errors should832// interrupt deletion, so it's okay833function commitUnmount(834 finishedRoot ,835 current ,836 renderPriorityLevel ,837) {838 onCommitUnmount(current);839 switch (current.tag) {840 case FunctionComponent:841 case ForwardRef:842 case MemoComponent:843 case SimpleMemoComponent:844 case Block: {845 const updateQueue = (current.updateQueue );846 if (updateQueue !== null) {847 const lastEffect = updateQueue.lastEffect;848 if (lastEffect !== null) {849 const firstEffect = lastEffect.next;850 let effect = firstEffect;851 do {852 const {destroy, tag} = effect;853 if (destroy !== undefined) {854 if ((tag & HookPassive) !== NoHookEffect) {855 enqueuePendingPassiveHookEffectUnmount(current, effect);856 } else {857 if (858 enableProfilerTimer &&859 enableProfilerCommitHooks &&860 current.mode & ProfileMode861 ) {862 startLayoutEffectTimer();863 safelyCallDestroy(current, destroy);864 recordLayoutEffectDuration(current);865 } else {866 safelyCallDestroy(current, destroy);867 }868 }869 }870 effect = effect.next;871 } while (effect !== firstEffect);872 }873 }874 return;875 }876 case ClassComponent: {877 safelyDetachRef(current);878 const instance = current.stateNode;879 if (typeof instance.componentWillUnmount === 'function') {880 safelyCallComponentWillUnmount(current, instance);881 }882 return;883 }884 case HostComponent: {885 safelyDetachRef(current);886 return;887 }888 case HostPortal: {889 // TODO: this is recursive.890 // We are also not using this parent because891 // the portal will get pushed immediately.892 if (supportsMutation) {893 unmountHostComponents(finishedRoot, current, renderPriorityLevel);894 } else if (supportsPersistence) {895 emptyPortalContainer(current);896 }897 return;898 }899 case FundamentalComponent: {900 if (enableFundamentalAPI) {901 const fundamentalInstance = current.stateNode;902 if (fundamentalInstance !== null) {903 unmountFundamentalComponent(fundamentalInstance);904 current.stateNode = null;905 }906 }907 return;908 }909 case DehydratedFragment: {910 if (enableSuspenseCallback) {911 const hydrationCallbacks = finishedRoot.hydrationCallbacks;912 if (hydrationCallbacks !== null) {913 const onDeleted = hydrationCallbacks.onDeleted;914 if (onDeleted) {915 onDeleted((current.stateNode ));916 }917 }918 }919 return;920 }921 case ScopeComponent: {922 if (enableScopeAPI) {923 safelyDetachRef(current);924 }925 return;926 }927 }928}929function commitNestedUnmounts(930 finishedRoot ,931 root ,932 renderPriorityLevel ,933) {934 // While we're inside a removed host node we don't want to call935 // removeChild on the inner nodes because they're removed by the top936 // call anyway. We also want to call componentWillUnmount on all937 // composites before this host node is removed from the tree. Therefore938 // we do an inner loop while we're still inside the host node.939 let node = root;940 while (true) {941 commitUnmount(finishedRoot, node, renderPriorityLevel);942 // Visit children because they may contain more composite or host nodes.943 // Skip portals because commitUnmount() currently visits them recursively.944 if (945 node.child !== null &&946 // If we use mutation we drill down into portals using commitUnmount above.947 // If we don't use mutation we drill down into portals here instead.948 (!supportsMutation || node.tag !== HostPortal)949 ) {950 node.child.return = node;951 node = node.child;952 continue;953 }954 if (node === root) {955 return;956 }957 while (node.sibling === null) {958 if (node.return === null || node.return === root) {959 return;960 }961 node = node.return;962 }963 node.sibling.return = node.return;964 node = node.sibling;965 }966}967function detachFiberMutation(fiber ) {968 // Cut off the return pointers to disconnect it from the tree. Ideally, we969 // should clear the child pointer of the parent alternate to let this970 // get GC:ed but we don't know which for sure which parent is the current971 // one so we'll settle for GC:ing the subtree of this child. This child972 // itself will be GC:ed when the parent updates the next time.973 // Note: we cannot null out sibling here, otherwise it can cause issues974 // with findDOMNode and how it requires the sibling field to carry out975 // traversal in a later effect. See PR #16820. We now clear the sibling976 // field after effects, see: detachFiberAfterEffects.977 //978 // Don't disconnect stateNode now; it will be detached in detachFiberAfterEffects.979 // It may be required if the current component is an error boundary,980 // and one of its descendants throws while unmounting a passive effect.981 fiber.alternate = null;982 fiber.child = null;983 fiber.dependencies = null;984 fiber.firstEffect = null;985 fiber.lastEffect = null;986 fiber.memoizedProps = null;987 fiber.memoizedState = null;988 fiber.pendingProps = null;989 fiber.return = null;990 fiber.updateQueue = null;991 if (__DEV__) {992 fiber._debugOwner = null;993 }994}995function emptyPortalContainer(current ) {996 if (!supportsPersistence) {997 return;998 }999 const portal 1000 1001 1002 1003 = current.stateNode;1004 const {containerInfo} = portal;1005 const emptyChildSet = createContainerChildSet(containerInfo);1006 replaceContainerChildren(containerInfo, emptyChildSet);1007}1008function commitContainer(finishedWork ) {1009 if (!supportsPersistence) {1010 return;1011 }1012 switch (finishedWork.tag) {1013 case ClassComponent:1014 case HostComponent:1015 case HostText:1016 case FundamentalComponent: {1017 return;1018 }1019 case HostRoot:1020 case HostPortal: {1021 const portalOrRoot 1022 1023 1024 1025 = finishedWork.stateNode;1026 const {containerInfo, pendingChildren} = portalOrRoot;1027 replaceContainerChildren(containerInfo, pendingChildren);1028 return;1029 }1030 }1031 invariant(1032 false,1033 'This unit of work tag should not have side-effects. This error is ' +1034 'likely caused by a bug in React. Please file an issue.',1035 );1036}1037function getHostParentFiber(fiber ) {1038 let parent = fiber.return;1039 while (parent !== null) {1040 if (isHostParent(parent)) {1041 return parent;1042 }1043 parent = parent.return;1044 }1045 invariant(1046 false,1047 'Expected to find a host parent. This error is likely caused by a bug ' +1048 'in React. Please file an issue.',1049 );1050}1051function isHostParent(fiber ) {1052 return (1053 fiber.tag === HostComponent ||1054 fiber.tag === HostRoot ||1055 fiber.tag === HostPortal1056 );1057}1058function getHostSibling(fiber ) {1059 // We're going to search forward into the tree until we find a sibling host1060 // node. Unfortunately, if multiple insertions are done in a row we have to1061 // search past them. This leads to exponential search for the next sibling.1062 // TODO: Find a more efficient way to do this.1063 let node = fiber;1064 siblings: while (true) {1065 // If we didn't find anything, let's try the next sibling.1066 while (node.sibling === null) {1067 if (node.return === null || isHostParent(node.return)) {1068 // If we pop out of the root or hit the parent the fiber we are the1069 // last sibling.1070 return null;1071 }1072 node = node.return;1073 }1074 node.sibling.return = node.return;1075 node = node.sibling;1076 while (1077 node.tag !== HostComponent &&1078 node.tag !== HostText &&1079 node.tag !== DehydratedFragment1080 ) {1081 // If it is not host node and, we might have a host node inside it.1082 // Try to search down until we find one.1083 if (node.flags & Placement) {1084 // If we don't have a child, try the siblings instead.1085 continue siblings;1086 }1087 // If we don't have a child, try the siblings instead.1088 // We also skip portals because they are not part of this host tree.1089 if (node.child === null || node.tag === HostPortal) {1090 continue siblings;1091 } else {1092 node.child.return = node;1093 node = node.child;1094 }1095 }1096 // Check if this host node is stable or about to be placed.1097 if (!(node.flags & Placement)) {1098 // Found it!1099 return node.stateNode;1100 }1101 }1102}1103function commitPlacement(finishedWork ) {1104 if (!supportsMutation) {1105 return;1106 }1107 // Recursively insert all host nodes into the parent.1108 const parentFiber = getHostParentFiber(finishedWork);1109 // Note: these two variables *must* always be updated together.1110 let parent;1111 let isContainer;1112 const parentStateNode = parentFiber.stateNode;1113 switch (parentFiber.tag) {1114 case HostComponent:1115 parent = parentStateNode;1116 isContainer = false;1117 break;1118 case HostRoot:1119 parent = parentStateNode.containerInfo;1120 isContainer = true;1121 break;1122 case HostPortal:1123 parent = parentStateNode.containerInfo;1124 isContainer = true;1125 break;1126 case FundamentalComponent:1127 if (enableFundamentalAPI) {1128 parent = parentStateNode.instance;1129 isContainer = false;1130 }1131 // eslint-disable-next-line-no-fallthrough1132 default:1133 invariant(1134 false,1135 'Invalid host parent fiber. This error is likely caused by a bug ' +1136 'in React. Please file an issue.',1137 );1138 }1139 if (parentFiber.flags & ContentReset) {1140 // Reset the text content of the parent before doing any insertions1141 resetTextContent(parent);1142 // Clear ContentReset from the effect tag1143 parentFiber.flags &= ~ContentReset;1144 }1145 const before = getHostSibling(finishedWork);1146 // We only have the top Fiber that was inserted but we need to recurse down its1147 // children to find all the terminal nodes.1148 if (isContainer) {1149 insertOrAppendPlacementNodeIntoContainer(finishedWork, before, parent);1150 } else {1151 insertOrAppendPlacementNode(finishedWork, before, parent);1152 }1153}1154function insertOrAppendPlacementNodeIntoContainer(1155 node ,1156 before ,1157 parent ,1158) {1159 const {tag} = node;1160 const isHost = tag === HostComponent || tag === HostText;1161 if (isHost || (enableFundamentalAPI && tag === FundamentalComponent)) {1162 const stateNode = isHost ? node.stateNode : node.stateNode.instance;1163 if (before) {1164 insertInContainerBefore(parent, stateNode, before);1165 } else {1166 appendChildToContainer(parent, stateNode);1167 }1168 } else if (tag === HostPortal) {1169 // If the insertion itself is a portal, then we don't want to traverse1170 // down its children. Instead, we'll get insertions from each child in1171 // the portal directly.1172 } else {1173 const child = node.child;1174 if (child !== null) {1175 insertOrAppendPlacementNodeIntoContainer(child, before, parent);1176 let sibling = child.sibling;1177 while (sibling !== null) {1178 insertOrAppendPlacementNodeIntoContainer(sibling, before, parent);1179 sibling = sibling.sibling;1180 }1181 }1182 }1183}1184function insertOrAppendPlacementNode(1185 node ,1186 before ,1187 parent ,1188) {1189 const {tag} = node;1190 const isHost = tag === HostComponent || tag === HostText;1191 if (isHost || (enableFundamentalAPI && tag === FundamentalComponent)) {1192 const stateNode = isHost ? node.stateNode : node.stateNode.instance;1193 if (before) {1194 insertBefore(parent, stateNode, before);1195 } else {1196 appendChild(parent, stateNode);1197 }1198 } else if (tag === HostPortal) {1199 // If the insertion itself is a portal, then we don't want to traverse1200 // down its children. Instead, we'll get insertions from each child in1201 // the portal directly.1202 } else {1203 const child = node.child;1204 if (child !== null) {1205 insertOrAppendPlacementNode(child, before, parent);1206 let sibling = child.sibling;1207 while (sibling !== null) {1208 insertOrAppendPlacementNode(sibling, before, parent);1209 sibling = sibling.sibling;1210 }1211 }1212 }1213}1214function unmountHostComponents(1215 finishedRoot ,1216 current ,1217 renderPriorityLevel ,1218) {1219 // We only have the top Fiber that was deleted but we need to recurse down its1220 // children to find all the terminal nodes.1221 let node = current;1222 // Each iteration, currentParent is populated with node's host parent if not1223 // currentParentIsValid.1224 let currentParentIsValid = false;1225 // Note: these two variables *must* always be updated together.1226 let currentParent;1227 let currentParentIsContainer;1228 while (true) {1229 if (!currentParentIsValid) {1230 let parent = node.return;1231 findParent: while (true) {1232 invariant(1233 parent !== null,1234 'Expected to find a host parent. This error is likely caused by ' +1235 'a bug in React. Please file an issue.',1236 );1237 const parentStateNode = parent.stateNode;1238 switch (parent.tag) {1239 case HostComponent:1240 currentParent = parentStateNode;1241 currentParentIsContainer = false;1242 break findParent;1243 case HostRoot:1244 currentParent = parentStateNode.containerInfo;1245 currentParentIsContainer = true;1246 break findParent;1247 case HostPortal:1248 currentParent = parentStateNode.containerInfo;1249 currentParentIsContainer = true;1250 break findParent;1251 case FundamentalComponent:1252 if (enableFundamentalAPI) {1253 currentParent = parentStateNode.instance;1254 currentParentIsContainer = false;1255 }1256 }1257 parent = parent.return;1258 }1259 currentParentIsValid = true;1260 }1261 if (node.tag === HostComponent || node.tag === HostText) {1262 commitNestedUnmounts(finishedRoot, node, renderPriorityLevel);1263 // After all the children have unmounted, it is now safe to remove the1264 // node from the tree.1265 if (currentParentIsContainer) {1266 removeChildFromContainer(1267 ((currentParent ) ),1268 (node.stateNode ),1269 );1270 } else {1271 removeChild(1272 ((currentParent ) ),1273 (node.stateNode ),1274 );1275 }1276 // Don't visit children because we already visited them.1277 } else if (enableFundamentalAPI && node.tag === FundamentalComponent) {1278 const fundamentalNode = node.stateNode.instance;1279 commitNestedUnmounts(finishedRoot, node, renderPriorityLevel);1280 // After all the children have unmounted, it is now safe to remove the1281 // node from the tree.1282 if (currentParentIsContainer) {1283 removeChildFromContainer(1284 ((currentParent ) ),1285 (fundamentalNode ),1286 );1287 } else {1288 removeChild(1289 ((currentParent ) ),1290 (fundamentalNode ),1291 );1292 }1293 } else if (1294 enableSuspenseServerRenderer &&1295 node.tag === DehydratedFragment1296 ) {1297 if (enableSuspenseCallback) {1298 const hydrationCallbacks = finishedRoot.hydrationCallbacks;1299 if (hydrationCallbacks !== null) {1300 const onDeleted = hydrationCallbacks.onDeleted;1301 if (onDeleted) {1302 onDeleted((node.stateNode ));1303 }1304 }1305 }1306 // Delete the dehydrated suspense boundary and all of its content.1307 if (currentParentIsContainer) {1308 clearSuspenseBoundaryFromContainer(1309 ((currentParent ) ),1310 (node.stateNode ),1311 );1312 } else {1313 clearSuspenseBoundary(1314 ((currentParent ) ),1315 (node.stateNode ),1316 );1317 }1318 } else if (node.tag === HostPortal) {1319 if (node.child !== null) {1320 // When we go into a portal, it becomes the parent to remove from.1321 // We will reassign it back when we pop the portal on the way up.1322 currentParent = node.stateNode.containerInfo;1323 currentParentIsContainer = true;1324 // Visit children because portals might contain host components.1325 node.child.return = node;1326 node = node.child;1327 continue;1328 }1329 } else {1330 commitUnmount(finishedRoot, node, renderPriorityLevel);1331 // Visit children because we may find more host components below.1332 if (node.child !== null) {1333 node.child.return = node;1334 node = node.child;1335 continue;1336 }1337 }1338 if (node === current) {1339 return;1340 }1341 while (node.sibling === null) {1342 if (node.return === null || node.return === current) {1343 return;1344 }1345 node = node.return;1346 if (node.tag === HostPortal) {1347 // When we go out of the portal, we need to restore the parent.1348 // Since we don't keep a stack of them, we will search for it.1349 currentParentIsValid = false;1350 }1351 }1352 node.sibling.return = node.return;1353 node = node.sibling;1354 }1355}1356function commitDeletion(1357 finishedRoot ,1358 current ,1359 renderPriorityLevel ,1360) {1361 if (supportsMutation) {1362 // Recursively delete all host nodes from the parent.1363 // Detach refs and call componentWillUnmount() on the whole subtree.1364 unmountHostComponents(finishedRoot, current, renderPriorityLevel);1365 } else {1366 // Detach refs and call componentWillUnmount() on the whole subtree.1367 commitNestedUnmounts(finishedRoot, current, renderPriorityLevel);1368 }1369 const alternate = current.alternate;1370 detachFiberMutation(current);1371 if (alternate !== null) {1372 detachFiberMutation(alternate);1373 }1374}1375function commitWork(current , finishedWork ) {1376 if (!supportsMutation) {1377 switch (finishedWork.tag) {1378 case FunctionComponent:1379 case ForwardRef:1380 case MemoComponent:1381 case SimpleMemoComponent:1382 case Block: {1383 // Layout effects are destroyed during the mutation phase so that all1384 // destroy functions for all fibers are called before any create functions.1385 // This prevents sibling component effects from interfering with each other,1386 // e.g. a destroy function in one component should never override a ref set1387 // by a create function in another component during the same commit.1388 if (1389 enableProfilerTimer &&1390 enableProfilerCommitHooks &&1391 finishedWork.mode & ProfileMode1392 ) {1393 try {1394 startLayoutEffectTimer();1395 commitHookEffectListUnmount(1396 HookLayout | HookHasEffect,1397 finishedWork,1398 );1399 } finally {1400 recordLayoutEffectDuration(finishedWork);1401 }1402 } else {1403 commitHookEffectListUnmount(HookLayout | HookHasEffect, finishedWork);1404 }1405 return;1406 }1407 case Profiler: {1408 return;1409 }1410 case SuspenseComponent: {1411 commitSuspenseComponent(finishedWork);1412 attachSuspenseRetryListeners(finishedWork);1413 return;1414 }1415 case SuspenseListComponent: {1416 attachSuspenseRetryListeners(finishedWork);1417 return;1418 }1419 case HostRoot: {1420 if (supportsHydration) {1421 const root = finishedWork.stateNode;1422 if (root.hydrate) {1423 // We've just hydrated. No need to hydrate again.1424 root.hydrate = false;1425 commitHydratedContainer(root.containerInfo);1426 }1427 }1428 break;1429 }1430 case OffscreenComponent:1431 case LegacyHiddenComponent: {1432 return;1433 }1434 }1435 commitContainer(finishedWork);1436 return;1437 }1438 switch (finishedWork.tag) {1439 case FunctionComponent:1440 case ForwardRef:1441 case MemoComponent:1442 case SimpleMemoComponent:1443 case Block: {1444 // Layout effects are destroyed during the mutation phase so that all1445 // destroy functions for all fibers are called before any create functions.1446 // This prevents sibling component effects from interfering with each other,1447 // e.g. a destroy function in one component should never override a ref set1448 // by a create function in another component during the same commit.1449 if (1450 enableProfilerTimer &&1451 enableProfilerCommitHooks &&1452 finishedWork.mode & ProfileMode1453 ) {1454 try {1455 startLayoutEffectTimer();1456 commitHookEffectListUnmount(HookLayout | HookHasEffect, finishedWork);1457 } finally {1458 recordLayoutEffectDuration(finishedWork);1459 }1460 } else {1461 commitHookEffectListUnmount(HookLayout | HookHasEffect, finishedWork);1462 }1463 return;1464 }1465 case ClassComponent: {1466 return;1467 }1468 case HostComponent: {1469 const instance = finishedWork.stateNode;1470 if (instance != null) {1471 // Commit the work prepared earlier.1472 const newProps = finishedWork.memoizedProps;1473 // For hydration we reuse the update path but we treat the oldProps1474 // as the newProps. The updatePayload will contain the real change in1475 // this case.1476 const oldProps = current !== null ? current.memoizedProps : newProps;1477 const type = finishedWork.type;1478 // TODO: Type the updateQueue to be specific to host components.1479 const updatePayload = (finishedWork.updateQueue );1480 finishedWork.updateQueue = null;1481 if (updatePayload !== null) {1482 commitUpdate(1483 instance,1484 updatePayload,1485 type,1486 oldProps,1487 newProps,1488 finishedWork,1489 );1490 }1491 }1492 return;1493 }1494 case HostText: {1495 invariant(1496 finishedWork.stateNode !== null,1497 'This should have a text node initialized. This error is likely ' +1498 'caused by a bug in React. Please file an issue.',1499 );1500 const textInstance = finishedWork.stateNode;1501 const newText = finishedWork.memoizedProps;1502 // For hydration we reuse the update path but we treat the oldProps1503 // as the newProps. The updatePayload will contain the real change in1504 // this case.1505 const oldText =1506 current !== null ? current.memoizedProps : newText;1507 commitTextUpdate(textInstance, oldText, newText);1508 return;1509 }1510 case HostRoot: {1511 if (supportsHydration) {1512 const root = finishedWork.stateNode;1513 if (root.hydrate) {1514 // We've just hydrated. No need to hydrate again.1515 root.hydrate = false;1516 commitHydratedContainer(root.containerInfo);1517 }1518 }1519 return;1520 }1521 case Profiler: {1522 return;1523 }1524 case SuspenseComponent: {1525 commitSuspenseComponent(finishedWork);1526 attachSuspenseRetryListeners(finishedWork);1527 return;1528 }1529 case SuspenseListComponent: {1530 attachSuspenseRetryListeners(finishedWork);1531 return;1532 }1533 case IncompleteClassComponent: {1534 return;1535 }1536 case FundamentalComponent: {1537 if (enableFundamentalAPI) {1538 const fundamentalInstance = finishedWork.stateNode;1539 updateFundamentalComponent(fundamentalInstance);1540 return;1541 }1542 break;1543 }1544 case ScopeComponent: {1545 if (enableScopeAPI) {1546 const scopeInstance = finishedWork.stateNode;1547 prepareScopeUpdate(scopeInstance, finishedWork);1548 return;1549 }1550 break;1551 }1552 case OffscreenComponent:1553 case LegacyHiddenComponent: {1554 const newState = finishedWork.memoizedState;1555 const isHidden = newState !== null;1556 hideOrUnhideAllChildren(finishedWork, isHidden);1557 return;1558 }1559 }1560 invariant(1561 false,1562 'This unit of work tag should not have side-effects. This error is ' +1563 'likely caused by a bug in React. Please file an issue.',1564 );1565}1566function commitSuspenseComponent(finishedWork ) {1567 const newState = finishedWork.memoizedState;1568 if (newState !== null) {1569 markCommitTimeOfFallback();1570 if (supportsMutation) {1571 // Hide the Offscreen component that contains the primary children. TODO:1572 // Ideally, this effect would have been scheduled on the Offscreen fiber1573 // itself. That's how unhiding works: the Offscreen component schedules an1574 // effect on itself. However, in this case, the component didn't complete,1575 // so the fiber was never added to the effect list in the normal path. We1576 // could have appended it to the effect list in the Suspense component's1577 // second pass, but doing it this way is less complicated. This would be1578 // simpler if we got rid of the effect list and traversed the tree, like1579 // we're planning to do.1580 const primaryChildParent = (finishedWork.child );1581 hideOrUnhideAllChildren(primaryChildParent, true);1582 }1583 }1584 if (enableSuspenseCallback && newState !== null) {1585 const suspenseCallback = finishedWork.memoizedProps.suspenseCallback;1586 if (typeof suspenseCallback === 'function') {1587 const wakeables = (finishedWork.updateQueue );1588 if (wakeables !== null) {1589 suspenseCallback(new Set(wakeables));1590 }1591 } else if (__DEV__) {1592 if (suspenseCallback !== undefined) {1593 console.error('Unexpected type for suspenseCallback.');1594 }1595 }1596 }1597}1598function commitSuspenseHydrationCallbacks(1599 finishedRoot ,1600 finishedWork ,1601) {1602 if (!supportsHydration) {1603 return;1604 }1605 const newState = finishedWork.memoizedState;1606 if (newState === null) {1607 const current = finishedWork.alternate;1608 if (current !== null) {1609 const prevState = current.memoizedState;1610 if (prevState !== null) {1611 const suspenseInstance = prevState.dehydrated;1612 if (suspenseInstance !== null) {1613 commitHydratedSuspenseInstance(suspenseInstance);1614 if (enableSuspenseCallback) {1615 const hydrationCallbacks = finishedRoot.hydrationCallbacks;1616 if (hydrationCallbacks !== null) {1617 const onHydrated = hydrationCallbacks.onHydrated;1618 if (onHydrated) {1619 onHydrated(suspenseInstance);1620 }1621 }1622 }1623 }1624 }1625 }1626 }1627}1628function attachSuspenseRetryListeners(finishedWork ) {1629 // If this boundary just timed out, then it will have a set of wakeables.1630 // For each wakeable, attach a listener so that when it resolves, React1631 // attempts to re-render the boundary in the primary (pre-timeout) state.1632 const wakeables = (finishedWork.updateQueue );1633 if (wakeables !== null) {1634 finishedWork.updateQueue = null;1635 let retryCache = finishedWork.stateNode;1636 if (retryCache === null) {1637 retryCache = finishedWork.stateNode = new PossiblyWeakSet();1638 }1639 wakeables.forEach(wakeable => {1640 // Memoize using the boundary fiber to prevent redundant listeners.1641 let retry = resolveRetryWakeable.bind(null, finishedWork, wakeable);1642 if (!retryCache.has(wakeable)) {1643 if (enableSchedulerTracing) {1644 if (wakeable.__reactDoNotTraceInteractions !== true) {1645 retry = Schedule_tracing_wrap(retry);1646 }1647 }1648 retryCache.add(wakeable);1649 wakeable.then(retry, retry);1650 }1651 });1652 }1653}1654// This function detects when a Suspense boundary goes from visible to hidden.1655// It returns false if the boundary is already hidden.1656// TODO: Use an effect tag.1657export function isSuspenseBoundaryBeingHidden(1658 current ,1659 finishedWork ,1660) {1661 if (current !== null) {1662 const oldState = current.memoizedState;1663 if (oldState === null || oldState.dehydrated !== null) {1664 const newState = finishedWork.memoizedState;1665 return newState !== null && newState.dehydrated === null;1666 }1667 }1668 return false;1669}1670function commitResetTextContent(current ) {1671 if (!supportsMutation) {1672 return;1673 }1674 resetTextContent(current.stateNode);1675}1676export {1677 commitBeforeMutationLifeCycles,1678 commitResetTextContent,1679 commitPlacement,1680 commitDeletion,1681 commitWork,1682 commitLifeCycles,1683 commitAttachRef,1684 commitDetachRef,...

Full Screen

Full Screen

FiberCommitWork.js

Source:FiberCommitWork.js Github

copy

Full Screen

1import{2 HostRoot,3 HostText,4 HostComponent,5 FunctionComponent,6 BeforeMutationMask,7 MutationMask,8 NoFlags,9 ContentReset,10 Placement,11 Update,12 PlacementAndUpdate,13 LayoutMask,14 SuspenseComponent,15 OffscreenComponent,16 ChildDeletion,17 PassiveMask,18 Passive,19 HookPassive,20 HookHasEffect21} from '@Jeact/shared/Constants';22import {23 resolveRetryWakeable24} from '@Jeact/vDOM/FiberWorkLoop';25import {26 updateFiberProps,27 detachDeletedInstance28} from '@Jeact/vDOM/DOMComponentTree';29import { updateDOMProperties } from '@Jeact/vDOM/DOMComponent'30let nextEffect = null;31export function commitBeforeMutationEffects(firstChild){32 nextEffect = firstChild;33 commitBeforeMutationEffects_begin();34}35function commitBeforeMutationEffects_begin(){36 while(nextEffect !== null){37 const fiber = nextEffect;38 const deletions = fiber.deletions;39 if(deletions !== null){40 for (let i = 0; i < deletions.length; i++){41 const deletion = deletions[i];42 // commitBeforeMutationEffectsDeletion(deletion);43 }44 }45 const child = fiber.child;46 if(47 (fiber.subtreeFlags & BeforeMutationMask) !== NoFlags &&48 child !== null49 ){50 nextEffect = child;51 } else {52 commitBeforeMutationEffects_complete();53 }54 }55}56function commitBeforeMutationEffects_complete(){57 while(nextEffect !== null){58 const fiber = nextEffect;59 commitBeforeMutationEffectsOnFiber(fiber);60 const sibling = fiber.sibling;61 if(sibling !== null){62 nextEffect = sibling;63 return;64 }65 nextEffect = fiber.return;66 }67}68function commitBeforeMutationEffectsOnFiber(finishedWork){69 const current = finishedWork.alternate;70 const flags = finishedWork.flags;71}72function commitHookEffectListUnmount(73 flags, 74 finishedWork, 75 nearestMountedAncestor76){77 const updateQueue = finishedWork.updateQueue;78 const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;79 if (lastEffect !== null){80 const firstEffect = lastEffect.next;81 let effect = firstEffect;82 do {83 if ((effect.tag & flags) === flags){84 // unmount85 const destroy = effect.destroy;86 effect.destroy = undefined;87 if (destroy !== undefined){88 destroy();89 }90 }91 effect = effect.next;92 } while (effect !== firstEffect);93 }94}95function commitHookEffectListMount(tag, finishedWork){96 const updateQueue = finishedWork.updateQueue;97 const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;98 if (lastEffect !== null){99 const firstEffect = lastEffect.next;100 let effect = firstEffect;101 do {102 if ((effect.tag & tag) === tag){103 // Mount104 const create = effect.create;105 effect.destroy = create();106 }107 effect = effect.next;108 } while(effect !== firstEffect);109 }110}111function attachSuspenseRetryListeners(finishedWork){112 const wakeables = finishedWork.updateQueue;113 if (wakeables !== null){114 finishedWork.updateQueue = null;115 let retryCache = finishedWork.stateNode;116 if(retryCache === null){117 retryCache = finishedWork.stateNode = new WeakSet()118 }119 wakeables.forEach(wakeable => {120 const retry = resolveRetryWakeable.bind(null, finishedWork, wakeable);121 if(!retryCache.has(wakeable)){122 retryCache.add(wakeable);123 wakeable.then(retry, retry); 124 }125 })126 }127}128export function commitMutationEffects(root,firstChild){129 nextEffect = firstChild;130 commitMutationEffects_begin(root);131}132function commitMutationEffects_begin(root){133 while(nextEffect !== null){134 const fiber = nextEffect;135 const deletions = fiber.deletions;136 if(deletions !==null ){137 for (let i = 0; i < deletions.length; i++){138 const childToDelete = deletions[i];139 commitDeletion(root, childToDelete, fiber);140 }141 }142 const child = fiber.child;143 if((fiber.subtreeFlags & MutationMask) !== NoFlags && child !== null){144 nextEffect = child;145 } else {146 commitMutationEffects_complete(root);147 }148 }149}150function commitMutationEffects_complete(root){151 while(nextEffect !== null){152 const fiber = nextEffect;153 commitMutationEffectsOnFiber(fiber, root);154 const sibling = fiber.sibling;155 if (sibling !== null){156 nextEffect = sibling;157 return;158 }159 nextEffect = fiber.return;160 }161}162function commitMutationEffectsOnFiber(finishedWork, root){163 const flags = finishedWork.flags;164 const primaryFlags = flags & (Placement | Update);165 switch(primaryFlags){166 case Placement:{167 commitPlacement(finishedWork);168 finishedWork.flags &= ~Placement;169 break;170 }171 case PlacementAndUpdate:{172 // Placement173 commitPlacement(finishedWork);174 finishedWork.flags &= ~Placement;175 //Update176 const current = finishedWork.alternate;177 commitWork(current, finishedWork);178 break;179 }180 case Update:{181 const current = finishedWork.alternate;182 commitWork(current, finishedWork);183 break;184 }185 }186}187export function commitLayoutEffects(finishedWork, root, committedLanes){188 nextEffect = finishedWork;189 commitLayoutEffects_begin(finishedWork, root, committedLanes);190}191function commitLayoutEffects_begin(subtreeRoot, root, committedLanes){192 while (nextEffect !== null){193 const fiber = nextEffect;194 const firstChild = fiber.child;195 if ((fiber.subtreeFlags & LayoutMask) !== NoFlags && firstChild !== null){196 nextEffect = firstChild;197 } else {198 commitLayoutMountEffects_complete(subtreeRoot, root, committedLanes);199 }200 }201}202function commitLayoutMountEffects_complete(subtreeRoot, root, committedLanes){203 while (nextEffect !== null){204 const fiber = nextEffect;205 if((fiber.flags & LayoutMask) !== NoFlags){206 const current = fiber.alternate;207 commitLayoutEffectOnFiber(root, current, fiber, committedLanes);208 }209 if (fiber === subtreeRoot){210 nextEffect = null;211 return;212 }213 const sibling = fiber.sibling;214 if (sibling !== null){215 nextEffect = sibling;216 return;217 }218 nextEffect = fiber.return;219 }220}221export function commitPassiveMountEffects(root, finishedWork){222 nextEffect = finishedWork;223 commitPassiveMountEffects_begin(finishedWork, root);224}225function commitPassiveMountEffects_begin(subtreeRoot, root){226 while(nextEffect!== null){227 const fiber = nextEffect;228 const firstChild = fiber.child;229 if ((fiber.subtreeFlags & PassiveMask) !== NoFlags && firstChild !== null){230 nextEffect = firstChild;231 } else {232 commitPassiveMountEffects_complete(subtreeRoot, root);233 }234 }235}236function commitPassiveMountEffects_complete(subtreeRoot, root){237 while(nextEffect !== null){238 const fiber = nextEffect;239 if ((fiber.flags & Passive) !== NoFlags){240 commitPassiveMountEffectsOnFiber(root, fiber);241 }242 if (fiber === subtreeRoot){243 nextEffect = null;244 return ;245 }246 const sibling = fiber.sibling;247 if (sibling !== null){248 nextEffect = sibling;249 return;250 }251 nextEffect = fiber.return;252 }253}254function commitPassiveMountOnFiber(finishedRoot, finishedWork){255 switch(finishedWork.tag){256 case FunctionComponent:{257 commitHookEffectListMount(258 HookPassive | HookHasEffect, 259 finishedWork260 );261 break;262 }263 }264}265function commitLayoutEffectOnFiber(finishedRoot, current, finishedWork, committedLanes){266 if ((finishedWork.flags & Update) !== NoFlags){267 switch(finishedWork.tag){268 default:269 break;270 }271 }272}273export function commitPassiveUnmountEffects(firstChild){274 nextEffect = firstChild;275 commitPassiveUnmountEffects_begin();276}277function commitPassiveUnmountEffects_begin(){278 while(nextEffect !== null){279 const fiber = nextEffect;280 const child = fiber.child;281 if ((nextEffect.flags & ChildDeletion) !== NoFlags){282 const deletions = fiber.deletions;283 if(deletions !== null){284 for (let i = 0; i < deletions.length; i++){285 const fiberToDel = deletions[i];286 nextEffect = fiberToDel;287 commitPassiveUnmountEffectsInDelTree_begin(288 fiberToDel,289 fiber,290 )291 }292 }293 }294 if ((fiber.subtreeFlags & PassiveMask) !== NoFlags && child !== null){295 nextEffect = child;296 } else {297 commitPassiveUnmountEffects_complete();298 }299 }300}301function commitPassiveUnmountEffects_complete(){302 while (nextEffect !== null){303 const fiber = nextEffect;304 if ((fiber.flags & Passive) !== NoFlags){305 commitPassiveUnmountOnFiber(fiber);306 }307 const sibling = fiber.sibling;308 if (sibling !== null){309 nextEffect = sibling;310 return;311 }312 nextEffect = fiber.return;313 }314}315function commitPassiveUnmountOnFiber(finishedWork){316 switch(finishedWork.tag){317 case FunctionComponent:{318 commitHookEffectListUnmount(319 HookPassive | HookHasEffect,320 finishedWork,321 finishedWork.return322 )323 }324 }325}326function commitPassiveUnmountEffectsInDelTree_begin(327 deletedSubtreeRoot,328 nearestMountedAncestor329){330 while (nextEffect !== null){331 const fiber = nextEffect;332 333 commitPassiveUnmountEffectsInDelTreeOnFiber(334 fiber, 335 nearestMountedAncestor336 );337 const child = fiber.child;338 if (child !== null){339 nextEffect = child;340 } else {341 commitPassiveUnmountEffectsInDelTree_complete(342 deletedSubtreeRoot343 )344 }345 }346}347function commitPassiveUnmountEffectsInDelTree_complete(deletedSubtreeRoot){348 while (nextEffect !== null){349 const fiber = nextEffect;350 const sibling = fiber.sibling;351 const returnFiber = fiber.return;352 if (fiber === deletedSubtreeRoot){353 detachFiberAfterEffects(fiber);354 nextEffect = null;355 return;356 }357 if (sibling !== null){358 nextEffect = sibling;359 return;360 }361 nextEffect = returnFiber;362 }363}364function commitPassiveUnmountEffectsInDelTreeOnFiber(365 current, nearestMountedAncestor366){367 switch(current.tag){368 case FunctionComponent:{369 commitHookEffectListUnmount(370 HookPassive,371 current,372 nearestMountedAncestor373 );374 break;375 }376 }377}378function commitUnmount(finishedRoot, current, nearestMountedAncestor){379 switch(current.tag){380 case FunctionComponent:381 case HostComponent:382 return;383 }384}385function commitNestedUnmounts(finishedRoot, root, nearestMountedAncestor){386 let node = root;387 while(true){388 commitUnmount(finishedRoot, node, nearestMountedAncestor);389 if(node.child !== null){390 node.child.return = node;391 node = node.child;392 continue;393 }394 if (node === root){395 return;396 }397 while (node.sibling === null){398 if (node.return === null || node.return === root){399 return;400 }401 node = node.return;402 }403 node.sibling.return = node.return;404 node = node.sibling;405 }406}407function detachFiberMutation(fiber){408 const alternate = fiber.alternate;409 if (alternate !== null){410 alternate.return = null;411 }412 fiber.return = null;413}414function detachFiberAfterEffects(fiber){415 const alternate = fiber.alternate;416 if (alternate !== null){417 fiber.alternate = null;418 detachFiberAfterEffects(alternate);419 }420 fiber.child = null;421 fiber.deletions = null;422 fiber.sibling = null;423 if (fiber.tag === HostComponent){424 if(fiber.stateNode !== null){425 detachDeletedInstance(fiber.stateNode);426 }427 }428 fiber.stateNode = null;429}430function toggleAllChildren(finishedWork, isHidden){431 let hostSubtreeRoot = null;432 let node = finishedWork;433 while(true){434 if (node.tag === HostComponent){435 if(hostSubtreeRoot === null){436 hostSubtreeRoot = node;437 const instance = node.stateNode;438 if (isHidden){439 const style = instance.style;440 if(typeof style.setProperty === 'function'){441 style.setProperty('display', 'none', 'important');442 } else {443 style.display = 'none';444 }445 } else {446 instance.style.removeProperty('display');447 }448 }449 } else if (node.tag === HostText){450 if(hostSubtreeRoot === null){451 const instance = node.stateNode;452 if (isHidden){453 instance.nodeValue ='';454 } else {455 instance.nodeValue = node.memoizedProps;456 }457 }458 } else if(459 node.tag === OffscreenComponent &&460 node.memoizedState !== null &&461 node !== finishedWork462 ){463 debugger;464 } else if (node.child !== null){465 node.child.return = node;466 node = node.child;467 continue;468 }469 if (node == finishedWork){470 return;471 }472 while(node.sibling === null){473 if (node.return === null || node.return === finishedWork){474 return;475 }476 if(hostSubtreeRoot === node){477 hostSubtreeRoot = null;478 }479 node = node.return;480 }481 if(hostSubtreeRoot === node){482 hostSubtreeRoot = null;483 }484 node.sibling.return = node.return;485 node = node.sibling;486 }487}488function getHostParentFiber(fiber){489 let parent = fiber.return;490 while (parent!== null){491 if (isHostParent(parent)){492 return parent;493 }494 parent = parent.return;495 }496}497function isHostParent(fiber){498 return (499 fiber.tag === HostRoot ||500 fiber.tag === HostComponent501 );502}503function getHostSibling(fiber){504 let node = fiber;505 siblings: while (true){506 while(node.sibling === null){507 if (node.return === null || isHostParent(node.return)){508 return null;509 }510 node = node.return;511 }512 node.sibling.return = node.return;513 node = node.sibling;514 while (515 node.tag !== HostComponent &&516 node.tag !== HostText517 ){518 if (node.flags & Placement){519 continue siblings;520 }521 if (node.child === null){522 continue siblings;523 } else {524 node.child.return = node;525 node = node.child;526 }527 }528 if (!(node.flags & Placement)){529 return node.stateNode;530 }531 }532}533function commitPlacement(finishedWork){534 const parentFiber = getHostParentFiber(finishedWork);535 let parent;536 let isContainer;537 const parentStateNode = parentFiber.stateNode;538 switch(parentFiber.tag){539 case HostComponent:540 parent = parentStateNode;541 isContainer = false;542 break;543 case HostRoot:544 parent = parentStateNode.container;545 isContainer = true;546 break;547 default:548 console.error('Unknown parentFiber', parentFiber.tag);549 }550 const before = getHostSibling(finishedWork);551 if(isContainer){552 insertOrAppendPlacementNodeIntoContainer(finishedWork, before, parent);553 } else {554 insertOrAppendPlacementNode(finishedWork, before, parent);555 }556}557function insertOrAppendPlacementNodeIntoContainer(node, before, parent){558 const tag = node.tag;559 const isHost = tag === HostComponent || tag === HostText;560 if (isHost){561 const stateNode =node.stateNode;562 if (before){563 parent.insertBefore(stateNode, before)564 } else {565 parent.append(stateNode);566 }567 } else {568 const child = node.child;569 if (child !== null){570 insertOrAppendPlacementNodeIntoContainer(child, before, parent);571 let sibling = child.sibling;572 while (sibling !== null ){573 insertOrAppendPlacementNodeIntoContainer(574 sibling, 575 before, 576 parent);577 sibling = sibling.sibling;578 }579 }580 }581}582function insertOrAppendPlacementNode(node, before, parent){583 const tag = node.tag;584 const isHost = tag === HostComponent || tag === HostText;585 if (isHost){586 const stateNode = node.stateNode;587 if (before){588 parent.insertBefore(stateNode, before);589 } else {590 parent.append(stateNode);591 }592 } else {593 const child = node.child;594 if(child !== null){595 insertOrAppendPlacementNode(child, before, parent);596 let sibling = child.sibling;597 while(sibling !== null){598 insertOrAppendPlacementNode(sibling, before, parent);599 sibling = sibling.sibling;600 }601 }602 }603}604function unmountHostComponents(finishedRoot, current, nearestMountedAncestor){605 let node = current;606 let currentParentIsValid = false;607 let currentParent;608 let currentParentIsContainer;609 while(true){610 if (!currentParentIsValid){611 let parent = node.return;612 findParent: while(true){613 const parentStateNode = parent.stateNode;614 switch(parent.tag){615 case HostComponent:616 currentParent = parentStateNode;617 currentParentIsContainer = false;618 break findParent;619 case HostRoot:620 currentParent = parentStateNode.container;621 currentParentIsContainer = true;622 break findParent;623 }624 parent = parent.return;625 }626 currentParentIsValid = true;627 }628 if (node.tag === HostComponent || node.tag === HostText){629 commitNestedUnmounts(finishedRoot, node, nearestMountedAncestor);630 currentParent.removeChild(node.stateNode);631 } else {632 commitUnmount(finishedRoot, node, nearestMountedAncestor);633 if (node.child !== null){634 node.child.return = node;635 node = node.child;636 continue;637 }638 }639 if (node === current){640 return;641 }642 while (node.sibling === null){643 if (node.return === null || node.return === current){644 return;645 }646 node = node.return;647 }648 node.sibling.return = node.return;649 node = node.sibling;650 }651}652function commitDeletion(finishedRoot, current, nearestMountedAncestor){653 unmountHostComponents(finishedRoot, current, nearestMountedAncestor);654 detachFiberMutation(current);655}656function commitWork(current, finishedWork){657 switch(finishedWork.tag){658 case HostComponent:{659 const instance = finishedWork.stateNode;660 if (instance !== null){661 const newProps = finishedWork.memoizedProps;662 const oldProps = current !== null ? current.memoizedProps : newProps;663 const type = finishedWork.type;664 const updatePayload = finishedWork.updateQueue;665 finishedWork.updateQueue = null;666 if (updatePayload !== null){667 commitUpdate(668 instance,669 updatePayload,670 type,671 oldProps,672 newProps,673 finishedWork,674 )675 }676 }677 return;678 }679 case SuspenseComponent:{680 commitSuspenseComponent(finishedWork);681 attachSuspenseRetryListeners(finishedWork);682 return;683 }684 case OffscreenComponent:{685 const newState = finishedWork.memoizedState;686 const isHidden = newState !== null;687 toggleAllChildren(finishedWork, isHidden);688 return;689 }690 case HostText:{691 const textInstance = finishedWork.stateNode;692 const newText = finishedWork.memoizedProps;693 textInstance.nodeValue = newText;694 }695 }696}697function commitSuspenseComponent(finishedWork){698 const newState = finishedWork.memoizedState;699 if (newState !== null){700 const primaryChildParent = finishedWork.child;701 //hideOrUnhideAllChildren()702 toggleAllChildren(primaryChildParent, true); 703 }704}705function commitUpdate(706 domElement,707 updatePayload,708 type,709 oldProps,710 newProps,711 internalInstanceHandle712){713 updateFiberProps(domElement, newProps);714 updateDOMProperties(domElement, updatePayload);...

Full Screen

Full Screen

FiberWorkLoop.js

Source:FiberWorkLoop.js Github

copy

Full Screen

...420 markRootUpdated(root, retryLane, eventTime);421 ensureRootIsScheduled(root, eventTime);422 }423}424export function resolveRetryWakeable(boundaryFiber, wakeable){425 let retryCache = boundaryFiber.stateNode;426 if(retryCache !== null){427 retryCache.delete(wakeable);428 }429 retryTimedOutBoundary(boundaryFiber);...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

1const { chromium } = require('playwright');2(async () => {3 const browser = await chromium.launch();4 const context = await browser.newContext();5 const page = await context.newPage();6 await page.screenshot({ path: `example.png` });7 await browser.close();8})();9const { resolveRetryWakeable } = require('playwright');10module.exports = {11 use: {12 viewport: { width: 800, height: 600 },13 },14};15const { resolveRetryWakeable } = require('playwright');16module.exports = {17 use: {18 viewport: { width: 800, height: 600 },19 },20};21const { resolveRetryWakeable } = require('playwright');22module.exports = {23 use: {24 viewport: { width: 800, height: 600 },25 },26};27const { resolveRetryWakeable } = require('playwright');28module.exports = {29 use: {30 viewport: { width: 800, height: 600 },31 },32};33const { resolveRetryWakeable } = require('playwright');34module.exports = {35 use: {36 viewport: { width: 800, height: 600 },37 },38};

Full Screen

Using AI Code Generation

copy

Full Screen

1const { resolveRetryWakeable } = require("@playwright/test/lib/server/wakeable");2const { chromium } = require("playwright");3(async () => {4 const browser = await chromium.launch();5 const context = await browser.newContext();6 const page = await context.newPage();7 const elementHandle = await page.$("text=Get Started");8 const wakeable = await elementHandle._retry();9 const retry = await resolveRetryWakeable(wakeable);10 console.log(retry);11 await browser.close();12})();

Full Screen

Using AI Code Generation

copy

Full Screen

1const { resolveRetryWakeable } = require('playwright-core/lib/server/wakeable');2const { chromium } = require('playwright-core');3const browser = await chromium.launch();4const page = await browser.newPage();5await page.waitForSelector('a');6const wakeable = await page.waitForSelector('a');7const element = await resolveRetryWakeable(wakeable);8console.log(element);9await browser.close();10ElementHandle {11 _context: ExecutionContext {12 _page: Page {13 _browserContext: BrowserContext {14 _browser: Browser {15 _connection: Connection {16 _ws: WebSocket {…},17 _callbacks: Map {},18 _sessions: Map {},19 _sessionsIds: Map {},20 _dispatchQueue: Promise {},21 _crBrowserSessionPromise: Promise {},22 _crBrowserSessionClosePromise: Promise {},

Full Screen

Using AI Code Generation

copy

Full Screen

1const { resolveRetryWakeable } = require('playwright/lib/internal/utils/utils');2const { resolveRetryWakeable } = require('playwright/lib/internal/utils/utils');3const { resolveRetryWakeable } = require('playwright/lib/internal/utils/utils');4const { resolveRetryWakeable } = require('playwright/lib/internal/utils/utils');5const { resolveRetryWakeable } = require('playwright/lib/internal/utils/utils');6const { resolveRetryWakeable } = require('playwright/lib/internal/utils/utils');7const { resolveRetryWakeable } = require('playwright/lib/internal/utils/utils');8const { resolveRetryWakeable } = require('playwright/lib/internal/utils/utils');9const { resolveRetryWakeable } = require('playwright/lib/internal/utils/utils');10const { resolveRetryWakeable } = require('playwright/lib/internal/utils/utils');11const { resolveRetryWakeable } = require('playwright/lib/internal/utils/utils');12const { resolve

Full Screen

Using AI Code Generation

copy

Full Screen

1const {InternalHelper} = require('playwright/lib/server/helper.js');2const helper = new InternalHelper();3const wakeable = helper.resolveRetryWakeable(1000);4wakeable.then((value) => {5 console.log(value);6});7const {InternalHelper} = require('playwright/lib/server/helper.js');8const helper = new InternalHelper();9const wakeable = helper.resolveRetryWakeable(1000);10wakeable.then((value) => {11 console.log(value);12});13const {InternalHelper} = require('playwright/lib/server/helper.js');14const helper = new InternalHelper();15const wakeable = helper.resolveRetryWakeable(1000);16wakeable.then((value) => {17 console.log(value);18});19const {InternalHelper} = require('playwright/lib/server/helper.js');20const helper = new InternalHelper();21const wakeable = helper.resolveRetryWakeable(1000);22wakeable.then((value) => {23 console.log(value);24});25const {InternalHelper} = require('playwright/lib/server/helper.js');26const helper = new InternalHelper();27const wakeable = helper.resolveRetryWakeable(1000);28wakeable.then((value) => {29 console.log(value);30});31const {InternalHelper} = require('playwright/lib/server/helper.js');32const helper = new InternalHelper();33const wakeable = helper.resolveRetryWakeable(1000);34wakeable.then((value) => {35 console.log(value);36});37const {InternalHelper} = require('playwright

Full Screen

Using AI Code Generation

copy

Full Screen

1const { resolveRetryWakeable } = require('playwright/lib/utils/utils');2const { PlaywrightTest } = require('@playwright/test');3const { test } = PlaywrightTest;4test('test', async ({ page }) => {5 await resolveRetryWakeable(() => page.isVisible('css=div'), false);6 await page.click('css=div');7});8Example: Wait for the element to be visible using waitForSelector()9const { test } = require('@playwright/test');10test('test', async ({ page }) => {11 await page.waitForSelector('css=div');12 await page.click('css=div');13});14Example: Wait for the element to be visible using waitForFunction()15const { test } = require('@playwright/test');16test('test', async ({ page }) => {17 await page.waitForFunction(() => document.querySelector('div').offsetWidth > 0);18 await page.click('css=div');19});20Example: Wait for the element to be visible using waitForTimeout()21const { test } = require('@playwright/test');22test('test', async ({ page }) => {23 await page.waitForTimeout(1000);24 await page.click('css=div');25});26Example: Wait for the element to be visible using waitForResponse()27const { test } = require('@playwright/test');28test('test', async ({ page }) => {29 await page.click('css=div');30});31Example: Wait for the element to be visible using waitForRequest()32const { test } = require('@playwright/test');33test('test', async ({ page }) => {34 await page.click('css=div');35});36Example: Wait for the element to be visible using waitForEvent()37const { test } = require('@playwright/test');

Full Screen

Using AI Code Generation

copy

Full Screen

1const { resolveRetryWakeable } = require('playwright/lib/utils/utils');2const { TimeoutError } = require('playwright/lib/errors');3const { createTestServer } = require('playwright/lib/utils/testserver');4(async () => {5 const server = await createTestServer();6 server.setRoute('/sleep', async (req, res) => {7 res.setHeader('Content-Type', 'text/plain');8 res.write('hello ');9 await new Promise(f => setTimeout(f, 1000));10 res.end('world');11 });12 const url = server.PREFIX + '/sleep';13 const wakeable = new Promise(f => setTimeout(f, 1000));14 const timeout = 100;15 try {16 await resolveRetryWakeable(wakeable, async () => {17 await page.goto(url);18 }, timeout);19 } catch (e) {20 if (e instanceof TimeoutError)21 console.log('Error: Timeout');22 }23})();

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