Best JavaScript code snippet using playwright-internal
ReactFiberCommitWork.js
Source:ReactFiberCommitWork.js  
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,...ReactFiberCommitWork.new.js
Source:ReactFiberCommitWork.new.js  
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,...ReactFiberCommitWork.old.js
Source:ReactFiberCommitWork.old.js  
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,...FiberCommitWork.js
Source:FiberCommitWork.js  
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);...FiberWorkLoop.js
Source:FiberWorkLoop.js  
...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);...Using AI Code Generation
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};Using AI Code Generation
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})();Using AI Code Generation
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 {},Using AI Code Generation
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 { resolveUsing AI Code Generation
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('playwrightUsing AI Code Generation
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');Using AI Code Generation
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})();LambdaTest’s Playwright tutorial will give you a broader idea about the Playwright automation framework, its unique features, and use cases with examples to exceed your understanding of Playwright testing. This tutorial will give A to Z guidance, from installing the Playwright framework to some best practices and advanced concepts.
Get 100 minutes of automation test minutes FREE!!
