Best JavaScript code snippet using playwright-internal
ReactFiberCommitWork.old.js
Source:ReactFiberCommitWork.old.js  
...191  current: Fiber,192  nearestMountedAncestor: Fiber | null,193) {194  try {195    commitHookEffectListMount(HookLayout, current);196  } catch (error) {197    reportUncaughtErrorInDEV(error);198    captureCommitPhaseError(current, nearestMountedAncestor, error);199  }200}201// Capture errors so they don't interrupt unmounting.202function safelyCallComponentWillUnmount(203  current: Fiber,204  nearestMountedAncestor: Fiber | null,205  instance: any,206) {207  try {208    callComponentWillUnmountWithTimer(current, instance);209  } catch (error) {210    reportUncaughtErrorInDEV(error);211    captureCommitPhaseError(current, nearestMountedAncestor, error);212  }213}214// Capture errors so they don't interrupt mounting.215function safelyCallComponentDidMount(216  current: Fiber,217  nearestMountedAncestor: Fiber | null,218  instance: any,219) {220  try {221    instance.componentDidMount();222  } catch (error) {223    reportUncaughtErrorInDEV(error);224    captureCommitPhaseError(current, nearestMountedAncestor, error);225  }226}227// Capture errors so they don't interrupt mounting.228function safelyAttachRef(current: Fiber, nearestMountedAncestor: Fiber | null) {229  try {230    commitAttachRef(current);231  } catch (error) {232    reportUncaughtErrorInDEV(error);233    captureCommitPhaseError(current, nearestMountedAncestor, error);234  }235}236function safelyDetachRef(current: Fiber, nearestMountedAncestor: Fiber | null) {237  const ref = current.ref;238  if (ref !== null) {239    if (typeof ref === 'function') {240      let retVal;241      try {242        if (243          enableProfilerTimer &&244          enableProfilerCommitHooks &&245          current.mode & ProfileMode246        ) {247          try {248            startLayoutEffectTimer();249            retVal = ref(null);250          } finally {251            recordLayoutEffectDuration(current);252          }253        } else {254          retVal = ref(null);255        }256      } catch (error) {257        reportUncaughtErrorInDEV(error);258        captureCommitPhaseError(current, nearestMountedAncestor, error);259      }260      if (__DEV__) {261        if (262          warnAboutCallbackRefReturningFunction &&263          typeof retVal === 'function'264        ) {265          console.error(266            'Unexpected return value from a callback ref in %s. ' +267              'A callback ref should not return a function.',268            getComponentNameFromFiber(current),269          );270        }271      }272    } else {273      ref.current = null;274    }275  }276}277function safelyCallDestroy(278  current: Fiber,279  nearestMountedAncestor: Fiber | null,280  destroy: () => void,281) {282  try {283    destroy();284  } catch (error) {285    reportUncaughtErrorInDEV(error);286    captureCommitPhaseError(current, nearestMountedAncestor, error);287  }288}289let focusedInstanceHandle: null | Fiber = null;290let shouldFireAfterActiveInstanceBlur: boolean = false;291export function commitBeforeMutationEffects(292  root: FiberRoot,293  firstChild: Fiber,294) {295  focusedInstanceHandle = prepareForCommit(root.containerInfo);296  nextEffect = firstChild;297  commitBeforeMutationEffects_begin();298  // We no longer need to track the active instance fiber299  const shouldFire = shouldFireAfterActiveInstanceBlur;300  shouldFireAfterActiveInstanceBlur = false;301  focusedInstanceHandle = null;302  return shouldFire;303}304function commitBeforeMutationEffects_begin() {305  while (nextEffect !== null) {306    const fiber = nextEffect;307    // This phase is only used for beforeActiveInstanceBlur.308    // Let's skip the whole loop if it's off.309    if (enableCreateEventHandleAPI) {310      // TODO: Should wrap this in flags check, too, as optimization311      const deletions = fiber.deletions;312      if (deletions !== null) {313        for (let i = 0; i < deletions.length; i++) {314          const deletion = deletions[i];315          commitBeforeMutationEffectsDeletion(deletion);316        }317      }318    }319    const child = fiber.child;320    if (321      (fiber.subtreeFlags & BeforeMutationMask) !== NoFlags &&322      child !== null323    ) {324      ensureCorrectReturnPointer(child, fiber);325      nextEffect = child;326    } else {327      commitBeforeMutationEffects_complete();328    }329  }330}331function commitBeforeMutationEffects_complete() {332  while (nextEffect !== null) {333    const fiber = nextEffect;334    setCurrentDebugFiberInDEV(fiber);335    try {336      commitBeforeMutationEffectsOnFiber(fiber);337    } catch (error) {338      reportUncaughtErrorInDEV(error);339      captureCommitPhaseError(fiber, fiber.return, error);340    }341    resetCurrentDebugFiberInDEV();342    const sibling = fiber.sibling;343    if (sibling !== null) {344      ensureCorrectReturnPointer(sibling, fiber.return);345      nextEffect = sibling;346      return;347    }348    nextEffect = fiber.return;349  }350}351function commitBeforeMutationEffectsOnFiber(finishedWork: Fiber) {352  const current = finishedWork.alternate;353  const flags = finishedWork.flags;354  if (enableCreateEventHandleAPI) {355    if (!shouldFireAfterActiveInstanceBlur && focusedInstanceHandle !== null) {356      // Check to see if the focused element was inside of a hidden (Suspense) subtree.357      // TODO: Move this out of the hot path using a dedicated effect tag.358      if (359        finishedWork.tag === SuspenseComponent &&360        isSuspenseBoundaryBeingHidden(current, finishedWork) &&361        doesFiberContain(finishedWork, focusedInstanceHandle)362      ) {363        shouldFireAfterActiveInstanceBlur = true;364        beforeActiveInstanceBlur(finishedWork);365      }366    }367  }368  if ((flags & Snapshot) !== NoFlags) {369    setCurrentDebugFiberInDEV(finishedWork);370    switch (finishedWork.tag) {371      case FunctionComponent:372      case ForwardRef:373      case SimpleMemoComponent: {374        break;375      }376      case ClassComponent: {377        if (current !== null) {378          const prevProps = current.memoizedProps;379          const prevState = current.memoizedState;380          const instance = finishedWork.stateNode;381          // We could update instance props and state here,382          // but instead we rely on them being set during last render.383          // TODO: revisit this when we implement resuming.384          if (__DEV__) {385            if (386              finishedWork.type === finishedWork.elementType &&387              !didWarnAboutReassigningProps388            ) {389              if (instance.props !== finishedWork.memoizedProps) {390                console.error(391                  'Expected %s props to match memoized props before ' +392                    'getSnapshotBeforeUpdate. ' +393                    'This might either be because of a bug in React, or because ' +394                    'a component reassigns its own `this.props`. ' +395                    'Please file an issue.',396                  getComponentNameFromFiber(finishedWork) || 'instance',397                );398              }399              if (instance.state !== finishedWork.memoizedState) {400                console.error(401                  'Expected %s state to match memoized state before ' +402                    'getSnapshotBeforeUpdate. ' +403                    'This might either be because of a bug in React, or because ' +404                    'a component reassigns its own `this.state`. ' +405                    'Please file an issue.',406                  getComponentNameFromFiber(finishedWork) || 'instance',407                );408              }409            }410          }411          const snapshot = instance.getSnapshotBeforeUpdate(412            finishedWork.elementType === finishedWork.type413              ? prevProps414              : resolveDefaultProps(finishedWork.type, prevProps),415            prevState,416          );417          if (__DEV__) {418            const didWarnSet = ((didWarnAboutUndefinedSnapshotBeforeUpdate: any): Set<mixed>);419            if (snapshot === undefined && !didWarnSet.has(finishedWork.type)) {420              didWarnSet.add(finishedWork.type);421              console.error(422                '%s.getSnapshotBeforeUpdate(): A snapshot value (or null) ' +423                  'must be returned. You have returned undefined.',424                getComponentNameFromFiber(finishedWork),425              );426            }427          }428          instance.__reactInternalSnapshotBeforeUpdate = snapshot;429        }430        break;431      }432      case HostRoot: {433        if (supportsMutation) {434          const root = finishedWork.stateNode;435          clearContainer(root.containerInfo);436        }437        break;438      }439      case HostComponent:440      case HostText:441      case HostPortal:442      case IncompleteClassComponent:443        // Nothing to do for these component types444        break;445      default: {446        invariant(447          false,448          'This unit of work tag should not have side-effects. This error is ' +449            'likely caused by a bug in React. Please file an issue.',450        );451      }452    }453    resetCurrentDebugFiberInDEV();454  }455}456function commitBeforeMutationEffectsDeletion(deletion: Fiber) {457  if (enableCreateEventHandleAPI) {458    // TODO (effects) It would be nice to avoid calling doesFiberContain()459    // Maybe we can repurpose one of the subtreeFlags positions for this instead?460    // Use it to store which part of the tree the focused instance is in?461    // This assumes we can safely determine that instance during the "render" phase.462    if (doesFiberContain(deletion, ((focusedInstanceHandle: any): Fiber))) {463      shouldFireAfterActiveInstanceBlur = true;464      beforeActiveInstanceBlur(deletion);465    }466  }467}468function commitHookEffectListUnmount(469  flags: HookFlags,470  finishedWork: Fiber,471  nearestMountedAncestor: Fiber | null,472) {473  const updateQueue: FunctionComponentUpdateQueue | null = (finishedWork.updateQueue: any);474  const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;475  if (lastEffect !== null) {476    const firstEffect = lastEffect.next;477    let effect = firstEffect;478    do {479      if ((effect.tag & flags) === flags) {480        // Unmount481        const destroy = effect.destroy;482        effect.destroy = undefined;483        if (destroy !== undefined) {484          safelyCallDestroy(finishedWork, nearestMountedAncestor, destroy);485        }486      }487      effect = effect.next;488    } while (effect !== firstEffect);489  }490}491function commitHookEffectListMount(tag: HookFlags, finishedWork: Fiber) {492  const updateQueue: FunctionComponentUpdateQueue | null = (finishedWork.updateQueue: any);493  const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;494  if (lastEffect !== null) {495    const firstEffect = lastEffect.next;496    let effect = firstEffect;497    do {498      if ((effect.tag & tag) === tag) {499        // Mount500        const create = effect.create;501        effect.destroy = create();502        if (__DEV__) {503          const destroy = effect.destroy;504          if (destroy !== undefined && typeof destroy !== 'function') {505            let hookName;506            if ((effect.tag & HookLayout) !== NoFlags) {507              hookName = 'useLayoutEffect';508            } else if ((effect.tag & HookInsertion) !== NoFlags) {509              hookName = 'useInsertionEffect';510            } else {511              hookName = 'useEffect';512            }513            let addendum;514            if (destroy === null) {515              addendum =516                ' You returned null. If your effect does not require clean ' +517                'up, return undefined (or nothing).';518            } else if (typeof destroy.then === 'function') {519              addendum =520                '\n\nIt looks like you wrote ' +521                hookName +522                '(async () => ...) or returned a Promise. ' +523                'Instead, write the async function inside your effect ' +524                'and call it immediately:\n\n' +525                hookName +526                '(() => {\n' +527                '  async function fetchData() {\n' +528                '    // You can await here\n' +529                '    const response = await MyAPI.getData(someId);\n' +530                '    // ...\n' +531                '  }\n' +532                '  fetchData();\n' +533                `}, [someId]); // Or [] if effect doesn't need props or state\n\n` +534                'Learn more about data fetching with Hooks: https://reactjs.org/link/hooks-data-fetching';535            } else {536              addendum = ' You returned: ' + destroy;537            }538            console.error(539              '%s must not return anything besides a function, ' +540                'which is used for clean-up.%s',541              hookName,542              addendum,543            );544          }545        }546      }547      effect = effect.next;548    } while (effect !== firstEffect);549  }550}551export function commitPassiveEffectDurations(552  finishedRoot: FiberRoot,553  finishedWork: Fiber,554): void {555  if (enableProfilerTimer && enableProfilerCommitHooks) {556    // Only Profilers with work in their subtree will have an Update effect scheduled.557    if ((finishedWork.flags & Update) !== NoFlags) {558      switch (finishedWork.tag) {559        case Profiler: {560          const {passiveEffectDuration} = finishedWork.stateNode;561          const {id, onPostCommit} = finishedWork.memoizedProps;562          // This value will still reflect the previous commit phase.563          // It does not get reset until the start of the next commit phase.564          const commitTime = getCommitTime();565          let phase = finishedWork.alternate === null ? 'mount' : 'update';566          if (enableProfilerNestedUpdatePhase) {567            if (isCurrentUpdateNested()) {568              phase = 'nested-update';569            }570          }571          if (typeof onPostCommit === 'function') {572            onPostCommit(id, phase, passiveEffectDuration, commitTime);573          }574          // Bubble times to the next nearest ancestor Profiler.575          // After we process that Profiler, we'll bubble further up.576          let parentFiber = finishedWork.return;577          outer: while (parentFiber !== null) {578            switch (parentFiber.tag) {579              case HostRoot:580                const root = parentFiber.stateNode;581                root.passiveEffectDuration += passiveEffectDuration;582                break outer;583              case Profiler:584                const parentStateNode = parentFiber.stateNode;585                parentStateNode.passiveEffectDuration += passiveEffectDuration;586                break outer;587            }588            parentFiber = parentFiber.return;589          }590          break;591        }592        default:593          break;594      }595    }596  }597}598function commitLayoutEffectOnFiber(599  finishedRoot: FiberRoot,600  current: Fiber | null,601  finishedWork: Fiber,602  committedLanes: Lanes,603): void {604  if ((finishedWork.flags & LayoutMask) !== NoFlags) {605    switch (finishedWork.tag) {606      case FunctionComponent:607      case ForwardRef:608      case SimpleMemoComponent: {609        if (610          !enableSuspenseLayoutEffectSemantics ||611          !offscreenSubtreeWasHidden612        ) {613          // At this point layout effects have already been destroyed (during mutation phase).614          // This is done to prevent sibling component effects from interfering with each other,615          // e.g. a destroy function in one component should never override a ref set616          // by a create function in another component during the same commit.617          if (618            enableProfilerTimer &&619            enableProfilerCommitHooks &&620            finishedWork.mode & ProfileMode621          ) {622            try {623              startLayoutEffectTimer();624              commitHookEffectListMount(625                HookLayout | HookHasEffect,626                finishedWork,627              );628            } finally {629              recordLayoutEffectDuration(finishedWork);630            }631          } else {632            commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork);633          }634        }635        break;636      }637      case ClassComponent: {638        const instance = finishedWork.stateNode;639        if (finishedWork.flags & Update) {640          if (!offscreenSubtreeWasHidden) {641            if (current === null) {642              // We could update instance props and state here,643              // but instead we rely on them being set during last render.644              // TODO: revisit this when we implement resuming.645              if (__DEV__) {646                if (647                  finishedWork.type === finishedWork.elementType &&648                  !didWarnAboutReassigningProps649                ) {650                  if (instance.props !== finishedWork.memoizedProps) {651                    console.error(652                      'Expected %s props to match memoized props before ' +653                        'componentDidMount. ' +654                        'This might either be because of a bug in React, or because ' +655                        'a component reassigns its own `this.props`. ' +656                        'Please file an issue.',657                      getComponentNameFromFiber(finishedWork) || 'instance',658                    );659                  }660                  if (instance.state !== finishedWork.memoizedState) {661                    console.error(662                      'Expected %s state to match memoized state before ' +663                        'componentDidMount. ' +664                        'This might either be because of a bug in React, or because ' +665                        'a component reassigns its own `this.state`. ' +666                        'Please file an issue.',667                      getComponentNameFromFiber(finishedWork) || 'instance',668                    );669                  }670                }671              }672              if (673                enableProfilerTimer &&674                enableProfilerCommitHooks &&675                finishedWork.mode & ProfileMode676              ) {677                try {678                  startLayoutEffectTimer();679                  instance.componentDidMount();680                } finally {681                  recordLayoutEffectDuration(finishedWork);682                }683              } else {684                instance.componentDidMount();685              }686            } else {687              const prevProps =688                finishedWork.elementType === finishedWork.type689                  ? current.memoizedProps690                  : resolveDefaultProps(691                      finishedWork.type,692                      current.memoizedProps,693                    );694              const prevState = current.memoizedState;695              // We could update instance props and state here,696              // but instead we rely on them being set during last render.697              // TODO: revisit this when we implement resuming.698              if (__DEV__) {699                if (700                  finishedWork.type === finishedWork.elementType &&701                  !didWarnAboutReassigningProps702                ) {703                  if (instance.props !== finishedWork.memoizedProps) {704                    console.error(705                      'Expected %s props to match memoized props before ' +706                        'componentDidUpdate. ' +707                        'This might either be because of a bug in React, or because ' +708                        'a component reassigns its own `this.props`. ' +709                        'Please file an issue.',710                      getComponentNameFromFiber(finishedWork) || 'instance',711                    );712                  }713                  if (instance.state !== finishedWork.memoizedState) {714                    console.error(715                      'Expected %s state to match memoized state before ' +716                        'componentDidUpdate. ' +717                        'This might either be because of a bug in React, or because ' +718                        'a component reassigns its own `this.state`. ' +719                        'Please file an issue.',720                      getComponentNameFromFiber(finishedWork) || 'instance',721                    );722                  }723                }724              }725              if (726                enableProfilerTimer &&727                enableProfilerCommitHooks &&728                finishedWork.mode & ProfileMode729              ) {730                try {731                  startLayoutEffectTimer();732                  instance.componentDidUpdate(733                    prevProps,734                    prevState,735                    instance.__reactInternalSnapshotBeforeUpdate,736                  );737                } finally {738                  recordLayoutEffectDuration(finishedWork);739                }740              } else {741                instance.componentDidUpdate(742                  prevProps,743                  prevState,744                  instance.__reactInternalSnapshotBeforeUpdate,745                );746              }747            }748          }749        }750        // TODO: I think this is now always non-null by the time it reaches the751        // commit phase. Consider removing the type check.752        const updateQueue: UpdateQueue<753          *,754        > | null = (finishedWork.updateQueue: any);755        if (updateQueue !== null) {756          if (__DEV__) {757            if (758              finishedWork.type === finishedWork.elementType &&759              !didWarnAboutReassigningProps760            ) {761              if (instance.props !== finishedWork.memoizedProps) {762                console.error(763                  'Expected %s props to match memoized props before ' +764                    'processing the update queue. ' +765                    'This might either be because of a bug in React, or because ' +766                    'a component reassigns its own `this.props`. ' +767                    'Please file an issue.',768                  getComponentNameFromFiber(finishedWork) || 'instance',769                );770              }771              if (instance.state !== finishedWork.memoizedState) {772                console.error(773                  'Expected %s state to match memoized state before ' +774                    'processing the update queue. ' +775                    'This might either be because of a bug in React, or because ' +776                    'a component reassigns its own `this.state`. ' +777                    'Please file an issue.',778                  getComponentNameFromFiber(finishedWork) || 'instance',779                );780              }781            }782          }783          // We could update instance props and state here,784          // but instead we rely on them being set during last render.785          // TODO: revisit this when we implement resuming.786          commitUpdateQueue(finishedWork, updateQueue, instance);787        }788        break;789      }790      case HostRoot: {791        // TODO: I think this is now always non-null by the time it reaches the792        // commit phase. Consider removing the type check.793        const updateQueue: UpdateQueue<794          *,795        > | null = (finishedWork.updateQueue: any);796        if (updateQueue !== null) {797          let instance = null;798          if (finishedWork.child !== null) {799            switch (finishedWork.child.tag) {800              case HostComponent:801                instance = getPublicInstance(finishedWork.child.stateNode);802                break;803              case ClassComponent:804                instance = finishedWork.child.stateNode;805                break;806            }807          }808          commitUpdateQueue(finishedWork, updateQueue, instance);809        }810        break;811      }812      case HostComponent: {813        const instance: Instance = finishedWork.stateNode;814        // Renderers may schedule work to be done after host components are mounted815        // (eg DOM renderer may schedule auto-focus for inputs and form controls).816        // These effects should only be committed when components are first mounted,817        // aka when there is no current/alternate.818        if (current === null && finishedWork.flags & Update) {819          const type = finishedWork.type;820          const props = finishedWork.memoizedProps;821          commitMount(instance, type, props, finishedWork);822        }823        break;824      }825      case HostText: {826        // We have no life-cycles associated with text.827        break;828      }829      case HostPortal: {830        // We have no life-cycles associated with portals.831        break;832      }833      case Profiler: {834        if (enableProfilerTimer) {835          const {onCommit, onRender} = finishedWork.memoizedProps;836          const {effectDuration} = finishedWork.stateNode;837          const commitTime = getCommitTime();838          let phase = current === null ? 'mount' : 'update';839          if (enableProfilerNestedUpdatePhase) {840            if (isCurrentUpdateNested()) {841              phase = 'nested-update';842            }843          }844          if (typeof onRender === 'function') {845            onRender(846              finishedWork.memoizedProps.id,847              phase,848              finishedWork.actualDuration,849              finishedWork.treeBaseDuration,850              finishedWork.actualStartTime,851              commitTime,852            );853          }854          if (enableProfilerCommitHooks) {855            if (typeof onCommit === 'function') {856              onCommit(857                finishedWork.memoizedProps.id,858                phase,859                effectDuration,860                commitTime,861              );862            }863            // Schedule a passive effect for this Profiler to call onPostCommit hooks.864            // This effect should be scheduled even if there is no onPostCommit callback for this Profiler,865            // because the effect is also where times bubble to parent Profilers.866            enqueuePendingPassiveProfilerEffect(finishedWork);867            // Propagate layout effect durations to the next nearest Profiler ancestor.868            // Do not reset these values until the next render so DevTools has a chance to read them first.869            let parentFiber = finishedWork.return;870            outer: while (parentFiber !== null) {871              switch (parentFiber.tag) {872                case HostRoot:873                  const root = parentFiber.stateNode;874                  root.effectDuration += effectDuration;875                  break outer;876                case Profiler:877                  const parentStateNode = parentFiber.stateNode;878                  parentStateNode.effectDuration += effectDuration;879                  break outer;880              }881              parentFiber = parentFiber.return;882            }883          }884        }885        break;886      }887      case SuspenseComponent: {888        commitSuspenseHydrationCallbacks(finishedRoot, finishedWork);889        break;890      }891      case SuspenseListComponent:892      case IncompleteClassComponent:893      case ScopeComponent:894      case OffscreenComponent:895      case LegacyHiddenComponent:896        break;897      default:898        invariant(899          false,900          'This unit of work tag should not have side-effects. This error is ' +901            'likely caused by a bug in React. Please file an issue.',902        );903    }904  }905  if (!enableSuspenseLayoutEffectSemantics || !offscreenSubtreeWasHidden) {906    if (enableScopeAPI) {907      // TODO: This is a temporary solution that allowed us to transition away908      // from React Flare on www.909      if (finishedWork.flags & Ref && finishedWork.tag !== ScopeComponent) {910        commitAttachRef(finishedWork);911      }912    } else {913      if (finishedWork.flags & Ref) {914        commitAttachRef(finishedWork);915      }916    }917  }918}919function reappearLayoutEffectsOnFiber(node: Fiber) {920  // Turn on layout effects in a tree that previously disappeared.921  // TODO (Offscreen) Check: flags & LayoutStatic922  switch (node.tag) {923    case FunctionComponent:924    case ForwardRef:925    case SimpleMemoComponent: {926      if (927        enableProfilerTimer &&928        enableProfilerCommitHooks &&929        node.mode & ProfileMode930      ) {931        try {932          startLayoutEffectTimer();933          safelyCallCommitHookLayoutEffectListMount(node, node.return);934        } finally {935          recordLayoutEffectDuration(node);936        }937      } else {938        safelyCallCommitHookLayoutEffectListMount(node, node.return);939      }940      break;941    }942    case ClassComponent: {943      const instance = node.stateNode;944      if (typeof instance.componentDidMount === 'function') {945        safelyCallComponentDidMount(node, node.return, instance);946      }947      safelyAttachRef(node, node.return);948      break;949    }950    case HostComponent: {951      safelyAttachRef(node, node.return);952      break;953    }954  }955}956function hideOrUnhideAllChildren(finishedWork, isHidden) {957  // Only hide or unhide the top-most host nodes.958  let hostSubtreeRoot = null;959  if (supportsMutation) {960    // We only have the top Fiber that was inserted but we need to recurse down its961    // children to find all the terminal nodes.962    let node: Fiber = finishedWork;963    while (true) {964      if (node.tag === HostComponent) {965        if (hostSubtreeRoot === null) {966          hostSubtreeRoot = node;967          const instance = node.stateNode;968          if (isHidden) {969            hideInstance(instance);970          } else {971            unhideInstance(node.stateNode, node.memoizedProps);972          }973        }974      } else if (node.tag === HostText) {975        if (hostSubtreeRoot === null) {976          const instance = node.stateNode;977          if (isHidden) {978            hideTextInstance(instance);979          } else {980            unhideTextInstance(instance, node.memoizedProps);981          }982        }983      } else if (984        (node.tag === OffscreenComponent ||985          node.tag === LegacyHiddenComponent) &&986        (node.memoizedState: OffscreenState) !== null &&987        node !== finishedWork988      ) {989        // Found a nested Offscreen component that is hidden.990        // Don't search any deeper. This tree should remain hidden.991      } else if (node.child !== null) {992        node.child.return = node;993        node = node.child;994        continue;995      }996      if (node === finishedWork) {997        return;998      }999      while (node.sibling === null) {1000        if (node.return === null || node.return === finishedWork) {1001          return;1002        }1003        if (hostSubtreeRoot === node) {1004          hostSubtreeRoot = null;1005        }1006        node = node.return;1007      }1008      if (hostSubtreeRoot === node) {1009        hostSubtreeRoot = null;1010      }1011      node.sibling.return = node.return;1012      node = node.sibling;1013    }1014  }1015}1016function commitAttachRef(finishedWork: Fiber) {1017  const ref = finishedWork.ref;1018  if (ref !== null) {1019    const instance = finishedWork.stateNode;1020    let instanceToUse;1021    switch (finishedWork.tag) {1022      case HostComponent:1023        instanceToUse = getPublicInstance(instance);1024        break;1025      default:1026        instanceToUse = instance;1027    }1028    // Moved outside to ensure DCE works with this flag1029    if (enableScopeAPI && finishedWork.tag === ScopeComponent) {1030      instanceToUse = instance;1031    }1032    if (typeof ref === 'function') {1033      let retVal;1034      if (1035        enableProfilerTimer &&1036        enableProfilerCommitHooks &&1037        finishedWork.mode & ProfileMode1038      ) {1039        try {1040          startLayoutEffectTimer();1041          retVal = ref(instanceToUse);1042        } finally {1043          recordLayoutEffectDuration(finishedWork);1044        }1045      } else {1046        retVal = ref(instanceToUse);1047      }1048      if (__DEV__) {1049        if (1050          warnAboutCallbackRefReturningFunction &&1051          typeof retVal === 'function'1052        ) {1053          console.error(1054            'Unexpected return value from a callback ref in %s. ' +1055              'A callback ref should not return a function.',1056            getComponentNameFromFiber(finishedWork),1057          );1058        }1059      }1060    } else {1061      if (__DEV__) {1062        if (!ref.hasOwnProperty('current')) {1063          console.error(1064            'Unexpected ref object provided for %s. ' +1065              'Use either a ref-setter function or React.createRef().',1066            getComponentNameFromFiber(finishedWork),1067          );1068        }1069      }1070      ref.current = instanceToUse;1071    }1072  }1073}1074function commitDetachRef(current: Fiber) {1075  const currentRef = current.ref;1076  if (currentRef !== null) {1077    if (typeof currentRef === 'function') {1078      if (1079        enableProfilerTimer &&1080        enableProfilerCommitHooks &&1081        current.mode & ProfileMode1082      ) {1083        try {1084          startLayoutEffectTimer();1085          currentRef(null);1086        } finally {1087          recordLayoutEffectDuration(current);1088        }1089      } else {1090        currentRef(null);1091      }1092    } else {1093      currentRef.current = null;1094    }1095  }1096}1097// User-originating errors (lifecycles and refs) should not interrupt1098// deletion, so don't let them throw. Host-originating errors should1099// interrupt deletion, so it's okay1100function commitUnmount(1101  finishedRoot: FiberRoot,1102  current: Fiber,1103  nearestMountedAncestor: Fiber,1104): void {1105  onCommitUnmount(current);1106  switch (current.tag) {1107    case FunctionComponent:1108    case ForwardRef:1109    case MemoComponent:1110    case SimpleMemoComponent: {1111      const updateQueue: FunctionComponentUpdateQueue | null = (current.updateQueue: any);1112      if (updateQueue !== null) {1113        const lastEffect = updateQueue.lastEffect;1114        if (lastEffect !== null) {1115          const firstEffect = lastEffect.next;1116          let effect = firstEffect;1117          do {1118            const {destroy, tag} = effect;1119            if (destroy !== undefined) {1120              if (1121                (tag & HookInsertion) !== NoHookEffect ||1122                (tag & HookLayout) !== NoHookEffect1123              ) {1124                if (1125                  enableProfilerTimer &&1126                  enableProfilerCommitHooks &&1127                  current.mode & ProfileMode1128                ) {1129                  startLayoutEffectTimer();1130                  safelyCallDestroy(current, nearestMountedAncestor, destroy);1131                  recordLayoutEffectDuration(current);1132                } else {1133                  safelyCallDestroy(current, nearestMountedAncestor, destroy);1134                }1135              }1136            }1137            effect = effect.next;1138          } while (effect !== firstEffect);1139        }1140      }1141      return;1142    }1143    case ClassComponent: {1144      safelyDetachRef(current, nearestMountedAncestor);1145      const instance = current.stateNode;1146      if (typeof instance.componentWillUnmount === 'function') {1147        safelyCallComponentWillUnmount(1148          current,1149          nearestMountedAncestor,1150          instance,1151        );1152      }1153      return;1154    }1155    case HostComponent: {1156      safelyDetachRef(current, nearestMountedAncestor);1157      return;1158    }1159    case HostPortal: {1160      // TODO: this is recursive.1161      // We are also not using this parent because1162      // the portal will get pushed immediately.1163      if (supportsMutation) {1164        unmountHostComponents(finishedRoot, current, nearestMountedAncestor);1165      } else if (supportsPersistence) {1166        emptyPortalContainer(current);1167      }1168      return;1169    }1170    case DehydratedFragment: {1171      if (enableSuspenseCallback) {1172        const hydrationCallbacks = finishedRoot.hydrationCallbacks;1173        if (hydrationCallbacks !== null) {1174          const onDeleted = hydrationCallbacks.onDeleted;1175          if (onDeleted) {1176            onDeleted((current.stateNode: SuspenseInstance));1177          }1178        }1179      }1180      return;1181    }1182    case ScopeComponent: {1183      if (enableScopeAPI) {1184        safelyDetachRef(current, nearestMountedAncestor);1185      }1186      return;1187    }1188  }1189}1190function commitNestedUnmounts(1191  finishedRoot: FiberRoot,1192  root: Fiber,1193  nearestMountedAncestor: Fiber,1194): void {1195  // While we're inside a removed host node we don't want to call1196  // removeChild on the inner nodes because they're removed by the top1197  // call anyway. We also want to call componentWillUnmount on all1198  // composites before this host node is removed from the tree. Therefore1199  // we do an inner loop while we're still inside the host node.1200  let node: Fiber = root;1201  while (true) {1202    commitUnmount(finishedRoot, node, nearestMountedAncestor);1203    // Visit children because they may contain more composite or host nodes.1204    // Skip portals because commitUnmount() currently visits them recursively.1205    if (1206      node.child !== null &&1207      // If we use mutation we drill down into portals using commitUnmount above.1208      // If we don't use mutation we drill down into portals here instead.1209      (!supportsMutation || node.tag !== HostPortal)1210    ) {1211      node.child.return = node;1212      node = node.child;1213      continue;1214    }1215    if (node === root) {1216      return;1217    }1218    while (node.sibling === null) {1219      if (node.return === null || node.return === root) {1220        return;1221      }1222      node = node.return;1223    }1224    node.sibling.return = node.return;1225    node = node.sibling;1226  }1227}1228function detachFiberMutation(fiber: Fiber) {1229  // Cut off the return pointer to disconnect it from the tree.1230  // This enables us to detect and warn against state updates on an unmounted component.1231  // It also prevents events from bubbling from within disconnected components.1232  //1233  // Ideally, we should also clear the child pointer of the parent alternate to let this1234  // get GC:ed but we don't know which for sure which parent is the current1235  // one so we'll settle for GC:ing the subtree of this child.1236  // This child itself will be GC:ed when the parent updates the next time.1237  //1238  // Note that we can't clear child or sibling pointers yet.1239  // They're needed for passive effects and for findDOMNode.1240  // We defer those fields, and all other cleanup, to the passive phase (see detachFiberAfterEffects).1241  //1242  // Don't reset the alternate yet, either. We need that so we can detach the1243  // alternate's fields in the passive phase. Clearing the return pointer is1244  // sufficient for findDOMNode semantics.1245  const alternate = fiber.alternate;1246  if (alternate !== null) {1247    alternate.return = null;1248  }1249  fiber.return = null;1250}1251function detachFiberAfterEffects(fiber: Fiber) {1252  const alternate = fiber.alternate;1253  if (alternate !== null) {1254    fiber.alternate = null;1255    detachFiberAfterEffects(alternate);1256  }1257  // Note: Defensively using negation instead of < in case1258  // `deletedTreeCleanUpLevel` is undefined.1259  if (!(deletedTreeCleanUpLevel >= 2)) {1260    // This is the default branch (level 0).1261    fiber.child = null;1262    fiber.deletions = null;1263    fiber.dependencies = null;1264    fiber.memoizedProps = null;1265    fiber.memoizedState = null;1266    fiber.pendingProps = null;1267    fiber.sibling = null;1268    fiber.stateNode = null;1269    fiber.updateQueue = null;1270    if (__DEV__) {1271      fiber._debugOwner = null;1272    }1273  } else {1274    // Clear cyclical Fiber fields. This level alone is designed to roughly1275    // approximate the planned Fiber refactor. In that world, `setState` will be1276    // bound to a special "instance" object instead of a Fiber. The Instance1277    // object will not have any of these fields. It will only be connected to1278    // the fiber tree via a single link at the root. So if this level alone is1279    // sufficient to fix memory issues, that bodes well for our plans.1280    fiber.child = null;1281    fiber.deletions = null;1282    fiber.sibling = null;1283    // The `stateNode` is cyclical because on host nodes it points to the host1284    // tree, which has its own pointers to children, parents, and siblings.1285    // The other host nodes also point back to fibers, so we should detach that1286    // one, too.1287    if (fiber.tag === HostComponent) {1288      const hostInstance: Instance = fiber.stateNode;1289      if (hostInstance !== null) {1290        detachDeletedInstance(hostInstance);1291      }1292    }1293    fiber.stateNode = null;1294    // I'm intentionally not clearing the `return` field in this level. We1295    // already disconnect the `return` pointer at the root of the deleted1296    // subtree (in `detachFiberMutation`). Besides, `return` by itself is not1297    // cyclical â it's only cyclical when combined with `child`, `sibling`, and1298    // `alternate`. But we'll clear it in the next level anyway, just in case.1299    if (__DEV__) {1300      fiber._debugOwner = null;1301    }1302    if (deletedTreeCleanUpLevel >= 3) {1303      // Theoretically, nothing in here should be necessary, because we already1304      // disconnected the fiber from the tree. So even if something leaks this1305      // particular fiber, it won't leak anything else1306      //1307      // The purpose of this branch is to be super aggressive so we can measure1308      // if there's any difference in memory impact. If there is, that could1309      // indicate a React leak we don't know about.1310      fiber.return = null;1311      fiber.dependencies = null;1312      fiber.memoizedProps = null;1313      fiber.memoizedState = null;1314      fiber.pendingProps = null;1315      fiber.stateNode = null;1316      // TODO: Move to `commitPassiveUnmountInsideDeletedTreeOnFiber` instead.1317      fiber.updateQueue = null;1318    }1319  }1320}1321function emptyPortalContainer(current: Fiber) {1322  if (!supportsPersistence) {1323    return;1324  }1325  const portal: {1326    containerInfo: Container,1327    pendingChildren: ChildSet,1328    ...1329  } = current.stateNode;1330  const {containerInfo} = portal;1331  const emptyChildSet = createContainerChildSet(containerInfo);1332  replaceContainerChildren(containerInfo, emptyChildSet);1333}1334function commitContainer(finishedWork: Fiber) {1335  if (!supportsPersistence) {1336    return;1337  }1338  switch (finishedWork.tag) {1339    case ClassComponent:1340    case HostComponent:1341    case HostText: {1342      return;1343    }1344    case HostRoot:1345    case HostPortal: {1346      const portalOrRoot: {1347        containerInfo: Container,1348        pendingChildren: ChildSet,1349        ...1350      } = finishedWork.stateNode;1351      const {containerInfo, pendingChildren} = portalOrRoot;1352      replaceContainerChildren(containerInfo, pendingChildren);1353      return;1354    }1355  }1356  invariant(1357    false,1358    'This unit of work tag should not have side-effects. This error is ' +1359      'likely caused by a bug in React. Please file an issue.',1360  );1361}1362function getHostParentFiber(fiber: Fiber): Fiber {1363  let parent = fiber.return;1364  while (parent !== null) {1365    if (isHostParent(parent)) {1366      return parent;1367    }1368    parent = parent.return;1369  }1370  invariant(1371    false,1372    'Expected to find a host parent. This error is likely caused by a bug ' +1373      'in React. Please file an issue.',1374  );1375}1376function isHostParent(fiber: Fiber): boolean {1377  return (1378    fiber.tag === HostComponent ||1379    fiber.tag === HostRoot ||1380    fiber.tag === HostPortal1381  );1382}1383function getHostSibling(fiber: Fiber): ?Instance {1384  // We're going to search forward into the tree until we find a sibling host1385  // node. Unfortunately, if multiple insertions are done in a row we have to1386  // search past them. This leads to exponential search for the next sibling.1387  // TODO: Find a more efficient way to do this.1388  let node: Fiber = fiber;1389  siblings: while (true) {1390    // If we didn't find anything, let's try the next sibling.1391    while (node.sibling === null) {1392      if (node.return === null || isHostParent(node.return)) {1393        // If we pop out of the root or hit the parent the fiber we are the1394        // last sibling.1395        return null;1396      }1397      node = node.return;1398    }1399    node.sibling.return = node.return;1400    node = node.sibling;1401    while (1402      node.tag !== HostComponent &&1403      node.tag !== HostText &&1404      node.tag !== DehydratedFragment1405    ) {1406      // If it is not host node and, we might have a host node inside it.1407      // Try to search down until we find one.1408      if (node.flags & Placement) {1409        // If we don't have a child, try the siblings instead.1410        continue siblings;1411      }1412      // If we don't have a child, try the siblings instead.1413      // We also skip portals because they are not part of this host tree.1414      if (node.child === null || node.tag === HostPortal) {1415        continue siblings;1416      } else {1417        node.child.return = node;1418        node = node.child;1419      }1420    }1421    // Check if this host node is stable or about to be placed.1422    if (!(node.flags & Placement)) {1423      // Found it!1424      return node.stateNode;1425    }1426  }1427}1428function commitPlacement(finishedWork: Fiber): void {1429  if (!supportsMutation) {1430    return;1431  }1432  // Recursively insert all host nodes into the parent.1433  const parentFiber = getHostParentFiber(finishedWork);1434  // Note: these two variables *must* always be updated together.1435  let parent;1436  let isContainer;1437  const parentStateNode = parentFiber.stateNode;1438  switch (parentFiber.tag) {1439    case HostComponent:1440      parent = parentStateNode;1441      isContainer = false;1442      break;1443    case HostRoot:1444      parent = parentStateNode.containerInfo;1445      isContainer = true;1446      break;1447    case HostPortal:1448      parent = parentStateNode.containerInfo;1449      isContainer = true;1450      break;1451    // eslint-disable-next-line-no-fallthrough1452    default:1453      invariant(1454        false,1455        'Invalid host parent fiber. This error is likely caused by a bug ' +1456          'in React. Please file an issue.',1457      );1458  }1459  if (parentFiber.flags & ContentReset) {1460    // Reset the text content of the parent before doing any insertions1461    resetTextContent(parent);1462    // Clear ContentReset from the effect tag1463    parentFiber.flags &= ~ContentReset;1464  }1465  const before = getHostSibling(finishedWork);1466  // We only have the top Fiber that was inserted but we need to recurse down its1467  // children to find all the terminal nodes.1468  if (isContainer) {1469    insertOrAppendPlacementNodeIntoContainer(finishedWork, before, parent);1470  } else {1471    insertOrAppendPlacementNode(finishedWork, before, parent);1472  }1473}1474function insertOrAppendPlacementNodeIntoContainer(1475  node: Fiber,1476  before: ?Instance,1477  parent: Container,1478): void {1479  const {tag} = node;1480  const isHost = tag === HostComponent || tag === HostText;1481  if (isHost) {1482    const stateNode = node.stateNode;1483    if (before) {1484      insertInContainerBefore(parent, stateNode, before);1485    } else {1486      appendChildToContainer(parent, stateNode);1487    }1488  } else if (tag === HostPortal) {1489    // If the insertion itself is a portal, then we don't want to traverse1490    // down its children. Instead, we'll get insertions from each child in1491    // the portal directly.1492  } else {1493    const child = node.child;1494    if (child !== null) {1495      insertOrAppendPlacementNodeIntoContainer(child, before, parent);1496      let sibling = child.sibling;1497      while (sibling !== null) {1498        insertOrAppendPlacementNodeIntoContainer(sibling, before, parent);1499        sibling = sibling.sibling;1500      }1501    }1502  }1503}1504function insertOrAppendPlacementNode(1505  node: Fiber,1506  before: ?Instance,1507  parent: Instance,1508): void {1509  const {tag} = node;1510  const isHost = tag === HostComponent || tag === HostText;1511  if (isHost) {1512    const stateNode = node.stateNode;1513    if (before) {1514      insertBefore(parent, stateNode, before);1515    } else {1516      appendChild(parent, stateNode);1517    }1518  } else if (tag === HostPortal) {1519    // If the insertion itself is a portal, then we don't want to traverse1520    // down its children. Instead, we'll get insertions from each child in1521    // the portal directly.1522  } else {1523    const child = node.child;1524    if (child !== null) {1525      insertOrAppendPlacementNode(child, before, parent);1526      let sibling = child.sibling;1527      while (sibling !== null) {1528        insertOrAppendPlacementNode(sibling, before, parent);1529        sibling = sibling.sibling;1530      }1531    }1532  }1533}1534function unmountHostComponents(1535  finishedRoot: FiberRoot,1536  current: Fiber,1537  nearestMountedAncestor: Fiber,1538): void {1539  // We only have the top Fiber that was deleted but we need to recurse down its1540  // children to find all the terminal nodes.1541  let node: Fiber = current;1542  // Each iteration, currentParent is populated with node's host parent if not1543  // currentParentIsValid.1544  let currentParentIsValid = false;1545  // Note: these two variables *must* always be updated together.1546  let currentParent;1547  let currentParentIsContainer;1548  while (true) {1549    if (!currentParentIsValid) {1550      let parent = node.return;1551      findParent: while (true) {1552        invariant(1553          parent !== null,1554          'Expected to find a host parent. This error is likely caused by ' +1555            'a bug in React. Please file an issue.',1556        );1557        const parentStateNode = parent.stateNode;1558        switch (parent.tag) {1559          case HostComponent:1560            currentParent = parentStateNode;1561            currentParentIsContainer = false;1562            break findParent;1563          case HostRoot:1564            currentParent = parentStateNode.containerInfo;1565            currentParentIsContainer = true;1566            break findParent;1567          case HostPortal:1568            currentParent = parentStateNode.containerInfo;1569            currentParentIsContainer = true;1570            break findParent;1571        }1572        parent = parent.return;1573      }1574      currentParentIsValid = true;1575    }1576    if (node.tag === HostComponent || node.tag === HostText) {1577      commitNestedUnmounts(finishedRoot, node, nearestMountedAncestor);1578      // After all the children have unmounted, it is now safe to remove the1579      // node from the tree.1580      if (currentParentIsContainer) {1581        removeChildFromContainer(1582          ((currentParent: any): Container),1583          (node.stateNode: Instance | TextInstance),1584        );1585      } else {1586        removeChild(1587          ((currentParent: any): Instance),1588          (node.stateNode: Instance | TextInstance),1589        );1590      }1591      // Don't visit children because we already visited them.1592    } else if (1593      enableSuspenseServerRenderer &&1594      node.tag === DehydratedFragment1595    ) {1596      if (enableSuspenseCallback) {1597        const hydrationCallbacks = finishedRoot.hydrationCallbacks;1598        if (hydrationCallbacks !== null) {1599          const onDeleted = hydrationCallbacks.onDeleted;1600          if (onDeleted) {1601            onDeleted((node.stateNode: SuspenseInstance));1602          }1603        }1604      }1605      // Delete the dehydrated suspense boundary and all of its content.1606      if (currentParentIsContainer) {1607        clearSuspenseBoundaryFromContainer(1608          ((currentParent: any): Container),1609          (node.stateNode: SuspenseInstance),1610        );1611      } else {1612        clearSuspenseBoundary(1613          ((currentParent: any): Instance),1614          (node.stateNode: SuspenseInstance),1615        );1616      }1617    } else if (node.tag === HostPortal) {1618      if (node.child !== null) {1619        // When we go into a portal, it becomes the parent to remove from.1620        // We will reassign it back when we pop the portal on the way up.1621        currentParent = node.stateNode.containerInfo;1622        currentParentIsContainer = true;1623        // Visit children because portals might contain host components.1624        node.child.return = node;1625        node = node.child;1626        continue;1627      }1628    } else {1629      commitUnmount(finishedRoot, node, nearestMountedAncestor);1630      // Visit children because we may find more host components below.1631      if (node.child !== null) {1632        node.child.return = node;1633        node = node.child;1634        continue;1635      }1636    }1637    if (node === current) {1638      return;1639    }1640    while (node.sibling === null) {1641      if (node.return === null || node.return === current) {1642        return;1643      }1644      node = node.return;1645      if (node.tag === HostPortal) {1646        // When we go out of the portal, we need to restore the parent.1647        // Since we don't keep a stack of them, we will search for it.1648        currentParentIsValid = false;1649      }1650    }1651    node.sibling.return = node.return;1652    node = node.sibling;1653  }1654}1655function commitDeletion(1656  finishedRoot: FiberRoot,1657  current: Fiber,1658  nearestMountedAncestor: Fiber,1659): void {1660  if (supportsMutation) {1661    // Recursively delete all host nodes from the parent.1662    // Detach refs and call componentWillUnmount() on the whole subtree.1663    unmountHostComponents(finishedRoot, current, nearestMountedAncestor);1664  } else {1665    // Detach refs and call componentWillUnmount() on the whole subtree.1666    commitNestedUnmounts(finishedRoot, current, nearestMountedAncestor);1667  }1668  detachFiberMutation(current);1669}1670function commitWork(current: Fiber | null, finishedWork: Fiber): void {1671  if (!supportsMutation) {1672    switch (finishedWork.tag) {1673      case FunctionComponent:1674      case ForwardRef:1675      case MemoComponent:1676      case SimpleMemoComponent: {1677        commitHookEffectListUnmount(1678          HookInsertion | HookHasEffect,1679          finishedWork,1680          finishedWork.return,1681        );1682        commitHookEffectListMount(HookInsertion | HookHasEffect, finishedWork);1683        // Layout effects are destroyed during the mutation phase so that all1684        // destroy functions for all fibers are called before any create functions.1685        // This prevents sibling component effects from interfering with each other,1686        // e.g. a destroy function in one component should never override a ref set1687        // by a create function in another component during the same commit.1688        // TODO: Check if we're inside an Offscreen subtree that disappeared1689        // during this commit. If so, we would have already unmounted its1690        // layout hooks. (However, since we null out the `destroy` function1691        // right before calling it, the behavior is already correct, so this1692        // would mostly be for modeling purposes.)1693        if (1694          enableProfilerTimer &&1695          enableProfilerCommitHooks &&1696          finishedWork.mode & ProfileMode1697        ) {1698          try {1699            startLayoutEffectTimer();1700            commitHookEffectListUnmount(1701              HookLayout | HookHasEffect,1702              finishedWork,1703              finishedWork.return,1704            );1705          } finally {1706            recordLayoutEffectDuration(finishedWork);1707          }1708        } else {1709          commitHookEffectListUnmount(1710            HookLayout | HookHasEffect,1711            finishedWork,1712            finishedWork.return,1713          );1714        }1715        return;1716      }1717      case Profiler: {1718        return;1719      }1720      case SuspenseComponent: {1721        commitSuspenseCallback(finishedWork);1722        attachSuspenseRetryListeners(finishedWork);1723        return;1724      }1725      case SuspenseListComponent: {1726        attachSuspenseRetryListeners(finishedWork);1727        return;1728      }1729      case HostRoot: {1730        if (supportsHydration) {1731          const root: FiberRoot = finishedWork.stateNode;1732          if (root.isDehydrated) {1733            // We've just hydrated. No need to hydrate again.1734            root.isDehydrated = false;1735            commitHydratedContainer(root.containerInfo);1736          }1737        }1738        break;1739      }1740      case OffscreenComponent:1741      case LegacyHiddenComponent: {1742        return;1743      }1744    }1745    commitContainer(finishedWork);1746    return;1747  }1748  switch (finishedWork.tag) {1749    case FunctionComponent:1750    case ForwardRef:1751    case MemoComponent:1752    case SimpleMemoComponent: {1753      commitHookEffectListUnmount(1754        HookInsertion | HookHasEffect,1755        finishedWork,1756        finishedWork.return,1757      );1758      commitHookEffectListMount(HookInsertion | HookHasEffect, finishedWork);1759      // Layout effects are destroyed during the mutation phase so that all1760      // destroy functions for all fibers are called before any create functions.1761      // This prevents sibling component effects from interfering with each other,1762      // e.g. a destroy function in one component should never override a ref set1763      // by a create function in another component during the same commit.1764      if (1765        enableProfilerTimer &&1766        enableProfilerCommitHooks &&1767        finishedWork.mode & ProfileMode1768      ) {1769        try {1770          startLayoutEffectTimer();1771          commitHookEffectListUnmount(1772            HookLayout | HookHasEffect,1773            finishedWork,1774            finishedWork.return,1775          );1776        } finally {1777          recordLayoutEffectDuration(finishedWork);1778        }1779      } else {1780        commitHookEffectListUnmount(1781          HookLayout | HookHasEffect,1782          finishedWork,1783          finishedWork.return,1784        );1785      }1786      return;1787    }1788    case ClassComponent: {1789      return;1790    }1791    case HostComponent: {1792      const instance: Instance = finishedWork.stateNode;1793      if (instance != null) {1794        // Commit the work prepared earlier.1795        const newProps = finishedWork.memoizedProps;1796        // For hydration we reuse the update path but we treat the oldProps1797        // as the newProps. The updatePayload will contain the real change in1798        // this case.1799        const oldProps = current !== null ? current.memoizedProps : newProps;1800        const type = finishedWork.type;1801        // TODO: Type the updateQueue to be specific to host components.1802        const updatePayload: null | UpdatePayload = (finishedWork.updateQueue: any);1803        finishedWork.updateQueue = null;1804        if (updatePayload !== null) {1805          commitUpdate(1806            instance,1807            updatePayload,1808            type,1809            oldProps,1810            newProps,1811            finishedWork,1812          );1813        }1814      }1815      return;1816    }1817    case HostText: {1818      invariant(1819        finishedWork.stateNode !== null,1820        'This should have a text node initialized. This error is likely ' +1821          'caused by a bug in React. Please file an issue.',1822      );1823      const textInstance: TextInstance = finishedWork.stateNode;1824      const newText: string = finishedWork.memoizedProps;1825      // For hydration we reuse the update path but we treat the oldProps1826      // as the newProps. The updatePayload will contain the real change in1827      // this case.1828      const oldText: string =1829        current !== null ? current.memoizedProps : newText;1830      commitTextUpdate(textInstance, oldText, newText);1831      return;1832    }1833    case HostRoot: {1834      if (supportsHydration) {1835        const root: FiberRoot = finishedWork.stateNode;1836        if (root.isDehydrated) {1837          // We've just hydrated. No need to hydrate again.1838          root.isDehydrated = false;1839          commitHydratedContainer(root.containerInfo);1840        }1841      }1842      return;1843    }1844    case Profiler: {1845      return;1846    }1847    case SuspenseComponent: {1848      commitSuspenseCallback(finishedWork);1849      attachSuspenseRetryListeners(finishedWork);1850      return;1851    }1852    case SuspenseListComponent: {1853      attachSuspenseRetryListeners(finishedWork);1854      return;1855    }1856    case IncompleteClassComponent: {1857      return;1858    }1859    case ScopeComponent: {1860      if (enableScopeAPI) {1861        const scopeInstance = finishedWork.stateNode;1862        prepareScopeUpdate(scopeInstance, finishedWork);1863        return;1864      }1865      break;1866    }1867  }1868  invariant(1869    false,1870    'This unit of work tag should not have side-effects. This error is ' +1871      'likely caused by a bug in React. Please file an issue.',1872  );1873}1874function commitSuspenseCallback(finishedWork: Fiber) {1875  // TODO: Move this to passive phase1876  const newState: SuspenseState | null = finishedWork.memoizedState;1877  if (enableSuspenseCallback && newState !== null) {1878    const suspenseCallback = finishedWork.memoizedProps.suspenseCallback;1879    if (typeof suspenseCallback === 'function') {1880      const wakeables: Set<Wakeable> | null = (finishedWork.updateQueue: any);1881      if (wakeables !== null) {1882        suspenseCallback(new Set(wakeables));1883      }1884    } else if (__DEV__) {1885      if (suspenseCallback !== undefined) {1886        console.error('Unexpected type for suspenseCallback.');1887      }1888    }1889  }1890}1891function commitSuspenseHydrationCallbacks(1892  finishedRoot: FiberRoot,1893  finishedWork: Fiber,1894) {1895  if (!supportsHydration) {1896    return;1897  }1898  const newState: SuspenseState | null = finishedWork.memoizedState;1899  if (newState === null) {1900    const current = finishedWork.alternate;1901    if (current !== null) {1902      const prevState: SuspenseState | null = current.memoizedState;1903      if (prevState !== null) {1904        const suspenseInstance = prevState.dehydrated;1905        if (suspenseInstance !== null) {1906          commitHydratedSuspenseInstance(suspenseInstance);1907          if (enableSuspenseCallback) {1908            const hydrationCallbacks = finishedRoot.hydrationCallbacks;1909            if (hydrationCallbacks !== null) {1910              const onHydrated = hydrationCallbacks.onHydrated;1911              if (onHydrated) {1912                onHydrated(suspenseInstance);1913              }1914            }1915          }1916        }1917      }1918    }1919  }1920}1921function attachSuspenseRetryListeners(finishedWork: Fiber) {1922  // If this boundary just timed out, then it will have a set of wakeables.1923  // For each wakeable, attach a listener so that when it resolves, React1924  // attempts to re-render the boundary in the primary (pre-timeout) state.1925  const wakeables: Set<Wakeable> | null = (finishedWork.updateQueue: any);1926  if (wakeables !== null) {1927    finishedWork.updateQueue = null;1928    let retryCache = finishedWork.stateNode;1929    if (retryCache === null) {1930      retryCache = finishedWork.stateNode = new PossiblyWeakSet();1931    }1932    wakeables.forEach(wakeable => {1933      // Memoize using the boundary fiber to prevent redundant listeners.1934      const retry = resolveRetryWakeable.bind(null, finishedWork, wakeable);1935      if (!retryCache.has(wakeable)) {1936        retryCache.add(wakeable);1937        if (enableUpdaterTracking) {1938          if (isDevToolsPresent) {1939            if (inProgressLanes !== null && inProgressRoot !== null) {1940              // If we have pending work still, associate the original updaters with it.1941              restorePendingUpdaters(inProgressRoot, inProgressLanes);1942            } else {1943              throw Error(1944                'Expected finished root and lanes to be set. This is a bug in React.',1945              );1946            }1947          }1948        }1949        wakeable.then(retry, retry);1950      }1951    });1952  }1953}1954// This function detects when a Suspense boundary goes from visible to hidden.1955// It returns false if the boundary is already hidden.1956// TODO: Use an effect tag.1957export function isSuspenseBoundaryBeingHidden(1958  current: Fiber | null,1959  finishedWork: Fiber,1960): boolean {1961  if (current !== null) {1962    const oldState: SuspenseState | null = current.memoizedState;1963    if (oldState === null || oldState.dehydrated !== null) {1964      const newState: SuspenseState | null = finishedWork.memoizedState;1965      return newState !== null && newState.dehydrated === null;1966    }1967  }1968  return false;1969}1970function commitResetTextContent(current: Fiber) {1971  if (!supportsMutation) {1972    return;1973  }1974  resetTextContent(current.stateNode);1975}1976export function commitMutationEffects(1977  root: FiberRoot,1978  firstChild: Fiber,1979  committedLanes: Lanes,1980) {1981  inProgressLanes = committedLanes;1982  inProgressRoot = root;1983  nextEffect = firstChild;1984  commitMutationEffects_begin(root);1985  inProgressLanes = null;1986  inProgressRoot = null;1987}1988function commitMutationEffects_begin(root: FiberRoot) {1989  while (nextEffect !== null) {1990    const fiber = nextEffect;1991    // TODO: Should wrap this in flags check, too, as optimization1992    const deletions = fiber.deletions;1993    if (deletions !== null) {1994      for (let i = 0; i < deletions.length; i++) {1995        const childToDelete = deletions[i];1996        try {1997          commitDeletion(root, childToDelete, fiber);1998        } catch (error) {1999          reportUncaughtErrorInDEV(error);2000          captureCommitPhaseError(childToDelete, fiber, error);2001        }2002      }2003    }2004    const child = fiber.child;2005    if ((fiber.subtreeFlags & MutationMask) !== NoFlags && child !== null) {2006      ensureCorrectReturnPointer(child, fiber);2007      nextEffect = child;2008    } else {2009      commitMutationEffects_complete(root);2010    }2011  }2012}2013function commitMutationEffects_complete(root: FiberRoot) {2014  while (nextEffect !== null) {2015    const fiber = nextEffect;2016    setCurrentDebugFiberInDEV(fiber);2017    try {2018      commitMutationEffectsOnFiber(fiber, root);2019    } catch (error) {2020      reportUncaughtErrorInDEV(error);2021      captureCommitPhaseError(fiber, fiber.return, error);2022    }2023    resetCurrentDebugFiberInDEV();2024    const sibling = fiber.sibling;2025    if (sibling !== null) {2026      ensureCorrectReturnPointer(sibling, fiber.return);2027      nextEffect = sibling;2028      return;2029    }2030    nextEffect = fiber.return;2031  }2032}2033function commitMutationEffectsOnFiber(finishedWork: Fiber, root: FiberRoot) {2034  // TODO: The factoring of this phase could probably be improved. Consider2035  // switching on the type of work before checking the flags. That's what2036  // we do in all the other phases. I think this one is only different2037  // because of the shared reconciliation logic below.2038  const flags = finishedWork.flags;2039  if (flags & ContentReset) {2040    commitResetTextContent(finishedWork);2041  }2042  if (flags & Ref) {2043    const current = finishedWork.alternate;2044    if (current !== null) {2045      commitDetachRef(current);2046    }2047    if (enableScopeAPI) {2048      // TODO: This is a temporary solution that allowed us to transition away2049      // from React Flare on www.2050      if (finishedWork.tag === ScopeComponent) {2051        commitAttachRef(finishedWork);2052      }2053    }2054  }2055  if (flags & Visibility) {2056    switch (finishedWork.tag) {2057      case SuspenseComponent: {2058        const newState: OffscreenState | null = finishedWork.memoizedState;2059        const isHidden = newState !== null;2060        if (isHidden) {2061          const current = finishedWork.alternate;2062          const wasHidden = current !== null && current.memoizedState !== null;2063          if (!wasHidden) {2064            // TODO: Move to passive phase2065            markCommitTimeOfFallback();2066          }2067        }2068        break;2069      }2070      case OffscreenComponent: {2071        const newState: OffscreenState | null = finishedWork.memoizedState;2072        const isHidden = newState !== null;2073        const current = finishedWork.alternate;2074        const wasHidden = current !== null && current.memoizedState !== null;2075        const offscreenBoundary: Fiber = finishedWork;2076        if (supportsMutation) {2077          // TODO: This needs to run whenever there's an insertion or update2078          // inside a hidden Offscreen tree.2079          hideOrUnhideAllChildren(offscreenBoundary, isHidden);2080        }2081        if (enableSuspenseLayoutEffectSemantics) {2082          if (isHidden) {2083            if (!wasHidden) {2084              if ((offscreenBoundary.mode & ConcurrentMode) !== NoMode) {2085                nextEffect = offscreenBoundary;2086                let offscreenChild = offscreenBoundary.child;2087                while (offscreenChild !== null) {2088                  nextEffect = offscreenChild;2089                  disappearLayoutEffects_begin(offscreenChild);2090                  offscreenChild = offscreenChild.sibling;2091                }2092              }2093            }2094          } else {2095            if (wasHidden) {2096              // TODO: Move re-appear call here for symmetry?2097            }2098          }2099          break;2100        }2101      }2102    }2103  }2104  // The following switch statement is only concerned about placement,2105  // updates, and deletions. To avoid needing to add a case for every possible2106  // bitmap value, we remove the secondary effects from the effect tag and2107  // switch on that value.2108  const primaryFlags = flags & (Placement | Update | Hydrating);2109  outer: switch (primaryFlags) {2110    case Placement: {2111      commitPlacement(finishedWork);2112      // Clear the "placement" from effect tag so that we know that this is2113      // inserted, before any life-cycles like componentDidMount gets called.2114      // TODO: findDOMNode doesn't rely on this any more but isMounted does2115      // and isMounted is deprecated anyway so we should be able to kill this.2116      finishedWork.flags &= ~Placement;2117      break;2118    }2119    case PlacementAndUpdate: {2120      // Placement2121      commitPlacement(finishedWork);2122      // Clear the "placement" from effect tag so that we know that this is2123      // inserted, before any life-cycles like componentDidMount gets called.2124      finishedWork.flags &= ~Placement;2125      // Update2126      const current = finishedWork.alternate;2127      commitWork(current, finishedWork);2128      break;2129    }2130    case Hydrating: {2131      finishedWork.flags &= ~Hydrating;2132      break;2133    }2134    case HydratingAndUpdate: {2135      finishedWork.flags &= ~Hydrating;2136      // Update2137      const current = finishedWork.alternate;2138      commitWork(current, finishedWork);2139      break;2140    }2141    case Update: {2142      const current = finishedWork.alternate;2143      commitWork(current, finishedWork);2144      break;2145    }2146  }2147}2148export function commitLayoutEffects(2149  finishedWork: Fiber,2150  root: FiberRoot,2151  committedLanes: Lanes,2152): void {2153  inProgressLanes = committedLanes;2154  inProgressRoot = root;2155  nextEffect = finishedWork;2156  commitLayoutEffects_begin(finishedWork, root, committedLanes);2157  inProgressLanes = null;2158  inProgressRoot = null;2159}2160function commitLayoutEffects_begin(2161  subtreeRoot: Fiber,2162  root: FiberRoot,2163  committedLanes: Lanes,2164) {2165  // Suspense layout effects semantics don't change for legacy roots.2166  const isModernRoot = (subtreeRoot.mode & ConcurrentMode) !== NoMode;2167  while (nextEffect !== null) {2168    const fiber = nextEffect;2169    const firstChild = fiber.child;2170    if (2171      enableSuspenseLayoutEffectSemantics &&2172      fiber.tag === OffscreenComponent &&2173      isModernRoot2174    ) {2175      // Keep track of the current Offscreen stack's state.2176      const isHidden = fiber.memoizedState !== null;2177      const newOffscreenSubtreeIsHidden = isHidden || offscreenSubtreeIsHidden;2178      if (newOffscreenSubtreeIsHidden) {2179        // The Offscreen tree is hidden. Skip over its layout effects.2180        commitLayoutMountEffects_complete(subtreeRoot, root, committedLanes);2181        continue;2182      } else {2183        // TODO (Offscreen) Also check: subtreeFlags & LayoutMask2184        const current = fiber.alternate;2185        const wasHidden = current !== null && current.memoizedState !== null;2186        const newOffscreenSubtreeWasHidden =2187          wasHidden || offscreenSubtreeWasHidden;2188        const prevOffscreenSubtreeIsHidden = offscreenSubtreeIsHidden;2189        const prevOffscreenSubtreeWasHidden = offscreenSubtreeWasHidden;2190        // Traverse the Offscreen subtree with the current Offscreen as the root.2191        offscreenSubtreeIsHidden = newOffscreenSubtreeIsHidden;2192        offscreenSubtreeWasHidden = newOffscreenSubtreeWasHidden;2193        if (offscreenSubtreeWasHidden && !prevOffscreenSubtreeWasHidden) {2194          // This is the root of a reappearing boundary. Turn its layout effects2195          // back on.2196          nextEffect = fiber;2197          reappearLayoutEffects_begin(fiber);2198        }2199        let child = firstChild;2200        while (child !== null) {2201          nextEffect = child;2202          commitLayoutEffects_begin(2203            child, // New root; bubble back up to here and stop.2204            root,2205            committedLanes,2206          );2207          child = child.sibling;2208        }2209        // Restore Offscreen state and resume in our-progress traversal.2210        nextEffect = fiber;2211        offscreenSubtreeIsHidden = prevOffscreenSubtreeIsHidden;2212        offscreenSubtreeWasHidden = prevOffscreenSubtreeWasHidden;2213        commitLayoutMountEffects_complete(subtreeRoot, root, committedLanes);2214        continue;2215      }2216    }2217    if ((fiber.subtreeFlags & LayoutMask) !== NoFlags && firstChild !== null) {2218      ensureCorrectReturnPointer(firstChild, fiber);2219      nextEffect = firstChild;2220    } else {2221      commitLayoutMountEffects_complete(subtreeRoot, root, committedLanes);2222    }2223  }2224}2225function commitLayoutMountEffects_complete(2226  subtreeRoot: Fiber,2227  root: FiberRoot,2228  committedLanes: Lanes,2229) {2230  while (nextEffect !== null) {2231    const fiber = nextEffect;2232    if ((fiber.flags & LayoutMask) !== NoFlags) {2233      const current = fiber.alternate;2234      setCurrentDebugFiberInDEV(fiber);2235      try {2236        commitLayoutEffectOnFiber(root, current, fiber, committedLanes);2237      } catch (error) {2238        reportUncaughtErrorInDEV(error);2239        captureCommitPhaseError(fiber, fiber.return, error);2240      }2241      resetCurrentDebugFiberInDEV();2242    }2243    if (fiber === subtreeRoot) {2244      nextEffect = null;2245      return;2246    }2247    const sibling = fiber.sibling;2248    if (sibling !== null) {2249      ensureCorrectReturnPointer(sibling, fiber.return);2250      nextEffect = sibling;2251      return;2252    }2253    nextEffect = fiber.return;2254  }2255}2256function disappearLayoutEffects_begin(subtreeRoot: Fiber) {2257  while (nextEffect !== null) {2258    const fiber = nextEffect;2259    const firstChild = fiber.child;2260    // TODO (Offscreen) Check: flags & (RefStatic | LayoutStatic)2261    switch (fiber.tag) {2262      case FunctionComponent:2263      case ForwardRef:2264      case MemoComponent:2265      case SimpleMemoComponent: {2266        if (2267          enableProfilerTimer &&2268          enableProfilerCommitHooks &&2269          fiber.mode & ProfileMode2270        ) {2271          try {2272            startLayoutEffectTimer();2273            commitHookEffectListUnmount(HookLayout, fiber, fiber.return);2274          } finally {2275            recordLayoutEffectDuration(fiber);2276          }2277        } else {2278          commitHookEffectListUnmount(HookLayout, fiber, fiber.return);2279        }2280        break;2281      }2282      case ClassComponent: {2283        // TODO (Offscreen) Check: flags & RefStatic2284        safelyDetachRef(fiber, fiber.return);2285        const instance = fiber.stateNode;2286        if (typeof instance.componentWillUnmount === 'function') {2287          safelyCallComponentWillUnmount(fiber, fiber.return, instance);2288        }2289        break;2290      }2291      case HostComponent: {2292        safelyDetachRef(fiber, fiber.return);2293        break;2294      }2295      case OffscreenComponent: {2296        // Check if this is a2297        const isHidden = fiber.memoizedState !== null;2298        if (isHidden) {2299          // Nested Offscreen tree is already hidden. Don't disappear2300          // its effects.2301          disappearLayoutEffects_complete(subtreeRoot);2302          continue;2303        }2304        break;2305      }2306    }2307    // TODO (Offscreen) Check: subtreeFlags & LayoutStatic2308    if (firstChild !== null) {2309      firstChild.return = fiber;2310      nextEffect = firstChild;2311    } else {2312      disappearLayoutEffects_complete(subtreeRoot);2313    }2314  }2315}2316function disappearLayoutEffects_complete(subtreeRoot: Fiber) {2317  while (nextEffect !== null) {2318    const fiber = nextEffect;2319    if (fiber === subtreeRoot) {2320      nextEffect = null;2321      return;2322    }2323    const sibling = fiber.sibling;2324    if (sibling !== null) {2325      sibling.return = fiber.return;2326      nextEffect = sibling;2327      return;2328    }2329    nextEffect = fiber.return;2330  }2331}2332function reappearLayoutEffects_begin(subtreeRoot: Fiber) {2333  while (nextEffect !== null) {2334    const fiber = nextEffect;2335    const firstChild = fiber.child;2336    if (fiber.tag === OffscreenComponent) {2337      const isHidden = fiber.memoizedState !== null;2338      if (isHidden) {2339        // Nested Offscreen tree is still hidden. Don't re-appear its effects.2340        reappearLayoutEffects_complete(subtreeRoot);2341        continue;2342      }2343    }2344    // TODO (Offscreen) Check: subtreeFlags & LayoutStatic2345    if (firstChild !== null) {2346      // This node may have been reused from a previous render, so we can't2347      // assume its return pointer is correct.2348      firstChild.return = fiber;2349      nextEffect = firstChild;2350    } else {2351      reappearLayoutEffects_complete(subtreeRoot);2352    }2353  }2354}2355function reappearLayoutEffects_complete(subtreeRoot: Fiber) {2356  while (nextEffect !== null) {2357    const fiber = nextEffect;2358    // TODO (Offscreen) Check: flags & LayoutStatic2359    setCurrentDebugFiberInDEV(fiber);2360    try {2361      reappearLayoutEffectsOnFiber(fiber);2362    } catch (error) {2363      reportUncaughtErrorInDEV(error);2364      captureCommitPhaseError(fiber, fiber.return, error);2365    }2366    resetCurrentDebugFiberInDEV();2367    if (fiber === subtreeRoot) {2368      nextEffect = null;2369      return;2370    }2371    const sibling = fiber.sibling;2372    if (sibling !== null) {2373      // This node may have been reused from a previous render, so we can't2374      // assume its return pointer is correct.2375      sibling.return = fiber.return;2376      nextEffect = sibling;2377      return;2378    }2379    nextEffect = fiber.return;2380  }2381}2382export function commitPassiveMountEffects(2383  root: FiberRoot,2384  finishedWork: Fiber,2385): void {2386  nextEffect = finishedWork;2387  commitPassiveMountEffects_begin(finishedWork, root);2388}2389function commitPassiveMountEffects_begin(subtreeRoot: Fiber, root: FiberRoot) {2390  while (nextEffect !== null) {2391    const fiber = nextEffect;2392    const firstChild = fiber.child;2393    if ((fiber.subtreeFlags & PassiveMask) !== NoFlags && firstChild !== null) {2394      ensureCorrectReturnPointer(firstChild, fiber);2395      nextEffect = firstChild;2396    } else {2397      commitPassiveMountEffects_complete(subtreeRoot, root);2398    }2399  }2400}2401function commitPassiveMountEffects_complete(2402  subtreeRoot: Fiber,2403  root: FiberRoot,2404) {2405  while (nextEffect !== null) {2406    const fiber = nextEffect;2407    if ((fiber.flags & Passive) !== NoFlags) {2408      setCurrentDebugFiberInDEV(fiber);2409      try {2410        commitPassiveMountOnFiber(root, fiber);2411      } catch (error) {2412        reportUncaughtErrorInDEV(error);2413        captureCommitPhaseError(fiber, fiber.return, error);2414      }2415      resetCurrentDebugFiberInDEV();2416    }2417    if (fiber === subtreeRoot) {2418      nextEffect = null;2419      return;2420    }2421    const sibling = fiber.sibling;2422    if (sibling !== null) {2423      ensureCorrectReturnPointer(sibling, fiber.return);2424      nextEffect = sibling;2425      return;2426    }2427    nextEffect = fiber.return;2428  }2429}2430function commitPassiveMountOnFiber(2431  finishedRoot: FiberRoot,2432  finishedWork: Fiber,2433): void {2434  switch (finishedWork.tag) {2435    case FunctionComponent:2436    case ForwardRef:2437    case SimpleMemoComponent: {2438      if (2439        enableProfilerTimer &&2440        enableProfilerCommitHooks &&2441        finishedWork.mode & ProfileMode2442      ) {2443        startPassiveEffectTimer();2444        try {2445          commitHookEffectListMount(HookPassive | HookHasEffect, finishedWork);2446        } finally {2447          recordPassiveEffectDuration(finishedWork);2448        }2449      } else {2450        commitHookEffectListMount(HookPassive | HookHasEffect, finishedWork);2451      }2452      break;2453    }2454  }2455}2456export function commitPassiveUnmountEffects(firstChild: Fiber): void {2457  nextEffect = firstChild;2458  commitPassiveUnmountEffects_begin();2459}2460function commitPassiveUnmountEffects_begin() {2461  while (nextEffect !== null) {2462    const fiber = nextEffect;2463    const child = fiber.child;2464    if ((nextEffect.flags & ChildDeletion) !== NoFlags) {2465      const deletions = fiber.deletions;2466      if (deletions !== null) {2467        for (let i = 0; i < deletions.length; i++) {2468          const fiberToDelete = deletions[i];2469          nextEffect = fiberToDelete;2470          commitPassiveUnmountEffectsInsideOfDeletedTree_begin(2471            fiberToDelete,2472            fiber,2473          );2474        }2475        if (deletedTreeCleanUpLevel >= 1) {2476          // A fiber was deleted from this parent fiber, but it's still part of2477          // the previous (alternate) parent fiber's list of children. Because2478          // children are a linked list, an earlier sibling that's still alive2479          // will be connected to the deleted fiber via its `alternate`:2480          //2481          //   live fiber2482          //   --alternate--> previous live fiber2483          //   --sibling--> deleted fiber2484          //2485          // We can't disconnect `alternate` on nodes that haven't been deleted2486          // yet, but we can disconnect the `sibling` and `child` pointers.2487          const previousFiber = fiber.alternate;2488          if (previousFiber !== null) {2489            let detachedChild = previousFiber.child;2490            if (detachedChild !== null) {2491              previousFiber.child = null;2492              do {2493                const detachedSibling = detachedChild.sibling;2494                detachedChild.sibling = null;2495                detachedChild = detachedSibling;2496              } while (detachedChild !== null);2497            }2498          }2499        }2500        nextEffect = fiber;2501      }2502    }2503    if ((fiber.subtreeFlags & PassiveMask) !== NoFlags && child !== null) {2504      ensureCorrectReturnPointer(child, fiber);2505      nextEffect = child;2506    } else {2507      commitPassiveUnmountEffects_complete();2508    }2509  }2510}2511function commitPassiveUnmountEffects_complete() {2512  while (nextEffect !== null) {2513    const fiber = nextEffect;2514    if ((fiber.flags & Passive) !== NoFlags) {2515      setCurrentDebugFiberInDEV(fiber);2516      commitPassiveUnmountOnFiber(fiber);2517      resetCurrentDebugFiberInDEV();2518    }2519    const sibling = fiber.sibling;2520    if (sibling !== null) {2521      ensureCorrectReturnPointer(sibling, fiber.return);2522      nextEffect = sibling;2523      return;2524    }2525    nextEffect = fiber.return;2526  }2527}2528function commitPassiveUnmountOnFiber(finishedWork: Fiber): void {2529  switch (finishedWork.tag) {2530    case FunctionComponent:2531    case ForwardRef:2532    case SimpleMemoComponent: {2533      if (2534        enableProfilerTimer &&2535        enableProfilerCommitHooks &&2536        finishedWork.mode & ProfileMode2537      ) {2538        startPassiveEffectTimer();2539        commitHookEffectListUnmount(2540          HookPassive | HookHasEffect,2541          finishedWork,2542          finishedWork.return,2543        );2544        recordPassiveEffectDuration(finishedWork);2545      } else {2546        commitHookEffectListUnmount(2547          HookPassive | HookHasEffect,2548          finishedWork,2549          finishedWork.return,2550        );2551      }2552      break;2553    }2554  }2555}2556function commitPassiveUnmountEffectsInsideOfDeletedTree_begin(2557  deletedSubtreeRoot: Fiber,2558  nearestMountedAncestor: Fiber | null,2559) {2560  while (nextEffect !== null) {2561    const fiber = nextEffect;2562    // Deletion effects fire in parent -> child order2563    // TODO: Check if fiber has a PassiveStatic flag2564    setCurrentDebugFiberInDEV(fiber);2565    commitPassiveUnmountInsideDeletedTreeOnFiber(fiber, nearestMountedAncestor);2566    resetCurrentDebugFiberInDEV();2567    const child = fiber.child;2568    // TODO: Only traverse subtree if it has a PassiveStatic flag. (But, if we2569    // do this, still need to handle `deletedTreeCleanUpLevel` correctly.)2570    if (child !== null) {2571      ensureCorrectReturnPointer(child, fiber);2572      nextEffect = child;2573    } else {2574      commitPassiveUnmountEffectsInsideOfDeletedTree_complete(2575        deletedSubtreeRoot,2576      );2577    }2578  }2579}2580function commitPassiveUnmountEffectsInsideOfDeletedTree_complete(2581  deletedSubtreeRoot: Fiber,2582) {2583  while (nextEffect !== null) {2584    const fiber = nextEffect;2585    const sibling = fiber.sibling;2586    const returnFiber = fiber.return;2587    if (deletedTreeCleanUpLevel >= 2) {2588      // Recursively traverse the entire deleted tree and clean up fiber fields.2589      // This is more aggressive than ideal, and the long term goal is to only2590      // have to detach the deleted tree at the root.2591      detachFiberAfterEffects(fiber);2592      if (fiber === deletedSubtreeRoot) {2593        nextEffect = null;2594        return;2595      }2596    } else {2597      // This is the default branch (level 0). We do not recursively clear all2598      // the fiber fields. Only the root of the deleted subtree.2599      if (fiber === deletedSubtreeRoot) {2600        detachFiberAfterEffects(fiber);2601        nextEffect = null;2602        return;2603      }2604    }2605    if (sibling !== null) {2606      ensureCorrectReturnPointer(sibling, returnFiber);2607      nextEffect = sibling;2608      return;2609    }2610    nextEffect = returnFiber;2611  }2612}2613function commitPassiveUnmountInsideDeletedTreeOnFiber(2614  current: Fiber,2615  nearestMountedAncestor: Fiber | null,2616): void {2617  switch (current.tag) {2618    case FunctionComponent:2619    case ForwardRef:2620    case SimpleMemoComponent: {2621      if (2622        enableProfilerTimer &&2623        enableProfilerCommitHooks &&2624        current.mode & ProfileMode2625      ) {2626        startPassiveEffectTimer();2627        commitHookEffectListUnmount(2628          HookPassive,2629          current,2630          nearestMountedAncestor,2631        );2632        recordPassiveEffectDuration(current);2633      } else {2634        commitHookEffectListUnmount(2635          HookPassive,2636          current,2637          nearestMountedAncestor,2638        );2639      }2640      break;2641    }2642  }2643}2644let didWarnWrongReturnPointer = false;2645function ensureCorrectReturnPointer(fiber, expectedReturnFiber) {2646  if (__DEV__) {2647    if (!didWarnWrongReturnPointer && fiber.return !== expectedReturnFiber) {2648      didWarnWrongReturnPointer = true;2649      console.error(2650        'Internal React error: Return pointer is inconsistent ' +2651          'with parent.',2652      );2653    }2654  }2655  // TODO: Remove this assignment once we're confident that it won't break2656  // anything, by checking the warning logs for the above invariant2657  fiber.return = expectedReturnFiber;2658}2659// TODO: Reuse reappearLayoutEffects traversal here?2660function invokeLayoutEffectMountInDEV(fiber: Fiber): void {2661  if (__DEV__ && enableStrictEffects) {2662    // We don't need to re-check StrictEffectsMode here.2663    // This function is only called if that check has already passed.2664    switch (fiber.tag) {2665      case FunctionComponent:2666      case ForwardRef:2667      case SimpleMemoComponent: {2668        try {2669          commitHookEffectListMount(HookLayout | HookHasEffect, fiber);2670        } catch (error) {2671          reportUncaughtErrorInDEV(error);2672          captureCommitPhaseError(fiber, fiber.return, error);2673        }2674        break;2675      }2676      case ClassComponent: {2677        const instance = fiber.stateNode;2678        try {2679          instance.componentDidMount();2680        } catch (error) {2681          reportUncaughtErrorInDEV(error);2682          captureCommitPhaseError(fiber, fiber.return, error);2683        }2684        break;2685      }2686    }2687  }2688}2689function invokePassiveEffectMountInDEV(fiber: Fiber): void {2690  if (__DEV__ && enableStrictEffects) {2691    // We don't need to re-check StrictEffectsMode here.2692    // This function is only called if that check has already passed.2693    switch (fiber.tag) {2694      case FunctionComponent:2695      case ForwardRef:2696      case SimpleMemoComponent: {2697        try {2698          commitHookEffectListMount(HookPassive | HookHasEffect, fiber);2699        } catch (error) {2700          reportUncaughtErrorInDEV(error);2701          captureCommitPhaseError(fiber, fiber.return, error);2702        }2703        break;2704      }2705    }2706  }2707}2708function invokeLayoutEffectUnmountInDEV(fiber: Fiber): void {2709  if (__DEV__ && enableStrictEffects) {2710    // We don't need to re-check StrictEffectsMode here.2711    // This function is only called if that check has already passed.2712    switch (fiber.tag) {...ReactFiberCommitWork.new.js
Source:ReactFiberCommitWork.new.js  
...337      effect = effect.next;338    } while (effect !== firstEffect);339  }340}341function commitHookEffectListMount(flags           , finishedWork       ) {342  const updateQueue                                      = (finishedWork.updateQueue     );343  const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;344  if (lastEffect !== null) {345    const firstEffect = lastEffect.next;346    let effect = firstEffect;347    do {348      if ((effect.tag & flags) === flags) {349        // Mount350        const create = effect.create;351        effect.destroy = create();352        if (__DEV__) {353          const destroy = effect.destroy;354          if (destroy !== undefined && typeof destroy !== 'function') {355            let addendum;356            if (destroy === null) {357              addendum =358                ' You returned null. If your effect does not require clean ' +359                'up, return undefined (or nothing).';360            } else if (typeof destroy.then === 'function') {361              addendum =362                '\n\nIt looks like you wrote useEffect(async () => ...) or returned a Promise. ' +363                'Instead, write the async function inside your effect ' +364                'and call it immediately:\n\n' +365                'useEffect(() => {\n' +366                '  async function fetchData() {\n' +367                '    // You can await here\n' +368                '    const response = await MyAPI.getData(someId);\n' +369                '    // ...\n' +370                '  }\n' +371                '  fetchData();\n' +372                `}, [someId]); // Or [] if effect doesn't need props or state\n\n` +373                'Learn more about data fetching with Hooks: https://reactjs.org/link/hooks-data-fetching';374            } else {375              addendum = ' You returned: ' + destroy;376            }377            console.error(378              'An effect function must not return anything besides a function, ' +379                'which is used for clean-up.%s',380              addendum,381            );382          }383        }384      }385      effect = effect.next;386    } while (effect !== firstEffect);387  }388}389function commitProfilerPassiveEffect(390  finishedRoot           ,391  finishedWork       ,392)       {393  if (enableProfilerTimer && enableProfilerCommitHooks) {394    switch (finishedWork.tag) {395      case Profiler: {396        const {passiveEffectDuration} = finishedWork.stateNode;397        const {id, onPostCommit} = finishedWork.memoizedProps;398        // This value will still reflect the previous commit phase.399        // It does not get reset until the start of the next commit phase.400        const commitTime = getCommitTime();401        if (typeof onPostCommit === 'function') {402          if (enableSchedulerTracing) {403            onPostCommit(404              id,405              finishedWork.alternate === null ? 'mount' : 'update',406              passiveEffectDuration,407              commitTime,408              finishedRoot.memoizedInteractions,409            );410          } else {411            onPostCommit(412              id,413              finishedWork.alternate === null ? 'mount' : 'update',414              passiveEffectDuration,415              commitTime,416            );417          }418        }419        break;420      }421      default:422        break;423    }424  }425}426function recursivelyCommitLayoutEffects(427  finishedWork       ,428  finishedRoot           ,429) {430  const {flags, tag} = finishedWork;431  switch (tag) {432    case Profiler: {433      let prevProfilerOnStack = null;434      if (enableProfilerTimer && enableProfilerCommitHooks) {435        prevProfilerOnStack = nearestProfilerOnStack;436        nearestProfilerOnStack = finishedWork;437      }438      let child = finishedWork.child;439      while (child !== null) {440        const primarySubtreeFlags = finishedWork.subtreeFlags & LayoutMask;441        if (primarySubtreeFlags !== NoFlags) {442          if (__DEV__) {443            const prevCurrentFiberInDEV = currentDebugFiberInDEV;444            setCurrentDebugFiberInDEV(child);445            invokeGuardedCallback(446              null,447              recursivelyCommitLayoutEffects,448              null,449              child,450              finishedRoot,451            );452            if (hasCaughtError()) {453              const error = clearCaughtError();454              captureCommitPhaseError(child, finishedWork, error);455            }456            if (prevCurrentFiberInDEV !== null) {457              setCurrentDebugFiberInDEV(prevCurrentFiberInDEV);458            } else {459              resetCurrentDebugFiberInDEV();460            }461          } else {462            try {463              recursivelyCommitLayoutEffects(child, finishedRoot);464            } catch (error) {465              captureCommitPhaseError(child, finishedWork, error);466            }467          }468        }469        child = child.sibling;470      }471      const primaryFlags = flags & (Update | Callback);472      if (primaryFlags !== NoFlags) {473        if (enableProfilerTimer) {474          if (__DEV__) {475            const prevCurrentFiberInDEV = currentDebugFiberInDEV;476            setCurrentDebugFiberInDEV(finishedWork);477            invokeGuardedCallback(478              null,479              commitLayoutEffectsForProfiler,480              null,481              finishedWork,482              finishedRoot,483            );484            if (hasCaughtError()) {485              const error = clearCaughtError();486              captureCommitPhaseError(finishedWork, finishedWork.return, error);487            }488            if (prevCurrentFiberInDEV !== null) {489              setCurrentDebugFiberInDEV(prevCurrentFiberInDEV);490            } else {491              resetCurrentDebugFiberInDEV();492            }493          } else {494            try {495              commitLayoutEffectsForProfiler(finishedWork, finishedRoot);496            } catch (error) {497              captureCommitPhaseError(finishedWork, finishedWork.return, error);498            }499          }500        }501      }502      if (enableProfilerTimer && enableProfilerCommitHooks) {503        // Propagate layout effect durations to the next nearest Profiler ancestor.504        // Do not reset these values until the next render so DevTools has a chance to read them first.505        if (prevProfilerOnStack !== null) {506          prevProfilerOnStack.stateNode.effectDuration +=507            finishedWork.stateNode.effectDuration;508        }509        nearestProfilerOnStack = prevProfilerOnStack;510      }511      break;512    }513    // case Offscreen: {514    //   TODO: Fast path to invoke all nested layout effects when Offscren goes from hidden to visible.515    //   break;516    // }517    default: {518      let child = finishedWork.child;519      while (child !== null) {520        const primarySubtreeFlags = finishedWork.subtreeFlags & LayoutMask;521        if (primarySubtreeFlags !== NoFlags) {522          if (__DEV__) {523            const prevCurrentFiberInDEV = currentDebugFiberInDEV;524            setCurrentDebugFiberInDEV(child);525            invokeGuardedCallback(526              null,527              recursivelyCommitLayoutEffects,528              null,529              child,530              finishedRoot,531            );532            if (hasCaughtError()) {533              const error = clearCaughtError();534              captureCommitPhaseError(child, finishedWork, error);535            }536            if (prevCurrentFiberInDEV !== null) {537              setCurrentDebugFiberInDEV(prevCurrentFiberInDEV);538            } else {539              resetCurrentDebugFiberInDEV();540            }541          } else {542            try {543              recursivelyCommitLayoutEffects(child, finishedRoot);544            } catch (error) {545              captureCommitPhaseError(child, finishedWork, error);546            }547          }548        }549        child = child.sibling;550      }551      const primaryFlags = flags & (Update | Callback);552      if (primaryFlags !== NoFlags) {553        switch (tag) {554          case FunctionComponent:555          case ForwardRef:556          case SimpleMemoComponent:557          case Block: {558            if (559              enableProfilerTimer &&560              enableProfilerCommitHooks &&561              finishedWork.mode & ProfileMode562            ) {563              try {564                startLayoutEffectTimer();565                commitHookEffectListMount(566                  HookLayout | HookHasEffect,567                  finishedWork,568                );569              } finally {570                recordLayoutEffectDuration(finishedWork);571              }572            } else {573              commitHookEffectListMount(574                HookLayout | HookHasEffect,575                finishedWork,576              );577            }578            if ((finishedWork.subtreeFlags & PassiveMask) !== NoFlags) {579              schedulePassiveEffectCallback();580            }581            break;582          }583          case ClassComponent: {584            // NOTE: Layout effect durations are measured within this function.585            commitLayoutEffectsForClassComponent(finishedWork);586            break;587          }588          case HostRoot: {589            commitLayoutEffectsForHostRoot(finishedWork);590            break;591          }592          case HostComponent: {593            commitLayoutEffectsForHostComponent(finishedWork);594            break;595          }596          case SuspenseComponent: {597            commitSuspenseHydrationCallbacks(finishedRoot, finishedWork);598            break;599          }600          case FundamentalComponent:601          case HostPortal:602          case HostText:603          case IncompleteClassComponent:604          case LegacyHiddenComponent:605          case OffscreenComponent:606          case ScopeComponent:607          case SuspenseListComponent: {608            // We have no life-cycles associated with these component types.609            break;610          }611          default: {612            invariant(613              false,614              'This unit of work tag should not have side-effects. This error is ' +615                'likely caused by a bug in React. Please file an issue.',616            );617          }618        }619      }620      if (enableScopeAPI) {621        // TODO: This is a temporary solution that allowed us to transition away from React Flare on www.622        if (flags & Ref && tag !== ScopeComponent) {623          commitAttachRef(finishedWork);624        }625      } else {626        if (flags & Ref) {627          commitAttachRef(finishedWork);628        }629      }630      break;631    }632  }633}634function commitLayoutEffectsForProfiler(635  finishedWork       ,636  finishedRoot           ,637) {638  if (enableProfilerTimer) {639    const flags = finishedWork.flags;640    const current = finishedWork.alternate;641    const {onCommit, onRender} = finishedWork.memoizedProps;642    const {effectDuration} = finishedWork.stateNode;643    const commitTime = getCommitTime();644    const OnRenderFlag = Update;645    const OnCommitFlag = Callback;646    if ((flags & OnRenderFlag) !== NoFlags && typeof onRender === 'function') {647      if (enableSchedulerTracing) {648        onRender(649          finishedWork.memoizedProps.id,650          current === null ? 'mount' : 'update',651          finishedWork.actualDuration,652          finishedWork.treeBaseDuration,653          finishedWork.actualStartTime,654          commitTime,655          finishedRoot.memoizedInteractions,656        );657      } else {658        onRender(659          finishedWork.memoizedProps.id,660          current === null ? 'mount' : 'update',661          finishedWork.actualDuration,662          finishedWork.treeBaseDuration,663          finishedWork.actualStartTime,664          commitTime,665        );666      }667    }668    if (enableProfilerCommitHooks) {669      if (670        (flags & OnCommitFlag) !== NoFlags &&671        typeof onCommit === 'function'672      ) {673        if (enableSchedulerTracing) {674          onCommit(675            finishedWork.memoizedProps.id,676            current === null ? 'mount' : 'update',677            effectDuration,678            commitTime,679            finishedRoot.memoizedInteractions,680          );681        } else {682          onCommit(683            finishedWork.memoizedProps.id,684            current === null ? 'mount' : 'update',685            effectDuration,686            commitTime,687          );688        }689      }690    }691  }692}693function commitLayoutEffectsForClassComponent(finishedWork       ) {694  const instance = finishedWork.stateNode;695  const current = finishedWork.alternate;696  if (finishedWork.flags & Update) {697    if (current === null) {698      // We could update instance props and state here,699      // but instead we rely on them being set during last render.700      // TODO: revisit this when we implement resuming.701      if (__DEV__) {702        if (703          finishedWork.type === finishedWork.elementType &&704          !didWarnAboutReassigningProps705        ) {706          if (instance.props !== finishedWork.memoizedProps) {707            console.error(708              'Expected %s props to match memoized props before ' +709                'componentDidMount. ' +710                'This might either be because of a bug in React, or because ' +711                'a component reassigns its own `this.props`. ' +712                'Please file an issue.',713              getComponentName(finishedWork.type) || 'instance',714            );715          }716          if (instance.state !== finishedWork.memoizedState) {717            console.error(718              'Expected %s state to match memoized state before ' +719                'componentDidMount. ' +720                'This might either be because of a bug in React, or because ' +721                'a component reassigns its own `this.state`. ' +722                'Please file an issue.',723              getComponentName(finishedWork.type) || 'instance',724            );725          }726        }727      }728      if (729        enableProfilerTimer &&730        enableProfilerCommitHooks &&731        finishedWork.mode & ProfileMode732      ) {733        try {734          startLayoutEffectTimer();735          instance.componentDidMount();736        } finally {737          recordLayoutEffectDuration(finishedWork);738        }739      } else {740        instance.componentDidMount();741      }742    } else {743      const prevProps =744        finishedWork.elementType === finishedWork.type745          ? current.memoizedProps746          : resolveDefaultProps(finishedWork.type, current.memoizedProps);747      const prevState = current.memoizedState;748      // We could update instance props and state here,749      // but instead we rely on them being set during last render.750      // TODO: revisit this when we implement resuming.751      if (__DEV__) {752        if (753          finishedWork.type === finishedWork.elementType &&754          !didWarnAboutReassigningProps755        ) {756          if (instance.props !== finishedWork.memoizedProps) {757            console.error(758              'Expected %s props to match memoized props before ' +759                'componentDidUpdate. ' +760                'This might either be because of a bug in React, or because ' +761                'a component reassigns its own `this.props`. ' +762                'Please file an issue.',763              getComponentName(finishedWork.type) || 'instance',764            );765          }766          if (instance.state !== finishedWork.memoizedState) {767            console.error(768              'Expected %s state to match memoized state before ' +769                'componentDidUpdate. ' +770                'This might either be because of a bug in React, or because ' +771                'a component reassigns its own `this.state`. ' +772                'Please file an issue.',773              getComponentName(finishedWork.type) || 'instance',774            );775          }776        }777      }778      if (779        enableProfilerTimer &&780        enableProfilerCommitHooks &&781        finishedWork.mode & ProfileMode782      ) {783        try {784          startLayoutEffectTimer();785          instance.componentDidUpdate(786            prevProps,787            prevState,788            instance.__reactInternalSnapshotBeforeUpdate,789          );790        } finally {791          recordLayoutEffectDuration(finishedWork);792        }793      } else {794        instance.componentDidUpdate(795          prevProps,796          prevState,797          instance.__reactInternalSnapshotBeforeUpdate,798        );799      }800    }801  }802  // TODO: I think this is now always non-null by the time it reaches the803  // commit phase. Consider removing the type check.804  const updateQueue                        = (finishedWork.updateQueue     );805  if (updateQueue !== null) {806    if (__DEV__) {807      if (808        finishedWork.type === finishedWork.elementType &&809        !didWarnAboutReassigningProps810      ) {811        if (instance.props !== finishedWork.memoizedProps) {812          console.error(813            'Expected %s props to match memoized props before ' +814              'processing the update queue. ' +815              'This might either be because of a bug in React, or because ' +816              'a component reassigns its own `this.props`. ' +817              'Please file an issue.',818            getComponentName(finishedWork.type) || 'instance',819          );820        }821        if (instance.state !== finishedWork.memoizedState) {822          console.error(823            'Expected %s state to match memoized state before ' +824              'processing the update queue. ' +825              'This might either be because of a bug in React, or because ' +826              'a component reassigns its own `this.state`. ' +827              'Please file an issue.',828            getComponentName(finishedWork.type) || 'instance',829          );830        }831      }832    }833    // We could update instance props and state here,834    // but instead we rely on them being set during last render.835    // TODO: revisit this when we implement resuming.836    commitUpdateQueue(finishedWork, updateQueue, instance);837  }838}839function commitLayoutEffectsForHostRoot(finishedWork       ) {840  // TODO: I think this is now always non-null by the time it reaches the841  // commit phase. Consider removing the type check.842  const updateQueue                        = (finishedWork.updateQueue     );843  if (updateQueue !== null) {844    let instance = null;845    if (finishedWork.child !== null) {846      switch (finishedWork.child.tag) {847        case HostComponent:848          instance = getPublicInstance(finishedWork.child.stateNode);849          break;850        case ClassComponent:851          instance = finishedWork.child.stateNode;852          break;853      }854    }855    commitUpdateQueue(finishedWork, updateQueue, instance);856  }857}858function commitLayoutEffectsForHostComponent(finishedWork       ) {859  const instance           = finishedWork.stateNode;860  const current = finishedWork.alternate;861  // Renderers may schedule work to be done after host components are mounted862  // (eg DOM renderer may schedule auto-focus for inputs and form controls).863  // These effects should only be committed when components are first mounted,864  // aka when there is no current/alternate.865  if (current === null && finishedWork.flags & Update) {866    const type = finishedWork.type;867    const props = finishedWork.memoizedProps;868    commitMount(instance, type, props, finishedWork);869  }870}871function hideOrUnhideAllChildren(finishedWork, isHidden) {872  if (supportsMutation) {873    // We only have the top Fiber that was inserted but we need to recurse down its874    // children to find all the terminal nodes.875    let node        = finishedWork;876    while (true) {877      if (node.tag === HostComponent) {878        const instance = node.stateNode;879        if (isHidden) {880          hideInstance(instance);881        } else {882          unhideInstance(node.stateNode, node.memoizedProps);883        }884      } else if (node.tag === HostText) {885        const instance = node.stateNode;886        if (isHidden) {887          hideTextInstance(instance);888        } else {889          unhideTextInstance(instance, node.memoizedProps);890        }891      } else if (892        (node.tag === OffscreenComponent ||893          node.tag === LegacyHiddenComponent) &&894        (node.memoizedState                ) !== null &&895        node !== finishedWork896      ) {897        // Found a nested Offscreen component that is hidden. Don't search898        // any deeper. This tree should remain hidden.899      } else if (node.child !== null) {900        node.child.return = node;901        node = node.child;902        continue;903      }904      if (node === finishedWork) {905        return;906      }907      while (node.sibling === null) {908        if (node.return === null || node.return === finishedWork) {909          return;910        }911        node = node.return;912      }913      node.sibling.return = node.return;914      node = node.sibling;915    }916  }917}918function commitAttachRef(finishedWork       ) {919  const ref = finishedWork.ref;920  if (ref !== null) {921    const instance = finishedWork.stateNode;922    let instanceToUse;923    switch (finishedWork.tag) {924      case HostComponent:925        instanceToUse = getPublicInstance(instance);926        break;927      default:928        instanceToUse = instance;929    }930    // Moved outside to ensure DCE works with this flag931    if (enableScopeAPI && finishedWork.tag === ScopeComponent) {932      instanceToUse = instance;933    }934    if (typeof ref === 'function') {935      ref(instanceToUse);936    } else {937      if (__DEV__) {938        if (!ref.hasOwnProperty('current')) {939          console.error(940            'Unexpected ref object provided for %s. ' +941              'Use either a ref-setter function or React.createRef().',942            getComponentName(finishedWork.type),943          );944        }945      }946      ref.current = instanceToUse;947    }948  }949}950function commitDetachRef(current       ) {951  const currentRef = current.ref;952  if (currentRef !== null) {953    if (typeof currentRef === 'function') {954      currentRef(null);955    } else {956      currentRef.current = null;957    }958  }959}960// User-originating errors (lifecycles and refs) should not interrupt961// deletion, so don't let them throw. Host-originating errors should962// interrupt deletion, so it's okay963function commitUnmount(964  finishedRoot           ,965  current       ,966  nearestMountedAncestor       ,967  renderPriorityLevel                    ,968)       {969  onCommitUnmount(current);970  switch (current.tag) {971    case FunctionComponent:972    case ForwardRef:973    case MemoComponent:974    case SimpleMemoComponent:975    case Block: {976      const updateQueue                                      = (current.updateQueue     );977      if (updateQueue !== null) {978        const lastEffect = updateQueue.lastEffect;979        if (lastEffect !== null) {980          const firstEffect = lastEffect.next;981          let effect = firstEffect;982          do {983            const {destroy, tag} = effect;984            if (destroy !== undefined) {985              if ((tag & HookLayout) !== NoHookEffect) {986                if (987                  enableProfilerTimer &&988                  enableProfilerCommitHooks &&989                  current.mode & ProfileMode990                ) {991                  startLayoutEffectTimer();992                  safelyCallDestroy(current, nearestMountedAncestor, destroy);993                  recordLayoutEffectDuration(current);994                } else {995                  safelyCallDestroy(current, nearestMountedAncestor, destroy);996                }997              }998            }999            effect = effect.next;1000          } while (effect !== firstEffect);1001        }1002      }1003      return;1004    }1005    case ClassComponent: {1006      safelyDetachRef(current, nearestMountedAncestor);1007      const instance = current.stateNode;1008      if (typeof instance.componentWillUnmount === 'function') {1009        safelyCallComponentWillUnmount(1010          current,1011          instance,1012          nearestMountedAncestor,1013        );1014      }1015      return;1016    }1017    case HostComponent: {1018      safelyDetachRef(current, nearestMountedAncestor);1019      return;1020    }1021    case HostPortal: {1022      // TODO: this is recursive.1023      // We are also not using this parent because1024      // the portal will get pushed immediately.1025      if (supportsMutation) {1026        unmountHostComponents(1027          finishedRoot,1028          current,1029          nearestMountedAncestor,1030          renderPriorityLevel,1031        );1032      } else if (supportsPersistence) {1033        emptyPortalContainer(current);1034      }1035      return;1036    }1037    case FundamentalComponent: {1038      if (enableFundamentalAPI) {1039        const fundamentalInstance = current.stateNode;1040        if (fundamentalInstance !== null) {1041          unmountFundamentalComponent(fundamentalInstance);1042          current.stateNode = null;1043        }1044      }1045      return;1046    }1047    case DehydratedFragment: {1048      if (enableSuspenseCallback) {1049        const hydrationCallbacks = finishedRoot.hydrationCallbacks;1050        if (hydrationCallbacks !== null) {1051          const onDeleted = hydrationCallbacks.onDeleted;1052          if (onDeleted) {1053            onDeleted((current.stateNode                  ));1054          }1055        }1056      }1057      return;1058    }1059    case ScopeComponent: {1060      if (enableScopeAPI) {1061        safelyDetachRef(current, nearestMountedAncestor);1062      }1063      return;1064    }1065  }1066}1067function commitNestedUnmounts(1068  finishedRoot           ,1069  root       ,1070  nearestMountedAncestor       ,1071  renderPriorityLevel                    ,1072)       {1073  // While we're inside a removed host node we don't want to call1074  // removeChild on the inner nodes because they're removed by the top1075  // call anyway. We also want to call componentWillUnmount on all1076  // composites before this host node is removed from the tree. Therefore1077  // we do an inner loop while we're still inside the host node.1078  let node        = root;1079  while (true) {1080    commitUnmount(1081      finishedRoot,1082      node,1083      nearestMountedAncestor,1084      renderPriorityLevel,1085    );1086    // Visit children because they may contain more composite or host nodes.1087    // Skip portals because commitUnmount() currently visits them recursively.1088    if (1089      node.child !== null &&1090      // If we use mutation we drill down into portals using commitUnmount above.1091      // If we don't use mutation we drill down into portals here instead.1092      (!supportsMutation || node.tag !== HostPortal)1093    ) {1094      node.child.return = node;1095      node = node.child;1096      continue;1097    }1098    if (node === root) {1099      return;1100    }1101    while (node.sibling === null) {1102      if (node.return === null || node.return === root) {1103        return;1104      }1105      node = node.return;1106    }1107    node.sibling.return = node.return;1108    node = node.sibling;1109  }1110}1111function detachFiberMutation(fiber       ) {1112  // Cut off the return pointer to disconnect it from the tree.1113  // This enables us to detect and warn against state updates on an unmounted component.1114  // It also prevents events from bubbling from within disconnected components.1115  //1116  // Ideally, we should also clear the child pointer of the parent alternate to let this1117  // get GC:ed but we don't know which for sure which parent is the current1118  // one so we'll settle for GC:ing the subtree of this child.1119  // This child itself will be GC:ed when the parent updates the next time.1120  //1121  // Note that we can't clear child or sibling pointers yet.1122  // They're needed for passive effects and for findDOMNode.1123  // We defer those fields, and all other cleanup, to the passive phase (see detachFiberAfterEffects).1124  const alternate = fiber.alternate;1125  if (alternate !== null) {1126    alternate.return = null;1127    fiber.alternate = null;1128  }1129  fiber.return = null;1130}1131function emptyPortalContainer(current       ) {1132  if (!supportsPersistence) {1133    return;1134  }1135  const portal   1136                             1137                              1138       1139    = current.stateNode;1140  const {containerInfo} = portal;1141  const emptyChildSet = createContainerChildSet(containerInfo);1142  replaceContainerChildren(containerInfo, emptyChildSet);1143}1144function commitContainer(finishedWork       ) {1145  if (!supportsPersistence) {1146    return;1147  }1148  switch (finishedWork.tag) {1149    case ClassComponent:1150    case HostComponent:1151    case HostText:1152    case FundamentalComponent: {1153      return;1154    }1155    case HostRoot:1156    case HostPortal: {1157      const portalOrRoot   1158                                 1159                                  1160           1161        = finishedWork.stateNode;1162      const {containerInfo, pendingChildren} = portalOrRoot;1163      replaceContainerChildren(containerInfo, pendingChildren);1164      return;1165    }1166  }1167  invariant(1168    false,1169    'This unit of work tag should not have side-effects. This error is ' +1170      'likely caused by a bug in React. Please file an issue.',1171  );1172}1173function getHostParentFiber(fiber       )        {1174  let parent = fiber.return;1175  while (parent !== null) {1176    if (isHostParent(parent)) {1177      return parent;1178    }1179    parent = parent.return;1180  }1181  invariant(1182    false,1183    'Expected to find a host parent. This error is likely caused by a bug ' +1184      'in React. Please file an issue.',1185  );1186}1187function isHostParent(fiber       )          {1188  return (1189    fiber.tag === HostComponent ||1190    fiber.tag === HostRoot ||1191    fiber.tag === HostPortal1192  );1193}1194function getHostSibling(fiber       )            {1195  // We're going to search forward into the tree until we find a sibling host1196  // node. Unfortunately, if multiple insertions are done in a row we have to1197  // search past them. This leads to exponential search for the next sibling.1198  // TODO: Find a more efficient way to do this.1199  let node        = fiber;1200  siblings: while (true) {1201    // If we didn't find anything, let's try the next sibling.1202    while (node.sibling === null) {1203      if (node.return === null || isHostParent(node.return)) {1204        // If we pop out of the root or hit the parent the fiber we are the1205        // last sibling.1206        return null;1207      }1208      node = node.return;1209    }1210    node.sibling.return = node.return;1211    node = node.sibling;1212    while (1213      node.tag !== HostComponent &&1214      node.tag !== HostText &&1215      node.tag !== DehydratedFragment1216    ) {1217      // If it is not host node and, we might have a host node inside it.1218      // Try to search down until we find one.1219      if (node.flags & Placement) {1220        // If we don't have a child, try the siblings instead.1221        continue siblings;1222      }1223      // If we don't have a child, try the siblings instead.1224      // We also skip portals because they are not part of this host tree.1225      if (node.child === null || node.tag === HostPortal) {1226        continue siblings;1227      } else {1228        node.child.return = node;1229        node = node.child;1230      }1231    }1232    // Check if this host node is stable or about to be placed.1233    if (!(node.flags & Placement)) {1234      // Found it!1235      return node.stateNode;1236    }1237  }1238}1239function commitPlacement(finishedWork       )       {1240  if (!supportsMutation) {1241    return;1242  }1243  // Recursively insert all host nodes into the parent.1244  const parentFiber = getHostParentFiber(finishedWork);1245  // Note: these two variables *must* always be updated together.1246  let parent;1247  let isContainer;1248  const parentStateNode = parentFiber.stateNode;1249  switch (parentFiber.tag) {1250    case HostComponent:1251      parent = parentStateNode;1252      isContainer = false;1253      break;1254    case HostRoot:1255      parent = parentStateNode.containerInfo;1256      isContainer = true;1257      break;1258    case HostPortal:1259      parent = parentStateNode.containerInfo;1260      isContainer = true;1261      break;1262    case FundamentalComponent:1263      if (enableFundamentalAPI) {1264        parent = parentStateNode.instance;1265        isContainer = false;1266      }1267    // eslint-disable-next-line-no-fallthrough1268    default:1269      invariant(1270        false,1271        'Invalid host parent fiber. This error is likely caused by a bug ' +1272          'in React. Please file an issue.',1273      );1274  }1275  if (parentFiber.flags & ContentReset) {1276    // Reset the text content of the parent before doing any insertions1277    resetTextContent(parent);1278    // Clear ContentReset from the effect tag1279    parentFiber.flags &= ~ContentReset;1280  }1281  const before = getHostSibling(finishedWork);1282  // We only have the top Fiber that was inserted but we need to recurse down its1283  // children to find all the terminal nodes.1284  if (isContainer) {1285    insertOrAppendPlacementNodeIntoContainer(finishedWork, before, parent);1286  } else {1287    insertOrAppendPlacementNode(finishedWork, before, parent);1288  }1289}1290function insertOrAppendPlacementNodeIntoContainer(1291  node       ,1292  before           ,1293  parent           ,1294)       {1295  const {tag} = node;1296  const isHost = tag === HostComponent || tag === HostText;1297  if (isHost || (enableFundamentalAPI && tag === FundamentalComponent)) {1298    const stateNode = isHost ? node.stateNode : node.stateNode.instance;1299    if (before) {1300      insertInContainerBefore(parent, stateNode, before);1301    } else {1302      appendChildToContainer(parent, stateNode);1303    }1304  } else if (tag === HostPortal) {1305    // If the insertion itself is a portal, then we don't want to traverse1306    // down its children. Instead, we'll get insertions from each child in1307    // the portal directly.1308  } else {1309    const child = node.child;1310    if (child !== null) {1311      insertOrAppendPlacementNodeIntoContainer(child, before, parent);1312      let sibling = child.sibling;1313      while (sibling !== null) {1314        insertOrAppendPlacementNodeIntoContainer(sibling, before, parent);1315        sibling = sibling.sibling;1316      }1317    }1318  }1319}1320function insertOrAppendPlacementNode(1321  node       ,1322  before           ,1323  parent          ,1324)       {1325  const {tag} = node;1326  const isHost = tag === HostComponent || tag === HostText;1327  if (isHost || (enableFundamentalAPI && tag === FundamentalComponent)) {1328    const stateNode = isHost ? node.stateNode : node.stateNode.instance;1329    if (before) {1330      insertBefore(parent, stateNode, before);1331    } else {1332      appendChild(parent, stateNode);1333    }1334  } else if (tag === HostPortal) {1335    // If the insertion itself is a portal, then we don't want to traverse1336    // down its children. Instead, we'll get insertions from each child in1337    // the portal directly.1338  } else {1339    const child = node.child;1340    if (child !== null) {1341      insertOrAppendPlacementNode(child, before, parent);1342      let sibling = child.sibling;1343      while (sibling !== null) {1344        insertOrAppendPlacementNode(sibling, before, parent);1345        sibling = sibling.sibling;1346      }1347    }1348  }1349}1350function unmountHostComponents(1351  finishedRoot           ,1352  current       ,1353  nearestMountedAncestor       ,1354  renderPriorityLevel                    ,1355)       {1356  // We only have the top Fiber that was deleted but we need to recurse down its1357  // children to find all the terminal nodes.1358  let node        = current;1359  // Each iteration, currentParent is populated with node's host parent if not1360  // currentParentIsValid.1361  let currentParentIsValid = false;1362  // Note: these two variables *must* always be updated together.1363  let currentParent;1364  let currentParentIsContainer;1365  while (true) {1366    if (!currentParentIsValid) {1367      let parent = node.return;1368      findParent: while (true) {1369        invariant(1370          parent !== null,1371          'Expected to find a host parent. This error is likely caused by ' +1372            'a bug in React. Please file an issue.',1373        );1374        const parentStateNode = parent.stateNode;1375        switch (parent.tag) {1376          case HostComponent:1377            currentParent = parentStateNode;1378            currentParentIsContainer = false;1379            break findParent;1380          case HostRoot:1381            currentParent = parentStateNode.containerInfo;1382            currentParentIsContainer = true;1383            break findParent;1384          case HostPortal:1385            currentParent = parentStateNode.containerInfo;1386            currentParentIsContainer = true;1387            break findParent;1388          case FundamentalComponent:1389            if (enableFundamentalAPI) {1390              currentParent = parentStateNode.instance;1391              currentParentIsContainer = false;1392            }1393        }1394        parent = parent.return;1395      }1396      currentParentIsValid = true;1397    }1398    if (node.tag === HostComponent || node.tag === HostText) {1399      commitNestedUnmounts(1400        finishedRoot,1401        node,1402        nearestMountedAncestor,1403        renderPriorityLevel,1404      );1405      // After all the children have unmounted, it is now safe to remove the1406      // node from the tree.1407      if (currentParentIsContainer) {1408        removeChildFromContainer(1409          ((currentParent     )           ),1410          (node.stateNode                         ),1411        );1412      } else {1413        removeChild(1414          ((currentParent     )          ),1415          (node.stateNode                         ),1416        );1417      }1418      // Don't visit children because we already visited them.1419    } else if (enableFundamentalAPI && node.tag === FundamentalComponent) {1420      const fundamentalNode = node.stateNode.instance;1421      commitNestedUnmounts(1422        finishedRoot,1423        node,1424        nearestMountedAncestor,1425        renderPriorityLevel,1426      );1427      // After all the children have unmounted, it is now safe to remove the1428      // node from the tree.1429      if (currentParentIsContainer) {1430        removeChildFromContainer(1431          ((currentParent     )           ),1432          (fundamentalNode          ),1433        );1434      } else {1435        removeChild(1436          ((currentParent     )          ),1437          (fundamentalNode          ),1438        );1439      }1440    } else if (1441      enableSuspenseServerRenderer &&1442      node.tag === DehydratedFragment1443    ) {1444      if (enableSuspenseCallback) {1445        const hydrationCallbacks = finishedRoot.hydrationCallbacks;1446        if (hydrationCallbacks !== null) {1447          const onDeleted = hydrationCallbacks.onDeleted;1448          if (onDeleted) {1449            onDeleted((node.stateNode                  ));1450          }1451        }1452      }1453      // Delete the dehydrated suspense boundary and all of its content.1454      if (currentParentIsContainer) {1455        clearSuspenseBoundaryFromContainer(1456          ((currentParent     )           ),1457          (node.stateNode                  ),1458        );1459      } else {1460        clearSuspenseBoundary(1461          ((currentParent     )          ),1462          (node.stateNode                  ),1463        );1464      }1465    } else if (node.tag === HostPortal) {1466      if (node.child !== null) {1467        // When we go into a portal, it becomes the parent to remove from.1468        // We will reassign it back when we pop the portal on the way up.1469        currentParent = node.stateNode.containerInfo;1470        currentParentIsContainer = true;1471        // Visit children because portals might contain host components.1472        node.child.return = node;1473        node = node.child;1474        continue;1475      }1476    } else {1477      commitUnmount(1478        finishedRoot,1479        node,1480        nearestMountedAncestor,1481        renderPriorityLevel,1482      );1483      // Visit children because we may find more host components below.1484      if (node.child !== null) {1485        node.child.return = node;1486        node = node.child;1487        continue;1488      }1489    }1490    if (node === current) {1491      return;1492    }1493    while (node.sibling === null) {1494      if (node.return === null || node.return === current) {1495        return;1496      }1497      node = node.return;1498      if (node.tag === HostPortal) {1499        // When we go out of the portal, we need to restore the parent.1500        // Since we don't keep a stack of them, we will search for it.1501        currentParentIsValid = false;1502      }1503    }1504    node.sibling.return = node.return;1505    node = node.sibling;1506  }1507}1508function commitDeletion(1509  finishedRoot           ,1510  current       ,1511  nearestMountedAncestor       ,1512  renderPriorityLevel                    ,1513)       {1514  if (supportsMutation) {1515    // Recursively delete all host nodes from the parent.1516    // Detach refs and call componentWillUnmount() on the whole subtree.1517    unmountHostComponents(1518      finishedRoot,1519      current,1520      nearestMountedAncestor,1521      renderPriorityLevel,1522    );1523  } else {1524    // Detach refs and call componentWillUnmount() on the whole subtree.1525    commitNestedUnmounts(1526      finishedRoot,1527      current,1528      nearestMountedAncestor,1529      renderPriorityLevel,1530    );1531  }1532  const alternate = current.alternate;1533  detachFiberMutation(current);1534  if (alternate !== null) {1535    detachFiberMutation(alternate);1536  }1537}1538function commitWork(current              , finishedWork       )       {1539  if (!supportsMutation) {1540    switch (finishedWork.tag) {1541      case FunctionComponent:1542      case ForwardRef:1543      case MemoComponent:1544      case SimpleMemoComponent:1545      case Block: {1546        // Layout effects are destroyed during the mutation phase so that all1547        // destroy functions for all fibers are called before any create functions.1548        // This prevents sibling component effects from interfering with each other,1549        // e.g. a destroy function in one component should never override a ref set1550        // by a create function in another component during the same commit.1551        if (1552          enableProfilerTimer &&1553          enableProfilerCommitHooks &&1554          finishedWork.mode & ProfileMode1555        ) {1556          try {1557            startLayoutEffectTimer();1558            commitHookEffectListUnmount(1559              HookLayout | HookHasEffect,1560              finishedWork,1561              finishedWork.return,1562            );1563          } finally {1564            recordLayoutEffectDuration(finishedWork);1565          }1566        } else {1567          commitHookEffectListUnmount(1568            HookLayout | HookHasEffect,1569            finishedWork,1570            finishedWork.return,1571          );1572        }1573        return;1574      }1575      case Profiler: {1576        return;1577      }1578      case SuspenseComponent: {1579        commitSuspenseComponent(finishedWork);1580        attachSuspenseRetryListeners(finishedWork);1581        return;1582      }1583      case SuspenseListComponent: {1584        attachSuspenseRetryListeners(finishedWork);1585        return;1586      }1587      case HostRoot: {1588        if (supportsHydration) {1589          const root            = finishedWork.stateNode;1590          if (root.hydrate) {1591            // We've just hydrated. No need to hydrate again.1592            root.hydrate = false;1593            commitHydratedContainer(root.containerInfo);1594          }1595        }1596        break;1597      }1598      case OffscreenComponent:1599      case LegacyHiddenComponent: {1600        return;1601      }1602    }1603    commitContainer(finishedWork);1604    return;1605  }1606  switch (finishedWork.tag) {1607    case FunctionComponent:1608    case ForwardRef:1609    case MemoComponent:1610    case SimpleMemoComponent:1611    case Block: {1612      // Layout effects are destroyed during the mutation phase so that all1613      // destroy functions for all fibers are called before any create functions.1614      // This prevents sibling component effects from interfering with each other,1615      // e.g. a destroy function in one component should never override a ref set1616      // by a create function in another component during the same commit.1617      if (1618        enableProfilerTimer &&1619        enableProfilerCommitHooks &&1620        finishedWork.mode & ProfileMode1621      ) {1622        try {1623          startLayoutEffectTimer();1624          commitHookEffectListUnmount(1625            HookLayout | HookHasEffect,1626            finishedWork,1627            finishedWork.return,1628          );1629        } finally {1630          recordLayoutEffectDuration(finishedWork);1631        }1632      } else {1633        commitHookEffectListUnmount(1634          HookLayout | HookHasEffect,1635          finishedWork,1636          finishedWork.return,1637        );1638      }1639      return;1640    }1641    case ClassComponent: {1642      return;1643    }1644    case HostComponent: {1645      const instance           = finishedWork.stateNode;1646      if (instance != null) {1647        // Commit the work prepared earlier.1648        const newProps = finishedWork.memoizedProps;1649        // For hydration we reuse the update path but we treat the oldProps1650        // as the newProps. The updatePayload will contain the real change in1651        // this case.1652        const oldProps = current !== null ? current.memoizedProps : newProps;1653        const type = finishedWork.type;1654        // TODO: Type the updateQueue to be specific to host components.1655        const updatePayload                       = (finishedWork.updateQueue     );1656        finishedWork.updateQueue = null;1657        if (updatePayload !== null) {1658          commitUpdate(1659            instance,1660            updatePayload,1661            type,1662            oldProps,1663            newProps,1664            finishedWork,1665          );1666        }1667      }1668      return;1669    }1670    case HostText: {1671      invariant(1672        finishedWork.stateNode !== null,1673        'This should have a text node initialized. This error is likely ' +1674          'caused by a bug in React. Please file an issue.',1675      );1676      const textInstance               = finishedWork.stateNode;1677      const newText         = finishedWork.memoizedProps;1678      // For hydration we reuse the update path but we treat the oldProps1679      // as the newProps. The updatePayload will contain the real change in1680      // this case.1681      const oldText         =1682        current !== null ? current.memoizedProps : newText;1683      commitTextUpdate(textInstance, oldText, newText);1684      return;1685    }1686    case HostRoot: {1687      if (supportsHydration) {1688        const root            = finishedWork.stateNode;1689        if (root.hydrate) {1690          // We've just hydrated. No need to hydrate again.1691          root.hydrate = false;1692          commitHydratedContainer(root.containerInfo);1693        }1694      }1695      return;1696    }1697    case Profiler: {1698      return;1699    }1700    case SuspenseComponent: {1701      commitSuspenseComponent(finishedWork);1702      attachSuspenseRetryListeners(finishedWork);1703      return;1704    }1705    case SuspenseListComponent: {1706      attachSuspenseRetryListeners(finishedWork);1707      return;1708    }1709    case IncompleteClassComponent: {1710      return;1711    }1712    case FundamentalComponent: {1713      if (enableFundamentalAPI) {1714        const fundamentalInstance = finishedWork.stateNode;1715        updateFundamentalComponent(fundamentalInstance);1716        return;1717      }1718      break;1719    }1720    case ScopeComponent: {1721      if (enableScopeAPI) {1722        const scopeInstance = finishedWork.stateNode;1723        prepareScopeUpdate(scopeInstance, finishedWork);1724        return;1725      }1726      break;1727    }1728    case OffscreenComponent:1729    case LegacyHiddenComponent: {1730      const newState                        = finishedWork.memoizedState;1731      const isHidden = newState !== null;1732      hideOrUnhideAllChildren(finishedWork, isHidden);1733      return;1734    }1735  }1736  invariant(1737    false,1738    'This unit of work tag should not have side-effects. This error is ' +1739      'likely caused by a bug in React. Please file an issue.',1740  );1741}1742function commitSuspenseComponent(finishedWork       ) {1743  const newState                       = finishedWork.memoizedState;1744  if (newState !== null) {1745    markCommitTimeOfFallback();1746    if (supportsMutation) {1747      // Hide the Offscreen component that contains the primary children. TODO:1748      // Ideally, this effect would have been scheduled on the Offscreen fiber1749      // itself. That's how unhiding works: the Offscreen component schedules an1750      // effect on itself. However, in this case, the component didn't complete,1751      // so the fiber was never added to the effect list in the normal path. We1752      // could have appended it to the effect list in the Suspense component's1753      // second pass, but doing it this way is less complicated. This would be1754      // simpler if we got rid of the effect list and traversed the tree, like1755      // we're planning to do.1756      const primaryChildParent        = (finishedWork.child     );1757      hideOrUnhideAllChildren(primaryChildParent, true);1758    }1759  }1760  if (enableSuspenseCallback && newState !== null) {1761    const suspenseCallback = finishedWork.memoizedProps.suspenseCallback;1762    if (typeof suspenseCallback === 'function') {1763      const wakeables                       = (finishedWork.updateQueue     );1764      if (wakeables !== null) {1765        suspenseCallback(new Set(wakeables));1766      }1767    } else if (__DEV__) {1768      if (suspenseCallback !== undefined) {1769        console.error('Unexpected type for suspenseCallback.');1770      }1771    }1772  }1773}1774function commitSuspenseHydrationCallbacks(1775  finishedRoot           ,1776  finishedWork       ,1777) {1778  if (!supportsHydration) {1779    return;1780  }1781  const newState                       = finishedWork.memoizedState;1782  if (newState === null) {1783    const current = finishedWork.alternate;1784    if (current !== null) {1785      const prevState                       = current.memoizedState;1786      if (prevState !== null) {1787        const suspenseInstance = prevState.dehydrated;1788        if (suspenseInstance !== null) {1789          commitHydratedSuspenseInstance(suspenseInstance);1790          if (enableSuspenseCallback) {1791            const hydrationCallbacks = finishedRoot.hydrationCallbacks;1792            if (hydrationCallbacks !== null) {1793              const onHydrated = hydrationCallbacks.onHydrated;1794              if (onHydrated) {1795                onHydrated(suspenseInstance);1796              }1797            }1798          }1799        }1800      }1801    }1802  }1803}1804function attachSuspenseRetryListeners(finishedWork       ) {1805  // If this boundary just timed out, then it will have a set of wakeables.1806  // For each wakeable, attach a listener so that when it resolves, React1807  // attempts to re-render the boundary in the primary (pre-timeout) state.1808  const wakeables                       = (finishedWork.updateQueue     );1809  if (wakeables !== null) {1810    finishedWork.updateQueue = null;1811    let retryCache = finishedWork.stateNode;1812    if (retryCache === null) {1813      retryCache = finishedWork.stateNode = new PossiblyWeakSet();1814    }1815    wakeables.forEach(wakeable => {1816      // Memoize using the boundary fiber to prevent redundant listeners.1817      let retry = resolveRetryWakeable.bind(null, finishedWork, wakeable);1818      if (!retryCache.has(wakeable)) {1819        if (enableSchedulerTracing) {1820          if (wakeable.__reactDoNotTraceInteractions !== true) {1821            retry = Schedule_tracing_wrap(retry);1822          }1823        }1824        retryCache.add(wakeable);1825        wakeable.then(retry, retry);1826      }1827    });1828  }1829}1830// This function detects when a Suspense boundary goes from visible to hidden.1831// It returns false if the boundary is already hidden.1832// TODO: Use an effect tag.1833export function isSuspenseBoundaryBeingHidden(1834  current              ,1835  finishedWork       ,1836)          {1837  if (current !== null) {1838    const oldState                       = current.memoizedState;1839    if (oldState === null || oldState.dehydrated !== null) {1840      const newState                       = finishedWork.memoizedState;1841      return newState !== null && newState.dehydrated === null;1842    }1843  }1844  return false;1845}1846function commitResetTextContent(current       )       {1847  if (!supportsMutation) {1848    return;1849  }1850  resetTextContent(current.stateNode);1851}1852function commitPassiveUnmount(finishedWork       )       {1853  switch (finishedWork.tag) {1854    case FunctionComponent:1855    case ForwardRef:1856    case SimpleMemoComponent:1857    case Block: {1858      if (1859        enableProfilerTimer &&1860        enableProfilerCommitHooks &&1861        finishedWork.mode & ProfileMode1862      ) {1863        startPassiveEffectTimer();1864        commitHookEffectListUnmount(1865          HookPassive | HookHasEffect,1866          finishedWork,1867          finishedWork.return,1868        );1869        recordPassiveEffectDuration(finishedWork);1870      } else {1871        commitHookEffectListUnmount(1872          HookPassive | HookHasEffect,1873          finishedWork,1874          finishedWork.return,1875        );1876      }1877      break;1878    }1879  }1880}1881function commitPassiveUnmountInsideDeletedTree(1882  current       ,1883  nearestMountedAncestor              ,1884)       {1885  switch (current.tag) {1886    case FunctionComponent:1887    case ForwardRef:1888    case SimpleMemoComponent:1889    case Block: {1890      if (1891        enableProfilerTimer &&1892        enableProfilerCommitHooks &&1893        current.mode & ProfileMode1894      ) {1895        startPassiveEffectTimer();1896        commitHookEffectListUnmount(1897          HookPassive,1898          current,1899          nearestMountedAncestor,1900        );1901        recordPassiveEffectDuration(current);1902      } else {1903        commitHookEffectListUnmount(1904          HookPassive,1905          current,1906          nearestMountedAncestor,1907        );1908      }1909      break;1910    }1911  }1912}1913function commitPassiveMount(1914  finishedRoot           ,1915  finishedWork       ,1916)       {1917  switch (finishedWork.tag) {1918    case FunctionComponent:1919    case ForwardRef:1920    case SimpleMemoComponent:1921    case Block: {1922      if (1923        enableProfilerTimer &&1924        enableProfilerCommitHooks &&1925        finishedWork.mode & ProfileMode1926      ) {1927        startPassiveEffectTimer();1928        try {1929          commitHookEffectListMount(HookPassive | HookHasEffect, finishedWork);1930        } finally {1931          recordPassiveEffectDuration(finishedWork);1932        }1933      } else {1934        commitHookEffectListMount(HookPassive | HookHasEffect, finishedWork);1935      }1936      break;1937    }1938    case Profiler: {1939      commitProfilerPassiveEffect(finishedRoot, finishedWork);1940      break;1941    }1942  }1943}1944function invokeLayoutEffectMountInDEV(fiber       )       {1945  if (__DEV__ && enableDoubleInvokingEffects) {1946    switch (fiber.tag) {1947      case FunctionComponent:1948      case ForwardRef:...hooks.js
Source:hooks.js  
...81    //effectæ¯å¦è¦æ§è¡82    //hook.queue æ¯å¦è¦æ´æ°83    //æ¤hook为hooké¾è¡¨84    //åè§2059185    //function commitHookEffectListMount(finishedWork) {86    // 弿¥æ§è¡ Effect87    //å¾®ä»»å¡ å¼æ¥æ§è¡fiber_Effect_List88    Promise.resolve().then(()=>{89        commitHookEffectListMount(HasEffect,currentlyRenderingFiber$1);90    })91    //æ§è¡å¯ä½ç¨  92}93//æ§è¡å¯ä½ç¨ EffectList94function commitHookEffectListMount(tag,finishedWork) {95    let updateQueue = finishedWork.updateQueue;96    let lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;97    if (lastEffect !== null) {98        let firstEffect = lastEffect.next;99        let effect = firstEffect;100        do {101            //effet çtag æ¯å¦å
å« tag 102            if ((effect.tag & tag) === tag) {103            // Mount104            let create = effect.create;105            //æ§è¡ åè°106            effect.destroy = create();107                //destroy çæ¥éä¿¡æ¯108                {...ReactFiberCommitWork.js
Source:ReactFiberCommitWork.js  
...160}161export function commitLifeCycles(finishedRoot, current, finishedWork, committedLanes) {162  switch(finishedWork.tag) {163    case FunctionComponent: {164      commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork);165      schedulePassiveEffects(finishedWork);166      return;167    }168    case HostRoot: {169      const updateQueue = finishedWork.updateQueue;170      if(updateQueue !== null) {171        let instance = null;172        if(finishedWork.child !== null) {173          switch(finishedWork.child.tag) {174            case HostComponent:175              instance = getPublicInstance(finishedWork.child.stateNode);176              break;177          }178        }179        commitUpdateQueue(finishedWork, updateQueue, instance);180      }181      return;182    }183    case HostComponent: {184      const instance = finishedWork.stateNode;185      if(current === null && finishedWork.flags & Update) {186        const type = finishedWork.type;187        const props = finishedWork.memoizedProps;188        // commitMount(instance, type, props, finishedWork);189      }190      return;191    }192    case HostText:193      return;194  }195}196function schedulePassiveEffects(finishedWork) {197  const updateQueue = finishedWork.updateQueue;198  const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;199  if(lastEffect !== null) {200    const firstEffect = lastEffect.next;201    let effect = firstEffect;202    do{203      const {next, tag} = effect;204      if(205        (tag & HookPassive) !== NoHookEffect &&206        (tag & HookHasEffect) !== NoHookEffect207      ) {208        // enqueuePendingPassiveHookEffectUnmount(finishedWork, effect);209        enqueuePendingPassiveHookEffectMount(finishedWork, effect);210      }211      effect = next;212    } while(effect !== firstEffect)213  }214}215export function recursivelyCommitLayoutEffects(finishedWork, finishedRoot) {216  const {flags, tag} = finishedWork;217  switch(tag) {218    default:  219      let child =  finishedWork.child;220      while(child !== null) {221        const primarySubtreeFlags = finishedWork.subtreeFlags &  LayoutMask;222        if(primarySubtreeFlags !== NoFlags) {223          recursivelyCommitLayoutEffects(child, finishedRoot);224        }225        child = child.sibling;226      }227      const primaryFlags = flags & (Update | Callback);228      if(primaryFlags !== NoFlags) {229        switch(tag) {230          case FunctionComponent:231            commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork);232            if((finishedWork.subtreeFlags & PassiveMask) !== NoFlags) {233              schedulePassiveEffectCallback();234            }235            break;236          case HostRoot:237            commitLayoutEffectsForHostRoot(finishedWork);238            break;239        }240      }241  }242}243function commitLayoutEffectsForHostRoot(finishedWork) {244  const update = finishedWork.update;245  if(update !== null) {246    let  instance  = null;247    if(finishedWork.child !== null) {248      switch(finishedWork.child.tag) {249        case HostComponent:250          instance = getPublicInstance(finishedWork.child.stateNode);251          break;252      }253    }254    commitUpdateQueue(finishedWork, updateQueue, instance);255  }256}257export function commitPassiveUnmount(finishedWork) {258  switch(finishedWork.tag) {259    case FunctionComponent: {260      commitHookEffectListUnmount(261        HookPassive | HookHasEffect,262        finishedWork,263        finishedWork.return264      );265      break;266    }267  }268}269function commitHookEffectListUnmount(flags, finishedWork, nearestMountedAncestor) {270  const updateQueue = finishedWork.updateQueue;271  const lastEffect = updateQueue.lastEffect !== null ? updateQueue.lastEffect : null;272  if(lastEffect !== null) {273    const firstEffect = lastEffect.next;274    let effect = firstEffect;275    do {276      if((effect.tag & flags) ===  flags) {277        const destory = effect.destory;278        effect.destory = undefined;279        if(destory !== undefined) {280          destory();281        }282      }283      effect = effect.next;284    } while(effect !== firstEffect)285  }286}287export function commitPassiveMount(finishedRoot, finishedWork) {288  switch(finishedWork.tag) {289    case FunctionComponent: {290      commitHookEffectListMount(HookPassive | HookHasEffect, finishedWork);291      break;292    }293  }294}295function commitHookEffectListMount(flags, finishedWork) {296  const updateQueue = finishedWork.updateQueue;297  const lastEffect = updateQueue.lastEffect !== null ? updateQueue.lastEffect : null;298  if(lastEffect !== null) {299    const firstEffect = lastEffect.next;300    let effect = firstEffect;301    do {302      if((effect.tag & flags) === flags) {303        const create = effect.create;304        effect.destory = create();305        effect = effect.next;306      }307    } while (effect !== firstEffect)308  }309}...commitRoot.js
Source:commitRoot.js  
...131function commitLayoutEffectOnFiber(finishedRoot, current, finishedWork, lanes) {132    switch (finishedWork.tag) {133        case FunctionComponent:134            // éåææeffectï¼æ§è¡createï¼è¿åå¼ä½ä¸ºdestroy135            commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork);136        case ClassComponent: {137            // çå½å¨æé©å138            if (current === null) {139                instance.componentDidMount();140            } else {141                instance.componentDidUpdate();142            }143        }144    }145    commitAttachRef(finishedWork);...Using AI Code Generation
1const { commitHookEffectListMount } = require('playwright/lib/server/supplements/recorder/recorderSupplement');2commitHookEffectListMount();3const { commitHookEffectListUnmount } = require('playwright/lib/server/supplements/recorder/recorderSupplement');4commitHookEffectListUnmount();5const { getHookEffectList } = require('playwright/lib/server/supplements/recorder/recorderSupplement');6console.log(getHookEffectList());7const { getHookEffectList } = require('playwright/lib/server/supplements/recorder/recorderSupplement');8console.log(getHookEffectList());9const { getHookEffectList } = require('playwright/lib/server/supplements/recorder/recorderSupplement');10console.log(getHookEffectList());11const { getHookEffectList } = require('playwright/lib/server/supplements/recorder/recorderSupplement');12console.log(getHookEffectList());13const { getHookEffectList } = require('playwright/lib/server/supplements/recorder/recorderSupplement');14console.log(getHookEffectList());15const { getHookEffectList } = require('playwright/lib/server/supplements/recorder/recorderSupplement');16console.log(getHookEffectList());17const { getHookEffectList } = require('playwright/lib/server/supplements/recorder/recorderSupplement');18console.log(getHookEffectList());19const { getHookEffectList } = require('playwright/lib/server/supplements/recorder/recorderSupplement');20console.log(getHookEffectList());21const { getHookEffectList } = require('playwright/lib/server/supplements/recorder/recorderSupplement');22console.log(getHookEffectList());Using AI Code Generation
1const { commitHookEffectListMount } = require('@playwright/test/lib/server/trace/viewer/traceModel');2const { TraceModel } = require('@playwright/test/lib/server/trace/viewer/traceModel');3const { Page } = require('@playwright/test/lib/server/page');4const { Frame } = require('@playwright/test/lib/server/frames');5const { FrameSnapshot } = require('@playwright/test/lib/server/trace/viewer/frameSnapshot');6const { SnapshotServer } = require('@playwright/test/lib/server/snapshot/snapshotServer');7const frame = new Frame();8const page = new Page();9const traceModel = new TraceModel();10const frameSnapshot = new FrameSnapshot();11const snapshotServer = new SnapshotServer();12commitHookEffectListMount(traceModel, page, frame, frameSnapshot, snapshotServer);13  0 passed (1s)14  1 failed (1s)15        at FrameSnapshot._commitHookEffectListMount (/Users/xxx/xxx/node_modules/@playwright/test/lib/server/trace/viewer/frameSnapshot.js:173:11)16        at Frame._commitHookEffectListMount (/Users/xxx/xxx/node_modules/@playwright/test/lib/server/frames.js:301:31)17        at Page._commitHookEffectListMount (/Users/xxx/xxx/node_modules/@playwright/test/lib/server/page.js:897:31)18        at TraceModel._commitHookEffectListMount (/Users/xxx/xxx/node_modules/@playwright/test/lib/server/trace/viewer/traceModel.js:341:31)19        at commitHookEffectListMount (/Users/xxx/xxx/test.js:13:1)20        at runMicrotasks (<anonymous>)21        at processTicksAndRejections (node:internal/process/task_queues:93:5)Using AI Code Generation
1const playwright = require('playwright');2const { commitHookEffectListMount } = require('playwright/lib/server/supplements/recorder/recorderSupplement');3const { chromium } = playwright;4(async () => {5  const browser = await chromium.launch();6  const context = await browser.newContext();7  const page = await context.newPage();8  await page.click('input[name="q"]');9  await page.fill('input[name="q"]', 'Hello World!');10  await page.press('input[name="q"]', 'Enter');11  await page.waitForSelector('text=Hello World!');12  await page.click('text=Hello World!');13  await page.waitForSelector('text=Hello World! - Google Search');14  await commitHookEffectListMount(page);15  await browser.close();16})();17const playwright = require('playwright');18const { chromium } = playwright;19(async () => {20  const browser = await chromium.launch();21  const context = await browser.newContext();22  const page = await context.newPage();23  await page.click('input[name="q"]');24  await page.fill('input[name="q"]', 'Hello World!');25  await page.press('input[name="q"]', 'Enter');26  await page.waitForSelector('text=Hello World!');27  await page.click('text=Hello World!');28  await page.waitForSelector('text=Hello World! - Google Search');29  await browser.close();30})();Using AI Code Generation
1const commitHookEffectListMount = require('playwright').internalAPI.commitHookEffectListMount;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  await commitHookEffectListMount(page);8  await page.waitForTimeout(5000);9  await commitHookEffectListMount(page, false);10  await browser.close();11})();12module.exports = {13  use: {14  }15};16commitHookEffectListMount(enabled = true) → Promise17enabled boolean (optional, default: true)18commitHookEffectListMount(page, enabled = true) → Promise19enabled boolean (optional, default: true)20commitHookEffectListMount(page, enabled = true) → Promise21enabled boolean (optional, default: true)22commitHookEffectListMount(page,Using AI Code Generation
1const { commitHookEffectListMount } = require('playwright');2const { getHookEffectList } = require('playwright');3const { getHookEffectListUnmount } = require('playwright');4const { getHookEffectListUpdate } = require('playwright');5const hookEffectList = getHookEffectList();6commitHookEffectListMount(hookEffectList);7const hookEffectListUnmount = getHookEffectListUnmount();8commitHookEffectListUnmount(hookEffectListUnmount);9const hookEffectListUpdate = getHookEffectListUpdate();10commitHookEffectListUpdate(hookEffectListUpdate);11const { test, expect } = require('@playwright/test');12const { getHookEffectList } = require('playwright');13const { getHookEffectListUnmount } = require('playwright');14const { getHookEffectListUpdate } = require('playwright');15test('My test', async ({ page }) => {16  const hookEffectList = getHookEffectList();17  const hookEffectListUnmount = getHookEffectListUnmount();18  const hookEffectListUpdate = getHookEffectListUpdate();19  expect(hookEffectList).toContain('useEffect');20  expect(hookEffectListUnmount).toContain('useEffect');21  expect(hookEffectListUpdate).toContain('useEffect');22});23import { test, expect } from '@playwright/test';24import { getHookEffectList } from 'playwright';25import { getHookEffectListUnmount } from 'playwright';26import { getHookEffectListUpdate } from 'playwright';27test('My test', async ({ page }) => {28  const hookEffectList = getHookEffectList();29  const hookEffectListUnmount = getHookEffectListUnmount();30  const hookEffectListUpdate = getHookEffectListUpdate();31  expect(hookEffectList).toContain('useEffect');32  expect(hookEffectListUnmount).toContain('useEffect');33  expect(hookEffectListUpdate).toContain('useEffect');34});35function getHookEffectList(): string[]Using AI Code Generation
1const { commitHookEffectListMount } = require('@playwright/test/lib/server/trace/snapshotter/injected');2commitHookEffectListMount('hookName', 'effectName', 'mount');3const { commitHookEffectListUnmount } = require('@playwright/test/lib/server/trace/snapshotter/injected');4commitHookEffectListUnmount('hookName', 'effectName', 'unmount');5const { test } = require('@playwright/test');6test('test name', async ({ page }) => {7  await page.evaluate(() => {8    commitHookEffectListMount('hookName', 'effectName', 'mount');9  });10  await page.evaluate(() => {11    commitHookEffectListUnmount('hookName', 'effectName', 'unmount');12  });13});14import { PlaywrightTestConfig } from '@playwright/test';15const config: PlaywrightTestConfig = {16  use: {17  },18};19export default config;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!!
