packages/react-reconciler/src/ReactFiberBeginWork.js JAVASCRIPT 4,476 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 4,476.
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 {setCurrentFiber} from './ReactCurrentFiber';135import {136  resolveFunctionForHotReloading,137  resolveForwardRefForHotReloading,138  resolveClassForHotReloading,139} from './ReactFiberHotReloading';140141import {142  mountChildFibers,143  reconcileChildFibers,144  cloneChildFibers,145  validateSuspenseListChildren,146} from './ReactChildFiber';147import {148  processUpdateQueue,149  cloneUpdateQueue,150  initializeUpdateQueue,151  enqueueCapturedUpdate,152  suspendIfUpdateReadFromEntangledAsyncAction,153} from './ReactFiberClassUpdateQueue';154import {155  NoLane,156  NoLanes,157  OffscreenLane,158  DefaultLane,159  SomeRetryLane,160  includesSomeLane,161  includesOnlyRetries,162  laneToLanes,163  removeLanes,164  mergeLanes,165  getBumpedLaneForHydration,166  pickArbitraryLane,167} from './ReactFiberLane';168import {169  ConcurrentMode,170  NoMode,171  ProfileMode,172  StrictLegacyMode,173} from './ReactTypeOfMode';174import {175  shouldSetTextContent,176  isSuspenseInstancePending,177  isSuspenseInstanceFallback,178  getSuspenseInstanceFallbackErrorDetails,179  supportsHydration,180  supportsResources,181  supportsSingletons,182  isPrimaryRenderer,183  getResource,184  createHoistableInstance,185  HostTransitionContext,186} from './ReactFiberConfig';187import type {ActivityInstance, SuspenseInstance} from './ReactFiberConfig';188import {shouldError, shouldSuspend} from './ReactFiberReconciler';189import {190  pushHostContext,191  pushHostContainer,192  getRootHostContainer,193} from './ReactFiberHostContext';194import {195  suspenseStackCursor,196  pushSuspenseListContext,197  ForceSuspenseFallback,198  hasSuspenseListContext,199  setDefaultShallowSuspenseListContext,200  setShallowSuspenseListContext,201  pushPrimaryTreeSuspenseHandler,202  pushFallbackTreeSuspenseHandler,203  pushDehydratedActivitySuspenseHandler,204  pushOffscreenSuspenseHandler,205  reuseSuspenseHandlerOnStack,206  popSuspenseHandler,207} from './ReactFiberSuspenseContext';208import {209  pushHiddenContext,210  reuseHiddenContextOnStack,211} from './ReactFiberHiddenContext';212import {findFirstSuspended} from './ReactFiberSuspenseComponent';213import {214  pushProvider,215  propagateContextChange,216  lazilyPropagateParentContextChanges,217  propagateParentContextChangesToDeferredTree,218  checkIfContextChanged,219  readContext,220  prepareToReadContext,221  scheduleContextWorkOnParentPath,222} from './ReactFiberNewContext';223import {224  renderWithHooks,225  checkDidRenderIdHook,226  bailoutHooks,227  replaySuspendedComponentWithHooks,228  renderTransitionAwareHostComponentWithHooks,229} from './ReactFiberHooks';230import {stopProfilerTimerIfRunning} from './ReactProfilerTimer';231import {232  getMaskedContext,233  getUnmaskedContext,234  hasContextChanged as hasLegacyContextChanged,235  pushContextProvider as pushLegacyContextProvider,236  isContextProvider as isLegacyContextProvider,237  pushTopLevelContextObject,238  invalidateContextProvider,239} from './ReactFiberLegacyContext';240import {241  getIsHydrating,242  enterHydrationState,243  reenterHydrationStateFromDehydratedActivityInstance,244  reenterHydrationStateFromDehydratedSuspenseInstance,245  resetHydrationState,246  claimHydratableSingleton,247  tryToClaimNextHydratableInstance,248  tryToClaimNextHydratableTextInstance,249  claimNextHydratableActivityInstance,250  claimNextHydratableSuspenseInstance,251  warnIfHydrating,252  queueHydrationError,253} from './ReactFiberHydrationContext';254import {255  constructClassInstance,256  mountClassInstance,257  resumeMountClassInstance,258  updateClassInstance,259  resolveClassComponentProps,260} from './ReactFiberClassComponent';261import {262  createFiberFromTypeAndProps,263  createFiberFromFragment,264  createFiberFromOffscreen,265  createWorkInProgress,266  isSimpleFunctionComponent,267  isFunctionClassComponent,268} from './ReactFiber';269import {270  scheduleUpdateOnFiber,271  renderDidSuspendDelayIfPossible,272  markSkippedUpdateLanes,273  markRenderDerivedCause,274  getWorkInProgressRoot,275  peekDeferredLane,276} from './ReactFiberWorkLoop';277import {enqueueConcurrentRenderForLane} from './ReactFiberConcurrentUpdates';278import {pushCacheProvider, CacheContext} from './ReactFiberCacheComponent';279import {280  createCapturedValueFromError,281  createCapturedValueAtFiber,282} from './ReactCapturedValue';283import {OffscreenVisible} from './ReactFiberOffscreenComponent';284import {285  createClassErrorUpdate,286  initializeClassErrorUpdate,287} from './ReactFiberThrow';288import {289  getForksAtLevel,290  isForkedChild,291  pushTreeId,292  pushMaterializedTreeId,293} from './ReactFiberTreeContext';294import {295  requestCacheFromPool,296  pushRootTransition,297  getSuspendedCache,298  pushTransition,299  getOffscreenDeferredCache,300  getPendingTransitions,301} from './ReactFiberTransition';302import {303  getMarkerInstances,304  pushMarkerInstance,305  pushRootMarkerInstance,306  TransitionTracingMarker,307} from './ReactFiberTracingMarkerComponent';308import {callComponentInDEV, callRenderInDEV} from './ReactFiberCallUserSpace';309import {resolveLazy} from './ReactFiberThenable';310311// A special exception that's used to unwind the stack when an update flows312// into a dehydrated boundary.313export const SelectiveHydrationException: mixed = new Error(314  "This is not a real error. It's an implementation detail of React's " +315    "selective hydration feature. If this leaks into userspace, it's a bug in " +316    'React. Please file an issue.',317);318319let didReceiveUpdate: boolean = false;320321let didWarnAboutBadClass;322let didWarnAboutContextTypeOnFunctionComponent;323let didWarnAboutContextTypes;324let didWarnAboutGetDerivedStateOnFunctionComponent;325export let didWarnAboutReassigningProps: boolean;326let didWarnAboutRevealOrder;327let didWarnAboutTailOptions;328let didWarnAboutClassNameOnViewTransition;329330if (__DEV__) {331  didWarnAboutBadClass = {} as {[string]: boolean};332  didWarnAboutContextTypeOnFunctionComponent = {} as {[string]: boolean};333  didWarnAboutContextTypes = {} as {[string]: boolean};334  didWarnAboutGetDerivedStateOnFunctionComponent = {} as {[string]: boolean};335  didWarnAboutReassigningProps = false;336  didWarnAboutRevealOrder = {} as {[string]: boolean};337  didWarnAboutTailOptions = {} as {[string]: boolean};338  didWarnAboutClassNameOnViewTransition = {} as {[string]: boolean};339}340341export function reconcileChildren(342  current: Fiber | null,343  workInProgress: Fiber,344  nextChildren: any,345  renderLanes: Lanes,346) {347  if (current === null) {348    // If this is a fresh new component that hasn't been rendered yet, we349    // won't update its child set by applying minimal side-effects. Instead,350    // we will add them all to the child before it gets rendered. That means351    // we can optimize this reconciliation pass by not tracking side-effects.352    workInProgress.child = mountChildFibers(353      workInProgress,354      null,355      nextChildren,356      renderLanes,357    );358  } else {359    // If the current child is the same as the work in progress, it means that360    // we haven't yet started any work on these children. Therefore, we use361    // the clone algorithm to create a copy of all the current children.362363    // If we had any progressed work already, that is invalid at this point so364    // let's throw it out.365    workInProgress.child = reconcileChildFibers(366      workInProgress,367      current.child,368      nextChildren,369      renderLanes,370    );371  }372}373374function forceUnmountCurrentAndReconcile(375  current: Fiber,376  workInProgress: Fiber,377  nextChildren: any,378  renderLanes: Lanes,379) {380  // This function is fork of reconcileChildren. It's used in cases where we381  // want to reconcile without matching against the existing set. This has the382  // effect of all current children being unmounted; even if the type and key383  // are the same, the old child is unmounted and a new child is created.384  //385  // To do this, we're going to go through the reconcile algorithm twice. In386  // the first pass, we schedule a deletion for all the current children by387  // passing null.388  workInProgress.child = reconcileChildFibers(389    workInProgress,390    current.child,391    null,392    renderLanes,393  );394  // In the second pass, we mount the new children. The trick here is that we395  // pass null in place of where we usually pass the current child set. This has396  // the effect of remounting all children regardless of whether their397  // identities match.398  workInProgress.child = reconcileChildFibers(399    workInProgress,400    null,401    nextChildren,402    renderLanes,403  );404}405406function updateForwardRef(407  current: Fiber | null,408  workInProgress: Fiber,409  Component: any,410  nextProps: any,411  renderLanes: Lanes,412) {413  // TODO: current can be non-null here even if the component414  // hasn't yet mounted. This happens after the first render suspends.415  // We'll need to figure out if this is fine or can cause issues.416  const render = Component.render;417  const ref = workInProgress.ref;418419  let propsWithoutRef;420  if ('ref' in nextProps) {421    // `ref` is just a prop now, but `forwardRef` expects it to not appear in422    // the props object. This used to happen in the JSX runtime, but now we do423    // it here.424    propsWithoutRef = {} as {[string]: any};425    for (const key in nextProps) {426      // Since `ref` should only appear in props via the JSX transform, we can427      // assume that this is a plain object. So we don't need a428      // hasOwnProperty check.429      if (key !== 'ref') {430        propsWithoutRef[key] = nextProps[key];431      }432    }433  } else {434    propsWithoutRef = nextProps;435  }436437  // The rest is a fork of updateFunctionComponent438  prepareToReadContext(workInProgress, renderLanes);439  if (enableSchedulingProfiler) {440    markComponentRenderStarted(workInProgress);441  }442443  const nextChildren = renderWithHooks(444    current,445    workInProgress,446    render,447    propsWithoutRef,448    ref,449    renderLanes,450  );451  const hasId = checkDidRenderIdHook();452453  if (enableSchedulingProfiler) {454    markComponentRenderStopped();455  }456457  if (current !== null && !didReceiveUpdate) {458    bailoutHooks(current, workInProgress, renderLanes);459    return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);460  }461462  if (getIsHydrating() && hasId) {463    pushMaterializedTreeId(workInProgress);464  }465466  // React DevTools reads this flag.467  workInProgress.flags |= PerformedWork;468  reconcileChildren(current, workInProgress, nextChildren, renderLanes);469  return workInProgress.child;470}471472function updateMemoComponent(473  current: Fiber | null,474  workInProgress: Fiber,475  Component: any,476  nextProps: any,477  renderLanes: Lanes,478): null | Fiber {479  if (current === null) {480    const type = Component.type;481    if (isSimpleFunctionComponent(type) && Component.compare === null) {482      let resolvedType = type;483      if (__DEV__) {484        resolvedType = resolveFunctionForHotReloading(type);485      }486      // If this is a plain function component without default props,487      // and with only the default shallow comparison, we upgrade it488      // to a SimpleMemoComponent to allow fast path updates.489      workInProgress.tag = SimpleMemoComponent;490      workInProgress.type = resolvedType;491      if (__DEV__) {492        validateFunctionComponentInDev(workInProgress, type);493      }494      return updateSimpleMemoComponent(495        current,496        workInProgress,497        resolvedType,498        nextProps,499        renderLanes,500      );501    }502    const child = createFiberFromTypeAndProps(503      Component.type,504      null,505      nextProps,506      workInProgress,507      workInProgress.mode,508      renderLanes,509    );510    child.ref = workInProgress.ref;511    child.return = workInProgress;512    workInProgress.child = child;513    return child;514  }515  const currentChild = current.child as any as Fiber; // This is always exactly one child516  const hasScheduledUpdateOrContext = checkScheduledUpdateOrContext(517    current,518    renderLanes,519  );520  if (!hasScheduledUpdateOrContext) {521    // This will be the props with resolved defaultProps,522    // unlike current.memoizedProps which will be the unresolved ones.523    const prevProps = currentChild.memoizedProps;524    // Default to shallow comparison525    let compare = Component.compare;526    compare = compare !== null ? compare : shallowEqual;527    if (compare(prevProps, nextProps) && current.ref === workInProgress.ref) {528      return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);529    }530  }531  // React DevTools reads this flag.532  workInProgress.flags |= PerformedWork;533  const newChild = createWorkInProgress(currentChild, nextProps);534  newChild.ref = workInProgress.ref;535  newChild.return = workInProgress;536  workInProgress.child = newChild;537  return newChild;538}539540function updateSimpleMemoComponent(541  current: Fiber | null,542  workInProgress: Fiber,543  Component: any,544  nextProps: any,545  renderLanes: Lanes,546): null | Fiber {547  // TODO: current can be non-null here even if the component548  // hasn't yet mounted. This happens when the inner render suspends.549  // We'll need to figure out if this is fine or can cause issues.550  if (current !== null) {551    const prevProps = current.memoizedProps;552    if (553      shallowEqual(prevProps, nextProps) &&554      current.ref === workInProgress.ref &&555      // Prevent bailout if the implementation changed due to hot reload.556      (__DEV__ ? workInProgress.type === current.type : true)557    ) {558      didReceiveUpdate = false;559560      // The props are shallowly equal. Reuse the previous props object, like we561      // would during a normal fiber bailout.562      //563      // We don't have strong guarantees that the props object is referentially564      // equal during updates where we can't bail out anyway — like if the props565      // are shallowly equal, but there's a local state or context update in the566      // same batch.567      //568      // However, as a principle, we should aim to make the behavior consistent569      // across different ways of memoizing a component. For example, React.memo570      // has a different internal Fiber layout if you pass a normal function571      // component (SimpleMemoComponent) versus if you pass a different type572      // like forwardRef (MemoComponent). But this is an implementation detail.573      // Wrapping a component in forwardRef (or React.lazy, etc) shouldn't574      // affect whether the props object is reused during a bailout.575      workInProgress.pendingProps = nextProps = prevProps;576577      if (!checkScheduledUpdateOrContext(current, renderLanes)) {578        // The pending lanes were cleared at the beginning of beginWork. We're579        // about to bail out, but there might be other lanes that weren't580        // included in the current render. Usually, the priority level of the581        // remaining updates is accumulated during the evaluation of the582        // component (i.e. when processing the update queue). But since since583        // we're bailing out early *without* evaluating the component, we need584        // to account for it here, too. Reset to the value of the current fiber.585        // NOTE: This only applies to SimpleMemoComponent, not MemoComponent,586        // because a MemoComponent fiber does not have hooks or an update queue;587        // rather, it wraps around an inner component, which may or may not588        // contains hooks.589        // TODO: Move the reset at in beginWork out of the common path so that590        // this is no longer necessary.591        workInProgress.lanes = current.lanes;592        return bailoutOnAlreadyFinishedWork(593          current,594          workInProgress,595          renderLanes,596        );597      } else if ((current.flags & ForceUpdateForLegacySuspense) !== NoFlags) {598        // This is a special case that only exists for legacy mode.599        // See https://github.com/facebook/react/pull/19216.600        didReceiveUpdate = true;601      }602    }603  }604  return updateFunctionComponent(605    current,606    workInProgress,607    Component,608    nextProps,609    renderLanes,610  );611}612613function updateOffscreenComponent(614  current: Fiber | null,615  workInProgress: Fiber,616  renderLanes: Lanes,617  nextProps: OffscreenProps,618) {619  const nextChildren = nextProps.children;620621  const prevState: OffscreenState | null =622    current !== null ? current.memoizedState : null;623624  if (current === null && workInProgress.stateNode === null) {625    // We previously reset the work-in-progress.626    // We need to create a new Offscreen instance.627    const primaryChildInstance: OffscreenInstance = {628      _visibility: OffscreenVisible,629      _pendingMarkers: null,630      _retryCache: null,631      _transitions: null,632    };633    workInProgress.stateNode = primaryChildInstance;634  }635636  if (637    nextProps.mode === 'hidden' ||638    (enableLegacyHidden && nextProps.mode === 'unstable-defer-without-hiding')639  ) {640    // Rendering a hidden tree.641642    const didSuspend = (workInProgress.flags & DidCapture) !== NoFlags;643    if (didSuspend) {644      // Something suspended inside a hidden tree645646      // Include the base lanes from the last render647      const nextBaseLanes =648        prevState !== null649          ? mergeLanes(prevState.baseLanes, renderLanes)650          : renderLanes;651652      let remainingChildLanes;653      if (current !== null) {654        // Reset to the current children655        let currentChild = (workInProgress.child = current.child);656657        // The current render suspended, but there may be other lanes with658        // pending work. We can't read `childLanes` from the current Offscreen659        // fiber because we reset it when it was deferred; however, we can read660        // the pending lanes from the child fibers.661        let currentChildLanes: Lanes = NoLanes;662        while (currentChild !== null) {663          currentChildLanes = mergeLanes(664            mergeLanes(currentChildLanes, currentChild.lanes),665            currentChild.childLanes,666          );667          currentChild = currentChild.sibling;668        }669        const lanesWeJustAttempted = nextBaseLanes;670        remainingChildLanes = removeLanes(671          currentChildLanes,672          lanesWeJustAttempted,673        );674      } else {675        remainingChildLanes = NoLanes;676        workInProgress.child = null;677      }678679      return deferHiddenOffscreenComponent(680        current,681        workInProgress,682        nextBaseLanes,683        renderLanes,684        remainingChildLanes,685      );686    }687688    if (689      !disableLegacyMode &&690      (workInProgress.mode & ConcurrentMode) === NoMode691    ) {692      // In legacy sync mode, don't defer the subtree. Render it now.693      // TODO: Consider how Offscreen should work with transitions in the future694      const nextState: OffscreenState = {695        baseLanes: NoLanes,696        cachePool: null,697      };698      workInProgress.memoizedState = nextState;699      // push the cache pool even though we're going to bail out700      // because otherwise there'd be a context mismatch701      if (current !== null) {702        pushTransition(workInProgress, null, null);703      }704      reuseHiddenContextOnStack(workInProgress);705      pushOffscreenSuspenseHandler(workInProgress);706    } else if (!includesSomeLane(renderLanes, OffscreenLane as Lane)) {707      // We're hidden, and we're not rendering at Offscreen. We will bail out708      // and resume this tree later.709710      // Schedule this fiber to re-render at Offscreen priority711712      const remainingChildLanes = (workInProgress.lanes =713        laneToLanes(OffscreenLane));714715      // Include the base lanes from the last render716      const nextBaseLanes =717        prevState !== null718          ? mergeLanes(prevState.baseLanes, renderLanes)719          : renderLanes;720721      return deferHiddenOffscreenComponent(722        current,723        workInProgress,724        nextBaseLanes,725        renderLanes,726        remainingChildLanes,727      );728    } else {729      // This is the second render. The surrounding visible content has already730      // committed. Now we resume rendering the hidden tree.731732      // Rendering at offscreen, so we can clear the base lanes.733      const nextState: OffscreenState = {734        baseLanes: NoLanes,735        cachePool: null,736      };737      workInProgress.memoizedState = nextState;738      if (current !== null) {739        // If the render that spawned this one accessed the cache pool, resume740        // using the same cache. Unless the parent changed, since that means741        // there was a refresh.742        const prevCachePool = prevState !== null ? prevState.cachePool : null;743        // TODO: Consider if and how Offscreen pre-rendering should744        // be attributed to the transition that spawned it745        pushTransition(workInProgress, prevCachePool, null);746      }747748      // Push the lanes that were skipped when we bailed out.749      if (prevState !== null) {750        pushHiddenContext(workInProgress, prevState);751      } else {752        reuseHiddenContextOnStack(workInProgress);753      }754      pushOffscreenSuspenseHandler(workInProgress);755    }756  } else {757    // Rendering a visible tree.758    if (prevState !== null) {759      // We're going from hidden -> visible.760      let prevCachePool = null;761      // If the render that spawned this one accessed the cache pool, resume762      // using the same cache. Unless the parent changed, since that means763      // there was a refresh.764      prevCachePool = prevState.cachePool;765766      let transitions = null;767      if (enableTransitionTracing) {768        // We have now gone from hidden to visible, so any transitions should769        // be added to the stack to get added to any Offscreen/suspense children770        const instance: OffscreenInstance | null = workInProgress.stateNode;771        if (instance !== null && instance._transitions != null) {772          transitions = Array.from(instance._transitions);773        }774      }775776      pushTransition(workInProgress, prevCachePool, transitions);777778      // Push the lanes that were skipped when we bailed out.779      pushHiddenContext(workInProgress, prevState);780      reuseSuspenseHandlerOnStack(workInProgress);781782      // Since we're not hidden anymore, reset the state783      workInProgress.memoizedState = null;784    } else {785      // We weren't previously hidden, and we still aren't, so there's nothing786      // special to do. Need to push to the stack regardless, though, to avoid787      // a push/pop misalignment.788789      // If the render that spawned this one accessed the cache pool, resume790      // using the same cache. Unless the parent changed, since that means791      // there was a refresh.792      if (current !== null) {793        pushTransition(workInProgress, null, null);794      }795796      // We're about to bail out, but we need to push this to the stack anyway797      // to avoid a push/pop misalignment.798      reuseHiddenContextOnStack(workInProgress);799      reuseSuspenseHandlerOnStack(workInProgress);800    }801  }802803  reconcileChildren(current, workInProgress, nextChildren, renderLanes);804  return workInProgress.child;805}806807function bailoutOffscreenComponent(808  current: Fiber | null,809  workInProgress: Fiber,810): Fiber | null {811  if (812    (current === null || current.tag !== OffscreenComponent) &&813    workInProgress.stateNode === null814  ) {815    const primaryChildInstance: OffscreenInstance = {816      _visibility: OffscreenVisible,817      _pendingMarkers: null,818      _retryCache: null,819      _transitions: null,820    };821    workInProgress.stateNode = primaryChildInstance;822  }823824  return workInProgress.sibling;825}826827function deferHiddenOffscreenComponent(828  current: Fiber | null,829  workInProgress: Fiber,830  nextBaseLanes: Lanes,831  renderLanes: Lanes,832  remainingChildLanes: Lanes,833) {834  const nextState: OffscreenState = {835    baseLanes: nextBaseLanes,836    // Save the cache pool so we can resume later.837    cachePool: getOffscreenDeferredCache(),838  };839  workInProgress.memoizedState = nextState;840  // push the cache pool even though we're going to bail out841  // because otherwise there'd be a context mismatch842  if (current !== null) {843    pushTransition(workInProgress, null, null);844  }845846  // We're about to bail out, but we need to push this to the stack anyway847  // to avoid a push/pop misalignment.848  reuseHiddenContextOnStack(workInProgress);849850  pushOffscreenSuspenseHandler(workInProgress);851852  if (current !== null) {853    // Since this tree will resume rendering in a separate render, we need854    // to propagate parent contexts now so we don't lose track of which855    // ones changed.856    propagateParentContextChangesToDeferredTree(857      current,858      workInProgress,859      renderLanes,860    );861  }862863  // We override the remaining child lanes to be the subset that we computed864  // on the outside. We need to do this after propagating the context865  // because propagateParentContextChangesToDeferredTree may schedule866  // work which bubbles all the way up to the root and updates our child lanes.867  // We want to dismiss that since we're not going to work on it yet.868  workInProgress.childLanes = remainingChildLanes;869870  return null;871}872873function updateLegacyHiddenComponent(874  current: null | Fiber,875  workInProgress: Fiber,876  renderLanes: Lanes,877) {878  const nextProps: LegacyHiddenProps = workInProgress.pendingProps;879  // Note: These happen to have identical begin phases, for now. We shouldn't hold880  // ourselves to this constraint, though. If the behavior diverges, we should881  // fork the function.882  // This just works today because it has the same Props.883  return updateOffscreenComponent(884    current,885    workInProgress,886    renderLanes,887    nextProps,888  );889}890891function mountActivityChildren(892  workInProgress: Fiber,893  nextProps: ActivityProps,894  renderLanes: Lanes,895) {896  if (__DEV__) {897    const hiddenProp = (nextProps as any).hidden;898    if (hiddenProp !== undefined) {899      console.error(900        '<Activity> doesn\'t accept a hidden prop. Use mode="hidden" instead.\n' +901          '- <Activity %s>\n' +902          '+ <Activity %s>',903        hiddenProp === true904          ? 'hidden'905          : hiddenProp === false906            ? 'hidden={false}'907            : 'hidden={...}',908        hiddenProp ? 'mode="hidden"' : 'mode="visible"',909      );910    }911  }912  const nextChildren = nextProps.children;913  const nextMode = nextProps.mode;914  const mode = workInProgress.mode;915  const offscreenChildProps: OffscreenProps = {916    mode: nextMode,917    children: nextChildren,918  };919  const primaryChildFragment = mountWorkInProgressOffscreenFiber(920    offscreenChildProps,921    mode,922    renderLanes,923  );924  primaryChildFragment.ref = workInProgress.ref;925  workInProgress.child = primaryChildFragment;926  primaryChildFragment.return = workInProgress;927  return primaryChildFragment;928}929930function retryActivityComponentWithoutHydrating(931  current: Fiber,932  workInProgress: Fiber,933  renderLanes: Lanes,934) {935  // Falling back to client rendering. Because this has performance936  // implications, it's considered a recoverable error, even though the user937  // likely won't observe anything wrong with the UI.938939  // This will add the old fiber to the deletion list940  reconcileChildFibers(workInProgress, current.child, null, renderLanes);941942  // We're now not suspended nor dehydrated.943  const nextProps: ActivityProps = workInProgress.pendingProps;944  const primaryChildFragment = mountActivityChildren(945    workInProgress,946    nextProps,947    renderLanes,948  );949  // Needs a placement effect because the parent (the Activity boundary) already950  // mounted but this is a new fiber.951  primaryChildFragment.flags |= Placement;952953  // If we're not going to hydrate we can't leave it dehydrated if something954  // suspends. In that case we want that to bubble to the nearest parent boundary955  // so we need to pop our own handler that we just pushed.956  popSuspenseHandler(workInProgress);957958  workInProgress.memoizedState = null;959960  return primaryChildFragment;961}962963function mountDehydratedActivityComponent(964  workInProgress: Fiber,965  activityInstance: ActivityInstance,966  renderLanes: Lanes,967): null | Fiber {968  // During the first pass, we'll bail out and not drill into the children.969  // Instead, we'll leave the content in place and try to hydrate it later.970  // We'll continue hydrating the rest at offscreen priority since we'll already971  // be showing the right content coming from the server, it is no rush.972  workInProgress.lanes = laneToLanes(OffscreenLane);973  return null;974}975976function updateDehydratedActivityComponent(977  current: Fiber,978  workInProgress: Fiber,979  didSuspend: boolean,980  nextProps: ActivityProps,981  activityInstance: ActivityInstance,982  activityState: ActivityState,983  renderLanes: Lanes,984): null | Fiber {985  // We'll handle suspending since if something suspends we can just leave986  // it dehydrated. We push early and then pop if we enter non-dehydrated attempts.987  pushDehydratedActivitySuspenseHandler(workInProgress);988  if (!didSuspend) {989    // This is the first render pass. Attempt to hydrate.990991    // We should never be hydrating at this point because it is the first pass,992    // but after we've already committed once.993    warnIfHydrating();994995    if (includesSomeLane(renderLanes, OffscreenLane as Lane)) {996      // If we're rendering Offscreen and we're entering the activity then it's possible997      // that the only reason we rendered was because this boundary left work. Provide998      // it as a cause if another one doesn't already exist.999      markRenderDerivedCause(workInProgress);1000    }10011002    if (1003      // TODO: Factoring is a little weird, since we check this right below, too.1004      !didReceiveUpdate1005    ) {1006      // We need to check if any children have context before we decide to bail1007      // out, so propagate the changes now.1008      lazilyPropagateParentContextChanges(current, workInProgress, renderLanes);1009    }10101011    // We use lanes to indicate that a child might depend on context, so if1012    // any context has changed, we need to treat is as if the input might have changed.1013    const hasContextChanged = includesSomeLane(renderLanes, current.childLanes);1014    if (didReceiveUpdate || hasContextChanged) {1015      // This boundary has changed since the first render. This means that we are now unable to1016      // hydrate it. We might still be able to hydrate it using a higher priority lane.1017      const root = getWorkInProgressRoot();1018      if (root !== null) {1019        const attemptHydrationAtLane = getBumpedLaneForHydration(1020          root,1021          renderLanes,1022        );1023        if (1024          attemptHydrationAtLane !== NoLane &&1025          attemptHydrationAtLane !== activityState.retryLane1026        ) {1027          // Intentionally mutating since this render will get interrupted. This1028          // is one of the very rare times where we mutate the current tree1029          // during the render phase.1030          activityState.retryLane = attemptHydrationAtLane;1031          enqueueConcurrentRenderForLane(current, attemptHydrationAtLane);1032          scheduleUpdateOnFiber(root, current, attemptHydrationAtLane);10331034          // Throw a special object that signals to the work loop that it should1035          // interrupt the current render.1036          //1037          // Because we're inside a React-only execution stack, we don't1038          // strictly need to throw here — we could instead modify some internal1039          // work loop state. But using an exception means we don't need to1040          // check for this case on every iteration of the work loop. So doing1041          // it this way moves the check out of the fast path.1042          throw SelectiveHydrationException;1043        } else {1044          // We have already tried to ping at a higher priority than we're rendering with1045          // so if we got here, we must have failed to hydrate at those levels. We must1046          // now give up. Instead, we're going to delete the whole subtree and instead inject1047          // a new real Activity boundary to take its place. This might suspend for a while1048          // and if it does we might still have an opportunity to hydrate before this pass1049          // commits.1050        }1051      }10521053      // If we did not selectively hydrate, we'll continue rendering without1054      // hydrating. Mark this tree as suspended to prevent it from committing1055      // outside a transition.1056      //1057      // This path should only happen if the hydration lane already suspended.1058      renderDidSuspendDelayIfPossible();1059      return retryActivityComponentWithoutHydrating(1060        current,1061        workInProgress,1062        renderLanes,1063      );1064    } else {1065      // This is the first attempt.10661067      reenterHydrationStateFromDehydratedActivityInstance(1068        workInProgress,1069        activityInstance,1070        activityState.treeContext,1071      );10721073      const primaryChildFragment = mountActivityChildren(1074        workInProgress,1075        nextProps,1076        renderLanes,1077      );1078      // Mark the children as hydrating. This is a fast path to know whether this1079      // tree is part of a hydrating tree. This is used to determine if a child1080      // node has fully mounted yet, and for scheduling event replaying.1081      // Conceptually this is similar to Placement in that a new subtree is1082      // inserted into the React tree here. It just happens to not need DOM1083      // mutations because it already exists.1084      // We should still treat it as a newly inserted Fiber to double invoke Strict Effects.1085      primaryChildFragment.flags |= Hydrating | PlacementDEV;1086      return primaryChildFragment;1087    }1088  } else {1089    // This is the second render pass. We already attempted to hydrated, but1090    // something either suspended or errored.10911092    if (workInProgress.flags & ForceClientRender) {1093      // Something errored during hydration. Try again without hydrating.1094      // The error should've already been logged in throwException.1095      workInProgress.flags &= ~ForceClientRender;1096      return retryActivityComponentWithoutHydrating(1097        current,1098        workInProgress,1099        renderLanes,1100      );1101    } else if (1102      (workInProgress.memoizedState as null | ActivityState) !== null1103    ) {1104      // Something suspended and we should still be in dehydrated mode.1105      // Leave the existing child in place.11061107      workInProgress.child = current.child;1108      // The dehydrated completion pass expects this flag to be there1109      // but the normal offscreen pass doesn't.1110      workInProgress.flags |= DidCapture;1111      return null;1112    } else {1113      // We called retryActivityComponentWithoutHydrating and tried client rendering1114      // but now we suspended again. We should never arrive here because we should1115      // not have pushed a suspense handler during that second pass and it should1116      // instead have suspended above.1117      throw new Error(1118        'Client rendering an Activity suspended it again. This is a bug in React.',1119      );1120    }1121  }1122}11231124function updateActivityComponent(1125  current: null | Fiber,1126  workInProgress: Fiber,1127  renderLanes: Lanes,1128) {1129  const nextProps: ActivityProps = workInProgress.pendingProps;11301131  // Check if the first pass suspended.1132  const didSuspend = (workInProgress.flags & DidCapture) !== NoFlags;1133  workInProgress.flags &= ~DidCapture;11341135  if (current === null) {1136    // Initial mount11371138    // Special path for hydration1139    // If we're currently hydrating, try to hydrate this boundary.1140    // Hidden Activity boundaries are not emitted on the server.1141    if (getIsHydrating()) {1142      if (nextProps.mode === 'hidden') {1143        // SSR doesn't render hidden Activity so it shouldn't hydrate,1144        // even at offscreen lane. Defer to a client rendered offscreen lane.1145        const primaryChildFragment = mountActivityChildren(1146          workInProgress,1147          nextProps,1148          renderLanes,1149        );1150        workInProgress.lanes = laneToLanes(OffscreenLane);1151        return bailoutOffscreenComponent(null, primaryChildFragment);1152      } else {1153        // We must push the suspense handler context *before* attempting to1154        // hydrate, to avoid a mismatch in case it errors.1155        pushDehydratedActivitySuspenseHandler(workInProgress);1156        const dehydrated: ActivityInstance =1157          claimNextHydratableActivityInstance(workInProgress);1158        return mountDehydratedActivityComponent(1159          workInProgress,1160          dehydrated,1161          renderLanes,1162        );1163      }1164    }11651166    return mountActivityChildren(workInProgress, nextProps, renderLanes);1167  } else {1168    // This is an update.11691170    // Special path for hydration1171    const prevState: null | ActivityState = current.memoizedState;11721173    if (prevState !== null) {1174      const dehydrated = prevState.dehydrated;1175      return updateDehydratedActivityComponent(1176        current,1177        workInProgress,1178        didSuspend,1179        nextProps,1180        dehydrated,1181        prevState,1182        renderLanes,1183      );1184    }11851186    const currentChild: Fiber = current.child as any;11871188    const nextChildren = nextProps.children;1189    const nextMode = nextProps.mode;1190    const offscreenChildProps: OffscreenProps = {1191      mode: nextMode,1192      children: nextChildren,1193    };11941195    if (1196      includesSomeLane(renderLanes, OffscreenLane as Lane) &&1197      includesSomeLane(renderLanes, current.lanes)1198    ) {1199      // If we're rendering Offscreen and we're entering the activity then it's possible1200      // that the only reason we rendered was because this boundary left work. Provide1201      // it as a cause if another one doesn't already exist.1202      markRenderDerivedCause(workInProgress);1203    }12041205    const primaryChildFragment = updateWorkInProgressOffscreenFiber(1206      currentChild,1207      offscreenChildProps,1208    );12091210    primaryChildFragment.ref = workInProgress.ref;1211    workInProgress.child = primaryChildFragment;1212    primaryChildFragment.return = workInProgress;1213    return primaryChildFragment;1214  }1215}12161217function updateCacheComponent(1218  current: Fiber | null,1219  workInProgress: Fiber,1220  renderLanes: Lanes,1221) {1222  prepareToReadContext(workInProgress, renderLanes);1223  const parentCache = readContext(CacheContext);12241225  if (current === null) {1226    // Initial mount. Request a fresh cache from the pool.1227    const freshCache = requestCacheFromPool(renderLanes);1228    const initialState: CacheComponentState = {1229      parent: parentCache,1230      cache: freshCache,1231    };1232    workInProgress.memoizedState = initialState;1233    initializeUpdateQueue(workInProgress);1234    pushCacheProvider(workInProgress, freshCache);1235  } else {1236    // Check for updates1237    if (includesSomeLane(current.lanes, renderLanes)) {1238      cloneUpdateQueue(current, workInProgress);1239      processUpdateQueue(workInProgress, null, null, renderLanes);1240      suspendIfUpdateReadFromEntangledAsyncAction();1241    }1242    const prevState: CacheComponentState = current.memoizedState;1243    const nextState: CacheComponentState = workInProgress.memoizedState;12441245    // Compare the new parent cache to the previous to see detect there was1246    // a refresh.1247    if (prevState.parent !== parentCache) {1248      // Refresh in parent. Update the parent.1249      const derivedState: CacheComponentState = {1250        parent: parentCache,1251        cache: parentCache,1252      };12531254      // Copied from getDerivedStateFromProps implementation. Once the update1255      // queue is empty, persist the derived state onto the base state.1256      workInProgress.memoizedState = derivedState;1257      if (workInProgress.lanes === NoLanes) {1258        const updateQueue: UpdateQueue<any> = workInProgress.updateQueue as any;1259        workInProgress.memoizedState = updateQueue.baseState = derivedState;1260      }12611262      pushCacheProvider(workInProgress, parentCache);1263      // No need to propagate a context change because the refreshed parent1264      // already did.1265    } else {1266      // The parent didn't refresh. Now check if this cache did.1267      const nextCache = nextState.cache;1268      pushCacheProvider(workInProgress, nextCache);1269      if (nextCache !== prevState.cache) {1270        // This cache refreshed. Propagate a context change.1271        propagateContextChange(workInProgress, CacheContext, renderLanes);1272      }1273    }1274  }12751276  const nextProps: CacheProps = workInProgress.pendingProps;12771278  const nextChildren = nextProps.children;1279  reconcileChildren(current, workInProgress, nextChildren, renderLanes);1280  return workInProgress.child;1281}12821283// This should only be called if the name changes1284function updateTracingMarkerComponent(1285  current: Fiber | null,1286  workInProgress: Fiber,1287  renderLanes: Lanes,1288) {1289  if (!enableTransitionTracing) {1290    return null;1291  }12921293  const nextProps: TracingMarkerProps = workInProgress.pendingProps;12941295  // TODO: (luna) Only update the tracing marker if it's newly rendered or it's name changed.1296  // A tracing marker is only associated with the transitions that rendered1297  // or updated it, so we can create a new set of transitions each time1298  if (current === null) {1299    const currentTransitions = getPendingTransitions();1300    if (currentTransitions !== null) {1301      const markerInstance: TracingMarkerInstance = {1302        tag: TransitionTracingMarker,1303        transitions: new Set(currentTransitions),1304        pendingBoundaries: null,1305        name: nextProps.name,1306        aborts: null,1307      };1308      workInProgress.stateNode = markerInstance;13091310      // We call the marker complete callback when all child suspense boundaries resolve.1311      // We do this in the commit phase on Offscreen. If the marker has no child suspense1312      // boundaries, we need to schedule a passive effect to make sure we call the marker1313      // complete callback.1314      workInProgress.flags |= Passive;1315    }1316  } else {1317    if (__DEV__) {1318      if (current.memoizedProps.name !== nextProps.name) {1319        console.error(1320          'Changing the name of a tracing marker after mount is not supported. ' +1321            'To remount the tracing marker, pass it a new key.',1322        );1323      }1324    }1325  }13261327  const instance: TracingMarkerInstance | null = workInProgress.stateNode;1328  if (instance !== null) {1329    pushMarkerInstance(workInProgress, instance);1330  }1331  const nextChildren = nextProps.children;1332  reconcileChildren(current, workInProgress, nextChildren, renderLanes);1333  return workInProgress.child;1334}13351336function updateFragment(1337  current: Fiber | null,1338  workInProgress: Fiber,1339  renderLanes: Lanes,1340) {1341  const nextChildren = workInProgress.pendingProps;1342  if (enableFragmentRefs) {1343    markRef(current, workInProgress);1344  }1345  reconcileChildren(current, workInProgress, nextChildren, renderLanes);1346  return workInProgress.child;1347}13481349function updateMode(1350  current: Fiber | null,1351  workInProgress: Fiber,1352  renderLanes: Lanes,1353) {1354  const nextChildren = workInProgress.pendingProps.children;1355  reconcileChildren(current, workInProgress, nextChildren, renderLanes);1356  return workInProgress.child;1357}13581359function updateProfiler(1360  current: Fiber | null,1361  workInProgress: Fiber,1362  renderLanes: Lanes,1363) {1364  if (enableProfilerTimer) {1365    workInProgress.flags |= Update;13661367    if (enableProfilerCommitHooks) {1368      // Schedule a passive effect for this Profiler to call onPostCommit hooks.1369      // This effect should be scheduled even if there is no onPostCommit callback for this Profiler,1370      // because the effect is also where times bubble to parent Profilers.1371      workInProgress.flags |= Passive;1372      // Reset effect durations for the next eventual effect phase.1373      // These are reset during render to allow the DevTools commit hook a chance to read them,1374      const stateNode = workInProgress.stateNode;1375      stateNode.effectDuration = -0;1376      stateNode.passiveEffectDuration = -0;1377    }1378  }1379  const nextProps: ProfilerProps = workInProgress.pendingProps;1380  const nextChildren = nextProps.children;1381  reconcileChildren(current, workInProgress, nextChildren, renderLanes);1382  return workInProgress.child;1383}13841385function markRef(current: Fiber | null, workInProgress: Fiber) {1386  // TODO: Check props.ref instead of fiber.ref when enableRefAsProp is on.1387  const ref = workInProgress.ref;1388  if (ref === null) {1389    if (current !== null && current.ref !== null) {1390      // Schedule a Ref effect1391      workInProgress.flags |= Ref | RefStatic;1392    }1393  } else {1394    if (typeof ref !== 'function' && typeof ref !== 'object') {1395      throw new Error(1396        'Expected ref to be a function, an object returned by React.createRef(), or undefined/null.',1397      );1398    }1399    if (current === null || current.ref !== ref) {1400      // Schedule a Ref effect1401      workInProgress.flags |= Ref | RefStatic;1402    }1403  }1404}14051406function mountIncompleteFunctionComponent(1407  _current: null | Fiber,1408  workInProgress: Fiber,1409  Component: any,1410  nextProps: any,1411  renderLanes: Lanes,1412) {1413  resetSuspendedCurrentOnMountInLegacyMode(_current, workInProgress);14141415  workInProgress.tag = FunctionComponent;14161417  return updateFunctionComponent(1418    null,1419    workInProgress,1420    Component,1421    nextProps,1422    renderLanes,1423  );1424}14251426function updateFunctionComponent(1427  current: null | Fiber,1428  workInProgress: Fiber,1429  Component: any,1430  nextProps: any,1431  renderLanes: Lanes,1432) {1433  if (__DEV__) {1434    if (1435      Component.prototype &&1436      typeof Component.prototype.render === 'function'1437    ) {1438      const componentName = getComponentNameFromType(Component) || 'Unknown';14391440      if (!didWarnAboutBadClass[componentName]) {1441        console.error(1442          "The <%s /> component appears to have a render method, but doesn't extend React.Component. " +1443            'This is likely to cause errors. Change %s to extend React.Component instead.',1444          componentName,1445          componentName,1446        );1447        didWarnAboutBadClass[componentName] = true;1448      }1449    }14501451    if (workInProgress.mode & StrictLegacyMode) {1452      ReactStrictModeWarnings.recordLegacyContextWarning(workInProgress, null);1453    }14541455    if (current === null) {1456      // Some validations were previously done in mountIndeterminateComponent however and are now run1457      // in updateFuntionComponent but only on mount1458      validateFunctionComponentInDev(workInProgress, workInProgress.type);14591460      if (Component.contextTypes) {1461        const componentName = getComponentNameFromType(Component) || 'Unknown';14621463        if (!didWarnAboutContextTypes[componentName]) {1464          didWarnAboutContextTypes[componentName] = true;1465          if (disableLegacyContext) {1466            console.error(1467              '%s uses the legacy contextTypes API which was removed in React 19. ' +1468                'Use React.createContext() with React.useContext() instead. ' +1469                '(https://react.dev/link/legacy-context)',1470              componentName,1471            );1472          } else {1473            console.error(1474              '%s uses the legacy contextTypes API which will be removed soon. ' +1475                'Use React.createContext() with React.useContext() instead. ' +1476                '(https://react.dev/link/legacy-context)',1477              componentName,1478            );1479          }1480        }1481      }1482    }1483  }14841485  let context;1486  if (!disableLegacyContext && !disableLegacyContextForFunctionComponents) {1487    const unmaskedContext = getUnmaskedContext(workInProgress, Component, true);1488    context = getMaskedContext(workInProgress, unmaskedContext);1489  }14901491  let nextChildren;1492  let hasId;1493  prepareToReadContext(workInProgress, renderLanes);1494  if (enableSchedulingProfiler) {1495    markComponentRenderStarted(workInProgress);1496  }1497  if (__DEV__) {1498    nextChildren = renderWithHooks(1499      current,1500      workInProgress,1501      Component,1502      nextProps,1503      context,1504      renderLanes,1505    );1506    hasId = checkDidRenderIdHook();1507  } else {1508    nextChildren = renderWithHooks(1509      current,1510      workInProgress,1511      Component,1512      nextProps,1513      context,1514      renderLanes,1515    );1516    hasId = checkDidRenderIdHook();1517  }1518  if (enableSchedulingProfiler) {1519    markComponentRenderStopped();1520  }15211522  if (current !== null && !didReceiveUpdate) {1523    bailoutHooks(current, workInProgress, renderLanes);1524    return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);1525  }15261527  if (getIsHydrating() && hasId) {1528    pushMaterializedTreeId(workInProgress);1529  }15301531  // React DevTools reads this flag.1532  workInProgress.flags |= PerformedWork;1533  reconcileChildren(current, workInProgress, nextChildren, renderLanes);1534  return workInProgress.child;1535}15361537export function replayFunctionComponent(1538  current: Fiber | null,1539  workInProgress: Fiber,1540  nextProps: any,1541  Component: any,1542  secondArg: any,1543  renderLanes: Lanes,1544): Fiber | null {1545  // This function is used to replay a component that previously suspended,1546  // after its data resolves. It's a simplified version of1547  // updateFunctionComponent that reuses the hooks from the previous attempt.15481549  prepareToReadContext(workInProgress, renderLanes);1550  if (enableSchedulingProfiler) {1551    markComponentRenderStarted(workInProgress);1552  }1553  const nextChildren = replaySuspendedComponentWithHooks(1554    current,1555    workInProgress,1556    Component,1557    nextProps,1558    secondArg,1559  );1560  const hasId = checkDidRenderIdHook();1561  if (enableSchedulingProfiler) {1562    markComponentRenderStopped();1563  }15641565  if (current !== null && !didReceiveUpdate) {1566    bailoutHooks(current, workInProgress, renderLanes);1567    return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);1568  }15691570  if (getIsHydrating() && hasId) {1571    pushMaterializedTreeId(workInProgress);1572  }15731574  // React DevTools reads this flag.1575  workInProgress.flags |= PerformedWork;1576  reconcileChildren(current, workInProgress, nextChildren, renderLanes);1577  return workInProgress.child;1578}15791580function updateClassComponent(1581  current: Fiber | null,1582  workInProgress: Fiber,1583  Component: any,1584  nextProps: any,1585  renderLanes: Lanes,1586) {1587  if (__DEV__) {1588    // This is used by DevTools to force a boundary to error.1589    switch (shouldError(workInProgress)) {1590      case false: {1591        // We previously simulated an error on this boundary1592        // so the instance must have been constructed in a previous1593        // commit.1594        const instance = workInProgress.stateNode;1595        const ctor = workInProgress.type;1596        // TODO This way of resetting the error boundary state is a hack.1597        // Is there a better way to do this?1598        const tempInstance = new ctor(1599          workInProgress.memoizedProps,1600          instance.context,1601        );1602        const state = tempInstance.state;1603        instance.updater.enqueueSetState(instance, state, null);1604        break;1605      }1606      case true: {1607        workInProgress.flags |= DidCapture;1608        workInProgress.flags |= ShouldCapture;1609        // eslint-disable-next-line react-internal/prod-error-codes1610        const error = new Error('Simulated error coming from DevTools');1611        const lane = pickArbitraryLane(renderLanes);1612        workInProgress.lanes = mergeLanes(workInProgress.lanes, lane);1613        // Schedule the error boundary to re-render using updated state1614        const root: FiberRoot | null = getWorkInProgressRoot();1615        if (root === null) {1616          throw new Error(1617            'Expected a work-in-progress root. This is a bug in React. Please file an issue.',1618          );1619        }1620        const update = createClassErrorUpdate(lane);1621        initializeClassErrorUpdate(1622          update,1623          root,1624          workInProgress,1625          createCapturedValueAtFiber(error, workInProgress),1626        );1627        enqueueCapturedUpdate(workInProgress, update);1628        break;1629      }1630    }1631  }16321633  // Push context providers early to prevent context stack mismatches.1634  // During mounting we don't know the child context yet as the instance doesn't exist.1635  // We will invalidate the child context in finishClassComponent() right after rendering.1636  let hasContext;1637  if (isLegacyContextProvider(Component)) {1638    hasContext = true;1639    pushLegacyContextProvider(workInProgress);1640  } else {1641    hasContext = false;1642  }1643  prepareToReadContext(workInProgress, renderLanes);16441645  const instance = workInProgress.stateNode;1646  let shouldUpdate;1647  if (instance === null) {1648    resetSuspendedCurrentOnMountInLegacyMode(current, workInProgress);16491650    // In the initial pass we might need to construct the instance.1651    constructClassInstance(workInProgress, Component, nextProps);1652    mountClassInstance(workInProgress, Component, nextProps, renderLanes);1653    shouldUpdate = true;1654  } else if (current === null) {1655    // In a resume, we'll already have an instance we can reuse.1656    shouldUpdate = resumeMountClassInstance(1657      workInProgress,1658      Component,1659      nextProps,1660      renderLanes,1661    );1662  } else {1663    shouldUpdate = updateClassInstance(1664      current,1665      workInProgress,1666      Component,1667      nextProps,1668      renderLanes,1669    );1670  }1671  const nextUnitOfWork = finishClassComponent(1672    current,1673    workInProgress,1674    Component,1675    shouldUpdate,1676    hasContext,1677    renderLanes,1678  );1679  if (__DEV__) {1680    const inst = workInProgress.stateNode;1681    if (shouldUpdate && inst.props !== nextProps) {1682      if (!didWarnAboutReassigningProps) {1683        console.error(1684          'It looks like %s is reassigning its own `this.props` while rendering. ' +1685            'This is not supported and can lead to confusing bugs.',1686          getComponentNameFromFiber(workInProgress) || 'a component',1687        );1688      }1689      didWarnAboutReassigningProps = true;1690    }1691  }1692  return nextUnitOfWork;1693}16941695function finishClassComponent(1696  current: Fiber | null,1697  workInProgress: Fiber,1698  Component: any,1699  shouldUpdate: boolean,1700  hasContext: boolean,1701  renderLanes: Lanes,1702) {1703  // Refs should update even if shouldComponentUpdate returns false1704  markRef(current, workInProgress);17051706  const didCaptureError = (workInProgress.flags & DidCapture) !== NoFlags;17071708  if (!shouldUpdate && !didCaptureError) {1709    // Context providers should defer to sCU for rendering1710    if (hasContext) {1711      invalidateContextProvider(workInProgress, Component, false);1712    }17131714    return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);1715  }17161717  const instance = workInProgress.stateNode;17181719  // Rerender1720  if (__DEV__) {1721    setCurrentFiber(workInProgress);1722  }1723  let nextChildren;1724  if (1725    didCaptureError &&1726    typeof Component.getDerivedStateFromError !== 'function'1727  ) {1728    // If we captured an error, but getDerivedStateFromError is not defined,1729    // unmount all the children. componentDidCatch will schedule an update to1730    // re-render a fallback. This is temporary until we migrate everyone to1731    // the new API.1732    // TODO: Warn in a future release.1733    nextChildren = null;17341735    if (enableProfilerTimer) {1736      stopProfilerTimerIfRunning(workInProgress);1737    }1738  } else {1739    if (enableSchedulingProfiler) {1740      markComponentRenderStarted(workInProgress);1741    }1742    if (__DEV__) {1743      nextChildren = callRenderInDEV(instance);1744      if (workInProgress.mode & StrictLegacyMode) {1745        setIsStrictModeForDevtools(true);1746        try {1747          callRenderInDEV(instance);1748        } finally {1749          setIsStrictModeForDevtools(false);1750        }1751      }1752    } else {1753      nextChildren = instance.render();1754    }1755    if (enableSchedulingProfiler) {1756      markComponentRenderStopped();1757    }1758  }17591760  // React DevTools reads this flag.1761  workInProgress.flags |= PerformedWork;1762  if (current !== null && didCaptureError) {1763    // If we're recovering from an error, reconcile without reusing any of1764    // the existing children. Conceptually, the normal children and the children1765    // that are shown on error are two different sets, so we shouldn't reuse1766    // normal children even if their identities match.1767    forceUnmountCurrentAndReconcile(1768      current,1769      workInProgress,1770      nextChildren,1771      renderLanes,1772    );1773  } else {1774    reconcileChildren(current, workInProgress, nextChildren, renderLanes);1775  }17761777  // Memoize state using the values we just used to render.1778  // TODO: Restructure so we never read values from the instance.1779  workInProgress.memoizedState = instance.state;17801781  // The context might have changed so we need to recalculate it.1782  if (hasContext) {1783    invalidateContextProvider(workInProgress, Component, true);1784  }17851786  return workInProgress.child;1787}17881789function pushHostRootContext(workInProgress: Fiber) {1790  const root = workInProgress.stateNode as FiberRoot;1791  if (root.pendingContext) {1792    pushTopLevelContextObject(1793      workInProgress,1794      root.pendingContext,1795      root.pendingContext !== root.context,1796    );1797  } else if (root.context) {1798    // Should always be set1799    pushTopLevelContextObject(workInProgress, root.context, false);1800  }1801  pushHostContainer(workInProgress, root.containerInfo);1802}18031804function updateHostRoot(1805  current: null | Fiber,1806  workInProgress: Fiber,1807  renderLanes: Lanes,1808) {1809  pushHostRootContext(workInProgress);18101811  if (current === null) {1812    throw new Error('Should have a current fiber. This is a bug in React.');1813  }18141815  const nextProps = workInProgress.pendingProps;1816  const prevState: RootState = workInProgress.memoizedState;1817  const prevChildren = prevState.element;1818  cloneUpdateQueue(current, workInProgress);1819  processUpdateQueue(workInProgress, nextProps, null, renderLanes);18201821  const nextState: RootState = workInProgress.memoizedState;1822  const root: FiberRoot = workInProgress.stateNode;1823  pushRootTransition(workInProgress, root, renderLanes);18241825  if (enableTransitionTracing) {1826    pushRootMarkerInstance(workInProgress);1827  }18281829  const nextCache: Cache = nextState.cache;1830  pushCacheProvider(workInProgress, nextCache);1831  if (nextCache !== prevState.cache) {1832    // The root cache refreshed.1833    propagateContextChange(workInProgress, CacheContext, renderLanes);1834  }18351836  // This would ideally go inside processUpdateQueue, but because it suspends,1837  // it needs to happen after the `pushCacheProvider` call above to avoid a1838  // context stack mismatch. A bit unfortunate.1839  suspendIfUpdateReadFromEntangledAsyncAction();18401841  // Caution: React DevTools currently depends on this property1842  // being called "element".1843  const nextChildren = nextState.element;1844  // $FlowFixMe[constant-condition]1845  if (supportsHydration && prevState.isDehydrated) {1846    // This is a hydration root whose shell has not yet hydrated. We should1847    // attempt to hydrate.18481849    // Flip isDehydrated to false to indicate that when this render1850    // finishes, the root will no longer be dehydrated.1851    const overrideState: RootState = {1852      element: nextChildren,1853      isDehydrated: false,1854      cache: nextState.cache,1855    };1856    const updateQueue: UpdateQueue<RootState> =1857      workInProgress.updateQueue as any;1858    // `baseState` can always be the last state because the root doesn't1859    // have reducer functions so it doesn't need rebasing.1860    updateQueue.baseState = overrideState;1861    workInProgress.memoizedState = overrideState;18621863    if (workInProgress.flags & ForceClientRender) {1864      // Something errored during a previous attempt to hydrate the shell, so we1865      // forced a client render. We should have a recoverable error already scheduled.1866      return mountHostRootWithoutHydrating(1867        current,1868        workInProgress,1869        nextChildren,1870        renderLanes,1871      );1872    } else if (nextChildren !== prevChildren) {1873      const recoverableError = createCapturedValueAtFiber<mixed>(1874        new Error(1875          'This root received an early update, before anything was able ' +1876            'hydrate. Switched the entire root to client rendering.',1877        ),1878        workInProgress,1879      );1880      queueHydrationError(recoverableError);1881      return mountHostRootWithoutHydrating(1882        current,1883        workInProgress,1884        nextChildren,1885        renderLanes,1886      );1887    } else {1888      // The outermost shell has not hydrated yet. Start hydrating.1889      enterHydrationState(workInProgress);18901891      const child = mountChildFibers(1892        workInProgress,1893        null,1894        nextChildren,1895        renderLanes,1896      );1897      workInProgress.child = child;18981899      let node = child;1900      while (node) {1901        // Mark each child as hydrating. This is a fast path to know whether this1902        // tree is part of a hydrating tree. This is used to determine if a child1903        // node has fully mounted yet, and for scheduling event replaying.1904        // Conceptually this is similar to Placement in that a new subtree is1905        // inserted into the React tree here. It just happens to not need DOM1906        // mutations because it already exists.1907        // We should still treat it as a newly inserted Fiber to double invoke Strict Effects.1908        node.flags = (node.flags & ~Placement) | Hydrating | PlacementDEV;1909        node = node.sibling;1910      }1911    }1912  } else {1913    // Root is not dehydrated. Either this is a client-only root, or it1914    // already hydrated.1915    resetHydrationState();1916    if (nextChildren === prevChildren) {1917      return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);1918    }1919    reconcileChildren(current, workInProgress, nextChildren, renderLanes);1920  }1921  return workInProgress.child;1922}19231924function mountHostRootWithoutHydrating(1925  current: Fiber,1926  workInProgress: Fiber,1927  nextChildren: ReactNodeList,1928  renderLanes: Lanes,1929) {1930  // Revert to client rendering.1931  resetHydrationState();19321933  workInProgress.flags |= ForceClientRender;19341935  reconcileChildren(current, workInProgress, nextChildren, renderLanes);1936  return workInProgress.child;1937}19381939function updateHostComponent(1940  current: Fiber | null,1941  workInProgress: Fiber,1942  renderLanes: Lanes,1943) {1944  if (current === null) {1945    tryToClaimNextHydratableInstance(workInProgress);1946  }19471948  pushHostContext(workInProgress);19491950  const type = workInProgress.type;1951  const nextProps = workInProgress.pendingProps;1952  const prevProps = current !== null ? current.memoizedProps : null;19531954  let nextChildren = nextProps.children;1955  const isDirectTextChild = shouldSetTextContent(type, nextProps);19561957  if (isDirectTextChild) {1958    // We special case a direct text child of a host node. This is a common1959    // case. We won't handle it as a reified child. We will instead handle1960    // this in the host environment that also has access to this prop. That1961    // avoids allocating another HostText fiber and traversing it.1962    nextChildren = null;1963  } else if (prevProps !== null && shouldSetTextContent(type, prevProps)) {1964    // If we're switching from a direct text child to a normal child, or to1965    // empty, we need to schedule the text content to be reset.1966    workInProgress.flags |= ContentReset;1967  }19681969  const memoizedState = workInProgress.memoizedState;1970  if (memoizedState !== null) {1971    // This fiber has been upgraded to a stateful component. The only way1972    // happens currently is for form actions. We use hooks to track the1973    // pending and error state of the form.1974    //1975    // Once a fiber is upgraded to be stateful, it remains stateful for the1976    // rest of its lifetime.1977    const newState = renderTransitionAwareHostComponentWithHooks(1978      current,1979      workInProgress,1980      renderLanes,1981    );19821983    // If the transition state changed, propagate the change to all the1984    // descendents. We use Context as an implementation detail for this.1985    //1986    // We need to update it here because1987    // pushHostContext gets called before we process the state hook, to avoid1988    // a state mismatch in the event that something suspends.1989    //1990    // NOTE: This assumes that there cannot be nested transition providers,1991    // because the only renderer that implements this feature is React DOM,1992    // and forms cannot be nested. If we did support nested providers, then1993    // we would need to push a context value even for host fibers that1994    // haven't been upgraded yet.1995    // $FlowFixMe[constant-condition]1996    if (isPrimaryRenderer) {1997      HostTransitionContext._currentValue = newState;1998    } else {1999      HostTransitionContext._currentValue2 = newState;2000    }

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.