packages/react-reconciler/src/ReactFiberBeginWork.js JAVASCRIPT 4,515 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 4,515.
1/**2 * Copyright (c) Meta Platforms, Inc. and affiliates.3 *4 * This source code is licensed under the MIT license found in the5 * LICENSE file in the root directory of this source tree.6 *7 * @flow8 */910import type {11  ReactConsumerType,12  ReactContext,13  ReactNodeList,14  ViewTransitionProps,15  ActivityProps,16  SuspenseProps,17  SuspenseListProps,18  SuspenseListRevealOrder,19  SuspenseListTailMode,20  TracingMarkerProps,21  CacheProps,22  ProfilerProps,23} from 'shared/ReactTypes';24import type {LazyComponent as LazyComponentType} from 'react/src/ReactLazy';25import type {Fiber, FiberRoot} from './ReactInternalTypes';26import type {TypeOfMode} from './ReactTypeOfMode';27import type {Lanes, Lane} from './ReactFiberLane';28import type {ActivityState} from './ReactFiberActivityComponent';29import type {30  SuspenseState,31  SuspenseListRenderState,32} from './ReactFiberSuspenseComponent';33import type {SuspenseContext} from './ReactFiberSuspenseContext';34import type {35  LegacyHiddenProps,36  OffscreenProps,37  OffscreenState,38  OffscreenQueue,39  OffscreenInstance,40} from './ReactFiberOffscreenComponent';41import type {42  Cache,43  CacheComponentState,44  SpawnedCachePool,45} from './ReactFiberCacheComponent';46import type {UpdateQueue} from './ReactFiberClassUpdateQueue';47import type {RootState} from './ReactFiberRoot';48import type {TracingMarkerInstance} from './ReactFiberTracingMarkerComponent';49import type {ViewTransitionState} from './ReactFiberViewTransitionComponent';5051import {52  markComponentRenderStarted,53  markComponentRenderStopped,54  setIsStrictModeForDevtools,55} from './ReactFiberDevToolsHook';56import {57  FunctionComponent,58  ClassComponent,59  HostRoot,60  HostComponent,61  HostHoistable,62  HostSingleton,63  HostText,64  HostPortal,65  ForwardRef,66  Fragment,67  Mode,68  ContextProvider,69  ContextConsumer,70  Profiler,71  SuspenseComponent,72  SuspenseListComponent,73  MemoComponent,74  SimpleMemoComponent,75  LazyComponent,76  IncompleteClassComponent,77  IncompleteFunctionComponent,78  ScopeComponent,79  OffscreenComponent,80  LegacyHiddenComponent,81  CacheComponent,82  TracingMarkerComponent,83  Throw,84  ViewTransitionComponent,85  ActivityComponent,86} from './ReactWorkTags';87import {88  NoFlags,89  PerformedWork,90  Placement,91  PlacementDEV,92  Hydrating,93  Callback,94  ContentReset,95  DidCapture,96  Update,97  Ref,98  RefStatic,99  ChildDeletion,100  ForceUpdateForLegacySuspense,101  StaticMask,102  ShouldCapture,103  ForceClientRender,104  Passive,105  DidDefer,106  ViewTransitionNamedStatic,107  ViewTransitionNamedMount,108  LayoutStatic,109} from './ReactFiberFlags';110import {111  disableLegacyContext,112  disableLegacyContextForFunctionComponents,113  enableProfilerCommitHooks,114  enableProfilerTimer,115  enableScopeAPI,116  enableSchedulingProfiler,117  enableTransitionTracing,118  enableLegacyHidden,119  enableCPUSuspense,120  disableLegacyMode,121  enableViewTransition,122  enableFragmentRefs,123} from 'shared/ReactFeatureFlags';124import shallowEqual from 'shared/shallowEqual';125import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFromFiber';126import getComponentNameFromType from 'shared/getComponentNameFromType';127import ReactStrictModeWarnings from './ReactStrictModeWarnings';128import {129  REACT_LAZY_TYPE,130  REACT_FORWARD_REF_TYPE,131  REACT_MEMO_TYPE,132  REACT_CONTEXT_TYPE,133} from 'shared/ReactSymbols';134import {REACT_RECOVERABLE_DIGEST} from 'shared/ReactRecoverable';135import {setCurrentFiber} from './ReactCurrentFiber';136import {resolveTypeForHotReloading} from './ReactFiberHotReloading';137138import {139  mountChildFibers,140  reconcileChildFibers,141  cloneChildFibers,142  validateSuspenseListChildren,143} from './ReactChildFiber';144import {145  processUpdateQueue,146  cloneUpdateQueue,147  initializeUpdateQueue,148  enqueueCapturedUpdate,149  suspendIfUpdateReadFromEntangledAsyncAction,150} from './ReactFiberClassUpdateQueue';151import {152  NoLane,153  NoLanes,154  OffscreenLane,155  DefaultLane,156  SomeRetryLane,157  includesSomeLane,158  includesOnlyRetries,159  laneToLanes,160  removeLanes,161  mergeLanes,162  getBumpedLaneForHydration,163  pickArbitraryLane,164} from './ReactFiberLane';165import {166  ConcurrentMode,167  NoMode,168  ProfileMode,169  StrictLegacyMode,170} from './ReactTypeOfMode';171import {172  shouldSetTextContent,173  isSuspenseInstancePending,174  isSuspenseInstanceFallback,175  getSuspenseInstanceFallbackErrorDetails,176  supportsHydration,177  supportsResources,178  supportsSingletons,179  isPrimaryRenderer,180  getResource,181  createHoistableInstance,182  HostTransitionContext,183} from './ReactFiberConfig';184import type {ActivityInstance, SuspenseInstance} from './ReactFiberConfig';185import {shouldError, shouldSuspend} from './ReactFiberReconciler';186import {187  pushHostContext,188  pushHostContainer,189  getRootHostContainer,190} from './ReactFiberHostContext';191import {192  suspenseStackCursor,193  pushSuspenseListContext,194  ForceSuspenseFallback,195  hasSuspenseListContext,196  setDefaultShallowSuspenseListContext,197  setShallowSuspenseListContext,198  pushPrimaryTreeSuspenseHandler,199  pushFallbackTreeSuspenseHandler,200  pushDehydratedActivitySuspenseHandler,201  pushOffscreenSuspenseHandler,202  reuseSuspenseHandlerOnStack,203  popSuspenseHandler,204} from './ReactFiberSuspenseContext';205import {206  pushHiddenContext,207  reuseHiddenContextOnStack,208  isCurrentTreeHidden,209} from './ReactFiberHiddenContext';210import {findFirstSuspended} from './ReactFiberSuspenseComponent';211import {212  pushProvider,213  propagateContextChange,214  lazilyPropagateParentContextChanges,215  propagateParentContextChangesToDeferredTree,216  checkIfContextChanged,217  readContext,218  prepareToReadContext,219  scheduleContextWorkOnParentPath,220} from './ReactFiberNewContext';221import {222  renderWithHooks,223  checkDidRenderIdHook,224  bailoutHooks,225  replaySuspendedComponentWithHooks,226  renderTransitionAwareHostComponentWithHooks,227} from './ReactFiberHooks';228import {stopProfilerTimerIfRunning} from './ReactProfilerTimer';229import {230  getMaskedContext,231  getUnmaskedContext,232  hasContextChanged as hasLegacyContextChanged,233  pushContextProvider as pushLegacyContextProvider,234  isContextProvider as isLegacyContextProvider,235  pushTopLevelContextObject,236  invalidateContextProvider,237} from './ReactFiberLegacyContext';238import {239  getIsHydrating,240  enterHydrationState,241  reenterHydrationStateFromDehydratedActivityInstance,242  reenterHydrationStateFromDehydratedSuspenseInstance,243  resetHydrationState,244  claimHydratableSingleton,245  tryToClaimNextHydratableInstance,246  tryToClaimNextHydratableTextInstance,247  claimNextHydratableActivityInstance,248  claimNextHydratableSuspenseInstance,249  warnIfHydrating,250  queueHydrationError,251} from './ReactFiberHydrationContext';252import {253  constructClassInstance,254  mountClassInstance,255  resumeMountClassInstance,256  updateClassInstance,257  resolveClassComponentProps,258} from './ReactFiberClassComponent';259import {260  createFiberFromTypeAndProps,261  createFiberFromFragment,262  createFiberFromOffscreen,263  createWorkInProgress,264  isSimpleFunctionComponent,265  isFunctionClassComponent,266} from './ReactFiber';267import {268  scheduleUpdateOnFiber,269  renderDidSuspendDelayIfPossible,270  markSkippedUpdateLanes,271  markRenderDerivedCause,272  getWorkInProgressRoot,273  peekDeferredLane,274} from './ReactFiberWorkLoop';275import {enqueueConcurrentRenderForLane} from './ReactFiberConcurrentUpdates';276import {pushCacheProvider, CacheContext} from './ReactFiberCacheComponent';277import {278  createCapturedValueFromError,279  createCapturedValueAtFiber,280} from './ReactCapturedValue';281import {OffscreenVisible} from './ReactFiberOffscreenComponent';282import {283  createClassErrorUpdate,284  initializeClassErrorUpdate,285} from './ReactFiberThrow';286import {287  getForksAtLevel,288  isForkedChild,289  pushTreeId,290  pushMaterializedTreeId,291} from './ReactFiberTreeContext';292import {293  requestCacheFromPool,294  pushRootTransition,295  getSuspendedCache,296  pushTransition,297  getOffscreenDeferredCache,298  getPendingTransitions,299} from './ReactFiberTransition';300import {301  getMarkerInstances,302  pushMarkerInstance,303  pushRootMarkerInstance,304  TransitionTracingMarker,305} from './ReactFiberTracingMarkerComponent';306import {callComponentInDEV, callRenderInDEV} from './ReactFiberCallUserSpace';307import {resolveLazy} from './ReactFiberThenable';308309// A special exception that's used to unwind the stack when an update flows310// into a dehydrated boundary.311export const SelectiveHydrationException: mixed = new Error(312  "This is not a real error. It's an implementation detail of React's " +313    "selective hydration feature. If this leaks into userspace, it's a bug in " +314    'React. Please file an issue.',315);316317let didReceiveUpdate: boolean = false;318319let didWarnAboutBadClass;320let didWarnAboutContextTypeOnFunctionComponent;321let didWarnAboutContextTypes;322let didWarnAboutGetDerivedStateOnFunctionComponent;323export let didWarnAboutReassigningProps: boolean;324let didWarnAboutRevealOrder;325let didWarnAboutTailOptions;326let didWarnAboutClassNameOnViewTransition;327328if (__DEV__) {329  didWarnAboutBadClass = {} as {[string]: boolean};330  didWarnAboutContextTypeOnFunctionComponent = {} as {[string]: boolean};331  didWarnAboutContextTypes = {} as {[string]: boolean};332  didWarnAboutGetDerivedStateOnFunctionComponent = {} as {[string]: boolean};333  didWarnAboutReassigningProps = false;334  didWarnAboutRevealOrder = {} as {[string]: boolean};335  didWarnAboutTailOptions = {} as {[string]: boolean};336  didWarnAboutClassNameOnViewTransition = {} as {[string]: boolean};337}338339export function reconcileChildren(340  current: Fiber | null,341  workInProgress: Fiber,342  nextChildren: any,343  renderLanes: Lanes,344) {345  if (current === null) {346    // If this is a fresh new component that hasn't been rendered yet, we347    // won't update its child set by applying minimal side-effects. Instead,348    // we will add them all to the child before it gets rendered. That means349    // we can optimize this reconciliation pass by not tracking side-effects.350    workInProgress.child = mountChildFibers(351      workInProgress,352      null,353      nextChildren,354      renderLanes,355    );356  } else {357    // If the current child is the same as the work in progress, it means that358    // we haven't yet started any work on these children. Therefore, we use359    // the clone algorithm to create a copy of all the current children.360361    // If we had any progressed work already, that is invalid at this point so362    // let's throw it out.363    workInProgress.child = reconcileChildFibers(364      workInProgress,365      current.child,366      nextChildren,367      renderLanes,368    );369  }370}371372function forceUnmountCurrentAndReconcile(373  current: Fiber,374  workInProgress: Fiber,375  nextChildren: any,376  renderLanes: Lanes,377) {378  // This function is fork of reconcileChildren. It's used in cases where we379  // want to reconcile without matching against the existing set. This has the380  // effect of all current children being unmounted; even if the type and key381  // are the same, the old child is unmounted and a new child is created.382  //383  // To do this, we're going to go through the reconcile algorithm twice. In384  // the first pass, we schedule a deletion for all the current children by385  // passing null.386  workInProgress.child = reconcileChildFibers(387    workInProgress,388    current.child,389    null,390    renderLanes,391  );392  // In the second pass, we mount the new children. The trick here is that we393  // pass null in place of where we usually pass the current child set. This has394  // the effect of remounting all children regardless of whether their395  // identities match.396  workInProgress.child = reconcileChildFibers(397    workInProgress,398    null,399    nextChildren,400    renderLanes,401  );402}403404function updateForwardRef(405  current: Fiber | null,406  workInProgress: Fiber,407  Component: any,408  nextProps: any,409  renderLanes: Lanes,410) {411  // TODO: current can be non-null here even if the component412  // hasn't yet mounted. This happens after the first render suspends.413  // We'll need to figure out if this is fine or can cause issues.414  let render = Component.render;415  if (__DEV__) {416    const resolvedRender = resolveTypeForHotReloading(render);417    if (resolvedRender !== render) {418      render = resolvedRender;419      if (current !== null) {420        didReceiveUpdate = true;421      }422    }423  }424  const ref = workInProgress.ref;425426  let propsWithoutRef;427  if ('ref' in nextProps) {428    // `ref` is just a prop now, but `forwardRef` expects it to not appear in429    // the props object. This used to happen in the JSX runtime, but now we do430    // it here.431    propsWithoutRef = {} as {[string]: any};432    for (const key in nextProps) {433      // Since `ref` should only appear in props via the JSX transform, we can434      // assume that this is a plain object. So we don't need a435      // hasOwnProperty check.436      if (key !== 'ref') {437        propsWithoutRef[key] = nextProps[key];438      }439    }440  } else {441    propsWithoutRef = nextProps;442  }443444  // The rest is a fork of updateFunctionComponent445  prepareToReadContext(workInProgress, renderLanes);446  if (enableSchedulingProfiler) {447    markComponentRenderStarted(workInProgress);448  }449450  const nextChildren = renderWithHooks(451    current,452    workInProgress,453    render,454    propsWithoutRef,455    ref,456    renderLanes,457  );458  const hasId = checkDidRenderIdHook();459460  if (enableSchedulingProfiler) {461    markComponentRenderStopped();462  }463464  if (current !== null && !didReceiveUpdate) {465    bailoutHooks(current, workInProgress, renderLanes);466    return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);467  }468469  if (getIsHydrating() && hasId) {470    pushMaterializedTreeId(workInProgress);471  }472473  // React DevTools reads this flag.474  workInProgress.flags |= PerformedWork;475  reconcileChildren(current, workInProgress, nextChildren, renderLanes);476  return workInProgress.child;477}478479function updateMemoComponent(480  current: Fiber | null,481  workInProgress: Fiber,482  Component: any,483  nextProps: any,484  renderLanes: Lanes,485): null | Fiber {486  if (current === null) {487    const type = Component.type;488    if (isSimpleFunctionComponent(type) && Component.compare === null) {489      let resolvedType = type;490      if (__DEV__) {491        resolvedType = resolveTypeForHotReloading(type);492      }493      // If this is a plain function component without default props,494      // and with only the default shallow comparison, we upgrade it495      // to a SimpleMemoComponent to allow fast path updates.496      workInProgress.tag = SimpleMemoComponent;497      workInProgress.type = resolvedType;498      if (__DEV__) {499        validateFunctionComponentInDev(workInProgress, type);500      }501      return updateSimpleMemoComponent(502        current,503        workInProgress,504        resolvedType,505        nextProps,506        renderLanes,507      );508    }509    const child = createFiberFromTypeAndProps(510      Component.type,511      null,512      nextProps,513      workInProgress,514      workInProgress.mode,515      renderLanes,516    );517    child.ref = workInProgress.ref;518    child.return = workInProgress;519    workInProgress.child = child;520    return child;521  }522  const currentChild = current.child as any as Fiber; // This is always exactly one child523  const hasScheduledUpdateOrContext = checkScheduledUpdateOrContext(524    current,525    renderLanes,526  );527  if (!hasScheduledUpdateOrContext) {528    // This will be the props with resolved defaultProps,529    // unlike current.memoizedProps which will be the unresolved ones.530    const prevProps = currentChild.memoizedProps;531    // Default to shallow comparison532    let compare = Component.compare;533    compare = compare !== null ? compare : shallowEqual;534    if (compare(prevProps, nextProps) && current.ref === workInProgress.ref) {535      return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);536    }537  }538  // React DevTools reads this flag.539  workInProgress.flags |= PerformedWork;540  const newChild = createWorkInProgress(currentChild, nextProps);541  newChild.ref = workInProgress.ref;542  newChild.return = workInProgress;543  workInProgress.child = newChild;544  return newChild;545}546547function updateSimpleMemoComponent(548  current: Fiber | null,549  workInProgress: Fiber,550  Component: any,551  nextProps: any,552  renderLanes: Lanes,553): null | Fiber {554  // TODO: current can be non-null here even if the component555  // hasn't yet mounted. This happens when the inner render suspends.556  // We'll need to figure out if this is fine or can cause issues.557  if (current !== null) {558    const prevProps = current.memoizedProps;559    if (560      shallowEqual(prevProps, nextProps) &&561      current.ref === workInProgress.ref &&562      // Prevent bailout if the implementation changed due to hot reload.563      (__DEV__ ? workInProgress.type === current.type : true)564    ) {565      didReceiveUpdate = false;566567      // The props are shallowly equal. Reuse the previous props object, like we568      // would during a normal fiber bailout.569      //570      // We don't have strong guarantees that the props object is referentially571      // equal during updates where we can't bail out anyway — like if the props572      // are shallowly equal, but there's a local state or context update in the573      // same batch.574      //575      // However, as a principle, we should aim to make the behavior consistent576      // across different ways of memoizing a component. For example, React.memo577      // has a different internal Fiber layout if you pass a normal function578      // component (SimpleMemoComponent) versus if you pass a different type579      // like forwardRef (MemoComponent). But this is an implementation detail.580      // Wrapping a component in forwardRef (or React.lazy, etc) shouldn't581      // affect whether the props object is reused during a bailout.582      workInProgress.pendingProps = nextProps = prevProps;583584      if (!checkScheduledUpdateOrContext(current, renderLanes)) {585        // The pending lanes were cleared at the beginning of beginWork. We're586        // about to bail out, but there might be other lanes that weren't587        // included in the current render. Usually, the priority level of the588        // remaining updates is accumulated during the evaluation of the589        // component (i.e. when processing the update queue). But since since590        // we're bailing out early *without* evaluating the component, we need591        // to account for it here, too. Reset to the value of the current fiber.592        // NOTE: This only applies to SimpleMemoComponent, not MemoComponent,593        // because a MemoComponent fiber does not have hooks or an update queue;594        // rather, it wraps around an inner component, which may or may not595        // contains hooks.596        // TODO: Move the reset at in beginWork out of the common path so that597        // this is no longer necessary.598        workInProgress.lanes = current.lanes;599        return bailoutOnAlreadyFinishedWork(600          current,601          workInProgress,602          renderLanes,603        );604      } else if ((current.flags & ForceUpdateForLegacySuspense) !== NoFlags) {605        // This is a special case that only exists for legacy mode.606        // See https://github.com/facebook/react/pull/19216.607        didReceiveUpdate = true;608      }609    }610  }611  return updateFunctionComponent(612    current,613    workInProgress,614    Component,615    nextProps,616    renderLanes,617  );618}619620function updateOffscreenComponent(621  current: Fiber | null,622  workInProgress: Fiber,623  renderLanes: Lanes,624  nextProps: OffscreenProps,625) {626  const nextChildren = nextProps.children;627628  const prevState: OffscreenState | null =629    current !== null ? current.memoizedState : null;630631  if (current === null && workInProgress.stateNode === null) {632    // We previously reset the work-in-progress.633    // We need to create a new Offscreen instance.634    const primaryChildInstance: OffscreenInstance = {635      _visibility: OffscreenVisible,636      _pendingMarkers: null,637      _retryCache: null,638      _transitions: null,639    };640    workInProgress.stateNode = primaryChildInstance;641  }642643  if (644    nextProps.mode === 'hidden' ||645    (enableLegacyHidden && nextProps.mode === 'unstable-defer-without-hiding')646  ) {647    // Rendering a hidden tree.648649    const didSuspend = (workInProgress.flags & DidCapture) !== NoFlags;650    if (didSuspend) {651      // Something suspended inside a hidden tree652653      // Include the base lanes from the last render654      const nextBaseLanes =655        prevState !== null656          ? mergeLanes(prevState.baseLanes, renderLanes)657          : renderLanes;658659      let remainingChildLanes;660      if (current !== null) {661        // Reset to the current children662        let currentChild = (workInProgress.child = current.child);663664        // The current render suspended, but there may be other lanes with665        // pending work. We can't read `childLanes` from the current Offscreen666        // fiber because we reset it when it was deferred; however, we can read667        // the pending lanes from the child fibers.668        let currentChildLanes: Lanes = NoLanes;669        while (currentChild !== null) {670          currentChildLanes = mergeLanes(671            mergeLanes(currentChildLanes, currentChild.lanes),672            currentChild.childLanes,673          );674          currentChild = currentChild.sibling;675        }676        const lanesWeJustAttempted = nextBaseLanes;677        remainingChildLanes = removeLanes(678          currentChildLanes,679          lanesWeJustAttempted,680        );681      } else {682        remainingChildLanes = NoLanes;683        workInProgress.child = null;684      }685686      return deferHiddenOffscreenComponent(687        current,688        workInProgress,689        nextBaseLanes,690        renderLanes,691        remainingChildLanes,692      );693    }694695    if (696      !disableLegacyMode &&697      (workInProgress.mode & ConcurrentMode) === NoMode698    ) {699      // In legacy sync mode, don't defer the subtree. Render it now.700      // TODO: Consider how Offscreen should work with transitions in the future701      const nextState: OffscreenState = {702        baseLanes: NoLanes,703        cachePool: null,704      };705      workInProgress.memoizedState = nextState;706      // push the cache pool even though we're going to bail out707      // because otherwise there'd be a context mismatch708      if (current !== null) {709        pushTransition(workInProgress, null, null);710      }711      reuseHiddenContextOnStack(workInProgress);712      pushOffscreenSuspenseHandler(workInProgress);713    } else if (!includesSomeLane(renderLanes, OffscreenLane as Lane)) {714      // We're hidden, and we're not rendering at Offscreen. We will bail out715      // and resume this tree later.716717      // Schedule this fiber to re-render at Offscreen priority718719      const remainingChildLanes = (workInProgress.lanes =720        laneToLanes(OffscreenLane));721722      // Include the base lanes from the last render723      const nextBaseLanes =724        prevState !== null725          ? mergeLanes(prevState.baseLanes, renderLanes)726          : renderLanes;727728      return deferHiddenOffscreenComponent(729        current,730        workInProgress,731        nextBaseLanes,732        renderLanes,733        remainingChildLanes,734      );735    } else {736      // This is the second render. The surrounding visible content has already737      // committed. Now we resume rendering the hidden tree.738739      // Rendering at offscreen, so we can clear the base lanes.740      const nextState: OffscreenState = {741        baseLanes: NoLanes,742        cachePool: null,743      };744      workInProgress.memoizedState = nextState;745      if (current !== null) {746        // If the render that spawned this one accessed the cache pool, resume747        // using the same cache. Unless the parent changed, since that means748        // there was a refresh.749        const prevCachePool = prevState !== null ? prevState.cachePool : null;750        // TODO: Consider if and how Offscreen pre-rendering should751        // be attributed to the transition that spawned it752        pushTransition(workInProgress, prevCachePool, null);753      }754755      // Push the lanes that were skipped when we bailed out.756      if (prevState !== null) {757        pushHiddenContext(workInProgress, prevState);758      } else {759        reuseHiddenContextOnStack(workInProgress);760      }761      pushOffscreenSuspenseHandler(workInProgress);762    }763  } else {764    // Rendering a visible tree.765    if (prevState !== null) {766      // We're going from hidden -> visible.767      let prevCachePool = null;768      // If the render that spawned this one accessed the cache pool, resume769      // using the same cache. Unless the parent changed, since that means770      // there was a refresh.771      prevCachePool = prevState.cachePool;772773      let transitions = null;774      if (enableTransitionTracing) {775        // We have now gone from hidden to visible, so any transitions should776        // be added to the stack to get added to any Offscreen/suspense children777        const instance: OffscreenInstance | null = workInProgress.stateNode;778        if (instance !== null && instance._transitions != null) {779          transitions = Array.from(instance._transitions);780        }781      }782783      pushTransition(workInProgress, prevCachePool, transitions);784785      // Push the lanes that were skipped when we bailed out.786      pushHiddenContext(workInProgress, prevState);787      reuseSuspenseHandlerOnStack(workInProgress);788789      // Since we're not hidden anymore, reset the state790      workInProgress.memoizedState = null;791    } else {792      // We weren't previously hidden, and we still aren't, so there's nothing793      // special to do. Need to push to the stack regardless, though, to avoid794      // a push/pop misalignment.795796      // If the render that spawned this one accessed the cache pool, resume797      // using the same cache. Unless the parent changed, since that means798      // there was a refresh.799      if (current !== null) {800        pushTransition(workInProgress, null, null);801      }802803      // We're about to bail out, but we need to push this to the stack anyway804      // to avoid a push/pop misalignment.805      reuseHiddenContextOnStack(workInProgress);806      reuseSuspenseHandlerOnStack(workInProgress);807    }808  }809810  reconcileChildren(current, workInProgress, nextChildren, renderLanes);811  return workInProgress.child;812}813814function bailoutOffscreenComponent(815  current: Fiber | null,816  workInProgress: Fiber,817): Fiber | null {818  if (819    (current === null || current.tag !== OffscreenComponent) &&820    workInProgress.stateNode === null821  ) {822    const primaryChildInstance: OffscreenInstance = {823      _visibility: OffscreenVisible,824      _pendingMarkers: null,825      _retryCache: null,826      _transitions: null,827    };828    workInProgress.stateNode = primaryChildInstance;829  }830831  return workInProgress.sibling;832}833834function deferHiddenOffscreenComponent(835  current: Fiber | null,836  workInProgress: Fiber,837  nextBaseLanes: Lanes,838  renderLanes: Lanes,839  remainingChildLanes: Lanes,840) {841  const nextState: OffscreenState = {842    baseLanes: nextBaseLanes,843    // Save the cache pool so we can resume later.844    cachePool: getOffscreenDeferredCache(),845  };846  workInProgress.memoizedState = nextState;847  // push the cache pool even though we're going to bail out848  // because otherwise there'd be a context mismatch849  if (current !== null) {850    pushTransition(workInProgress, null, null);851  }852853  // We're about to bail out, but we need to push this to the stack anyway854  // to avoid a push/pop misalignment.855  reuseHiddenContextOnStack(workInProgress);856857  pushOffscreenSuspenseHandler(workInProgress);858859  if (current !== null) {860    // Since this tree will resume rendering in a separate render, we need861    // to propagate parent contexts now so we don't lose track of which862    // ones changed.863    propagateParentContextChangesToDeferredTree(864      current,865      workInProgress,866      renderLanes,867    );868  }869870  // We override the remaining child lanes to be the subset that we computed871  // on the outside. We need to do this after propagating the context872  // because propagateParentContextChangesToDeferredTree may schedule873  // work which bubbles all the way up to the root and updates our child lanes.874  // We want to dismiss that since we're not going to work on it yet.875  workInProgress.childLanes = remainingChildLanes;876877  return null;878}879880function updateLegacyHiddenComponent(881  current: null | Fiber,882  workInProgress: Fiber,883  renderLanes: Lanes,884) {885  const nextProps: LegacyHiddenProps = workInProgress.pendingProps;886  // Note: These happen to have identical begin phases, for now. We shouldn't hold887  // ourselves to this constraint, though. If the behavior diverges, we should888  // fork the function.889  // This just works today because it has the same Props.890  return updateOffscreenComponent(891    current,892    workInProgress,893    renderLanes,894    nextProps,895  );896}897898function mountActivityChildren(899  workInProgress: Fiber,900  nextProps: ActivityProps,901  renderLanes: Lanes,902) {903  if (__DEV__) {904    const hiddenProp = (nextProps as any).hidden;905    if (hiddenProp !== undefined) {906      console.error(907        '<Activity> doesn\'t accept a hidden prop. Use mode="hidden" instead.\n' +908          '- <Activity %s>\n' +909          '+ <Activity %s>',910        hiddenProp === true911          ? 'hidden'912          : hiddenProp === false913            ? 'hidden={false}'914            : 'hidden={...}',915        hiddenProp ? 'mode="hidden"' : 'mode="visible"',916      );917    }918  }919  const nextChildren = nextProps.children;920  const nextMode = nextProps.mode;921  const mode = workInProgress.mode;922  const offscreenChildProps: OffscreenProps = {923    mode: nextMode,924    children: nextChildren,925  };926  const primaryChildFragment = mountWorkInProgressOffscreenFiber(927    offscreenChildProps,928    mode,929    renderLanes,930  );931  primaryChildFragment.ref = workInProgress.ref;932  workInProgress.child = primaryChildFragment;933  primaryChildFragment.return = workInProgress;934  return primaryChildFragment;935}936937function retryActivityComponentWithoutHydrating(938  current: Fiber,939  workInProgress: Fiber,940  renderLanes: Lanes,941) {942  // Falling back to client rendering. Because this has performance943  // implications, it's considered a recoverable error, even though the user944  // likely won't observe anything wrong with the UI.945946  // This will add the old fiber to the deletion list947  reconcileChildFibers(workInProgress, current.child, null, renderLanes);948949  // We're now not suspended nor dehydrated.950  const nextProps: ActivityProps = workInProgress.pendingProps;951  const primaryChildFragment = mountActivityChildren(952    workInProgress,953    nextProps,954    renderLanes,955  );956  // Needs a placement effect because the parent (the Activity boundary) already957  // mounted but this is a new fiber.958  primaryChildFragment.flags |= Placement;959960  // If we're not going to hydrate we can't leave it dehydrated if something961  // suspends. In that case we want that to bubble to the nearest parent boundary962  // so we need to pop our own handler that we just pushed.963  popSuspenseHandler(workInProgress);964965  workInProgress.memoizedState = null;966967  return primaryChildFragment;968}969970function mountDehydratedActivityComponent(971  workInProgress: Fiber,972  activityInstance: ActivityInstance,973  renderLanes: Lanes,974): null | Fiber {975  // During the first pass, we'll bail out and not drill into the children.976  // Instead, we'll leave the content in place and try to hydrate it later.977  // We'll continue hydrating the rest at offscreen priority since we'll already978  // be showing the right content coming from the server, it is no rush.979  workInProgress.lanes = laneToLanes(OffscreenLane);980  return null;981}982983function updateDehydratedActivityComponent(984  current: Fiber,985  workInProgress: Fiber,986  didSuspend: boolean,987  nextProps: ActivityProps,988  activityInstance: ActivityInstance,989  activityState: ActivityState,990  renderLanes: Lanes,991): null | Fiber {992  // We'll handle suspending since if something suspends we can just leave993  // it dehydrated. We push early and then pop if we enter non-dehydrated attempts.994  pushDehydratedActivitySuspenseHandler(workInProgress);995  if (!didSuspend) {996    // This is the first render pass. Attempt to hydrate.997998    // We should never be hydrating at this point because it is the first pass,999    // but after we've already committed once.1000    warnIfHydrating();10011002    if (includesSomeLane(renderLanes, OffscreenLane as Lane)) {1003      // If we're rendering Offscreen and we're entering the activity then it's possible1004      // that the only reason we rendered was because this boundary left work. Provide1005      // it as a cause if another one doesn't already exist.1006      markRenderDerivedCause(workInProgress);1007    }10081009    if (1010      // TODO: Factoring is a little weird, since we check this right below, too.1011      !didReceiveUpdate1012    ) {1013      // We need to check if any children have context before we decide to bail1014      // out, so propagate the changes now.1015      lazilyPropagateParentContextChanges(current, workInProgress, renderLanes);1016    }10171018    // We use lanes to indicate that a child might depend on context, so if1019    // any context has changed, we need to treat is as if the input might have changed.1020    const hasContextChanged = includesSomeLane(renderLanes, current.childLanes);1021    if (didReceiveUpdate || hasContextChanged) {1022      // This boundary has changed since the first render. This means that we are now unable to1023      // hydrate it. We might still be able to hydrate it using a higher priority lane.1024      if (isCurrentTreeHidden()) {1025        // This boundary is inside a hidden subtree, where all work is1026        // deferred until the tree is revealed. Selective hydration works by1027        // rendering the boundary at a higher priority before the update1028        // applies, so it can't make progress here; delaying the commit to1029        // wait for it would deadlock. Replacing hidden content isn't1030        // visible, so give up and client render.1031        return retryActivityComponentWithoutHydrating(1032          current,1033          workInProgress,1034          renderLanes,1035        );1036      }1037      const root = getWorkInProgressRoot();1038      if (root !== null) {1039        const attemptHydrationAtLane = getBumpedLaneForHydration(1040          root,1041          renderLanes,1042        );1043        if (1044          attemptHydrationAtLane !== NoLane &&1045          attemptHydrationAtLane !== activityState.retryLane1046        ) {1047          // Intentionally mutating since this render will get interrupted. This1048          // is one of the very rare times where we mutate the current tree1049          // during the render phase.1050          activityState.retryLane = attemptHydrationAtLane;1051          enqueueConcurrentRenderForLane(current, attemptHydrationAtLane);1052          scheduleUpdateOnFiber(root, current, attemptHydrationAtLane);10531054          // Throw a special object that signals to the work loop that it should1055          // interrupt the current render.1056          //1057          // Because we're inside a React-only execution stack, we don't1058          // strictly need to throw here — we could instead modify some internal1059          // work loop state. But using an exception means we don't need to1060          // check for this case on every iteration of the work loop. So doing1061          // it this way moves the check out of the fast path.1062          throw SelectiveHydrationException;1063        } else {1064          // We have already tried to ping at a higher priority than we're rendering with1065          // so if we got here, we must have failed to hydrate at those levels. We must1066          // now give up. Instead, we're going to delete the whole subtree and instead inject1067          // a new real Activity boundary to take its place. This might suspend for a while1068          // and if it does we might still have an opportunity to hydrate before this pass1069          // commits.1070        }1071      }10721073      // If we did not selectively hydrate, we'll continue rendering without1074      // hydrating. Mark this tree as suspended to prevent it from committing1075      // outside a transition.1076      //1077      // This path should only happen if the hydration lane already suspended.1078      renderDidSuspendDelayIfPossible();1079      return retryActivityComponentWithoutHydrating(1080        current,1081        workInProgress,1082        renderLanes,1083      );1084    } else {1085      // This is the first attempt.10861087      reenterHydrationStateFromDehydratedActivityInstance(1088        workInProgress,1089        activityInstance,1090        activityState.treeContext,1091      );10921093      const primaryChildFragment = mountActivityChildren(1094        workInProgress,1095        nextProps,1096        renderLanes,1097      );1098      // Mark the children as hydrating. This is a fast path to know whether this1099      // tree is part of a hydrating tree. This is used to determine if a child1100      // node has fully mounted yet, and for scheduling event replaying.1101      // Conceptually this is similar to Placement in that a new subtree is1102      // inserted into the React tree here. It just happens to not need DOM1103      // mutations because it already exists.1104      // We should still treat it as a newly inserted Fiber to double invoke Strict Effects.1105      primaryChildFragment.flags |= Hydrating | PlacementDEV;1106      return primaryChildFragment;1107    }1108  } else {1109    // This is the second render pass. We already attempted to hydrated, but1110    // something either suspended or errored.11111112    if (workInProgress.flags & ForceClientRender) {1113      // Something errored during hydration. Try again without hydrating.1114      // The error should've already been logged in throwException.1115      workInProgress.flags &= ~ForceClientRender;1116      return retryActivityComponentWithoutHydrating(1117        current,1118        workInProgress,1119        renderLanes,1120      );1121    } else if (1122      (workInProgress.memoizedState as null | ActivityState) !== null1123    ) {1124      // Something suspended and we should still be in dehydrated mode.1125      // Leave the existing child in place.11261127      workInProgress.child = current.child;1128      // The dehydrated completion pass expects this flag to be there1129      // but the normal offscreen pass doesn't.1130      workInProgress.flags |= DidCapture;1131      return null;1132    } else {1133      // We called retryActivityComponentWithoutHydrating and tried client rendering1134      // but now we suspended again. We should never arrive here because we should1135      // not have pushed a suspense handler during that second pass and it should1136      // instead have suspended above.1137      throw new Error(1138        'Client rendering an Activity suspended it again. This is a bug in React.',1139      );1140    }1141  }1142}11431144function updateActivityComponent(1145  current: null | Fiber,1146  workInProgress: Fiber,1147  renderLanes: Lanes,1148) {1149  const nextProps: ActivityProps = workInProgress.pendingProps;11501151  // Check if the first pass suspended.1152  const didSuspend = (workInProgress.flags & DidCapture) !== NoFlags;1153  workInProgress.flags &= ~DidCapture;11541155  if (current === null) {1156    // Initial mount11571158    // Special path for hydration1159    // If we're currently hydrating, try to hydrate this boundary.1160    // Hidden Activity boundaries are not emitted on the server.1161    if (getIsHydrating()) {1162      if (nextProps.mode === 'hidden') {1163        // SSR doesn't render hidden Activity so it shouldn't hydrate,1164        // even at offscreen lane. Defer to a client rendered offscreen lane.1165        const primaryChildFragment = mountActivityChildren(1166          workInProgress,1167          nextProps,1168          renderLanes,1169        );1170        workInProgress.lanes = laneToLanes(OffscreenLane);1171        // This tree hasn't been mounted yet so there are no baseLanes to carry over.1172        const nextState: OffscreenState = {1173          baseLanes: NoLanes,1174          cachePool: null,1175        };1176        primaryChildFragment.memoizedState = nextState;11771178        return bailoutOffscreenComponent(null, primaryChildFragment);1179      } else {1180        // We must push the suspense handler context *before* attempting to1181        // hydrate, to avoid a mismatch in case it errors.1182        pushDehydratedActivitySuspenseHandler(workInProgress);1183        const dehydrated: ActivityInstance =1184          claimNextHydratableActivityInstance(workInProgress);1185        return mountDehydratedActivityComponent(1186          workInProgress,1187          dehydrated,1188          renderLanes,1189        );1190      }1191    }11921193    return mountActivityChildren(workInProgress, nextProps, renderLanes);1194  } else {1195    // This is an update.11961197    // Special path for hydration1198    const prevState: null | ActivityState = current.memoizedState;11991200    if (prevState !== null) {1201      const dehydrated = prevState.dehydrated;1202      return updateDehydratedActivityComponent(1203        current,1204        workInProgress,1205        didSuspend,1206        nextProps,1207        dehydrated,1208        prevState,1209        renderLanes,1210      );1211    }12121213    const currentChild: Fiber = current.child as any;12141215    const nextChildren = nextProps.children;1216    const nextMode = nextProps.mode;1217    const offscreenChildProps: OffscreenProps = {1218      mode: nextMode,1219      children: nextChildren,1220    };12211222    if (1223      includesSomeLane(renderLanes, OffscreenLane as Lane) &&1224      includesSomeLane(renderLanes, current.lanes)1225    ) {1226      // If we're rendering Offscreen and we're entering the activity then it's possible1227      // that the only reason we rendered was because this boundary left work. Provide1228      // it as a cause if another one doesn't already exist.1229      markRenderDerivedCause(workInProgress);1230    }12311232    const primaryChildFragment = updateWorkInProgressOffscreenFiber(1233      currentChild,1234      offscreenChildProps,1235    );12361237    primaryChildFragment.ref = workInProgress.ref;1238    workInProgress.child = primaryChildFragment;1239    primaryChildFragment.return = workInProgress;1240    return primaryChildFragment;1241  }1242}12431244function updateCacheComponent(1245  current: Fiber | null,1246  workInProgress: Fiber,1247  renderLanes: Lanes,1248) {1249  prepareToReadContext(workInProgress, renderLanes);1250  const parentCache = readContext(CacheContext);12511252  if (current === null) {1253    // Initial mount. Request a fresh cache from the pool.1254    const freshCache = requestCacheFromPool(renderLanes);1255    const initialState: CacheComponentState = {1256      parent: parentCache,1257      cache: freshCache,1258    };1259    workInProgress.memoizedState = initialState;1260    initializeUpdateQueue(workInProgress);1261    pushCacheProvider(workInProgress, freshCache);1262  } else {1263    // Check for updates1264    if (includesSomeLane(current.lanes, renderLanes)) {1265      cloneUpdateQueue(current, workInProgress);1266      processUpdateQueue(workInProgress, null, null, renderLanes);1267      suspendIfUpdateReadFromEntangledAsyncAction();1268    }1269    const prevState: CacheComponentState = current.memoizedState;1270    const nextState: CacheComponentState = workInProgress.memoizedState;12711272    // Compare the new parent cache to the previous to see detect there was1273    // a refresh.1274    if (prevState.parent !== parentCache) {1275      // Refresh in parent. Update the parent.1276      const derivedState: CacheComponentState = {1277        parent: parentCache,1278        cache: parentCache,1279      };12801281      // Copied from getDerivedStateFromProps implementation. Once the update1282      // queue is empty, persist the derived state onto the base state.1283      workInProgress.memoizedState = derivedState;1284      if (workInProgress.lanes === NoLanes) {1285        const updateQueue: UpdateQueue<any> = workInProgress.updateQueue as any;1286        workInProgress.memoizedState = updateQueue.baseState = derivedState;1287      }12881289      pushCacheProvider(workInProgress, parentCache);1290      // No need to propagate a context change because the refreshed parent1291      // already did.1292    } else {1293      // The parent didn't refresh. Now check if this cache did.1294      const nextCache = nextState.cache;1295      pushCacheProvider(workInProgress, nextCache);1296      if (nextCache !== prevState.cache) {1297        // This cache refreshed. Propagate a context change.1298        propagateContextChange(workInProgress, CacheContext, renderLanes);1299      }1300    }1301  }13021303  const nextProps: CacheProps = workInProgress.pendingProps;13041305  const nextChildren = nextProps.children;1306  reconcileChildren(current, workInProgress, nextChildren, renderLanes);1307  return workInProgress.child;1308}13091310// This should only be called if the name changes1311function updateTracingMarkerComponent(1312  current: Fiber | null,1313  workInProgress: Fiber,1314  renderLanes: Lanes,1315) {1316  if (!enableTransitionTracing) {1317    return null;1318  }13191320  const nextProps: TracingMarkerProps = workInProgress.pendingProps;13211322  // TODO: (luna) Only update the tracing marker if it's newly rendered or it's name changed.1323  // A tracing marker is only associated with the transitions that rendered1324  // or updated it, so we can create a new set of transitions each time1325  if (current === null) {1326    const currentTransitions = getPendingTransitions();1327    if (currentTransitions !== null) {1328      const markerInstance: TracingMarkerInstance = {1329        tag: TransitionTracingMarker,1330        transitions: new Set(currentTransitions),1331        pendingBoundaries: null,1332        name: nextProps.name,1333        aborts: null,1334      };1335      workInProgress.stateNode = markerInstance;13361337      // We call the marker complete callback when all child suspense boundaries resolve.1338      // We do this in the commit phase on Offscreen. If the marker has no child suspense1339      // boundaries, we need to schedule a passive effect to make sure we call the marker1340      // complete callback.1341      workInProgress.flags |= Passive;1342    }1343  } else {1344    if (__DEV__) {1345      if (current.memoizedProps.name !== nextProps.name) {1346        console.error(1347          'Changing the name of a tracing marker after mount is not supported. ' +1348            'To remount the tracing marker, pass it a new key.',1349        );1350      }1351    }1352  }13531354  const instance: TracingMarkerInstance | null = workInProgress.stateNode;1355  if (instance !== null) {1356    pushMarkerInstance(workInProgress, instance);1357  }1358  const nextChildren = nextProps.children;1359  reconcileChildren(current, workInProgress, nextChildren, renderLanes);1360  return workInProgress.child;1361}13621363function updateFragment(1364  current: Fiber | null,1365  workInProgress: Fiber,1366  renderLanes: Lanes,1367) {1368  const nextChildren = workInProgress.pendingProps;1369  if (enableFragmentRefs) {1370    markRef(current, workInProgress);1371  }1372  reconcileChildren(current, workInProgress, nextChildren, renderLanes);1373  return workInProgress.child;1374}13751376function updateMode(1377  current: Fiber | null,1378  workInProgress: Fiber,1379  renderLanes: Lanes,1380) {1381  const nextChildren = workInProgress.pendingProps.children;1382  reconcileChildren(current, workInProgress, nextChildren, renderLanes);1383  return workInProgress.child;1384}13851386function updateProfiler(1387  current: Fiber | null,1388  workInProgress: Fiber,1389  renderLanes: Lanes,1390) {1391  if (enableProfilerTimer) {1392    workInProgress.flags |= Update;13931394    if (enableProfilerCommitHooks) {1395      // Schedule a passive effect for this Profiler to call onPostCommit hooks.1396      // This effect should be scheduled even if there is no onPostCommit callback for this Profiler,1397      // because the effect is also where times bubble to parent Profilers.1398      workInProgress.flags |= Passive;1399      // Reset effect durations for the next eventual effect phase.1400      // These are reset during render to allow the DevTools commit hook a chance to read them,1401      const stateNode = workInProgress.stateNode;1402      stateNode.effectDuration = -0;1403      stateNode.passiveEffectDuration = -0;1404    }1405  }1406  const nextProps: ProfilerProps = workInProgress.pendingProps;1407  const nextChildren = nextProps.children;1408  reconcileChildren(current, workInProgress, nextChildren, renderLanes);1409  return workInProgress.child;1410}14111412function markRef(current: Fiber | null, workInProgress: Fiber) {1413  // TODO: Check props.ref instead of fiber.ref when enableRefAsProp is on.1414  const ref = workInProgress.ref;1415  if (ref === null) {1416    if (current !== null && current.ref !== null) {1417      // Schedule a Ref effect1418      workInProgress.flags |= Ref | RefStatic;1419    }1420  } else {1421    if (typeof ref !== 'function' && typeof ref !== 'object') {1422      throw new Error(1423        'Expected ref to be a function, an object returned by React.createRef(), or undefined/null.',1424      );1425    }1426    if (current === null || current.ref !== ref) {1427      // Schedule a Ref effect1428      workInProgress.flags |= Ref | RefStatic;1429    }1430  }1431}14321433function mountIncompleteFunctionComponent(1434  _current: null | Fiber,1435  workInProgress: Fiber,1436  Component: any,1437  nextProps: any,1438  renderLanes: Lanes,1439) {1440  resetSuspendedCurrentOnMountInLegacyMode(_current, workInProgress);14411442  workInProgress.tag = FunctionComponent;14431444  return updateFunctionComponent(1445    null,1446    workInProgress,1447    Component,1448    nextProps,1449    renderLanes,1450  );1451}14521453function updateFunctionComponent(1454  current: null | Fiber,1455  workInProgress: Fiber,1456  Component: any,1457  nextProps: any,1458  renderLanes: Lanes,1459) {1460  if (__DEV__) {1461    if (1462      Component.prototype &&1463      typeof Component.prototype.render === 'function'1464    ) {1465      const componentName = getComponentNameFromType(Component) || 'Unknown';14661467      if (!didWarnAboutBadClass[componentName]) {1468        console.error(1469          "The <%s /> component appears to have a render method, but doesn't extend React.Component. " +1470            'This is likely to cause errors. Change %s to extend React.Component instead.',1471          componentName,1472          componentName,1473        );1474        didWarnAboutBadClass[componentName] = true;1475      }1476    }14771478    if (workInProgress.mode & StrictLegacyMode) {1479      ReactStrictModeWarnings.recordLegacyContextWarning(workInProgress, null);1480    }14811482    if (current === null) {1483      // Some validations were previously done in mountIndeterminateComponent however and are now run1484      // in updateFuntionComponent but only on mount1485      validateFunctionComponentInDev(workInProgress, workInProgress.type);14861487      if (Component.contextTypes) {1488        const componentName = getComponentNameFromType(Component) || 'Unknown';14891490        if (!didWarnAboutContextTypes[componentName]) {1491          didWarnAboutContextTypes[componentName] = true;1492          if (disableLegacyContext) {1493            console.error(1494              '%s uses the legacy contextTypes API which was removed in React 19. ' +1495                'Use React.createContext() with React.useContext() instead. ' +1496                '(https://react.dev/link/legacy-context)',1497              componentName,1498            );1499          } else {1500            console.error(1501              '%s uses the legacy contextTypes API which will be removed soon. ' +1502                'Use React.createContext() with React.useContext() instead. ' +1503                '(https://react.dev/link/legacy-context)',1504              componentName,1505            );1506          }1507        }1508      }1509    }1510  }15111512  let context;1513  if (!disableLegacyContext && !disableLegacyContextForFunctionComponents) {1514    const unmaskedContext = getUnmaskedContext(workInProgress, Component, true);1515    context = getMaskedContext(workInProgress, unmaskedContext);1516  }15171518  let nextChildren;1519  let hasId;1520  prepareToReadContext(workInProgress, renderLanes);1521  if (enableSchedulingProfiler) {1522    markComponentRenderStarted(workInProgress);1523  }1524  if (__DEV__) {1525    nextChildren = renderWithHooks(1526      current,1527      workInProgress,1528      Component,1529      nextProps,1530      context,1531      renderLanes,1532    );1533    hasId = checkDidRenderIdHook();1534  } else {1535    nextChildren = renderWithHooks(1536      current,1537      workInProgress,1538      Component,1539      nextProps,1540      context,1541      renderLanes,1542    );1543    hasId = checkDidRenderIdHook();1544  }1545  if (enableSchedulingProfiler) {1546    markComponentRenderStopped();1547  }15481549  if (current !== null && !didReceiveUpdate) {1550    bailoutHooks(current, workInProgress, renderLanes);1551    return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);1552  }15531554  if (getIsHydrating() && hasId) {1555    pushMaterializedTreeId(workInProgress);1556  }15571558  // React DevTools reads this flag.1559  workInProgress.flags |= PerformedWork;1560  reconcileChildren(current, workInProgress, nextChildren, renderLanes);1561  return workInProgress.child;1562}15631564export function replayFunctionComponent(1565  current: Fiber | null,1566  workInProgress: Fiber,1567  nextProps: any,1568  Component: any,1569  secondArg: any,1570  renderLanes: Lanes,1571): Fiber | null {1572  // This function is used to replay a component that previously suspended,1573  // after its data resolves. It's a simplified version of1574  // updateFunctionComponent that reuses the hooks from the previous attempt.15751576  prepareToReadContext(workInProgress, renderLanes);1577  if (enableSchedulingProfiler) {1578    markComponentRenderStarted(workInProgress);1579  }1580  const nextChildren = replaySuspendedComponentWithHooks(1581    current,1582    workInProgress,1583    Component,1584    nextProps,1585    secondArg,1586  );1587  const hasId = checkDidRenderIdHook();1588  if (enableSchedulingProfiler) {1589    markComponentRenderStopped();1590  }15911592  if (current !== null && !didReceiveUpdate) {1593    bailoutHooks(current, workInProgress, renderLanes);1594    return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);1595  }15961597  if (getIsHydrating() && hasId) {1598    pushMaterializedTreeId(workInProgress);1599  }16001601  // React DevTools reads this flag.1602  workInProgress.flags |= PerformedWork;1603  reconcileChildren(current, workInProgress, nextChildren, renderLanes);1604  return workInProgress.child;1605}16061607function updateClassComponent(1608  current: Fiber | null,1609  workInProgress: Fiber,1610  Component: any,1611  nextProps: any,1612  renderLanes: Lanes,1613) {1614  if (__DEV__) {1615    // This is used by DevTools to force a boundary to error.1616    switch (shouldError(workInProgress)) {1617      case false: {1618        // We previously simulated an error on this boundary1619        // so the instance must have been constructed in a previous1620        // commit.1621        const instance = workInProgress.stateNode;1622        const ctor = workInProgress.type;1623        // TODO This way of resetting the error boundary state is a hack.1624        // Is there a better way to do this?1625        const tempInstance = new ctor(1626          workInProgress.memoizedProps,1627          instance.context,1628        );1629        const state = tempInstance.state;1630        instance.updater.enqueueSetState(instance, state, null);1631        break;1632      }1633      case true: {1634        workInProgress.flags |= DidCapture;1635        workInProgress.flags |= ShouldCapture;1636        // eslint-disable-next-line react-internal/prod-error-codes1637        const error = new Error('Simulated error coming from DevTools');1638        const lane = pickArbitraryLane(renderLanes);1639        workInProgress.lanes = mergeLanes(workInProgress.lanes, lane);1640        // Schedule the error boundary to re-render using updated state1641        const root: FiberRoot | null = getWorkInProgressRoot();1642        if (root === null) {1643          throw new Error(1644            'Expected a work-in-progress root. This is a bug in React. Please file an issue.',1645          );1646        }1647        const update = createClassErrorUpdate(lane);1648        initializeClassErrorUpdate(1649          update,1650          root,1651          workInProgress,1652          createCapturedValueAtFiber(error, workInProgress),1653        );1654        enqueueCapturedUpdate(workInProgress, update);1655        break;1656      }1657    }1658  }16591660  // Push context providers early to prevent context stack mismatches.1661  // During mounting we don't know the child context yet as the instance doesn't exist.1662  // We will invalidate the child context in finishClassComponent() right after rendering.1663  let hasContext;1664  if (isLegacyContextProvider(Component)) {1665    hasContext = true;1666    pushLegacyContextProvider(workInProgress);1667  } else {1668    hasContext = false;1669  }1670  prepareToReadContext(workInProgress, renderLanes);16711672  const instance = workInProgress.stateNode;1673  let shouldUpdate;1674  if (instance === null) {1675    resetSuspendedCurrentOnMountInLegacyMode(current, workInProgress);16761677    // In the initial pass we might need to construct the instance.1678    constructClassInstance(workInProgress, Component, nextProps);1679    mountClassInstance(workInProgress, Component, nextProps, renderLanes);1680    shouldUpdate = true;1681  } else if (current === null) {1682    // In a resume, we'll already have an instance we can reuse.1683    shouldUpdate = resumeMountClassInstance(1684      workInProgress,1685      Component,1686      nextProps,1687      renderLanes,1688    );1689  } else {1690    shouldUpdate = updateClassInstance(1691      current,1692      workInProgress,1693      Component,1694      nextProps,1695      renderLanes,1696    );1697  }1698  const nextUnitOfWork = finishClassComponent(1699    current,1700    workInProgress,1701    Component,1702    shouldUpdate,1703    hasContext,1704    renderLanes,1705  );1706  if (__DEV__) {1707    const inst = workInProgress.stateNode;1708    if (shouldUpdate && inst.props !== nextProps) {1709      if (!didWarnAboutReassigningProps) {1710        console.error(1711          'It looks like %s is reassigning its own `this.props` while rendering. ' +1712            'This is not supported and can lead to confusing bugs.',1713          getComponentNameFromFiber(workInProgress) || 'a component',1714        );1715      }1716      didWarnAboutReassigningProps = true;1717    }1718  }1719  return nextUnitOfWork;1720}17211722function finishClassComponent(1723  current: Fiber | null,1724  workInProgress: Fiber,1725  Component: any,1726  shouldUpdate: boolean,1727  hasContext: boolean,1728  renderLanes: Lanes,1729) {1730  // Refs should update even if shouldComponentUpdate returns false1731  markRef(current, workInProgress);17321733  const didCaptureError = (workInProgress.flags & DidCapture) !== NoFlags;17341735  if (!shouldUpdate && !didCaptureError) {1736    // Context providers should defer to sCU for rendering1737    if (hasContext) {1738      invalidateContextProvider(workInProgress, Component, false);1739    }17401741    return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);1742  }17431744  const instance = workInProgress.stateNode;17451746  // Rerender1747  if (__DEV__) {1748    setCurrentFiber(workInProgress);1749  }1750  let nextChildren;1751  if (1752    didCaptureError &&1753    typeof Component.getDerivedStateFromError !== 'function'1754  ) {1755    // If we captured an error, but getDerivedStateFromError is not defined,1756    // unmount all the children. componentDidCatch will schedule an update to1757    // re-render a fallback. This is temporary until we migrate everyone to1758    // the new API.1759    // TODO: Warn in a future release.1760    nextChildren = null;17611762    if (enableProfilerTimer) {1763      stopProfilerTimerIfRunning(workInProgress);1764    }1765  } else {1766    if (enableSchedulingProfiler) {1767      markComponentRenderStarted(workInProgress);1768    }1769    if (__DEV__) {1770      nextChildren = callRenderInDEV(instance);1771      if (workInProgress.mode & StrictLegacyMode) {1772        setIsStrictModeForDevtools(true);1773        try {1774          callRenderInDEV(instance);1775        } finally {1776          setIsStrictModeForDevtools(false);1777        }1778      }1779    } else {1780      nextChildren = instance.render();1781    }1782    if (enableSchedulingProfiler) {1783      markComponentRenderStopped();1784    }1785  }17861787  // React DevTools reads this flag.1788  workInProgress.flags |= PerformedWork;1789  if (current !== null && didCaptureError) {1790    // If we're recovering from an error, reconcile without reusing any of1791    // the existing children. Conceptually, the normal children and the children1792    // that are shown on error are two different sets, so we shouldn't reuse1793    // normal children even if their identities match.1794    forceUnmountCurrentAndReconcile(1795      current,1796      workInProgress,1797      nextChildren,1798      renderLanes,1799    );1800  } else {1801    reconcileChildren(current, workInProgress, nextChildren, renderLanes);1802  }18031804  // Memoize state using the values we just used to render.1805  // TODO: Restructure so we never read values from the instance.1806  workInProgress.memoizedState = instance.state;18071808  // The context might have changed so we need to recalculate it.1809  if (hasContext) {1810    invalidateContextProvider(workInProgress, Component, true);1811  }18121813  return workInProgress.child;1814}18151816function pushHostRootContext(workInProgress: Fiber) {1817  const root = workInProgress.stateNode as FiberRoot;1818  if (root.pendingContext) {1819    pushTopLevelContextObject(1820      workInProgress,1821      root.pendingContext,1822      root.pendingContext !== root.context,1823    );1824  } else if (root.context) {1825    // Should always be set1826    pushTopLevelContextObject(workInProgress, root.context, false);1827  }1828  pushHostContainer(workInProgress, root.containerInfo);1829}18301831function updateHostRoot(1832  current: null | Fiber,1833  workInProgress: Fiber,1834  renderLanes: Lanes,1835) {1836  pushHostRootContext(workInProgress);18371838  if (current === null) {1839    throw new Error('Should have a current fiber. This is a bug in React.');1840  }18411842  const nextProps = workInProgress.pendingProps;1843  const prevState: RootState = workInProgress.memoizedState;1844  const prevChildren = prevState.element;1845  cloneUpdateQueue(current, workInProgress);1846  processUpdateQueue(workInProgress, nextProps, null, renderLanes);18471848  const nextState: RootState = workInProgress.memoizedState;1849  const root: FiberRoot = workInProgress.stateNode;1850  pushRootTransition(workInProgress, root, renderLanes);18511852  if (enableTransitionTracing) {1853    pushRootMarkerInstance(workInProgress);1854  }18551856  const nextCache: Cache = nextState.cache;1857  pushCacheProvider(workInProgress, nextCache);1858  if (nextCache !== prevState.cache) {1859    // The root cache refreshed.1860    propagateContextChange(workInProgress, CacheContext, renderLanes);1861  }18621863  // This would ideally go inside processUpdateQueue, but because it suspends,1864  // it needs to happen after the `pushCacheProvider` call above to avoid a1865  // context stack mismatch. A bit unfortunate.1866  suspendIfUpdateReadFromEntangledAsyncAction();18671868  // Caution: React DevTools currently depends on this property1869  // being called "element".1870  const nextChildren = nextState.element;1871  // $FlowFixMe[constant-condition]1872  if (supportsHydration && prevState.isDehydrated) {1873    // This is a hydration root whose shell has not yet hydrated. We should1874    // attempt to hydrate.18751876    // Flip isDehydrated to false to indicate that when this render1877    // finishes, the root will no longer be dehydrated.1878    const overrideState: RootState = {1879      element: nextChildren,1880      isDehydrated: false,1881      cache: nextState.cache,1882    };1883    const updateQueue: UpdateQueue<RootState> =1884      workInProgress.updateQueue as any;1885    // `baseState` can always be the last state because the root doesn't1886    // have reducer functions so it doesn't need rebasing.1887    updateQueue.baseState = overrideState;1888    workInProgress.memoizedState = overrideState;18891890    if (workInProgress.flags & ForceClientRender) {1891      // Something errored during a previous attempt to hydrate the shell, so we1892      // forced a client render. We should have a recoverable error already scheduled.1893      return mountHostRootWithoutHydrating(1894        current,1895        workInProgress,1896        nextChildren,1897        renderLanes,1898      );1899    } else if (nextChildren !== prevChildren) {1900      const recoverableError = createCapturedValueAtFiber<mixed>(1901        new Error(1902          'This root received an early update, before anything was able ' +1903            'hydrate. Switched the entire root to client rendering.',1904        ),1905        workInProgress,1906      );1907      queueHydrationError(recoverableError);1908      return mountHostRootWithoutHydrating(1909        current,1910        workInProgress,1911        nextChildren,1912        renderLanes,1913      );1914    } else {1915      // The outermost shell has not hydrated yet. Start hydrating.1916      enterHydrationState(workInProgress);19171918      const child = mountChildFibers(1919        workInProgress,1920        null,1921        nextChildren,1922        renderLanes,1923      );1924      workInProgress.child = child;19251926      let node = child;1927      while (node) {1928        // Mark each child as hydrating. This is a fast path to know whether this1929        // tree is part of a hydrating tree. This is used to determine if a child1930        // node has fully mounted yet, and for scheduling event replaying.1931        // Conceptually this is similar to Placement in that a new subtree is1932        // inserted into the React tree here. It just happens to not need DOM1933        // mutations because it already exists.1934        // We should still treat it as a newly inserted Fiber to double invoke Strict Effects.1935        node.flags = (node.flags & ~Placement) | Hydrating | PlacementDEV;1936        node = node.sibling;1937      }1938    }1939  } else {1940    // Root is not dehydrated. Either this is a client-only root, or it1941    // already hydrated.1942    resetHydrationState();1943    if (nextChildren === prevChildren) {1944      return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);1945    }1946    reconcileChildren(current, workInProgress, nextChildren, renderLanes);1947  }1948  return workInProgress.child;1949}19501951function mountHostRootWithoutHydrating(1952  current: Fiber,1953  workInProgress: Fiber,1954  nextChildren: ReactNodeList,1955  renderLanes: Lanes,1956) {1957  // Revert to client rendering.1958  resetHydrationState();19591960  workInProgress.flags |= ForceClientRender;19611962  reconcileChildren(current, workInProgress, nextChildren, renderLanes);1963  return workInProgress.child;1964}19651966function updateHostComponent(1967  current: Fiber | null,1968  workInProgress: Fiber,1969  renderLanes: Lanes,1970) {1971  if (current === null) {1972    tryToClaimNextHydratableInstance(workInProgress);1973  }19741975  pushHostContext(workInProgress);19761977  const type = workInProgress.type;1978  const nextProps = workInProgress.pendingProps;1979  const prevProps = current !== null ? current.memoizedProps : null;19801981  let nextChildren = nextProps.children;1982  const isDirectTextChild = shouldSetTextContent(type, nextProps);19831984  if (isDirectTextChild) {1985    // We special case a direct text child of a host node. This is a common1986    // case. We won't handle it as a reified child. We will instead handle1987    // this in the host environment that also has access to this prop. That1988    // avoids allocating another HostText fiber and traversing it.1989    nextChildren = null;1990  } else if (prevProps !== null && shouldSetTextContent(type, prevProps)) {1991    // If we're switching from a direct text child to a normal child, or to1992    // empty, we need to schedule the text content to be reset.1993    workInProgress.flags |= ContentReset;1994  }19951996  const memoizedState = workInProgress.memoizedState;1997  if (memoizedState !== null) {1998    // This fiber has been upgraded to a stateful component. The only way1999    // happens currently is for form actions. We use hooks to track the2000    // pending and error state of the form.

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.