diff --git a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-dev.js b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-dev.js index 69fc6d9876c44..7cb0d2b61767b 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-dev.js +++ b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-dev.js @@ -23649,7 +23649,7 @@ function createFiberRoot( return root; } -var ReactVersion = "18.3.0-next-f77099b6f-20230322"; +var ReactVersion = "18.3.0-next-9c54b29b4-20230322"; // Might add PROFILE later. diff --git a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-prod.js b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-prod.js index 7da629e475833..2464085e976d7 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-prod.js +++ b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-prod.js @@ -8570,7 +8570,7 @@ var devToolsConfig$jscomp$inline_1029 = { throw Error("TestRenderer does not support findFiberByHostInstance()"); }, bundleType: 0, - version: "18.3.0-next-f77099b6f-20230322", + version: "18.3.0-next-9c54b29b4-20230322", rendererPackageName: "react-test-renderer" }; var internals$jscomp$inline_1217 = { @@ -8601,7 +8601,7 @@ var internals$jscomp$inline_1217 = { scheduleRoot: null, setRefreshHandler: null, getCurrentFiber: null, - reconcilerVersion: "18.3.0-next-f77099b6f-20230322" + reconcilerVersion: "18.3.0-next-9c54b29b4-20230322" }; if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) { var hook$jscomp$inline_1218 = __REACT_DEVTOOLS_GLOBAL_HOOK__; diff --git a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-profiling.js b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-profiling.js index 88a12d88aabd2..cf918323d4d9b 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-profiling.js +++ b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-profiling.js @@ -8995,7 +8995,7 @@ var devToolsConfig$jscomp$inline_1072 = { throw Error("TestRenderer does not support findFiberByHostInstance()"); }, bundleType: 0, - version: "18.3.0-next-f77099b6f-20230322", + version: "18.3.0-next-9c54b29b4-20230322", rendererPackageName: "react-test-renderer" }; var internals$jscomp$inline_1258 = { @@ -9026,7 +9026,7 @@ var internals$jscomp$inline_1258 = { scheduleRoot: null, setRefreshHandler: null, getCurrentFiber: null, - reconcilerVersion: "18.3.0-next-f77099b6f-20230322" + reconcilerVersion: "18.3.0-next-9c54b29b4-20230322" }; if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) { var hook$jscomp$inline_1259 = __REACT_DEVTOOLS_GLOBAL_HOOK__; diff --git a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-dev.js b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-dev.js index da22b7721b9d5..ad4c62d8324a2 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-dev.js +++ b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-dev.js @@ -27,7 +27,7 @@ if ( } "use strict"; -var ReactVersion = "18.3.0-next-f77099b6f-20230322"; +var ReactVersion = "18.3.0-next-9c54b29b4-20230322"; // ATTENTION // When adding new symbols to this file, diff --git a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-prod.js b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-prod.js index 695a9b460ea91..64f17108760d3 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-prod.js +++ b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-prod.js @@ -639,4 +639,4 @@ exports.useSyncExternalStore = function ( ); }; exports.useTransition = useTransition; -exports.version = "18.3.0-next-f77099b6f-20230322"; +exports.version = "18.3.0-next-9c54b29b4-20230322"; diff --git a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-profiling.js b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-profiling.js index b39b22b2f48c7..b7524c2621f68 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-profiling.js +++ b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-profiling.js @@ -642,7 +642,7 @@ exports.useSyncExternalStore = function ( ); }; exports.useTransition = useTransition; -exports.version = "18.3.0-next-f77099b6f-20230322"; +exports.version = "18.3.0-next-9c54b29b4-20230322"; /* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */ if ( diff --git a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/REVISION b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/REVISION index b0bbc865ab0da..51ceb6c7135e3 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/REVISION +++ b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/REVISION @@ -1 +1 @@ -f77099b6f1ccc658eff3467c6b9337e1b77ec854 +9c54b29b44d24f8f8090da9c7ebf569747a444df diff --git a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-dev.fb.js b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-dev.fb.js index c9156cb66330b..9ba6f6825bb47 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-dev.fb.js +++ b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-dev.fb.js @@ -3003,308 +3003,205 @@ function diff(prevProps, nextProps, validAttributes) { ); } -function warnForStyleProps(props, validAttributes) { - { - for (var key in validAttributes.style) { - if (!(validAttributes[key] || props[key] === undefined)) { - error( - "You are setting the style `{ %s" + - ": ... }` as a prop. You " + - "should nest it in a style object. " + - "E.g. `{ style: { %s" + - ": ... } }`", - key, - key - ); - } - } - } -} - -/** - * `ReactInstanceMap` maintains a mapping from a public facing stateful - * instance (key) and the internal representation (value). This allows public - * methods to accept the user facing instance as an argument and map them back - * to internal methods. - * - * Note that this module is currently shared and assumed to be stateless. - * If this becomes an actual Map, that will break. - */ -function get(key) { - return key._reactInternals; -} -function set(key, value) { - key._reactInternals = value; -} - -// NOTE: There are no flags, currently. Uncomment the stuff below if we add one. -// the exports object every time a flag is read. - -var enableUseRefAccessWarning = dynamicFlags.enableUseRefAccessWarning; // The rest of the flags are static for better dead code elimination. -var enableSchedulingProfiler = true; -var enableProfilerTimer = true; -var enableProfilerCommitHooks = true; -var enableProfilerNestedUpdatePhase = true; -var createRootStrictEffectsByDefault = false; -var enableLazyContextPropagation = false; +// Used as a way to call batchedUpdates when we don't have a reference to +// the renderer. Such as when we're dispatching events or if third party +// libraries need to call batchedUpdates. Eventually, this API will go away when +// everything is batched by default. We'll then have a similar API to opt-out of +// scheduled work and instead do synchronous work. +// Defaults +var batchedUpdatesImpl = function (fn, bookkeeping) { + return fn(bookkeeping); +}; -// ATTENTION -// When adding new symbols to this file, -// Please consider also adding to 'react-devtools-shared/src/backend/ReactSymbols' -// The Symbol used to tag the ReactElement-like types. -var REACT_ELEMENT_TYPE = Symbol.for("react.element"); -var REACT_PORTAL_TYPE = Symbol.for("react.portal"); -var REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"); -var REACT_STRICT_MODE_TYPE = Symbol.for("react.strict_mode"); -var REACT_PROFILER_TYPE = Symbol.for("react.profiler"); -var REACT_PROVIDER_TYPE = Symbol.for("react.provider"); -var REACT_CONTEXT_TYPE = Symbol.for("react.context"); -var REACT_SERVER_CONTEXT_TYPE = Symbol.for("react.server_context"); -var REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"); -var REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"); -var REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"); -var REACT_MEMO_TYPE = Symbol.for("react.memo"); -var REACT_LAZY_TYPE = Symbol.for("react.lazy"); -var REACT_SCOPE_TYPE = Symbol.for("react.scope"); -var REACT_DEBUG_TRACING_MODE_TYPE = Symbol.for("react.debug_trace_mode"); -var REACT_OFFSCREEN_TYPE = Symbol.for("react.offscreen"); -var REACT_LEGACY_HIDDEN_TYPE = Symbol.for("react.legacy_hidden"); -var REACT_CACHE_TYPE = Symbol.for("react.cache"); -var REACT_TRACING_MARKER_TYPE = Symbol.for("react.tracing_marker"); -var REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED = Symbol.for( - "react.default_value" -); -var REACT_MEMO_CACHE_SENTINEL = Symbol.for("react.memo_cache_sentinel"); -var MAYBE_ITERATOR_SYMBOL = Symbol.iterator; -var FAUX_ITERATOR_SYMBOL = "@@iterator"; -function getIteratorFn(maybeIterable) { - if (maybeIterable === null || typeof maybeIterable !== "object") { - return null; +var isInsideEventHandler = false; +function batchedUpdates$1(fn, bookkeeping) { + if (isInsideEventHandler) { + // If we are currently inside another batch, we need to wait until it + // fully completes before restoring state. + return fn(bookkeeping); } - var maybeIterator = - (MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL]) || - maybeIterable[FAUX_ITERATOR_SYMBOL]; + isInsideEventHandler = true; - if (typeof maybeIterator === "function") { - return maybeIterator; + try { + return batchedUpdatesImpl(fn, bookkeeping); + } finally { + isInsideEventHandler = false; } - - return null; +} +function setBatchingImplementation(_batchedUpdatesImpl, _discreteUpdatesImpl) { + batchedUpdatesImpl = _batchedUpdatesImpl; } -function getWrappedName$1(outerType, innerType, wrapperName) { - var displayName = outerType.displayName; - - if (displayName) { - return displayName; - } - - var functionName = innerType.displayName || innerType.name || ""; - return functionName !== "" - ? wrapperName + "(" + functionName + ")" - : wrapperName; -} // Keep in sync with react-reconciler/getComponentNameFromFiber +/** + * Internal queue of events that have accumulated their dispatches and are + * waiting to have their dispatches executed. + */ -function getContextName$1(type) { - return type.displayName || "Context"; -} // Note that the reconciler package should generally prefer to use getComponentNameFromFiber() instead. +var eventQueue = null; +/** + * Dispatches an event and releases it back into the pool, unless persistent. + * + * @param {?object} event Synthetic event to be dispatched. + * @private + */ -function getComponentNameFromType(type) { - if (type == null) { - // Host root, text node or just invalid type. - return null; - } +function executeDispatchesAndRelease(event) { + if (event) { + executeDispatchesInOrder(event); - { - if (typeof type.tag === "number") { - error( - "Received an unexpected object in getComponentNameFromType(). " + - "This is likely a bug in React. Please file an issue." - ); + if (!event.isPersistent()) { + event.constructor.release(event); } } +} // $FlowFixMe[missing-local-annot] - if (typeof type === "function") { - return type.displayName || type.name || null; - } - - if (typeof type === "string") { - return type; - } - - switch (type) { - case REACT_FRAGMENT_TYPE: - return "Fragment"; - - case REACT_PORTAL_TYPE: - return "Portal"; - - case REACT_PROFILER_TYPE: - return "Profiler"; +function executeDispatchesAndReleaseTopLevel(e) { + return executeDispatchesAndRelease(e); +} - case REACT_STRICT_MODE_TYPE: - return "StrictMode"; +function runEventsInBatch(events) { + if (events !== null) { + eventQueue = accumulateInto(eventQueue, events); + } // Set `eventQueue` to null before processing it so that we can tell if more + // events get enqueued while processing. - case REACT_SUSPENSE_TYPE: - return "Suspense"; + var processingEventQueue = eventQueue; + eventQueue = null; - case REACT_SUSPENSE_LIST_TYPE: - return "SuspenseList"; + if (!processingEventQueue) { + return; } - if (typeof type === "object") { - switch (type.$$typeof) { - case REACT_CONTEXT_TYPE: - var context = type; - return getContextName$1(context) + ".Consumer"; - - case REACT_PROVIDER_TYPE: - var provider = type; - return getContextName$1(provider._context) + ".Provider"; + forEachAccumulated(processingEventQueue, executeDispatchesAndReleaseTopLevel); - case REACT_FORWARD_REF_TYPE: - return getWrappedName$1(type, type.render, "ForwardRef"); + if (eventQueue) { + throw new Error( + "processEventQueue(): Additional events were enqueued while processing " + + "an event queue. Support for this has not yet been implemented." + ); + } // This would be a good time to rethrow if any of the event handlers threw. - case REACT_MEMO_TYPE: - var outerName = type.displayName || null; + rethrowCaughtError(); +} - if (outerName !== null) { - return outerName; - } +/** + * Allows registered plugins an opportunity to extract events from top-level + * native browser events. + * + * @return {*} An accumulation of synthetic events. + * @internal + */ - return getComponentNameFromType(type.type) || "Memo"; +function extractPluginEvents( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget +) { + var events = null; + var legacyPlugins = plugins; - case REACT_LAZY_TYPE: { - var lazyComponent = type; - var payload = lazyComponent._payload; - var init = lazyComponent._init; + for (var i = 0; i < legacyPlugins.length; i++) { + // Not every plugin in the ordering may be loaded at runtime. + var possiblePlugin = legacyPlugins[i]; - try { - return getComponentNameFromType(init(payload)); - } catch (x) { - return null; - } - } + if (possiblePlugin) { + var extractedEvents = possiblePlugin.extractEvents( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ); - case REACT_SERVER_CONTEXT_TYPE: { - var context2 = type; - return (context2.displayName || context2._globalName) + ".Provider"; + if (extractedEvents) { + events = accumulateInto(events, extractedEvents); } - - // eslint-disable-next-line no-fallthrough } } - return null; -} - -function getWrappedName(outerType, innerType, wrapperName) { - var functionName = innerType.displayName || innerType.name || ""; - return ( - outerType.displayName || - (functionName !== "" ? wrapperName + "(" + functionName + ")" : wrapperName) - ); -} // Keep in sync with shared/getComponentNameFromType - -function getContextName(type) { - return type.displayName || "Context"; + return events; } -function getComponentNameFromFiber(fiber) { - var tag = fiber.tag, - type = fiber.type; - - switch (tag) { - case CacheComponent: - return "Cache"; - - case ContextConsumer: - var context = type; - return getContextName(context) + ".Consumer"; - - case ContextProvider: - var provider = type; - return getContextName(provider._context) + ".Provider"; - - case DehydratedFragment: - return "DehydratedFragment"; - - case ForwardRef: - return getWrappedName(type, type.render, "ForwardRef"); - - case Fragment: - return "Fragment"; - - case HostHoistable: - case HostSingleton: - case HostComponent: - // Host component type is the display name (e.g. "div", "View") - return type; - - case HostPortal: - return "Portal"; - - case HostRoot: - return "Root"; - - case HostText: - return "Text"; - - case LazyComponent: - // Name comes from the type in this case; we don't have a tag. - return getComponentNameFromType(type); - - case Mode: - if (type === REACT_STRICT_MODE_TYPE) { - // Don't be less specific than shared/getComponentNameFromType - return "StrictMode"; - } - - return "Mode"; - - case OffscreenComponent: - return "Offscreen"; - - case Profiler: - return "Profiler"; +function runExtractedPluginEventsInBatch( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget +) { + var events = extractPluginEvents( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ); + runEventsInBatch(events); +} - case ScopeComponent: - return "Scope"; +function dispatchEvent(target, topLevelType, nativeEvent) { + var targetFiber = target; + var eventTarget = null; - case SuspenseComponent: - return "Suspense"; + if (targetFiber != null) { + var stateNode = targetFiber.stateNode; // Guard against Fiber being unmounted - case SuspenseListComponent: - return "SuspenseList"; + if (stateNode != null) { + // $FlowExpectedError[incompatible-cast] public instances in Fabric do not implement `EventTarget` yet. + eventTarget = getPublicInstance(stateNode); + } + } - case TracingMarkerComponent: - return "TracingMarker"; - // The display name for this tags come from the user-provided type: + batchedUpdates$1(function () { + // Emit event to the RawEventEmitter. This is an unused-by-default EventEmitter + // that can be used to instrument event performance monitoring (primarily - could be useful + // for other things too). + // + // NOTE: this merely emits events into the EventEmitter below. + // If *you* do not add listeners to the `RawEventEmitter`, + // then all of these emitted events will just blackhole and are no-ops. + // It is available (although not officially supported... yet) if you want to collect + // perf data on event latency in your application, and could also be useful for debugging + // low-level events issues. + // + // If you do not have any event perf monitoring and are extremely concerned about event perf, + // it is safe to disable these "emit" statements; it will prevent checking the size of + // an empty array twice and prevent two no-ops. Practically the overhead is so low that + // we don't think it's worth thinking about in prod; your perf issues probably lie elsewhere. + // + // We emit two events here: one for listeners to this specific event, + // and one for the catchall listener '*', for any listeners that want + // to be notified for all events. + // Note that extracted events are *not* emitted, + // only events that have a 1:1 mapping with a native event, at least for now. + var event = { + eventName: topLevelType, + nativeEvent: nativeEvent + }; // $FlowFixMe[class-object-subtyping] found when upgrading Flow - case ClassComponent: - case FunctionComponent: - case IncompleteClassComponent: - case IndeterminateComponent: - case MemoComponent: - case SimpleMemoComponent: - if (typeof type === "function") { - return type.displayName || type.name || null; - } + ReactNativePrivateInterface.RawEventEmitter.emit(topLevelType, event); // $FlowFixMe[class-object-subtyping] found when upgrading Flow - if (typeof type === "string") { - return type; - } + ReactNativePrivateInterface.RawEventEmitter.emit("*", event); // Heritage plugin event system - break; + runExtractedPluginEventsInBatch( + topLevelType, + targetFiber, + nativeEvent, + eventTarget + ); + }); // React Native doesn't use ReactControlledComponent but if it did, here's + // where it would do it. +} - case LegacyHiddenComponent: { - return "LegacyHidden"; - } - } +// NOTE: There are no flags, currently. Uncomment the stuff below if we add one. +// the exports object every time a flag is read. - return null; -} +var enableUseRefAccessWarning = dynamicFlags.enableUseRefAccessWarning; // The rest of the flags are static for better dead code elimination. +var enableSchedulingProfiler = true; +var enableProfilerTimer = true; +var enableProfilerCommitHooks = true; +var enableProfilerNestedUpdatePhase = true; +var createRootStrictEffectsByDefault = false; +var enableLazyContextPropagation = false; var NoFlags$1 = /* */ @@ -3429,980 +3326,591 @@ var PassiveMask = Passive$1 | Visibility | ChildDeletion; // Union of tags that var StaticMask = LayoutStatic | PassiveStatic | RefStatic | SuspenseyCommit; -var ReactCurrentOwner$3 = ReactSharedInternals.ReactCurrentOwner; -function getNearestMountedFiber(fiber) { - var node = fiber; - var nearestMounted = fiber; +// This module only exists as an ESM wrapper around the external CommonJS +var scheduleCallback$1 = Scheduler.unstable_scheduleCallback; +var cancelCallback$1 = Scheduler.unstable_cancelCallback; +var shouldYield = Scheduler.unstable_shouldYield; +var requestPaint = Scheduler.unstable_requestPaint; +var now$1 = Scheduler.unstable_now; +var ImmediatePriority = Scheduler.unstable_ImmediatePriority; +var UserBlockingPriority = Scheduler.unstable_UserBlockingPriority; +var NormalPriority = Scheduler.unstable_NormalPriority; +var IdlePriority = Scheduler.unstable_IdlePriority; // this doesn't actually exist on the scheduler, but it *does* - if (!fiber.alternate) { - // If there is no alternate, this might be a new tree that isn't inserted - // yet. If it is, then it will have a pending insertion effect on it. - var nextNode = node; +// Helpers to patch console.logs to avoid logging during side-effect free +// replaying on render function. This currently only patches the object +// lazily which won't cover if the log function was extracted eagerly. +// We could also eagerly patch the method. +var disabledDepth = 0; +var prevLog; +var prevInfo; +var prevWarn; +var prevError; +var prevGroup; +var prevGroupCollapsed; +var prevGroupEnd; - do { - node = nextNode; +function disabledLog() {} - if ((node.flags & (Placement | Hydrating)) !== NoFlags$1) { - // This is an insertion or in-progress hydration. The nearest possible - // mounted fiber is the parent but we need to continue to figure out - // if that one is still mounted. - nearestMounted = node.return; - } // $FlowFixMe[incompatible-type] we bail out when we get a null +disabledLog.__reactDisabledLog = true; +function disableLogs() { + { + if (disabledDepth === 0) { + /* eslint-disable react-internal/no-production-logging */ + prevLog = console.log; + prevInfo = console.info; + prevWarn = console.warn; + prevError = console.error; + prevGroup = console.group; + prevGroupCollapsed = console.groupCollapsed; + prevGroupEnd = console.groupEnd; // https://github.com/facebook/react/issues/19099 - nextNode = node.return; - } while (nextNode); - } else { - while (node.return) { - node = node.return; - } - } + var props = { + configurable: true, + enumerable: true, + value: disabledLog, + writable: true + }; // $FlowFixMe Flow thinks console is immutable. - if (node.tag === HostRoot) { - // TODO: Check if this was a nested HostRoot when used with - // renderContainerIntoSubtree. - return nearestMounted; - } // If we didn't hit the root, that means that we're in an disconnected tree - // that has been unmounted. + Object.defineProperties(console, { + info: props, + log: props, + warn: props, + error: props, + group: props, + groupCollapsed: props, + groupEnd: props + }); + /* eslint-enable react-internal/no-production-logging */ + } - return null; -} -function isFiberMounted(fiber) { - return getNearestMountedFiber(fiber) === fiber; + disabledDepth++; + } } -function isMounted(component) { +function reenableLogs() { { - var owner = ReactCurrentOwner$3.current; + disabledDepth--; - if (owner !== null && owner.tag === ClassComponent) { - var ownerFiber = owner; - var instance = ownerFiber.stateNode; + if (disabledDepth === 0) { + /* eslint-disable react-internal/no-production-logging */ + var props = { + configurable: true, + enumerable: true, + writable: true + }; // $FlowFixMe Flow thinks console is immutable. - if (!instance._warnedAboutRefsInRender) { - error( - "%s is accessing isMounted inside its render() function. " + - "render() should be a pure function of props and state. It should " + - "never access something that requires stale data from the previous " + - "render, such as refs. Move this logic to componentDidMount and " + - "componentDidUpdate instead.", - getComponentNameFromFiber(ownerFiber) || "A component" - ); - } + Object.defineProperties(console, { + log: assign({}, props, { + value: prevLog + }), + info: assign({}, props, { + value: prevInfo + }), + warn: assign({}, props, { + value: prevWarn + }), + error: assign({}, props, { + value: prevError + }), + group: assign({}, props, { + value: prevGroup + }), + groupCollapsed: assign({}, props, { + value: prevGroupCollapsed + }), + groupEnd: assign({}, props, { + value: prevGroupEnd + }) + }); + /* eslint-enable react-internal/no-production-logging */ + } - instance._warnedAboutRefsInRender = true; + if (disabledDepth < 0) { + error( + "disabledDepth fell below zero. " + + "This is a bug in React. Please file an issue." + ); } } +} - var fiber = get(component); - - if (!fiber) { +var rendererID = null; +var injectedHook = null; +var injectedProfilingHooks = null; +var hasLoggedError = false; +var isDevToolsPresent = typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== "undefined"; +function injectInternals(internals) { + if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === "undefined") { + // No DevTools return false; } - return getNearestMountedFiber(fiber) === fiber; -} + var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__; -function assertIsMounted(fiber) { - if (getNearestMountedFiber(fiber) !== fiber) { - throw new Error("Unable to find node on an unmounted component."); + if (hook.isDisabled) { + // This isn't a real property on the hook, but it can be set to opt out + // of DevTools integration and associated warnings and logs. + // https://github.com/facebook/react/issues/3877 + return true; } -} - -function findCurrentFiberUsingSlowPath(fiber) { - var alternate = fiber.alternate; - if (!alternate) { - // If there is no alternate, then we only need to check if it is mounted. - var nearestMounted = getNearestMountedFiber(fiber); + if (!hook.supportsFiber) { + { + error( + "The installed version of React DevTools is too old and will not work " + + "with the current version of React. Please update React DevTools. " + + "https://reactjs.org/link/react-devtools" + ); + } // DevTools exists, even though it doesn't support Fiber. - if (nearestMounted === null) { - throw new Error("Unable to find node on an unmounted component."); - } + return true; + } - if (nearestMounted !== fiber) { - return null; + try { + if (enableSchedulingProfiler) { + // Conditionally inject these hooks only if Timeline profiler is supported by this build. + // This gives DevTools a way to feature detect that isn't tied to version number + // (since profiling and timeline are controlled by different feature flags). + internals = assign({}, internals, { + getLaneLabelMap: getLaneLabelMap, + injectProfilingHooks: injectProfilingHooks + }); } - return fiber; - } // If we have two possible branches, we'll walk backwards up to the root - // to see what path the root points to. On the way we may hit one of the - // special cases and we'll deal with them. - - var a = fiber; - var b = alternate; - - while (true) { - var parentA = a.return; + rendererID = hook.inject(internals); // We have successfully injected, so now it is safe to set up hooks. - if (parentA === null) { - // We're at the root. - break; + injectedHook = hook; + } catch (err) { + // Catch all errors because it is unsafe to throw during initialization. + { + error("React instrumentation encountered an error: %s.", err); } + } - var parentB = parentA.alternate; - - if (parentB === null) { - // There is no alternate. This is an unusual case. Currently, it only - // happens when a Suspense component is hidden. An extra fragment fiber - // is inserted in between the Suspense fiber and its children. Skip - // over this extra fragment fiber and proceed to the next parent. - var nextParent = parentA.return; - - if (nextParent !== null) { - a = b = nextParent; - continue; - } // If there's no parent, we're at the root. - - break; - } // If both copies of the parent fiber point to the same child, we can - // assume that the child is current. This happens when we bailout on low - // priority: the bailed out fiber's child reuses the current child. - - if (parentA.child === parentB.child) { - var child = parentA.child; - - while (child) { - if (child === a) { - // We've determined that A is the current branch. - assertIsMounted(parentA); - return fiber; - } + if (hook.checkDCE) { + // This is the real DevTools. + return true; + } else { + // This is likely a hook installed by Fast Refresh runtime. + return false; + } +} +function onScheduleRoot(root, children) { + { + if ( + injectedHook && + typeof injectedHook.onScheduleFiberRoot === "function" + ) { + try { + injectedHook.onScheduleFiberRoot(rendererID, root, children); + } catch (err) { + if (!hasLoggedError) { + hasLoggedError = true; - if (child === b) { - // We've determined that B is the current branch. - assertIsMounted(parentA); - return alternate; + error("React instrumentation encountered an error: %s", err); } - - child = child.sibling; - } // We should never have an alternate for any mounting node. So the only - // way this could possibly happen is if this was unmounted, if at all. - - throw new Error("Unable to find node on an unmounted component."); + } } + } +} +function onCommitRoot(root, eventPriority) { + if (injectedHook && typeof injectedHook.onCommitFiberRoot === "function") { + try { + var didError = (root.current.flags & DidCapture) === DidCapture; - if (a.return !== b.return) { - // The return pointer of A and the return pointer of B point to different - // fibers. We assume that return pointers never criss-cross, so A must - // belong to the child set of A.return, and B must belong to the child - // set of B.return. - a = parentA; - b = parentB; - } else { - // The return pointers point to the same fiber. We'll have to use the - // default, slow path: scan the child sets of each parent alternate to see - // which child belongs to which set. - // - // Search parent A's child set - var didFindChild = false; - var _child = parentA.child; - - while (_child) { - if (_child === a) { - didFindChild = true; - a = parentA; - b = parentB; - break; - } - - if (_child === b) { - didFindChild = true; - b = parentA; - a = parentB; - break; - } + if (enableProfilerTimer) { + var schedulerPriority; - _child = _child.sibling; - } + switch (eventPriority) { + case DiscreteEventPriority: + schedulerPriority = ImmediatePriority; + break; - if (!didFindChild) { - // Search parent B's child set - _child = parentB.child; + case ContinuousEventPriority: + schedulerPriority = UserBlockingPriority; + break; - while (_child) { - if (_child === a) { - didFindChild = true; - a = parentB; - b = parentA; + case DefaultEventPriority: + schedulerPriority = NormalPriority; break; - } - if (_child === b) { - didFindChild = true; - b = parentB; - a = parentA; + case IdleEventPriority: + schedulerPriority = IdlePriority; break; - } - _child = _child.sibling; + default: + schedulerPriority = NormalPriority; + break; } - if (!didFindChild) { - throw new Error( - "Child was not found in either parent set. This indicates a bug " + - "in React related to the return pointer. Please file an issue." - ); - } + injectedHook.onCommitFiberRoot( + rendererID, + root, + schedulerPriority, + didError + ); } - } - - if (a.alternate !== b) { - throw new Error( - "Return fibers should always be each others' alternates. " + - "This error is likely caused by a bug in React. Please file an issue." - ); - } - } // If the root is not a host container, we're in a disconnected tree. I.e. - // unmounted. + } catch (err) { + { + if (!hasLoggedError) { + hasLoggedError = true; - if (a.tag !== HostRoot) { - throw new Error("Unable to find node on an unmounted component."); + error("React instrumentation encountered an error: %s", err); + } + } + } } - - if (a.stateNode.current === a) { - // We've determined that A is the current branch. - return fiber; - } // Otherwise B has to be current branch. - - return alternate; } -function findCurrentHostFiber(parent) { - var currentParent = findCurrentFiberUsingSlowPath(parent); - return currentParent !== null - ? findCurrentHostFiberImpl(currentParent) - : null; -} - -function findCurrentHostFiberImpl(node) { - // Next we'll drill down this component to find the first HostComponent/Text. - var tag = node.tag; - +function onPostCommitRoot(root) { if ( - tag === HostComponent || - tag === HostHoistable || - tag === HostSingleton || - tag === HostText + injectedHook && + typeof injectedHook.onPostCommitFiberRoot === "function" ) { - return node; - } - - var child = node.child; - - while (child !== null) { - var match = findCurrentHostFiberImpl(child); + try { + injectedHook.onPostCommitFiberRoot(rendererID, root); + } catch (err) { + { + if (!hasLoggedError) { + hasLoggedError = true; - if (match !== null) { - return match; + error("React instrumentation encountered an error: %s", err); + } + } } - - child = child.sibling; } - - return null; } +function onCommitUnmount(fiber) { + if (injectedHook && typeof injectedHook.onCommitFiberUnmount === "function") { + try { + injectedHook.onCommitFiberUnmount(rendererID, fiber); + } catch (err) { + { + if (!hasLoggedError) { + hasLoggedError = true; -// Helpers to patch console.logs to avoid logging during side-effect free -// replaying on render function. This currently only patches the object -// lazily which won't cover if the log function was extracted eagerly. -// We could also eagerly patch the method. -var disabledDepth = 0; -var prevLog; -var prevInfo; -var prevWarn; -var prevError; -var prevGroup; -var prevGroupCollapsed; -var prevGroupEnd; - -function disabledLog() {} - -disabledLog.__reactDisabledLog = true; -function disableLogs() { - { - if (disabledDepth === 0) { - /* eslint-disable react-internal/no-production-logging */ - prevLog = console.log; - prevInfo = console.info; - prevWarn = console.warn; - prevError = console.error; - prevGroup = console.group; - prevGroupCollapsed = console.groupCollapsed; - prevGroupEnd = console.groupEnd; // https://github.com/facebook/react/issues/19099 - - var props = { - configurable: true, - enumerable: true, - value: disabledLog, - writable: true - }; // $FlowFixMe Flow thinks console is immutable. - - Object.defineProperties(console, { - info: props, - log: props, - warn: props, - error: props, - group: props, - groupCollapsed: props, - groupEnd: props - }); - /* eslint-enable react-internal/no-production-logging */ + error("React instrumentation encountered an error: %s", err); + } + } } - - disabledDepth++; } } -function reenableLogs() { +function setIsStrictModeForDevtools(newIsStrictMode) { { - disabledDepth--; - - if (disabledDepth === 0) { - /* eslint-disable react-internal/no-production-logging */ - var props = { - configurable: true, - enumerable: true, - writable: true - }; // $FlowFixMe Flow thinks console is immutable. - - Object.defineProperties(console, { - log: assign({}, props, { - value: prevLog - }), - info: assign({}, props, { - value: prevInfo - }), - warn: assign({}, props, { - value: prevWarn - }), - error: assign({}, props, { - value: prevError - }), - group: assign({}, props, { - value: prevGroup - }), - groupCollapsed: assign({}, props, { - value: prevGroupCollapsed - }), - groupEnd: assign({}, props, { - value: prevGroupEnd - }) - }); - /* eslint-enable react-internal/no-production-logging */ - } - - if (disabledDepth < 0) { - error( - "disabledDepth fell below zero. " + - "This is a bug in React. Please file an issue." - ); + if (newIsStrictMode) { + disableLogs(); + } else { + reenableLogs(); } } +} // Profiler API hooks + +function injectProfilingHooks(profilingHooks) { + injectedProfilingHooks = profilingHooks; } -function describeBuiltInComponentFrame(name, source, ownerFn) { +function getLaneLabelMap() { { - var ownerName = null; + var map = new Map(); + var lane = 1; - if (ownerFn) { - ownerName = ownerFn.displayName || ownerFn.name || null; + for (var index = 0; index < TotalLanes; index++) { + var label = getLabelForLane(lane); + map.set(lane, label); + lane *= 2; } - return describeComponentFrame(name, source, ownerName); + return map; } } -{ - var PossiblyWeakMap$1 = typeof WeakMap === "function" ? WeakMap : Map; - new PossiblyWeakMap$1(); -} -var BEFORE_SLASH_RE = /^(.*)[\\\/]/; - -function describeComponentFrame(name, source, ownerName) { - var sourceInfo = ""; - - if (source) { - var path = source.fileName; - var fileName = path.replace(BEFORE_SLASH_RE, ""); // In DEV, include code for a common special case: - // prefer "folder/index.js" instead of just "index.js". - - if (/^index\./.test(fileName)) { - var match = path.match(BEFORE_SLASH_RE); - - if (match) { - var pathBeforeSlash = match[1]; - - if (pathBeforeSlash) { - var folderName = pathBeforeSlash.replace(BEFORE_SLASH_RE, ""); - fileName = folderName + "/" + fileName; - } - } +function markCommitStarted(lanes) { + { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markCommitStarted === "function" + ) { + injectedProfilingHooks.markCommitStarted(lanes); } - - sourceInfo = " (at " + fileName + ":" + source.lineNumber + ")"; - } else if (ownerName) { - sourceInfo = " (created by " + ownerName + ")"; } - - return "\n in " + (name || "Unknown") + sourceInfo; } - -function describeClassComponentFrame(ctor, source, ownerFn) { +function markCommitStopped() { { - return describeFunctionComponentFrame(ctor, source, ownerFn); + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markCommitStopped === "function" + ) { + injectedProfilingHooks.markCommitStopped(); + } } } -function describeFunctionComponentFrame(fn, source, ownerFn) { +function markComponentRenderStarted(fiber) { { - if (!fn) { - return ""; - } - - var name = fn.displayName || fn.name || null; - var ownerName = null; - - if (ownerFn) { - ownerName = ownerFn.displayName || ownerFn.name || null; + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentRenderStarted === "function" + ) { + injectedProfilingHooks.markComponentRenderStarted(fiber); } - - return describeComponentFrame(name, source, ownerName); } } - -function describeUnknownElementTypeFrameInDEV(type, source, ownerFn) { - if (type == null) { - return ""; - } - - if (typeof type === "function") { - { - return describeFunctionComponentFrame(type, source, ownerFn); +function markComponentRenderStopped() { + { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentRenderStopped === "function" + ) { + injectedProfilingHooks.markComponentRenderStopped(); } } - - if (typeof type === "string") { - return describeBuiltInComponentFrame(type, source, ownerFn); - } - - switch (type) { - case REACT_SUSPENSE_TYPE: - return describeBuiltInComponentFrame("Suspense", source, ownerFn); - - case REACT_SUSPENSE_LIST_TYPE: - return describeBuiltInComponentFrame("SuspenseList", source, ownerFn); - } - - if (typeof type === "object") { - switch (type.$$typeof) { - case REACT_FORWARD_REF_TYPE: - return describeFunctionComponentFrame(type.render, source, ownerFn); - - case REACT_MEMO_TYPE: - // Memo may contain any component type so we recursively resolve it. - return describeUnknownElementTypeFrameInDEV(type.type, source, ownerFn); - - case REACT_LAZY_TYPE: { - var lazyComponent = type; - var payload = lazyComponent._payload; - var init = lazyComponent._init; - - try { - // Lazy may contain any component type so we recursively resolve it. - return describeUnknownElementTypeFrameInDEV( - init(payload), - source, - ownerFn - ); - } catch (x) {} - } +} +function markComponentPassiveEffectMountStarted(fiber) { + { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentPassiveEffectMountStarted === + "function" + ) { + injectedProfilingHooks.markComponentPassiveEffectMountStarted(fiber); } } - - return ""; } - -// $FlowFixMe[method-unbinding] -var hasOwnProperty = Object.prototype.hasOwnProperty; - -var loggedTypeFailures = {}; -var ReactDebugCurrentFrame$1 = ReactSharedInternals.ReactDebugCurrentFrame; - -function setCurrentlyValidatingElement(element) { +function markComponentPassiveEffectMountStopped() { { - if (element) { - var owner = element._owner; - var stack = describeUnknownElementTypeFrameInDEV( - element.type, - element._source, - owner ? owner.type : null - ); - ReactDebugCurrentFrame$1.setExtraStackFrame(stack); - } else { - ReactDebugCurrentFrame$1.setExtraStackFrame(null); + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentPassiveEffectMountStopped === + "function" + ) { + injectedProfilingHooks.markComponentPassiveEffectMountStopped(); } } } - -function checkPropTypes(typeSpecs, values, location, componentName, element) { +function markComponentPassiveEffectUnmountStarted(fiber) { { - // $FlowFixMe This is okay but Flow doesn't know it. - var has = Function.call.bind(hasOwnProperty); - - for (var typeSpecName in typeSpecs) { - if (has(typeSpecs, typeSpecName)) { - var error$1 = void 0; // Prop type validation may throw. In case they do, we don't want to - // fail the render phase where it didn't fail before. So we log it. - // After these have been cleaned up, we'll let them throw. - - try { - // This is intentionally an invariant that gets caught. It's the same - // behavior as without this statement except with a better message. - if (typeof typeSpecs[typeSpecName] !== "function") { - // eslint-disable-next-line react-internal/prod-error-codes - var err = Error( - (componentName || "React class") + - ": " + - location + - " type `" + - typeSpecName + - "` is invalid; " + - "it must be a function, usually from the `prop-types` package, but received `" + - typeof typeSpecs[typeSpecName] + - "`." + - "This often happens because of typos such as `PropTypes.function` instead of `PropTypes.func`." - ); - err.name = "Invariant Violation"; - throw err; - } - - error$1 = typeSpecs[typeSpecName]( - values, - typeSpecName, - componentName, - location, - null, - "SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED" - ); - } catch (ex) { - error$1 = ex; - } - - if (error$1 && !(error$1 instanceof Error)) { - setCurrentlyValidatingElement(element); - - error( - "%s: type specification of %s" + - " `%s` is invalid; the type checker " + - "function must return `null` or an `Error` but returned a %s. " + - "You may have forgotten to pass an argument to the type checker " + - "creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and " + - "shape all require an argument).", - componentName || "React class", - location, - typeSpecName, - typeof error$1 - ); - - setCurrentlyValidatingElement(null); - } - - if ( - error$1 instanceof Error && - !(error$1.message in loggedTypeFailures) - ) { - // Only monitor this failure once because there tends to be a lot of the - // same error. - loggedTypeFailures[error$1.message] = true; - setCurrentlyValidatingElement(element); - - error("Failed %s type: %s", location, error$1.message); - - setCurrentlyValidatingElement(null); - } - } + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentPassiveEffectUnmountStarted === + "function" + ) { + injectedProfilingHooks.markComponentPassiveEffectUnmountStarted(fiber); } } } - -var valueStack = []; -var fiberStack; - -{ - fiberStack = []; -} - -var index = -1; - -function createCursor(defaultValue) { - return { - current: defaultValue - }; -} - -function pop(cursor, fiber) { - if (index < 0) { - { - error("Unexpected pop."); +function markComponentPassiveEffectUnmountStopped() { + { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentPassiveEffectUnmountStopped === + "function" + ) { + injectedProfilingHooks.markComponentPassiveEffectUnmountStopped(); } - - return; } - +} +function markComponentLayoutEffectMountStarted(fiber) { { - if (fiber !== fiberStack[index]) { - error("Unexpected Fiber popped."); + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentLayoutEffectMountStarted === + "function" + ) { + injectedProfilingHooks.markComponentLayoutEffectMountStarted(fiber); } } - - cursor.current = valueStack[index]; - valueStack[index] = null; - +} +function markComponentLayoutEffectMountStopped() { { - fiberStack[index] = null; + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentLayoutEffectMountStopped === + "function" + ) { + injectedProfilingHooks.markComponentLayoutEffectMountStopped(); + } } - - index--; } - -function push(cursor, value, fiber) { - index++; - valueStack[index] = cursor.current; - +function markComponentLayoutEffectUnmountStarted(fiber) { { - fiberStack[index] = fiber; + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentLayoutEffectUnmountStarted === + "function" + ) { + injectedProfilingHooks.markComponentLayoutEffectUnmountStarted(fiber); + } } - - cursor.current = value; } - -var warnedAboutMissingGetChildContext; - -{ - warnedAboutMissingGetChildContext = {}; +function markComponentLayoutEffectUnmountStopped() { + { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentLayoutEffectUnmountStopped === + "function" + ) { + injectedProfilingHooks.markComponentLayoutEffectUnmountStopped(); + } + } } - -var emptyContextObject = {}; - -{ - Object.freeze(emptyContextObject); -} // A cursor to the current merged context object on the stack. - -var contextStackCursor$1 = createCursor(emptyContextObject); // A cursor to a boolean indicating whether the context has changed. - -var didPerformWorkStackCursor = createCursor(false); // Keep track of the previous context object that was on the stack. -// We use this to get access to the parent context after we have already -// pushed the next context provider, and now need to merge their contexts. - -var previousContext = emptyContextObject; - -function getUnmaskedContext( - workInProgress, - Component, - didPushOwnContextIfProvider -) { +function markComponentErrored(fiber, thrownValue, lanes) { { - if (didPushOwnContextIfProvider && isContextProvider(Component)) { - // If the fiber is a context provider itself, when we read its context - // we may have already pushed its own child context on the stack. A context - // provider should not "see" its own child context. Therefore we read the - // previous (parent) context instead for a context provider. - return previousContext; + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentErrored === "function" + ) { + injectedProfilingHooks.markComponentErrored(fiber, thrownValue, lanes); } - - return contextStackCursor$1.current; } } - -function cacheContext(workInProgress, unmaskedContext, maskedContext) { +function markComponentSuspended(fiber, wakeable, lanes) { { - var instance = workInProgress.stateNode; - instance.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext; - instance.__reactInternalMemoizedMaskedChildContext = maskedContext; + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentSuspended === "function" + ) { + injectedProfilingHooks.markComponentSuspended(fiber, wakeable, lanes); + } } } - -function getMaskedContext(workInProgress, unmaskedContext) { +function markLayoutEffectsStarted(lanes) { { - var type = workInProgress.type; - var contextTypes = type.contextTypes; - - if (!contextTypes) { - return emptyContextObject; - } // Avoid recreating masked context unless unmasked context has changed. - // Failing to do this will result in unnecessary calls to componentWillReceiveProps. - // This may trigger infinite loops if componentWillReceiveProps calls setState. - - var instance = workInProgress.stateNode; - if ( - instance && - instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markLayoutEffectsStarted === "function" ) { - return instance.__reactInternalMemoizedMaskedChildContext; + injectedProfilingHooks.markLayoutEffectsStarted(lanes); } - - var context = {}; - - for (var key in contextTypes) { - context[key] = unmaskedContext[key]; + } +} +function markLayoutEffectsStopped() { + { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markLayoutEffectsStopped === "function" + ) { + injectedProfilingHooks.markLayoutEffectsStopped(); } - - { - var name = getComponentNameFromFiber(workInProgress) || "Unknown"; - checkPropTypes(contextTypes, context, "context", name); - } // Cache unmasked context so we can avoid recreating masked context unless necessary. - // Context is created before the class component is instantiated so check for instance. - - if (instance) { - cacheContext(workInProgress, unmaskedContext, context); + } +} +function markPassiveEffectsStarted(lanes) { + { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markPassiveEffectsStarted === "function" + ) { + injectedProfilingHooks.markPassiveEffectsStarted(lanes); } - - return context; } } - -function hasContextChanged() { +function markPassiveEffectsStopped() { { - return didPerformWorkStackCursor.current; + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markPassiveEffectsStopped === "function" + ) { + injectedProfilingHooks.markPassiveEffectsStopped(); + } } } - -function isContextProvider(type) { +function markRenderStarted(lanes) { { - var childContextTypes = type.childContextTypes; - return childContextTypes !== null && childContextTypes !== undefined; + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markRenderStarted === "function" + ) { + injectedProfilingHooks.markRenderStarted(lanes); + } } } - -function popContext(fiber) { +function markRenderYielded() { { - pop(didPerformWorkStackCursor, fiber); - pop(contextStackCursor$1, fiber); + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markRenderYielded === "function" + ) { + injectedProfilingHooks.markRenderYielded(); + } } } - -function popTopLevelContextObject(fiber) { +function markRenderStopped() { { - pop(didPerformWorkStackCursor, fiber); - pop(contextStackCursor$1, fiber); + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markRenderStopped === "function" + ) { + injectedProfilingHooks.markRenderStopped(); + } } } - -function pushTopLevelContextObject(fiber, context, didChange) { +function markRenderScheduled(lane) { { - if (contextStackCursor$1.current !== emptyContextObject) { - throw new Error( - "Unexpected context found on stack. " + - "This error is likely caused by a bug in React. Please file an issue." - ); + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markRenderScheduled === "function" + ) { + injectedProfilingHooks.markRenderScheduled(lane); } - - push(contextStackCursor$1, context, fiber); - push(didPerformWorkStackCursor, didChange, fiber); } } - -function processChildContext(fiber, type, parentContext) { +function markForceUpdateScheduled(fiber, lane) { { - var instance = fiber.stateNode; - var childContextTypes = type.childContextTypes; // TODO (bvaughn) Replace this behavior with an invariant() in the future. - // It has only been added in Fiber to match the (unintentional) behavior in Stack. - - if (typeof instance.getChildContext !== "function") { - { - var componentName = getComponentNameFromFiber(fiber) || "Unknown"; - - if (!warnedAboutMissingGetChildContext[componentName]) { - warnedAboutMissingGetChildContext[componentName] = true; + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markForceUpdateScheduled === "function" + ) { + injectedProfilingHooks.markForceUpdateScheduled(fiber, lane); + } + } +} +function markStateUpdateScheduled(fiber, lane) { + { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markStateUpdateScheduled === "function" + ) { + injectedProfilingHooks.markStateUpdateScheduled(fiber, lane); + } + } +} - error( - "%s.childContextTypes is specified but there is no getChildContext() method " + - "on the instance. You can either define getChildContext() on %s or remove " + - "childContextTypes from it.", - componentName, - componentName - ); - } - } +var NoMode = + /* */ + 0; // TODO: Remove ConcurrentMode by reading from the root tag instead - return parentContext; - } +var ConcurrentMode = + /* */ + 1; +var ProfileMode = + /* */ + 2; +var StrictLegacyMode = + /* */ + 8; +var StrictEffectsMode = + /* */ + 16; +var ConcurrentUpdatesByDefaultMode = + /* */ + 32; - var childContext = instance.getChildContext(); +// TODO: This is pretty well supported by browsers. Maybe we can drop it. +var clz32 = Math.clz32 ? Math.clz32 : clz32Fallback; // Count leading zeros. +// Based on: +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32 - for (var contextKey in childContext) { - if (!(contextKey in childContextTypes)) { - throw new Error( - (getComponentNameFromFiber(fiber) || "Unknown") + - '.getChildContext(): key "' + - contextKey + - '" is not defined in childContextTypes.' - ); - } - } +var log = Math.log; +var LN2 = Math.LN2; - { - var name = getComponentNameFromFiber(fiber) || "Unknown"; - checkPropTypes(childContextTypes, childContext, "child context", name); - } +function clz32Fallback(x) { + var asUint = x >>> 0; - return assign({}, parentContext, childContext); + if (asUint === 0) { + return 32; } + + return (31 - ((log(asUint) / LN2) | 0)) | 0; } -function pushContextProvider(workInProgress) { - { - var instance = workInProgress.stateNode; // We push the context as early as possible to ensure stack integrity. - // If the instance does not exist yet, we will push null at first, - // and replace it on the stack later when invalidating the context. - - var memoizedMergedChildContext = - (instance && instance.__reactInternalMemoizedMergedChildContext) || - emptyContextObject; // Remember the parent context so we can merge with it later. - // Inherit the parent's did-perform-work value to avoid inadvertently blocking updates. - - previousContext = contextStackCursor$1.current; - push(contextStackCursor$1, memoizedMergedChildContext, workInProgress); - push( - didPerformWorkStackCursor, - didPerformWorkStackCursor.current, - workInProgress - ); - return true; - } -} - -function invalidateContextProvider(workInProgress, type, didChange) { - { - var instance = workInProgress.stateNode; - - if (!instance) { - throw new Error( - "Expected to have an instance by this point. " + - "This error is likely caused by a bug in React. Please file an issue." - ); - } - - if (didChange) { - // Merge parent and own context. - // Skip this if we're not updating due to sCU. - // This avoids unnecessarily recomputing memoized values. - var mergedContext = processChildContext( - workInProgress, - type, - previousContext - ); - instance.__reactInternalMemoizedMergedChildContext = mergedContext; // Replace the old (or empty) context with the new one. - // It is important to unwind the context in the reverse order. - - pop(didPerformWorkStackCursor, workInProgress); - pop(contextStackCursor$1, workInProgress); // Now push the new context and mark that it has changed. - - push(contextStackCursor$1, mergedContext, workInProgress); - push(didPerformWorkStackCursor, didChange, workInProgress); - } else { - pop(didPerformWorkStackCursor, workInProgress); - push(didPerformWorkStackCursor, didChange, workInProgress); - } - } -} - -function findCurrentUnmaskedContext(fiber) { - { - // Currently this is only used with renderSubtreeIntoContainer; not sure if it - // makes sense elsewhere - if (!isFiberMounted(fiber) || fiber.tag !== ClassComponent) { - throw new Error( - "Expected subtree parent to be a mounted class component. " + - "This error is likely caused by a bug in React. Please file an issue." - ); - } - - var node = fiber; - - do { - switch (node.tag) { - case HostRoot: - return node.stateNode.context; - - case ClassComponent: { - var Component = node.type; - - if (isContextProvider(Component)) { - return node.stateNode.__reactInternalMemoizedMergedChildContext; - } - - break; - } - } // $FlowFixMe[incompatible-type] we bail out when we get a null - - node = node.return; - } while (node !== null); - - throw new Error( - "Found unexpected detached subtree parent. " + - "This error is likely caused by a bug in React. Please file an issue." - ); - } -} - -var LegacyRoot = 0; -var ConcurrentRoot = 1; - -// We use the existence of the state object as an indicator that the component -// is hidden. -var OffscreenVisible = - /* */ - 1; -var OffscreenDetached = - /* */ - 2; -var OffscreenPassiveEffectsConnected = - /* */ - 4; -function isOffscreenManual(offscreenFiber) { - return ( - offscreenFiber.memoizedProps !== null && - offscreenFiber.memoizedProps.mode === "manual" - ); -} - -var NoMode = - /* */ - 0; // TODO: Remove ConcurrentMode by reading from the root tag instead - -var ConcurrentMode = - /* */ - 1; -var ProfileMode = - /* */ - 2; -var StrictLegacyMode = - /* */ - 8; -var StrictEffectsMode = - /* */ - 16; -var ConcurrentUpdatesByDefaultMode = - /* */ - 32; - -// TODO: This is pretty well supported by browsers. Maybe we can drop it. -var clz32 = Math.clz32 ? Math.clz32 : clz32Fallback; // Count leading zeros. -// Based on: -// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32 - -var log = Math.log; -var LN2 = Math.LN2; - -function clz32Fallback(x) { - var asUint = x >>> 0; - - if (asUint === 0) { - return 32; - } - - return (31 - ((log(asUint) / LN2) | 0)) | 0; -} - -// If those values are changed that package should be rebuilt and redeployed. +// If those values are changed that package should be rebuilt and redeployed. var TotalLanes = 31; var NoLanes = @@ -5294,11654 +4802,11237 @@ function lanesToEventPriority(lanes) { return IdleEventPriority; } -// This module only exists as an ESM wrapper around the external CommonJS -var scheduleCallback$1 = Scheduler.unstable_scheduleCallback; -var cancelCallback$1 = Scheduler.unstable_cancelCallback; -var shouldYield = Scheduler.unstable_shouldYield; -var requestPaint = Scheduler.unstable_requestPaint; -var now$1 = Scheduler.unstable_now; -var ImmediatePriority = Scheduler.unstable_ImmediatePriority; -var UserBlockingPriority = Scheduler.unstable_UserBlockingPriority; -var NormalPriority = Scheduler.unstable_NormalPriority; -var IdlePriority = Scheduler.unstable_IdlePriority; // this doesn't actually exist on the scheduler, but it *does* - -var rendererID = null; -var injectedHook = null; -var injectedProfilingHooks = null; -var hasLoggedError = false; -var isDevToolsPresent = typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== "undefined"; -function injectInternals(internals) { - if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === "undefined") { - // No DevTools - return false; - } +// Renderers that don't support mutation +// can re-export everything from this module. +function shim$1() { + throw new Error( + "The current renderer does not support mutation. " + + "This error is likely caused by a bug in React. " + + "Please file an issue." + ); +} // Mutation (when unsupported) +var commitMount = shim$1; - var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__; +// Renderers that don't support hydration +// can re-export everything from this module. +function shim() { + throw new Error( + "The current renderer does not support hydration. " + + "This error is likely caused by a bug in React. " + + "Please file an issue." + ); +} // Hydration (when unsupported) +var isSuspenseInstancePending = shim; +var isSuspenseInstanceFallback = shim; +var getSuspenseInstanceFallbackErrorDetails = shim; +var registerSuspenseInstanceRetry = shim; +var errorHydratingContainer = shim; - if (hook.isDisabled) { - // This isn't a real property on the hook, but it can be set to opt out - // of DevTools integration and associated warnings and logs. - // https://github.com/facebook/react/issues/3877 - return true; - } +var _nativeFabricUIManage = nativeFabricUIManager, + createNode = _nativeFabricUIManage.createNode, + cloneNode = _nativeFabricUIManage.cloneNode, + cloneNodeWithNewChildren = _nativeFabricUIManage.cloneNodeWithNewChildren, + cloneNodeWithNewChildrenAndProps = + _nativeFabricUIManage.cloneNodeWithNewChildrenAndProps, + cloneNodeWithNewProps = _nativeFabricUIManage.cloneNodeWithNewProps, + createChildNodeSet = _nativeFabricUIManage.createChildSet, + appendChildNode = _nativeFabricUIManage.appendChild, + appendChildNodeToSet = _nativeFabricUIManage.appendChildToSet, + completeRoot = _nativeFabricUIManage.completeRoot, + registerEventHandler = _nativeFabricUIManage.registerEventHandler, + FabricDefaultPriority = _nativeFabricUIManage.unstable_DefaultEventPriority, + FabricDiscretePriority = _nativeFabricUIManage.unstable_DiscreteEventPriority, + fabricGetCurrentEventPriority = + _nativeFabricUIManage.unstable_getCurrentEventPriority; +var getViewConfigForType = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.get; // Counter for uniquely identifying views. +// % 10 === 1 means it is a rootTag. +// % 2 === 0 means it is a Fabric tag. +// This means that they never overlap. - if (!hook.supportsFiber) { - { - error( - "The installed version of React DevTools is too old and will not work " + - "with the current version of React. Please update React DevTools. " + - "https://reactjs.org/link/react-devtools" - ); - } // DevTools exists, even though it doesn't support Fiber. +var nextReactTag = 2; // TODO: Remove this conditional once all changes have propagated. - return true; - } +if (registerEventHandler) { + /** + * Register the event emitter with the native bridge + */ + registerEventHandler(dispatchEvent); +} +function appendInitialChild(parentInstance, child) { + appendChildNode(parentInstance.node, child.node); +} +function createInstance( + type, + props, + rootContainerInstance, + hostContext, + internalInstanceHandle +) { + var tag = nextReactTag; + nextReactTag += 2; + var viewConfig = getViewConfigForType(type); - try { - if (enableSchedulingProfiler) { - // Conditionally inject these hooks only if Timeline profiler is supported by this build. - // This gives DevTools a way to feature detect that isn't tied to version number - // (since profiling and timeline are controlled by different feature flags). - internals = assign({}, internals, { - getLaneLabelMap: getLaneLabelMap, - injectProfilingHooks: injectProfilingHooks - }); - } - - rendererID = hook.inject(internals); // We have successfully injected, so now it is safe to set up hooks. - - injectedHook = hook; - } catch (err) { - // Catch all errors because it is unsafe to throw during initialization. - { - error("React instrumentation encountered an error: %s.", err); + { + for (var key in viewConfig.validAttributes) { + if (props.hasOwnProperty(key)) { + ReactNativePrivateInterface.deepFreezeAndThrowOnMutationInDev( + props[key] + ); + } } } - if (hook.checkDCE) { - // This is the real DevTools. - return true; - } else { - // This is likely a hook installed by Fast Refresh runtime. - return false; - } + var updatePayload = create(props, viewConfig.validAttributes); + var node = createNode( + tag, // reactTag + viewConfig.uiViewClassName, // viewName + rootContainerInstance, // rootTag + updatePayload, // props + internalInstanceHandle // internalInstanceHandle + ); + var component = ReactNativePrivateInterface.createPublicInstance( + tag, + viewConfig, + internalInstanceHandle + ); + return { + node: node, + canonical: { + nativeTag: tag, + viewConfig: viewConfig, + currentProps: props, + internalInstanceHandle: internalInstanceHandle, + publicInstance: component + } + }; } -function onScheduleRoot(root, children) { +function createTextInstance( + text, + rootContainerInstance, + hostContext, + internalInstanceHandle +) { { - if ( - injectedHook && - typeof injectedHook.onScheduleFiberRoot === "function" - ) { - try { - injectedHook.onScheduleFiberRoot(rendererID, root, children); - } catch (err) { - if (!hasLoggedError) { - hasLoggedError = true; - - error("React instrumentation encountered an error: %s", err); - } - } + if (!hostContext.isInAParentText) { + error("Text strings must be rendered within a component."); } } -} -function onCommitRoot(root, eventPriority) { - if (injectedHook && typeof injectedHook.onCommitFiberRoot === "function") { - try { - var didError = (root.current.flags & DidCapture) === DidCapture; - - if (enableProfilerTimer) { - var schedulerPriority; - switch (eventPriority) { - case DiscreteEventPriority: - schedulerPriority = ImmediatePriority; - break; + var tag = nextReactTag; + nextReactTag += 2; + var node = createNode( + tag, // reactTag + "RCTRawText", // viewName + rootContainerInstance, // rootTag + { + text: text + }, // props + internalInstanceHandle // instance handle + ); + return { + node: node + }; +} +function getRootHostContext(rootContainerInstance) { + return { + isInAParentText: false + }; +} +function getChildHostContext(parentHostContext, type) { + var prevIsInAParentText = parentHostContext.isInAParentText; + var isInAParentText = + type === "AndroidTextInput" || // Android + type === "RCTMultilineTextInputView" || // iOS + type === "RCTSinglelineTextInputView" || // iOS + type === "RCTText" || + type === "RCTVirtualText"; // TODO: If this is an offscreen host container, we should reuse the + // parent context. - case ContinuousEventPriority: - schedulerPriority = UserBlockingPriority; - break; + if (prevIsInAParentText !== isInAParentText) { + return { + isInAParentText: isInAParentText + }; + } else { + return parentHostContext; + } +} +function getPublicInstance(instance) { + if (instance.canonical != null && instance.canonical.publicInstance != null) { + return instance.canonical.publicInstance; + } // For compatibility with the legacy renderer, in case it's used with Fabric + // in the same app. + // $FlowExpectedError[prop-missing] - case DefaultEventPriority: - schedulerPriority = NormalPriority; - break; + if (instance._nativeTag != null) { + // $FlowExpectedError[incompatible-return] + return instance; + } - case IdleEventPriority: - schedulerPriority = IdlePriority; - break; + return null; +} +function getPublicInstanceFromInternalInstanceHandle(internalInstanceHandle) { + var instance = internalInstanceHandle.stateNode; + return getPublicInstance(instance); +} +function prepareUpdate(instance, type, oldProps, newProps, hostContext) { + var viewConfig = instance.canonical.viewConfig; + var updatePayload = diff(oldProps, newProps, viewConfig.validAttributes); // TODO: If the event handlers have changed, we need to update the current props + // in the commit phase but there is no host config hook to do it yet. + // So instead we hack it by updating it in the render phase. - default: - schedulerPriority = NormalPriority; - break; - } + instance.canonical.currentProps = newProps; + return updatePayload; +} +function shouldSetTextContent(type, props) { + // TODO (bvaughn) Revisit this decision. + // Always returning false simplifies the createInstance() implementation, + // But creates an additional child Fiber for raw text children. + // No additional native views are created though. + // It's not clear to me which is better so I'm deferring for now. + // More context @ github.com/facebook/react/pull/8560#discussion_r92111303 + return false; +} +function getCurrentEventPriority() { + var currentEventPriority = fabricGetCurrentEventPriority + ? fabricGetCurrentEventPriority() + : null; - injectedHook.onCommitFiberRoot( - rendererID, - root, - schedulerPriority, - didError - ); - } - } catch (err) { - { - if (!hasLoggedError) { - hasLoggedError = true; + if (currentEventPriority != null) { + switch (currentEventPriority) { + case FabricDiscretePriority: + return DiscreteEventPriority; - error("React instrumentation encountered an error: %s", err); - } - } + case FabricDefaultPriority: + default: + return DefaultEventPriority; } } -} -function onPostCommitRoot(root) { - if ( - injectedHook && - typeof injectedHook.onPostCommitFiberRoot === "function" - ) { - try { - injectedHook.onPostCommitFiberRoot(rendererID, root); - } catch (err) { - { - if (!hasLoggedError) { - hasLoggedError = true; - error("React instrumentation encountered an error: %s", err); - } - } - } - } -} -function onCommitUnmount(fiber) { - if (injectedHook && typeof injectedHook.onCommitFiberUnmount === "function") { - try { - injectedHook.onCommitFiberUnmount(rendererID, fiber); - } catch (err) { - { - if (!hasLoggedError) { - hasLoggedError = true; + return DefaultEventPriority; +} // The Fabric renderer is secondary to the existing React Native renderer. - error("React instrumentation encountered an error: %s", err); - } - } +var warnsIfNotActing = false; +var scheduleTimeout = setTimeout; +var cancelTimeout = clearTimeout; +var noTimeout = -1; // ------------------- +function cloneInstance( + instance, + updatePayload, + type, + oldProps, + newProps, + internalInstanceHandle, + keepChildren, + recyclableInstance +) { + var node = instance.node; + var clone; + + if (keepChildren) { + if (updatePayload !== null) { + clone = cloneNodeWithNewProps(node, updatePayload); + } else { + clone = cloneNode(node); } - } -} -function setIsStrictModeForDevtools(newIsStrictMode) { - { - if (newIsStrictMode) { - disableLogs(); + } else { + if (updatePayload !== null) { + clone = cloneNodeWithNewChildrenAndProps(node, updatePayload); } else { - reenableLogs(); + clone = cloneNodeWithNewChildren(node); } } -} // Profiler API hooks -function injectProfilingHooks(profilingHooks) { - injectedProfilingHooks = profilingHooks; + return { + node: clone, + canonical: instance.canonical + }; +} +function cloneHiddenInstance(instance, type, props, internalInstanceHandle) { + var viewConfig = instance.canonical.viewConfig; + var node = instance.node; + var updatePayload = create( + { + style: { + display: "none" + } + }, + viewConfig.validAttributes + ); + return { + node: cloneNodeWithNewProps(node, updatePayload), + canonical: instance.canonical + }; +} +function cloneHiddenTextInstance(instance, text, internalInstanceHandle) { + throw new Error("Not yet implemented."); +} +function createContainerChildSet(container) { + return createChildNodeSet(container); +} +function appendChildToContainerChildSet(childSet, child) { + appendChildNodeToSet(childSet, child.node); +} +function finalizeContainerChildren(container, newChildren) { + completeRoot(container, newChildren); +} +function replaceContainerChildren(container, newChildren) {} +function preloadInstance(type, props) { + return true; +} +function waitForCommitToBeReady() { + return null; } -function getLaneLabelMap() { - { - var map = new Map(); - var lane = 1; +// This is ok in DOM because they types are interchangeable, but in React Native +// they aren't. - for (var index = 0; index < TotalLanes; index++) { - var label = getLabelForLane(lane); - map.set(lane, label); - lane *= 2; - } +function getInstanceFromNode(node) { + var instance = node; // In React Native, node is never a text instance - return map; - } + if ( + instance.canonical != null && + instance.canonical.internalInstanceHandle != null + ) { + return instance.canonical.internalInstanceHandle; + } // $FlowFixMe[incompatible-return] DevTools incorrectly passes a fiber in React Native. + + return node; } -function markCommitStarted(lanes) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markCommitStarted === "function" - ) { - injectedProfilingHooks.markCommitStarted(lanes); - } +function getNodeFromInstance(fiber) { + var publicInstance = getPublicInstance(fiber.stateNode); + + if (publicInstance == null) { + throw new Error("Could not find host instance from fiber"); } + + return publicInstance; } -function markCommitStopped() { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markCommitStopped === "function" - ) { - injectedProfilingHooks.markCommitStopped(); - } - } + +function getFiberCurrentPropsFromNode(instance) { + return instance.canonical.currentProps; } -function markComponentRenderStarted(fiber) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentRenderStarted === "function" - ) { - injectedProfilingHooks.markComponentRenderStarted(fiber); + +var ReactFabricGlobalResponderHandler = { + onChange: function (from, to, blockNativeResponder) { + if (from && from.stateNode) { + // equivalent to clearJSResponder + nativeFabricUIManager.setIsJSResponder( + from.stateNode.node, + false, + blockNativeResponder || false + ); } - } -} -function markComponentRenderStopped() { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentRenderStopped === "function" - ) { - injectedProfilingHooks.markComponentRenderStopped(); + + if (to && to.stateNode) { + // equivalent to setJSResponder + nativeFabricUIManager.setIsJSResponder( + to.stateNode.node, + true, + blockNativeResponder || false + ); } } +}; + +setComponentTree( + getFiberCurrentPropsFromNode, + getInstanceFromNode, + getNodeFromInstance +); +ResponderEventPlugin.injection.injectGlobalResponderHandler( + ReactFabricGlobalResponderHandler +); + +/** + * `ReactInstanceMap` maintains a mapping from a public facing stateful + * instance (key) and the internal representation (value). This allows public + * methods to accept the user facing instance as an argument and map them back + * to internal methods. + * + * Note that this module is currently shared and assumed to be stateless. + * If this becomes an actual Map, that will break. + */ +function get(key) { + return key._reactInternals; } -function markComponentPassiveEffectMountStarted(fiber) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentPassiveEffectMountStarted === - "function" - ) { - injectedProfilingHooks.markComponentPassiveEffectMountStarted(fiber); - } - } +function set(key, value) { + key._reactInternals = value; } -function markComponentPassiveEffectMountStopped() { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentPassiveEffectMountStopped === - "function" - ) { - injectedProfilingHooks.markComponentPassiveEffectMountStopped(); - } + +// ATTENTION +// When adding new symbols to this file, +// Please consider also adding to 'react-devtools-shared/src/backend/ReactSymbols' +// The Symbol used to tag the ReactElement-like types. +var REACT_ELEMENT_TYPE = Symbol.for("react.element"); +var REACT_PORTAL_TYPE = Symbol.for("react.portal"); +var REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"); +var REACT_STRICT_MODE_TYPE = Symbol.for("react.strict_mode"); +var REACT_PROFILER_TYPE = Symbol.for("react.profiler"); +var REACT_PROVIDER_TYPE = Symbol.for("react.provider"); +var REACT_CONTEXT_TYPE = Symbol.for("react.context"); +var REACT_SERVER_CONTEXT_TYPE = Symbol.for("react.server_context"); +var REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"); +var REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"); +var REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"); +var REACT_MEMO_TYPE = Symbol.for("react.memo"); +var REACT_LAZY_TYPE = Symbol.for("react.lazy"); +var REACT_SCOPE_TYPE = Symbol.for("react.scope"); +var REACT_DEBUG_TRACING_MODE_TYPE = Symbol.for("react.debug_trace_mode"); +var REACT_OFFSCREEN_TYPE = Symbol.for("react.offscreen"); +var REACT_LEGACY_HIDDEN_TYPE = Symbol.for("react.legacy_hidden"); +var REACT_CACHE_TYPE = Symbol.for("react.cache"); +var REACT_TRACING_MARKER_TYPE = Symbol.for("react.tracing_marker"); +var REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED = Symbol.for( + "react.default_value" +); +var REACT_MEMO_CACHE_SENTINEL = Symbol.for("react.memo_cache_sentinel"); +var MAYBE_ITERATOR_SYMBOL = Symbol.iterator; +var FAUX_ITERATOR_SYMBOL = "@@iterator"; +function getIteratorFn(maybeIterable) { + if (maybeIterable === null || typeof maybeIterable !== "object") { + return null; } -} -function markComponentPassiveEffectUnmountStarted(fiber) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentPassiveEffectUnmountStarted === - "function" - ) { - injectedProfilingHooks.markComponentPassiveEffectUnmountStarted(fiber); - } + + var maybeIterator = + (MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL]) || + maybeIterable[FAUX_ITERATOR_SYMBOL]; + + if (typeof maybeIterator === "function") { + return maybeIterator; } + + return null; } -function markComponentPassiveEffectUnmountStopped() { + +function getWrappedName$1(outerType, innerType, wrapperName) { + var displayName = outerType.displayName; + + if (displayName) { + return displayName; + } + + var functionName = innerType.displayName || innerType.name || ""; + return functionName !== "" + ? wrapperName + "(" + functionName + ")" + : wrapperName; +} // Keep in sync with react-reconciler/getComponentNameFromFiber + +function getContextName$1(type) { + return type.displayName || "Context"; +} // Note that the reconciler package should generally prefer to use getComponentNameFromFiber() instead. + +function getComponentNameFromType(type) { + if (type == null) { + // Host root, text node or just invalid type. + return null; + } + { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentPassiveEffectUnmountStopped === - "function" - ) { - injectedProfilingHooks.markComponentPassiveEffectUnmountStopped(); + if (typeof type.tag === "number") { + error( + "Received an unexpected object in getComponentNameFromType(). " + + "This is likely a bug in React. Please file an issue." + ); } } -} -function markComponentLayoutEffectMountStarted(fiber) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentLayoutEffectMountStarted === - "function" - ) { - injectedProfilingHooks.markComponentLayoutEffectMountStarted(fiber); - } - } -} -function markComponentLayoutEffectMountStopped() { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentLayoutEffectMountStopped === - "function" - ) { - injectedProfilingHooks.markComponentLayoutEffectMountStopped(); - } - } -} -function markComponentLayoutEffectUnmountStarted(fiber) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentLayoutEffectUnmountStarted === - "function" - ) { - injectedProfilingHooks.markComponentLayoutEffectUnmountStarted(fiber); - } - } -} -function markComponentLayoutEffectUnmountStopped() { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentLayoutEffectUnmountStopped === - "function" - ) { - injectedProfilingHooks.markComponentLayoutEffectUnmountStopped(); - } - } -} -function markComponentErrored(fiber, thrownValue, lanes) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentErrored === "function" - ) { - injectedProfilingHooks.markComponentErrored(fiber, thrownValue, lanes); - } - } -} -function markComponentSuspended(fiber, wakeable, lanes) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentSuspended === "function" - ) { - injectedProfilingHooks.markComponentSuspended(fiber, wakeable, lanes); - } - } -} -function markLayoutEffectsStarted(lanes) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markLayoutEffectsStarted === "function" - ) { - injectedProfilingHooks.markLayoutEffectsStarted(lanes); - } - } -} -function markLayoutEffectsStopped() { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markLayoutEffectsStopped === "function" - ) { - injectedProfilingHooks.markLayoutEffectsStopped(); - } - } -} -function markPassiveEffectsStarted(lanes) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markPassiveEffectsStarted === "function" - ) { - injectedProfilingHooks.markPassiveEffectsStarted(lanes); - } - } -} -function markPassiveEffectsStopped() { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markPassiveEffectsStopped === "function" - ) { - injectedProfilingHooks.markPassiveEffectsStopped(); - } - } -} -function markRenderStarted(lanes) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markRenderStarted === "function" - ) { - injectedProfilingHooks.markRenderStarted(lanes); - } - } -} -function markRenderYielded() { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markRenderYielded === "function" - ) { - injectedProfilingHooks.markRenderYielded(); - } - } -} -function markRenderStopped() { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markRenderStopped === "function" - ) { - injectedProfilingHooks.markRenderStopped(); - } + + if (typeof type === "function") { + return type.displayName || type.name || null; } -} -function markRenderScheduled(lane) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markRenderScheduled === "function" - ) { - injectedProfilingHooks.markRenderScheduled(lane); - } + + if (typeof type === "string") { + return type; } -} -function markForceUpdateScheduled(fiber, lane) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markForceUpdateScheduled === "function" - ) { - injectedProfilingHooks.markForceUpdateScheduled(fiber, lane); - } + + switch (type) { + case REACT_FRAGMENT_TYPE: + return "Fragment"; + + case REACT_PORTAL_TYPE: + return "Portal"; + + case REACT_PROFILER_TYPE: + return "Profiler"; + + case REACT_STRICT_MODE_TYPE: + return "StrictMode"; + + case REACT_SUSPENSE_TYPE: + return "Suspense"; + + case REACT_SUSPENSE_LIST_TYPE: + return "SuspenseList"; } -} -function markStateUpdateScheduled(fiber, lane) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markStateUpdateScheduled === "function" - ) { - injectedProfilingHooks.markStateUpdateScheduled(fiber, lane); + + if (typeof type === "object") { + switch (type.$$typeof) { + case REACT_CONTEXT_TYPE: + var context = type; + return getContextName$1(context) + ".Consumer"; + + case REACT_PROVIDER_TYPE: + var provider = type; + return getContextName$1(provider._context) + ".Provider"; + + case REACT_FORWARD_REF_TYPE: + return getWrappedName$1(type, type.render, "ForwardRef"); + + case REACT_MEMO_TYPE: + var outerName = type.displayName || null; + + if (outerName !== null) { + return outerName; + } + + return getComponentNameFromType(type.type) || "Memo"; + + case REACT_LAZY_TYPE: { + var lazyComponent = type; + var payload = lazyComponent._payload; + var init = lazyComponent._init; + + try { + return getComponentNameFromType(init(payload)); + } catch (x) { + return null; + } + } + + case REACT_SERVER_CONTEXT_TYPE: { + var context2 = type; + return (context2.displayName || context2._globalName) + ".Provider"; + } + + // eslint-disable-next-line no-fallthrough } } + + return null; } -/** - * inlined Object.is polyfill to avoid requiring consumers ship their own - * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is - */ -function is(x, y) { +function getWrappedName(outerType, innerType, wrapperName) { + var functionName = innerType.displayName || innerType.name || ""; return ( - (x === y && (x !== 0 || 1 / x === 1 / y)) || (x !== x && y !== y) // eslint-disable-line no-self-compare + outerType.displayName || + (functionName !== "" ? wrapperName + "(" + functionName + ")" : wrapperName) ); +} // Keep in sync with shared/getComponentNameFromType + +function getContextName(type) { + return type.displayName || "Context"; } -var objectIs = typeof Object.is === "function" ? Object.is : is; // $FlowFixMe[method-unbinding] +function getComponentNameFromFiber(fiber) { + var tag = fiber.tag, + type = fiber.type; -var syncQueue = null; -var includesLegacySyncCallbacks = false; -var isFlushingSyncQueue = false; -function scheduleSyncCallback(callback) { - // Push this callback into an internal queue. We'll flush these either in - // the next tick, or earlier if something calls `flushSyncCallbackQueue`. - if (syncQueue === null) { - syncQueue = [callback]; - } else { - // Push onto existing queue. Don't need to schedule a callback because - // we already scheduled one when we created the queue. - syncQueue.push(callback); - } -} -function scheduleLegacySyncCallback(callback) { - includesLegacySyncCallbacks = true; - scheduleSyncCallback(callback); -} -function flushSyncCallbacksOnlyInLegacyMode() { - // Only flushes the queue if there's a legacy sync callback scheduled. - // TODO: There's only a single type of callback: performSyncOnWorkOnRoot. So - // it might make more sense for the queue to be a list of roots instead of a - // list of generic callbacks. Then we can have two: one for legacy roots, one - // for concurrent roots. And this method would only flush the legacy ones. - if (includesLegacySyncCallbacks) { - flushSyncCallbacks(); - } -} -function flushSyncCallbacks() { - if (!isFlushingSyncQueue && syncQueue !== null) { - // Prevent re-entrance. - isFlushingSyncQueue = true; // Set the event priority to discrete - // TODO: Is this necessary anymore? The only user code that runs in this - // queue is in the render or commit phases, which already set the - // event priority. Should be able to remove. + switch (tag) { + case CacheComponent: + return "Cache"; - var previousUpdatePriority = getCurrentUpdatePriority(); - setCurrentUpdatePriority(DiscreteEventPriority); - var errors = null; - var queue = syncQueue; // $FlowFixMe[incompatible-use] found when upgrading Flow + case ContextConsumer: + var context = type; + return getContextName(context) + ".Consumer"; - for (var i = 0; i < queue.length; i++) { - // $FlowFixMe[incompatible-use] found when upgrading Flow - var callback = queue[i]; + case ContextProvider: + var provider = type; + return getContextName(provider._context) + ".Provider"; - try { - do { - var isSync = true; // $FlowFixMe[incompatible-type] we bail out when we get a null + case DehydratedFragment: + return "DehydratedFragment"; - callback = callback(isSync); - } while (callback !== null); - } catch (error) { - // Collect errors so we can rethrow them at the end - if (errors === null) { - errors = [error]; - } else { - errors.push(error); - } + case ForwardRef: + return getWrappedName(type, type.render, "ForwardRef"); + + case Fragment: + return "Fragment"; + + case HostHoistable: + case HostSingleton: + case HostComponent: + // Host component type is the display name (e.g. "div", "View") + return type; + + case HostPortal: + return "Portal"; + + case HostRoot: + return "Root"; + + case HostText: + return "Text"; + + case LazyComponent: + // Name comes from the type in this case; we don't have a tag. + return getComponentNameFromType(type); + + case Mode: + if (type === REACT_STRICT_MODE_TYPE) { + // Don't be less specific than shared/getComponentNameFromType + return "StrictMode"; } - } - syncQueue = null; - includesLegacySyncCallbacks = false; - setCurrentUpdatePriority(previousUpdatePriority); - isFlushingSyncQueue = false; + return "Mode"; - if (errors !== null) { - if (errors.length > 1) { - if (typeof AggregateError === "function") { - // eslint-disable-next-line no-undef - throw new AggregateError(errors); - } else { - for (var _i = 1; _i < errors.length; _i++) { - scheduleCallback$1( - ImmediatePriority, - throwError.bind(null, errors[_i]) - ); - } + case OffscreenComponent: + return "Offscreen"; - var firstError = errors[0]; - throw firstError; - } - } else { - var error = errors[0]; - throw error; + case Profiler: + return "Profiler"; + + case ScopeComponent: + return "Scope"; + + case SuspenseComponent: + return "Suspense"; + + case SuspenseListComponent: + return "SuspenseList"; + + case TracingMarkerComponent: + return "TracingMarker"; + // The display name for this tags come from the user-provided type: + + case ClassComponent: + case FunctionComponent: + case IncompleteClassComponent: + case IndeterminateComponent: + case MemoComponent: + case SimpleMemoComponent: + if (typeof type === "function") { + return type.displayName || type.name || null; + } + + if (typeof type === "string") { + return type; } + + break; + + case LegacyHiddenComponent: { + return "LegacyHidden"; } } return null; } -function throwError(error) { - throw error; -} +var ReactCurrentOwner$3 = ReactSharedInternals.ReactCurrentOwner; +function getNearestMountedFiber(fiber) { + var node = fiber; + var nearestMounted = fiber; -// This is imported by the event replaying implementation in React DOM. It's -// in a separate file to break a circular dependency between the renderer and -// the reconciler. -function isRootDehydrated(root) { - var currentState = root.current.memoizedState; - return currentState.isDehydrated; -} + if (!fiber.alternate) { + // If there is no alternate, this might be a new tree that isn't inserted + // yet. If it is, then it will have a pending insertion effect on it. + var nextNode = node; -var contextStackCursor = createCursor(null); -var contextFiberStackCursor = createCursor(null); -var rootInstanceStackCursor = createCursor(null); + do { + node = nextNode; -function requiredContext(c) { - { - if (c === null) { - error( - "Expected host context to exist. This error is likely caused by a bug " + - "in React. Please file an issue." - ); + if ((node.flags & (Placement | Hydrating)) !== NoFlags$1) { + // This is an insertion or in-progress hydration. The nearest possible + // mounted fiber is the parent but we need to continue to figure out + // if that one is still mounted. + nearestMounted = node.return; + } // $FlowFixMe[incompatible-type] we bail out when we get a null + + nextNode = node.return; + } while (nextNode); + } else { + while (node.return) { + node = node.return; } } - return c; -} + if (node.tag === HostRoot) { + // TODO: Check if this was a nested HostRoot when used with + // renderContainerIntoSubtree. + return nearestMounted; + } // If we didn't hit the root, that means that we're in an disconnected tree + // that has been unmounted. -function getRootHostContainer() { - var rootInstance = requiredContext(rootInstanceStackCursor.current); - return rootInstance; + return null; +} +function isFiberMounted(fiber) { + return getNearestMountedFiber(fiber) === fiber; } +function isMounted(component) { + { + var owner = ReactCurrentOwner$3.current; -function pushHostContainer(fiber, nextRootInstance) { - // Push current root instance onto the stack; - // This allows us to reset root when portals are popped. - push(rootInstanceStackCursor, nextRootInstance, fiber); // Track the context and the Fiber that provided it. - // This enables us to pop only Fibers that provide unique contexts. + if (owner !== null && owner.tag === ClassComponent) { + var ownerFiber = owner; + var instance = ownerFiber.stateNode; - push(contextFiberStackCursor, fiber, fiber); // Finally, we need to push the host context to the stack. - // However, we can't just call getRootHostContext() and push it because - // we'd have a different number of entries on the stack depending on - // whether getRootHostContext() throws somewhere in renderer code or not. - // So we push an empty value first. This lets us safely unwind on errors. + if (!instance._warnedAboutRefsInRender) { + error( + "%s is accessing isMounted inside its render() function. " + + "render() should be a pure function of props and state. It should " + + "never access something that requires stale data from the previous " + + "render, such as refs. Move this logic to componentDidMount and " + + "componentDidUpdate instead.", + getComponentNameFromFiber(ownerFiber) || "A component" + ); + } - push(contextStackCursor, null, fiber); - var nextRootContext = getRootHostContext(); // Now that we know this function doesn't throw, replace it. + instance._warnedAboutRefsInRender = true; + } + } - pop(contextStackCursor, fiber); - push(contextStackCursor, nextRootContext, fiber); -} + var fiber = get(component); -function popHostContainer(fiber) { - pop(contextStackCursor, fiber); - pop(contextFiberStackCursor, fiber); - pop(rootInstanceStackCursor, fiber); + if (!fiber) { + return false; + } + + return getNearestMountedFiber(fiber) === fiber; } -function getHostContext() { - var context = requiredContext(contextStackCursor.current); - return context; +function assertIsMounted(fiber) { + if (getNearestMountedFiber(fiber) !== fiber) { + throw new Error("Unable to find node on an unmounted component."); + } } -function pushHostContext(fiber) { - var context = requiredContext(contextStackCursor.current); - var nextContext = getChildHostContext(context, fiber.type); // Don't push this Fiber's context unless it's unique. +function findCurrentFiberUsingSlowPath(fiber) { + var alternate = fiber.alternate; - if (context === nextContext) { - return; - } // Track the context and the Fiber that provided it. - // This enables us to pop only Fibers that provide unique contexts. + if (!alternate) { + // If there is no alternate, then we only need to check if it is mounted. + var nearestMounted = getNearestMountedFiber(fiber); - push(contextFiberStackCursor, fiber, fiber); - push(contextStackCursor, nextContext, fiber); -} + if (nearestMounted === null) { + throw new Error("Unable to find node on an unmounted component."); + } -function popHostContext(fiber) { - // Do not pop unless this Fiber provided the current context. - // pushHostContext() only pushes Fibers that provide unique contexts. - if (contextFiberStackCursor.current !== fiber) { - return; - } + if (nearestMounted !== fiber) { + return null; + } - pop(contextStackCursor, fiber); - pop(contextFiberStackCursor, fiber); -} + return fiber; + } // If we have two possible branches, we'll walk backwards up to the root + // to see what path the root points to. On the way we may hit one of the + // special cases and we'll deal with them. -var isHydrating = false; // This flag allows for warning supression when we expect there to be mismatches -// due to earlier mismatches or a suspended fiber. + var a = fiber; + var b = alternate; -var didSuspendOrErrorDEV = false; // Hydration errors that were thrown inside this boundary + while (true) { + var parentA = a.return; -var hydrationErrors = null; -function didSuspendOrErrorWhileHydratingDEV() { - { - return didSuspendOrErrorDEV; - } -} + if (parentA === null) { + // We're at the root. + break; + } -function prepareToHydrateHostInstance(fiber, hostContext) { - { - throw new Error( - "Expected prepareToHydrateHostInstance() to never be called. " + - "This error is likely caused by a bug in React. Please file an issue." - ); - } -} + var parentB = parentA.alternate; -function prepareToHydrateHostTextInstance(fiber) { - { - throw new Error( - "Expected prepareToHydrateHostTextInstance() to never be called. " + - "This error is likely caused by a bug in React. Please file an issue." - ); - } -} + if (parentB === null) { + // There is no alternate. This is an unusual case. Currently, it only + // happens when a Suspense component is hidden. An extra fragment fiber + // is inserted in between the Suspense fiber and its children. Skip + // over this extra fragment fiber and proceed to the next parent. + var nextParent = parentA.return; -function prepareToHydrateHostSuspenseInstance(fiber) { - { - throw new Error( - "Expected prepareToHydrateHostSuspenseInstance() to never be called. " + - "This error is likely caused by a bug in React. Please file an issue." - ); - } -} + if (nextParent !== null) { + a = b = nextParent; + continue; + } // If there's no parent, we're at the root. -function popHydrationState(fiber) { - { - return false; - } -} + break; + } // If both copies of the parent fiber point to the same child, we can + // assume that the child is current. This happens when we bailout on low + // priority: the bailed out fiber's child reuses the current child. -function upgradeHydrationErrorsToRecoverable() { - if (hydrationErrors !== null) { - // Successfully completed a forced client render. The errors that occurred - // during the hydration attempt are now recovered. We will log them in - // commit phase, once the entire tree has finished. - queueRecoverableErrors(hydrationErrors); - hydrationErrors = null; - } -} + if (parentA.child === parentB.child) { + var child = parentA.child; -function getIsHydrating() { - return isHydrating; -} + while (child) { + if (child === a) { + // We've determined that A is the current branch. + assertIsMounted(parentA); + return fiber; + } -function queueHydrationError(error) { - if (hydrationErrors === null) { - hydrationErrors = [error]; - } else { - hydrationErrors.push(error); - } -} + if (child === b) { + // We've determined that B is the current branch. + assertIsMounted(parentA); + return alternate; + } -// we wait until the current render is over (either finished or interrupted) -// before adding it to the fiber/hook queue. Push to this array so we can -// access the queue, fiber, update, et al later. + child = child.sibling; + } // We should never have an alternate for any mounting node. So the only + // way this could possibly happen is if this was unmounted, if at all. -var concurrentQueues = []; -var concurrentQueuesIndex = 0; -var concurrentlyUpdatedLanes = NoLanes; -function finishQueueingConcurrentUpdates() { - var endIndex = concurrentQueuesIndex; - concurrentQueuesIndex = 0; - concurrentlyUpdatedLanes = NoLanes; - var i = 0; + throw new Error("Unable to find node on an unmounted component."); + } - while (i < endIndex) { - var fiber = concurrentQueues[i]; - concurrentQueues[i++] = null; - var queue = concurrentQueues[i]; - concurrentQueues[i++] = null; - var update = concurrentQueues[i]; - concurrentQueues[i++] = null; - var lane = concurrentQueues[i]; - concurrentQueues[i++] = null; + if (a.return !== b.return) { + // The return pointer of A and the return pointer of B point to different + // fibers. We assume that return pointers never criss-cross, so A must + // belong to the child set of A.return, and B must belong to the child + // set of B.return. + a = parentA; + b = parentB; + } else { + // The return pointers point to the same fiber. We'll have to use the + // default, slow path: scan the child sets of each parent alternate to see + // which child belongs to which set. + // + // Search parent A's child set + var didFindChild = false; + var _child = parentA.child; - if (queue !== null && update !== null) { - var pending = queue.pending; + while (_child) { + if (_child === a) { + didFindChild = true; + a = parentA; + b = parentB; + break; + } - if (pending === null) { - // This is the first update. Create a circular list. - update.next = update; - } else { - update.next = pending.next; - pending.next = update; + if (_child === b) { + didFindChild = true; + b = parentA; + a = parentB; + break; + } + + _child = _child.sibling; } - queue.pending = update; + if (!didFindChild) { + // Search parent B's child set + _child = parentB.child; + + while (_child) { + if (_child === a) { + didFindChild = true; + a = parentB; + b = parentA; + break; + } + + if (_child === b) { + didFindChild = true; + b = parentB; + a = parentA; + break; + } + + _child = _child.sibling; + } + + if (!didFindChild) { + throw new Error( + "Child was not found in either parent set. This indicates a bug " + + "in React related to the return pointer. Please file an issue." + ); + } + } } - if (lane !== NoLane) { - markUpdateLaneFromFiberToRoot(fiber, update, lane); + if (a.alternate !== b) { + throw new Error( + "Return fibers should always be each others' alternates. " + + "This error is likely caused by a bug in React. Please file an issue." + ); } - } -} -function getConcurrentlyUpdatedLanes() { - return concurrentlyUpdatedLanes; -} + } // If the root is not a host container, we're in a disconnected tree. I.e. + // unmounted. -function enqueueUpdate$1(fiber, queue, update, lane) { - // Don't update the `childLanes` on the return path yet. If we already in - // the middle of rendering, wait until after it has completed. - concurrentQueues[concurrentQueuesIndex++] = fiber; - concurrentQueues[concurrentQueuesIndex++] = queue; - concurrentQueues[concurrentQueuesIndex++] = update; - concurrentQueues[concurrentQueuesIndex++] = lane; - concurrentlyUpdatedLanes = mergeLanes(concurrentlyUpdatedLanes, lane); // The fiber's `lane` field is used in some places to check if any work is - // scheduled, to perform an eager bailout, so we need to update it immediately. - // TODO: We should probably move this to the "shared" queue instead. + if (a.tag !== HostRoot) { + throw new Error("Unable to find node on an unmounted component."); + } - fiber.lanes = mergeLanes(fiber.lanes, lane); - var alternate = fiber.alternate; + if (a.stateNode.current === a) { + // We've determined that A is the current branch. + return fiber; + } // Otherwise B has to be current branch. - if (alternate !== null) { - alternate.lanes = mergeLanes(alternate.lanes, lane); - } + return alternate; +} +function findCurrentHostFiber(parent) { + var currentParent = findCurrentFiberUsingSlowPath(parent); + return currentParent !== null + ? findCurrentHostFiberImpl(currentParent) + : null; } -function enqueueConcurrentHookUpdate(fiber, queue, update, lane) { - var concurrentQueue = queue; - var concurrentUpdate = update; - enqueueUpdate$1(fiber, concurrentQueue, concurrentUpdate, lane); - return getRootForUpdatedFiber(fiber); -} -function enqueueConcurrentHookUpdateAndEagerlyBailout(fiber, queue, update) { - // This function is used to queue an update that doesn't need a rerender. The - // only reason we queue it is in case there's a subsequent higher priority - // update that causes it to be rebased. - var lane = NoLane; - var concurrentQueue = queue; - var concurrentUpdate = update; - enqueueUpdate$1(fiber, concurrentQueue, concurrentUpdate, lane); // Usually we can rely on the upcoming render phase to process the concurrent - // queue. However, since this is a bail out, we're not scheduling any work - // here. So the update we just queued will leak until something else happens - // to schedule work (if ever). - // - // Check if we're currently in the middle of rendering a tree, and if not, - // process the queue immediately to prevent a leak. - - var isConcurrentlyRendering = getWorkInProgressRoot() !== null; +function findCurrentHostFiberImpl(node) { + // Next we'll drill down this component to find the first HostComponent/Text. + var tag = node.tag; - if (!isConcurrentlyRendering) { - finishQueueingConcurrentUpdates(); + if ( + tag === HostComponent || + tag === HostHoistable || + tag === HostSingleton || + tag === HostText + ) { + return node; } -} -function enqueueConcurrentClassUpdate(fiber, queue, update, lane) { - var concurrentQueue = queue; - var concurrentUpdate = update; - enqueueUpdate$1(fiber, concurrentQueue, concurrentUpdate, lane); - return getRootForUpdatedFiber(fiber); -} -function enqueueConcurrentRenderForLane(fiber, lane) { - enqueueUpdate$1(fiber, null, null, lane); - return getRootForUpdatedFiber(fiber); -} // Calling this function outside this module should only be done for backwards -// compatibility and should always be accompanied by a warning. - -function unsafe_markUpdateLaneFromFiberToRoot(sourceFiber, lane) { - // NOTE: For Hyrum's Law reasons, if an infinite update loop is detected, it - // should throw before `markUpdateLaneFromFiberToRoot` is called. But this is - // undefined behavior and we can change it if we need to; it just so happens - // that, at the time of this writing, there's an internal product test that - // happens to rely on this. - var root = getRootForUpdatedFiber(sourceFiber); - markUpdateLaneFromFiberToRoot(sourceFiber, null, lane); - return root; -} -function markUpdateLaneFromFiberToRoot(sourceFiber, update, lane) { - // Update the source fiber's lanes - sourceFiber.lanes = mergeLanes(sourceFiber.lanes, lane); - var alternate = sourceFiber.alternate; + var child = node.child; - if (alternate !== null) { - alternate.lanes = mergeLanes(alternate.lanes, lane); - } // Walk the parent path to the root and update the child lanes. + while (child !== null) { + var match = findCurrentHostFiberImpl(child); - var isHidden = false; - var parent = sourceFiber.return; - var node = sourceFiber; + if (match !== null) { + return match; + } - while (parent !== null) { - parent.childLanes = mergeLanes(parent.childLanes, lane); - alternate = parent.alternate; + child = child.sibling; + } - if (alternate !== null) { - alternate.childLanes = mergeLanes(alternate.childLanes, lane); - } + return null; +} - if (parent.tag === OffscreenComponent) { - // Check if this offscreen boundary is currently hidden. - // - // The instance may be null if the Offscreen parent was unmounted. Usually - // the parent wouldn't be reachable in that case because we disconnect - // fibers from the tree when they are deleted. However, there's a weird - // edge case where setState is called on a fiber that was interrupted - // before it ever mounted. Because it never mounts, it also never gets - // deleted. Because it never gets deleted, its return pointer never gets - // disconnected. Which means it may be attached to a deleted Offscreen - // parent node. (This discovery suggests it may be better for memory usage - // if we don't attach the `return` pointer until the commit phase, though - // in order to do that we'd need some other way to track the return - // pointer during the initial render, like on the stack.) - // - // This case is always accompanied by a warning, but we still need to - // account for it. (There may be other cases that we haven't discovered, - // too.) - var offscreenInstance = parent.stateNode; +function describeBuiltInComponentFrame(name, source, ownerFn) { + { + var ownerName = null; - if ( - offscreenInstance !== null && - !(offscreenInstance._visibility & OffscreenVisible) - ) { - isHidden = true; - } + if (ownerFn) { + ownerName = ownerFn.displayName || ownerFn.name || null; } - node = parent; - parent = parent.return; + return describeComponentFrame(name, source, ownerName); } +} - if (isHidden && update !== null && node.tag === HostRoot) { - var root = node.stateNode; - markHiddenUpdate(root, update, lane); - } +{ + var PossiblyWeakMap$1 = typeof WeakMap === "function" ? WeakMap : Map; + new PossiblyWeakMap$1(); } +var BEFORE_SLASH_RE = /^(.*)[\\\/]/; -function getRootForUpdatedFiber(sourceFiber) { - // TODO: We will detect and infinite update loop and throw even if this fiber - // has already unmounted. This isn't really necessary but it happens to be the - // current behavior we've used for several release cycles. Consider not - // performing this check if the updated fiber already unmounted, since it's - // not possible for that to cause an infinite update loop. - throwIfInfiniteUpdateLoopDetected(); // When a setState happens, we must ensure the root is scheduled. Because - // update queues do not have a backpointer to the root, the only way to do - // this currently is to walk up the return path. This used to not be a big - // deal because we would have to walk up the return path to set - // the `childLanes`, anyway, but now those two traversals happen at - // different times. - // TODO: Consider adding a `root` backpointer on the update queue. +function describeComponentFrame(name, source, ownerName) { + var sourceInfo = ""; - detectUpdateOnUnmountedFiber(sourceFiber, sourceFiber); - var node = sourceFiber; - var parent = node.return; + if (source) { + var path = source.fileName; + var fileName = path.replace(BEFORE_SLASH_RE, ""); // In DEV, include code for a common special case: + // prefer "folder/index.js" instead of just "index.js". - while (parent !== null) { - detectUpdateOnUnmountedFiber(sourceFiber, node); - node = parent; - parent = node.return; + if (/^index\./.test(fileName)) { + var match = path.match(BEFORE_SLASH_RE); + + if (match) { + var pathBeforeSlash = match[1]; + + if (pathBeforeSlash) { + var folderName = pathBeforeSlash.replace(BEFORE_SLASH_RE, ""); + fileName = folderName + "/" + fileName; + } + } + } + + sourceInfo = " (at " + fileName + ":" + source.lineNumber + ")"; + } else if (ownerName) { + sourceInfo = " (created by " + ownerName + ")"; } - return node.tag === HostRoot ? node.stateNode : null; + return "\n in " + (name || "Unknown") + sourceInfo; } -function detectUpdateOnUnmountedFiber(sourceFiber, parent) { +function describeClassComponentFrame(ctor, source, ownerFn) { { - var alternate = parent.alternate; - - if ( - alternate === null && - (parent.flags & (Placement | Hydrating)) !== NoFlags$1 - ) { - warnAboutUpdateOnNotYetMountedFiberInDEV(sourceFiber); - } + return describeFunctionComponentFrame(ctor, source, ownerFn); } } +function describeFunctionComponentFrame(fn, source, ownerFn) { + { + if (!fn) { + return ""; + } -var UpdateState = 0; -var ReplaceState = 1; -var ForceUpdate = 2; -var CaptureUpdate = 3; // Global state that is reset at the beginning of calling `processUpdateQueue`. -// It should only be read right after calling `processUpdateQueue`, via -// `checkHasForceUpdateAfterProcessing`. + var name = fn.displayName || fn.name || null; + var ownerName = null; -var hasForceUpdate = false; -var didWarnUpdateInsideUpdate; -var currentlyProcessingQueue; + if (ownerFn) { + ownerName = ownerFn.displayName || ownerFn.name || null; + } -{ - didWarnUpdateInsideUpdate = false; - currentlyProcessingQueue = null; + return describeComponentFrame(name, source, ownerName); + } } -function initializeUpdateQueue(fiber) { - var queue = { - baseState: fiber.memoizedState, - firstBaseUpdate: null, - lastBaseUpdate: null, - shared: { - pending: null, - lanes: NoLanes, - hiddenCallbacks: null - }, - callbacks: null - }; - fiber.updateQueue = queue; -} -function cloneUpdateQueue(current, workInProgress) { - // Clone the update queue from current. Unless it's already a clone. - var queue = workInProgress.updateQueue; - var currentQueue = current.updateQueue; +function describeUnknownElementTypeFrameInDEV(type, source, ownerFn) { + if (type == null) { + return ""; + } - if (queue === currentQueue) { - var clone = { - baseState: currentQueue.baseState, - firstBaseUpdate: currentQueue.firstBaseUpdate, - lastBaseUpdate: currentQueue.lastBaseUpdate, - shared: currentQueue.shared, - callbacks: null - }; - workInProgress.updateQueue = clone; + if (typeof type === "function") { + { + return describeFunctionComponentFrame(type, source, ownerFn); + } } -} -function createUpdate(lane) { - var update = { - lane: lane, - tag: UpdateState, - payload: null, - callback: null, - next: null - }; - return update; -} -function enqueueUpdate(fiber, update, lane) { - var updateQueue = fiber.updateQueue; - if (updateQueue === null) { - // Only occurs if the fiber has been unmounted. - return null; + if (typeof type === "string") { + return describeBuiltInComponentFrame(type, source, ownerFn); } - var sharedQueue = updateQueue.shared; + switch (type) { + case REACT_SUSPENSE_TYPE: + return describeBuiltInComponentFrame("Suspense", source, ownerFn); - { - if ( - currentlyProcessingQueue === sharedQueue && - !didWarnUpdateInsideUpdate - ) { - var componentName = getComponentNameFromFiber(fiber); + case REACT_SUSPENSE_LIST_TYPE: + return describeBuiltInComponentFrame("SuspenseList", source, ownerFn); + } - error( - "An update (setState, replaceState, or forceUpdate) was scheduled " + - "from inside an update function. Update functions should be pure, " + - "with zero side-effects. Consider using componentDidUpdate or a " + - "callback.\n\nPlease update the following component: %s", - componentName - ); + if (typeof type === "object") { + switch (type.$$typeof) { + case REACT_FORWARD_REF_TYPE: + return describeFunctionComponentFrame(type.render, source, ownerFn); - didWarnUpdateInsideUpdate = true; + case REACT_MEMO_TYPE: + // Memo may contain any component type so we recursively resolve it. + return describeUnknownElementTypeFrameInDEV(type.type, source, ownerFn); + + case REACT_LAZY_TYPE: { + var lazyComponent = type; + var payload = lazyComponent._payload; + var init = lazyComponent._init; + + try { + // Lazy may contain any component type so we recursively resolve it. + return describeUnknownElementTypeFrameInDEV( + init(payload), + source, + ownerFn + ); + } catch (x) {} + } } } - if (isUnsafeClassRenderPhaseUpdate()) { - // This is an unsafe render phase update. Add directly to the update - // queue so we can process it immediately during the current render. - var pending = sharedQueue.pending; + return ""; +} - if (pending === null) { - // This is the first update. Create a circular list. - update.next = update; - } else { - update.next = pending.next; - pending.next = update; - } +// $FlowFixMe[method-unbinding] +var hasOwnProperty = Object.prototype.hasOwnProperty; - sharedQueue.pending = update; // Update the childLanes even though we're most likely already rendering - // this fiber. This is for backwards compatibility in the case where you - // update a different component during render phase than the one that is - // currently renderings (a pattern that is accompanied by a warning). +var loggedTypeFailures = {}; +var ReactDebugCurrentFrame$1 = ReactSharedInternals.ReactDebugCurrentFrame; - return unsafe_markUpdateLaneFromFiberToRoot(fiber, lane); - } else { - return enqueueConcurrentClassUpdate(fiber, sharedQueue, update, lane); +function setCurrentlyValidatingElement(element) { + { + if (element) { + var owner = element._owner; + var stack = describeUnknownElementTypeFrameInDEV( + element.type, + element._source, + owner ? owner.type : null + ); + ReactDebugCurrentFrame$1.setExtraStackFrame(stack); + } else { + ReactDebugCurrentFrame$1.setExtraStackFrame(null); + } } } -function entangleTransitions(root, fiber, lane) { - var updateQueue = fiber.updateQueue; - if (updateQueue === null) { - // Only occurs if the fiber has been unmounted. - return; - } +function checkPropTypes(typeSpecs, values, location, componentName, element) { + { + // $FlowFixMe This is okay but Flow doesn't know it. + var has = Function.call.bind(hasOwnProperty); - var sharedQueue = updateQueue.shared; + for (var typeSpecName in typeSpecs) { + if (has(typeSpecs, typeSpecName)) { + var error$1 = void 0; // Prop type validation may throw. In case they do, we don't want to + // fail the render phase where it didn't fail before. So we log it. + // After these have been cleaned up, we'll let them throw. - if (isTransitionLane(lane)) { - var queueLanes = sharedQueue.lanes; // If any entangled lanes are no longer pending on the root, then they must - // have finished. We can remove them from the shared queue, which represents - // a superset of the actually pending lanes. In some cases we may entangle - // more than we need to, but that's OK. In fact it's worse if we *don't* - // entangle when we should. + try { + // This is intentionally an invariant that gets caught. It's the same + // behavior as without this statement except with a better message. + if (typeof typeSpecs[typeSpecName] !== "function") { + // eslint-disable-next-line react-internal/prod-error-codes + var err = Error( + (componentName || "React class") + + ": " + + location + + " type `" + + typeSpecName + + "` is invalid; " + + "it must be a function, usually from the `prop-types` package, but received `" + + typeof typeSpecs[typeSpecName] + + "`." + + "This often happens because of typos such as `PropTypes.function` instead of `PropTypes.func`." + ); + err.name = "Invariant Violation"; + throw err; + } - queueLanes = intersectLanes(queueLanes, root.pendingLanes); // Entangle the new transition lane with the other transition lanes. + error$1 = typeSpecs[typeSpecName]( + values, + typeSpecName, + componentName, + location, + null, + "SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED" + ); + } catch (ex) { + error$1 = ex; + } - var newQueueLanes = mergeLanes(queueLanes, lane); - sharedQueue.lanes = newQueueLanes; // Even if queue.lanes already include lane, we don't know for certain if - // the lane finished since the last time we entangled it. So we need to - // entangle it again, just to be sure. + if (error$1 && !(error$1 instanceof Error)) { + setCurrentlyValidatingElement(element); - markRootEntangled(root, newQueueLanes); - } -} -function enqueueCapturedUpdate(workInProgress, capturedUpdate) { - // Captured updates are updates that are thrown by a child during the render - // phase. They should be discarded if the render is aborted. Therefore, - // we should only put them on the work-in-progress queue, not the current one. - var queue = workInProgress.updateQueue; // Check if the work-in-progress queue is a clone. + error( + "%s: type specification of %s" + + " `%s` is invalid; the type checker " + + "function must return `null` or an `Error` but returned a %s. " + + "You may have forgotten to pass an argument to the type checker " + + "creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and " + + "shape all require an argument).", + componentName || "React class", + location, + typeSpecName, + typeof error$1 + ); - var current = workInProgress.alternate; + setCurrentlyValidatingElement(null); + } - if (current !== null) { - var currentQueue = current.updateQueue; + if ( + error$1 instanceof Error && + !(error$1.message in loggedTypeFailures) + ) { + // Only monitor this failure once because there tends to be a lot of the + // same error. + loggedTypeFailures[error$1.message] = true; + setCurrentlyValidatingElement(element); - if (queue === currentQueue) { - // The work-in-progress queue is the same as current. This happens when - // we bail out on a parent fiber that then captures an error thrown by - // a child. Since we want to append the update only to the work-in - // -progress queue, we need to clone the updates. We usually clone during - // processUpdateQueue, but that didn't happen in this case because we - // skipped over the parent when we bailed out. - var newFirst = null; - var newLast = null; - var firstBaseUpdate = queue.firstBaseUpdate; + error("Failed %s type: %s", location, error$1.message); - if (firstBaseUpdate !== null) { - // Loop through the updates and clone them. - var update = firstBaseUpdate; + setCurrentlyValidatingElement(null); + } + } + } + } +} - do { - var clone = { - lane: update.lane, - tag: update.tag, - payload: update.payload, - // When this update is rebased, we should not fire its - // callback again. - callback: null, - next: null - }; +var valueStack = []; +var fiberStack; - if (newLast === null) { - newFirst = newLast = clone; - } else { - newLast.next = clone; - newLast = clone; - } // $FlowFixMe[incompatible-type] we bail out when we get a null +{ + fiberStack = []; +} - update = update.next; - } while (update !== null); // Append the captured update the end of the cloned list. +var index = -1; - if (newLast === null) { - newFirst = newLast = capturedUpdate; - } else { - newLast.next = capturedUpdate; - newLast = capturedUpdate; - } - } else { - // There are no base updates. - newFirst = newLast = capturedUpdate; - } +function createCursor(defaultValue) { + return { + current: defaultValue + }; +} - queue = { - baseState: currentQueue.baseState, - firstBaseUpdate: newFirst, - lastBaseUpdate: newLast, - shared: currentQueue.shared, - callbacks: currentQueue.callbacks - }; - workInProgress.updateQueue = queue; - return; +function pop(cursor, fiber) { + if (index < 0) { + { + error("Unexpected pop."); } - } // Append the update to the end of the list. - - var lastBaseUpdate = queue.lastBaseUpdate; - if (lastBaseUpdate === null) { - queue.firstBaseUpdate = capturedUpdate; - } else { - lastBaseUpdate.next = capturedUpdate; + return; } - queue.lastBaseUpdate = capturedUpdate; -} - -function getStateFromUpdate( - workInProgress, - queue, - update, - prevState, - nextProps, - instance -) { - switch (update.tag) { - case ReplaceState: { - var payload = update.payload; + { + if (fiber !== fiberStack[index]) { + error("Unexpected Fiber popped."); + } + } - if (typeof payload === "function") { - // Updater function - { - enterDisallowedContextReadInDEV(); - } + cursor.current = valueStack[index]; + valueStack[index] = null; - var nextState = payload.call(instance, prevState, nextProps); + { + fiberStack[index] = null; + } - { - if (workInProgress.mode & StrictLegacyMode) { - setIsStrictModeForDevtools(true); + index--; +} - try { - payload.call(instance, prevState, nextProps); - } finally { - setIsStrictModeForDevtools(false); - } - } +function push(cursor, value, fiber) { + index++; + valueStack[index] = cursor.current; - exitDisallowedContextReadInDEV(); - } + { + fiberStack[index] = fiber; + } - return nextState; - } // State object + cursor.current = value; +} - return payload; - } +var warnedAboutMissingGetChildContext; - case CaptureUpdate: { - workInProgress.flags = - (workInProgress.flags & ~ShouldCapture) | DidCapture; +{ + warnedAboutMissingGetChildContext = {}; +} + +var emptyContextObject = {}; + +{ + Object.freeze(emptyContextObject); +} // A cursor to the current merged context object on the stack. + +var contextStackCursor$1 = createCursor(emptyContextObject); // A cursor to a boolean indicating whether the context has changed. + +var didPerformWorkStackCursor = createCursor(false); // Keep track of the previous context object that was on the stack. +// We use this to get access to the parent context after we have already +// pushed the next context provider, and now need to merge their contexts. + +var previousContext = emptyContextObject; + +function getUnmaskedContext( + workInProgress, + Component, + didPushOwnContextIfProvider +) { + { + if (didPushOwnContextIfProvider && isContextProvider(Component)) { + // If the fiber is a context provider itself, when we read its context + // we may have already pushed its own child context on the stack. A context + // provider should not "see" its own child context. Therefore we read the + // previous (parent) context instead for a context provider. + return previousContext; } - // Intentional fallthrough - case UpdateState: { - var _payload = update.payload; - var partialState; + return contextStackCursor$1.current; + } +} - if (typeof _payload === "function") { - // Updater function - { - enterDisallowedContextReadInDEV(); - } +function cacheContext(workInProgress, unmaskedContext, maskedContext) { + { + var instance = workInProgress.stateNode; + instance.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext; + instance.__reactInternalMemoizedMaskedChildContext = maskedContext; + } +} - partialState = _payload.call(instance, prevState, nextProps); +function getMaskedContext(workInProgress, unmaskedContext) { + { + var type = workInProgress.type; + var contextTypes = type.contextTypes; - { - if (workInProgress.mode & StrictLegacyMode) { - setIsStrictModeForDevtools(true); + if (!contextTypes) { + return emptyContextObject; + } // Avoid recreating masked context unless unmasked context has changed. + // Failing to do this will result in unnecessary calls to componentWillReceiveProps. + // This may trigger infinite loops if componentWillReceiveProps calls setState. - try { - _payload.call(instance, prevState, nextProps); - } finally { - setIsStrictModeForDevtools(false); - } - } + var instance = workInProgress.stateNode; - exitDisallowedContextReadInDEV(); - } - } else { - // Partial state object - partialState = _payload; - } + if ( + instance && + instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext + ) { + return instance.__reactInternalMemoizedMaskedChildContext; + } - if (partialState === null || partialState === undefined) { - // Null and undefined are treated as no-ops. - return prevState; - } // Merge the partial state and the previous state. + var context = {}; - return assign({}, prevState, partialState); + for (var key in contextTypes) { + context[key] = unmaskedContext[key]; } - case ForceUpdate: { - hasForceUpdate = true; - return prevState; + { + var name = getComponentNameFromFiber(workInProgress) || "Unknown"; + checkPropTypes(contextTypes, context, "context", name); + } // Cache unmasked context so we can avoid recreating masked context unless necessary. + // Context is created before the class component is instantiated so check for instance. + + if (instance) { + cacheContext(workInProgress, unmaskedContext, context); } - } - return prevState; + return context; + } } -function processUpdateQueue(workInProgress, props, instance, renderLanes) { - // This is always non-null on a ClassComponent or HostRoot - var queue = workInProgress.updateQueue; - hasForceUpdate = false; - +function hasContextChanged() { { - currentlyProcessingQueue = queue.shared; + return didPerformWorkStackCursor.current; } +} - var firstBaseUpdate = queue.firstBaseUpdate; - var lastBaseUpdate = queue.lastBaseUpdate; // Check if there are pending updates. If so, transfer them to the base queue. - - var pendingQueue = queue.shared.pending; +function isContextProvider(type) { + { + var childContextTypes = type.childContextTypes; + return childContextTypes !== null && childContextTypes !== undefined; + } +} - if (pendingQueue !== null) { - queue.shared.pending = null; // The pending queue is circular. Disconnect the pointer between first - // and last so that it's non-circular. +function popContext(fiber) { + { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor$1, fiber); + } +} - var lastPendingUpdate = pendingQueue; - var firstPendingUpdate = lastPendingUpdate.next; - lastPendingUpdate.next = null; // Append pending updates to base queue +function popTopLevelContextObject(fiber) { + { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor$1, fiber); + } +} - if (lastBaseUpdate === null) { - firstBaseUpdate = firstPendingUpdate; - } else { - lastBaseUpdate.next = firstPendingUpdate; +function pushTopLevelContextObject(fiber, context, didChange) { + { + if (contextStackCursor$1.current !== emptyContextObject) { + throw new Error( + "Unexpected context found on stack. " + + "This error is likely caused by a bug in React. Please file an issue." + ); } - lastBaseUpdate = lastPendingUpdate; // If there's a current queue, and it's different from the base queue, then - // we need to transfer the updates to that queue, too. Because the base - // queue is a singly-linked list with no cycles, we can append to both - // lists and take advantage of structural sharing. - // TODO: Pass `current` as argument + push(contextStackCursor$1, context, fiber); + push(didPerformWorkStackCursor, didChange, fiber); + } +} - var current = workInProgress.alternate; +function processChildContext(fiber, type, parentContext) { + { + var instance = fiber.stateNode; + var childContextTypes = type.childContextTypes; // TODO (bvaughn) Replace this behavior with an invariant() in the future. + // It has only been added in Fiber to match the (unintentional) behavior in Stack. - if (current !== null) { - // This is always non-null on a ClassComponent or HostRoot - var currentQueue = current.updateQueue; - var currentLastBaseUpdate = currentQueue.lastBaseUpdate; + if (typeof instance.getChildContext !== "function") { + { + var componentName = getComponentNameFromFiber(fiber) || "Unknown"; - if (currentLastBaseUpdate !== lastBaseUpdate) { - if (currentLastBaseUpdate === null) { - currentQueue.firstBaseUpdate = firstPendingUpdate; - } else { - currentLastBaseUpdate.next = firstPendingUpdate; - } + if (!warnedAboutMissingGetChildContext[componentName]) { + warnedAboutMissingGetChildContext[componentName] = true; - currentQueue.lastBaseUpdate = lastPendingUpdate; + error( + "%s.childContextTypes is specified but there is no getChildContext() method " + + "on the instance. You can either define getChildContext() on %s or remove " + + "childContextTypes from it.", + componentName, + componentName + ); + } } + + return parentContext; } - } // These values may change as we process the queue. - if (firstBaseUpdate !== null) { - // Iterate through the list of updates to compute the result. - var newState = queue.baseState; // TODO: Don't need to accumulate this. Instead, we can remove renderLanes - // from the original lanes. + var childContext = instance.getChildContext(); - var newLanes = NoLanes; - var newBaseState = null; - var newFirstBaseUpdate = null; - var newLastBaseUpdate = null; - var update = firstBaseUpdate; - - do { - // An extra OffscreenLane bit is added to updates that were made to - // a hidden tree, so that we can distinguish them from updates that were - // already there when the tree was hidden. - var updateLane = removeLanes(update.lane, OffscreenLane); - var isHiddenUpdate = updateLane !== update.lane; // Check if this update was made while the tree was hidden. If so, then - // it's not a "base" update and we should disregard the extra base lanes - // that were added to renderLanes when we entered the Offscreen tree. - - var shouldSkipUpdate = isHiddenUpdate - ? !isSubsetOfLanes(getWorkInProgressRootRenderLanes(), updateLane) - : !isSubsetOfLanes(renderLanes, updateLane); + for (var contextKey in childContext) { + if (!(contextKey in childContextTypes)) { + throw new Error( + (getComponentNameFromFiber(fiber) || "Unknown") + + '.getChildContext(): key "' + + contextKey + + '" is not defined in childContextTypes.' + ); + } + } - if (shouldSkipUpdate) { - // Priority is insufficient. Skip this update. If this is the first - // skipped update, the previous update/state is the new base - // update/state. - var clone = { - lane: updateLane, - tag: update.tag, - payload: update.payload, - callback: update.callback, - next: null - }; + { + var name = getComponentNameFromFiber(fiber) || "Unknown"; + checkPropTypes(childContextTypes, childContext, "child context", name); + } - if (newLastBaseUpdate === null) { - newFirstBaseUpdate = newLastBaseUpdate = clone; - newBaseState = newState; - } else { - newLastBaseUpdate = newLastBaseUpdate.next = clone; - } // Update the remaining priority in the queue. + return assign({}, parentContext, childContext); + } +} - newLanes = mergeLanes(newLanes, updateLane); - } else { - // This update does have sufficient priority. - if (newLastBaseUpdate !== null) { - var _clone = { - // This update is going to be committed so we never want uncommit - // it. Using NoLane works because 0 is a subset of all bitmasks, so - // this will never be skipped by the check above. - lane: NoLane, - tag: update.tag, - payload: update.payload, - // When this update is rebased, we should not fire its - // callback again. - callback: null, - next: null - }; - newLastBaseUpdate = newLastBaseUpdate.next = _clone; - } // Process this update. +function pushContextProvider(workInProgress) { + { + var instance = workInProgress.stateNode; // We push the context as early as possible to ensure stack integrity. + // If the instance does not exist yet, we will push null at first, + // and replace it on the stack later when invalidating the context. - newState = getStateFromUpdate( - workInProgress, - queue, - update, - newState, - props, - instance - ); - var callback = update.callback; + var memoizedMergedChildContext = + (instance && instance.__reactInternalMemoizedMergedChildContext) || + emptyContextObject; // Remember the parent context so we can merge with it later. + // Inherit the parent's did-perform-work value to avoid inadvertently blocking updates. - if (callback !== null) { - workInProgress.flags |= Callback; + previousContext = contextStackCursor$1.current; + push(contextStackCursor$1, memoizedMergedChildContext, workInProgress); + push( + didPerformWorkStackCursor, + didPerformWorkStackCursor.current, + workInProgress + ); + return true; + } +} - if (isHiddenUpdate) { - workInProgress.flags |= Visibility; - } +function invalidateContextProvider(workInProgress, type, didChange) { + { + var instance = workInProgress.stateNode; - var callbacks = queue.callbacks; + if (!instance) { + throw new Error( + "Expected to have an instance by this point. " + + "This error is likely caused by a bug in React. Please file an issue." + ); + } - if (callbacks === null) { - queue.callbacks = [callback]; - } else { - callbacks.push(callback); - } - } - } // $FlowFixMe[incompatible-type] we bail out when we get a null + if (didChange) { + // Merge parent and own context. + // Skip this if we're not updating due to sCU. + // This avoids unnecessarily recomputing memoized values. + var mergedContext = processChildContext( + workInProgress, + type, + previousContext + ); + instance.__reactInternalMemoizedMergedChildContext = mergedContext; // Replace the old (or empty) context with the new one. + // It is important to unwind the context in the reverse order. - update = update.next; + pop(didPerformWorkStackCursor, workInProgress); + pop(contextStackCursor$1, workInProgress); // Now push the new context and mark that it has changed. - if (update === null) { - pendingQueue = queue.shared.pending; + push(contextStackCursor$1, mergedContext, workInProgress); + push(didPerformWorkStackCursor, didChange, workInProgress); + } else { + pop(didPerformWorkStackCursor, workInProgress); + push(didPerformWorkStackCursor, didChange, workInProgress); + } + } +} - if (pendingQueue === null) { - break; - } else { - // An update was scheduled from inside a reducer. Add the new - // pending updates to the end of the list and keep processing. - var _lastPendingUpdate = pendingQueue; // Intentionally unsound. Pending updates form a circular list, but we - // unravel them when transferring them to the base queue. +function findCurrentUnmaskedContext(fiber) { + { + // Currently this is only used with renderSubtreeIntoContainer; not sure if it + // makes sense elsewhere + if (!isFiberMounted(fiber) || fiber.tag !== ClassComponent) { + throw new Error( + "Expected subtree parent to be a mounted class component. " + + "This error is likely caused by a bug in React. Please file an issue." + ); + } - var _firstPendingUpdate = _lastPendingUpdate.next; - _lastPendingUpdate.next = null; - update = _firstPendingUpdate; - queue.lastBaseUpdate = _lastPendingUpdate; - queue.shared.pending = null; - } - } - } while (true); + var node = fiber; - if (newLastBaseUpdate === null) { - newBaseState = newState; - } + do { + switch (node.tag) { + case HostRoot: + return node.stateNode.context; - queue.baseState = newBaseState; - queue.firstBaseUpdate = newFirstBaseUpdate; - queue.lastBaseUpdate = newLastBaseUpdate; + case ClassComponent: { + var Component = node.type; - if (firstBaseUpdate === null) { - // `queue.lanes` is used for entangling transitions. We can set it back to - // zero once the queue is empty. - queue.shared.lanes = NoLanes; - } // Set the remaining expiration time to be whatever is remaining in the queue. - // This should be fine because the only two other things that contribute to - // expiration time are props and context. We're already in the middle of the - // begin phase by the time we start processing the queue, so we've already - // dealt with the props. Context in components that specify - // shouldComponentUpdate is tricky; but we'll have to account for - // that regardless. + if (isContextProvider(Component)) { + return node.stateNode.__reactInternalMemoizedMergedChildContext; + } - markSkippedUpdateLanes(newLanes); - workInProgress.lanes = newLanes; - workInProgress.memoizedState = newState; - } + break; + } + } // $FlowFixMe[incompatible-type] we bail out when we get a null - { - currentlyProcessingQueue = null; - } -} + node = node.return; + } while (node !== null); -function callCallback(callback, context) { - if (typeof callback !== "function") { throw new Error( - "Invalid argument passed as callback. Expected a function. Instead " + - ("received: " + callback) + "Found unexpected detached subtree parent. " + + "This error is likely caused by a bug in React. Please file an issue." ); } - - callback.call(context); } -function resetHasForceUpdateBeforeProcessing() { - hasForceUpdate = false; +var LegacyRoot = 0; +var ConcurrentRoot = 1; + +// We use the existence of the state object as an indicator that the component +// is hidden. +var OffscreenVisible = + /* */ + 1; +var OffscreenDetached = + /* */ + 2; +var OffscreenPassiveEffectsConnected = + /* */ + 4; +function isOffscreenManual(offscreenFiber) { + return ( + offscreenFiber.memoizedProps !== null && + offscreenFiber.memoizedProps.mode === "manual" + ); } -function checkHasForceUpdateAfterProcessing() { - return hasForceUpdate; + +/** + * inlined Object.is polyfill to avoid requiring consumers ship their own + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is + */ +function is(x, y) { + return ( + (x === y && (x !== 0 || 1 / x === 1 / y)) || (x !== x && y !== y) // eslint-disable-line no-self-compare + ); } -function deferHiddenCallbacks(updateQueue) { - // When an update finishes on a hidden component, its callback should not - // be fired until/unless the component is made visible again. Stash the - // callback on the shared queue object so it can be fired later. - var newHiddenCallbacks = updateQueue.callbacks; - if (newHiddenCallbacks !== null) { - var existingHiddenCallbacks = updateQueue.shared.hiddenCallbacks; +var objectIs = typeof Object.is === "function" ? Object.is : is; // $FlowFixMe[method-unbinding] - if (existingHiddenCallbacks === null) { - updateQueue.shared.hiddenCallbacks = newHiddenCallbacks; - } else { - updateQueue.shared.hiddenCallbacks = - existingHiddenCallbacks.concat(newHiddenCallbacks); - } +var syncQueue = null; +var includesLegacySyncCallbacks = false; +var isFlushingSyncQueue = false; +function scheduleSyncCallback(callback) { + // Push this callback into an internal queue. We'll flush these either in + // the next tick, or earlier if something calls `flushSyncCallbackQueue`. + if (syncQueue === null) { + syncQueue = [callback]; + } else { + // Push onto existing queue. Don't need to schedule a callback because + // we already scheduled one when we created the queue. + syncQueue.push(callback); } } -function commitHiddenCallbacks(updateQueue, context) { - // This component is switching from hidden -> visible. Commit any callbacks - // that were previously deferred. - var hiddenCallbacks = updateQueue.shared.hiddenCallbacks; - - if (hiddenCallbacks !== null) { - updateQueue.shared.hiddenCallbacks = null; - - for (var i = 0; i < hiddenCallbacks.length; i++) { - var callback = hiddenCallbacks[i]; - callCallback(callback, context); - } +function scheduleLegacySyncCallback(callback) { + includesLegacySyncCallbacks = true; + scheduleSyncCallback(callback); +} +function flushSyncCallbacksOnlyInLegacyMode() { + // Only flushes the queue if there's a legacy sync callback scheduled. + // TODO: There's only a single type of callback: performSyncOnWorkOnRoot. So + // it might make more sense for the queue to be a list of roots instead of a + // list of generic callbacks. Then we can have two: one for legacy roots, one + // for concurrent roots. And this method would only flush the legacy ones. + if (includesLegacySyncCallbacks) { + flushSyncCallbacks(); } } -function commitCallbacks(updateQueue, context) { - var callbacks = updateQueue.callbacks; +function flushSyncCallbacks() { + if (!isFlushingSyncQueue && syncQueue !== null) { + // Prevent re-entrance. + isFlushingSyncQueue = true; // Set the event priority to discrete + // TODO: Is this necessary anymore? The only user code that runs in this + // queue is in the render or commit phases, which already set the + // event priority. Should be able to remove. - if (callbacks !== null) { - updateQueue.callbacks = null; + var previousUpdatePriority = getCurrentUpdatePriority(); + setCurrentUpdatePriority(DiscreteEventPriority); + var errors = null; + var queue = syncQueue; // $FlowFixMe[incompatible-use] found when upgrading Flow - for (var i = 0; i < callbacks.length; i++) { - var callback = callbacks[i]; - callCallback(callback, context); + for (var i = 0; i < queue.length; i++) { + // $FlowFixMe[incompatible-use] found when upgrading Flow + var callback = queue[i]; + + try { + do { + var isSync = true; // $FlowFixMe[incompatible-type] we bail out when we get a null + + callback = callback(isSync); + } while (callback !== null); + } catch (error) { + // Collect errors so we can rethrow them at the end + if (errors === null) { + errors = [error]; + } else { + errors.push(error); + } + } } - } -} -/** - * Performs equality by iterating through keys on an object and returning false - * when any key has values which are not strictly equal between the arguments. - * Returns true when the values of all keys are strictly equal. - */ + syncQueue = null; + includesLegacySyncCallbacks = false; + setCurrentUpdatePriority(previousUpdatePriority); + isFlushingSyncQueue = false; -function shallowEqual(objA, objB) { - if (objectIs(objA, objB)) { - return true; - } + if (errors !== null) { + if (errors.length > 1) { + if (typeof AggregateError === "function") { + // eslint-disable-next-line no-undef + throw new AggregateError(errors); + } else { + for (var _i = 1; _i < errors.length; _i++) { + scheduleCallback$1( + ImmediatePriority, + throwError.bind(null, errors[_i]) + ); + } - if ( - typeof objA !== "object" || - objA === null || - typeof objB !== "object" || - objB === null - ) { - return false; + var firstError = errors[0]; + throw firstError; + } + } else { + var error = errors[0]; + throw error; + } + } } - var keysA = Object.keys(objA); - var keysB = Object.keys(objB); + return null; +} - if (keysA.length !== keysB.length) { - return false; - } // Test for A's keys different from B. +function throwError(error) { + throw error; +} - for (var i = 0; i < keysA.length; i++) { - var currentKey = keysA[i]; +// This is imported by the event replaying implementation in React DOM. It's +// in a separate file to break a circular dependency between the renderer and +// the reconciler. +function isRootDehydrated(root) { + var currentState = root.current.memoizedState; + return currentState.isDehydrated; +} - if ( - !hasOwnProperty.call(objB, currentKey) || - !objectIs(objA[currentKey], objB[currentKey]) - ) { - return false; +var contextStackCursor = createCursor(null); +var contextFiberStackCursor = createCursor(null); +var rootInstanceStackCursor = createCursor(null); + +function requiredContext(c) { + { + if (c === null) { + error( + "Expected host context to exist. This error is likely caused by a bug " + + "in React. Please file an issue." + ); } } - return true; + return c; } -function describeFiber(fiber) { - var owner = fiber._debugOwner ? fiber._debugOwner.type : null; - var source = fiber._debugSource; +function getRootHostContainer() { + var rootInstance = requiredContext(rootInstanceStackCursor.current); + return rootInstance; +} - switch (fiber.tag) { - case HostHoistable: - case HostSingleton: - case HostComponent: - return describeBuiltInComponentFrame(fiber.type, source, owner); +function pushHostContainer(fiber, nextRootInstance) { + // Push current root instance onto the stack; + // This allows us to reset root when portals are popped. + push(rootInstanceStackCursor, nextRootInstance, fiber); // Track the context and the Fiber that provided it. + // This enables us to pop only Fibers that provide unique contexts. - case LazyComponent: - return describeBuiltInComponentFrame("Lazy", source, owner); + push(contextFiberStackCursor, fiber, fiber); // Finally, we need to push the host context to the stack. + // However, we can't just call getRootHostContext() and push it because + // we'd have a different number of entries on the stack depending on + // whether getRootHostContext() throws somewhere in renderer code or not. + // So we push an empty value first. This lets us safely unwind on errors. - case SuspenseComponent: - return describeBuiltInComponentFrame("Suspense", source, owner); + push(contextStackCursor, null, fiber); + var nextRootContext = getRootHostContext(); // Now that we know this function doesn't throw, replace it. - case SuspenseListComponent: - return describeBuiltInComponentFrame("SuspenseList", source, owner); + pop(contextStackCursor, fiber); + push(contextStackCursor, nextRootContext, fiber); +} - case FunctionComponent: - case IndeterminateComponent: - case SimpleMemoComponent: - return describeFunctionComponentFrame(fiber.type, source, owner); +function popHostContainer(fiber) { + pop(contextStackCursor, fiber); + pop(contextFiberStackCursor, fiber); + pop(rootInstanceStackCursor, fiber); +} - case ForwardRef: - return describeFunctionComponentFrame(fiber.type.render, source, owner); +function getHostContext() { + var context = requiredContext(contextStackCursor.current); + return context; +} - case ClassComponent: - return describeClassComponentFrame(fiber.type, source, owner); +function pushHostContext(fiber) { + var context = requiredContext(contextStackCursor.current); + var nextContext = getChildHostContext(context, fiber.type); // Don't push this Fiber's context unless it's unique. - default: - return ""; - } + if (context === nextContext) { + return; + } // Track the context and the Fiber that provided it. + // This enables us to pop only Fibers that provide unique contexts. + + push(contextFiberStackCursor, fiber, fiber); + push(contextStackCursor, nextContext, fiber); } -function getStackByFiberInDevAndProd(workInProgress) { - try { - var info = ""; - var node = workInProgress; +function popHostContext(fiber) { + // Do not pop unless this Fiber provided the current context. + // pushHostContext() only pushes Fibers that provide unique contexts. + if (contextFiberStackCursor.current !== fiber) { + return; + } - do { - info += describeFiber(node); // $FlowFixMe[incompatible-type] we bail out when we get a null + pop(contextStackCursor, fiber); + pop(contextFiberStackCursor, fiber); +} - node = node.return; - } while (node); +var isHydrating = false; // This flag allows for warning supression when we expect there to be mismatches +// due to earlier mismatches or a suspended fiber. - return info; - } catch (x) { - return "\nError generating stack: " + x.message + "\n" + x.stack; +var didSuspendOrErrorDEV = false; // Hydration errors that were thrown inside this boundary + +var hydrationErrors = null; +function didSuspendOrErrorWhileHydratingDEV() { + { + return didSuspendOrErrorDEV; } } -var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; -var current = null; -var isRendering = false; -function getCurrentFiberOwnerNameInDevOrNull() { +function prepareToHydrateHostInstance(fiber, hostContext) { { - if (current === null) { - return null; - } - - var owner = current._debugOwner; - - if (owner !== null && typeof owner !== "undefined") { - return getComponentNameFromFiber(owner); - } + throw new Error( + "Expected prepareToHydrateHostInstance() to never be called. " + + "This error is likely caused by a bug in React. Please file an issue." + ); } - - return null; } -function getCurrentFiberStackInDev() { +function prepareToHydrateHostTextInstance(fiber) { { - if (current === null) { - return ""; - } // Safe because if current fiber exists, we are reconciling, - // and it is guaranteed to be the work-in-progress version. - - return getStackByFiberInDevAndProd(current); + throw new Error( + "Expected prepareToHydrateHostTextInstance() to never be called. " + + "This error is likely caused by a bug in React. Please file an issue." + ); } } -function resetCurrentFiber() { +function prepareToHydrateHostSuspenseInstance(fiber) { { - ReactDebugCurrentFrame.getCurrentStack = null; - current = null; - isRendering = false; + throw new Error( + "Expected prepareToHydrateHostSuspenseInstance() to never be called. " + + "This error is likely caused by a bug in React. Please file an issue." + ); } } -function setCurrentFiber(fiber) { + +function popHydrationState(fiber) { { - ReactDebugCurrentFrame.getCurrentStack = - fiber === null ? null : getCurrentFiberStackInDev; - current = fiber; - isRendering = false; + return false; } } -function getCurrentFiber() { - { - return current; + +function upgradeHydrationErrorsToRecoverable() { + if (hydrationErrors !== null) { + // Successfully completed a forced client render. The errors that occurred + // during the hydration attempt are now recovered. We will log them in + // commit phase, once the entire tree has finished. + queueRecoverableErrors(hydrationErrors); + hydrationErrors = null; } } -function setIsRendering(rendering) { - { - isRendering = rendering; + +function getIsHydrating() { + return isHydrating; +} + +function queueHydrationError(error) { + if (hydrationErrors === null) { + hydrationErrors = [error]; + } else { + hydrationErrors.push(error); } } -var ReactStrictModeWarnings = { - recordUnsafeLifecycleWarnings: function (fiber, instance) {}, - flushPendingUnsafeLifecycleWarnings: function () {}, - recordLegacyContextWarning: function (fiber, instance) {}, - flushLegacyContextWarning: function () {}, - discardPendingWarnings: function () {} -}; +// we wait until the current render is over (either finished or interrupted) +// before adding it to the fiber/hook queue. Push to this array so we can +// access the queue, fiber, update, et al later. -{ - var findStrictRoot = function (fiber) { - var maybeStrictRoot = null; - var node = fiber; +var concurrentQueues = []; +var concurrentQueuesIndex = 0; +var concurrentlyUpdatedLanes = NoLanes; +function finishQueueingConcurrentUpdates() { + var endIndex = concurrentQueuesIndex; + concurrentQueuesIndex = 0; + concurrentlyUpdatedLanes = NoLanes; + var i = 0; - while (node !== null) { - if (node.mode & StrictLegacyMode) { - maybeStrictRoot = node; + while (i < endIndex) { + var fiber = concurrentQueues[i]; + concurrentQueues[i++] = null; + var queue = concurrentQueues[i]; + concurrentQueues[i++] = null; + var update = concurrentQueues[i]; + concurrentQueues[i++] = null; + var lane = concurrentQueues[i]; + concurrentQueues[i++] = null; + + if (queue !== null && update !== null) { + var pending = queue.pending; + + if (pending === null) { + // This is the first update. Create a circular list. + update.next = update; + } else { + update.next = pending.next; + pending.next = update; } - node = node.return; + queue.pending = update; } - return maybeStrictRoot; - }; - - var setToSortedString = function (set) { - var array = []; - set.forEach(function (value) { - array.push(value); - }); - return array.sort().join(", "); - }; + if (lane !== NoLane) { + markUpdateLaneFromFiberToRoot(fiber, update, lane); + } + } +} +function getConcurrentlyUpdatedLanes() { + return concurrentlyUpdatedLanes; +} - var pendingComponentWillMountWarnings = []; - var pendingUNSAFE_ComponentWillMountWarnings = []; - var pendingComponentWillReceivePropsWarnings = []; - var pendingUNSAFE_ComponentWillReceivePropsWarnings = []; - var pendingComponentWillUpdateWarnings = []; - var pendingUNSAFE_ComponentWillUpdateWarnings = []; // Tracks components we have already warned about. +function enqueueUpdate$1(fiber, queue, update, lane) { + // Don't update the `childLanes` on the return path yet. If we already in + // the middle of rendering, wait until after it has completed. + concurrentQueues[concurrentQueuesIndex++] = fiber; + concurrentQueues[concurrentQueuesIndex++] = queue; + concurrentQueues[concurrentQueuesIndex++] = update; + concurrentQueues[concurrentQueuesIndex++] = lane; + concurrentlyUpdatedLanes = mergeLanes(concurrentlyUpdatedLanes, lane); // The fiber's `lane` field is used in some places to check if any work is + // scheduled, to perform an eager bailout, so we need to update it immediately. + // TODO: We should probably move this to the "shared" queue instead. - var didWarnAboutUnsafeLifecycles = new Set(); + fiber.lanes = mergeLanes(fiber.lanes, lane); + var alternate = fiber.alternate; - ReactStrictModeWarnings.recordUnsafeLifecycleWarnings = function ( - fiber, - instance - ) { - // Dedupe strategy: Warn once per component. - if (didWarnAboutUnsafeLifecycles.has(fiber.type)) { - return; - } + if (alternate !== null) { + alternate.lanes = mergeLanes(alternate.lanes, lane); + } +} - if ( - typeof instance.componentWillMount === "function" && // Don't warn about react-lifecycles-compat polyfilled components. - instance.componentWillMount.__suppressDeprecationWarning !== true - ) { - pendingComponentWillMountWarnings.push(fiber); - } +function enqueueConcurrentHookUpdate(fiber, queue, update, lane) { + var concurrentQueue = queue; + var concurrentUpdate = update; + enqueueUpdate$1(fiber, concurrentQueue, concurrentUpdate, lane); + return getRootForUpdatedFiber(fiber); +} +function enqueueConcurrentHookUpdateAndEagerlyBailout(fiber, queue, update) { + // This function is used to queue an update that doesn't need a rerender. The + // only reason we queue it is in case there's a subsequent higher priority + // update that causes it to be rebased. + var lane = NoLane; + var concurrentQueue = queue; + var concurrentUpdate = update; + enqueueUpdate$1(fiber, concurrentQueue, concurrentUpdate, lane); // Usually we can rely on the upcoming render phase to process the concurrent + // queue. However, since this is a bail out, we're not scheduling any work + // here. So the update we just queued will leak until something else happens + // to schedule work (if ever). + // + // Check if we're currently in the middle of rendering a tree, and if not, + // process the queue immediately to prevent a leak. - if ( - fiber.mode & StrictLegacyMode && - typeof instance.UNSAFE_componentWillMount === "function" - ) { - pendingUNSAFE_ComponentWillMountWarnings.push(fiber); - } + var isConcurrentlyRendering = getWorkInProgressRoot() !== null; - if ( - typeof instance.componentWillReceiveProps === "function" && - instance.componentWillReceiveProps.__suppressDeprecationWarning !== true - ) { - pendingComponentWillReceivePropsWarnings.push(fiber); - } + if (!isConcurrentlyRendering) { + finishQueueingConcurrentUpdates(); + } +} +function enqueueConcurrentClassUpdate(fiber, queue, update, lane) { + var concurrentQueue = queue; + var concurrentUpdate = update; + enqueueUpdate$1(fiber, concurrentQueue, concurrentUpdate, lane); + return getRootForUpdatedFiber(fiber); +} +function enqueueConcurrentRenderForLane(fiber, lane) { + enqueueUpdate$1(fiber, null, null, lane); + return getRootForUpdatedFiber(fiber); +} // Calling this function outside this module should only be done for backwards +// compatibility and should always be accompanied by a warning. - if ( - fiber.mode & StrictLegacyMode && - typeof instance.UNSAFE_componentWillReceiveProps === "function" - ) { - pendingUNSAFE_ComponentWillReceivePropsWarnings.push(fiber); - } +function unsafe_markUpdateLaneFromFiberToRoot(sourceFiber, lane) { + // NOTE: For Hyrum's Law reasons, if an infinite update loop is detected, it + // should throw before `markUpdateLaneFromFiberToRoot` is called. But this is + // undefined behavior and we can change it if we need to; it just so happens + // that, at the time of this writing, there's an internal product test that + // happens to rely on this. + var root = getRootForUpdatedFiber(sourceFiber); + markUpdateLaneFromFiberToRoot(sourceFiber, null, lane); + return root; +} - if ( - typeof instance.componentWillUpdate === "function" && - instance.componentWillUpdate.__suppressDeprecationWarning !== true - ) { - pendingComponentWillUpdateWarnings.push(fiber); - } +function markUpdateLaneFromFiberToRoot(sourceFiber, update, lane) { + // Update the source fiber's lanes + sourceFiber.lanes = mergeLanes(sourceFiber.lanes, lane); + var alternate = sourceFiber.alternate; - if ( - fiber.mode & StrictLegacyMode && - typeof instance.UNSAFE_componentWillUpdate === "function" - ) { - pendingUNSAFE_ComponentWillUpdateWarnings.push(fiber); - } - }; + if (alternate !== null) { + alternate.lanes = mergeLanes(alternate.lanes, lane); + } // Walk the parent path to the root and update the child lanes. - ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = function () { - // We do an initial pass to gather component names - var componentWillMountUniqueNames = new Set(); + var isHidden = false; + var parent = sourceFiber.return; + var node = sourceFiber; - if (pendingComponentWillMountWarnings.length > 0) { - pendingComponentWillMountWarnings.forEach(function (fiber) { - componentWillMountUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingComponentWillMountWarnings = []; + while (parent !== null) { + parent.childLanes = mergeLanes(parent.childLanes, lane); + alternate = parent.alternate; + + if (alternate !== null) { + alternate.childLanes = mergeLanes(alternate.childLanes, lane); } - var UNSAFE_componentWillMountUniqueNames = new Set(); + if (parent.tag === OffscreenComponent) { + // Check if this offscreen boundary is currently hidden. + // + // The instance may be null if the Offscreen parent was unmounted. Usually + // the parent wouldn't be reachable in that case because we disconnect + // fibers from the tree when they are deleted. However, there's a weird + // edge case where setState is called on a fiber that was interrupted + // before it ever mounted. Because it never mounts, it also never gets + // deleted. Because it never gets deleted, its return pointer never gets + // disconnected. Which means it may be attached to a deleted Offscreen + // parent node. (This discovery suggests it may be better for memory usage + // if we don't attach the `return` pointer until the commit phase, though + // in order to do that we'd need some other way to track the return + // pointer during the initial render, like on the stack.) + // + // This case is always accompanied by a warning, but we still need to + // account for it. (There may be other cases that we haven't discovered, + // too.) + var offscreenInstance = parent.stateNode; - if (pendingUNSAFE_ComponentWillMountWarnings.length > 0) { - pendingUNSAFE_ComponentWillMountWarnings.forEach(function (fiber) { - UNSAFE_componentWillMountUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingUNSAFE_ComponentWillMountWarnings = []; + if ( + offscreenInstance !== null && + !(offscreenInstance._visibility & OffscreenVisible) + ) { + isHidden = true; + } } - var componentWillReceivePropsUniqueNames = new Set(); + node = parent; + parent = parent.return; + } - if (pendingComponentWillReceivePropsWarnings.length > 0) { - pendingComponentWillReceivePropsWarnings.forEach(function (fiber) { - componentWillReceivePropsUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingComponentWillReceivePropsWarnings = []; - } + if (isHidden && update !== null && node.tag === HostRoot) { + var root = node.stateNode; + markHiddenUpdate(root, update, lane); + } +} - var UNSAFE_componentWillReceivePropsUniqueNames = new Set(); +function getRootForUpdatedFiber(sourceFiber) { + // TODO: We will detect and infinite update loop and throw even if this fiber + // has already unmounted. This isn't really necessary but it happens to be the + // current behavior we've used for several release cycles. Consider not + // performing this check if the updated fiber already unmounted, since it's + // not possible for that to cause an infinite update loop. + throwIfInfiniteUpdateLoopDetected(); // When a setState happens, we must ensure the root is scheduled. Because + // update queues do not have a backpointer to the root, the only way to do + // this currently is to walk up the return path. This used to not be a big + // deal because we would have to walk up the return path to set + // the `childLanes`, anyway, but now those two traversals happen at + // different times. + // TODO: Consider adding a `root` backpointer on the update queue. - if (pendingUNSAFE_ComponentWillReceivePropsWarnings.length > 0) { - pendingUNSAFE_ComponentWillReceivePropsWarnings.forEach(function (fiber) { - UNSAFE_componentWillReceivePropsUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingUNSAFE_ComponentWillReceivePropsWarnings = []; - } + detectUpdateOnUnmountedFiber(sourceFiber, sourceFiber); + var node = sourceFiber; + var parent = node.return; - var componentWillUpdateUniqueNames = new Set(); + while (parent !== null) { + detectUpdateOnUnmountedFiber(sourceFiber, node); + node = parent; + parent = node.return; + } - if (pendingComponentWillUpdateWarnings.length > 0) { - pendingComponentWillUpdateWarnings.forEach(function (fiber) { - componentWillUpdateUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingComponentWillUpdateWarnings = []; + return node.tag === HostRoot ? node.stateNode : null; +} + +function detectUpdateOnUnmountedFiber(sourceFiber, parent) { + { + var alternate = parent.alternate; + + if ( + alternate === null && + (parent.flags & (Placement | Hydrating)) !== NoFlags$1 + ) { + warnAboutUpdateOnNotYetMountedFiberInDEV(sourceFiber); } + } +} - var UNSAFE_componentWillUpdateUniqueNames = new Set(); +var UpdateState = 0; +var ReplaceState = 1; +var ForceUpdate = 2; +var CaptureUpdate = 3; // Global state that is reset at the beginning of calling `processUpdateQueue`. +// It should only be read right after calling `processUpdateQueue`, via +// `checkHasForceUpdateAfterProcessing`. - if (pendingUNSAFE_ComponentWillUpdateWarnings.length > 0) { - pendingUNSAFE_ComponentWillUpdateWarnings.forEach(function (fiber) { - UNSAFE_componentWillUpdateUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingUNSAFE_ComponentWillUpdateWarnings = []; - } // Finally, we flush all the warnings - // UNSAFE_ ones before the deprecated ones, since they'll be 'louder' +var hasForceUpdate = false; +var didWarnUpdateInsideUpdate; +var currentlyProcessingQueue; - if (UNSAFE_componentWillMountUniqueNames.size > 0) { - var sortedNames = setToSortedString(UNSAFE_componentWillMountUniqueNames); +{ + didWarnUpdateInsideUpdate = false; + currentlyProcessingQueue = null; +} - error( - "Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code. " + - "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + - "* Move code with side effects to componentDidMount, and set initial state in the constructor.\n" + - "\nPlease update the following components: %s", - sortedNames - ); - } +function initializeUpdateQueue(fiber) { + var queue = { + baseState: fiber.memoizedState, + firstBaseUpdate: null, + lastBaseUpdate: null, + shared: { + pending: null, + lanes: NoLanes, + hiddenCallbacks: null + }, + callbacks: null + }; + fiber.updateQueue = queue; +} +function cloneUpdateQueue(current, workInProgress) { + // Clone the update queue from current. Unless it's already a clone. + var queue = workInProgress.updateQueue; + var currentQueue = current.updateQueue; - if (UNSAFE_componentWillReceivePropsUniqueNames.size > 0) { - var _sortedNames = setToSortedString( - UNSAFE_componentWillReceivePropsUniqueNames - ); + if (queue === currentQueue) { + var clone = { + baseState: currentQueue.baseState, + firstBaseUpdate: currentQueue.firstBaseUpdate, + lastBaseUpdate: currentQueue.lastBaseUpdate, + shared: currentQueue.shared, + callbacks: null + }; + workInProgress.updateQueue = clone; + } +} +function createUpdate(lane) { + var update = { + lane: lane, + tag: UpdateState, + payload: null, + callback: null, + next: null + }; + return update; +} +function enqueueUpdate(fiber, update, lane) { + var updateQueue = fiber.updateQueue; - error( - "Using UNSAFE_componentWillReceiveProps in strict mode is not recommended " + - "and may indicate bugs in your code. " + - "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + - "* Move data fetching code or side effects to componentDidUpdate.\n" + - "* If you're updating state whenever props change, " + - "refactor your code to use memoization techniques or move it to " + - "static getDerivedStateFromProps. Learn more at: https://reactjs.org/link/derived-state\n" + - "\nPlease update the following components: %s", - _sortedNames - ); - } + if (updateQueue === null) { + // Only occurs if the fiber has been unmounted. + return null; + } - if (UNSAFE_componentWillUpdateUniqueNames.size > 0) { - var _sortedNames2 = setToSortedString( - UNSAFE_componentWillUpdateUniqueNames - ); + var sharedQueue = updateQueue.shared; + + { + if ( + currentlyProcessingQueue === sharedQueue && + !didWarnUpdateInsideUpdate + ) { + var componentName = getComponentNameFromFiber(fiber); error( - "Using UNSAFE_componentWillUpdate in strict mode is not recommended " + - "and may indicate bugs in your code. " + - "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + - "* Move data fetching code or side effects to componentDidUpdate.\n" + - "\nPlease update the following components: %s", - _sortedNames2 + "An update (setState, replaceState, or forceUpdate) was scheduled " + + "from inside an update function. Update functions should be pure, " + + "with zero side-effects. Consider using componentDidUpdate or a " + + "callback.\n\nPlease update the following component: %s", + componentName ); - } - - if (componentWillMountUniqueNames.size > 0) { - var _sortedNames3 = setToSortedString(componentWillMountUniqueNames); - warn( - "componentWillMount has been renamed, and is not recommended for use. " + - "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + - "* Move code with side effects to componentDidMount, and set initial state in the constructor.\n" + - "* Rename componentWillMount to UNSAFE_componentWillMount to suppress " + - "this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. " + - "To rename all deprecated lifecycles to their new names, you can run " + - "`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n" + - "\nPlease update the following components: %s", - _sortedNames3 - ); + didWarnUpdateInsideUpdate = true; } + } - if (componentWillReceivePropsUniqueNames.size > 0) { - var _sortedNames4 = setToSortedString( - componentWillReceivePropsUniqueNames - ); + if (isUnsafeClassRenderPhaseUpdate()) { + // This is an unsafe render phase update. Add directly to the update + // queue so we can process it immediately during the current render. + var pending = sharedQueue.pending; - warn( - "componentWillReceiveProps has been renamed, and is not recommended for use. " + - "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + - "* Move data fetching code or side effects to componentDidUpdate.\n" + - "* If you're updating state whenever props change, refactor your " + - "code to use memoization techniques or move it to " + - "static getDerivedStateFromProps. Learn more at: https://reactjs.org/link/derived-state\n" + - "* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress " + - "this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. " + - "To rename all deprecated lifecycles to their new names, you can run " + - "`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n" + - "\nPlease update the following components: %s", - _sortedNames4 - ); + if (pending === null) { + // This is the first update. Create a circular list. + update.next = update; + } else { + update.next = pending.next; + pending.next = update; } - if (componentWillUpdateUniqueNames.size > 0) { - var _sortedNames5 = setToSortedString(componentWillUpdateUniqueNames); + sharedQueue.pending = update; // Update the childLanes even though we're most likely already rendering + // this fiber. This is for backwards compatibility in the case where you + // update a different component during render phase than the one that is + // currently renderings (a pattern that is accompanied by a warning). - warn( - "componentWillUpdate has been renamed, and is not recommended for use. " + - "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + - "* Move data fetching code or side effects to componentDidUpdate.\n" + - "* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress " + - "this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. " + - "To rename all deprecated lifecycles to their new names, you can run " + - "`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n" + - "\nPlease update the following components: %s", - _sortedNames5 - ); - } - }; + return unsafe_markUpdateLaneFromFiberToRoot(fiber, lane); + } else { + return enqueueConcurrentClassUpdate(fiber, sharedQueue, update, lane); + } +} +function entangleTransitions(root, fiber, lane) { + var updateQueue = fiber.updateQueue; - var pendingLegacyContextWarning = new Map(); // Tracks components we have already warned about. + if (updateQueue === null) { + // Only occurs if the fiber has been unmounted. + return; + } - var didWarnAboutLegacyContext = new Set(); + var sharedQueue = updateQueue.shared; - ReactStrictModeWarnings.recordLegacyContextWarning = function ( - fiber, - instance - ) { - var strictRoot = findStrictRoot(fiber); + if (isTransitionLane(lane)) { + var queueLanes = sharedQueue.lanes; // If any entangled lanes are no longer pending on the root, then they must + // have finished. We can remove them from the shared queue, which represents + // a superset of the actually pending lanes. In some cases we may entangle + // more than we need to, but that's OK. In fact it's worse if we *don't* + // entangle when we should. - if (strictRoot === null) { - error( - "Expected to find a StrictMode component in a strict mode tree. " + - "This error is likely caused by a bug in React. Please file an issue." - ); + queueLanes = intersectLanes(queueLanes, root.pendingLanes); // Entangle the new transition lane with the other transition lanes. - return; - } // Dedup strategy: Warn once per component. + var newQueueLanes = mergeLanes(queueLanes, lane); + sharedQueue.lanes = newQueueLanes; // Even if queue.lanes already include lane, we don't know for certain if + // the lane finished since the last time we entangled it. So we need to + // entangle it again, just to be sure. - if (didWarnAboutLegacyContext.has(fiber.type)) { - return; - } + markRootEntangled(root, newQueueLanes); + } +} +function enqueueCapturedUpdate(workInProgress, capturedUpdate) { + // Captured updates are updates that are thrown by a child during the render + // phase. They should be discarded if the render is aborted. Therefore, + // we should only put them on the work-in-progress queue, not the current one. + var queue = workInProgress.updateQueue; // Check if the work-in-progress queue is a clone. - var warningsForRoot = pendingLegacyContextWarning.get(strictRoot); + var current = workInProgress.alternate; - if ( - fiber.type.contextTypes != null || - fiber.type.childContextTypes != null || - (instance !== null && typeof instance.getChildContext === "function") - ) { - if (warningsForRoot === undefined) { - warningsForRoot = []; - pendingLegacyContextWarning.set(strictRoot, warningsForRoot); - } + if (current !== null) { + var currentQueue = current.updateQueue; - warningsForRoot.push(fiber); - } - }; + if (queue === currentQueue) { + // The work-in-progress queue is the same as current. This happens when + // we bail out on a parent fiber that then captures an error thrown by + // a child. Since we want to append the update only to the work-in + // -progress queue, we need to clone the updates. We usually clone during + // processUpdateQueue, but that didn't happen in this case because we + // skipped over the parent when we bailed out. + var newFirst = null; + var newLast = null; + var firstBaseUpdate = queue.firstBaseUpdate; - ReactStrictModeWarnings.flushLegacyContextWarning = function () { - pendingLegacyContextWarning.forEach(function (fiberArray, strictRoot) { - if (fiberArray.length === 0) { - return; - } + if (firstBaseUpdate !== null) { + // Loop through the updates and clone them. + var update = firstBaseUpdate; - var firstFiber = fiberArray[0]; - var uniqueNames = new Set(); - fiberArray.forEach(function (fiber) { - uniqueNames.add(getComponentNameFromFiber(fiber) || "Component"); - didWarnAboutLegacyContext.add(fiber.type); - }); - var sortedNames = setToSortedString(uniqueNames); + do { + var clone = { + lane: update.lane, + tag: update.tag, + payload: update.payload, + // When this update is rebased, we should not fire its + // callback again. + callback: null, + next: null + }; - try { - setCurrentFiber(firstFiber); + if (newLast === null) { + newFirst = newLast = clone; + } else { + newLast.next = clone; + newLast = clone; + } // $FlowFixMe[incompatible-type] we bail out when we get a null - error( - "Legacy context API has been detected within a strict-mode tree." + - "\n\nThe old API will be supported in all 16.x releases, but applications " + - "using it should migrate to the new version." + - "\n\nPlease update the following components: %s" + - "\n\nLearn more about this warning here: https://reactjs.org/link/legacy-context", - sortedNames - ); - } finally { - resetCurrentFiber(); + update = update.next; + } while (update !== null); // Append the captured update the end of the cloned list. + + if (newLast === null) { + newFirst = newLast = capturedUpdate; + } else { + newLast.next = capturedUpdate; + newLast = capturedUpdate; + } + } else { + // There are no base updates. + newFirst = newLast = capturedUpdate; } - }); - }; - ReactStrictModeWarnings.discardPendingWarnings = function () { - pendingComponentWillMountWarnings = []; - pendingUNSAFE_ComponentWillMountWarnings = []; - pendingComponentWillReceivePropsWarnings = []; - pendingUNSAFE_ComponentWillReceivePropsWarnings = []; - pendingComponentWillUpdateWarnings = []; - pendingUNSAFE_ComponentWillUpdateWarnings = []; - pendingLegacyContextWarning = new Map(); - }; -} + queue = { + baseState: currentQueue.baseState, + firstBaseUpdate: newFirst, + lastBaseUpdate: newLast, + shared: currentQueue.shared, + callbacks: currentQueue.callbacks + }; + workInProgress.updateQueue = queue; + return; + } + } // Append the update to the end of the list. -/* - * The `'' + value` pattern (used in perf-sensitive code) throws for Symbol - * and Temporal.* types. See https://github.com/facebook/react/pull/22064. - * - * The functions in this module will throw an easier-to-understand, - * easier-to-debug exception with a clear errors message message explaining the - * problem. (Instead of a confusing exception thrown inside the implementation - * of the `value` object). - */ -// $FlowFixMe only called in DEV, so void return is not possible. -function typeName(value) { - { - // toStringTag is needed for namespaced types like Temporal.Instant - var hasToStringTag = typeof Symbol === "function" && Symbol.toStringTag; - var type = - (hasToStringTag && value[Symbol.toStringTag]) || - value.constructor.name || - "Object"; // $FlowFixMe + var lastBaseUpdate = queue.lastBaseUpdate; - return type; + if (lastBaseUpdate === null) { + queue.firstBaseUpdate = capturedUpdate; + } else { + lastBaseUpdate.next = capturedUpdate; } -} // $FlowFixMe only called in DEV, so void return is not possible. -function willCoercionThrow(value) { - { - try { - testStringCoercion(value); - return false; - } catch (e) { - return true; - } - } + queue.lastBaseUpdate = capturedUpdate; } -function testStringCoercion(value) { - // If you ended up here by following an exception call stack, here's what's - // happened: you supplied an object or symbol value to React (as a prop, key, - // DOM attribute, CSS property, string ref, etc.) and when React tried to - // coerce it to a string using `'' + value`, an exception was thrown. - // - // The most common types that will cause this exception are `Symbol` instances - // and Temporal objects like `Temporal.Instant`. But any object that has a - // `valueOf` or `[Symbol.toPrimitive]` method that throws will also cause this - // exception. (Library authors do this to prevent users from using built-in - // numeric operators like `+` or comparison operators like `>=` because custom - // methods are needed to perform accurate arithmetic or comparison.) - // - // To fix the problem, coerce this object or symbol value to a string before - // passing it to React. The most reliable way is usually `String(value)`. - // - // To find which value is throwing, check the browser or debugger console. - // Before this exception was thrown, there should be `console.error` output - // that shows the type (Symbol, Temporal.PlainDate, etc.) that caused the - // problem and how that type was used: key, atrribute, input value prop, etc. - // In most cases, this console output also shows the component and its - // ancestor components where the exception happened. - // - // eslint-disable-next-line react-internal/safe-string-coercion - return "" + value; -} -function checkKeyStringCoercion(value) { - { - if (willCoercionThrow(value)) { - error( - "The provided key is an unsupported type %s." + - " This value must be coerced to a string before before using it here.", - typeName(value) - ); - - return testStringCoercion(value); // throw (to help callers find troubleshooting comments) - } - } -} -function checkPropStringCoercion(value, propName) { - { - if (willCoercionThrow(value)) { - error( - "The provided `%s` prop is an unsupported type %s." + - " This value must be coerced to a string before before using it here.", - propName, - typeName(value) - ); - - return testStringCoercion(value); // throw (to help callers find troubleshooting comments) - } - } -} +function getStateFromUpdate( + workInProgress, + queue, + update, + prevState, + nextProps, + instance +) { + switch (update.tag) { + case ReplaceState: { + var payload = update.payload; -var ReactCurrentActQueue$2 = ReactSharedInternals.ReactCurrentActQueue; // An error that is thrown (e.g. by `use`) to trigger Suspense. If we -// detect this is caught by userspace, we'll log a warning in development. + if (typeof payload === "function") { + // Updater function + { + enterDisallowedContextReadInDEV(); + } -var SuspenseException = new Error( - "Suspense Exception: This is not a real error! It's an implementation " + - "detail of `use` to interrupt the current render. You must either " + - "rethrow it immediately, or move the `use` call outside of the " + - "`try/catch` block. Capturing without rethrowing will lead to " + - "unexpected behavior.\n\n" + - "To handle async errors, wrap your component in an error boundary, or " + - "call the promise's `.catch` method and pass the result to `use`" -); -var SuspenseyCommitException = new Error( - "Suspense Exception: This is not a real error, and should not leak into " + - "userspace. If you're seeing this, it's likely a bug in React." -); // This is a noop thenable that we use to trigger a fallback in throwException. -// TODO: It would be better to refactor throwException into multiple functions -// so we can trigger a fallback directly without having to check the type. But -// for now this will do. + var nextState = payload.call(instance, prevState, nextProps); -var noopSuspenseyCommitThenable = { - then: function () {} -}; -function createThenableState() { - // The ThenableState is created the first time a component suspends. If it - // suspends again, we'll reuse the same state. - return []; -} -function isThenableResolved(thenable) { - var status = thenable.status; - return status === "fulfilled" || status === "rejected"; -} + { + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); -function noop$1() {} + try { + payload.call(instance, prevState, nextProps); + } finally { + setIsStrictModeForDevtools(false); + } + } -function trackUsedThenable(thenableState, thenable, index) { - if (ReactCurrentActQueue$2.current !== null) { - ReactCurrentActQueue$2.didUsePromise = true; - } + exitDisallowedContextReadInDEV(); + } - var previous = thenableState[index]; + return nextState; + } // State object - if (previous === undefined) { - thenableState.push(thenable); - } else { - if (previous !== thenable) { - // Reuse the previous thenable, and drop the new one. We can assume - // they represent the same value, because components are idempotent. - // Avoid an unhandled rejection errors for the Promises that we'll - // intentionally ignore. - thenable.then(noop$1, noop$1); - thenable = previous; + return payload; } - } // We use an expando to track the status and result of a thenable so that we - // can synchronously unwrap the value. Think of this as an extension of the - // Promise API, or a custom interface that is a superset of Thenable. - // - // If the thenable doesn't have a status, set it to "pending" and attach - // a listener that will update its status and result when it resolves. - switch (thenable.status) { - case "fulfilled": { - var fulfilledValue = thenable.value; - return fulfilledValue; + case CaptureUpdate: { + workInProgress.flags = + (workInProgress.flags & ~ShouldCapture) | DidCapture; } + // Intentional fallthrough - case "rejected": { - var rejectedError = thenable.reason; - throw rejectedError; - } + case UpdateState: { + var _payload = update.payload; + var partialState; - default: { - if (typeof thenable.status === "string") { - // Only instrument the thenable if the status if not defined. If - // it's defined, but an unknown value, assume it's been instrumented by - // some custom userspace implementation. We treat it as "pending". - // Attach a dummy listener, to ensure that any lazy initialization can - // happen. Flight lazily parses JSON when the value is actually awaited. - thenable.then(noop$1, noop$1); - } else { - var pendingThenable = thenable; - pendingThenable.status = "pending"; - pendingThenable.then( - function (fulfilledValue) { - if (thenable.status === "pending") { - var fulfilledThenable = thenable; - fulfilledThenable.status = "fulfilled"; - fulfilledThenable.value = fulfilledValue; - } - }, - function (error) { - if (thenable.status === "pending") { - var rejectedThenable = thenable; - rejectedThenable.status = "rejected"; - rejectedThenable.reason = error; + if (typeof _payload === "function") { + // Updater function + { + enterDisallowedContextReadInDEV(); + } + + partialState = _payload.call(instance, prevState, nextProps); + + { + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); + + try { + _payload.call(instance, prevState, nextProps); + } finally { + setIsStrictModeForDevtools(false); } } - ); - } // Check one more time in case the thenable resolved synchronously. - - switch (thenable.status) { - case "fulfilled": { - var fulfilledThenable = thenable; - return fulfilledThenable.value; - } - case "rejected": { - var rejectedThenable = thenable; - throw rejectedThenable.reason; + exitDisallowedContextReadInDEV(); } - } // Suspend. - // - // Throwing here is an implementation detail that allows us to unwind the - // call stack. But we shouldn't allow it to leak into userspace. Throw an - // opaque placeholder value instead of the actual thenable. If it doesn't - // get captured by the work loop, log a warning, because that means - // something in userspace must have caught it. + } else { + // Partial state object + partialState = _payload; + } - suspendedThenable = thenable; + if (partialState === null || partialState === undefined) { + // Null and undefined are treated as no-ops. + return prevState; + } // Merge the partial state and the previous state. - { - needsToResetSuspendedThenableDEV = true; - } + return assign({}, prevState, partialState); + } - throw SuspenseException; + case ForceUpdate: { + hasForceUpdate = true; + return prevState; } } -} -// passed to the rest of the Suspense implementation — which, for historical -// reasons, expects to receive a thenable. -var suspendedThenable = null; -var needsToResetSuspendedThenableDEV = false; -function getSuspendedThenable() { - // This is called right after `use` suspends by throwing an exception. `use` - // throws an opaque value instead of the thenable itself so that it can't be - // caught in userspace. Then the work loop accesses the actual thenable using - // this function. - if (suspendedThenable === null) { - throw new Error( - "Expected a suspended thenable. This is a bug in React. Please file " + - "an issue." - ); - } + return prevState; +} - var thenable = suspendedThenable; - suspendedThenable = null; +function processUpdateQueue(workInProgress, props, instance, renderLanes) { + // This is always non-null on a ClassComponent or HostRoot + var queue = workInProgress.updateQueue; + hasForceUpdate = false; { - needsToResetSuspendedThenableDEV = false; + currentlyProcessingQueue = queue.shared; } - return thenable; -} -function checkIfUseWrappedInTryCatch() { - { - // This was set right before SuspenseException was thrown, and it should - // have been cleared when the exception was handled. If it wasn't, - // it must have been caught by userspace. - if (needsToResetSuspendedThenableDEV) { - needsToResetSuspendedThenableDEV = false; - return true; - } - } + var firstBaseUpdate = queue.firstBaseUpdate; + var lastBaseUpdate = queue.lastBaseUpdate; // Check if there are pending updates. If so, transfer them to the base queue. - return false; -} + var pendingQueue = queue.shared.pending; -var thenableState$1 = null; -var thenableIndexCounter$1 = 0; -var didWarnAboutMaps; -var didWarnAboutGenerators; -var didWarnAboutStringRefs; -var ownerHasKeyUseWarning; -var ownerHasFunctionTypeWarning; + if (pendingQueue !== null) { + queue.shared.pending = null; // The pending queue is circular. Disconnect the pointer between first + // and last so that it's non-circular. -var warnForMissingKey = function (child, returnFiber) {}; - -{ - didWarnAboutMaps = false; - didWarnAboutGenerators = false; - didWarnAboutStringRefs = {}; - /** - * Warn if there's no key explicitly set on dynamic arrays of children or - * object keys are not valid. This allows us to keep track of children between - * updates. - */ - - ownerHasKeyUseWarning = {}; - ownerHasFunctionTypeWarning = {}; + var lastPendingUpdate = pendingQueue; + var firstPendingUpdate = lastPendingUpdate.next; + lastPendingUpdate.next = null; // Append pending updates to base queue - warnForMissingKey = function (child, returnFiber) { - if (child === null || typeof child !== "object") { - return; + if (lastBaseUpdate === null) { + firstBaseUpdate = firstPendingUpdate; + } else { + lastBaseUpdate.next = firstPendingUpdate; } - if (!child._store || child._store.validated || child.key != null) { - return; - } + lastBaseUpdate = lastPendingUpdate; // If there's a current queue, and it's different from the base queue, then + // we need to transfer the updates to that queue, too. Because the base + // queue is a singly-linked list with no cycles, we can append to both + // lists and take advantage of structural sharing. + // TODO: Pass `current` as argument - if (typeof child._store !== "object") { - throw new Error( - "React Component in warnForMissingKey should have a _store. " + - "This error is likely caused by a bug in React. Please file an issue." - ); - } // $FlowFixMe unable to narrow type from mixed to writable object + var current = workInProgress.alternate; - child._store.validated = true; - var componentName = getComponentNameFromFiber(returnFiber) || "Component"; + if (current !== null) { + // This is always non-null on a ClassComponent or HostRoot + var currentQueue = current.updateQueue; + var currentLastBaseUpdate = currentQueue.lastBaseUpdate; - if (ownerHasKeyUseWarning[componentName]) { - return; - } + if (currentLastBaseUpdate !== lastBaseUpdate) { + if (currentLastBaseUpdate === null) { + currentQueue.firstBaseUpdate = firstPendingUpdate; + } else { + currentLastBaseUpdate.next = firstPendingUpdate; + } - ownerHasKeyUseWarning[componentName] = true; + currentQueue.lastBaseUpdate = lastPendingUpdate; + } + } + } // These values may change as we process the queue. - error( - "Each child in a list should have a unique " + - '"key" prop. See https://reactjs.org/link/warning-keys for ' + - "more information." - ); - }; -} + if (firstBaseUpdate !== null) { + // Iterate through the list of updates to compute the result. + var newState = queue.baseState; // TODO: Don't need to accumulate this. Instead, we can remove renderLanes + // from the original lanes. -function isReactClass(type) { - return type.prototype && type.prototype.isReactComponent; -} + var newLanes = NoLanes; + var newBaseState = null; + var newFirstBaseUpdate = null; + var newLastBaseUpdate = null; + var update = firstBaseUpdate; -function unwrapThenable(thenable) { - var index = thenableIndexCounter$1; - thenableIndexCounter$1 += 1; + do { + // An extra OffscreenLane bit is added to updates that were made to + // a hidden tree, so that we can distinguish them from updates that were + // already there when the tree was hidden. + var updateLane = removeLanes(update.lane, OffscreenLane); + var isHiddenUpdate = updateLane !== update.lane; // Check if this update was made while the tree was hidden. If so, then + // it's not a "base" update and we should disregard the extra base lanes + // that were added to renderLanes when we entered the Offscreen tree. - if (thenableState$1 === null) { - thenableState$1 = createThenableState(); - } + var shouldSkipUpdate = isHiddenUpdate + ? !isSubsetOfLanes(getWorkInProgressRootRenderLanes(), updateLane) + : !isSubsetOfLanes(renderLanes, updateLane); - return trackUsedThenable(thenableState$1, thenable, index); -} + if (shouldSkipUpdate) { + // Priority is insufficient. Skip this update. If this is the first + // skipped update, the previous update/state is the new base + // update/state. + var clone = { + lane: updateLane, + tag: update.tag, + payload: update.payload, + callback: update.callback, + next: null + }; -function coerceRef(returnFiber, current, element) { - var mixedRef = element.ref; + if (newLastBaseUpdate === null) { + newFirstBaseUpdate = newLastBaseUpdate = clone; + newBaseState = newState; + } else { + newLastBaseUpdate = newLastBaseUpdate.next = clone; + } // Update the remaining priority in the queue. - if ( - mixedRef !== null && - typeof mixedRef !== "function" && - typeof mixedRef !== "object" - ) { - { - if ( - // We warn in ReactElement.js if owner and self are equal for string refs - // because these cannot be automatically converted to an arrow function - // using a codemod. Therefore, we don't have to warn about string refs again. - !( - element._owner && - element._self && - element._owner.stateNode !== element._self - ) && // Will already throw with "Function components cannot have string refs" - !(element._owner && element._owner.tag !== ClassComponent) && // Will already warn with "Function components cannot be given refs" - !(typeof element.type === "function" && !isReactClass(element.type)) && // Will already throw with "Element ref was specified as a string (someStringRef) but no owner was set" - element._owner - ) { - var componentName = - getComponentNameFromFiber(returnFiber) || "Component"; + newLanes = mergeLanes(newLanes, updateLane); + } else { + // This update does have sufficient priority. + if (newLastBaseUpdate !== null) { + var _clone = { + // This update is going to be committed so we never want uncommit + // it. Using NoLane works because 0 is a subset of all bitmasks, so + // this will never be skipped by the check above. + lane: NoLane, + tag: update.tag, + payload: update.payload, + // When this update is rebased, we should not fire its + // callback again. + callback: null, + next: null + }; + newLastBaseUpdate = newLastBaseUpdate.next = _clone; + } // Process this update. - if (!didWarnAboutStringRefs[componentName]) { - error( - 'Component "%s" contains the string ref "%s". Support for string refs ' + - "will be removed in a future major release. We recommend using " + - "useRef() or createRef() instead. " + - "Learn more about using refs safely here: " + - "https://reactjs.org/link/strict-mode-string-ref", - componentName, - mixedRef - ); + newState = getStateFromUpdate( + workInProgress, + queue, + update, + newState, + props, + instance + ); + var callback = update.callback; - didWarnAboutStringRefs[componentName] = true; - } - } - } + if (callback !== null) { + workInProgress.flags |= Callback; - if (element._owner) { - var owner = element._owner; - var inst; + if (isHiddenUpdate) { + workInProgress.flags |= Visibility; + } - if (owner) { - var ownerFiber = owner; + var callbacks = queue.callbacks; - if (ownerFiber.tag !== ClassComponent) { - throw new Error( - "Function components cannot have string refs. " + - "We recommend using useRef() instead. " + - "Learn more about using refs safely here: " + - "https://reactjs.org/link/strict-mode-string-ref" - ); + if (callbacks === null) { + queue.callbacks = [callback]; + } else { + callbacks.push(callback); + } } + } // $FlowFixMe[incompatible-type] we bail out when we get a null - inst = ownerFiber.stateNode; - } - - if (!inst) { - throw new Error( - "Missing owner for string ref " + - mixedRef + - ". This error is likely caused by a " + - "bug in React. Please file an issue." - ); - } // Assigning this to a const so Flow knows it won't change in the closure - - var resolvedInst = inst; + update = update.next; - { - checkPropStringCoercion(mixedRef, "ref"); - } + if (update === null) { + pendingQueue = queue.shared.pending; - var stringRef = "" + mixedRef; // Check if previous string ref matches new string ref + if (pendingQueue === null) { + break; + } else { + // An update was scheduled from inside a reducer. Add the new + // pending updates to the end of the list and keep processing. + var _lastPendingUpdate = pendingQueue; // Intentionally unsound. Pending updates form a circular list, but we + // unravel them when transferring them to the base queue. - if ( - current !== null && - current.ref !== null && - typeof current.ref === "function" && - current.ref._stringRef === stringRef - ) { - return current.ref; + var _firstPendingUpdate = _lastPendingUpdate.next; + _lastPendingUpdate.next = null; + update = _firstPendingUpdate; + queue.lastBaseUpdate = _lastPendingUpdate; + queue.shared.pending = null; + } } + } while (true); - var ref = function (value) { - var refs = resolvedInst.refs; + if (newLastBaseUpdate === null) { + newBaseState = newState; + } - if (value === null) { - delete refs[stringRef]; - } else { - refs[stringRef] = value; - } - }; + queue.baseState = newBaseState; + queue.firstBaseUpdate = newFirstBaseUpdate; + queue.lastBaseUpdate = newLastBaseUpdate; - ref._stringRef = stringRef; - return ref; - } else { - if (typeof mixedRef !== "string") { - throw new Error( - "Expected ref to be a function, a string, an object returned by React.createRef(), or null." - ); - } + if (firstBaseUpdate === null) { + // `queue.lanes` is used for entangling transitions. We can set it back to + // zero once the queue is empty. + queue.shared.lanes = NoLanes; + } // Set the remaining expiration time to be whatever is remaining in the queue. + // This should be fine because the only two other things that contribute to + // expiration time are props and context. We're already in the middle of the + // begin phase by the time we start processing the queue, so we've already + // dealt with the props. Context in components that specify + // shouldComponentUpdate is tricky; but we'll have to account for + // that regardless. - if (!element._owner) { - throw new Error( - "Element ref was specified as a string (" + - mixedRef + - ") but no owner was set. This could happen for one of" + - " the following reasons:\n" + - "1. You may be adding a ref to a function component\n" + - "2. You may be adding a ref to a component that was not created inside a component's render method\n" + - "3. You have multiple copies of React loaded\n" + - "See https://reactjs.org/link/refs-must-have-owner for more information." - ); - } - } + markSkippedUpdateLanes(newLanes); + workInProgress.lanes = newLanes; + workInProgress.memoizedState = newState; } - return mixedRef; + { + currentlyProcessingQueue = null; + } } -function throwOnInvalidObjectType(returnFiber, newChild) { - // $FlowFixMe[method-unbinding] - var childString = Object.prototype.toString.call(newChild); - throw new Error( - "Objects are not valid as a React child (found: " + - (childString === "[object Object]" - ? "object with keys {" + Object.keys(newChild).join(", ") + "}" - : childString) + - "). " + - "If you meant to render a collection of children, use an array " + - "instead." - ); -} +function callCallback(callback, context) { + if (typeof callback !== "function") { + throw new Error( + "Invalid argument passed as callback. Expected a function. Instead " + + ("received: " + callback) + ); + } -function warnOnFunctionType(returnFiber) { - { - var componentName = getComponentNameFromFiber(returnFiber) || "Component"; + callback.call(context); +} - if (ownerHasFunctionTypeWarning[componentName]) { - return; - } +function resetHasForceUpdateBeforeProcessing() { + hasForceUpdate = false; +} +function checkHasForceUpdateAfterProcessing() { + return hasForceUpdate; +} +function deferHiddenCallbacks(updateQueue) { + // When an update finishes on a hidden component, its callback should not + // be fired until/unless the component is made visible again. Stash the + // callback on the shared queue object so it can be fired later. + var newHiddenCallbacks = updateQueue.callbacks; - ownerHasFunctionTypeWarning[componentName] = true; + if (newHiddenCallbacks !== null) { + var existingHiddenCallbacks = updateQueue.shared.hiddenCallbacks; - error( - "Functions are not valid as a React child. This may happen if " + - "you return a Component instead of from render. " + - "Or maybe you meant to call this function rather than return it." - ); + if (existingHiddenCallbacks === null) { + updateQueue.shared.hiddenCallbacks = newHiddenCallbacks; + } else { + updateQueue.shared.hiddenCallbacks = + existingHiddenCallbacks.concat(newHiddenCallbacks); + } } } +function commitHiddenCallbacks(updateQueue, context) { + // This component is switching from hidden -> visible. Commit any callbacks + // that were previously deferred. + var hiddenCallbacks = updateQueue.shared.hiddenCallbacks; -function resolveLazy(lazyType) { - var payload = lazyType._payload; - var init = lazyType._init; - return init(payload); -} // This wrapper function exists because I expect to clone the code in each path -// to be able to optimize each path individually by branching early. This needs -// a compiler or we can do it manually. Helpers that don't need this branching -// live outside of this function. + if (hiddenCallbacks !== null) { + updateQueue.shared.hiddenCallbacks = null; -function createChildReconciler(shouldTrackSideEffects) { - function deleteChild(returnFiber, childToDelete) { - if (!shouldTrackSideEffects) { - // Noop. - return; + for (var i = 0; i < hiddenCallbacks.length; i++) { + var callback = hiddenCallbacks[i]; + callCallback(callback, context); } + } +} +function commitCallbacks(updateQueue, context) { + var callbacks = updateQueue.callbacks; - var deletions = returnFiber.deletions; + if (callbacks !== null) { + updateQueue.callbacks = null; - if (deletions === null) { - returnFiber.deletions = [childToDelete]; - returnFiber.flags |= ChildDeletion; - } else { - deletions.push(childToDelete); + for (var i = 0; i < callbacks.length; i++) { + var callback = callbacks[i]; + callCallback(callback, context); } } +} - function deleteRemainingChildren(returnFiber, currentFirstChild) { - if (!shouldTrackSideEffects) { - // Noop. - return null; - } // TODO: For the shouldClone case, this could be micro-optimized a bit by - // assuming that after the first child we've already added everything. - - var childToDelete = currentFirstChild; +/** + * Performs equality by iterating through keys on an object and returning false + * when any key has values which are not strictly equal between the arguments. + * Returns true when the values of all keys are strictly equal. + */ - while (childToDelete !== null) { - deleteChild(returnFiber, childToDelete); - childToDelete = childToDelete.sibling; - } +function shallowEqual(objA, objB) { + if (objectIs(objA, objB)) { + return true; + } - return null; + if ( + typeof objA !== "object" || + objA === null || + typeof objB !== "object" || + objB === null + ) { + return false; } - function mapRemainingChildren(returnFiber, currentFirstChild) { - // Add the remaining children to a temporary map so that we can find them by - // keys quickly. Implicit (null) keys get added to this set with their index - // instead. - var existingChildren = new Map(); - var existingChild = currentFirstChild; + var keysA = Object.keys(objA); + var keysB = Object.keys(objB); - while (existingChild !== null) { - if (existingChild.key !== null) { - existingChildren.set(existingChild.key, existingChild); - } else { - existingChildren.set(existingChild.index, existingChild); - } + if (keysA.length !== keysB.length) { + return false; + } // Test for A's keys different from B. - existingChild = existingChild.sibling; - } + for (var i = 0; i < keysA.length; i++) { + var currentKey = keysA[i]; - return existingChildren; + if ( + !hasOwnProperty.call(objB, currentKey) || + !objectIs(objA[currentKey], objB[currentKey]) + ) { + return false; + } } - function useFiber(fiber, pendingProps) { - // We currently set sibling to null and index to 0 here because it is easy - // to forget to do before returning it. E.g. for the single child case. - var clone = createWorkInProgress(fiber, pendingProps); - clone.index = 0; - clone.sibling = null; - return clone; - } + return true; +} - function placeChild(newFiber, lastPlacedIndex, newIndex) { - newFiber.index = newIndex; +function describeFiber(fiber) { + var owner = fiber._debugOwner ? fiber._debugOwner.type : null; + var source = fiber._debugSource; - if (!shouldTrackSideEffects) { - // During hydration, the useId algorithm needs to know which fibers are - // part of a list of children (arrays, iterators). - newFiber.flags |= Forked; - return lastPlacedIndex; - } + switch (fiber.tag) { + case HostHoistable: + case HostSingleton: + case HostComponent: + return describeBuiltInComponentFrame(fiber.type, source, owner); - var current = newFiber.alternate; + case LazyComponent: + return describeBuiltInComponentFrame("Lazy", source, owner); - if (current !== null) { - var oldIndex = current.index; + case SuspenseComponent: + return describeBuiltInComponentFrame("Suspense", source, owner); - if (oldIndex < lastPlacedIndex) { - // This is a move. - newFiber.flags |= Placement | PlacementDEV; - return lastPlacedIndex; - } else { - // This item can stay in place. - return oldIndex; - } - } else { - // This is an insertion. - newFiber.flags |= Placement | PlacementDEV; - return lastPlacedIndex; - } - } + case SuspenseListComponent: + return describeBuiltInComponentFrame("SuspenseList", source, owner); - function placeSingleChild(newFiber) { - // This is simpler for the single child case. We only need to do a - // placement for inserting new children. - if (shouldTrackSideEffects && newFiber.alternate === null) { - newFiber.flags |= Placement | PlacementDEV; - } + case FunctionComponent: + case IndeterminateComponent: + case SimpleMemoComponent: + return describeFunctionComponentFrame(fiber.type, source, owner); - return newFiber; + case ForwardRef: + return describeFunctionComponentFrame(fiber.type.render, source, owner); + + case ClassComponent: + return describeClassComponentFrame(fiber.type, source, owner); + + default: + return ""; } +} - function updateTextNode(returnFiber, current, textContent, lanes) { - if (current === null || current.tag !== HostText) { - // Insert - var created = createFiberFromText(textContent, returnFiber.mode, lanes); - created.return = returnFiber; - return created; - } else { - // Update - var existing = useFiber(current, textContent); - existing.return = returnFiber; - return existing; - } - } - - function updateElement(returnFiber, current, element, lanes) { - var elementType = element.type; - - if (elementType === REACT_FRAGMENT_TYPE) { - return updateFragment( - returnFiber, - current, - element.props.children, - lanes, - element.key - ); - } - - if (current !== null) { - if ( - current.elementType === elementType || // Keep this check inline so it only runs on the false path: - isCompatibleFamilyForHotReloading(current, element) || // Lazy types should reconcile their resolved type. - // We need to do this after the Hot Reloading check above, - // because hot reloading has different semantics than prod because - // it doesn't resuspend. So we can't let the call below suspend. - (typeof elementType === "object" && - elementType !== null && - elementType.$$typeof === REACT_LAZY_TYPE && - resolveLazy(elementType) === current.type) - ) { - // Move based on index - var existing = useFiber(current, element.props); - existing.ref = coerceRef(returnFiber, current, element); - existing.return = returnFiber; +function getStackByFiberInDevAndProd(workInProgress) { + try { + var info = ""; + var node = workInProgress; - { - existing._debugSource = element._source; - existing._debugOwner = element._owner; - } + do { + info += describeFiber(node); // $FlowFixMe[incompatible-type] we bail out when we get a null - return existing; - } - } // Insert + node = node.return; + } while (node); - var created = createFiberFromElement(element, returnFiber.mode, lanes); - created.ref = coerceRef(returnFiber, current, element); - created.return = returnFiber; - return created; + return info; + } catch (x) { + return "\nError generating stack: " + x.message + "\n" + x.stack; } +} - function updatePortal(returnFiber, current, portal, lanes) { - if ( - current === null || - current.tag !== HostPortal || - current.stateNode.containerInfo !== portal.containerInfo || - current.stateNode.implementation !== portal.implementation - ) { - // Insert - var created = createFiberFromPortal(portal, returnFiber.mode, lanes); - created.return = returnFiber; - return created; - } else { - // Update - var existing = useFiber(current, portal.children || []); - existing.return = returnFiber; - return existing; +var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; +var current = null; +var isRendering = false; +function getCurrentFiberOwnerNameInDevOrNull() { + { + if (current === null) { + return null; } - } - function updateFragment(returnFiber, current, fragment, lanes, key) { - if (current === null || current.tag !== Fragment) { - // Insert - var created = createFiberFromFragment( - fragment, - returnFiber.mode, - lanes, - key - ); - created.return = returnFiber; - return created; - } else { - // Update - var existing = useFiber(current, fragment); - existing.return = returnFiber; - return existing; - } - } + var owner = current._debugOwner; - function createChild(returnFiber, newChild, lanes) { - if ( - (typeof newChild === "string" && newChild !== "") || - typeof newChild === "number" - ) { - // Text nodes don't have keys. If the previous node is implicitly keyed - // we can continue to replace it without aborting even if it is not a text - // node. - var created = createFiberFromText("" + newChild, returnFiber.mode, lanes); - created.return = returnFiber; - return created; + if (owner !== null && typeof owner !== "undefined") { + return getComponentNameFromFiber(owner); } + } - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: { - var _created = createFiberFromElement( - newChild, - returnFiber.mode, - lanes - ); - - _created.ref = coerceRef(returnFiber, null, newChild); - _created.return = returnFiber; - return _created; - } - - case REACT_PORTAL_TYPE: { - var _created2 = createFiberFromPortal( - newChild, - returnFiber.mode, - lanes - ); + return null; +} - _created2.return = returnFiber; - return _created2; - } +function getCurrentFiberStackInDev() { + { + if (current === null) { + return ""; + } // Safe because if current fiber exists, we are reconciling, + // and it is guaranteed to be the work-in-progress version. - case REACT_LAZY_TYPE: { - var payload = newChild._payload; - var init = newChild._init; - return createChild(returnFiber, init(payload), lanes); - } - } + return getStackByFiberInDevAndProd(current); + } +} - if (isArray(newChild) || getIteratorFn(newChild)) { - var _created3 = createFiberFromFragment( - newChild, - returnFiber.mode, - lanes, - null - ); +function resetCurrentFiber() { + { + ReactDebugCurrentFrame.getCurrentStack = null; + current = null; + isRendering = false; + } +} +function setCurrentFiber(fiber) { + { + ReactDebugCurrentFrame.getCurrentStack = + fiber === null ? null : getCurrentFiberStackInDev; + current = fiber; + isRendering = false; + } +} +function getCurrentFiber() { + { + return current; + } +} +function setIsRendering(rendering) { + { + isRendering = rendering; + } +} - _created3.return = returnFiber; - return _created3; - } // Usable node types - // - // Unwrap the inner value and recursively call this function again. +var ReactStrictModeWarnings = { + recordUnsafeLifecycleWarnings: function (fiber, instance) {}, + flushPendingUnsafeLifecycleWarnings: function () {}, + recordLegacyContextWarning: function (fiber, instance) {}, + flushLegacyContextWarning: function () {}, + discardPendingWarnings: function () {} +}; - if (typeof newChild.then === "function") { - var thenable = newChild; - return createChild(returnFiber, unwrapThenable(thenable), lanes); - } +{ + var findStrictRoot = function (fiber) { + var maybeStrictRoot = null; + var node = fiber; - if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) { - var context = newChild; - return createChild( - returnFiber, - readContextDuringReconcilation(returnFiber, context, lanes), - lanes - ); + while (node !== null) { + if (node.mode & StrictLegacyMode) { + maybeStrictRoot = node; } - throwOnInvalidObjectType(returnFiber, newChild); + node = node.return; } - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber); - } - } + return maybeStrictRoot; + }; - return null; - } + var setToSortedString = function (set) { + var array = []; + set.forEach(function (value) { + array.push(value); + }); + return array.sort().join(", "); + }; - function updateSlot(returnFiber, oldFiber, newChild, lanes) { - // Update the fiber if the keys match, otherwise return null. - var key = oldFiber !== null ? oldFiber.key : null; + var pendingComponentWillMountWarnings = []; + var pendingUNSAFE_ComponentWillMountWarnings = []; + var pendingComponentWillReceivePropsWarnings = []; + var pendingUNSAFE_ComponentWillReceivePropsWarnings = []; + var pendingComponentWillUpdateWarnings = []; + var pendingUNSAFE_ComponentWillUpdateWarnings = []; // Tracks components we have already warned about. - if ( - (typeof newChild === "string" && newChild !== "") || - typeof newChild === "number" - ) { - // Text nodes don't have keys. If the previous node is implicitly keyed - // we can continue to replace it without aborting even if it is not a text - // node. - if (key !== null) { - return null; - } + var didWarnAboutUnsafeLifecycles = new Set(); - return updateTextNode(returnFiber, oldFiber, "" + newChild, lanes); + ReactStrictModeWarnings.recordUnsafeLifecycleWarnings = function ( + fiber, + instance + ) { + // Dedupe strategy: Warn once per component. + if (didWarnAboutUnsafeLifecycles.has(fiber.type)) { + return; } - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: { - if (newChild.key === key) { - return updateElement(returnFiber, oldFiber, newChild, lanes); - } else { - return null; - } - } - - case REACT_PORTAL_TYPE: { - if (newChild.key === key) { - return updatePortal(returnFiber, oldFiber, newChild, lanes); - } else { - return null; - } - } - - case REACT_LAZY_TYPE: { - var payload = newChild._payload; - var init = newChild._init; - return updateSlot(returnFiber, oldFiber, init(payload), lanes); - } - } - - if (isArray(newChild) || getIteratorFn(newChild)) { - if (key !== null) { - return null; - } - - return updateFragment(returnFiber, oldFiber, newChild, lanes, null); - } // Usable node types - // - // Unwrap the inner value and recursively call this function again. - - if (typeof newChild.then === "function") { - var thenable = newChild; - return updateSlot( - returnFiber, - oldFiber, - unwrapThenable(thenable), - lanes - ); - } - - if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) { - var context = newChild; - return updateSlot( - returnFiber, - oldFiber, - readContextDuringReconcilation(returnFiber, context, lanes), - lanes - ); - } + if ( + typeof instance.componentWillMount === "function" && // Don't warn about react-lifecycles-compat polyfilled components. + instance.componentWillMount.__suppressDeprecationWarning !== true + ) { + pendingComponentWillMountWarnings.push(fiber); + } - throwOnInvalidObjectType(returnFiber, newChild); + if ( + fiber.mode & StrictLegacyMode && + typeof instance.UNSAFE_componentWillMount === "function" + ) { + pendingUNSAFE_ComponentWillMountWarnings.push(fiber); } - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber); - } + if ( + typeof instance.componentWillReceiveProps === "function" && + instance.componentWillReceiveProps.__suppressDeprecationWarning !== true + ) { + pendingComponentWillReceivePropsWarnings.push(fiber); } - return null; - } + if ( + fiber.mode & StrictLegacyMode && + typeof instance.UNSAFE_componentWillReceiveProps === "function" + ) { + pendingUNSAFE_ComponentWillReceivePropsWarnings.push(fiber); + } - function updateFromMap( - existingChildren, - returnFiber, - newIdx, - newChild, - lanes - ) { if ( - (typeof newChild === "string" && newChild !== "") || - typeof newChild === "number" + typeof instance.componentWillUpdate === "function" && + instance.componentWillUpdate.__suppressDeprecationWarning !== true ) { - // Text nodes don't have keys, so we neither have to check the old nor - // new node for the key. If both are text nodes, they match. - var matchedFiber = existingChildren.get(newIdx) || null; - return updateTextNode(returnFiber, matchedFiber, "" + newChild, lanes); + pendingComponentWillUpdateWarnings.push(fiber); } - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: { - var _matchedFiber = - existingChildren.get( - newChild.key === null ? newIdx : newChild.key - ) || null; + if ( + fiber.mode & StrictLegacyMode && + typeof instance.UNSAFE_componentWillUpdate === "function" + ) { + pendingUNSAFE_ComponentWillUpdateWarnings.push(fiber); + } + }; - return updateElement(returnFiber, _matchedFiber, newChild, lanes); - } + ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = function () { + // We do an initial pass to gather component names + var componentWillMountUniqueNames = new Set(); - case REACT_PORTAL_TYPE: { - var _matchedFiber2 = - existingChildren.get( - newChild.key === null ? newIdx : newChild.key - ) || null; + if (pendingComponentWillMountWarnings.length > 0) { + pendingComponentWillMountWarnings.forEach(function (fiber) { + componentWillMountUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingComponentWillMountWarnings = []; + } - return updatePortal(returnFiber, _matchedFiber2, newChild, lanes); - } + var UNSAFE_componentWillMountUniqueNames = new Set(); - case REACT_LAZY_TYPE: - var payload = newChild._payload; - var init = newChild._init; - return updateFromMap( - existingChildren, - returnFiber, - newIdx, - init(payload), - lanes - ); - } + if (pendingUNSAFE_ComponentWillMountWarnings.length > 0) { + pendingUNSAFE_ComponentWillMountWarnings.forEach(function (fiber) { + UNSAFE_componentWillMountUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingUNSAFE_ComponentWillMountWarnings = []; + } - if (isArray(newChild) || getIteratorFn(newChild)) { - var _matchedFiber3 = existingChildren.get(newIdx) || null; + var componentWillReceivePropsUniqueNames = new Set(); - return updateFragment( - returnFiber, - _matchedFiber3, - newChild, - lanes, - null + if (pendingComponentWillReceivePropsWarnings.length > 0) { + pendingComponentWillReceivePropsWarnings.forEach(function (fiber) { + componentWillReceivePropsUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" ); - } // Usable node types - // - // Unwrap the inner value and recursively call this function again. + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingComponentWillReceivePropsWarnings = []; + } - if (typeof newChild.then === "function") { - var thenable = newChild; - return updateFromMap( - existingChildren, - returnFiber, - newIdx, - unwrapThenable(thenable), - lanes - ); - } + var UNSAFE_componentWillReceivePropsUniqueNames = new Set(); - if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) { - var context = newChild; - return updateFromMap( - existingChildren, - returnFiber, - newIdx, - readContextDuringReconcilation(returnFiber, context, lanes), - lanes + if (pendingUNSAFE_ComponentWillReceivePropsWarnings.length > 0) { + pendingUNSAFE_ComponentWillReceivePropsWarnings.forEach(function (fiber) { + UNSAFE_componentWillReceivePropsUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" ); - } - - throwOnInvalidObjectType(returnFiber, newChild); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingUNSAFE_ComponentWillReceivePropsWarnings = []; } - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber); - } - } + var componentWillUpdateUniqueNames = new Set(); - return null; - } - /** - * Warns if there is a duplicate or missing key - */ + if (pendingComponentWillUpdateWarnings.length > 0) { + pendingComponentWillUpdateWarnings.forEach(function (fiber) { + componentWillUpdateUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingComponentWillUpdateWarnings = []; + } - function warnOnInvalidKey(child, knownKeys, returnFiber) { - { - if (typeof child !== "object" || child === null) { - return knownKeys; - } + var UNSAFE_componentWillUpdateUniqueNames = new Set(); - switch (child.$$typeof) { - case REACT_ELEMENT_TYPE: - case REACT_PORTAL_TYPE: - warnForMissingKey(child, returnFiber); - var key = child.key; + if (pendingUNSAFE_ComponentWillUpdateWarnings.length > 0) { + pendingUNSAFE_ComponentWillUpdateWarnings.forEach(function (fiber) { + UNSAFE_componentWillUpdateUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingUNSAFE_ComponentWillUpdateWarnings = []; + } // Finally, we flush all the warnings + // UNSAFE_ ones before the deprecated ones, since they'll be 'louder' - if (typeof key !== "string") { - break; - } + if (UNSAFE_componentWillMountUniqueNames.size > 0) { + var sortedNames = setToSortedString(UNSAFE_componentWillMountUniqueNames); - if (knownKeys === null) { - knownKeys = new Set(); - knownKeys.add(key); - break; - } + error( + "Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code. " + + "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + + "* Move code with side effects to componentDidMount, and set initial state in the constructor.\n" + + "\nPlease update the following components: %s", + sortedNames + ); + } - if (!knownKeys.has(key)) { - knownKeys.add(key); - break; - } + if (UNSAFE_componentWillReceivePropsUniqueNames.size > 0) { + var _sortedNames = setToSortedString( + UNSAFE_componentWillReceivePropsUniqueNames + ); - error( - "Encountered two children with the same key, `%s`. " + - "Keys should be unique so that components maintain their identity " + - "across updates. Non-unique keys may cause children to be " + - "duplicated and/or omitted — the behavior is unsupported and " + - "could change in a future version.", - key - ); + error( + "Using UNSAFE_componentWillReceiveProps in strict mode is not recommended " + + "and may indicate bugs in your code. " + + "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + + "* Move data fetching code or side effects to componentDidUpdate.\n" + + "* If you're updating state whenever props change, " + + "refactor your code to use memoization techniques or move it to " + + "static getDerivedStateFromProps. Learn more at: https://reactjs.org/link/derived-state\n" + + "\nPlease update the following components: %s", + _sortedNames + ); + } - break; + if (UNSAFE_componentWillUpdateUniqueNames.size > 0) { + var _sortedNames2 = setToSortedString( + UNSAFE_componentWillUpdateUniqueNames + ); - case REACT_LAZY_TYPE: - var payload = child._payload; - var init = child._init; - warnOnInvalidKey(init(payload), knownKeys, returnFiber); - break; - } + error( + "Using UNSAFE_componentWillUpdate in strict mode is not recommended " + + "and may indicate bugs in your code. " + + "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + + "* Move data fetching code or side effects to componentDidUpdate.\n" + + "\nPlease update the following components: %s", + _sortedNames2 + ); } - return knownKeys; - } - - function reconcileChildrenArray( - returnFiber, - currentFirstChild, - newChildren, - lanes - ) { - // This algorithm can't optimize by searching from both ends since we - // don't have backpointers on fibers. I'm trying to see how far we can get - // with that model. If it ends up not being worth the tradeoffs, we can - // add it later. - // Even with a two ended optimization, we'd want to optimize for the case - // where there are few changes and brute force the comparison instead of - // going for the Map. It'd like to explore hitting that path first in - // forward-only mode and only go for the Map once we notice that we need - // lots of look ahead. This doesn't handle reversal as well as two ended - // search but that's unusual. Besides, for the two ended optimization to - // work on Iterables, we'd need to copy the whole set. - // In this first iteration, we'll just live with hitting the bad case - // (adding everything to a Map) in for every insert/move. - // If you change this code, also update reconcileChildrenIterator() which - // uses the same algorithm. - { - // First, validate keys. - var knownKeys = null; + if (componentWillMountUniqueNames.size > 0) { + var _sortedNames3 = setToSortedString(componentWillMountUniqueNames); - for (var i = 0; i < newChildren.length; i++) { - var child = newChildren[i]; - knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber); - } + warn( + "componentWillMount has been renamed, and is not recommended for use. " + + "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + + "* Move code with side effects to componentDidMount, and set initial state in the constructor.\n" + + "* Rename componentWillMount to UNSAFE_componentWillMount to suppress " + + "this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. " + + "To rename all deprecated lifecycles to their new names, you can run " + + "`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n" + + "\nPlease update the following components: %s", + _sortedNames3 + ); } - var resultingFirstChild = null; - var previousNewFiber = null; - var oldFiber = currentFirstChild; - var lastPlacedIndex = 0; - var newIdx = 0; - var nextOldFiber = null; - - for (; oldFiber !== null && newIdx < newChildren.length; newIdx++) { - if (oldFiber.index > newIdx) { - nextOldFiber = oldFiber; - oldFiber = null; - } else { - nextOldFiber = oldFiber.sibling; - } + if (componentWillReceivePropsUniqueNames.size > 0) { + var _sortedNames4 = setToSortedString( + componentWillReceivePropsUniqueNames + ); - var newFiber = updateSlot( - returnFiber, - oldFiber, - newChildren[newIdx], - lanes + warn( + "componentWillReceiveProps has been renamed, and is not recommended for use. " + + "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + + "* Move data fetching code or side effects to componentDidUpdate.\n" + + "* If you're updating state whenever props change, refactor your " + + "code to use memoization techniques or move it to " + + "static getDerivedStateFromProps. Learn more at: https://reactjs.org/link/derived-state\n" + + "* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress " + + "this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. " + + "To rename all deprecated lifecycles to their new names, you can run " + + "`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n" + + "\nPlease update the following components: %s", + _sortedNames4 ); + } - if (newFiber === null) { - // TODO: This breaks on empty slots like null children. That's - // unfortunate because it triggers the slow path all the time. We need - // a better way to communicate whether this was a miss or null, - // boolean, undefined, etc. - if (oldFiber === null) { - oldFiber = nextOldFiber; - } + if (componentWillUpdateUniqueNames.size > 0) { + var _sortedNames5 = setToSortedString(componentWillUpdateUniqueNames); - break; - } + warn( + "componentWillUpdate has been renamed, and is not recommended for use. " + + "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + + "* Move data fetching code or side effects to componentDidUpdate.\n" + + "* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress " + + "this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. " + + "To rename all deprecated lifecycles to their new names, you can run " + + "`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n" + + "\nPlease update the following components: %s", + _sortedNames5 + ); + } + }; - if (shouldTrackSideEffects) { - if (oldFiber && newFiber.alternate === null) { - // We matched the slot, but we didn't reuse the existing fiber, so we - // need to delete the existing child. - deleteChild(returnFiber, oldFiber); - } - } + var pendingLegacyContextWarning = new Map(); // Tracks components we have already warned about. - lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); + var didWarnAboutLegacyContext = new Set(); - if (previousNewFiber === null) { - // TODO: Move out of the loop. This only happens for the first run. - resultingFirstChild = newFiber; - } else { - // TODO: Defer siblings if we're not at the right index for this slot. - // I.e. if we had null values before, then we want to defer this - // for each null value. However, we also don't want to call updateSlot - // with the previous one. - previousNewFiber.sibling = newFiber; - } + ReactStrictModeWarnings.recordLegacyContextWarning = function ( + fiber, + instance + ) { + var strictRoot = findStrictRoot(fiber); - previousNewFiber = newFiber; - oldFiber = nextOldFiber; - } + if (strictRoot === null) { + error( + "Expected to find a StrictMode component in a strict mode tree. " + + "This error is likely caused by a bug in React. Please file an issue." + ); - if (newIdx === newChildren.length) { - // We've reached the end of the new children. We can delete the rest. - deleteRemainingChildren(returnFiber, oldFiber); + return; + } // Dedup strategy: Warn once per component. - return resultingFirstChild; + if (didWarnAboutLegacyContext.has(fiber.type)) { + return; } - if (oldFiber === null) { - // If we don't have any more existing children we can choose a fast path - // since the rest will all be insertions. - for (; newIdx < newChildren.length; newIdx++) { - var _newFiber = createChild(returnFiber, newChildren[newIdx], lanes); - - if (_newFiber === null) { - continue; - } - - lastPlacedIndex = placeChild(_newFiber, lastPlacedIndex, newIdx); - - if (previousNewFiber === null) { - // TODO: Move out of the loop. This only happens for the first run. - resultingFirstChild = _newFiber; - } else { - previousNewFiber.sibling = _newFiber; - } + var warningsForRoot = pendingLegacyContextWarning.get(strictRoot); - previousNewFiber = _newFiber; + if ( + fiber.type.contextTypes != null || + fiber.type.childContextTypes != null || + (instance !== null && typeof instance.getChildContext === "function") + ) { + if (warningsForRoot === undefined) { + warningsForRoot = []; + pendingLegacyContextWarning.set(strictRoot, warningsForRoot); } - return resultingFirstChild; - } // Add all children to a key map for quick lookups. - - var existingChildren = mapRemainingChildren(returnFiber, oldFiber); // Keep scanning and use the map to restore deleted items as moves. - - for (; newIdx < newChildren.length; newIdx++) { - var _newFiber2 = updateFromMap( - existingChildren, - returnFiber, - newIdx, - newChildren[newIdx], - lanes - ); + warningsForRoot.push(fiber); + } + }; - if (_newFiber2 !== null) { - if (shouldTrackSideEffects) { - if (_newFiber2.alternate !== null) { - // The new fiber is a work in progress, but if there exists a - // current, that means that we reused the fiber. We need to delete - // it from the child list so that we don't add it to the deletion - // list. - existingChildren.delete( - _newFiber2.key === null ? newIdx : _newFiber2.key - ); - } - } + ReactStrictModeWarnings.flushLegacyContextWarning = function () { + pendingLegacyContextWarning.forEach(function (fiberArray, strictRoot) { + if (fiberArray.length === 0) { + return; + } - lastPlacedIndex = placeChild(_newFiber2, lastPlacedIndex, newIdx); + var firstFiber = fiberArray[0]; + var uniqueNames = new Set(); + fiberArray.forEach(function (fiber) { + uniqueNames.add(getComponentNameFromFiber(fiber) || "Component"); + didWarnAboutLegacyContext.add(fiber.type); + }); + var sortedNames = setToSortedString(uniqueNames); - if (previousNewFiber === null) { - resultingFirstChild = _newFiber2; - } else { - previousNewFiber.sibling = _newFiber2; - } + try { + setCurrentFiber(firstFiber); - previousNewFiber = _newFiber2; + error( + "Legacy context API has been detected within a strict-mode tree." + + "\n\nThe old API will be supported in all 16.x releases, but applications " + + "using it should migrate to the new version." + + "\n\nPlease update the following components: %s" + + "\n\nLearn more about this warning here: https://reactjs.org/link/legacy-context", + sortedNames + ); + } finally { + resetCurrentFiber(); } - } + }); + }; - if (shouldTrackSideEffects) { - // Any existing children that weren't consumed above were deleted. We need - // to add them to the deletion list. - existingChildren.forEach(function (child) { - return deleteChild(returnFiber, child); - }); - } + ReactStrictModeWarnings.discardPendingWarnings = function () { + pendingComponentWillMountWarnings = []; + pendingUNSAFE_ComponentWillMountWarnings = []; + pendingComponentWillReceivePropsWarnings = []; + pendingUNSAFE_ComponentWillReceivePropsWarnings = []; + pendingComponentWillUpdateWarnings = []; + pendingUNSAFE_ComponentWillUpdateWarnings = []; + pendingLegacyContextWarning = new Map(); + }; +} - return resultingFirstChild; +/* + * The `'' + value` pattern (used in perf-sensitive code) throws for Symbol + * and Temporal.* types. See https://github.com/facebook/react/pull/22064. + * + * The functions in this module will throw an easier-to-understand, + * easier-to-debug exception with a clear errors message message explaining the + * problem. (Instead of a confusing exception thrown inside the implementation + * of the `value` object). + */ +// $FlowFixMe only called in DEV, so void return is not possible. +function typeName(value) { + { + // toStringTag is needed for namespaced types like Temporal.Instant + var hasToStringTag = typeof Symbol === "function" && Symbol.toStringTag; + var type = + (hasToStringTag && value[Symbol.toStringTag]) || + value.constructor.name || + "Object"; // $FlowFixMe + + return type; } +} // $FlowFixMe only called in DEV, so void return is not possible. - function reconcileChildrenIterator( - returnFiber, - currentFirstChild, - newChildrenIterable, - lanes - ) { - // This is the same implementation as reconcileChildrenArray(), - // but using the iterator instead. - var iteratorFn = getIteratorFn(newChildrenIterable); +function willCoercionThrow(value) { + { + try { + testStringCoercion(value); + return false; + } catch (e) { + return true; + } + } +} - if (typeof iteratorFn !== "function") { - throw new Error( - "An object is not an iterable. This error is likely caused by a bug in " + - "React. Please file an issue." +function testStringCoercion(value) { + // If you ended up here by following an exception call stack, here's what's + // happened: you supplied an object or symbol value to React (as a prop, key, + // DOM attribute, CSS property, string ref, etc.) and when React tried to + // coerce it to a string using `'' + value`, an exception was thrown. + // + // The most common types that will cause this exception are `Symbol` instances + // and Temporal objects like `Temporal.Instant`. But any object that has a + // `valueOf` or `[Symbol.toPrimitive]` method that throws will also cause this + // exception. (Library authors do this to prevent users from using built-in + // numeric operators like `+` or comparison operators like `>=` because custom + // methods are needed to perform accurate arithmetic or comparison.) + // + // To fix the problem, coerce this object or symbol value to a string before + // passing it to React. The most reliable way is usually `String(value)`. + // + // To find which value is throwing, check the browser or debugger console. + // Before this exception was thrown, there should be `console.error` output + // that shows the type (Symbol, Temporal.PlainDate, etc.) that caused the + // problem and how that type was used: key, atrribute, input value prop, etc. + // In most cases, this console output also shows the component and its + // ancestor components where the exception happened. + // + // eslint-disable-next-line react-internal/safe-string-coercion + return "" + value; +} +function checkKeyStringCoercion(value) { + { + if (willCoercionThrow(value)) { + error( + "The provided key is an unsupported type %s." + + " This value must be coerced to a string before before using it here.", + typeName(value) ); + + return testStringCoercion(value); // throw (to help callers find troubleshooting comments) } + } +} +function checkPropStringCoercion(value, propName) { + { + if (willCoercionThrow(value)) { + error( + "The provided `%s` prop is an unsupported type %s." + + " This value must be coerced to a string before before using it here.", + propName, + typeName(value) + ); - { - // We don't support rendering Generators because it's a mutation. - // See https://github.com/facebook/react/issues/12995 - if ( - typeof Symbol === "function" && // $FlowFixMe Flow doesn't know about toStringTag - newChildrenIterable[Symbol.toStringTag] === "Generator" - ) { - if (!didWarnAboutGenerators) { - error( - "Using Generators as children is unsupported and will likely yield " + - "unexpected results because enumerating a generator mutates it. " + - "You may convert it to an array with `Array.from()` or the " + - "`[...spread]` operator before rendering. Keep in mind " + - "you might need to polyfill these features for older browsers." - ); - } + return testStringCoercion(value); // throw (to help callers find troubleshooting comments) + } + } +} - didWarnAboutGenerators = true; - } // Warn about using Maps as children +var ReactCurrentActQueue$2 = ReactSharedInternals.ReactCurrentActQueue; // An error that is thrown (e.g. by `use`) to trigger Suspense. If we +// detect this is caught by userspace, we'll log a warning in development. - if (newChildrenIterable.entries === iteratorFn) { - if (!didWarnAboutMaps) { - error( - "Using Maps as children is not supported. " + - "Use an array of keyed ReactElements instead." - ); - } +var SuspenseException = new Error( + "Suspense Exception: This is not a real error! It's an implementation " + + "detail of `use` to interrupt the current render. You must either " + + "rethrow it immediately, or move the `use` call outside of the " + + "`try/catch` block. Capturing without rethrowing will lead to " + + "unexpected behavior.\n\n" + + "To handle async errors, wrap your component in an error boundary, or " + + "call the promise's `.catch` method and pass the result to `use`" +); +var SuspenseyCommitException = new Error( + "Suspense Exception: This is not a real error, and should not leak into " + + "userspace. If you're seeing this, it's likely a bug in React." +); // This is a noop thenable that we use to trigger a fallback in throwException. +// TODO: It would be better to refactor throwException into multiple functions +// so we can trigger a fallback directly without having to check the type. But +// for now this will do. - didWarnAboutMaps = true; - } // First, validate keys. - // We'll get a different iterator later for the main pass. +var noopSuspenseyCommitThenable = { + then: function () {} +}; +function createThenableState() { + // The ThenableState is created the first time a component suspends. If it + // suspends again, we'll reuse the same state. + return []; +} +function isThenableResolved(thenable) { + var status = thenable.status; + return status === "fulfilled" || status === "rejected"; +} - var _newChildren = iteratorFn.call(newChildrenIterable); +function noop() {} - if (_newChildren) { - var knownKeys = null; +function trackUsedThenable(thenableState, thenable, index) { + if (ReactCurrentActQueue$2.current !== null) { + ReactCurrentActQueue$2.didUsePromise = true; + } - var _step = _newChildren.next(); + var previous = thenableState[index]; - for (; !_step.done; _step = _newChildren.next()) { - var child = _step.value; - knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber); - } - } + if (previous === undefined) { + thenableState.push(thenable); + } else { + if (previous !== thenable) { + // Reuse the previous thenable, and drop the new one. We can assume + // they represent the same value, because components are idempotent. + // Avoid an unhandled rejection errors for the Promises that we'll + // intentionally ignore. + thenable.then(noop, noop); + thenable = previous; } - - var newChildren = iteratorFn.call(newChildrenIterable); - - if (newChildren == null) { - throw new Error("An iterable object provided no iterator."); + } // We use an expando to track the status and result of a thenable so that we + // can synchronously unwrap the value. Think of this as an extension of the + // Promise API, or a custom interface that is a superset of Thenable. + // + // If the thenable doesn't have a status, set it to "pending" and attach + // a listener that will update its status and result when it resolves. + + switch (thenable.status) { + case "fulfilled": { + var fulfilledValue = thenable.value; + return fulfilledValue; } - var resultingFirstChild = null; - var previousNewFiber = null; - var oldFiber = currentFirstChild; - var lastPlacedIndex = 0; - var newIdx = 0; - var nextOldFiber = null; - var step = newChildren.next(); + case "rejected": { + var rejectedError = thenable.reason; + throw rejectedError; + } - for ( - ; - oldFiber !== null && !step.done; - newIdx++, step = newChildren.next() - ) { - if (oldFiber.index > newIdx) { - nextOldFiber = oldFiber; - oldFiber = null; + default: { + if (typeof thenable.status === "string") { + // Only instrument the thenable if the status if not defined. If + // it's defined, but an unknown value, assume it's been instrumented by + // some custom userspace implementation. We treat it as "pending". + // Attach a dummy listener, to ensure that any lazy initialization can + // happen. Flight lazily parses JSON when the value is actually awaited. + thenable.then(noop, noop); } else { - nextOldFiber = oldFiber.sibling; - } - - var newFiber = updateSlot(returnFiber, oldFiber, step.value, lanes); + var pendingThenable = thenable; + pendingThenable.status = "pending"; + pendingThenable.then( + function (fulfilledValue) { + if (thenable.status === "pending") { + var fulfilledThenable = thenable; + fulfilledThenable.status = "fulfilled"; + fulfilledThenable.value = fulfilledValue; + } + }, + function (error) { + if (thenable.status === "pending") { + var rejectedThenable = thenable; + rejectedThenable.status = "rejected"; + rejectedThenable.reason = error; + } + } + ); + } // Check one more time in case the thenable resolved synchronously. - if (newFiber === null) { - // TODO: This breaks on empty slots like null children. That's - // unfortunate because it triggers the slow path all the time. We need - // a better way to communicate whether this was a miss or null, - // boolean, undefined, etc. - if (oldFiber === null) { - oldFiber = nextOldFiber; + switch (thenable.status) { + case "fulfilled": { + var fulfilledThenable = thenable; + return fulfilledThenable.value; } - break; - } - - if (shouldTrackSideEffects) { - if (oldFiber && newFiber.alternate === null) { - // We matched the slot, but we didn't reuse the existing fiber, so we - // need to delete the existing child. - deleteChild(returnFiber, oldFiber); + case "rejected": { + var rejectedThenable = thenable; + throw rejectedThenable.reason; } - } + } // Suspend. + // + // Throwing here is an implementation detail that allows us to unwind the + // call stack. But we shouldn't allow it to leak into userspace. Throw an + // opaque placeholder value instead of the actual thenable. If it doesn't + // get captured by the work loop, log a warning, because that means + // something in userspace must have caught it. - lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); + suspendedThenable = thenable; - if (previousNewFiber === null) { - // TODO: Move out of the loop. This only happens for the first run. - resultingFirstChild = newFiber; - } else { - // TODO: Defer siblings if we're not at the right index for this slot. - // I.e. if we had null values before, then we want to defer this - // for each null value. However, we also don't want to call updateSlot - // with the previous one. - previousNewFiber.sibling = newFiber; + { + needsToResetSuspendedThenableDEV = true; } - previousNewFiber = newFiber; - oldFiber = nextOldFiber; + throw SuspenseException; } + } +} +// passed to the rest of the Suspense implementation — which, for historical +// reasons, expects to receive a thenable. - if (step.done) { - // We've reached the end of the new children. We can delete the rest. - deleteRemainingChildren(returnFiber, oldFiber); +var suspendedThenable = null; +var needsToResetSuspendedThenableDEV = false; +function getSuspendedThenable() { + // This is called right after `use` suspends by throwing an exception. `use` + // throws an opaque value instead of the thenable itself so that it can't be + // caught in userspace. Then the work loop accesses the actual thenable using + // this function. + if (suspendedThenable === null) { + throw new Error( + "Expected a suspended thenable. This is a bug in React. Please file " + + "an issue." + ); + } - return resultingFirstChild; + var thenable = suspendedThenable; + suspendedThenable = null; + + { + needsToResetSuspendedThenableDEV = false; + } + + return thenable; +} +function checkIfUseWrappedInTryCatch() { + { + // This was set right before SuspenseException was thrown, and it should + // have been cleared when the exception was handled. If it wasn't, + // it must have been caught by userspace. + if (needsToResetSuspendedThenableDEV) { + needsToResetSuspendedThenableDEV = false; + return true; } + } - if (oldFiber === null) { - // If we don't have any more existing children we can choose a fast path - // since the rest will all be insertions. - for (; !step.done; newIdx++, step = newChildren.next()) { - var _newFiber3 = createChild(returnFiber, step.value, lanes); + return false; +} - if (_newFiber3 === null) { - continue; - } +var thenableState$1 = null; +var thenableIndexCounter$1 = 0; +var didWarnAboutMaps; +var didWarnAboutGenerators; +var didWarnAboutStringRefs; +var ownerHasKeyUseWarning; +var ownerHasFunctionTypeWarning; - lastPlacedIndex = placeChild(_newFiber3, lastPlacedIndex, newIdx); +var warnForMissingKey = function (child, returnFiber) {}; - if (previousNewFiber === null) { - // TODO: Move out of the loop. This only happens for the first run. - resultingFirstChild = _newFiber3; - } else { - previousNewFiber.sibling = _newFiber3; - } +{ + didWarnAboutMaps = false; + didWarnAboutGenerators = false; + didWarnAboutStringRefs = {}; + /** + * Warn if there's no key explicitly set on dynamic arrays of children or + * object keys are not valid. This allows us to keep track of children between + * updates. + */ - previousNewFiber = _newFiber3; - } + ownerHasKeyUseWarning = {}; + ownerHasFunctionTypeWarning = {}; - return resultingFirstChild; - } // Add all children to a key map for quick lookups. + warnForMissingKey = function (child, returnFiber) { + if (child === null || typeof child !== "object") { + return; + } - var existingChildren = mapRemainingChildren(returnFiber, oldFiber); // Keep scanning and use the map to restore deleted items as moves. + if (!child._store || child._store.validated || child.key != null) { + return; + } - for (; !step.done; newIdx++, step = newChildren.next()) { - var _newFiber4 = updateFromMap( - existingChildren, - returnFiber, - newIdx, - step.value, - lanes + if (typeof child._store !== "object") { + throw new Error( + "React Component in warnForMissingKey should have a _store. " + + "This error is likely caused by a bug in React. Please file an issue." ); + } // $FlowFixMe unable to narrow type from mixed to writable object - if (_newFiber4 !== null) { - if (shouldTrackSideEffects) { - if (_newFiber4.alternate !== null) { - // The new fiber is a work in progress, but if there exists a - // current, that means that we reused the fiber. We need to delete - // it from the child list so that we don't add it to the deletion - // list. - existingChildren.delete( - _newFiber4.key === null ? newIdx : _newFiber4.key - ); - } - } + child._store.validated = true; + var componentName = getComponentNameFromFiber(returnFiber) || "Component"; - lastPlacedIndex = placeChild(_newFiber4, lastPlacedIndex, newIdx); + if (ownerHasKeyUseWarning[componentName]) { + return; + } - if (previousNewFiber === null) { - resultingFirstChild = _newFiber4; - } else { - previousNewFiber.sibling = _newFiber4; - } + ownerHasKeyUseWarning[componentName] = true; - previousNewFiber = _newFiber4; - } - } + error( + "Each child in a list should have a unique " + + '"key" prop. See https://reactjs.org/link/warning-keys for ' + + "more information." + ); + }; +} - if (shouldTrackSideEffects) { - // Any existing children that weren't consumed above were deleted. We need - // to add them to the deletion list. - existingChildren.forEach(function (child) { - return deleteChild(returnFiber, child); - }); - } +function isReactClass(type) { + return type.prototype && type.prototype.isReactComponent; +} - return resultingFirstChild; - } +function unwrapThenable(thenable) { + var index = thenableIndexCounter$1; + thenableIndexCounter$1 += 1; - function reconcileSingleTextNode( - returnFiber, - currentFirstChild, - textContent, - lanes - ) { - // There's no need to check for keys on text nodes since we don't have a - // way to define them. - if (currentFirstChild !== null && currentFirstChild.tag === HostText) { - // We already have an existing node so let's just update it and delete - // the rest. - deleteRemainingChildren(returnFiber, currentFirstChild.sibling); - var existing = useFiber(currentFirstChild, textContent); - existing.return = returnFiber; - return existing; - } // The existing first child is not a text node so we need to create one - // and delete the existing ones. - - deleteRemainingChildren(returnFiber, currentFirstChild); - var created = createFiberFromText(textContent, returnFiber.mode, lanes); - created.return = returnFiber; - return created; + if (thenableState$1 === null) { + thenableState$1 = createThenableState(); } - function reconcileSingleElement( - returnFiber, - currentFirstChild, - element, - lanes + return trackUsedThenable(thenableState$1, thenable, index); +} + +function coerceRef(returnFiber, current, element) { + var mixedRef = element.ref; + + if ( + mixedRef !== null && + typeof mixedRef !== "function" && + typeof mixedRef !== "object" ) { - var key = element.key; - var child = currentFirstChild; + { + if ( + // We warn in ReactElement.js if owner and self are equal for string refs + // because these cannot be automatically converted to an arrow function + // using a codemod. Therefore, we don't have to warn about string refs again. + !( + element._owner && + element._self && + element._owner.stateNode !== element._self + ) && // Will already throw with "Function components cannot have string refs" + !(element._owner && element._owner.tag !== ClassComponent) && // Will already warn with "Function components cannot be given refs" + !(typeof element.type === "function" && !isReactClass(element.type)) && // Will already throw with "Element ref was specified as a string (someStringRef) but no owner was set" + element._owner + ) { + var componentName = + getComponentNameFromFiber(returnFiber) || "Component"; - while (child !== null) { - // TODO: If key === null and child.key === null, then this only applies to - // the first item in the list. - if (child.key === key) { - var elementType = element.type; + if (!didWarnAboutStringRefs[componentName]) { + error( + 'Component "%s" contains the string ref "%s". Support for string refs ' + + "will be removed in a future major release. We recommend using " + + "useRef() or createRef() instead. " + + "Learn more about using refs safely here: " + + "https://reactjs.org/link/strict-mode-string-ref", + componentName, + mixedRef + ); - if (elementType === REACT_FRAGMENT_TYPE) { - if (child.tag === Fragment) { - deleteRemainingChildren(returnFiber, child.sibling); - var existing = useFiber(child, element.props.children); - existing.return = returnFiber; + didWarnAboutStringRefs[componentName] = true; + } + } + } - { - existing._debugSource = element._source; - existing._debugOwner = element._owner; - } + if (element._owner) { + var owner = element._owner; + var inst; - return existing; - } - } else { - if ( - child.elementType === elementType || // Keep this check inline so it only runs on the false path: - isCompatibleFamilyForHotReloading(child, element) || // Lazy types should reconcile their resolved type. - // We need to do this after the Hot Reloading check above, - // because hot reloading has different semantics than prod because - // it doesn't resuspend. So we can't let the call below suspend. - (typeof elementType === "object" && - elementType !== null && - elementType.$$typeof === REACT_LAZY_TYPE && - resolveLazy(elementType) === child.type) - ) { - deleteRemainingChildren(returnFiber, child.sibling); + if (owner) { + var ownerFiber = owner; - var _existing = useFiber(child, element.props); + if (ownerFiber.tag !== ClassComponent) { + throw new Error( + "Function components cannot have string refs. " + + "We recommend using useRef() instead. " + + "Learn more about using refs safely here: " + + "https://reactjs.org/link/strict-mode-string-ref" + ); + } - _existing.ref = coerceRef(returnFiber, child, element); - _existing.return = returnFiber; + inst = ownerFiber.stateNode; + } - { - _existing._debugSource = element._source; - _existing._debugOwner = element._owner; - } + if (!inst) { + throw new Error( + "Missing owner for string ref " + + mixedRef + + ". This error is likely caused by a " + + "bug in React. Please file an issue." + ); + } // Assigning this to a const so Flow knows it won't change in the closure - return _existing; - } - } // Didn't match. + var resolvedInst = inst; - deleteRemainingChildren(returnFiber, child); - break; - } else { - deleteChild(returnFiber, child); + { + checkPropStringCoercion(mixedRef, "ref"); } - child = child.sibling; - } + var stringRef = "" + mixedRef; // Check if previous string ref matches new string ref - if (element.type === REACT_FRAGMENT_TYPE) { - var created = createFiberFromFragment( - element.props.children, - returnFiber.mode, - lanes, - element.key - ); - created.return = returnFiber; - return created; + if ( + current !== null && + current.ref !== null && + typeof current.ref === "function" && + current.ref._stringRef === stringRef + ) { + return current.ref; + } + + var ref = function (value) { + var refs = resolvedInst.refs; + + if (value === null) { + delete refs[stringRef]; + } else { + refs[stringRef] = value; + } + }; + + ref._stringRef = stringRef; + return ref; } else { - var _created4 = createFiberFromElement(element, returnFiber.mode, lanes); + if (typeof mixedRef !== "string") { + throw new Error( + "Expected ref to be a function, a string, an object returned by React.createRef(), or null." + ); + } - _created4.ref = coerceRef(returnFiber, currentFirstChild, element); - _created4.return = returnFiber; - return _created4; + if (!element._owner) { + throw new Error( + "Element ref was specified as a string (" + + mixedRef + + ") but no owner was set. This could happen for one of" + + " the following reasons:\n" + + "1. You may be adding a ref to a function component\n" + + "2. You may be adding a ref to a component that was not created inside a component's render method\n" + + "3. You have multiple copies of React loaded\n" + + "See https://reactjs.org/link/refs-must-have-owner for more information." + ); + } } } - function reconcileSinglePortal( - returnFiber, - currentFirstChild, - portal, - lanes - ) { - var key = portal.key; - var child = currentFirstChild; + return mixedRef; +} - while (child !== null) { - // TODO: If key === null and child.key === null, then this only applies to - // the first item in the list. - if (child.key === key) { - if ( - child.tag === HostPortal && - child.stateNode.containerInfo === portal.containerInfo && - child.stateNode.implementation === portal.implementation - ) { - deleteRemainingChildren(returnFiber, child.sibling); - var existing = useFiber(child, portal.children || []); - existing.return = returnFiber; - return existing; - } else { - deleteRemainingChildren(returnFiber, child); - break; - } - } else { - deleteChild(returnFiber, child); - } +function throwOnInvalidObjectType(returnFiber, newChild) { + // $FlowFixMe[method-unbinding] + var childString = Object.prototype.toString.call(newChild); + throw new Error( + "Objects are not valid as a React child (found: " + + (childString === "[object Object]" + ? "object with keys {" + Object.keys(newChild).join(", ") + "}" + : childString) + + "). " + + "If you meant to render a collection of children, use an array " + + "instead." + ); +} - child = child.sibling; +function warnOnFunctionType(returnFiber) { + { + var componentName = getComponentNameFromFiber(returnFiber) || "Component"; + + if (ownerHasFunctionTypeWarning[componentName]) { + return; } - var created = createFiberFromPortal(portal, returnFiber.mode, lanes); - created.return = returnFiber; - return created; - } // This API will tag the children with the side-effect of the reconciliation - // itself. They will be added to the side-effect list as we pass through the - // children and the parent. + ownerHasFunctionTypeWarning[componentName] = true; - function reconcileChildFibersImpl( - returnFiber, - currentFirstChild, - newChild, - lanes - ) { - // This function is not recursive. - // If the top level item is an array, we treat it as a set of children, - // not as a fragment. Nested arrays on the other hand will be treated as - // fragment nodes. Recursion happens at the normal flow. - // Handle top level unkeyed fragments as if they were arrays. - // This leads to an ambiguity between <>{[...]} and <>.... - // We treat the ambiguous cases above the same. - // TODO: Let's use recursion like we do for Usable nodes? - var isUnkeyedTopLevelFragment = - typeof newChild === "object" && - newChild !== null && - newChild.type === REACT_FRAGMENT_TYPE && - newChild.key === null; + error( + "Functions are not valid as a React child. This may happen if " + + "you return a Component instead of from render. " + + "Or maybe you meant to call this function rather than return it." + ); + } +} - if (isUnkeyedTopLevelFragment) { - newChild = newChild.props.children; - } // Handle object types +function resolveLazy(lazyType) { + var payload = lazyType._payload; + var init = lazyType._init; + return init(payload); +} // This wrapper function exists because I expect to clone the code in each path +// to be able to optimize each path individually by branching early. This needs +// a compiler or we can do it manually. Helpers that don't need this branching +// live outside of this function. - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: - return placeSingleChild( - reconcileSingleElement( - returnFiber, - currentFirstChild, - newChild, - lanes - ) - ); +function createChildReconciler(shouldTrackSideEffects) { + function deleteChild(returnFiber, childToDelete) { + if (!shouldTrackSideEffects) { + // Noop. + return; + } - case REACT_PORTAL_TYPE: - return placeSingleChild( - reconcileSinglePortal( - returnFiber, - currentFirstChild, - newChild, - lanes - ) - ); + var deletions = returnFiber.deletions; - case REACT_LAZY_TYPE: - var payload = newChild._payload; - var init = newChild._init; // TODO: This function is supposed to be non-recursive. + if (deletions === null) { + returnFiber.deletions = [childToDelete]; + returnFiber.flags |= ChildDeletion; + } else { + deletions.push(childToDelete); + } + } - return reconcileChildFibers( - returnFiber, - currentFirstChild, - init(payload), - lanes - ); - } + function deleteRemainingChildren(returnFiber, currentFirstChild) { + if (!shouldTrackSideEffects) { + // Noop. + return null; + } // TODO: For the shouldClone case, this could be micro-optimized a bit by + // assuming that after the first child we've already added everything. - if (isArray(newChild)) { - return reconcileChildrenArray( - returnFiber, - currentFirstChild, - newChild, - lanes - ); - } + var childToDelete = currentFirstChild; - if (getIteratorFn(newChild)) { - return reconcileChildrenIterator( - returnFiber, - currentFirstChild, - newChild, - lanes - ); - } // Usables are a valid React node type. When React encounters a Usable in - // a child position, it unwraps it using the same algorithm as `use`. For - // example, for promises, React will throw an exception to unwind the - // stack, then replay the component once the promise resolves. - // - // A difference from `use` is that React will keep unwrapping the value - // until it reaches a non-Usable type. - // - // e.g. Usable>> should resolve to T - // - // The structure is a bit unfortunate. Ideally, we shouldn't need to - // replay the entire begin phase of the parent fiber in order to reconcile - // the children again. This would require a somewhat significant refactor, - // because reconcilation happens deep within the begin phase, and - // depending on the type of work, not always at the end. We should - // consider as an future improvement. + while (childToDelete !== null) { + deleteChild(returnFiber, childToDelete); + childToDelete = childToDelete.sibling; + } - if (typeof newChild.then === "function") { - var thenable = newChild; - return reconcileChildFibersImpl( - returnFiber, - currentFirstChild, - unwrapThenable(thenable), - lanes - ); - } + return null; + } - if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) { - var context = newChild; - return reconcileChildFibersImpl( - returnFiber, - currentFirstChild, - readContextDuringReconcilation(returnFiber, context, lanes), - lanes - ); - } + function mapRemainingChildren(returnFiber, currentFirstChild) { + // Add the remaining children to a temporary map so that we can find them by + // keys quickly. Implicit (null) keys get added to this set with their index + // instead. + var existingChildren = new Map(); + var existingChild = currentFirstChild; - throwOnInvalidObjectType(returnFiber, newChild); - } + while (existingChild !== null) { + if (existingChild.key !== null) { + existingChildren.set(existingChild.key, existingChild); + } else { + existingChildren.set(existingChild.index, existingChild); + } - if ( - (typeof newChild === "string" && newChild !== "") || - typeof newChild === "number" - ) { - return placeSingleChild( - reconcileSingleTextNode( - returnFiber, - currentFirstChild, - "" + newChild, - lanes - ) - ); + existingChild = existingChild.sibling; } - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber); - } - } // Remaining cases are all treated as empty. - - return deleteRemainingChildren(returnFiber, currentFirstChild); + return existingChildren; } - function reconcileChildFibers( - returnFiber, - currentFirstChild, - newChild, - lanes - ) { - // This indirection only exists so we can reset `thenableState` at the end. - // It should get inlined by Closure. - thenableIndexCounter$1 = 0; - var firstChildFiber = reconcileChildFibersImpl( - returnFiber, - currentFirstChild, - newChild, - lanes - ); - thenableState$1 = null; // Don't bother to reset `thenableIndexCounter` to 0 because it always gets - // set at the beginning. - - return firstChildFiber; + function useFiber(fiber, pendingProps) { + // We currently set sibling to null and index to 0 here because it is easy + // to forget to do before returning it. E.g. for the single child case. + var clone = createWorkInProgress(fiber, pendingProps); + clone.index = 0; + clone.sibling = null; + return clone; } - return reconcileChildFibers; -} + function placeChild(newFiber, lastPlacedIndex, newIndex) { + newFiber.index = newIndex; -var reconcileChildFibers = createChildReconciler(true); -var mountChildFibers = createChildReconciler(false); -function resetChildReconcilerOnUnwind() { - // On unwind, clear any pending thenables that were used. - thenableState$1 = null; - thenableIndexCounter$1 = 0; -} -function cloneChildFibers(current, workInProgress) { - if (current !== null && workInProgress.child !== current.child) { - throw new Error("Resuming work not yet implemented."); - } + if (!shouldTrackSideEffects) { + // During hydration, the useId algorithm needs to know which fibers are + // part of a list of children (arrays, iterators). + newFiber.flags |= Forked; + return lastPlacedIndex; + } - if (workInProgress.child === null) { - return; - } + var current = newFiber.alternate; - var currentChild = workInProgress.child; - var newChild = createWorkInProgress(currentChild, currentChild.pendingProps); - workInProgress.child = newChild; - newChild.return = workInProgress; + if (current !== null) { + var oldIndex = current.index; - while (currentChild.sibling !== null) { - currentChild = currentChild.sibling; - newChild = newChild.sibling = createWorkInProgress( - currentChild, - currentChild.pendingProps - ); - newChild.return = workInProgress; + if (oldIndex < lastPlacedIndex) { + // This is a move. + newFiber.flags |= Placement | PlacementDEV; + return lastPlacedIndex; + } else { + // This item can stay in place. + return oldIndex; + } + } else { + // This is an insertion. + newFiber.flags |= Placement | PlacementDEV; + return lastPlacedIndex; + } } - newChild.sibling = null; -} // Reset a workInProgress child set to prepare it for a second pass. - -function resetChildFibers(workInProgress, lanes) { - var child = workInProgress.child; + function placeSingleChild(newFiber) { + // This is simpler for the single child case. We only need to do a + // placement for inserting new children. + if (shouldTrackSideEffects && newFiber.alternate === null) { + newFiber.flags |= Placement | PlacementDEV; + } - while (child !== null) { - resetWorkInProgress(child, lanes); - child = child.sibling; + return newFiber; } -} -// TODO: This isn't being used yet, but it's intended to replace the -// InvisibleParentContext that is currently managed by SuspenseContext. - -var currentTreeHiddenStackCursor = createCursor(null); -var prevRenderLanesStackCursor = createCursor(NoLanes); -function pushHiddenContext(fiber, context) { - var prevRenderLanes = getRenderLanes(); - push(prevRenderLanesStackCursor, prevRenderLanes, fiber); - push(currentTreeHiddenStackCursor, context, fiber); // When rendering a subtree that's currently hidden, we must include all - // lanes that would have rendered if the hidden subtree hadn't been deferred. - // That is, in order to reveal content from hidden -> visible, we must commit - // all the updates that we skipped when we originally hid the tree. + function updateTextNode(returnFiber, current, textContent, lanes) { + if (current === null || current.tag !== HostText) { + // Insert + var created = createFiberFromText(textContent, returnFiber.mode, lanes); + created.return = returnFiber; + return created; + } else { + // Update + var existing = useFiber(current, textContent); + existing.return = returnFiber; + return existing; + } + } - setRenderLanes(mergeLanes(prevRenderLanes, context.baseLanes)); -} -function reuseHiddenContextOnStack(fiber) { - // This subtree is not currently hidden, so we don't need to add any lanes - // to the render lanes. But we still need to push something to avoid a - // context mismatch. Reuse the existing context on the stack. - push(prevRenderLanesStackCursor, getRenderLanes(), fiber); - push( - currentTreeHiddenStackCursor, - currentTreeHiddenStackCursor.current, - fiber - ); -} -function popHiddenContext(fiber) { - // Restore the previous render lanes from the stack - setRenderLanes(prevRenderLanesStackCursor.current); - pop(currentTreeHiddenStackCursor, fiber); - pop(prevRenderLanesStackCursor, fiber); -} -function isCurrentTreeHidden() { - return currentTreeHiddenStackCursor.current !== null; -} + function updateElement(returnFiber, current, element, lanes) { + var elementType = element.type; -// suspends, i.e. it's the nearest `catch` block on the stack. + if (elementType === REACT_FRAGMENT_TYPE) { + return updateFragment( + returnFiber, + current, + element.props.children, + lanes, + element.key + ); + } -var suspenseHandlerStackCursor = createCursor(null); // Represents the outermost boundary that is not visible in the current tree. -// Everything above this is the "shell". When this is null, it means we're -// rendering in the shell of the app. If it's non-null, it means we're rendering -// deeper than the shell, inside a new tree that wasn't already visible. -// -// The main way we use this concept is to determine whether showing a fallback -// would result in a desirable or undesirable loading state. Activing a fallback -// in the shell is considered an undersirable loading state, because it would -// mean hiding visible (albeit stale) content in the current tree — we prefer to -// show the stale content, rather than switch to a fallback. But showing a -// fallback in a new tree is fine, because there's no stale content to -// prefer instead. + if (current !== null) { + if ( + current.elementType === elementType || // Keep this check inline so it only runs on the false path: + isCompatibleFamilyForHotReloading(current, element) || // Lazy types should reconcile their resolved type. + // We need to do this after the Hot Reloading check above, + // because hot reloading has different semantics than prod because + // it doesn't resuspend. So we can't let the call below suspend. + (typeof elementType === "object" && + elementType !== null && + elementType.$$typeof === REACT_LAZY_TYPE && + resolveLazy(elementType) === current.type) + ) { + // Move based on index + var existing = useFiber(current, element.props); + existing.ref = coerceRef(returnFiber, current, element); + existing.return = returnFiber; -var shellBoundary = null; -function getShellBoundary() { - return shellBoundary; -} -function pushPrimaryTreeSuspenseHandler(handler) { - // TODO: Pass as argument - var current = handler.alternate; - // propagated a single level. For example, when ForceSuspenseFallback is set, - // it should only force the nearest Suspense boundary into fallback mode. + { + existing._debugSource = element._source; + existing._debugOwner = element._owner; + } - pushSuspenseListContext( - handler, - setDefaultShallowSuspenseListContext(suspenseStackCursor.current) - ); // Experimental feature: Some Suspense boundaries are marked as having an - // to push a nested Suspense handler, because it will get replaced by the - // outer fallback, anyway. Consider this as a future optimization. + return existing; + } + } // Insert - push(suspenseHandlerStackCursor, handler, handler); + var created = createFiberFromElement(element, returnFiber.mode, lanes); + created.ref = coerceRef(returnFiber, current, element); + created.return = returnFiber; + return created; + } - if (shellBoundary === null) { - if (current === null || isCurrentTreeHidden()) { - // This boundary is not visible in the current UI. - shellBoundary = handler; + function updatePortal(returnFiber, current, portal, lanes) { + if ( + current === null || + current.tag !== HostPortal || + current.stateNode.containerInfo !== portal.containerInfo || + current.stateNode.implementation !== portal.implementation + ) { + // Insert + var created = createFiberFromPortal(portal, returnFiber.mode, lanes); + created.return = returnFiber; + return created; } else { - var prevState = current.memoizedState; + // Update + var existing = useFiber(current, portal.children || []); + existing.return = returnFiber; + return existing; + } + } - if (prevState !== null) { - // This boundary is showing a fallback in the current UI. - shellBoundary = handler; - } + function updateFragment(returnFiber, current, fragment, lanes, key) { + if (current === null || current.tag !== Fragment) { + // Insert + var created = createFiberFromFragment( + fragment, + returnFiber.mode, + lanes, + key + ); + created.return = returnFiber; + return created; + } else { + // Update + var existing = useFiber(current, fragment); + existing.return = returnFiber; + return existing; } } -} -function pushFallbackTreeSuspenseHandler(fiber) { - // We're about to render the fallback. If something in the fallback suspends, - // it's akin to throwing inside of a `catch` block. This boundary should not - // capture. Reuse the existing handler on the stack. - reuseSuspenseHandlerOnStack(fiber); -} -function pushOffscreenSuspenseHandler(fiber) { - if (fiber.tag === OffscreenComponent) { - // A SuspenseList context is only pushed here to avoid a push/pop mismatch. - // Reuse the current value on the stack. - // TODO: We can avoid needing to push here by by forking popSuspenseHandler - // into separate functions for Suspense and Offscreen. - pushSuspenseListContext(fiber, suspenseStackCursor.current); - push(suspenseHandlerStackCursor, fiber, fiber); - if (shellBoundary !== null); - else { - var current = fiber.alternate; + function createChild(returnFiber, newChild, lanes) { + if ( + (typeof newChild === "string" && newChild !== "") || + typeof newChild === "number" + ) { + // Text nodes don't have keys. If the previous node is implicitly keyed + // we can continue to replace it without aborting even if it is not a text + // node. + var created = createFiberFromText("" + newChild, returnFiber.mode, lanes); + created.return = returnFiber; + return created; + } - if (current !== null) { - var prevState = current.memoizedState; + if (typeof newChild === "object" && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: { + var _created = createFiberFromElement( + newChild, + returnFiber.mode, + lanes + ); - if (prevState !== null) { - // This is the first boundary in the stack that's already showing - // a fallback. So everything outside is considered the shell. - shellBoundary = fiber; + _created.ref = coerceRef(returnFiber, null, newChild); + _created.return = returnFiber; + return _created; } - } - } - } else { - // This is a LegacyHidden component. - reuseSuspenseHandlerOnStack(fiber); - } -} -function reuseSuspenseHandlerOnStack(fiber) { - pushSuspenseListContext(fiber, suspenseStackCursor.current); - push(suspenseHandlerStackCursor, getSuspenseHandler(), fiber); -} -function getSuspenseHandler() { - return suspenseHandlerStackCursor.current; -} -function popSuspenseHandler(fiber) { - pop(suspenseHandlerStackCursor, fiber); - if (shellBoundary === fiber) { - // Popping back into the shell. - shellBoundary = null; - } - - popSuspenseListContext(fiber); -} // SuspenseList context -// TODO: Move to a separate module? We may change the SuspenseList -// implementation to hide/show in the commit phase, anyway. + case REACT_PORTAL_TYPE: { + var _created2 = createFiberFromPortal( + newChild, + returnFiber.mode, + lanes + ); -var DefaultSuspenseContext = 0; -var SubtreeSuspenseContextMask = 1; // ForceSuspenseFallback can be used by SuspenseList to force newly added -// items into their fallback state during one of the render passes. + _created2.return = returnFiber; + return _created2; + } -var ForceSuspenseFallback = 2; -var suspenseStackCursor = createCursor(DefaultSuspenseContext); -function hasSuspenseListContext(parentContext, flag) { - return (parentContext & flag) !== 0; -} -function setDefaultShallowSuspenseListContext(parentContext) { - return parentContext & SubtreeSuspenseContextMask; -} -function setShallowSuspenseListContext(parentContext, shallowContext) { - return (parentContext & SubtreeSuspenseContextMask) | shallowContext; -} -function pushSuspenseListContext(fiber, newContext) { - push(suspenseStackCursor, newContext, fiber); -} -function popSuspenseListContext(fiber) { - pop(suspenseStackCursor, fiber); -} - -// A non-null SuspenseState means that it is blocked for one reason or another. -// - A non-null dehydrated field means it's blocked pending hydration. -// - A non-null dehydrated field can use isSuspenseInstancePending or -// isSuspenseInstanceFallback to query the reason for being dehydrated. -// - A null dehydrated field means it's blocked by something suspending and -// we're currently showing a fallback instead. - -function findFirstSuspended(row) { - var node = row; + case REACT_LAZY_TYPE: { + var payload = newChild._payload; + var init = newChild._init; + return createChild(returnFiber, init(payload), lanes); + } + } - while (node !== null) { - if (node.tag === SuspenseComponent) { - var state = node.memoizedState; + if (isArray(newChild) || getIteratorFn(newChild)) { + var _created3 = createFiberFromFragment( + newChild, + returnFiber.mode, + lanes, + null + ); - if (state !== null) { - var dehydrated = state.dehydrated; + _created3.return = returnFiber; + return _created3; + } // Usable node types + // + // Unwrap the inner value and recursively call this function again. - if ( - dehydrated === null || - isSuspenseInstancePending() || - isSuspenseInstanceFallback() - ) { - return node; - } + if (typeof newChild.then === "function") { + var thenable = newChild; + return createChild(returnFiber, unwrapThenable(thenable), lanes); } - } else if ( - node.tag === SuspenseListComponent && // revealOrder undefined can't be trusted because it don't - // keep track of whether it suspended or not. - node.memoizedProps.revealOrder !== undefined - ) { - var didSuspend = (node.flags & DidCapture) !== NoFlags$1; - if (didSuspend) { - return node; + if ( + newChild.$$typeof === REACT_CONTEXT_TYPE || + newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE + ) { + var context = newChild; + return createChild( + returnFiber, + readContextDuringReconcilation(returnFiber, context, lanes), + lanes + ); } - } else if (node.child !== null) { - node.child.return = node; - node = node.child; - continue; + + throwOnInvalidObjectType(returnFiber, newChild); } - if (node === row) { - return null; + { + if (typeof newChild === "function") { + warnOnFunctionType(returnFiber); + } } - while (node.sibling === null) { - if (node.return === null || node.return === row) { + return null; + } + + function updateSlot(returnFiber, oldFiber, newChild, lanes) { + // Update the fiber if the keys match, otherwise return null. + var key = oldFiber !== null ? oldFiber.key : null; + + if ( + (typeof newChild === "string" && newChild !== "") || + typeof newChild === "number" + ) { + // Text nodes don't have keys. If the previous node is implicitly keyed + // we can continue to replace it without aborting even if it is not a text + // node. + if (key !== null) { return null; } - node = node.return; + return updateTextNode(returnFiber, oldFiber, "" + newChild, lanes); } - node.sibling.return = node.return; - node = node.sibling; - } - - return null; -} + if (typeof newChild === "object" && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: { + if (newChild.key === key) { + return updateElement(returnFiber, oldFiber, newChild, lanes); + } else { + return null; + } + } -var NoFlags = - /* */ - 0; // Represents whether effect should fire. + case REACT_PORTAL_TYPE: { + if (newChild.key === key) { + return updatePortal(returnFiber, oldFiber, newChild, lanes); + } else { + return null; + } + } -var HasEffect = - /* */ - 1; // Represents the phase in which the effect (not the clean-up) fires. + case REACT_LAZY_TYPE: { + var payload = newChild._payload; + var init = newChild._init; + return updateSlot(returnFiber, oldFiber, init(payload), lanes); + } + } -var Insertion = - /* */ - 2; -var Layout = - /* */ - 4; -var Passive = - /* */ - 8; + if (isArray(newChild) || getIteratorFn(newChild)) { + if (key !== null) { + return null; + } -// and should be reset before starting a new render. -// This tracks which mutable sources need to be reset after a render. + return updateFragment(returnFiber, oldFiber, newChild, lanes, null); + } // Usable node types + // + // Unwrap the inner value and recursively call this function again. -var workInProgressSources = []; -var rendererSigil$1; + if (typeof newChild.then === "function") { + var thenable = newChild; + return updateSlot( + returnFiber, + oldFiber, + unwrapThenable(thenable), + lanes + ); + } -{ - // Used to detect multiple renderers using the same mutable source. - rendererSigil$1 = {}; -} + if ( + newChild.$$typeof === REACT_CONTEXT_TYPE || + newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE + ) { + var context = newChild; + return updateSlot( + returnFiber, + oldFiber, + readContextDuringReconcilation(returnFiber, context, lanes), + lanes + ); + } -function markSourceAsDirty(mutableSource) { - workInProgressSources.push(mutableSource); -} -function resetWorkInProgressVersions() { - for (var i = 0; i < workInProgressSources.length; i++) { - var mutableSource = workInProgressSources[i]; + throwOnInvalidObjectType(returnFiber, newChild); + } { - mutableSource._workInProgressVersionSecondary = null; + if (typeof newChild === "function") { + warnOnFunctionType(returnFiber); + } } - } - workInProgressSources.length = 0; -} -function getWorkInProgressVersion(mutableSource) { - { - return mutableSource._workInProgressVersionSecondary; - } -} -function setWorkInProgressVersion(mutableSource, version) { - { - mutableSource._workInProgressVersionSecondary = version; + return null; } - workInProgressSources.push(mutableSource); -} -function warnAboutMultipleRenderersDEV(mutableSource) { - { - { - if (mutableSource._currentSecondaryRenderer == null) { - mutableSource._currentSecondaryRenderer = rendererSigil$1; - } else if (mutableSource._currentSecondaryRenderer !== rendererSigil$1) { - error( - "Detected multiple renderers concurrently rendering the " + - "same mutable source. This is currently unsupported." - ); - } + function updateFromMap( + existingChildren, + returnFiber, + newIdx, + newChild, + lanes + ) { + if ( + (typeof newChild === "string" && newChild !== "") || + typeof newChild === "number" + ) { + // Text nodes don't have keys, so we neither have to check the old nor + // new node for the key. If both are text nodes, they match. + var matchedFiber = existingChildren.get(newIdx) || null; + return updateTextNode(returnFiber, matchedFiber, "" + newChild, lanes); } - } -} // Eager reads the version of a mutable source and stores it on the root. -var ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher, - ReactCurrentBatchConfig$2 = ReactSharedInternals.ReactCurrentBatchConfig; -var didWarnAboutMismatchedHooksForComponent; -var didWarnUncachedGetSnapshot; -var didWarnAboutUseWrappedInTryCatch; + if (typeof newChild === "object" && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: { + var _matchedFiber = + existingChildren.get( + newChild.key === null ? newIdx : newChild.key + ) || null; -{ - didWarnAboutMismatchedHooksForComponent = new Set(); - didWarnAboutUseWrappedInTryCatch = new Set(); -} // These are set right before calling the component. - -var renderLanes$1 = NoLanes; // The work-in-progress fiber. I've named it differently to distinguish it from -// the work-in-progress hook. - -var currentlyRenderingFiber$1 = null; // Hooks are stored as a linked list on the fiber's memoizedState field. The -// current hook list is the list that belongs to the current fiber. The -// work-in-progress hook list is a new list that will be added to the -// work-in-progress fiber. - -var currentHook = null; -var workInProgressHook = null; // Whether an update was scheduled at any point during the render phase. This -// does not get reset if we do another render pass; only when we're completely -// finished evaluating this component. This is an optimization so we know -// whether we need to clear render phase updates after a throw. - -var didScheduleRenderPhaseUpdate = false; // Where an update was scheduled only during the current render pass. This -// gets reset after each attempt. -// TODO: Maybe there's some way to consolidate this with -// `didScheduleRenderPhaseUpdate`. Or with `numberOfReRenders`. + return updateElement(returnFiber, _matchedFiber, newChild, lanes); + } -var didScheduleRenderPhaseUpdateDuringThisPass = false; -var shouldDoubleInvokeUserFnsInHooksDEV = false; // Counts the number of useId hooks in this component. + case REACT_PORTAL_TYPE: { + var _matchedFiber2 = + existingChildren.get( + newChild.key === null ? newIdx : newChild.key + ) || null; -var thenableIndexCounter = 0; -var thenableState = null; // Used for ids that are generated completely client-side (i.e. not during -// hydration). This counter is global, so client ids are not stable across -// render attempts. + return updatePortal(returnFiber, _matchedFiber2, newChild, lanes); + } -var globalClientIdCounter = 0; -var RE_RENDER_LIMIT = 25; // In DEV, this is the name of the currently executing primitive hook + case REACT_LAZY_TYPE: + var payload = newChild._payload; + var init = newChild._init; + return updateFromMap( + existingChildren, + returnFiber, + newIdx, + init(payload), + lanes + ); + } -var currentHookNameInDev = null; // In DEV, this list ensures that hooks are called in the same order between renders. -// The list stores the order of hooks used during the initial render (mount). -// Subsequent renders (updates) reference this list. + if (isArray(newChild) || getIteratorFn(newChild)) { + var _matchedFiber3 = existingChildren.get(newIdx) || null; -var hookTypesDev = null; -var hookTypesUpdateIndexDev = -1; // In DEV, this tracks whether currently rendering component needs to ignore -// the dependencies for Hooks that need them (e.g. useEffect or useMemo). -// When true, such Hooks will always be "remounted". Only used during hot reload. + return updateFragment( + returnFiber, + _matchedFiber3, + newChild, + lanes, + null + ); + } // Usable node types + // + // Unwrap the inner value and recursively call this function again. -var ignorePreviousDependencies = false; + if (typeof newChild.then === "function") { + var thenable = newChild; + return updateFromMap( + existingChildren, + returnFiber, + newIdx, + unwrapThenable(thenable), + lanes + ); + } -function mountHookTypesDev() { - { - var hookName = currentHookNameInDev; + if ( + newChild.$$typeof === REACT_CONTEXT_TYPE || + newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE + ) { + var context = newChild; + return updateFromMap( + existingChildren, + returnFiber, + newIdx, + readContextDuringReconcilation(returnFiber, context, lanes), + lanes + ); + } - if (hookTypesDev === null) { - hookTypesDev = [hookName]; - } else { - hookTypesDev.push(hookName); + throwOnInvalidObjectType(returnFiber, newChild); } - } -} - -function updateHookTypesDev() { - { - var hookName = currentHookNameInDev; - if (hookTypesDev !== null) { - hookTypesUpdateIndexDev++; - - if (hookTypesDev[hookTypesUpdateIndexDev] !== hookName) { - warnOnHookMismatchInDev(hookName); + { + if (typeof newChild === "function") { + warnOnFunctionType(returnFiber); } } - } -} -function checkDepsAreArrayDev(deps) { - { - if (deps !== undefined && deps !== null && !isArray(deps)) { - // Verify deps, but only on mount to avoid extra checks. - // It's unlikely their type would change as usually you define them inline. - error( - "%s received a final argument that is not an array (instead, received `%s`). When " + - "specified, the final argument must be an array.", - currentHookNameInDev, - typeof deps - ); - } + return null; } -} + /** + * Warns if there is a duplicate or missing key + */ -function warnOnHookMismatchInDev(currentHookName) { - { - var componentName = getComponentNameFromFiber(currentlyRenderingFiber$1); + function warnOnInvalidKey(child, knownKeys, returnFiber) { + { + if (typeof child !== "object" || child === null) { + return knownKeys; + } - if (!didWarnAboutMismatchedHooksForComponent.has(componentName)) { - didWarnAboutMismatchedHooksForComponent.add(componentName); + switch (child.$$typeof) { + case REACT_ELEMENT_TYPE: + case REACT_PORTAL_TYPE: + warnForMissingKey(child, returnFiber); + var key = child.key; - if (hookTypesDev !== null) { - var table = ""; - var secondColumnStart = 30; + if (typeof key !== "string") { + break; + } - for (var i = 0; i <= hookTypesUpdateIndexDev; i++) { - var oldHookName = hookTypesDev[i]; - var newHookName = - i === hookTypesUpdateIndexDev ? currentHookName : oldHookName; - var row = i + 1 + ". " + oldHookName; // Extra space so second column lines up - // lol @ IE not supporting String#repeat + if (knownKeys === null) { + knownKeys = new Set(); + knownKeys.add(key); + break; + } - while (row.length < secondColumnStart) { - row += " "; + if (!knownKeys.has(key)) { + knownKeys.add(key); + break; } - row += newHookName + "\n"; - table += row; - } + error( + "Encountered two children with the same key, `%s`. " + + "Keys should be unique so that components maintain their identity " + + "across updates. Non-unique keys may cause children to be " + + "duplicated and/or omitted — the behavior is unsupported and " + + "could change in a future version.", + key + ); - error( - "React has detected a change in the order of Hooks called by %s. " + - "This will lead to bugs and errors if not fixed. " + - "For more information, read the Rules of Hooks: https://reactjs.org/link/rules-of-hooks\n\n" + - " Previous render Next render\n" + - " ------------------------------------------------------\n" + - "%s" + - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - componentName, - table - ); + break; + + case REACT_LAZY_TYPE: + var payload = child._payload; + var init = child._init; + warnOnInvalidKey(init(payload), knownKeys, returnFiber); + break; } } - } -} - -function throwInvalidHookError() { - throw new Error( - "Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for" + - " one of the following reasons:\n" + - "1. You might have mismatching versions of React and the renderer (such as React DOM)\n" + - "2. You might be breaking the Rules of Hooks\n" + - "3. You might have more than one copy of React in the same app\n" + - "See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem." - ); -} -function areHookInputsEqual(nextDeps, prevDeps) { - { - if (ignorePreviousDependencies) { - // Only true when this component is being hot reloaded. - return false; - } + return knownKeys; } - if (prevDeps === null) { + function reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChildren, + lanes + ) { + // This algorithm can't optimize by searching from both ends since we + // don't have backpointers on fibers. I'm trying to see how far we can get + // with that model. If it ends up not being worth the tradeoffs, we can + // add it later. + // Even with a two ended optimization, we'd want to optimize for the case + // where there are few changes and brute force the comparison instead of + // going for the Map. It'd like to explore hitting that path first in + // forward-only mode and only go for the Map once we notice that we need + // lots of look ahead. This doesn't handle reversal as well as two ended + // search but that's unusual. Besides, for the two ended optimization to + // work on Iterables, we'd need to copy the whole set. + // In this first iteration, we'll just live with hitting the bad case + // (adding everything to a Map) in for every insert/move. + // If you change this code, also update reconcileChildrenIterator() which + // uses the same algorithm. { - error( - "%s received a final argument during this render, but not during " + - "the previous render. Even though the final argument is optional, " + - "its type cannot change between renders.", - currentHookNameInDev - ); - } + // First, validate keys. + var knownKeys = null; - return false; - } + for (var i = 0; i < newChildren.length; i++) { + var child = newChildren[i]; + knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber); + } + } - { - // Don't bother comparing lengths in prod because these arrays should be - // passed inline. - if (nextDeps.length !== prevDeps.length) { - error( - "The final argument passed to %s changed size between renders. The " + - "order and size of this array must remain constant.\n\n" + - "Previous: %s\n" + - "Incoming: %s", - currentHookNameInDev, - "[" + prevDeps.join(", ") + "]", - "[" + nextDeps.join(", ") + "]" - ); - } - } // $FlowFixMe[incompatible-use] found when upgrading Flow + var resultingFirstChild = null; + var previousNewFiber = null; + var oldFiber = currentFirstChild; + var lastPlacedIndex = 0; + var newIdx = 0; + var nextOldFiber = null; - for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++) { - // $FlowFixMe[incompatible-use] found when upgrading Flow - if (objectIs(nextDeps[i], prevDeps[i])) { - continue; - } + for (; oldFiber !== null && newIdx < newChildren.length; newIdx++) { + if (oldFiber.index > newIdx) { + nextOldFiber = oldFiber; + oldFiber = null; + } else { + nextOldFiber = oldFiber.sibling; + } - return false; - } + var newFiber = updateSlot( + returnFiber, + oldFiber, + newChildren[newIdx], + lanes + ); - return true; -} + if (newFiber === null) { + // TODO: This breaks on empty slots like null children. That's + // unfortunate because it triggers the slow path all the time. We need + // a better way to communicate whether this was a miss or null, + // boolean, undefined, etc. + if (oldFiber === null) { + oldFiber = nextOldFiber; + } -function renderWithHooks( - current, - workInProgress, - Component, - props, - secondArg, - nextRenderLanes -) { - renderLanes$1 = nextRenderLanes; - currentlyRenderingFiber$1 = workInProgress; + break; + } - { - hookTypesDev = current !== null ? current._debugHookTypes : null; - hookTypesUpdateIndexDev = -1; // Used for hot reloading: + if (shouldTrackSideEffects) { + if (oldFiber && newFiber.alternate === null) { + // We matched the slot, but we didn't reuse the existing fiber, so we + // need to delete the existing child. + deleteChild(returnFiber, oldFiber); + } + } - ignorePreviousDependencies = - current !== null && current.type !== workInProgress.type; - } + lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); - workInProgress.memoizedState = null; - workInProgress.updateQueue = null; - workInProgress.lanes = NoLanes; // The following should have already been reset - // currentHook = null; - // workInProgressHook = null; - // didScheduleRenderPhaseUpdate = false; - // localIdCounter = 0; - // thenableIndexCounter = 0; - // thenableState = null; - // TODO Warn if no hooks are used at all during mount, then some are used during update. - // Currently we will identify the update render as a mount because memoizedState === null. - // This is tricky because it's valid for certain types of components (e.g. React.lazy) - // Using memoizedState to differentiate between mount/update only works if at least one stateful hook is used. - // Non-stateful hooks (e.g. context) don't get added to memoizedState, - // so memoizedState would be null during updates and mounts. + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = newFiber; + } else { + // TODO: Defer siblings if we're not at the right index for this slot. + // I.e. if we had null values before, then we want to defer this + // for each null value. However, we also don't want to call updateSlot + // with the previous one. + previousNewFiber.sibling = newFiber; + } - { - if (current !== null && current.memoizedState !== null) { - ReactCurrentDispatcher$1.current = HooksDispatcherOnUpdateInDEV; - } else if (hookTypesDev !== null) { - // This dispatcher handles an edge case where a component is updating, - // but no stateful hooks have been used. - // We want to match the production code behavior (which will use HooksDispatcherOnMount), - // but with the extra DEV validation to ensure hooks ordering hasn't changed. - // This dispatcher does that. - ReactCurrentDispatcher$1.current = - HooksDispatcherOnMountWithHookTypesInDEV; - } else { - ReactCurrentDispatcher$1.current = HooksDispatcherOnMountInDEV; + previousNewFiber = newFiber; + oldFiber = nextOldFiber; } - } // In Strict Mode, during development, user functions are double invoked to - // help detect side effects. The logic for how this is implemented for in - // hook components is a bit complex so let's break it down. - // - // We will invoke the entire component function twice. However, during the - // second invocation of the component, the hook state from the first - // invocation will be reused. That means things like `useMemo` functions won't - // run again, because the deps will match and the memoized result will - // be reused. - // - // We want memoized functions to run twice, too, so account for this, user - // functions are double invoked during the *first* invocation of the component - // function, and are *not* double invoked during the second incovation: - // - // - First execution of component function: user functions are double invoked - // - Second execution of component function (in Strict Mode, during - // development): user functions are not double invoked. - // - // This is intentional for a few reasons; most importantly, it's because of - // how `use` works when something suspends: it reuses the promise that was - // passed during the first attempt. This is itself a form of memoization. - // We need to be able to memoize the reactive inputs to the `use` call using - // a hook (i.e. `useMemo`), which means, the reactive inputs to `use` must - // come from the same component invocation as the output. - // - // There are plenty of tests to ensure this behavior is correct. - var shouldDoubleRenderDEV = - (workInProgress.mode & StrictLegacyMode) !== NoMode; - shouldDoubleInvokeUserFnsInHooksDEV = shouldDoubleRenderDEV; - var children = Component(props, secondArg); - shouldDoubleInvokeUserFnsInHooksDEV = false; // Check if there was a render phase update + if (newIdx === newChildren.length) { + // We've reached the end of the new children. We can delete the rest. + deleteRemainingChildren(returnFiber, oldFiber); - if (didScheduleRenderPhaseUpdateDuringThisPass) { - // Keep rendering until the component stabilizes (there are no more render - // phase updates). - children = renderWithHooksAgain( - workInProgress, - Component, - props, - secondArg - ); - } + return resultingFirstChild; + } - if (shouldDoubleRenderDEV) { - // In development, components are invoked twice to help detect side effects. - setIsStrictModeForDevtools(true); + if (oldFiber === null) { + // If we don't have any more existing children we can choose a fast path + // since the rest will all be insertions. + for (; newIdx < newChildren.length; newIdx++) { + var _newFiber = createChild(returnFiber, newChildren[newIdx], lanes); - try { - children = renderWithHooksAgain( - workInProgress, - Component, - props, - secondArg - ); - } finally { - setIsStrictModeForDevtools(false); - } - } + if (_newFiber === null) { + continue; + } - finishRenderingHooks(current, workInProgress); - return children; -} + lastPlacedIndex = placeChild(_newFiber, lastPlacedIndex, newIdx); -function finishRenderingHooks(current, workInProgress) { - // We can assume the previous dispatcher is always this one, since we set it - // at the beginning of the render phase and there's no re-entrance. - ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = _newFiber; + } else { + previousNewFiber.sibling = _newFiber; + } - { - workInProgress._debugHookTypes = hookTypesDev; - } // This check uses currentHook so that it works the same in DEV and prod bundles. - // hookTypesDev could catch more cases (e.g. context) but only in DEV bundles. + previousNewFiber = _newFiber; + } - var didRenderTooFewHooks = currentHook !== null && currentHook.next !== null; - renderLanes$1 = NoLanes; - currentlyRenderingFiber$1 = null; - currentHook = null; - workInProgressHook = null; + return resultingFirstChild; + } // Add all children to a key map for quick lookups. - { - currentHookNameInDev = null; - hookTypesDev = null; - hookTypesUpdateIndexDev = -1; // Confirm that a static flag was not added or removed since the last - // render. If this fires, it suggests that we incorrectly reset the static - // flags in some other part of the codebase. This has happened before, for - // example, in the SuspenseList implementation. + var existingChildren = mapRemainingChildren(returnFiber, oldFiber); // Keep scanning and use the map to restore deleted items as moves. - if ( - current !== null && - (current.flags & StaticMask) !== (workInProgress.flags & StaticMask) && // Disable this warning in legacy mode, because legacy Suspense is weird - // and creates false positives. To make this work in legacy mode, we'd - // need to mark fibers that commit in an incomplete state, somehow. For - // now I'll disable the warning that most of the bugs that would trigger - // it are either exclusive to concurrent mode or exist in both. - (current.mode & ConcurrentMode) !== NoMode - ) { - error( - "Internal React error: Expected static flag was missing. Please " + - "notify the React team." + for (; newIdx < newChildren.length; newIdx++) { + var _newFiber2 = updateFromMap( + existingChildren, + returnFiber, + newIdx, + newChildren[newIdx], + lanes ); - } - } - didScheduleRenderPhaseUpdate = false; // This is reset by checkDidRenderIdHook - // localIdCounter = 0; + if (_newFiber2 !== null) { + if (shouldTrackSideEffects) { + if (_newFiber2.alternate !== null) { + // The new fiber is a work in progress, but if there exists a + // current, that means that we reused the fiber. We need to delete + // it from the child list so that we don't add it to the deletion + // list. + existingChildren.delete( + _newFiber2.key === null ? newIdx : _newFiber2.key + ); + } + } - thenableIndexCounter = 0; - thenableState = null; - - if (didRenderTooFewHooks) { - throw new Error( - "Rendered fewer hooks than expected. This may be caused by an accidental " + - "early return statement." - ); - } - - { - if (checkIfUseWrappedInTryCatch()) { - var componentName = - getComponentNameFromFiber(workInProgress) || "Unknown"; + lastPlacedIndex = placeChild(_newFiber2, lastPlacedIndex, newIdx); - if (!didWarnAboutUseWrappedInTryCatch.has(componentName)) { - didWarnAboutUseWrappedInTryCatch.add(componentName); + if (previousNewFiber === null) { + resultingFirstChild = _newFiber2; + } else { + previousNewFiber.sibling = _newFiber2; + } - error( - "`use` was called from inside a try/catch block. This is not allowed " + - "and can lead to unexpected behavior. To handle errors triggered " + - "by `use`, wrap your component in a error boundary." - ); + previousNewFiber = _newFiber2; } } - } -} -function replaySuspendedComponentWithHooks( - current, - workInProgress, - Component, - props, - secondArg -) { - // This function is used to replay a component that previously suspended, - // after its data resolves. - // - // It's a simplified version of renderWithHooks, but it doesn't need to do - // most of the set up work because they weren't reset when we suspended; they - // only get reset when the component either completes (finishRenderingHooks) - // or unwinds (resetHooksOnUnwind). - { - hookTypesUpdateIndexDev = -1; // Used for hot reloading: + if (shouldTrackSideEffects) { + // Any existing children that weren't consumed above were deleted. We need + // to add them to the deletion list. + existingChildren.forEach(function (child) { + return deleteChild(returnFiber, child); + }); + } - ignorePreviousDependencies = - current !== null && current.type !== workInProgress.type; + return resultingFirstChild; } - var children = renderWithHooksAgain( - workInProgress, - Component, - props, - secondArg - ); - finishRenderingHooks(current, workInProgress); - return children; -} - -function renderWithHooksAgain(workInProgress, Component, props, secondArg) { - // This is used to perform another render pass. It's used when setState is - // called during render, and for double invoking components in Strict Mode - // during development. - // - // The state from the previous pass is reused whenever possible. So, state - // updates that were already processed are not processed again, and memoized - // functions (`useMemo`) are not invoked again. - // - // Keep rendering in a loop for as long as render phase updates continue to - // be scheduled. Use a counter to prevent infinite loops. - var numberOfReRenders = 0; - var children; - - do { - if (didScheduleRenderPhaseUpdateDuringThisPass) { - // It's possible that a use() value depended on a state that was updated in - // this rerender, so we need to watch for different thenables this time. - thenableState = null; - } - - thenableIndexCounter = 0; - didScheduleRenderPhaseUpdateDuringThisPass = false; + function reconcileChildrenIterator( + returnFiber, + currentFirstChild, + newChildrenIterable, + lanes + ) { + // This is the same implementation as reconcileChildrenArray(), + // but using the iterator instead. + var iteratorFn = getIteratorFn(newChildrenIterable); - if (numberOfReRenders >= RE_RENDER_LIMIT) { + if (typeof iteratorFn !== "function") { throw new Error( - "Too many re-renders. React limits the number of renders to prevent " + - "an infinite loop." + "An object is not an iterable. This error is likely caused by a bug in " + + "React. Please file an issue." ); } - numberOfReRenders += 1; - { - // Even when hot reloading, allow dependencies to stabilize - // after first render to prevent infinite render phase updates. - ignorePreviousDependencies = false; - } // Start over from the beginning of the list - - currentHook = null; - workInProgressHook = null; - workInProgress.updateQueue = null; + // We don't support rendering Generators because it's a mutation. + // See https://github.com/facebook/react/issues/12995 + if ( + typeof Symbol === "function" && // $FlowFixMe Flow doesn't know about toStringTag + newChildrenIterable[Symbol.toStringTag] === "Generator" + ) { + if (!didWarnAboutGenerators) { + error( + "Using Generators as children is unsupported and will likely yield " + + "unexpected results because enumerating a generator mutates it. " + + "You may convert it to an array with `Array.from()` or the " + + "`[...spread]` operator before rendering. Keep in mind " + + "you might need to polyfill these features for older browsers." + ); + } - { - // Also validate hook order for cascading updates. - hookTypesUpdateIndexDev = -1; - } + didWarnAboutGenerators = true; + } // Warn about using Maps as children - ReactCurrentDispatcher$1.current = HooksDispatcherOnRerenderInDEV; - children = Component(props, secondArg); - } while (didScheduleRenderPhaseUpdateDuringThisPass); + if (newChildrenIterable.entries === iteratorFn) { + if (!didWarnAboutMaps) { + error( + "Using Maps as children is not supported. " + + "Use an array of keyed ReactElements instead." + ); + } - return children; -} -function bailoutHooks(current, workInProgress, lanes) { - workInProgress.updateQueue = current.updateQueue; // TODO: Don't need to reset the flags here, because they're reset in the - // complete phase (bubbleProperties). + didWarnAboutMaps = true; + } // First, validate keys. + // We'll get a different iterator later for the main pass. - if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { - workInProgress.flags &= ~( - MountPassiveDev | - MountLayoutDev | - Passive$1 | - Update - ); - } else { - workInProgress.flags &= ~(Passive$1 | Update); - } + var _newChildren = iteratorFn.call(newChildrenIterable); - current.lanes = removeLanes(current.lanes, lanes); -} -function resetHooksAfterThrow() { - // This is called immediaetly after a throw. It shouldn't reset the entire - // module state, because the work loop might decide to replay the component - // again without rewinding. - // - // It should only reset things like the current dispatcher, to prevent hooks - // from being called outside of a component. - // We can assume the previous dispatcher is always this one, since we set it - // at the beginning of the render phase and there's no re-entrance. - ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; -} -function resetHooksOnUnwind() { - if (didScheduleRenderPhaseUpdate) { - // There were render phase updates. These are only valid for this render - // phase, which we are now aborting. Remove the updates from the queues so - // they do not persist to the next render. Do not remove updates from hooks - // that weren't processed. - // - // Only reset the updates from the queue if it has a clone. If it does - // not have a clone, that means it wasn't processed, and the updates were - // scheduled before we entered the render phase. - var hook = currentlyRenderingFiber$1.memoizedState; + if (_newChildren) { + var knownKeys = null; - while (hook !== null) { - var queue = hook.queue; + var _step = _newChildren.next(); - if (queue !== null) { - queue.pending = null; + for (; !_step.done; _step = _newChildren.next()) { + var child = _step.value; + knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber); + } } + } - hook = hook.next; + var newChildren = iteratorFn.call(newChildrenIterable); + + if (newChildren == null) { + throw new Error("An iterable object provided no iterator."); } - didScheduleRenderPhaseUpdate = false; - } + var resultingFirstChild = null; + var previousNewFiber = null; + var oldFiber = currentFirstChild; + var lastPlacedIndex = 0; + var newIdx = 0; + var nextOldFiber = null; + var step = newChildren.next(); - renderLanes$1 = NoLanes; - currentlyRenderingFiber$1 = null; - currentHook = null; - workInProgressHook = null; + for ( + ; + oldFiber !== null && !step.done; + newIdx++, step = newChildren.next() + ) { + if (oldFiber.index > newIdx) { + nextOldFiber = oldFiber; + oldFiber = null; + } else { + nextOldFiber = oldFiber.sibling; + } - { - hookTypesDev = null; - hookTypesUpdateIndexDev = -1; - currentHookNameInDev = null; - } + var newFiber = updateSlot(returnFiber, oldFiber, step.value, lanes); - didScheduleRenderPhaseUpdateDuringThisPass = false; - thenableIndexCounter = 0; - thenableState = null; -} + if (newFiber === null) { + // TODO: This breaks on empty slots like null children. That's + // unfortunate because it triggers the slow path all the time. We need + // a better way to communicate whether this was a miss or null, + // boolean, undefined, etc. + if (oldFiber === null) { + oldFiber = nextOldFiber; + } -function mountWorkInProgressHook() { - var hook = { - memoizedState: null, - baseState: null, - baseQueue: null, - queue: null, - next: null - }; + break; + } - if (workInProgressHook === null) { - // This is the first hook in the list - currentlyRenderingFiber$1.memoizedState = workInProgressHook = hook; - } else { - // Append to the end of the list - workInProgressHook = workInProgressHook.next = hook; - } - - return workInProgressHook; -} + if (shouldTrackSideEffects) { + if (oldFiber && newFiber.alternate === null) { + // We matched the slot, but we didn't reuse the existing fiber, so we + // need to delete the existing child. + deleteChild(returnFiber, oldFiber); + } + } -function updateWorkInProgressHook() { - // This function is used both for updates and for re-renders triggered by a - // render phase update. It assumes there is either a current hook we can - // clone, or a work-in-progress hook from a previous render pass that we can - // use as a base. - var nextCurrentHook; + lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); - if (currentHook === null) { - var current = currentlyRenderingFiber$1.alternate; + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = newFiber; + } else { + // TODO: Defer siblings if we're not at the right index for this slot. + // I.e. if we had null values before, then we want to defer this + // for each null value. However, we also don't want to call updateSlot + // with the previous one. + previousNewFiber.sibling = newFiber; + } - if (current !== null) { - nextCurrentHook = current.memoizedState; - } else { - nextCurrentHook = null; + previousNewFiber = newFiber; + oldFiber = nextOldFiber; } - } else { - nextCurrentHook = currentHook.next; - } - - var nextWorkInProgressHook; - - if (workInProgressHook === null) { - nextWorkInProgressHook = currentlyRenderingFiber$1.memoizedState; - } else { - nextWorkInProgressHook = workInProgressHook.next; - } - if (nextWorkInProgressHook !== null) { - // There's already a work-in-progress. Reuse it. - workInProgressHook = nextWorkInProgressHook; - nextWorkInProgressHook = workInProgressHook.next; - currentHook = nextCurrentHook; - } else { - // Clone from the current hook. - if (nextCurrentHook === null) { - var currentFiber = currentlyRenderingFiber$1.alternate; + if (step.done) { + // We've reached the end of the new children. We can delete the rest. + deleteRemainingChildren(returnFiber, oldFiber); - if (currentFiber === null) { - // This is the initial render. This branch is reached when the component - // suspends, resumes, then renders an additional hook. - // Should never be reached because we should switch to the mount dispatcher first. - throw new Error( - "Update hook called on initial render. This is likely a bug in React. Please file an issue." - ); - } else { - // This is an update. We should always have a current hook. - throw new Error("Rendered more hooks than during the previous render."); - } + return resultingFirstChild; } - currentHook = nextCurrentHook; - var newHook = { - memoizedState: currentHook.memoizedState, - baseState: currentHook.baseState, - baseQueue: currentHook.baseQueue, - queue: currentHook.queue, - next: null - }; + if (oldFiber === null) { + // If we don't have any more existing children we can choose a fast path + // since the rest will all be insertions. + for (; !step.done; newIdx++, step = newChildren.next()) { + var _newFiber3 = createChild(returnFiber, step.value, lanes); - if (workInProgressHook === null) { - // This is the first hook in the list. - currentlyRenderingFiber$1.memoizedState = workInProgressHook = newHook; - } else { - // Append to the end of the list. - workInProgressHook = workInProgressHook.next = newHook; - } - } + if (_newFiber3 === null) { + continue; + } - return workInProgressHook; -} // NOTE: defining two versions of this function to avoid size impact when this feature is disabled. -// Previously this function was inlined, the additional `memoCache` property makes it not inlined. + lastPlacedIndex = placeChild(_newFiber3, lastPlacedIndex, newIdx); -var createFunctionComponentUpdateQueue; + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = _newFiber3; + } else { + previousNewFiber.sibling = _newFiber3; + } -{ - createFunctionComponentUpdateQueue = function () { - return { - lastEffect: null, - events: null, - stores: null, - memoCache: null - }; - }; -} + previousNewFiber = _newFiber3; + } -function use(usable) { - if (usable !== null && typeof usable === "object") { - // $FlowFixMe[method-unbinding] - if (typeof usable.then === "function") { - // This is a thenable. - var thenable = usable; // Track the position of the thenable within this fiber. + return resultingFirstChild; + } // Add all children to a key map for quick lookups. - var index = thenableIndexCounter; - thenableIndexCounter += 1; + var existingChildren = mapRemainingChildren(returnFiber, oldFiber); // Keep scanning and use the map to restore deleted items as moves. - if (thenableState === null) { - thenableState = createThenableState(); - } + for (; !step.done; newIdx++, step = newChildren.next()) { + var _newFiber4 = updateFromMap( + existingChildren, + returnFiber, + newIdx, + step.value, + lanes + ); - var result = trackUsedThenable(thenableState, thenable, index); + if (_newFiber4 !== null) { + if (shouldTrackSideEffects) { + if (_newFiber4.alternate !== null) { + // The new fiber is a work in progress, but if there exists a + // current, that means that we reused the fiber. We need to delete + // it from the child list so that we don't add it to the deletion + // list. + existingChildren.delete( + _newFiber4.key === null ? newIdx : _newFiber4.key + ); + } + } - if ( - currentlyRenderingFiber$1.alternate === null && - (workInProgressHook === null - ? currentlyRenderingFiber$1.memoizedState === null - : workInProgressHook.next === null) - ) { - // Initial render, and either this is the first time the component is - // called, or there were no Hooks called after this use() the previous - // time (perhaps because it threw). Subsequent Hook calls should use the - // mount dispatcher. - { - ReactCurrentDispatcher$1.current = HooksDispatcherOnMountInDEV; + lastPlacedIndex = placeChild(_newFiber4, lastPlacedIndex, newIdx); + + if (previousNewFiber === null) { + resultingFirstChild = _newFiber4; + } else { + previousNewFiber.sibling = _newFiber4; } + + previousNewFiber = _newFiber4; } + } - return result; - } else if ( - usable.$$typeof === REACT_CONTEXT_TYPE || - usable.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) { - var context = usable; - return readContext(context); + if (shouldTrackSideEffects) { + // Any existing children that weren't consumed above were deleted. We need + // to add them to the deletion list. + existingChildren.forEach(function (child) { + return deleteChild(returnFiber, child); + }); } - } // eslint-disable-next-line react-internal/safe-string-coercion - throw new Error("An unsupported type was passed to use(): " + String(usable)); -} + return resultingFirstChild; + } -function useMemoCache(size) { - var memoCache = null; // Fast-path, load memo cache from wip fiber if already prepared + function reconcileSingleTextNode( + returnFiber, + currentFirstChild, + textContent, + lanes + ) { + // There's no need to check for keys on text nodes since we don't have a + // way to define them. + if (currentFirstChild !== null && currentFirstChild.tag === HostText) { + // We already have an existing node so let's just update it and delete + // the rest. + deleteRemainingChildren(returnFiber, currentFirstChild.sibling); + var existing = useFiber(currentFirstChild, textContent); + existing.return = returnFiber; + return existing; + } // The existing first child is not a text node so we need to create one + // and delete the existing ones. - var updateQueue = currentlyRenderingFiber$1.updateQueue; + deleteRemainingChildren(returnFiber, currentFirstChild); + var created = createFiberFromText(textContent, returnFiber.mode, lanes); + created.return = returnFiber; + return created; + } - if (updateQueue !== null) { - memoCache = updateQueue.memoCache; - } // Otherwise clone from the current fiber + function reconcileSingleElement( + returnFiber, + currentFirstChild, + element, + lanes + ) { + var key = element.key; + var child = currentFirstChild; - if (memoCache == null) { - var current = currentlyRenderingFiber$1.alternate; + while (child !== null) { + // TODO: If key === null and child.key === null, then this only applies to + // the first item in the list. + if (child.key === key) { + var elementType = element.type; - if (current !== null) { - var currentUpdateQueue = current.updateQueue; + if (elementType === REACT_FRAGMENT_TYPE) { + if (child.tag === Fragment) { + deleteRemainingChildren(returnFiber, child.sibling); + var existing = useFiber(child, element.props.children); + existing.return = returnFiber; - if (currentUpdateQueue !== null) { - var currentMemoCache = currentUpdateQueue.memoCache; + { + existing._debugSource = element._source; + existing._debugOwner = element._owner; + } - if (currentMemoCache != null) { - memoCache = { - data: currentMemoCache.data.map(function (array) { - return array.slice(); - }), - index: 0 - }; - } - } - } - } // Finally fall back to allocating a fresh instance of the cache + return existing; + } + } else { + if ( + child.elementType === elementType || // Keep this check inline so it only runs on the false path: + isCompatibleFamilyForHotReloading(child, element) || // Lazy types should reconcile their resolved type. + // We need to do this after the Hot Reloading check above, + // because hot reloading has different semantics than prod because + // it doesn't resuspend. So we can't let the call below suspend. + (typeof elementType === "object" && + elementType !== null && + elementType.$$typeof === REACT_LAZY_TYPE && + resolveLazy(elementType) === child.type) + ) { + deleteRemainingChildren(returnFiber, child.sibling); - if (memoCache == null) { - memoCache = { - data: [], - index: 0 - }; - } + var _existing = useFiber(child, element.props); - if (updateQueue === null) { - updateQueue = createFunctionComponentUpdateQueue(); - currentlyRenderingFiber$1.updateQueue = updateQueue; - } + _existing.ref = coerceRef(returnFiber, child, element); + _existing.return = returnFiber; - updateQueue.memoCache = memoCache; - var data = memoCache.data[memoCache.index]; + { + _existing._debugSource = element._source; + _existing._debugOwner = element._owner; + } - if (data === undefined) { - data = memoCache.data[memoCache.index] = new Array(size); + return _existing; + } + } // Didn't match. - for (var i = 0; i < size; i++) { - data[i] = REACT_MEMO_CACHE_SENTINEL; + deleteRemainingChildren(returnFiber, child); + break; + } else { + deleteChild(returnFiber, child); + } + + child = child.sibling; } - } else if (data.length !== size) { - // TODO: consider warning or throwing here - { - error( - "Expected a constant size argument for each invocation of useMemoCache. " + - "The previous cache was allocated with size %s but size %s was requested.", - data.length, - size + + if (element.type === REACT_FRAGMENT_TYPE) { + var created = createFiberFromFragment( + element.props.children, + returnFiber.mode, + lanes, + element.key ); + created.return = returnFiber; + return created; + } else { + var _created4 = createFiberFromElement(element, returnFiber.mode, lanes); + + _created4.ref = coerceRef(returnFiber, currentFirstChild, element); + _created4.return = returnFiber; + return _created4; } } - memoCache.index++; - return data; -} - -function basicStateReducer(state, action) { - // $FlowFixMe: Flow doesn't like mixed types - return typeof action === "function" ? action(state) : action; -} + function reconcileSinglePortal( + returnFiber, + currentFirstChild, + portal, + lanes + ) { + var key = portal.key; + var child = currentFirstChild; -function mountReducer(reducer, initialArg, init) { - var hook = mountWorkInProgressHook(); - var initialState; + while (child !== null) { + // TODO: If key === null and child.key === null, then this only applies to + // the first item in the list. + if (child.key === key) { + if ( + child.tag === HostPortal && + child.stateNode.containerInfo === portal.containerInfo && + child.stateNode.implementation === portal.implementation + ) { + deleteRemainingChildren(returnFiber, child.sibling); + var existing = useFiber(child, portal.children || []); + existing.return = returnFiber; + return existing; + } else { + deleteRemainingChildren(returnFiber, child); + break; + } + } else { + deleteChild(returnFiber, child); + } - if (init !== undefined) { - initialState = init(initialArg); - } else { - initialState = initialArg; - } + child = child.sibling; + } - hook.memoizedState = hook.baseState = initialState; - var queue = { - pending: null, - lanes: NoLanes, - dispatch: null, - lastRenderedReducer: reducer, - lastRenderedState: initialState - }; - hook.queue = queue; - var dispatch = (queue.dispatch = dispatchReducerAction.bind( - null, - currentlyRenderingFiber$1, - queue - )); - return [hook.memoizedState, dispatch]; -} + var created = createFiberFromPortal(portal, returnFiber.mode, lanes); + created.return = returnFiber; + return created; + } // This API will tag the children with the side-effect of the reconciliation + // itself. They will be added to the side-effect list as we pass through the + // children and the parent. -function updateReducer(reducer, initialArg, init) { - var hook = updateWorkInProgressHook(); - var queue = hook.queue; + function reconcileChildFibersImpl( + returnFiber, + currentFirstChild, + newChild, + lanes + ) { + // This function is not recursive. + // If the top level item is an array, we treat it as a set of children, + // not as a fragment. Nested arrays on the other hand will be treated as + // fragment nodes. Recursion happens at the normal flow. + // Handle top level unkeyed fragments as if they were arrays. + // This leads to an ambiguity between <>{[...]} and <>.... + // We treat the ambiguous cases above the same. + // TODO: Let's use recursion like we do for Usable nodes? + var isUnkeyedTopLevelFragment = + typeof newChild === "object" && + newChild !== null && + newChild.type === REACT_FRAGMENT_TYPE && + newChild.key === null; - if (queue === null) { - throw new Error( - "Should have a queue. This is likely a bug in React. Please file an issue." - ); - } + if (isUnkeyedTopLevelFragment) { + newChild = newChild.props.children; + } // Handle object types - queue.lastRenderedReducer = reducer; - var current = currentHook; // The last rebase update that is NOT part of the base state. + if (typeof newChild === "object" && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return placeSingleChild( + reconcileSingleElement( + returnFiber, + currentFirstChild, + newChild, + lanes + ) + ); - var baseQueue = current.baseQueue; // The last pending update that hasn't been processed yet. + case REACT_PORTAL_TYPE: + return placeSingleChild( + reconcileSinglePortal( + returnFiber, + currentFirstChild, + newChild, + lanes + ) + ); - var pendingQueue = queue.pending; + case REACT_LAZY_TYPE: + var payload = newChild._payload; + var init = newChild._init; // TODO: This function is supposed to be non-recursive. - if (pendingQueue !== null) { - // We have new updates that haven't been processed yet. - // We'll add them to the base queue. - if (baseQueue !== null) { - // Merge the pending queue and the base queue. - var baseFirst = baseQueue.next; - var pendingFirst = pendingQueue.next; - baseQueue.next = pendingFirst; - pendingQueue.next = baseFirst; - } + return reconcileChildFibers( + returnFiber, + currentFirstChild, + init(payload), + lanes + ); + } - { - if (current.baseQueue !== baseQueue) { - // Internal invariant that should never happen, but feasibly could in - // the future if we implement resuming, or some form of that. - error( - "Internal error: Expected work-in-progress queue to be a clone. " + - "This is a bug in React." + if (isArray(newChild)) { + return reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChild, + lanes ); } - } - - current.baseQueue = baseQueue = pendingQueue; - queue.pending = null; - } - - if (baseQueue !== null) { - // We have a queue to process. - var first = baseQueue.next; - var newState = current.baseState; - var newBaseState = null; - var newBaseQueueFirst = null; - var newBaseQueueLast = null; - var update = first; - do { - // An extra OffscreenLane bit is added to updates that were made to - // a hidden tree, so that we can distinguish them from updates that were - // already there when the tree was hidden. - var updateLane = removeLanes(update.lane, OffscreenLane); - var isHiddenUpdate = updateLane !== update.lane; // Check if this update was made while the tree was hidden. If so, then - // it's not a "base" update and we should disregard the extra base lanes - // that were added to renderLanes when we entered the Offscreen tree. - - var shouldSkipUpdate = isHiddenUpdate - ? !isSubsetOfLanes(getWorkInProgressRootRenderLanes(), updateLane) - : !isSubsetOfLanes(renderLanes$1, updateLane); - - if (shouldSkipUpdate) { - // Priority is insufficient. Skip this update. If this is the first - // skipped update, the previous update/state is the new base - // update/state. - var clone = { - lane: updateLane, - action: update.action, - hasEagerState: update.hasEagerState, - eagerState: update.eagerState, - next: null - }; - - if (newBaseQueueLast === null) { - newBaseQueueFirst = newBaseQueueLast = clone; - newBaseState = newState; - } else { - newBaseQueueLast = newBaseQueueLast.next = clone; - } // Update the remaining priority in the queue. - // TODO: Don't need to accumulate this. Instead, we can remove - // renderLanes from the original lanes. - - currentlyRenderingFiber$1.lanes = mergeLanes( - currentlyRenderingFiber$1.lanes, - updateLane + if (getIteratorFn(newChild)) { + return reconcileChildrenIterator( + returnFiber, + currentFirstChild, + newChild, + lanes ); - markSkippedUpdateLanes(updateLane); - } else { - // This update does have sufficient priority. - if (newBaseQueueLast !== null) { - var _clone = { - // This update is going to be committed so we never want uncommit - // it. Using NoLane works because 0 is a subset of all bitmasks, so - // this will never be skipped by the check above. - lane: NoLane, - action: update.action, - hasEagerState: update.hasEagerState, - eagerState: update.eagerState, - next: null - }; - newBaseQueueLast = newBaseQueueLast.next = _clone; - } // Process this update. - - var action = update.action; - - if (shouldDoubleInvokeUserFnsInHooksDEV) { - reducer(newState, action); - } + } // Usables are a valid React node type. When React encounters a Usable in + // a child position, it unwraps it using the same algorithm as `use`. For + // example, for promises, React will throw an exception to unwind the + // stack, then replay the component once the promise resolves. + // + // A difference from `use` is that React will keep unwrapping the value + // until it reaches a non-Usable type. + // + // e.g. Usable>> should resolve to T + // + // The structure is a bit unfortunate. Ideally, we shouldn't need to + // replay the entire begin phase of the parent fiber in order to reconcile + // the children again. This would require a somewhat significant refactor, + // because reconcilation happens deep within the begin phase, and + // depending on the type of work, not always at the end. We should + // consider as an future improvement. - if (update.hasEagerState) { - // If this update is a state update (not a reducer) and was processed eagerly, - // we can use the eagerly computed state - newState = update.eagerState; - } else { - newState = reducer(newState, action); - } + if (typeof newChild.then === "function") { + var thenable = newChild; + return reconcileChildFibersImpl( + returnFiber, + currentFirstChild, + unwrapThenable(thenable), + lanes + ); } - update = update.next; - } while (update !== null && update !== first); + if ( + newChild.$$typeof === REACT_CONTEXT_TYPE || + newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE + ) { + var context = newChild; + return reconcileChildFibersImpl( + returnFiber, + currentFirstChild, + readContextDuringReconcilation(returnFiber, context, lanes), + lanes + ); + } - if (newBaseQueueLast === null) { - newBaseState = newState; - } else { - newBaseQueueLast.next = newBaseQueueFirst; - } // Mark that the fiber performed work, but only if the new state is - // different from the current state. + throwOnInvalidObjectType(returnFiber, newChild); + } - if (!objectIs(newState, hook.memoizedState)) { - markWorkInProgressReceivedUpdate(); + if ( + (typeof newChild === "string" && newChild !== "") || + typeof newChild === "number" + ) { + return placeSingleChild( + reconcileSingleTextNode( + returnFiber, + currentFirstChild, + "" + newChild, + lanes + ) + ); } - hook.memoizedState = newState; - hook.baseState = newBaseState; - hook.baseQueue = newBaseQueueLast; - queue.lastRenderedState = newState; - } + { + if (typeof newChild === "function") { + warnOnFunctionType(returnFiber); + } + } // Remaining cases are all treated as empty. - if (baseQueue === null) { - // `queue.lanes` is used for entangling transitions. We can set it back to - // zero once the queue is empty. - queue.lanes = NoLanes; + return deleteRemainingChildren(returnFiber, currentFirstChild); } - var dispatch = queue.dispatch; - return [hook.memoizedState, dispatch]; -} - -function rerenderReducer(reducer, initialArg, init) { - var hook = updateWorkInProgressHook(); - var queue = hook.queue; - - if (queue === null) { - throw new Error( - "Should have a queue. This is likely a bug in React. Please file an issue." + function reconcileChildFibers( + returnFiber, + currentFirstChild, + newChild, + lanes + ) { + // This indirection only exists so we can reset `thenableState` at the end. + // It should get inlined by Closure. + thenableIndexCounter$1 = 0; + var firstChildFiber = reconcileChildFibersImpl( + returnFiber, + currentFirstChild, + newChild, + lanes ); + thenableState$1 = null; // Don't bother to reset `thenableIndexCounter` to 0 because it always gets + // set at the beginning. + + return firstChildFiber; } - queue.lastRenderedReducer = reducer; // This is a re-render. Apply the new render phase updates to the previous - // work-in-progress hook. + return reconcileChildFibers; +} - var dispatch = queue.dispatch; - var lastRenderPhaseUpdate = queue.pending; - var newState = hook.memoizedState; +var reconcileChildFibers = createChildReconciler(true); +var mountChildFibers = createChildReconciler(false); +function resetChildReconcilerOnUnwind() { + // On unwind, clear any pending thenables that were used. + thenableState$1 = null; + thenableIndexCounter$1 = 0; +} +function cloneChildFibers(current, workInProgress) { + if (current !== null && workInProgress.child !== current.child) { + throw new Error("Resuming work not yet implemented."); + } - if (lastRenderPhaseUpdate !== null) { - // The queue doesn't persist past this render pass. - queue.pending = null; - var firstRenderPhaseUpdate = lastRenderPhaseUpdate.next; - var update = firstRenderPhaseUpdate; + if (workInProgress.child === null) { + return; + } - do { - // Process this render phase update. We don't have to check the - // priority because it will always be the same as the current - // render's. - var action = update.action; - newState = reducer(newState, action); - update = update.next; - } while (update !== firstRenderPhaseUpdate); // Mark that the fiber performed work, but only if the new state is - // different from the current state. + var currentChild = workInProgress.child; + var newChild = createWorkInProgress(currentChild, currentChild.pendingProps); + workInProgress.child = newChild; + newChild.return = workInProgress; - if (!objectIs(newState, hook.memoizedState)) { - markWorkInProgressReceivedUpdate(); - } + while (currentChild.sibling !== null) { + currentChild = currentChild.sibling; + newChild = newChild.sibling = createWorkInProgress( + currentChild, + currentChild.pendingProps + ); + newChild.return = workInProgress; + } - hook.memoizedState = newState; // Don't persist the state accumulated from the render phase updates to - // the base state unless the queue is empty. - // TODO: Not sure if this is the desired semantics, but it's what we - // do for gDSFP. I can't remember why. + newChild.sibling = null; +} // Reset a workInProgress child set to prepare it for a second pass. - if (hook.baseQueue === null) { - hook.baseState = newState; - } +function resetChildFibers(workInProgress, lanes) { + var child = workInProgress.child; - queue.lastRenderedState = newState; + while (child !== null) { + resetWorkInProgress(child, lanes); + child = child.sibling; } - - return [newState, dispatch]; } -function readFromUnsubscribedMutableSource(root, source, getSnapshot) { - { - warnAboutMultipleRenderersDEV(source); - } - - var getVersion = source._getVersion; - var version = getVersion(source._source); // Is it safe for this component to read from this source during the current render? +// TODO: This isn't being used yet, but it's intended to replace the +// InvisibleParentContext that is currently managed by SuspenseContext. - var isSafeToReadFromSource = false; // Check the version first. - // If this render has already been started with a specific version, - // we can use it alone to determine if we can safely read from the source. +var currentTreeHiddenStackCursor = createCursor(null); +var prevRenderLanesStackCursor = createCursor(NoLanes); +function pushHiddenContext(fiber, context) { + var prevRenderLanes = getRenderLanes(); + push(prevRenderLanesStackCursor, prevRenderLanes, fiber); + push(currentTreeHiddenStackCursor, context, fiber); // When rendering a subtree that's currently hidden, we must include all + // lanes that would have rendered if the hidden subtree hadn't been deferred. + // That is, in order to reveal content from hidden -> visible, we must commit + // all the updates that we skipped when we originally hid the tree. - var currentRenderVersion = getWorkInProgressVersion(source); + setRenderLanes(mergeLanes(prevRenderLanes, context.baseLanes)); +} +function reuseHiddenContextOnStack(fiber) { + // This subtree is not currently hidden, so we don't need to add any lanes + // to the render lanes. But we still need to push something to avoid a + // context mismatch. Reuse the existing context on the stack. + push(prevRenderLanesStackCursor, getRenderLanes(), fiber); + push( + currentTreeHiddenStackCursor, + currentTreeHiddenStackCursor.current, + fiber + ); +} +function popHiddenContext(fiber) { + // Restore the previous render lanes from the stack + setRenderLanes(prevRenderLanesStackCursor.current); + pop(currentTreeHiddenStackCursor, fiber); + pop(prevRenderLanesStackCursor, fiber); +} +function isCurrentTreeHidden() { + return currentTreeHiddenStackCursor.current !== null; +} - if (currentRenderVersion !== null) { - // It's safe to read if the store hasn't been mutated since the last time - // we read something. - isSafeToReadFromSource = currentRenderVersion === version; - } else { - // If there's no version, then this is the first time we've read from the - // source during the current render pass, so we need to do a bit more work. - // What we need to determine is if there are any hooks that already - // subscribed to the source, and if so, whether there are any pending - // mutations that haven't been synchronized yet. - // - // If there are no pending mutations, then `root.mutableReadLanes` will be - // empty, and we know we can safely read. - // - // If there *are* pending mutations, we may still be able to safely read - // if the currently rendering lanes are inclusive of the pending mutation - // lanes, since that guarantees that the value we're about to read from - // the source is consistent with the values that we read during the most - // recent mutation. - isSafeToReadFromSource = isSubsetOfLanes( - renderLanes$1, - root.mutableReadLanes - ); +// suspends, i.e. it's the nearest `catch` block on the stack. - if (isSafeToReadFromSource) { - // If it's safe to read from this source during the current render, - // store the version in case other components read from it. - // A changed version number will let those components know to throw and restart the render. - setWorkInProgressVersion(source, version); +var suspenseHandlerStackCursor = createCursor(null); // Represents the outermost boundary that is not visible in the current tree. +// Everything above this is the "shell". When this is null, it means we're +// rendering in the shell of the app. If it's non-null, it means we're rendering +// deeper than the shell, inside a new tree that wasn't already visible. +// +// The main way we use this concept is to determine whether showing a fallback +// would result in a desirable or undesirable loading state. Activing a fallback +// in the shell is considered an undersirable loading state, because it would +// mean hiding visible (albeit stale) content in the current tree — we prefer to +// show the stale content, rather than switch to a fallback. But showing a +// fallback in a new tree is fine, because there's no stale content to +// prefer instead. + +var shellBoundary = null; +function getShellBoundary() { + return shellBoundary; +} +function pushPrimaryTreeSuspenseHandler(handler) { + // TODO: Pass as argument + var current = handler.alternate; + // propagated a single level. For example, when ForceSuspenseFallback is set, + // it should only force the nearest Suspense boundary into fallback mode. + + pushSuspenseListContext( + handler, + setDefaultShallowSuspenseListContext(suspenseStackCursor.current) + ); // Experimental feature: Some Suspense boundaries are marked as having an + // to push a nested Suspense handler, because it will get replaced by the + // outer fallback, anyway. Consider this as a future optimization. + + push(suspenseHandlerStackCursor, handler, handler); + + if (shellBoundary === null) { + if (current === null || isCurrentTreeHidden()) { + // This boundary is not visible in the current UI. + shellBoundary = handler; + } else { + var prevState = current.memoizedState; + + if (prevState !== null) { + // This boundary is showing a fallback in the current UI. + shellBoundary = handler; + } } } +} +function pushFallbackTreeSuspenseHandler(fiber) { + // We're about to render the fallback. If something in the fallback suspends, + // it's akin to throwing inside of a `catch` block. This boundary should not + // capture. Reuse the existing handler on the stack. + reuseSuspenseHandlerOnStack(fiber); +} +function pushOffscreenSuspenseHandler(fiber) { + if (fiber.tag === OffscreenComponent) { + // A SuspenseList context is only pushed here to avoid a push/pop mismatch. + // Reuse the current value on the stack. + // TODO: We can avoid needing to push here by by forking popSuspenseHandler + // into separate functions for Suspense and Offscreen. + pushSuspenseListContext(fiber, suspenseStackCursor.current); + push(suspenseHandlerStackCursor, fiber, fiber); - if (isSafeToReadFromSource) { - var snapshot = getSnapshot(source._source); + if (shellBoundary !== null); + else { + var current = fiber.alternate; - { - if (typeof snapshot === "function") { - error( - "Mutable source should not return a function as the snapshot value. " + - "Functions may close over mutable values and cause tearing." - ); + if (current !== null) { + var prevState = current.memoizedState; + + if (prevState !== null) { + // This is the first boundary in the stack that's already showing + // a fallback. So everything outside is considered the shell. + shellBoundary = fiber; + } } } - - return snapshot; } else { - // This handles the special case of a mutable source being shared between renderers. - // In that case, if the source is mutated between the first and second renderer, - // The second renderer don't know that it needs to reset the WIP version during unwind, - // (because the hook only marks sources as dirty if it's written to their WIP version). - // That would cause this tear check to throw again and eventually be visible to the user. - // We can avoid this infinite loop by explicitly marking the source as dirty. - // - // This can lead to tearing in the first renderer when it resumes, - // but there's nothing we can do about that (short of throwing here and refusing to continue the render). - markSourceAsDirty(source); // Intentioally throw an error to force React to retry synchronously. During - // the synchronous retry, it will block interleaved mutations, so we should - // get a consistent read. Therefore, the following error should never be - // visible to the user. - // We expect this error not to be thrown during the synchronous retry, - // because we blocked interleaved mutations. - - throw new Error( - "Cannot read from mutable source during the current render without tearing. This may be a bug in React. Please file an issue." - ); + // This is a LegacyHidden component. + reuseSuspenseHandlerOnStack(fiber); } } +function reuseSuspenseHandlerOnStack(fiber) { + pushSuspenseListContext(fiber, suspenseStackCursor.current); + push(suspenseHandlerStackCursor, getSuspenseHandler(), fiber); +} +function getSuspenseHandler() { + return suspenseHandlerStackCursor.current; +} +function popSuspenseHandler(fiber) { + pop(suspenseHandlerStackCursor, fiber); -function useMutableSource(hook, source, getSnapshot, subscribe) { - var root = getWorkInProgressRoot(); - - if (root === null) { - throw new Error( - "Expected a work-in-progress root. This is a bug in React. Please file an issue." - ); + if (shellBoundary === fiber) { + // Popping back into the shell. + shellBoundary = null; } - var getVersion = source._getVersion; - var version = getVersion(source._source); - var dispatcher = ReactCurrentDispatcher$1.current; // eslint-disable-next-line prefer-const - - var _dispatcher$useState = dispatcher.useState(function () { - return readFromUnsubscribedMutableSource(root, source, getSnapshot); - }), - currentSnapshot = _dispatcher$useState[0], - setSnapshot = _dispatcher$useState[1]; + popSuspenseListContext(fiber); +} // SuspenseList context +// TODO: Move to a separate module? We may change the SuspenseList +// implementation to hide/show in the commit phase, anyway. - var snapshot = currentSnapshot; // Grab a handle to the state hook as well. - // We use it to clear the pending update queue if we have a new source. +var DefaultSuspenseContext = 0; +var SubtreeSuspenseContextMask = 1; // ForceSuspenseFallback can be used by SuspenseList to force newly added +// items into their fallback state during one of the render passes. - var stateHook = workInProgressHook; - var memoizedState = hook.memoizedState; - var refs = memoizedState.refs; - var prevGetSnapshot = refs.getSnapshot; - var prevSource = memoizedState.source; - var prevSubscribe = memoizedState.subscribe; - var fiber = currentlyRenderingFiber$1; - hook.memoizedState = { - refs: refs, - source: source, - subscribe: subscribe - }; // Sync the values needed by our subscription handler after each commit. +var ForceSuspenseFallback = 2; +var suspenseStackCursor = createCursor(DefaultSuspenseContext); +function hasSuspenseListContext(parentContext, flag) { + return (parentContext & flag) !== 0; +} +function setDefaultShallowSuspenseListContext(parentContext) { + return parentContext & SubtreeSuspenseContextMask; +} +function setShallowSuspenseListContext(parentContext, shallowContext) { + return (parentContext & SubtreeSuspenseContextMask) | shallowContext; +} +function pushSuspenseListContext(fiber, newContext) { + push(suspenseStackCursor, newContext, fiber); +} +function popSuspenseListContext(fiber) { + pop(suspenseStackCursor, fiber); +} - dispatcher.useEffect( - function () { - refs.getSnapshot = getSnapshot; // Normally the dispatch function for a state hook never changes, - // but this hook recreates the queue in certain cases to avoid updates from stale sources. - // handleChange() below needs to reference the dispatch function without re-subscribing, - // so we use a ref to ensure that it always has the latest version. +// A non-null SuspenseState means that it is blocked for one reason or another. +// - A non-null dehydrated field means it's blocked pending hydration. +// - A non-null dehydrated field can use isSuspenseInstancePending or +// isSuspenseInstanceFallback to query the reason for being dehydrated. +// - A null dehydrated field means it's blocked by something suspending and +// we're currently showing a fallback instead. - refs.setSnapshot = setSnapshot; // Check for a possible change between when we last rendered now. +function findFirstSuspended(row) { + var node = row; - var maybeNewVersion = getVersion(source._source); + while (node !== null) { + if (node.tag === SuspenseComponent) { + var state = node.memoizedState; - if (!objectIs(version, maybeNewVersion)) { - var maybeNewSnapshot = getSnapshot(source._source); + if (state !== null) { + var dehydrated = state.dehydrated; - { - if (typeof maybeNewSnapshot === "function") { - error( - "Mutable source should not return a function as the snapshot value. " + - "Functions may close over mutable values and cause tearing." - ); - } + if ( + dehydrated === null || + isSuspenseInstancePending() || + isSuspenseInstanceFallback() + ) { + return node; } - - if (!objectIs(snapshot, maybeNewSnapshot)) { - setSnapshot(maybeNewSnapshot); - var lane = requestUpdateLane(fiber); - markRootMutableRead(root, lane); - } // If the source mutated between render and now, - // there may be state updates already scheduled from the old source. - // Entangle the updates so that they render in the same batch. - - markRootEntangled(root, root.mutableReadLanes); } - }, - [getSnapshot, source, subscribe] - ); // If we got a new source or subscribe function, re-subscribe in a passive effect. - - dispatcher.useEffect( - function () { - var handleChange = function () { - var latestGetSnapshot = refs.getSnapshot; - var latestSetSnapshot = refs.setSnapshot; - - try { - latestSetSnapshot(latestGetSnapshot(source._source)); // Record a pending mutable source update with the same expiration time. + } else if ( + node.tag === SuspenseListComponent && // revealOrder undefined can't be trusted because it don't + // keep track of whether it suspended or not. + node.memoizedProps.revealOrder !== undefined + ) { + var didSuspend = (node.flags & DidCapture) !== NoFlags$1; - var lane = requestUpdateLane(fiber); - markRootMutableRead(root, lane); - } catch (error) { - // A selector might throw after a source mutation. - // e.g. it might try to read from a part of the store that no longer exists. - // In this case we should still schedule an update with React. - // Worst case the selector will throw again and then an error boundary will handle it. - latestSetSnapshot(function () { - throw error; - }); - } - }; + if (didSuspend) { + return node; + } + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } - var unsubscribe = subscribe(source._source, handleChange); + if (node === row) { + return null; + } - { - if (typeof unsubscribe !== "function") { - error( - "Mutable source subscribe function must return an unsubscribe function." - ); - } + while (node.sibling === null) { + if (node.return === null || node.return === row) { + return null; } - return unsubscribe; - }, - [source, subscribe] - ); // If any of the inputs to useMutableSource change, reading is potentially unsafe. - // - // If either the source or the subscription have changed we can't can't trust the update queue. - // Maybe the source changed in a way that the old subscription ignored but the new one depends on. - // - // If the getSnapshot function changed, we also shouldn't rely on the update queue. - // It's possible that the underlying source was mutated between the when the last "change" event fired, - // and when the current render (with the new getSnapshot function) is processed. - // - // In both cases, we need to throw away pending updates (since they are no longer relevant) - // and treat reading from the source as we do in the mount case. + node = node.return; + } - if ( - !objectIs(prevGetSnapshot, getSnapshot) || - !objectIs(prevSource, source) || - !objectIs(prevSubscribe, subscribe) - ) { - // Create a new queue and setState method, - // So if there are interleaved updates, they get pushed to the older queue. - // When this becomes current, the previous queue and dispatch method will be discarded, - // including any interleaving updates that occur. - var newQueue = { - pending: null, - lanes: NoLanes, - dispatch: null, - lastRenderedReducer: basicStateReducer, - lastRenderedState: snapshot - }; - newQueue.dispatch = setSnapshot = dispatchSetState.bind( - null, - currentlyRenderingFiber$1, - newQueue - ); - stateHook.queue = newQueue; - stateHook.baseQueue = null; - snapshot = readFromUnsubscribedMutableSource(root, source, getSnapshot); - stateHook.memoizedState = stateHook.baseState = snapshot; + node.sibling.return = node.return; + node = node.sibling; } - return snapshot; -} - -function mountMutableSource(source, getSnapshot, subscribe) { - var hook = mountWorkInProgressHook(); - hook.memoizedState = { - refs: { - getSnapshot: getSnapshot, - setSnapshot: null - }, - source: source, - subscribe: subscribe - }; - return useMutableSource(hook, source, getSnapshot, subscribe); -} - -function updateMutableSource(source, getSnapshot, subscribe) { - var hook = updateWorkInProgressHook(); - return useMutableSource(hook, source, getSnapshot, subscribe); + return null; } -function mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) { - var fiber = currentlyRenderingFiber$1; - var hook = mountWorkInProgressHook(); - var nextSnapshot; +var NoFlags = + /* */ + 0; // Represents whether effect should fire. - { - nextSnapshot = getSnapshot(); +var HasEffect = + /* */ + 1; // Represents the phase in which the effect (not the clean-up) fires. - { - if (!didWarnUncachedGetSnapshot) { - var cachedSnapshot = getSnapshot(); +var Insertion = + /* */ + 2; +var Layout = + /* */ + 4; +var Passive = + /* */ + 8; - if (!objectIs(nextSnapshot, cachedSnapshot)) { - error( - "The result of getSnapshot should be cached to avoid an infinite loop" - ); +// and should be reset before starting a new render. +// This tracks which mutable sources need to be reset after a render. - didWarnUncachedGetSnapshot = true; - } - } - } // Unless we're rendering a blocking lane, schedule a consistency check. - // Right before committing, we will walk the tree and check if any of the - // stores were mutated. - // - // We won't do this if we're hydrating server-rendered content, because if - // the content is stale, it's already visible anyway. Instead we'll patch - // it up in a passive effect. +var workInProgressSources = []; +var rendererSigil$1; - var root = getWorkInProgressRoot(); +{ + // Used to detect multiple renderers using the same mutable source. + rendererSigil$1 = {}; +} - if (root === null) { - throw new Error( - "Expected a work-in-progress root. This is a bug in React. Please file an issue." - ); - } +function markSourceAsDirty(mutableSource) { + workInProgressSources.push(mutableSource); +} +function resetWorkInProgressVersions() { + for (var i = 0; i < workInProgressSources.length; i++) { + var mutableSource = workInProgressSources[i]; - if (!includesBlockingLane(root, renderLanes$1)) { - pushStoreConsistencyCheck(fiber, getSnapshot, nextSnapshot); + { + mutableSource._workInProgressVersionSecondary = null; } - } // Read the current snapshot from the store on every render. This breaks the - // normal rules of React, and only works because store updates are - // always synchronous. - - hook.memoizedState = nextSnapshot; - var inst = { - value: nextSnapshot, - getSnapshot: getSnapshot - }; - hook.queue = inst; // Schedule an effect to subscribe to the store. - - mountEffect(subscribeToStore.bind(null, fiber, inst, subscribe), [subscribe]); // Schedule an effect to update the mutable instance fields. We will update - // this whenever subscribe, getSnapshot, or value changes. Because there's no - // clean-up function, and we track the deps correctly, we can call pushEffect - // directly, without storing any additional state. For the same reason, we - // don't need to set a static flag, either. - // TODO: We can move this to the passive phase once we add a pre-commit - // consistency check. See the next comment. + } - fiber.flags |= Passive$1; - pushEffect( - HasEffect | Passive, - updateStoreInstance.bind(null, fiber, inst, nextSnapshot, getSnapshot), - undefined, - null - ); - return nextSnapshot; + workInProgressSources.length = 0; } - -function updateSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) { - var fiber = currentlyRenderingFiber$1; - var hook = updateWorkInProgressHook(); // Read the current snapshot from the store on every render. This breaks the - // normal rules of React, and only works because store updates are - // always synchronous. - - var nextSnapshot = getSnapshot(); - +function getWorkInProgressVersion(mutableSource) { { - if (!didWarnUncachedGetSnapshot) { - var cachedSnapshot = getSnapshot(); + return mutableSource._workInProgressVersionSecondary; + } +} +function setWorkInProgressVersion(mutableSource, version) { + { + mutableSource._workInProgressVersionSecondary = version; + } - if (!objectIs(nextSnapshot, cachedSnapshot)) { + workInProgressSources.push(mutableSource); +} +function warnAboutMultipleRenderersDEV(mutableSource) { + { + { + if (mutableSource._currentSecondaryRenderer == null) { + mutableSource._currentSecondaryRenderer = rendererSigil$1; + } else if (mutableSource._currentSecondaryRenderer !== rendererSigil$1) { error( - "The result of getSnapshot should be cached to avoid an infinite loop" + "Detected multiple renderers concurrently rendering the " + + "same mutable source. This is currently unsupported." ); - - didWarnUncachedGetSnapshot = true; } } } +} // Eager reads the version of a mutable source and stores it on the root. - var prevSnapshot = (currentHook || hook).memoizedState; - var snapshotChanged = !objectIs(prevSnapshot, nextSnapshot); +var ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher, + ReactCurrentBatchConfig$2 = ReactSharedInternals.ReactCurrentBatchConfig; +var didWarnAboutMismatchedHooksForComponent; +var didWarnUncachedGetSnapshot; +var didWarnAboutUseWrappedInTryCatch; - if (snapshotChanged) { - hook.memoizedState = nextSnapshot; - markWorkInProgressReceivedUpdate(); - } +{ + didWarnAboutMismatchedHooksForComponent = new Set(); + didWarnAboutUseWrappedInTryCatch = new Set(); +} // These are set right before calling the component. - var inst = hook.queue; - updateEffect(subscribeToStore.bind(null, fiber, inst, subscribe), [ - subscribe - ]); // Whenever getSnapshot or subscribe changes, we need to check in the - // commit phase if there was an interleaved mutation. In concurrent mode - // this can happen all the time, but even in synchronous mode, an earlier - // effect may have mutated the store. +var renderLanes$1 = NoLanes; // The work-in-progress fiber. I've named it differently to distinguish it from +// the work-in-progress hook. - if ( - inst.getSnapshot !== getSnapshot || - snapshotChanged || // Check if the susbcribe function changed. We can save some memory by - // checking whether we scheduled a subscription effect above. - (workInProgressHook !== null && - workInProgressHook.memoizedState.tag & HasEffect) - ) { - fiber.flags |= Passive$1; - pushEffect( - HasEffect | Passive, - updateStoreInstance.bind(null, fiber, inst, nextSnapshot, getSnapshot), - undefined, - null - ); // Unless we're rendering a blocking lane, schedule a consistency check. - // Right before committing, we will walk the tree and check if any of the - // stores were mutated. +var currentlyRenderingFiber$1 = null; // Hooks are stored as a linked list on the fiber's memoizedState field. The +// current hook list is the list that belongs to the current fiber. The +// work-in-progress hook list is a new list that will be added to the +// work-in-progress fiber. - var root = getWorkInProgressRoot(); +var currentHook = null; +var workInProgressHook = null; // Whether an update was scheduled at any point during the render phase. This +// does not get reset if we do another render pass; only when we're completely +// finished evaluating this component. This is an optimization so we know +// whether we need to clear render phase updates after a throw. - if (root === null) { - throw new Error( - "Expected a work-in-progress root. This is a bug in React. Please file an issue." - ); - } +var didScheduleRenderPhaseUpdate = false; // Where an update was scheduled only during the current render pass. This +// gets reset after each attempt. +// TODO: Maybe there's some way to consolidate this with +// `didScheduleRenderPhaseUpdate`. Or with `numberOfReRenders`. - if (!includesBlockingLane(root, renderLanes$1)) { - pushStoreConsistencyCheck(fiber, getSnapshot, nextSnapshot); - } - } +var didScheduleRenderPhaseUpdateDuringThisPass = false; +var shouldDoubleInvokeUserFnsInHooksDEV = false; // Counts the number of useId hooks in this component. - return nextSnapshot; -} +var thenableIndexCounter = 0; +var thenableState = null; // Used for ids that are generated completely client-side (i.e. not during +// hydration). This counter is global, so client ids are not stable across +// render attempts. -function pushStoreConsistencyCheck(fiber, getSnapshot, renderedSnapshot) { - fiber.flags |= StoreConsistency; - var check = { - getSnapshot: getSnapshot, - value: renderedSnapshot - }; - var componentUpdateQueue = currentlyRenderingFiber$1.updateQueue; +var globalClientIdCounter = 0; +var RE_RENDER_LIMIT = 25; // In DEV, this is the name of the currently executing primitive hook - if (componentUpdateQueue === null) { - componentUpdateQueue = createFunctionComponentUpdateQueue(); - currentlyRenderingFiber$1.updateQueue = componentUpdateQueue; - componentUpdateQueue.stores = [check]; - } else { - var stores = componentUpdateQueue.stores; +var currentHookNameInDev = null; // In DEV, this list ensures that hooks are called in the same order between renders. +// The list stores the order of hooks used during the initial render (mount). +// Subsequent renders (updates) reference this list. - if (stores === null) { - componentUpdateQueue.stores = [check]; +var hookTypesDev = null; +var hookTypesUpdateIndexDev = -1; // In DEV, this tracks whether currently rendering component needs to ignore +// the dependencies for Hooks that need them (e.g. useEffect or useMemo). +// When true, such Hooks will always be "remounted". Only used during hot reload. + +var ignorePreviousDependencies = false; + +function mountHookTypesDev() { + { + var hookName = currentHookNameInDev; + + if (hookTypesDev === null) { + hookTypesDev = [hookName]; } else { - stores.push(check); + hookTypesDev.push(hookName); } } } -function updateStoreInstance(fiber, inst, nextSnapshot, getSnapshot) { - // These are updated in the passive phase - inst.value = nextSnapshot; - inst.getSnapshot = getSnapshot; // Something may have been mutated in between render and commit. This could - // have been in an event that fired before the passive effects, or it could - // have been in a layout effect. In that case, we would have used the old - // snapsho and getSnapshot values to bail out. We need to check one more time. +function updateHookTypesDev() { + { + var hookName = currentHookNameInDev; - if (checkIfSnapshotChanged(inst)) { - // Force a re-render. - forceStoreRerender(fiber); - } -} + if (hookTypesDev !== null) { + hookTypesUpdateIndexDev++; -function subscribeToStore(fiber, inst, subscribe) { - var handleStoreChange = function () { - // The store changed. Check if the snapshot changed since the last time we - // read from the store. - if (checkIfSnapshotChanged(inst)) { - // Force a re-render. - forceStoreRerender(fiber); + if (hookTypesDev[hookTypesUpdateIndexDev] !== hookName) { + warnOnHookMismatchInDev(hookName); + } } - }; // Subscribe to the store and return a clean-up function. - - return subscribe(handleStoreChange); -} - -function checkIfSnapshotChanged(inst) { - var latestGetSnapshot = inst.getSnapshot; - var prevValue = inst.value; - - try { - var nextValue = latestGetSnapshot(); - return !objectIs(prevValue, nextValue); - } catch (error) { - return true; } } -function forceStoreRerender(fiber) { - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); +function checkDepsAreArrayDev(deps) { + { + if (deps !== undefined && deps !== null && !isArray(deps)) { + // Verify deps, but only on mount to avoid extra checks. + // It's unlikely their type would change as usually you define them inline. + error( + "%s received a final argument that is not an array (instead, received `%s`). When " + + "specified, the final argument must be an array.", + currentHookNameInDev, + typeof deps + ); + } } } -function mountState(initialState) { - var hook = mountWorkInProgressHook(); - - if (typeof initialState === "function") { - // $FlowFixMe: Flow doesn't like mixed types - initialState = initialState(); - } +function warnOnHookMismatchInDev(currentHookName) { + { + var componentName = getComponentNameFromFiber(currentlyRenderingFiber$1); - hook.memoizedState = hook.baseState = initialState; - var queue = { - pending: null, - lanes: NoLanes, - dispatch: null, - lastRenderedReducer: basicStateReducer, - lastRenderedState: initialState - }; - hook.queue = queue; - var dispatch = (queue.dispatch = dispatchSetState.bind( - null, - currentlyRenderingFiber$1, - queue - )); - return [hook.memoizedState, dispatch]; -} + if (!didWarnAboutMismatchedHooksForComponent.has(componentName)) { + didWarnAboutMismatchedHooksForComponent.add(componentName); -function updateState(initialState) { - return updateReducer(basicStateReducer); -} + if (hookTypesDev !== null) { + var table = ""; + var secondColumnStart = 30; -function rerenderState(initialState) { - return rerenderReducer(basicStateReducer); -} + for (var i = 0; i <= hookTypesUpdateIndexDev; i++) { + var oldHookName = hookTypesDev[i]; + var newHookName = + i === hookTypesUpdateIndexDev ? currentHookName : oldHookName; + var row = i + 1 + ". " + oldHookName; // Extra space so second column lines up + // lol @ IE not supporting String#repeat -function pushEffect(tag, create, destroy, deps) { - var effect = { - tag: tag, - create: create, - destroy: destroy, - deps: deps, - // Circular - next: null - }; - var componentUpdateQueue = currentlyRenderingFiber$1.updateQueue; + while (row.length < secondColumnStart) { + row += " "; + } - if (componentUpdateQueue === null) { - componentUpdateQueue = createFunctionComponentUpdateQueue(); - currentlyRenderingFiber$1.updateQueue = componentUpdateQueue; - componentUpdateQueue.lastEffect = effect.next = effect; - } else { - var lastEffect = componentUpdateQueue.lastEffect; + row += newHookName + "\n"; + table += row; + } - if (lastEffect === null) { - componentUpdateQueue.lastEffect = effect.next = effect; - } else { - var firstEffect = lastEffect.next; - lastEffect.next = effect; - effect.next = firstEffect; - componentUpdateQueue.lastEffect = effect; + error( + "React has detected a change in the order of Hooks called by %s. " + + "This will lead to bugs and errors if not fixed. " + + "For more information, read the Rules of Hooks: https://reactjs.org/link/rules-of-hooks\n\n" + + " Previous render Next render\n" + + " ------------------------------------------------------\n" + + "%s" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + componentName, + table + ); + } } } - - return effect; } -var stackContainsErrorMessage = null; - -function getCallerStackFrame() { - // eslint-disable-next-line react-internal/prod-error-codes - var stackFrames = new Error("Error message").stack.split("\n"); // Some browsers (e.g. Chrome) include the error message in the stack - // but others (e.g. Firefox) do not. +function throwInvalidHookError() { + throw new Error( + "Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for" + + " one of the following reasons:\n" + + "1. You might have mismatching versions of React and the renderer (such as React DOM)\n" + + "2. You might be breaking the Rules of Hooks\n" + + "3. You might have more than one copy of React in the same app\n" + + "See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem." + ); +} - if (stackContainsErrorMessage === null) { - stackContainsErrorMessage = stackFrames[0].includes("Error message"); +function areHookInputsEqual(nextDeps, prevDeps) { + { + if (ignorePreviousDependencies) { + // Only true when this component is being hot reloaded. + return false; + } } - return stackContainsErrorMessage - ? stackFrames.slice(3, 4).join("\n") - : stackFrames.slice(2, 3).join("\n"); -} - -function mountRef(initialValue) { - var hook = mountWorkInProgressHook(); - - if (enableUseRefAccessWarning) { + if (prevDeps === null) { { - // Support lazy initialization pattern shown in docs. - // We need to store the caller stack frame so that we don't warn on subsequent renders. - var hasBeenInitialized = initialValue != null; - var lazyInitGetterStack = null; - var didCheckForLazyInit = false; // Only warn once per component+hook. - - var didWarnAboutRead = false; - var didWarnAboutWrite = false; - var current = initialValue; - var ref = { - get current() { - if (!hasBeenInitialized) { - didCheckForLazyInit = true; - lazyInitGetterStack = getCallerStackFrame(); - } else if (currentlyRenderingFiber$1 !== null && !didWarnAboutRead) { - if ( - lazyInitGetterStack === null || - lazyInitGetterStack !== getCallerStackFrame() - ) { - didWarnAboutRead = true; - - warn( - "%s: Unsafe read of a mutable value during render.\n\n" + - "Reading from a ref during render is only safe if:\n" + - "1. The ref value has not been updated, or\n" + - "2. The ref holds a lazily-initialized value that is only set once.\n", - getComponentNameFromFiber(currentlyRenderingFiber$1) || - "Unknown" - ); - } - } - - return current; - }, + error( + "%s received a final argument during this render, but not during " + + "the previous render. Even though the final argument is optional, " + + "its type cannot change between renders.", + currentHookNameInDev + ); + } - set current(value) { - if (currentlyRenderingFiber$1 !== null && !didWarnAboutWrite) { - if (hasBeenInitialized || !didCheckForLazyInit) { - didWarnAboutWrite = true; + return false; + } - warn( - "%s: Unsafe write of a mutable value during render.\n\n" + - "Writing to a ref during render is only safe if the ref holds " + - "a lazily-initialized value that is only set once.\n", - getComponentNameFromFiber(currentlyRenderingFiber$1) || - "Unknown" - ); - } - } + { + // Don't bother comparing lengths in prod because these arrays should be + // passed inline. + if (nextDeps.length !== prevDeps.length) { + error( + "The final argument passed to %s changed size between renders. The " + + "order and size of this array must remain constant.\n\n" + + "Previous: %s\n" + + "Incoming: %s", + currentHookNameInDev, + "[" + prevDeps.join(", ") + "]", + "[" + nextDeps.join(", ") + "]" + ); + } + } // $FlowFixMe[incompatible-use] found when upgrading Flow - hasBeenInitialized = true; - current = value; - } - }; - Object.seal(ref); - hook.memoizedState = ref; - return ref; + for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++) { + // $FlowFixMe[incompatible-use] found when upgrading Flow + if (objectIs(nextDeps[i], prevDeps[i])) { + continue; } - } else { - var _ref2 = { - current: initialValue - }; - hook.memoizedState = _ref2; - return _ref2; + + return false; } -} -function updateRef(initialValue) { - var hook = updateWorkInProgressHook(); - return hook.memoizedState; + return true; } -function mountEffectImpl(fiberFlags, hookFlags, create, deps) { - var hook = mountWorkInProgressHook(); - var nextDeps = deps === undefined ? null : deps; - currentlyRenderingFiber$1.flags |= fiberFlags; - hook.memoizedState = pushEffect( - HasEffect | hookFlags, - create, - undefined, - nextDeps - ); -} +function renderWithHooks( + current, + workInProgress, + Component, + props, + secondArg, + nextRenderLanes +) { + renderLanes$1 = nextRenderLanes; + currentlyRenderingFiber$1 = workInProgress; -function updateEffectImpl(fiberFlags, hookFlags, create, deps) { - var hook = updateWorkInProgressHook(); - var nextDeps = deps === undefined ? null : deps; - var destroy = undefined; // currentHook is null when rerendering after a render phase state update. + { + hookTypesDev = current !== null ? current._debugHookTypes : null; + hookTypesUpdateIndexDev = -1; // Used for hot reloading: - if (currentHook !== null) { - var prevEffect = currentHook.memoizedState; - destroy = prevEffect.destroy; + ignorePreviousDependencies = + current !== null && current.type !== workInProgress.type; + } - if (nextDeps !== null) { - var prevDeps = prevEffect.deps; + workInProgress.memoizedState = null; + workInProgress.updateQueue = null; + workInProgress.lanes = NoLanes; // The following should have already been reset + // currentHook = null; + // workInProgressHook = null; + // didScheduleRenderPhaseUpdate = false; + // localIdCounter = 0; + // thenableIndexCounter = 0; + // thenableState = null; + // TODO Warn if no hooks are used at all during mount, then some are used during update. + // Currently we will identify the update render as a mount because memoizedState === null. + // This is tricky because it's valid for certain types of components (e.g. React.lazy) + // Using memoizedState to differentiate between mount/update only works if at least one stateful hook is used. + // Non-stateful hooks (e.g. context) don't get added to memoizedState, + // so memoizedState would be null during updates and mounts. - if (areHookInputsEqual(nextDeps, prevDeps)) { - hook.memoizedState = pushEffect(hookFlags, create, destroy, nextDeps); - return; - } + { + if (current !== null && current.memoizedState !== null) { + ReactCurrentDispatcher$1.current = HooksDispatcherOnUpdateInDEV; + } else if (hookTypesDev !== null) { + // This dispatcher handles an edge case where a component is updating, + // but no stateful hooks have been used. + // We want to match the production code behavior (which will use HooksDispatcherOnMount), + // but with the extra DEV validation to ensure hooks ordering hasn't changed. + // This dispatcher does that. + ReactCurrentDispatcher$1.current = + HooksDispatcherOnMountWithHookTypesInDEV; + } else { + ReactCurrentDispatcher$1.current = HooksDispatcherOnMountInDEV; } - } + } // In Strict Mode, during development, user functions are double invoked to + // help detect side effects. The logic for how this is implemented for in + // hook components is a bit complex so let's break it down. + // + // We will invoke the entire component function twice. However, during the + // second invocation of the component, the hook state from the first + // invocation will be reused. That means things like `useMemo` functions won't + // run again, because the deps will match and the memoized result will + // be reused. + // + // We want memoized functions to run twice, too, so account for this, user + // functions are double invoked during the *first* invocation of the component + // function, and are *not* double invoked during the second incovation: + // + // - First execution of component function: user functions are double invoked + // - Second execution of component function (in Strict Mode, during + // development): user functions are not double invoked. + // + // This is intentional for a few reasons; most importantly, it's because of + // how `use` works when something suspends: it reuses the promise that was + // passed during the first attempt. This is itself a form of memoization. + // We need to be able to memoize the reactive inputs to the `use` call using + // a hook (i.e. `useMemo`), which means, the reactive inputs to `use` must + // come from the same component invocation as the output. + // + // There are plenty of tests to ensure this behavior is correct. - currentlyRenderingFiber$1.flags |= fiberFlags; - hook.memoizedState = pushEffect( - HasEffect | hookFlags, - create, - destroy, - nextDeps - ); -} + var shouldDoubleRenderDEV = + (workInProgress.mode & StrictLegacyMode) !== NoMode; + shouldDoubleInvokeUserFnsInHooksDEV = shouldDoubleRenderDEV; + var children = Component(props, secondArg); + shouldDoubleInvokeUserFnsInHooksDEV = false; // Check if there was a render phase update -function mountEffect(create, deps) { - if ((currentlyRenderingFiber$1.mode & StrictEffectsMode) !== NoMode) { - mountEffectImpl( - MountPassiveDev | Passive$1 | PassiveStatic, - Passive, - create, - deps + if (didScheduleRenderPhaseUpdateDuringThisPass) { + // Keep rendering until the component stabilizes (there are no more render + // phase updates). + children = renderWithHooksAgain( + workInProgress, + Component, + props, + secondArg ); - } else { - mountEffectImpl(Passive$1 | PassiveStatic, Passive, create, deps); } -} - -function updateEffect(create, deps) { - updateEffectImpl(Passive$1, Passive, create, deps); -} - -function mountInsertionEffect(create, deps) { - mountEffectImpl(Update, Insertion, create, deps); -} - -function updateInsertionEffect(create, deps) { - return updateEffectImpl(Update, Insertion, create, deps); -} -function mountLayoutEffect(create, deps) { - var fiberFlags = Update | LayoutStatic; + if (shouldDoubleRenderDEV) { + // In development, components are invoked twice to help detect side effects. + setIsStrictModeForDevtools(true); - if ((currentlyRenderingFiber$1.mode & StrictEffectsMode) !== NoMode) { - fiberFlags |= MountLayoutDev; + try { + children = renderWithHooksAgain( + workInProgress, + Component, + props, + secondArg + ); + } finally { + setIsStrictModeForDevtools(false); + } } - return mountEffectImpl(fiberFlags, Layout, create, deps); -} - -function updateLayoutEffect(create, deps) { - return updateEffectImpl(Update, Layout, create, deps); + finishRenderingHooks(current, workInProgress); + return children; } -function imperativeHandleEffect(create, ref) { - if (typeof ref === "function") { - var refCallback = ref; - var inst = create(); - refCallback(inst); - return function () { - refCallback(null); - }; - } else if (ref !== null && ref !== undefined) { - var refObject = ref; - - { - if (!refObject.hasOwnProperty("current")) { - error( - "Expected useImperativeHandle() first argument to either be a " + - "ref callback or React.createRef() object. Instead received: %s.", - "an object with keys {" + Object.keys(refObject).join(", ") + "}" - ); - } - } - - var _inst = create(); - - refObject.current = _inst; - return function () { - refObject.current = null; - }; - } -} +function finishRenderingHooks(current, workInProgress) { + // We can assume the previous dispatcher is always this one, since we set it + // at the beginning of the render phase and there's no re-entrance. + ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; -function mountImperativeHandle(ref, create, deps) { { - if (typeof create !== "function") { - error( - "Expected useImperativeHandle() second argument to be a function " + - "that creates a handle. Instead received: %s.", - create !== null ? typeof create : "null" - ); - } - } // TODO: If deps are provided, should we skip comparing the ref itself? - - var effectDeps = - deps !== null && deps !== undefined ? deps.concat([ref]) : null; - var fiberFlags = Update | LayoutStatic; - - if ((currentlyRenderingFiber$1.mode & StrictEffectsMode) !== NoMode) { - fiberFlags |= MountLayoutDev; - } + workInProgress._debugHookTypes = hookTypesDev; + } // This check uses currentHook so that it works the same in DEV and prod bundles. + // hookTypesDev could catch more cases (e.g. context) but only in DEV bundles. - mountEffectImpl( - fiberFlags, - Layout, - imperativeHandleEffect.bind(null, create, ref), - effectDeps - ); -} + var didRenderTooFewHooks = currentHook !== null && currentHook.next !== null; + renderLanes$1 = NoLanes; + currentlyRenderingFiber$1 = null; + currentHook = null; + workInProgressHook = null; -function updateImperativeHandle(ref, create, deps) { { - if (typeof create !== "function") { + currentHookNameInDev = null; + hookTypesDev = null; + hookTypesUpdateIndexDev = -1; // Confirm that a static flag was not added or removed since the last + // render. If this fires, it suggests that we incorrectly reset the static + // flags in some other part of the codebase. This has happened before, for + // example, in the SuspenseList implementation. + + if ( + current !== null && + (current.flags & StaticMask) !== (workInProgress.flags & StaticMask) && // Disable this warning in legacy mode, because legacy Suspense is weird + // and creates false positives. To make this work in legacy mode, we'd + // need to mark fibers that commit in an incomplete state, somehow. For + // now I'll disable the warning that most of the bugs that would trigger + // it are either exclusive to concurrent mode or exist in both. + (current.mode & ConcurrentMode) !== NoMode + ) { error( - "Expected useImperativeHandle() second argument to be a function " + - "that creates a handle. Instead received: %s.", - create !== null ? typeof create : "null" + "Internal React error: Expected static flag was missing. Please " + + "notify the React team." ); } - } // TODO: If deps are provided, should we skip comparing the ref itself? - - var effectDeps = - deps !== null && deps !== undefined ? deps.concat([ref]) : null; - updateEffectImpl( - Update, - Layout, - imperativeHandleEffect.bind(null, create, ref), - effectDeps - ); -} + } -function mountDebugValue(value, formatterFn) { - // This hook is normally a no-op. - // The react-debug-hooks package injects its own implementation - // so that e.g. DevTools can display custom hook values. -} + didScheduleRenderPhaseUpdate = false; // This is reset by checkDidRenderIdHook + // localIdCounter = 0; -var updateDebugValue = mountDebugValue; + thenableIndexCounter = 0; + thenableState = null; -function mountCallback(callback, deps) { - var hook = mountWorkInProgressHook(); - var nextDeps = deps === undefined ? null : deps; - hook.memoizedState = [callback, nextDeps]; - return callback; -} + if (didRenderTooFewHooks) { + throw new Error( + "Rendered fewer hooks than expected. This may be caused by an accidental " + + "early return statement." + ); + } -function updateCallback(callback, deps) { - var hook = updateWorkInProgressHook(); - var nextDeps = deps === undefined ? null : deps; - var prevState = hook.memoizedState; + { + if (checkIfUseWrappedInTryCatch()) { + var componentName = + getComponentNameFromFiber(workInProgress) || "Unknown"; - if (nextDeps !== null) { - var prevDeps = prevState[1]; + if (!didWarnAboutUseWrappedInTryCatch.has(componentName)) { + didWarnAboutUseWrappedInTryCatch.add(componentName); - if (areHookInputsEqual(nextDeps, prevDeps)) { - return prevState[0]; + error( + "`use` was called from inside a try/catch block. This is not allowed " + + "and can lead to unexpected behavior. To handle errors triggered " + + "by `use`, wrap your component in a error boundary." + ); + } } } - - hook.memoizedState = [callback, nextDeps]; - return callback; } -function mountMemo(nextCreate, deps) { - var hook = mountWorkInProgressHook(); - var nextDeps = deps === undefined ? null : deps; +function replaySuspendedComponentWithHooks( + current, + workInProgress, + Component, + props, + secondArg +) { + // This function is used to replay a component that previously suspended, + // after its data resolves. + // + // It's a simplified version of renderWithHooks, but it doesn't need to do + // most of the set up work because they weren't reset when we suspended; they + // only get reset when the component either completes (finishRenderingHooks) + // or unwinds (resetHooksOnUnwind). + { + hookTypesUpdateIndexDev = -1; // Used for hot reloading: - if (shouldDoubleInvokeUserFnsInHooksDEV) { - nextCreate(); + ignorePreviousDependencies = + current !== null && current.type !== workInProgress.type; } - var nextValue = nextCreate(); - hook.memoizedState = [nextValue, nextDeps]; - return nextValue; + var children = renderWithHooksAgain( + workInProgress, + Component, + props, + secondArg + ); + finishRenderingHooks(current, workInProgress); + return children; } -function updateMemo(nextCreate, deps) { - var hook = updateWorkInProgressHook(); - var nextDeps = deps === undefined ? null : deps; - var prevState = hook.memoizedState; // Assume these are defined. If they're not, areHookInputsEqual will warn. +function renderWithHooksAgain(workInProgress, Component, props, secondArg) { + // This is used to perform another render pass. It's used when setState is + // called during render, and for double invoking components in Strict Mode + // during development. + // + // The state from the previous pass is reused whenever possible. So, state + // updates that were already processed are not processed again, and memoized + // functions (`useMemo`) are not invoked again. + // + // Keep rendering in a loop for as long as render phase updates continue to + // be scheduled. Use a counter to prevent infinite loops. + var numberOfReRenders = 0; + var children; - if (nextDeps !== null) { - var prevDeps = prevState[1]; + do { + if (didScheduleRenderPhaseUpdateDuringThisPass) { + // It's possible that a use() value depended on a state that was updated in + // this rerender, so we need to watch for different thenables this time. + thenableState = null; + } - if (areHookInputsEqual(nextDeps, prevDeps)) { - return prevState[0]; + thenableIndexCounter = 0; + didScheduleRenderPhaseUpdateDuringThisPass = false; + + if (numberOfReRenders >= RE_RENDER_LIMIT) { + throw new Error( + "Too many re-renders. React limits the number of renders to prevent " + + "an infinite loop." + ); } - } - if (shouldDoubleInvokeUserFnsInHooksDEV) { - nextCreate(); - } + numberOfReRenders += 1; - var nextValue = nextCreate(); - hook.memoizedState = [nextValue, nextDeps]; - return nextValue; -} + { + // Even when hot reloading, allow dependencies to stabilize + // after first render to prevent infinite render phase updates. + ignorePreviousDependencies = false; + } // Start over from the beginning of the list -function mountDeferredValue(value) { - var hook = mountWorkInProgressHook(); - hook.memoizedState = value; - return value; -} + currentHook = null; + workInProgressHook = null; + workInProgress.updateQueue = null; -function updateDeferredValue(value) { - var hook = updateWorkInProgressHook(); - var resolvedCurrentHook = currentHook; - var prevValue = resolvedCurrentHook.memoizedState; - return updateDeferredValueImpl(hook, prevValue, value); -} + { + // Also validate hook order for cascading updates. + hookTypesUpdateIndexDev = -1; + } -function rerenderDeferredValue(value) { - var hook = updateWorkInProgressHook(); + ReactCurrentDispatcher$1.current = HooksDispatcherOnRerenderInDEV; + children = Component(props, secondArg); + } while (didScheduleRenderPhaseUpdateDuringThisPass); - if (currentHook === null) { - // This is a rerender during a mount. - hook.memoizedState = value; - return value; + return children; +} +function bailoutHooks(current, workInProgress, lanes) { + workInProgress.updateQueue = current.updateQueue; // TODO: Don't need to reset the flags here, because they're reset in the + // complete phase (bubbleProperties). + + if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { + workInProgress.flags &= ~( + MountPassiveDev | + MountLayoutDev | + Passive$1 | + Update + ); } else { - // This is a rerender during an update. - var prevValue = currentHook.memoizedState; - return updateDeferredValueImpl(hook, prevValue, value); + workInProgress.flags &= ~(Passive$1 | Update); } -} -function updateDeferredValueImpl(hook, prevValue, value) { - var shouldDeferValue = !includesOnlyNonUrgentLanes(renderLanes$1); + current.lanes = removeLanes(current.lanes, lanes); +} +function resetHooksAfterThrow() { + // This is called immediaetly after a throw. It shouldn't reset the entire + // module state, because the work loop might decide to replay the component + // again without rewinding. + // + // It should only reset things like the current dispatcher, to prevent hooks + // from being called outside of a component. + // We can assume the previous dispatcher is always this one, since we set it + // at the beginning of the render phase and there's no re-entrance. + ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; +} +function resetHooksOnUnwind() { + if (didScheduleRenderPhaseUpdate) { + // There were render phase updates. These are only valid for this render + // phase, which we are now aborting. Remove the updates from the queues so + // they do not persist to the next render. Do not remove updates from hooks + // that weren't processed. + // + // Only reset the updates from the queue if it has a clone. If it does + // not have a clone, that means it wasn't processed, and the updates were + // scheduled before we entered the render phase. + var hook = currentlyRenderingFiber$1.memoizedState; - if (shouldDeferValue) { - // This is an urgent update. If the value has changed, keep using the - // previous value and spawn a deferred render to update it later. - if (!objectIs(value, prevValue)) { - // Schedule a deferred render - var deferredLane = claimNextTransitionLane(); - currentlyRenderingFiber$1.lanes = mergeLanes( - currentlyRenderingFiber$1.lanes, - deferredLane - ); - markSkippedUpdateLanes(deferredLane); // Set this to true to indicate that the rendered value is inconsistent - // from the latest value. The name "baseState" doesn't really match how we - // use it because we're reusing a state hook field instead of creating a - // new one. + while (hook !== null) { + var queue = hook.queue; - hook.baseState = true; - } // Reuse the previous value + if (queue !== null) { + queue.pending = null; + } - return prevValue; - } else { - // This is not an urgent update, so we can use the latest value regardless - // of what it is. No need to defer it. - // However, if we're currently inside a spawned render, then we need to mark - // this as an update to prevent the fiber from bailing out. - // - // `baseState` is true when the current value is different from the rendered - // value. The name doesn't really match how we use it because we're reusing - // a state hook field instead of creating a new one. - if (hook.baseState) { - // Flip this back to false. - hook.baseState = false; - markWorkInProgressReceivedUpdate(); + hook = hook.next; } - hook.memoizedState = value; - return value; + didScheduleRenderPhaseUpdate = false; } -} -function startTransition(setPending, callback, options) { - var previousPriority = getCurrentUpdatePriority(); - setCurrentUpdatePriority( - higherEventPriority(previousPriority, ContinuousEventPriority) - ); - var prevTransition = ReactCurrentBatchConfig$2.transition; - ReactCurrentBatchConfig$2.transition = null; - setPending(true); - var currentTransition = (ReactCurrentBatchConfig$2.transition = {}); + renderLanes$1 = NoLanes; + currentlyRenderingFiber$1 = null; + currentHook = null; + workInProgressHook = null; { - ReactCurrentBatchConfig$2.transition._updatedFibers = new Set(); - } - - try { - setPending(false); - callback(); - } finally { - setCurrentUpdatePriority(previousPriority); - ReactCurrentBatchConfig$2.transition = prevTransition; - - { - if (prevTransition === null && currentTransition._updatedFibers) { - var updatedFibersCount = currentTransition._updatedFibers.size; - - currentTransition._updatedFibers.clear(); - - if (updatedFibersCount > 10) { - warn( - "Detected a large number of updates inside startTransition. " + - "If this is due to a subscription please re-write it to use React provided hooks. " + - "Otherwise concurrent mode guarantees are off the table." - ); - } - } - } + hookTypesDev = null; + hookTypesUpdateIndexDev = -1; + currentHookNameInDev = null; } -} - -function mountTransition() { - var _mountState = mountState(false), - isPending = _mountState[0], - setPending = _mountState[1]; // The `start` method never changes. - - var start = startTransition.bind(null, setPending); - var hook = mountWorkInProgressHook(); - hook.memoizedState = start; - return [isPending, start]; -} - -function updateTransition() { - var _updateState = updateState(), - isPending = _updateState[0]; - - var hook = updateWorkInProgressHook(); - var start = hook.memoizedState; - return [isPending, start]; -} - -function rerenderTransition() { - var _rerenderState = rerenderState(), - isPending = _rerenderState[0]; - var hook = updateWorkInProgressHook(); - var start = hook.memoizedState; - return [isPending, start]; + didScheduleRenderPhaseUpdateDuringThisPass = false; + thenableIndexCounter = 0; + thenableState = null; } -function mountId() { - var hook = mountWorkInProgressHook(); - var root = getWorkInProgressRoot(); // TODO: In Fizz, id generation is specific to each server config. Maybe we - // should do this in Fiber, too? Deferring this decision for now because - // there's no other place to store the prefix except for an internal field on - // the public createRoot object, which the fiber tree does not currently have - // a reference to. - - var identifierPrefix = root.identifierPrefix; - var id; +function mountWorkInProgressHook() { + var hook = { + memoizedState: null, + baseState: null, + baseQueue: null, + queue: null, + next: null + }; - { - // Use a lowercase r prefix for client-generated ids. - var globalClientId = globalClientIdCounter++; - id = ":" + identifierPrefix + "r" + globalClientId.toString(32) + ":"; + if (workInProgressHook === null) { + // This is the first hook in the list + currentlyRenderingFiber$1.memoizedState = workInProgressHook = hook; + } else { + // Append to the end of the list + workInProgressHook = workInProgressHook.next = hook; } - hook.memoizedState = id; - return id; + return workInProgressHook; } -function updateId() { - var hook = updateWorkInProgressHook(); - var id = hook.memoizedState; - return id; -} +function updateWorkInProgressHook() { + // This function is used both for updates and for re-renders triggered by a + // render phase update. It assumes there is either a current hook we can + // clone, or a work-in-progress hook from a previous render pass that we can + // use as a base. + var nextCurrentHook; -function dispatchReducerAction(fiber, queue, action) { - { - if (typeof arguments[3] === "function") { - error( - "State updates from the useState() and useReducer() Hooks don't support the " + - "second callback argument. To execute a side effect after " + - "rendering, declare it in the component body with useEffect()." - ); + if (currentHook === null) { + var current = currentlyRenderingFiber$1.alternate; + + if (current !== null) { + nextCurrentHook = current.memoizedState; + } else { + nextCurrentHook = null; } + } else { + nextCurrentHook = currentHook.next; } - var lane = requestUpdateLane(fiber); - var update = { - lane: lane, - action: action, - hasEagerState: false, - eagerState: null, - next: null - }; + var nextWorkInProgressHook; - if (isRenderPhaseUpdate(fiber)) { - enqueueRenderPhaseUpdate(queue, update); + if (workInProgressHook === null) { + nextWorkInProgressHook = currentlyRenderingFiber$1.memoizedState; } else { - var root = enqueueConcurrentHookUpdate(fiber, queue, update, lane); - - if (root !== null) { - var eventTime = requestEventTime(); - scheduleUpdateOnFiber(root, fiber, lane, eventTime); - entangleTransitionUpdate(root, queue, lane); - } + nextWorkInProgressHook = workInProgressHook.next; } - markUpdateInDevTools(fiber, lane); -} + if (nextWorkInProgressHook !== null) { + // There's already a work-in-progress. Reuse it. + workInProgressHook = nextWorkInProgressHook; + nextWorkInProgressHook = workInProgressHook.next; + currentHook = nextCurrentHook; + } else { + // Clone from the current hook. + if (nextCurrentHook === null) { + var currentFiber = currentlyRenderingFiber$1.alternate; -function dispatchSetState(fiber, queue, action) { - { - if (typeof arguments[3] === "function") { - error( - "State updates from the useState() and useReducer() Hooks don't support the " + - "second callback argument. To execute a side effect after " + - "rendering, declare it in the component body with useEffect()." - ); + if (currentFiber === null) { + // This is the initial render. This branch is reached when the component + // suspends, resumes, then renders an additional hook. + // Should never be reached because we should switch to the mount dispatcher first. + throw new Error( + "Update hook called on initial render. This is likely a bug in React. Please file an issue." + ); + } else { + // This is an update. We should always have a current hook. + throw new Error("Rendered more hooks than during the previous render."); + } + } + + currentHook = nextCurrentHook; + var newHook = { + memoizedState: currentHook.memoizedState, + baseState: currentHook.baseState, + baseQueue: currentHook.baseQueue, + queue: currentHook.queue, + next: null + }; + + if (workInProgressHook === null) { + // This is the first hook in the list. + currentlyRenderingFiber$1.memoizedState = workInProgressHook = newHook; + } else { + // Append to the end of the list. + workInProgressHook = workInProgressHook.next = newHook; } } - var lane = requestUpdateLane(fiber); - var update = { - lane: lane, - action: action, - hasEagerState: false, - eagerState: null, - next: null - }; + return workInProgressHook; +} // NOTE: defining two versions of this function to avoid size impact when this feature is disabled. +// Previously this function was inlined, the additional `memoCache` property makes it not inlined. - if (isRenderPhaseUpdate(fiber)) { - enqueueRenderPhaseUpdate(queue, update); - } else { - var alternate = fiber.alternate; +var createFunctionComponentUpdateQueue; - if ( - fiber.lanes === NoLanes && - (alternate === null || alternate.lanes === NoLanes) - ) { - // The queue is currently empty, which means we can eagerly compute the - // next state before entering the render phase. If the new state is the - // same as the current state, we may be able to bail out entirely. - var lastRenderedReducer = queue.lastRenderedReducer; +{ + createFunctionComponentUpdateQueue = function () { + return { + lastEffect: null, + events: null, + stores: null, + memoCache: null + }; + }; +} - if (lastRenderedReducer !== null) { - var prevDispatcher; +function use(usable) { + if (usable !== null && typeof usable === "object") { + // $FlowFixMe[method-unbinding] + if (typeof usable.then === "function") { + // This is a thenable. + var thenable = usable; // Track the position of the thenable within this fiber. - { - prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnUpdateInDEV; - } + var index = thenableIndexCounter; + thenableIndexCounter += 1; - try { - var currentState = queue.lastRenderedState; - var eagerState = lastRenderedReducer(currentState, action); // Stash the eagerly computed state, and the reducer used to compute - // it, on the update object. If the reducer hasn't changed by the - // time we enter the render phase, then the eager state can be used - // without calling the reducer again. + if (thenableState === null) { + thenableState = createThenableState(); + } - update.hasEagerState = true; - update.eagerState = eagerState; + var result = trackUsedThenable(thenableState, thenable, index); - if (objectIs(eagerState, currentState)) { - // Fast path. We can bail out without scheduling React to re-render. - // It's still possible that we'll need to rebase this update later, - // if the component re-renders for a different reason and by that - // time the reducer has changed. - // TODO: Do we still need to entangle transitions in this case? - enqueueConcurrentHookUpdateAndEagerlyBailout(fiber, queue, update); - return; - } - } catch (error) { - // Suppress the error. It will throw again in the render phase. - } finally { - { - ReactCurrentDispatcher$1.current = prevDispatcher; - } + if ( + currentlyRenderingFiber$1.alternate === null && + (workInProgressHook === null + ? currentlyRenderingFiber$1.memoizedState === null + : workInProgressHook.next === null) + ) { + // Initial render, and either this is the first time the component is + // called, or there were no Hooks called after this use() the previous + // time (perhaps because it threw). Subsequent Hook calls should use the + // mount dispatcher. + { + ReactCurrentDispatcher$1.current = HooksDispatcherOnMountInDEV; } } - } - - var root = enqueueConcurrentHookUpdate(fiber, queue, update, lane); - if (root !== null) { - var eventTime = requestEventTime(); - scheduleUpdateOnFiber(root, fiber, lane, eventTime); - entangleTransitionUpdate(root, queue, lane); + return result; + } else if ( + usable.$$typeof === REACT_CONTEXT_TYPE || + usable.$$typeof === REACT_SERVER_CONTEXT_TYPE + ) { + var context = usable; + return readContext(context); } - } + } // eslint-disable-next-line react-internal/safe-string-coercion - markUpdateInDevTools(fiber, lane); + throw new Error("An unsupported type was passed to use(): " + String(usable)); } -function isRenderPhaseUpdate(fiber) { - var alternate = fiber.alternate; - return ( - fiber === currentlyRenderingFiber$1 || - (alternate !== null && alternate === currentlyRenderingFiber$1) - ); -} +function useMemoCache(size) { + var memoCache = null; // Fast-path, load memo cache from wip fiber if already prepared -function enqueueRenderPhaseUpdate(queue, update) { - // This is a render phase update. Stash it in a lazily-created map of - // queue -> linked list of updates. After this render pass, we'll restart - // and apply the stashed updates on top of the work-in-progress hook. - didScheduleRenderPhaseUpdateDuringThisPass = didScheduleRenderPhaseUpdate = - true; - var pending = queue.pending; + var updateQueue = currentlyRenderingFiber$1.updateQueue; - if (pending === null) { - // This is the first update. Create a circular list. - update.next = update; - } else { - update.next = pending.next; - pending.next = update; - } + if (updateQueue !== null) { + memoCache = updateQueue.memoCache; + } // Otherwise clone from the current fiber - queue.pending = update; -} // TODO: Move to ReactFiberConcurrentUpdates? + if (memoCache == null) { + var current = currentlyRenderingFiber$1.alternate; -function entangleTransitionUpdate(root, queue, lane) { - if (isTransitionLane(lane)) { - var queueLanes = queue.lanes; // If any entangled lanes are no longer pending on the root, then they - // must have finished. We can remove them from the shared queue, which - // represents a superset of the actually pending lanes. In some cases we - // may entangle more than we need to, but that's OK. In fact it's worse if - // we *don't* entangle when we should. + if (current !== null) { + var currentUpdateQueue = current.updateQueue; - queueLanes = intersectLanes(queueLanes, root.pendingLanes); // Entangle the new transition lane with the other transition lanes. + if (currentUpdateQueue !== null) { + var currentMemoCache = currentUpdateQueue.memoCache; - var newQueueLanes = mergeLanes(queueLanes, lane); - queue.lanes = newQueueLanes; // Even if queue.lanes already include lane, we don't know for certain if - // the lane finished since the last time we entangled it. So we need to - // entangle it again, just to be sure. + if (currentMemoCache != null) { + memoCache = { + data: currentMemoCache.data.map(function (array) { + return array.slice(); + }), + index: 0 + }; + } + } + } + } // Finally fall back to allocating a fresh instance of the cache - markRootEntangled(root, newQueueLanes); + if (memoCache == null) { + memoCache = { + data: [], + index: 0 + }; } -} -function markUpdateInDevTools(fiber, lane, action) { - { - markStateUpdateScheduled(fiber, lane); + if (updateQueue === null) { + updateQueue = createFunctionComponentUpdateQueue(); + currentlyRenderingFiber$1.updateQueue = updateQueue; } -} - -var ContextOnlyDispatcher = { - readContext: readContext, - useCallback: throwInvalidHookError, - useContext: throwInvalidHookError, - useEffect: throwInvalidHookError, - useImperativeHandle: throwInvalidHookError, - useInsertionEffect: throwInvalidHookError, - useLayoutEffect: throwInvalidHookError, - useMemo: throwInvalidHookError, - useReducer: throwInvalidHookError, - useRef: throwInvalidHookError, - useState: throwInvalidHookError, - useDebugValue: throwInvalidHookError, - useDeferredValue: throwInvalidHookError, - useTransition: throwInvalidHookError, - useMutableSource: throwInvalidHookError, - useSyncExternalStore: throwInvalidHookError, - useId: throwInvalidHookError -}; -{ - ContextOnlyDispatcher.use = throwInvalidHookError; -} + updateQueue.memoCache = memoCache; + var data = memoCache.data[memoCache.index]; -{ - ContextOnlyDispatcher.useMemoCache = throwInvalidHookError; -} + if (data === undefined) { + data = memoCache.data[memoCache.index] = new Array(size); -var HooksDispatcherOnMountInDEV = null; -var HooksDispatcherOnMountWithHookTypesInDEV = null; -var HooksDispatcherOnUpdateInDEV = null; -var HooksDispatcherOnRerenderInDEV = null; -var InvalidNestedHooksDispatcherOnMountInDEV = null; -var InvalidNestedHooksDispatcherOnUpdateInDEV = null; -var InvalidNestedHooksDispatcherOnRerenderInDEV = null; + for (var i = 0; i < size; i++) { + data[i] = REACT_MEMO_CACHE_SENTINEL; + } + } else if (data.length !== size) { + // TODO: consider warning or throwing here + { + error( + "Expected a constant size argument for each invocation of useMemoCache. " + + "The previous cache was allocated with size %s but size %s was requested.", + data.length, + size + ); + } + } -{ - var warnInvalidContextAccess = function () { - error( - "Context can only be read while React is rendering. " + - "In classes, you can read it in the render method or getDerivedStateFromProps. " + - "In function components, you can read it directly in the function body, but not " + - "inside Hooks like useReducer() or useMemo()." - ); + memoCache.index++; + return data; +} + +function basicStateReducer(state, action) { + // $FlowFixMe: Flow doesn't like mixed types + return typeof action === "function" ? action(state) : action; +} + +function mountReducer(reducer, initialArg, init) { + var hook = mountWorkInProgressHook(); + var initialState; + + if (init !== undefined) { + initialState = init(initialArg); + } else { + initialState = initialArg; + } + + hook.memoizedState = hook.baseState = initialState; + var queue = { + pending: null, + lanes: NoLanes, + dispatch: null, + lastRenderedReducer: reducer, + lastRenderedState: initialState }; + hook.queue = queue; + var dispatch = (queue.dispatch = dispatchReducerAction.bind( + null, + currentlyRenderingFiber$1, + queue + )); + return [hook.memoizedState, dispatch]; +} - var warnInvalidHookAccess = function () { - error( - "Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. " + - "You can only call Hooks at the top level of your React function. " + - "For more information, see " + - "https://reactjs.org/link/rules-of-hooks" +function updateReducer(reducer, initialArg, init) { + var hook = updateWorkInProgressHook(); + var queue = hook.queue; + + if (queue === null) { + throw new Error( + "Should have a queue. This is likely a bug in React. Please file an issue." ); - }; + } - HooksDispatcherOnMountInDEV = { - readContext: function (context) { - return readContext(context); - }, - useCallback: function (callback, deps) { - currentHookNameInDev = "useCallback"; - mountHookTypesDev(); - checkDepsAreArrayDev(deps); - return mountCallback(callback, deps); - }, - useContext: function (context) { - currentHookNameInDev = "useContext"; - mountHookTypesDev(); - return readContext(context); - }, - useEffect: function (create, deps) { - currentHookNameInDev = "useEffect"; - mountHookTypesDev(); - checkDepsAreArrayDev(deps); - return mountEffect(create, deps); - }, - useImperativeHandle: function (ref, create, deps) { - currentHookNameInDev = "useImperativeHandle"; - mountHookTypesDev(); - checkDepsAreArrayDev(deps); - return mountImperativeHandle(ref, create, deps); - }, - useInsertionEffect: function (create, deps) { - currentHookNameInDev = "useInsertionEffect"; - mountHookTypesDev(); - checkDepsAreArrayDev(deps); - return mountInsertionEffect(create, deps); - }, - useLayoutEffect: function (create, deps) { - currentHookNameInDev = "useLayoutEffect"; - mountHookTypesDev(); - checkDepsAreArrayDev(deps); - return mountLayoutEffect(create, deps); - }, - useMemo: function (create, deps) { - currentHookNameInDev = "useMemo"; - mountHookTypesDev(); - checkDepsAreArrayDev(deps); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnMountInDEV; + queue.lastRenderedReducer = reducer; + var current = currentHook; // The last rebase update that is NOT part of the base state. - try { - return mountMemo(create, deps); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; - } - }, - useReducer: function (reducer, initialArg, init) { - currentHookNameInDev = "useReducer"; - mountHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnMountInDEV; + var baseQueue = current.baseQueue; // The last pending update that hasn't been processed yet. - try { - return mountReducer(reducer, initialArg, init); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; - } - }, - useRef: function (initialValue) { - currentHookNameInDev = "useRef"; - mountHookTypesDev(); - return mountRef(initialValue); - }, - useState: function (initialState) { - currentHookNameInDev = "useState"; - mountHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnMountInDEV; + var pendingQueue = queue.pending; - try { - return mountState(initialState); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; + if (pendingQueue !== null) { + // We have new updates that haven't been processed yet. + // We'll add them to the base queue. + if (baseQueue !== null) { + // Merge the pending queue and the base queue. + var baseFirst = baseQueue.next; + var pendingFirst = pendingQueue.next; + baseQueue.next = pendingFirst; + pendingQueue.next = baseFirst; + } + + { + if (current.baseQueue !== baseQueue) { + // Internal invariant that should never happen, but feasibly could in + // the future if we implement resuming, or some form of that. + error( + "Internal error: Expected work-in-progress queue to be a clone. " + + "This is a bug in React." + ); } - }, - useDebugValue: function (value, formatterFn) { - currentHookNameInDev = "useDebugValue"; - mountHookTypesDev(); - return mountDebugValue(); - }, - useDeferredValue: function (value) { - currentHookNameInDev = "useDeferredValue"; - mountHookTypesDev(); - return mountDeferredValue(value); - }, - useTransition: function () { - currentHookNameInDev = "useTransition"; - mountHookTypesDev(); - return mountTransition(); - }, - useMutableSource: function (source, getSnapshot, subscribe) { - currentHookNameInDev = "useMutableSource"; - mountHookTypesDev(); - return mountMutableSource(source, getSnapshot, subscribe); - }, - useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { - currentHookNameInDev = "useSyncExternalStore"; - mountHookTypesDev(); - return mountSyncExternalStore(subscribe, getSnapshot); - }, - useId: function () { - currentHookNameInDev = "useId"; - mountHookTypesDev(); - return mountId(); } - }; - { - HooksDispatcherOnMountInDEV.use = use; + current.baseQueue = baseQueue = pendingQueue; + queue.pending = null; } - { - HooksDispatcherOnMountInDEV.useMemoCache = useMemoCache; - } + if (baseQueue !== null) { + // We have a queue to process. + var first = baseQueue.next; + var newState = current.baseState; + var newBaseState = null; + var newBaseQueueFirst = null; + var newBaseQueueLast = null; + var update = first; - HooksDispatcherOnMountWithHookTypesInDEV = { - readContext: function (context) { - return readContext(context); - }, - useCallback: function (callback, deps) { - currentHookNameInDev = "useCallback"; - updateHookTypesDev(); - return mountCallback(callback, deps); - }, - useContext: function (context) { - currentHookNameInDev = "useContext"; - updateHookTypesDev(); - return readContext(context); - }, - useEffect: function (create, deps) { - currentHookNameInDev = "useEffect"; - updateHookTypesDev(); - return mountEffect(create, deps); - }, - useImperativeHandle: function (ref, create, deps) { - currentHookNameInDev = "useImperativeHandle"; - updateHookTypesDev(); - return mountImperativeHandle(ref, create, deps); - }, - useInsertionEffect: function (create, deps) { - currentHookNameInDev = "useInsertionEffect"; - updateHookTypesDev(); - return mountInsertionEffect(create, deps); - }, - useLayoutEffect: function (create, deps) { - currentHookNameInDev = "useLayoutEffect"; - updateHookTypesDev(); - return mountLayoutEffect(create, deps); - }, - useMemo: function (create, deps) { - currentHookNameInDev = "useMemo"; - updateHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnMountInDEV; + do { + // An extra OffscreenLane bit is added to updates that were made to + // a hidden tree, so that we can distinguish them from updates that were + // already there when the tree was hidden. + var updateLane = removeLanes(update.lane, OffscreenLane); + var isHiddenUpdate = updateLane !== update.lane; // Check if this update was made while the tree was hidden. If so, then + // it's not a "base" update and we should disregard the extra base lanes + // that were added to renderLanes when we entered the Offscreen tree. - try { - return mountMemo(create, deps); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; - } - }, - useReducer: function (reducer, initialArg, init) { - currentHookNameInDev = "useReducer"; - updateHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnMountInDEV; + var shouldSkipUpdate = isHiddenUpdate + ? !isSubsetOfLanes(getWorkInProgressRootRenderLanes(), updateLane) + : !isSubsetOfLanes(renderLanes$1, updateLane); - try { - return mountReducer(reducer, initialArg, init); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; - } - }, - useRef: function (initialValue) { - currentHookNameInDev = "useRef"; - updateHookTypesDev(); - return mountRef(initialValue); - }, - useState: function (initialState) { - currentHookNameInDev = "useState"; - updateHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnMountInDEV; + if (shouldSkipUpdate) { + // Priority is insufficient. Skip this update. If this is the first + // skipped update, the previous update/state is the new base + // update/state. + var clone = { + lane: updateLane, + action: update.action, + hasEagerState: update.hasEagerState, + eagerState: update.eagerState, + next: null + }; - try { - return mountState(initialState); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; + if (newBaseQueueLast === null) { + newBaseQueueFirst = newBaseQueueLast = clone; + newBaseState = newState; + } else { + newBaseQueueLast = newBaseQueueLast.next = clone; + } // Update the remaining priority in the queue. + // TODO: Don't need to accumulate this. Instead, we can remove + // renderLanes from the original lanes. + + currentlyRenderingFiber$1.lanes = mergeLanes( + currentlyRenderingFiber$1.lanes, + updateLane + ); + markSkippedUpdateLanes(updateLane); + } else { + // This update does have sufficient priority. + if (newBaseQueueLast !== null) { + var _clone = { + // This update is going to be committed so we never want uncommit + // it. Using NoLane works because 0 is a subset of all bitmasks, so + // this will never be skipped by the check above. + lane: NoLane, + action: update.action, + hasEagerState: update.hasEagerState, + eagerState: update.eagerState, + next: null + }; + newBaseQueueLast = newBaseQueueLast.next = _clone; + } // Process this update. + + var action = update.action; + + if (shouldDoubleInvokeUserFnsInHooksDEV) { + reducer(newState, action); + } + + if (update.hasEagerState) { + // If this update is a state update (not a reducer) and was processed eagerly, + // we can use the eagerly computed state + newState = update.eagerState; + } else { + newState = reducer(newState, action); + } } - }, - useDebugValue: function (value, formatterFn) { - currentHookNameInDev = "useDebugValue"; - updateHookTypesDev(); - return mountDebugValue(); - }, - useDeferredValue: function (value) { - currentHookNameInDev = "useDeferredValue"; - updateHookTypesDev(); - return mountDeferredValue(value); - }, - useTransition: function () { - currentHookNameInDev = "useTransition"; - updateHookTypesDev(); - return mountTransition(); - }, - useMutableSource: function (source, getSnapshot, subscribe) { - currentHookNameInDev = "useMutableSource"; - updateHookTypesDev(); - return mountMutableSource(source, getSnapshot, subscribe); - }, - useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { - currentHookNameInDev = "useSyncExternalStore"; - updateHookTypesDev(); - return mountSyncExternalStore(subscribe, getSnapshot); - }, - useId: function () { - currentHookNameInDev = "useId"; - updateHookTypesDev(); - return mountId(); + + update = update.next; + } while (update !== null && update !== first); + + if (newBaseQueueLast === null) { + newBaseState = newState; + } else { + newBaseQueueLast.next = newBaseQueueFirst; + } // Mark that the fiber performed work, but only if the new state is + // different from the current state. + + if (!objectIs(newState, hook.memoizedState)) { + markWorkInProgressReceivedUpdate(); } - }; - { - HooksDispatcherOnMountWithHookTypesInDEV.use = use; + hook.memoizedState = newState; + hook.baseState = newBaseState; + hook.baseQueue = newBaseQueueLast; + queue.lastRenderedState = newState; } - { - HooksDispatcherOnMountWithHookTypesInDEV.useMemoCache = useMemoCache; + if (baseQueue === null) { + // `queue.lanes` is used for entangling transitions. We can set it back to + // zero once the queue is empty. + queue.lanes = NoLanes; } - HooksDispatcherOnUpdateInDEV = { - readContext: function (context) { - return readContext(context); - }, - useCallback: function (callback, deps) { - currentHookNameInDev = "useCallback"; - updateHookTypesDev(); - return updateCallback(callback, deps); - }, - useContext: function (context) { - currentHookNameInDev = "useContext"; - updateHookTypesDev(); - return readContext(context); - }, - useEffect: function (create, deps) { - currentHookNameInDev = "useEffect"; - updateHookTypesDev(); - return updateEffect(create, deps); - }, - useImperativeHandle: function (ref, create, deps) { - currentHookNameInDev = "useImperativeHandle"; - updateHookTypesDev(); - return updateImperativeHandle(ref, create, deps); - }, - useInsertionEffect: function (create, deps) { - currentHookNameInDev = "useInsertionEffect"; - updateHookTypesDev(); - return updateInsertionEffect(create, deps); - }, - useLayoutEffect: function (create, deps) { - currentHookNameInDev = "useLayoutEffect"; - updateHookTypesDev(); - return updateLayoutEffect(create, deps); - }, - useMemo: function (create, deps) { - currentHookNameInDev = "useMemo"; - updateHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnUpdateInDEV; + var dispatch = queue.dispatch; + return [hook.memoizedState, dispatch]; +} - try { - return updateMemo(create, deps); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; - } - }, - useReducer: function (reducer, initialArg, init) { - currentHookNameInDev = "useReducer"; - updateHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnUpdateInDEV; +function rerenderReducer(reducer, initialArg, init) { + var hook = updateWorkInProgressHook(); + var queue = hook.queue; - try { - return updateReducer(reducer, initialArg, init); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; - } - }, - useRef: function (initialValue) { - currentHookNameInDev = "useRef"; - updateHookTypesDev(); - return updateRef(); - }, - useState: function (initialState) { - currentHookNameInDev = "useState"; - updateHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnUpdateInDEV; + if (queue === null) { + throw new Error( + "Should have a queue. This is likely a bug in React. Please file an issue." + ); + } - try { - return updateState(initialState); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; - } - }, - useDebugValue: function (value, formatterFn) { - currentHookNameInDev = "useDebugValue"; - updateHookTypesDev(); - return updateDebugValue(); - }, - useDeferredValue: function (value) { - currentHookNameInDev = "useDeferredValue"; - updateHookTypesDev(); - return updateDeferredValue(value); - }, - useTransition: function () { - currentHookNameInDev = "useTransition"; - updateHookTypesDev(); - return updateTransition(); - }, - useMutableSource: function (source, getSnapshot, subscribe) { - currentHookNameInDev = "useMutableSource"; - updateHookTypesDev(); - return updateMutableSource(source, getSnapshot, subscribe); - }, - useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { - currentHookNameInDev = "useSyncExternalStore"; - updateHookTypesDev(); - return updateSyncExternalStore(subscribe, getSnapshot); - }, - useId: function () { - currentHookNameInDev = "useId"; - updateHookTypesDev(); - return updateId(); + queue.lastRenderedReducer = reducer; // This is a re-render. Apply the new render phase updates to the previous + // work-in-progress hook. + + var dispatch = queue.dispatch; + var lastRenderPhaseUpdate = queue.pending; + var newState = hook.memoizedState; + + if (lastRenderPhaseUpdate !== null) { + // The queue doesn't persist past this render pass. + queue.pending = null; + var firstRenderPhaseUpdate = lastRenderPhaseUpdate.next; + var update = firstRenderPhaseUpdate; + + do { + // Process this render phase update. We don't have to check the + // priority because it will always be the same as the current + // render's. + var action = update.action; + newState = reducer(newState, action); + update = update.next; + } while (update !== firstRenderPhaseUpdate); // Mark that the fiber performed work, but only if the new state is + // different from the current state. + + if (!objectIs(newState, hook.memoizedState)) { + markWorkInProgressReceivedUpdate(); } - }; - { - HooksDispatcherOnUpdateInDEV.use = use; + hook.memoizedState = newState; // Don't persist the state accumulated from the render phase updates to + // the base state unless the queue is empty. + // TODO: Not sure if this is the desired semantics, but it's what we + // do for gDSFP. I can't remember why. + + if (hook.baseQueue === null) { + hook.baseState = newState; + } + + queue.lastRenderedState = newState; } + return [newState, dispatch]; +} + +function readFromUnsubscribedMutableSource(root, source, getSnapshot) { { - HooksDispatcherOnUpdateInDEV.useMemoCache = useMemoCache; + warnAboutMultipleRenderersDEV(source); } - HooksDispatcherOnRerenderInDEV = { - readContext: function (context) { - return readContext(context); - }, - useCallback: function (callback, deps) { - currentHookNameInDev = "useCallback"; - updateHookTypesDev(); - return updateCallback(callback, deps); - }, - useContext: function (context) { - currentHookNameInDev = "useContext"; - updateHookTypesDev(); - return readContext(context); - }, - useEffect: function (create, deps) { - currentHookNameInDev = "useEffect"; - updateHookTypesDev(); - return updateEffect(create, deps); - }, - useImperativeHandle: function (ref, create, deps) { - currentHookNameInDev = "useImperativeHandle"; - updateHookTypesDev(); - return updateImperativeHandle(ref, create, deps); - }, - useInsertionEffect: function (create, deps) { - currentHookNameInDev = "useInsertionEffect"; - updateHookTypesDev(); - return updateInsertionEffect(create, deps); - }, - useLayoutEffect: function (create, deps) { - currentHookNameInDev = "useLayoutEffect"; - updateHookTypesDev(); - return updateLayoutEffect(create, deps); - }, - useMemo: function (create, deps) { - currentHookNameInDev = "useMemo"; - updateHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnRerenderInDEV; + var getVersion = source._getVersion; + var version = getVersion(source._source); // Is it safe for this component to read from this source during the current render? - try { - return updateMemo(create, deps); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; - } - }, - useReducer: function (reducer, initialArg, init) { - currentHookNameInDev = "useReducer"; - updateHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnRerenderInDEV; + var isSafeToReadFromSource = false; // Check the version first. + // If this render has already been started with a specific version, + // we can use it alone to determine if we can safely read from the source. - try { - return rerenderReducer(reducer, initialArg, init); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; - } - }, - useRef: function (initialValue) { - currentHookNameInDev = "useRef"; - updateHookTypesDev(); - return updateRef(); - }, - useState: function (initialState) { - currentHookNameInDev = "useState"; - updateHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnRerenderInDEV; + var currentRenderVersion = getWorkInProgressVersion(source); - try { - return rerenderState(initialState); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; + if (currentRenderVersion !== null) { + // It's safe to read if the store hasn't been mutated since the last time + // we read something. + isSafeToReadFromSource = currentRenderVersion === version; + } else { + // If there's no version, then this is the first time we've read from the + // source during the current render pass, so we need to do a bit more work. + // What we need to determine is if there are any hooks that already + // subscribed to the source, and if so, whether there are any pending + // mutations that haven't been synchronized yet. + // + // If there are no pending mutations, then `root.mutableReadLanes` will be + // empty, and we know we can safely read. + // + // If there *are* pending mutations, we may still be able to safely read + // if the currently rendering lanes are inclusive of the pending mutation + // lanes, since that guarantees that the value we're about to read from + // the source is consistent with the values that we read during the most + // recent mutation. + isSafeToReadFromSource = isSubsetOfLanes( + renderLanes$1, + root.mutableReadLanes + ); + + if (isSafeToReadFromSource) { + // If it's safe to read from this source during the current render, + // store the version in case other components read from it. + // A changed version number will let those components know to throw and restart the render. + setWorkInProgressVersion(source, version); + } + } + + if (isSafeToReadFromSource) { + var snapshot = getSnapshot(source._source); + + { + if (typeof snapshot === "function") { + error( + "Mutable source should not return a function as the snapshot value. " + + "Functions may close over mutable values and cause tearing." + ); } - }, - useDebugValue: function (value, formatterFn) { - currentHookNameInDev = "useDebugValue"; - updateHookTypesDev(); - return updateDebugValue(); - }, - useDeferredValue: function (value) { - currentHookNameInDev = "useDeferredValue"; - updateHookTypesDev(); - return rerenderDeferredValue(value); - }, - useTransition: function () { - currentHookNameInDev = "useTransition"; - updateHookTypesDev(); - return rerenderTransition(); - }, - useMutableSource: function (source, getSnapshot, subscribe) { - currentHookNameInDev = "useMutableSource"; - updateHookTypesDev(); - return updateMutableSource(source, getSnapshot, subscribe); - }, - useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { - currentHookNameInDev = "useSyncExternalStore"; - updateHookTypesDev(); - return updateSyncExternalStore(subscribe, getSnapshot); - }, - useId: function () { - currentHookNameInDev = "useId"; - updateHookTypesDev(); - return updateId(); } - }; - { - HooksDispatcherOnRerenderInDEV.use = use; + return snapshot; + } else { + // This handles the special case of a mutable source being shared between renderers. + // In that case, if the source is mutated between the first and second renderer, + // The second renderer don't know that it needs to reset the WIP version during unwind, + // (because the hook only marks sources as dirty if it's written to their WIP version). + // That would cause this tear check to throw again and eventually be visible to the user. + // We can avoid this infinite loop by explicitly marking the source as dirty. + // + // This can lead to tearing in the first renderer when it resumes, + // but there's nothing we can do about that (short of throwing here and refusing to continue the render). + markSourceAsDirty(source); // Intentioally throw an error to force React to retry synchronously. During + // the synchronous retry, it will block interleaved mutations, so we should + // get a consistent read. Therefore, the following error should never be + // visible to the user. + // We expect this error not to be thrown during the synchronous retry, + // because we blocked interleaved mutations. + + throw new Error( + "Cannot read from mutable source during the current render without tearing. This may be a bug in React. Please file an issue." + ); } +} - { - HooksDispatcherOnRerenderInDEV.useMemoCache = useMemoCache; +function useMutableSource(hook, source, getSnapshot, subscribe) { + var root = getWorkInProgressRoot(); + + if (root === null) { + throw new Error( + "Expected a work-in-progress root. This is a bug in React. Please file an issue." + ); } - InvalidNestedHooksDispatcherOnMountInDEV = { - readContext: function (context) { - warnInvalidContextAccess(); - return readContext(context); - }, - useCallback: function (callback, deps) { - currentHookNameInDev = "useCallback"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountCallback(callback, deps); - }, - useContext: function (context) { - currentHookNameInDev = "useContext"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return readContext(context); - }, - useEffect: function (create, deps) { - currentHookNameInDev = "useEffect"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountEffect(create, deps); - }, - useImperativeHandle: function (ref, create, deps) { - currentHookNameInDev = "useImperativeHandle"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountImperativeHandle(ref, create, deps); - }, - useInsertionEffect: function (create, deps) { - currentHookNameInDev = "useInsertionEffect"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountInsertionEffect(create, deps); - }, - useLayoutEffect: function (create, deps) { - currentHookNameInDev = "useLayoutEffect"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountLayoutEffect(create, deps); - }, - useMemo: function (create, deps) { - currentHookNameInDev = "useMemo"; - warnInvalidHookAccess(); - mountHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnMountInDEV; + var getVersion = source._getVersion; + var version = getVersion(source._source); + var dispatcher = ReactCurrentDispatcher$1.current; // eslint-disable-next-line prefer-const - try { - return mountMemo(create, deps); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; - } - }, - useReducer: function (reducer, initialArg, init) { - currentHookNameInDev = "useReducer"; - warnInvalidHookAccess(); - mountHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnMountInDEV; + var _dispatcher$useState = dispatcher.useState(function () { + return readFromUnsubscribedMutableSource(root, source, getSnapshot); + }), + currentSnapshot = _dispatcher$useState[0], + setSnapshot = _dispatcher$useState[1]; - try { - return mountReducer(reducer, initialArg, init); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; + var snapshot = currentSnapshot; // Grab a handle to the state hook as well. + // We use it to clear the pending update queue if we have a new source. + + var stateHook = workInProgressHook; + var memoizedState = hook.memoizedState; + var refs = memoizedState.refs; + var prevGetSnapshot = refs.getSnapshot; + var prevSource = memoizedState.source; + var prevSubscribe = memoizedState.subscribe; + var fiber = currentlyRenderingFiber$1; + hook.memoizedState = { + refs: refs, + source: source, + subscribe: subscribe + }; // Sync the values needed by our subscription handler after each commit. + + dispatcher.useEffect( + function () { + refs.getSnapshot = getSnapshot; // Normally the dispatch function for a state hook never changes, + // but this hook recreates the queue in certain cases to avoid updates from stale sources. + // handleChange() below needs to reference the dispatch function without re-subscribing, + // so we use a ref to ensure that it always has the latest version. + + refs.setSnapshot = setSnapshot; // Check for a possible change between when we last rendered now. + + var maybeNewVersion = getVersion(source._source); + + if (!objectIs(version, maybeNewVersion)) { + var maybeNewSnapshot = getSnapshot(source._source); + + { + if (typeof maybeNewSnapshot === "function") { + error( + "Mutable source should not return a function as the snapshot value. " + + "Functions may close over mutable values and cause tearing." + ); + } + } + + if (!objectIs(snapshot, maybeNewSnapshot)) { + setSnapshot(maybeNewSnapshot); + var lane = requestUpdateLane(fiber); + markRootMutableRead(root, lane); + } // If the source mutated between render and now, + // there may be state updates already scheduled from the old source. + // Entangle the updates so that they render in the same batch. + + markRootEntangled(root, root.mutableReadLanes); } }, - useRef: function (initialValue) { - currentHookNameInDev = "useRef"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountRef(initialValue); - }, - useState: function (initialState) { - currentHookNameInDev = "useState"; - warnInvalidHookAccess(); - mountHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnMountInDEV; + [getSnapshot, source, subscribe] + ); // If we got a new source or subscribe function, re-subscribe in a passive effect. - try { - return mountState(initialState); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; + dispatcher.useEffect( + function () { + var handleChange = function () { + var latestGetSnapshot = refs.getSnapshot; + var latestSetSnapshot = refs.setSnapshot; + + try { + latestSetSnapshot(latestGetSnapshot(source._source)); // Record a pending mutable source update with the same expiration time. + + var lane = requestUpdateLane(fiber); + markRootMutableRead(root, lane); + } catch (error) { + // A selector might throw after a source mutation. + // e.g. it might try to read from a part of the store that no longer exists. + // In this case we should still schedule an update with React. + // Worst case the selector will throw again and then an error boundary will handle it. + latestSetSnapshot(function () { + throw error; + }); + } + }; + + var unsubscribe = subscribe(source._source, handleChange); + + { + if (typeof unsubscribe !== "function") { + error( + "Mutable source subscribe function must return an unsubscribe function." + ); + } } + + return unsubscribe; }, - useDebugValue: function (value, formatterFn) { - currentHookNameInDev = "useDebugValue"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountDebugValue(); - }, - useDeferredValue: function (value) { - currentHookNameInDev = "useDeferredValue"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountDeferredValue(value); - }, - useTransition: function () { - currentHookNameInDev = "useTransition"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountTransition(); - }, - useMutableSource: function (source, getSnapshot, subscribe) { - currentHookNameInDev = "useMutableSource"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountMutableSource(source, getSnapshot, subscribe); - }, - useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { - currentHookNameInDev = "useSyncExternalStore"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountSyncExternalStore(subscribe, getSnapshot); - }, - useId: function () { - currentHookNameInDev = "useId"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountId(); - } - }; + [source, subscribe] + ); // If any of the inputs to useMutableSource change, reading is potentially unsafe. + // + // If either the source or the subscription have changed we can't can't trust the update queue. + // Maybe the source changed in a way that the old subscription ignored but the new one depends on. + // + // If the getSnapshot function changed, we also shouldn't rely on the update queue. + // It's possible that the underlying source was mutated between the when the last "change" event fired, + // and when the current render (with the new getSnapshot function) is processed. + // + // In both cases, we need to throw away pending updates (since they are no longer relevant) + // and treat reading from the source as we do in the mount case. - { - InvalidNestedHooksDispatcherOnMountInDEV.use = function (usable) { - warnInvalidHookAccess(); - return use(usable); + if ( + !objectIs(prevGetSnapshot, getSnapshot) || + !objectIs(prevSource, source) || + !objectIs(prevSubscribe, subscribe) + ) { + // Create a new queue and setState method, + // So if there are interleaved updates, they get pushed to the older queue. + // When this becomes current, the previous queue and dispatch method will be discarded, + // including any interleaving updates that occur. + var newQueue = { + pending: null, + lanes: NoLanes, + dispatch: null, + lastRenderedReducer: basicStateReducer, + lastRenderedState: snapshot }; + newQueue.dispatch = setSnapshot = dispatchSetState.bind( + null, + currentlyRenderingFiber$1, + newQueue + ); + stateHook.queue = newQueue; + stateHook.baseQueue = null; + snapshot = readFromUnsubscribedMutableSource(root, source, getSnapshot); + stateHook.memoizedState = stateHook.baseState = snapshot; } - { - InvalidNestedHooksDispatcherOnMountInDEV.useMemoCache = function (size) { - warnInvalidHookAccess(); - return useMemoCache(size); - }; - } + return snapshot; +} - InvalidNestedHooksDispatcherOnUpdateInDEV = { - readContext: function (context) { - warnInvalidContextAccess(); - return readContext(context); - }, - useCallback: function (callback, deps) { - currentHookNameInDev = "useCallback"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateCallback(callback, deps); - }, - useContext: function (context) { - currentHookNameInDev = "useContext"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return readContext(context); - }, - useEffect: function (create, deps) { - currentHookNameInDev = "useEffect"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateEffect(create, deps); - }, - useImperativeHandle: function (ref, create, deps) { - currentHookNameInDev = "useImperativeHandle"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateImperativeHandle(ref, create, deps); - }, - useInsertionEffect: function (create, deps) { - currentHookNameInDev = "useInsertionEffect"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateInsertionEffect(create, deps); - }, - useLayoutEffect: function (create, deps) { - currentHookNameInDev = "useLayoutEffect"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateLayoutEffect(create, deps); +function mountMutableSource(source, getSnapshot, subscribe) { + var hook = mountWorkInProgressHook(); + hook.memoizedState = { + refs: { + getSnapshot: getSnapshot, + setSnapshot: null }, - useMemo: function (create, deps) { - currentHookNameInDev = "useMemo"; - warnInvalidHookAccess(); - updateHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnUpdateInDEV; + source: source, + subscribe: subscribe + }; + return useMutableSource(hook, source, getSnapshot, subscribe); +} - try { - return updateMemo(create, deps); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; - } - }, - useReducer: function (reducer, initialArg, init) { - currentHookNameInDev = "useReducer"; - warnInvalidHookAccess(); - updateHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnUpdateInDEV; +function updateMutableSource(source, getSnapshot, subscribe) { + var hook = updateWorkInProgressHook(); + return useMutableSource(hook, source, getSnapshot, subscribe); +} - try { - return updateReducer(reducer, initialArg, init); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; - } - }, - useRef: function (initialValue) { - currentHookNameInDev = "useRef"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateRef(); - }, - useState: function (initialState) { - currentHookNameInDev = "useState"; - warnInvalidHookAccess(); - updateHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnUpdateInDEV; +function mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) { + var fiber = currentlyRenderingFiber$1; + var hook = mountWorkInProgressHook(); + var nextSnapshot; - try { - return updateState(initialState); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; + { + nextSnapshot = getSnapshot(); + + { + if (!didWarnUncachedGetSnapshot) { + var cachedSnapshot = getSnapshot(); + + if (!objectIs(nextSnapshot, cachedSnapshot)) { + error( + "The result of getSnapshot should be cached to avoid an infinite loop" + ); + + didWarnUncachedGetSnapshot = true; + } } - }, - useDebugValue: function (value, formatterFn) { - currentHookNameInDev = "useDebugValue"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateDebugValue(); - }, - useDeferredValue: function (value) { - currentHookNameInDev = "useDeferredValue"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateDeferredValue(value); - }, - useTransition: function () { - currentHookNameInDev = "useTransition"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateTransition(); - }, - useMutableSource: function (source, getSnapshot, subscribe) { - currentHookNameInDev = "useMutableSource"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateMutableSource(source, getSnapshot, subscribe); - }, - useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { - currentHookNameInDev = "useSyncExternalStore"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateSyncExternalStore(subscribe, getSnapshot); - }, - useId: function () { - currentHookNameInDev = "useId"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateId(); + } // Unless we're rendering a blocking lane, schedule a consistency check. + // Right before committing, we will walk the tree and check if any of the + // stores were mutated. + // + // We won't do this if we're hydrating server-rendered content, because if + // the content is stale, it's already visible anyway. Instead we'll patch + // it up in a passive effect. + + var root = getWorkInProgressRoot(); + + if (root === null) { + throw new Error( + "Expected a work-in-progress root. This is a bug in React. Please file an issue." + ); + } + + if (!includesBlockingLane(root, renderLanes$1)) { + pushStoreConsistencyCheck(fiber, getSnapshot, nextSnapshot); } + } // Read the current snapshot from the store on every render. This breaks the + // normal rules of React, and only works because store updates are + // always synchronous. + + hook.memoizedState = nextSnapshot; + var inst = { + value: nextSnapshot, + getSnapshot: getSnapshot }; + hook.queue = inst; // Schedule an effect to subscribe to the store. + + mountEffect(subscribeToStore.bind(null, fiber, inst, subscribe), [subscribe]); // Schedule an effect to update the mutable instance fields. We will update + // this whenever subscribe, getSnapshot, or value changes. Because there's no + // clean-up function, and we track the deps correctly, we can call pushEffect + // directly, without storing any additional state. For the same reason, we + // don't need to set a static flag, either. + // TODO: We can move this to the passive phase once we add a pre-commit + // consistency check. See the next comment. + + fiber.flags |= Passive$1; + pushEffect( + HasEffect | Passive, + updateStoreInstance.bind(null, fiber, inst, nextSnapshot, getSnapshot), + undefined, + null + ); + return nextSnapshot; +} + +function updateSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) { + var fiber = currentlyRenderingFiber$1; + var hook = updateWorkInProgressHook(); // Read the current snapshot from the store on every render. This breaks the + // normal rules of React, and only works because store updates are + // always synchronous. + + var nextSnapshot = getSnapshot(); { - InvalidNestedHooksDispatcherOnUpdateInDEV.use = function (usable) { - warnInvalidHookAccess(); - return use(usable); - }; + if (!didWarnUncachedGetSnapshot) { + var cachedSnapshot = getSnapshot(); + + if (!objectIs(nextSnapshot, cachedSnapshot)) { + error( + "The result of getSnapshot should be cached to avoid an infinite loop" + ); + + didWarnUncachedGetSnapshot = true; + } + } } - { - InvalidNestedHooksDispatcherOnUpdateInDEV.useMemoCache = function (size) { - warnInvalidHookAccess(); - return useMemoCache(size); - }; + var prevSnapshot = (currentHook || hook).memoizedState; + var snapshotChanged = !objectIs(prevSnapshot, nextSnapshot); + + if (snapshotChanged) { + hook.memoizedState = nextSnapshot; + markWorkInProgressReceivedUpdate(); } - InvalidNestedHooksDispatcherOnRerenderInDEV = { - readContext: function (context) { - warnInvalidContextAccess(); - return readContext(context); - }, - useCallback: function (callback, deps) { - currentHookNameInDev = "useCallback"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateCallback(callback, deps); - }, - useContext: function (context) { - currentHookNameInDev = "useContext"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return readContext(context); - }, - useEffect: function (create, deps) { - currentHookNameInDev = "useEffect"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateEffect(create, deps); - }, - useImperativeHandle: function (ref, create, deps) { - currentHookNameInDev = "useImperativeHandle"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateImperativeHandle(ref, create, deps); - }, - useInsertionEffect: function (create, deps) { - currentHookNameInDev = "useInsertionEffect"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateInsertionEffect(create, deps); - }, - useLayoutEffect: function (create, deps) { - currentHookNameInDev = "useLayoutEffect"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateLayoutEffect(create, deps); - }, - useMemo: function (create, deps) { - currentHookNameInDev = "useMemo"; - warnInvalidHookAccess(); - updateHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnUpdateInDEV; + var inst = hook.queue; + updateEffect(subscribeToStore.bind(null, fiber, inst, subscribe), [ + subscribe + ]); // Whenever getSnapshot or subscribe changes, we need to check in the + // commit phase if there was an interleaved mutation. In concurrent mode + // this can happen all the time, but even in synchronous mode, an earlier + // effect may have mutated the store. - try { - return updateMemo(create, deps); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; - } - }, - useReducer: function (reducer, initialArg, init) { - currentHookNameInDev = "useReducer"; - warnInvalidHookAccess(); - updateHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnUpdateInDEV; + if ( + inst.getSnapshot !== getSnapshot || + snapshotChanged || // Check if the susbcribe function changed. We can save some memory by + // checking whether we scheduled a subscription effect above. + (workInProgressHook !== null && + workInProgressHook.memoizedState.tag & HasEffect) + ) { + fiber.flags |= Passive$1; + pushEffect( + HasEffect | Passive, + updateStoreInstance.bind(null, fiber, inst, nextSnapshot, getSnapshot), + undefined, + null + ); // Unless we're rendering a blocking lane, schedule a consistency check. + // Right before committing, we will walk the tree and check if any of the + // stores were mutated. - try { - return rerenderReducer(reducer, initialArg, init); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; - } - }, - useRef: function (initialValue) { - currentHookNameInDev = "useRef"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateRef(); - }, - useState: function (initialState) { - currentHookNameInDev = "useState"; - warnInvalidHookAccess(); - updateHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnUpdateInDEV; + var root = getWorkInProgressRoot(); - try { - return rerenderState(initialState); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; - } - }, - useDebugValue: function (value, formatterFn) { - currentHookNameInDev = "useDebugValue"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateDebugValue(); - }, - useDeferredValue: function (value) { - currentHookNameInDev = "useDeferredValue"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return rerenderDeferredValue(value); - }, - useTransition: function () { - currentHookNameInDev = "useTransition"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return rerenderTransition(); - }, - useMutableSource: function (source, getSnapshot, subscribe) { - currentHookNameInDev = "useMutableSource"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateMutableSource(source, getSnapshot, subscribe); - }, - useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { - currentHookNameInDev = "useSyncExternalStore"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateSyncExternalStore(subscribe, getSnapshot); - }, - useId: function () { - currentHookNameInDev = "useId"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateId(); + if (root === null) { + throw new Error( + "Expected a work-in-progress root. This is a bug in React. Please file an issue." + ); } - }; - { - InvalidNestedHooksDispatcherOnRerenderInDEV.use = function (usable) { - warnInvalidHookAccess(); - return use(usable); - }; + if (!includesBlockingLane(root, renderLanes$1)) { + pushStoreConsistencyCheck(fiber, getSnapshot, nextSnapshot); + } } - { - InvalidNestedHooksDispatcherOnRerenderInDEV.useMemoCache = function (size) { - warnInvalidHookAccess(); - return useMemoCache(size); - }; - } + return nextSnapshot; } -var now = Scheduler.unstable_now; -var commitTime = 0; -var layoutEffectStartTime = -1; -var profilerStartTime = -1; -var passiveEffectStartTime = -1; -/** - * Tracks whether the current update was a nested/cascading update (scheduled from a layout effect). - * - * The overall sequence is: - * 1. render - * 2. commit (and call `onRender`, `onCommit`) - * 3. check for nested updates - * 4. flush passive effects (and call `onPostCommit`) - * - * Nested updates are identified in step 3 above, - * but step 4 still applies to the work that was just committed. - * We use two flags to track nested updates then: - * one tracks whether the upcoming update is a nested update, - * and the other tracks whether the current update was a nested update. - * The first value gets synced to the second at the start of the render phase. - */ - -var currentUpdateIsNested = false; -var nestedUpdateScheduled = false; +function pushStoreConsistencyCheck(fiber, getSnapshot, renderedSnapshot) { + fiber.flags |= StoreConsistency; + var check = { + getSnapshot: getSnapshot, + value: renderedSnapshot + }; + var componentUpdateQueue = currentlyRenderingFiber$1.updateQueue; -function isCurrentUpdateNested() { - return currentUpdateIsNested; -} + if (componentUpdateQueue === null) { + componentUpdateQueue = createFunctionComponentUpdateQueue(); + currentlyRenderingFiber$1.updateQueue = componentUpdateQueue; + componentUpdateQueue.stores = [check]; + } else { + var stores = componentUpdateQueue.stores; -function markNestedUpdateScheduled() { - { - nestedUpdateScheduled = true; + if (stores === null) { + componentUpdateQueue.stores = [check]; + } else { + stores.push(check); + } } } -function resetNestedUpdateFlag() { - { - currentUpdateIsNested = false; - nestedUpdateScheduled = false; - } -} +function updateStoreInstance(fiber, inst, nextSnapshot, getSnapshot) { + // These are updated in the passive phase + inst.value = nextSnapshot; + inst.getSnapshot = getSnapshot; // Something may have been mutated in between render and commit. This could + // have been in an event that fired before the passive effects, or it could + // have been in a layout effect. In that case, we would have used the old + // snapsho and getSnapshot values to bail out. We need to check one more time. -function syncNestedUpdateFlag() { - { - currentUpdateIsNested = nestedUpdateScheduled; - nestedUpdateScheduled = false; + if (checkIfSnapshotChanged(inst)) { + // Force a re-render. + forceStoreRerender(fiber); } } -function getCommitTime() { - return commitTime; -} +function subscribeToStore(fiber, inst, subscribe) { + var handleStoreChange = function () { + // The store changed. Check if the snapshot changed since the last time we + // read from the store. + if (checkIfSnapshotChanged(inst)) { + // Force a re-render. + forceStoreRerender(fiber); + } + }; // Subscribe to the store and return a clean-up function. -function recordCommitTime() { - commitTime = now(); + return subscribe(handleStoreChange); } -function startProfilerTimer(fiber) { - profilerStartTime = now(); +function checkIfSnapshotChanged(inst) { + var latestGetSnapshot = inst.getSnapshot; + var prevValue = inst.value; - if (fiber.actualStartTime < 0) { - fiber.actualStartTime = now(); + try { + var nextValue = latestGetSnapshot(); + return !objectIs(prevValue, nextValue); + } catch (error) { + return true; } } -function stopProfilerTimerIfRunning(fiber) { - profilerStartTime = -1; -} - -function stopProfilerTimerIfRunningAndRecordDelta(fiber, overrideBaseTime) { - if (profilerStartTime >= 0) { - var elapsedTime = now() - profilerStartTime; - fiber.actualDuration += elapsedTime; - - if (overrideBaseTime) { - fiber.selfBaseDuration = elapsedTime; - } +function forceStoreRerender(fiber) { + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - profilerStartTime = -1; + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); } } -function recordLayoutEffectDuration(fiber) { - if (layoutEffectStartTime >= 0) { - var elapsedTime = now() - layoutEffectStartTime; - layoutEffectStartTime = -1; // Store duration on the next nearest Profiler ancestor - // Or the root (for the DevTools Profiler to read) - - var parentFiber = fiber.return; +function mountState(initialState) { + var hook = mountWorkInProgressHook(); - while (parentFiber !== null) { - switch (parentFiber.tag) { - case HostRoot: - var root = parentFiber.stateNode; - root.effectDuration += elapsedTime; - return; + if (typeof initialState === "function") { + // $FlowFixMe: Flow doesn't like mixed types + initialState = initialState(); + } - case Profiler: - var parentStateNode = parentFiber.stateNode; - parentStateNode.effectDuration += elapsedTime; - return; - } + hook.memoizedState = hook.baseState = initialState; + var queue = { + pending: null, + lanes: NoLanes, + dispatch: null, + lastRenderedReducer: basicStateReducer, + lastRenderedState: initialState + }; + hook.queue = queue; + var dispatch = (queue.dispatch = dispatchSetState.bind( + null, + currentlyRenderingFiber$1, + queue + )); + return [hook.memoizedState, dispatch]; +} - parentFiber = parentFiber.return; +function updateState(initialState) { + return updateReducer(basicStateReducer); +} + +function rerenderState(initialState) { + return rerenderReducer(basicStateReducer); +} + +function pushEffect(tag, create, destroy, deps) { + var effect = { + tag: tag, + create: create, + destroy: destroy, + deps: deps, + // Circular + next: null + }; + var componentUpdateQueue = currentlyRenderingFiber$1.updateQueue; + + if (componentUpdateQueue === null) { + componentUpdateQueue = createFunctionComponentUpdateQueue(); + currentlyRenderingFiber$1.updateQueue = componentUpdateQueue; + componentUpdateQueue.lastEffect = effect.next = effect; + } else { + var lastEffect = componentUpdateQueue.lastEffect; + + if (lastEffect === null) { + componentUpdateQueue.lastEffect = effect.next = effect; + } else { + var firstEffect = lastEffect.next; + lastEffect.next = effect; + effect.next = firstEffect; + componentUpdateQueue.lastEffect = effect; } } + + return effect; } -function recordPassiveEffectDuration(fiber) { - if (passiveEffectStartTime >= 0) { - var elapsedTime = now() - passiveEffectStartTime; - passiveEffectStartTime = -1; // Store duration on the next nearest Profiler ancestor - // Or the root (for the DevTools Profiler to read) +var stackContainsErrorMessage = null; - var parentFiber = fiber.return; +function getCallerStackFrame() { + // eslint-disable-next-line react-internal/prod-error-codes + var stackFrames = new Error("Error message").stack.split("\n"); // Some browsers (e.g. Chrome) include the error message in the stack + // but others (e.g. Firefox) do not. - while (parentFiber !== null) { - switch (parentFiber.tag) { - case HostRoot: - var root = parentFiber.stateNode; + if (stackContainsErrorMessage === null) { + stackContainsErrorMessage = stackFrames[0].includes("Error message"); + } - if (root !== null) { - root.passiveEffectDuration += elapsedTime; - } + return stackContainsErrorMessage + ? stackFrames.slice(3, 4).join("\n") + : stackFrames.slice(2, 3).join("\n"); +} - return; +function mountRef(initialValue) { + var hook = mountWorkInProgressHook(); - case Profiler: - var parentStateNode = parentFiber.stateNode; + if (enableUseRefAccessWarning) { + { + // Support lazy initialization pattern shown in docs. + // We need to store the caller stack frame so that we don't warn on subsequent renders. + var hasBeenInitialized = initialValue != null; + var lazyInitGetterStack = null; + var didCheckForLazyInit = false; // Only warn once per component+hook. - if (parentStateNode !== null) { - // Detached fibers have their state node cleared out. - // In this case, the return pointer is also cleared out, - // so we won't be able to report the time spent in this Profiler's subtree. - parentStateNode.passiveEffectDuration += elapsedTime; + var didWarnAboutRead = false; + var didWarnAboutWrite = false; + var current = initialValue; + var ref = { + get current() { + if (!hasBeenInitialized) { + didCheckForLazyInit = true; + lazyInitGetterStack = getCallerStackFrame(); + } else if (currentlyRenderingFiber$1 !== null && !didWarnAboutRead) { + if ( + lazyInitGetterStack === null || + lazyInitGetterStack !== getCallerStackFrame() + ) { + didWarnAboutRead = true; + + warn( + "%s: Unsafe read of a mutable value during render.\n\n" + + "Reading from a ref during render is only safe if:\n" + + "1. The ref value has not been updated, or\n" + + "2. The ref holds a lazily-initialized value that is only set once.\n", + getComponentNameFromFiber(currentlyRenderingFiber$1) || + "Unknown" + ); + } } - return; - } + return current; + }, - parentFiber = parentFiber.return; + set current(value) { + if (currentlyRenderingFiber$1 !== null && !didWarnAboutWrite) { + if (hasBeenInitialized || !didCheckForLazyInit) { + didWarnAboutWrite = true; + + warn( + "%s: Unsafe write of a mutable value during render.\n\n" + + "Writing to a ref during render is only safe if the ref holds " + + "a lazily-initialized value that is only set once.\n", + getComponentNameFromFiber(currentlyRenderingFiber$1) || + "Unknown" + ); + } + } + + hasBeenInitialized = true; + current = value; + } + }; + Object.seal(ref); + hook.memoizedState = ref; + return ref; } + } else { + var _ref2 = { + current: initialValue + }; + hook.memoizedState = _ref2; + return _ref2; } } -function startLayoutEffectTimer() { - layoutEffectStartTime = now(); +function updateRef(initialValue) { + var hook = updateWorkInProgressHook(); + return hook.memoizedState; } -function startPassiveEffectTimer() { - passiveEffectStartTime = now(); +function mountEffectImpl(fiberFlags, hookFlags, create, deps) { + var hook = mountWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + currentlyRenderingFiber$1.flags |= fiberFlags; + hook.memoizedState = pushEffect( + HasEffect | hookFlags, + create, + undefined, + nextDeps + ); } -function transferActualDuration(fiber) { - // Transfer time spent rendering these children so we don't lose it - // after we rerender. This is used as a helper in special cases - // where we should count the work of multiple passes. - var child = fiber.child; +function updateEffectImpl(fiberFlags, hookFlags, create, deps) { + var hook = updateWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + var destroy = undefined; // currentHook is null when rerendering after a render phase state update. - while (child) { - // $FlowFixMe[unsafe-addition] addition with possible null/undefined value - fiber.actualDuration += child.actualDuration; - child = child.sibling; - } -} + if (currentHook !== null) { + var prevEffect = currentHook.memoizedState; + destroy = prevEffect.destroy; -function resolveDefaultProps(Component, baseProps) { - if (Component && Component.defaultProps) { - // Resolve default props. Taken from ReactElement - var props = assign({}, baseProps); - var defaultProps = Component.defaultProps; + if (nextDeps !== null) { + var prevDeps = prevEffect.deps; - for (var propName in defaultProps) { - if (props[propName] === undefined) { - props[propName] = defaultProps[propName]; + if (areHookInputsEqual(nextDeps, prevDeps)) { + hook.memoizedState = pushEffect(hookFlags, create, destroy, nextDeps); + return; } } + } - return props; + currentlyRenderingFiber$1.flags |= fiberFlags; + hook.memoizedState = pushEffect( + HasEffect | hookFlags, + create, + destroy, + nextDeps + ); +} + +function mountEffect(create, deps) { + if ((currentlyRenderingFiber$1.mode & StrictEffectsMode) !== NoMode) { + mountEffectImpl( + MountPassiveDev | Passive$1 | PassiveStatic, + Passive, + create, + deps + ); + } else { + mountEffectImpl(Passive$1 | PassiveStatic, Passive, create, deps); } +} - return baseProps; +function updateEffect(create, deps) { + updateEffectImpl(Passive$1, Passive, create, deps); } -var fakeInternalInstance = {}; -var didWarnAboutStateAssignmentForComponent; -var didWarnAboutUninitializedState; -var didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate; -var didWarnAboutLegacyLifecyclesAndDerivedState; -var didWarnAboutUndefinedDerivedState; -var didWarnAboutDirectlyAssigningPropsToState; -var didWarnAboutContextTypeAndContextTypes; -var didWarnAboutInvalidateContextType; -var didWarnOnInvalidCallback; +function mountInsertionEffect(create, deps) { + mountEffectImpl(Update, Insertion, create, deps); +} -{ - didWarnAboutStateAssignmentForComponent = new Set(); - didWarnAboutUninitializedState = new Set(); - didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate = new Set(); - didWarnAboutLegacyLifecyclesAndDerivedState = new Set(); - didWarnAboutDirectlyAssigningPropsToState = new Set(); - didWarnAboutUndefinedDerivedState = new Set(); - didWarnAboutContextTypeAndContextTypes = new Set(); - didWarnAboutInvalidateContextType = new Set(); - didWarnOnInvalidCallback = new Set(); // This is so gross but it's at least non-critical and can be removed if - // it causes problems. This is meant to give a nicer error message for - // ReactDOM15.unstable_renderSubtreeIntoContainer(reactDOM16Component, - // ...)) which otherwise throws a "_processChildContext is not a function" - // exception. - - Object.defineProperty(fakeInternalInstance, "_processChildContext", { - enumerable: false, - value: function () { - throw new Error( - "_processChildContext is not available in React 16+. This likely " + - "means you have multiple copies of React and are attempting to nest " + - "a React 15 tree inside a React 16 tree using " + - "unstable_renderSubtreeIntoContainer, which isn't supported. Try " + - "to make sure you have only one copy of React (and ideally, switch " + - "to ReactDOM.createPortal)." - ); - } - }); - Object.freeze(fakeInternalInstance); +function updateInsertionEffect(create, deps) { + return updateEffectImpl(Update, Insertion, create, deps); } -function warnOnInvalidCallback(callback, callerName) { - { - if (callback === null || typeof callback === "function") { - return; - } - - var key = callerName + "_" + callback; - - if (!didWarnOnInvalidCallback.has(key)) { - didWarnOnInvalidCallback.add(key); +function mountLayoutEffect(create, deps) { + var fiberFlags = Update | LayoutStatic; - error( - "%s(...): Expected the last optional `callback` argument to be a " + - "function. Instead received: %s.", - callerName, - callback - ); - } + if ((currentlyRenderingFiber$1.mode & StrictEffectsMode) !== NoMode) { + fiberFlags |= MountLayoutDev; } + + return mountEffectImpl(fiberFlags, Layout, create, deps); } -function warnOnUndefinedDerivedState(type, partialState) { - { - if (partialState === undefined) { - var componentName = getComponentNameFromType(type) || "Component"; +function updateLayoutEffect(create, deps) { + return updateEffectImpl(Update, Layout, create, deps); +} - if (!didWarnAboutUndefinedDerivedState.has(componentName)) { - didWarnAboutUndefinedDerivedState.add(componentName); +function imperativeHandleEffect(create, ref) { + if (typeof ref === "function") { + var refCallback = ref; + var inst = create(); + refCallback(inst); + return function () { + refCallback(null); + }; + } else if (ref !== null && ref !== undefined) { + var refObject = ref; + { + if (!refObject.hasOwnProperty("current")) { error( - "%s.getDerivedStateFromProps(): A valid state object (or null) must be returned. " + - "You have returned undefined.", - componentName + "Expected useImperativeHandle() first argument to either be a " + + "ref callback or React.createRef() object. Instead received: %s.", + "an object with keys {" + Object.keys(refObject).join(", ") + "}" ); } } + + var _inst = create(); + + refObject.current = _inst; + return function () { + refObject.current = null; + }; } } -function applyDerivedStateFromProps( - workInProgress, - ctor, - getDerivedStateFromProps, - nextProps -) { - var prevState = workInProgress.memoizedState; - var partialState = getDerivedStateFromProps(nextProps, prevState); - +function mountImperativeHandle(ref, create, deps) { { - if (workInProgress.mode & StrictLegacyMode) { - setIsStrictModeForDevtools(true); - - try { - // Invoke the function an extra time to help detect side-effects. - partialState = getDerivedStateFromProps(nextProps, prevState); - } finally { - setIsStrictModeForDevtools(false); - } + if (typeof create !== "function") { + error( + "Expected useImperativeHandle() second argument to be a function " + + "that creates a handle. Instead received: %s.", + create !== null ? typeof create : "null" + ); } + } // TODO: If deps are provided, should we skip comparing the ref itself? - warnOnUndefinedDerivedState(ctor, partialState); - } // Merge the partial state and the previous state. - - var memoizedState = - partialState === null || partialState === undefined - ? prevState - : assign({}, prevState, partialState); - workInProgress.memoizedState = memoizedState; // Once the update queue is empty, persist the derived state onto the - // base state. + var effectDeps = + deps !== null && deps !== undefined ? deps.concat([ref]) : null; + var fiberFlags = Update | LayoutStatic; - if (workInProgress.lanes === NoLanes) { - // Queue is always non-null for classes - var updateQueue = workInProgress.updateQueue; - updateQueue.baseState = memoizedState; + if ((currentlyRenderingFiber$1.mode & StrictEffectsMode) !== NoMode) { + fiberFlags |= MountLayoutDev; } + + mountEffectImpl( + fiberFlags, + Layout, + imperativeHandleEffect.bind(null, create, ref), + effectDeps + ); } -var classComponentUpdater = { - isMounted: isMounted, - // $FlowFixMe[missing-local-annot] - enqueueSetState: function (inst, payload, callback) { - var fiber = get(inst); - var lane = requestUpdateLane(fiber); - var update = createUpdate(lane); - update.payload = payload; +function updateImperativeHandle(ref, create, deps) { + { + if (typeof create !== "function") { + error( + "Expected useImperativeHandle() second argument to be a function " + + "that creates a handle. Instead received: %s.", + create !== null ? typeof create : "null" + ); + } + } // TODO: If deps are provided, should we skip comparing the ref itself? - if (callback !== undefined && callback !== null) { - { - warnOnInvalidCallback(callback, "setState"); - } + var effectDeps = + deps !== null && deps !== undefined ? deps.concat([ref]) : null; + updateEffectImpl( + Update, + Layout, + imperativeHandleEffect.bind(null, create, ref), + effectDeps + ); +} - update.callback = callback; - } +function mountDebugValue(value, formatterFn) { + // This hook is normally a no-op. + // The react-debug-hooks package injects its own implementation + // so that e.g. DevTools can display custom hook values. +} - var root = enqueueUpdate(fiber, update, lane); +var updateDebugValue = mountDebugValue; - if (root !== null) { - var eventTime = requestEventTime(); - scheduleUpdateOnFiber(root, fiber, lane, eventTime); - entangleTransitions(root, fiber, lane); - } +function mountCallback(callback, deps) { + var hook = mountWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + hook.memoizedState = [callback, nextDeps]; + return callback; +} - { - markStateUpdateScheduled(fiber, lane); - } - }, - enqueueReplaceState: function (inst, payload, callback) { - var fiber = get(inst); - var lane = requestUpdateLane(fiber); - var update = createUpdate(lane); - update.tag = ReplaceState; - update.payload = payload; +function updateCallback(callback, deps) { + var hook = updateWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + var prevState = hook.memoizedState; - if (callback !== undefined && callback !== null) { - { - warnOnInvalidCallback(callback, "replaceState"); - } + if (nextDeps !== null) { + var prevDeps = prevState[1]; - update.callback = callback; + if (areHookInputsEqual(nextDeps, prevDeps)) { + return prevState[0]; } + } - var root = enqueueUpdate(fiber, update, lane); + hook.memoizedState = [callback, nextDeps]; + return callback; +} - if (root !== null) { - var eventTime = requestEventTime(); - scheduleUpdateOnFiber(root, fiber, lane, eventTime); - entangleTransitions(root, fiber, lane); - } +function mountMemo(nextCreate, deps) { + var hook = mountWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; - { - markStateUpdateScheduled(fiber, lane); - } - }, - // $FlowFixMe[missing-local-annot] - enqueueForceUpdate: function (inst, callback) { - var fiber = get(inst); - var lane = requestUpdateLane(fiber); - var update = createUpdate(lane); - update.tag = ForceUpdate; + if (shouldDoubleInvokeUserFnsInHooksDEV) { + nextCreate(); + } - if (callback !== undefined && callback !== null) { - { - warnOnInvalidCallback(callback, "forceUpdate"); - } + var nextValue = nextCreate(); + hook.memoizedState = [nextValue, nextDeps]; + return nextValue; +} - update.callback = callback; - } +function updateMemo(nextCreate, deps) { + var hook = updateWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + var prevState = hook.memoizedState; // Assume these are defined. If they're not, areHookInputsEqual will warn. - var root = enqueueUpdate(fiber, update, lane); + if (nextDeps !== null) { + var prevDeps = prevState[1]; - if (root !== null) { - var eventTime = requestEventTime(); - scheduleUpdateOnFiber(root, fiber, lane, eventTime); - entangleTransitions(root, fiber, lane); - } - - { - markForceUpdateScheduled(fiber, lane); + if (areHookInputsEqual(nextDeps, prevDeps)) { + return prevState[0]; } } -}; - -function checkShouldComponentUpdate( - workInProgress, - ctor, - oldProps, - newProps, - oldState, - newState, - nextContext -) { - var instance = workInProgress.stateNode; - if (typeof instance.shouldComponentUpdate === "function") { - var shouldUpdate = instance.shouldComponentUpdate( - newProps, - newState, - nextContext - ); + if (shouldDoubleInvokeUserFnsInHooksDEV) { + nextCreate(); + } - { - if (workInProgress.mode & StrictLegacyMode) { - setIsStrictModeForDevtools(true); + var nextValue = nextCreate(); + hook.memoizedState = [nextValue, nextDeps]; + return nextValue; +} - try { - // Invoke the function an extra time to help detect side-effects. - shouldUpdate = instance.shouldComponentUpdate( - newProps, - newState, - nextContext - ); - } finally { - setIsStrictModeForDevtools(false); - } - } +function mountDeferredValue(value) { + var hook = mountWorkInProgressHook(); + hook.memoizedState = value; + return value; +} - if (shouldUpdate === undefined) { - error( - "%s.shouldComponentUpdate(): Returned undefined instead of a " + - "boolean value. Make sure to return true or false.", - getComponentNameFromType(ctor) || "Component" - ); - } - } +function updateDeferredValue(value) { + var hook = updateWorkInProgressHook(); + var resolvedCurrentHook = currentHook; + var prevValue = resolvedCurrentHook.memoizedState; + return updateDeferredValueImpl(hook, prevValue, value); +} - return shouldUpdate; - } +function rerenderDeferredValue(value) { + var hook = updateWorkInProgressHook(); - if (ctor.prototype && ctor.prototype.isPureReactComponent) { - return ( - !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState) - ); + if (currentHook === null) { + // This is a rerender during a mount. + hook.memoizedState = value; + return value; + } else { + // This is a rerender during an update. + var prevValue = currentHook.memoizedState; + return updateDeferredValueImpl(hook, prevValue, value); } - - return true; } -function checkClassInstance(workInProgress, ctor, newProps) { - var instance = workInProgress.stateNode; +function updateDeferredValueImpl(hook, prevValue, value) { + var shouldDeferValue = !includesOnlyNonUrgentLanes(renderLanes$1); - { - var name = getComponentNameFromType(ctor) || "Component"; - var renderPresent = instance.render; + if (shouldDeferValue) { + // This is an urgent update. If the value has changed, keep using the + // previous value and spawn a deferred render to update it later. + if (!objectIs(value, prevValue)) { + // Schedule a deferred render + var deferredLane = claimNextTransitionLane(); + currentlyRenderingFiber$1.lanes = mergeLanes( + currentlyRenderingFiber$1.lanes, + deferredLane + ); + markSkippedUpdateLanes(deferredLane); // Set this to true to indicate that the rendered value is inconsistent + // from the latest value. The name "baseState" doesn't really match how we + // use it because we're reusing a state hook field instead of creating a + // new one. - if (!renderPresent) { - if (ctor.prototype && typeof ctor.prototype.render === "function") { - error( - "%s(...): No `render` method found on the returned component " + - "instance: did you accidentally return an object from the constructor?", - name - ); - } else { - error( - "%s(...): No `render` method found on the returned component " + - "instance: you may have forgotten to define `render`.", - name - ); - } - } + hook.baseState = true; + } // Reuse the previous value - if ( - instance.getInitialState && - !instance.getInitialState.isReactClassApproved && - !instance.state - ) { - error( - "getInitialState was defined on %s, a plain JavaScript class. " + - "This is only supported for classes created using React.createClass. " + - "Did you mean to define a state property instead?", - name - ); + return prevValue; + } else { + // This is not an urgent update, so we can use the latest value regardless + // of what it is. No need to defer it. + // However, if we're currently inside a spawned render, then we need to mark + // this as an update to prevent the fiber from bailing out. + // + // `baseState` is true when the current value is different from the rendered + // value. The name doesn't really match how we use it because we're reusing + // a state hook field instead of creating a new one. + if (hook.baseState) { + // Flip this back to false. + hook.baseState = false; + markWorkInProgressReceivedUpdate(); } - if ( - instance.getDefaultProps && - !instance.getDefaultProps.isReactClassApproved - ) { - error( - "getDefaultProps was defined on %s, a plain JavaScript class. " + - "This is only supported for classes created using React.createClass. " + - "Use a static property to define defaultProps instead.", - name - ); - } + hook.memoizedState = value; + return value; + } +} - if (instance.propTypes) { - error( - "propTypes was defined as an instance property on %s. Use a static " + - "property to define propTypes instead.", - name - ); - } +function startTransition(setPending, callback, options) { + var previousPriority = getCurrentUpdatePriority(); + setCurrentUpdatePriority( + higherEventPriority(previousPriority, ContinuousEventPriority) + ); + var prevTransition = ReactCurrentBatchConfig$2.transition; + ReactCurrentBatchConfig$2.transition = null; + setPending(true); + var currentTransition = (ReactCurrentBatchConfig$2.transition = {}); - if (instance.contextType) { - error( - "contextType was defined as an instance property on %s. Use a static " + - "property to define contextType instead.", - name - ); - } + { + ReactCurrentBatchConfig$2.transition._updatedFibers = new Set(); + } + + try { + setPending(false); + callback(); + } finally { + setCurrentUpdatePriority(previousPriority); + ReactCurrentBatchConfig$2.transition = prevTransition; { - if (instance.contextTypes) { - error( - "contextTypes was defined as an instance property on %s. Use a static " + - "property to define contextTypes instead.", - name - ); - } + if (prevTransition === null && currentTransition._updatedFibers) { + var updatedFibersCount = currentTransition._updatedFibers.size; - if ( - ctor.contextType && - ctor.contextTypes && - !didWarnAboutContextTypeAndContextTypes.has(ctor) - ) { - didWarnAboutContextTypeAndContextTypes.add(ctor); + currentTransition._updatedFibers.clear(); - error( - "%s declares both contextTypes and contextType static properties. " + - "The legacy contextTypes property will be ignored.", - name - ); + if (updatedFibersCount > 10) { + warn( + "Detected a large number of updates inside startTransition. " + + "If this is due to a subscription please re-write it to use React provided hooks. " + + "Otherwise concurrent mode guarantees are off the table." + ); + } } } + } +} - if (typeof instance.componentShouldUpdate === "function") { - error( - "%s has a method called " + - "componentShouldUpdate(). Did you mean shouldComponentUpdate()? " + - "The name is phrased as a question because the function is " + - "expected to return a value.", - name - ); - } +function mountTransition() { + var _mountState = mountState(false), + isPending = _mountState[0], + setPending = _mountState[1]; // The `start` method never changes. - if ( - ctor.prototype && - ctor.prototype.isPureReactComponent && - typeof instance.shouldComponentUpdate !== "undefined" - ) { - error( - "%s has a method called shouldComponentUpdate(). " + - "shouldComponentUpdate should not be used when extending React.PureComponent. " + - "Please extend React.Component if shouldComponentUpdate is used.", - getComponentNameFromType(ctor) || "A pure component" - ); - } + var start = startTransition.bind(null, setPending); + var hook = mountWorkInProgressHook(); + hook.memoizedState = start; + return [isPending, start]; +} - if (typeof instance.componentDidUnmount === "function") { - error( - "%s has a method called " + - "componentDidUnmount(). But there is no such lifecycle method. " + - "Did you mean componentWillUnmount()?", - name - ); - } - - if (typeof instance.componentDidReceiveProps === "function") { - error( - "%s has a method called " + - "componentDidReceiveProps(). But there is no such lifecycle method. " + - "If you meant to update the state in response to changing props, " + - "use componentWillReceiveProps(). If you meant to fetch data or " + - "run side-effects or mutations after React has updated the UI, use componentDidUpdate().", - name - ); - } +function updateTransition() { + var _updateState = updateState(), + isPending = _updateState[0]; - if (typeof instance.componentWillRecieveProps === "function") { - error( - "%s has a method called " + - "componentWillRecieveProps(). Did you mean componentWillReceiveProps()?", - name - ); - } + var hook = updateWorkInProgressHook(); + var start = hook.memoizedState; + return [isPending, start]; +} - if (typeof instance.UNSAFE_componentWillRecieveProps === "function") { - error( - "%s has a method called " + - "UNSAFE_componentWillRecieveProps(). Did you mean UNSAFE_componentWillReceiveProps()?", - name - ); - } +function rerenderTransition() { + var _rerenderState = rerenderState(), + isPending = _rerenderState[0]; - var hasMutatedProps = instance.props !== newProps; + var hook = updateWorkInProgressHook(); + var start = hook.memoizedState; + return [isPending, start]; +} - if (instance.props !== undefined && hasMutatedProps) { - error( - "%s(...): When calling super() in `%s`, make sure to pass " + - "up the same props that your component's constructor was passed.", - name, - name - ); - } +function mountId() { + var hook = mountWorkInProgressHook(); + var root = getWorkInProgressRoot(); // TODO: In Fizz, id generation is specific to each server config. Maybe we + // should do this in Fiber, too? Deferring this decision for now because + // there's no other place to store the prefix except for an internal field on + // the public createRoot object, which the fiber tree does not currently have + // a reference to. - if (instance.defaultProps) { - error( - "Setting defaultProps as an instance property on %s is not supported and will be ignored." + - " Instead, define defaultProps as a static property on %s.", - name, - name - ); - } + var identifierPrefix = root.identifierPrefix; + var id; - if ( - typeof instance.getSnapshotBeforeUpdate === "function" && - typeof instance.componentDidUpdate !== "function" && - !didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.has(ctor) - ) { - didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.add(ctor); + { + // Use a lowercase r prefix for client-generated ids. + var globalClientId = globalClientIdCounter++; + id = ":" + identifierPrefix + "r" + globalClientId.toString(32) + ":"; + } - error( - "%s: getSnapshotBeforeUpdate() should be used with componentDidUpdate(). " + - "This component defines getSnapshotBeforeUpdate() only.", - getComponentNameFromType(ctor) - ); - } + hook.memoizedState = id; + return id; +} - if (typeof instance.getDerivedStateFromProps === "function") { - error( - "%s: getDerivedStateFromProps() is defined as an instance method " + - "and will be ignored. Instead, declare it as a static method.", - name - ); - } +function updateId() { + var hook = updateWorkInProgressHook(); + var id = hook.memoizedState; + return id; +} - if (typeof instance.getDerivedStateFromError === "function") { +function dispatchReducerAction(fiber, queue, action) { + { + if (typeof arguments[3] === "function") { error( - "%s: getDerivedStateFromError() is defined as an instance method " + - "and will be ignored. Instead, declare it as a static method.", - name + "State updates from the useState() and useReducer() Hooks don't support the " + + "second callback argument. To execute a side effect after " + + "rendering, declare it in the component body with useEffect()." ); } + } - if (typeof ctor.getSnapshotBeforeUpdate === "function") { - error( - "%s: getSnapshotBeforeUpdate() is defined as a static method " + - "and will be ignored. Instead, declare it as an instance method.", - name - ); - } + var lane = requestUpdateLane(fiber); + var update = { + lane: lane, + action: action, + hasEagerState: false, + eagerState: null, + next: null + }; - var state = instance.state; + if (isRenderPhaseUpdate(fiber)) { + enqueueRenderPhaseUpdate(queue, update); + } else { + var root = enqueueConcurrentHookUpdate(fiber, queue, update, lane); - if (state && (typeof state !== "object" || isArray(state))) { - error("%s.state: must be set to an object or null", name); + if (root !== null) { + var eventTime = requestEventTime(); + scheduleUpdateOnFiber(root, fiber, lane, eventTime); + entangleTransitionUpdate(root, queue, lane); } + } - if ( - typeof instance.getChildContext === "function" && - typeof ctor.childContextTypes !== "object" - ) { + markUpdateInDevTools(fiber, lane); +} + +function dispatchSetState(fiber, queue, action) { + { + if (typeof arguments[3] === "function") { error( - "%s.getChildContext(): childContextTypes must be defined in order to " + - "use getChildContext().", - name + "State updates from the useState() and useReducer() Hooks don't support the " + + "second callback argument. To execute a side effect after " + + "rendering, declare it in the component body with useEffect()." ); } } -} -function adoptClassInstance(workInProgress, instance) { - instance.updater = classComponentUpdater; - workInProgress.stateNode = instance; // The instance needs access to the fiber so that it can schedule updates + var lane = requestUpdateLane(fiber); + var update = { + lane: lane, + action: action, + hasEagerState: false, + eagerState: null, + next: null + }; - set(instance, workInProgress); + if (isRenderPhaseUpdate(fiber)) { + enqueueRenderPhaseUpdate(queue, update); + } else { + var alternate = fiber.alternate; - { - instance._reactInternalInstance = fakeInternalInstance; - } -} + if ( + fiber.lanes === NoLanes && + (alternate === null || alternate.lanes === NoLanes) + ) { + // The queue is currently empty, which means we can eagerly compute the + // next state before entering the render phase. If the new state is the + // same as the current state, we may be able to bail out entirely. + var lastRenderedReducer = queue.lastRenderedReducer; -function constructClassInstance(workInProgress, ctor, props) { - var isLegacyContextConsumer = false; - var unmaskedContext = emptyContextObject; - var context = emptyContextObject; - var contextType = ctor.contextType; + if (lastRenderedReducer !== null) { + var prevDispatcher; - { - if ("contextType" in ctor) { - var isValid = // Allow null for conditional declaration - contextType === null || - (contextType !== undefined && - contextType.$$typeof === REACT_CONTEXT_TYPE && - contextType._context === undefined); // Not a + { + prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnUpdateInDEV; + } - if (!isValid && !didWarnAboutInvalidateContextType.has(ctor)) { - didWarnAboutInvalidateContextType.add(ctor); - var addendum = ""; + try { + var currentState = queue.lastRenderedState; + var eagerState = lastRenderedReducer(currentState, action); // Stash the eagerly computed state, and the reducer used to compute + // it, on the update object. If the reducer hasn't changed by the + // time we enter the render phase, then the eager state can be used + // without calling the reducer again. - if (contextType === undefined) { - addendum = - " However, it is set to undefined. " + - "This can be caused by a typo or by mixing up named and default imports. " + - "This can also happen due to a circular dependency, so " + - "try moving the createContext() call to a separate file."; - } else if (typeof contextType !== "object") { - addendum = " However, it is set to a " + typeof contextType + "."; - } else if (contextType.$$typeof === REACT_PROVIDER_TYPE) { - addendum = " Did you accidentally pass the Context.Provider instead?"; - } else if (contextType._context !== undefined) { - // - addendum = " Did you accidentally pass the Context.Consumer instead?"; - } else { - addendum = - " However, it is set to an object with keys {" + - Object.keys(contextType).join(", ") + - "}."; - } + update.hasEagerState = true; + update.eagerState = eagerState; - error( - "%s defines an invalid contextType. " + - "contextType should point to the Context object returned by React.createContext().%s", - getComponentNameFromType(ctor) || "Component", - addendum - ); + if (objectIs(eagerState, currentState)) { + // Fast path. We can bail out without scheduling React to re-render. + // It's still possible that we'll need to rebase this update later, + // if the component re-renders for a different reason and by that + // time the reducer has changed. + // TODO: Do we still need to entangle transitions in this case? + enqueueConcurrentHookUpdateAndEagerlyBailout(fiber, queue, update); + return; + } + } catch (error) { + // Suppress the error. It will throw again in the render phase. + } finally { + { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + } } } - } - if (typeof contextType === "object" && contextType !== null) { - context = readContext(contextType); - } else { - unmaskedContext = getUnmaskedContext(workInProgress, ctor, true); - var contextTypes = ctor.contextTypes; - isLegacyContextConsumer = - contextTypes !== null && contextTypes !== undefined; - context = isLegacyContextConsumer - ? getMaskedContext(workInProgress, unmaskedContext) - : emptyContextObject; - } - - var instance = new ctor(props, context); // Instantiate twice to help detect side-effects. - - { - if (workInProgress.mode & StrictLegacyMode) { - setIsStrictModeForDevtools(true); + var root = enqueueConcurrentHookUpdate(fiber, queue, update, lane); - try { - instance = new ctor(props, context); // eslint-disable-line no-new - } finally { - setIsStrictModeForDevtools(false); - } + if (root !== null) { + var eventTime = requestEventTime(); + scheduleUpdateOnFiber(root, fiber, lane, eventTime); + entangleTransitionUpdate(root, queue, lane); } } - var state = (workInProgress.memoizedState = - instance.state !== null && instance.state !== undefined - ? instance.state - : null); - adoptClassInstance(workInProgress, instance); - - { - if (typeof ctor.getDerivedStateFromProps === "function" && state === null) { - var componentName = getComponentNameFromType(ctor) || "Component"; - - if (!didWarnAboutUninitializedState.has(componentName)) { - didWarnAboutUninitializedState.add(componentName); - - error( - "`%s` uses `getDerivedStateFromProps` but its initial state is " + - "%s. This is not recommended. Instead, define the initial state by " + - "assigning an object to `this.state` in the constructor of `%s`. " + - "This ensures that `getDerivedStateFromProps` arguments have a consistent shape.", - componentName, - instance.state === null ? "null" : "undefined", - componentName - ); - } - } // If new component APIs are defined, "unsafe" lifecycles won't be called. - // Warn about these lifecycles if they are present. - // Don't warn about react-lifecycles-compat polyfilled methods though. - - if ( - typeof ctor.getDerivedStateFromProps === "function" || - typeof instance.getSnapshotBeforeUpdate === "function" - ) { - var foundWillMountName = null; - var foundWillReceivePropsName = null; - var foundWillUpdateName = null; + markUpdateInDevTools(fiber, lane); +} - if ( - typeof instance.componentWillMount === "function" && - instance.componentWillMount.__suppressDeprecationWarning !== true - ) { - foundWillMountName = "componentWillMount"; - } else if (typeof instance.UNSAFE_componentWillMount === "function") { - foundWillMountName = "UNSAFE_componentWillMount"; - } +function isRenderPhaseUpdate(fiber) { + var alternate = fiber.alternate; + return ( + fiber === currentlyRenderingFiber$1 || + (alternate !== null && alternate === currentlyRenderingFiber$1) + ); +} - if ( - typeof instance.componentWillReceiveProps === "function" && - instance.componentWillReceiveProps.__suppressDeprecationWarning !== true - ) { - foundWillReceivePropsName = "componentWillReceiveProps"; - } else if ( - typeof instance.UNSAFE_componentWillReceiveProps === "function" - ) { - foundWillReceivePropsName = "UNSAFE_componentWillReceiveProps"; - } +function enqueueRenderPhaseUpdate(queue, update) { + // This is a render phase update. Stash it in a lazily-created map of + // queue -> linked list of updates. After this render pass, we'll restart + // and apply the stashed updates on top of the work-in-progress hook. + didScheduleRenderPhaseUpdateDuringThisPass = didScheduleRenderPhaseUpdate = + true; + var pending = queue.pending; - if ( - typeof instance.componentWillUpdate === "function" && - instance.componentWillUpdate.__suppressDeprecationWarning !== true - ) { - foundWillUpdateName = "componentWillUpdate"; - } else if (typeof instance.UNSAFE_componentWillUpdate === "function") { - foundWillUpdateName = "UNSAFE_componentWillUpdate"; - } + if (pending === null) { + // This is the first update. Create a circular list. + update.next = update; + } else { + update.next = pending.next; + pending.next = update; + } - if ( - foundWillMountName !== null || - foundWillReceivePropsName !== null || - foundWillUpdateName !== null - ) { - var _componentName = getComponentNameFromType(ctor) || "Component"; + queue.pending = update; +} // TODO: Move to ReactFiberConcurrentUpdates? - var newApiName = - typeof ctor.getDerivedStateFromProps === "function" - ? "getDerivedStateFromProps()" - : "getSnapshotBeforeUpdate()"; +function entangleTransitionUpdate(root, queue, lane) { + if (isTransitionLane(lane)) { + var queueLanes = queue.lanes; // If any entangled lanes are no longer pending on the root, then they + // must have finished. We can remove them from the shared queue, which + // represents a superset of the actually pending lanes. In some cases we + // may entangle more than we need to, but that's OK. In fact it's worse if + // we *don't* entangle when we should. - if (!didWarnAboutLegacyLifecyclesAndDerivedState.has(_componentName)) { - didWarnAboutLegacyLifecyclesAndDerivedState.add(_componentName); + queueLanes = intersectLanes(queueLanes, root.pendingLanes); // Entangle the new transition lane with the other transition lanes. - error( - "Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n" + - "%s uses %s but also contains the following legacy lifecycles:%s%s%s\n\n" + - "The above lifecycles should be removed. Learn more about this warning here:\n" + - "https://reactjs.org/link/unsafe-component-lifecycles", - _componentName, - newApiName, - foundWillMountName !== null ? "\n " + foundWillMountName : "", - foundWillReceivePropsName !== null - ? "\n " + foundWillReceivePropsName - : "", - foundWillUpdateName !== null ? "\n " + foundWillUpdateName : "" - ); - } - } - } - } // Cache unmasked context so we can avoid recreating masked context unless necessary. - // ReactFiberContext usually updates this cache but can't for newly-created instances. + var newQueueLanes = mergeLanes(queueLanes, lane); + queue.lanes = newQueueLanes; // Even if queue.lanes already include lane, we don't know for certain if + // the lane finished since the last time we entangled it. So we need to + // entangle it again, just to be sure. - if (isLegacyContextConsumer) { - cacheContext(workInProgress, unmaskedContext, context); + markRootEntangled(root, newQueueLanes); } - - return instance; } -function callComponentWillMount(workInProgress, instance) { - var oldState = instance.state; - - if (typeof instance.componentWillMount === "function") { - instance.componentWillMount(); - } - - if (typeof instance.UNSAFE_componentWillMount === "function") { - instance.UNSAFE_componentWillMount(); +function markUpdateInDevTools(fiber, lane, action) { + { + markStateUpdateScheduled(fiber, lane); } +} - if (oldState !== instance.state) { - { - error( - "%s.componentWillMount(): Assigning directly to this.state is " + - "deprecated (except inside a component's " + - "constructor). Use setState instead.", - getComponentNameFromFiber(workInProgress) || "Component" - ); - } +var ContextOnlyDispatcher = { + readContext: readContext, + useCallback: throwInvalidHookError, + useContext: throwInvalidHookError, + useEffect: throwInvalidHookError, + useImperativeHandle: throwInvalidHookError, + useInsertionEffect: throwInvalidHookError, + useLayoutEffect: throwInvalidHookError, + useMemo: throwInvalidHookError, + useReducer: throwInvalidHookError, + useRef: throwInvalidHookError, + useState: throwInvalidHookError, + useDebugValue: throwInvalidHookError, + useDeferredValue: throwInvalidHookError, + useTransition: throwInvalidHookError, + useMutableSource: throwInvalidHookError, + useSyncExternalStore: throwInvalidHookError, + useId: throwInvalidHookError +}; - classComponentUpdater.enqueueReplaceState(instance, instance.state, null); - } +{ + ContextOnlyDispatcher.use = throwInvalidHookError; } -function callComponentWillReceiveProps( - workInProgress, - instance, - newProps, - nextContext -) { - var oldState = instance.state; - - if (typeof instance.componentWillReceiveProps === "function") { - instance.componentWillReceiveProps(newProps, nextContext); - } +{ + ContextOnlyDispatcher.useMemoCache = throwInvalidHookError; +} - if (typeof instance.UNSAFE_componentWillReceiveProps === "function") { - instance.UNSAFE_componentWillReceiveProps(newProps, nextContext); - } +var HooksDispatcherOnMountInDEV = null; +var HooksDispatcherOnMountWithHookTypesInDEV = null; +var HooksDispatcherOnUpdateInDEV = null; +var HooksDispatcherOnRerenderInDEV = null; +var InvalidNestedHooksDispatcherOnMountInDEV = null; +var InvalidNestedHooksDispatcherOnUpdateInDEV = null; +var InvalidNestedHooksDispatcherOnRerenderInDEV = null; - if (instance.state !== oldState) { - { - var componentName = - getComponentNameFromFiber(workInProgress) || "Component"; +{ + var warnInvalidContextAccess = function () { + error( + "Context can only be read while React is rendering. " + + "In classes, you can read it in the render method or getDerivedStateFromProps. " + + "In function components, you can read it directly in the function body, but not " + + "inside Hooks like useReducer() or useMemo()." + ); + }; - if (!didWarnAboutStateAssignmentForComponent.has(componentName)) { - didWarnAboutStateAssignmentForComponent.add(componentName); + var warnInvalidHookAccess = function () { + error( + "Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. " + + "You can only call Hooks at the top level of your React function. " + + "For more information, see " + + "https://reactjs.org/link/rules-of-hooks" + ); + }; - error( - "%s.componentWillReceiveProps(): Assigning directly to " + - "this.state is deprecated (except inside a component's " + - "constructor). Use setState instead.", - componentName - ); + HooksDispatcherOnMountInDEV = { + readContext: function (context) { + return readContext(context); + }, + useCallback: function (callback, deps) { + currentHookNameInDev = "useCallback"; + mountHookTypesDev(); + checkDepsAreArrayDev(deps); + return mountCallback(callback, deps); + }, + useContext: function (context) { + currentHookNameInDev = "useContext"; + mountHookTypesDev(); + return readContext(context); + }, + useEffect: function (create, deps) { + currentHookNameInDev = "useEffect"; + mountHookTypesDev(); + checkDepsAreArrayDev(deps); + return mountEffect(create, deps); + }, + useImperativeHandle: function (ref, create, deps) { + currentHookNameInDev = "useImperativeHandle"; + mountHookTypesDev(); + checkDepsAreArrayDev(deps); + return mountImperativeHandle(ref, create, deps); + }, + useInsertionEffect: function (create, deps) { + currentHookNameInDev = "useInsertionEffect"; + mountHookTypesDev(); + checkDepsAreArrayDev(deps); + return mountInsertionEffect(create, deps); + }, + useLayoutEffect: function (create, deps) { + currentHookNameInDev = "useLayoutEffect"; + mountHookTypesDev(); + checkDepsAreArrayDev(deps); + return mountLayoutEffect(create, deps); + }, + useMemo: function (create, deps) { + currentHookNameInDev = "useMemo"; + mountHookTypesDev(); + checkDepsAreArrayDev(deps); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnMountInDEV; + + try { + return mountMemo(create, deps); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; } - } + }, + useReducer: function (reducer, initialArg, init) { + currentHookNameInDev = "useReducer"; + mountHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnMountInDEV; - classComponentUpdater.enqueueReplaceState(instance, instance.state, null); - } -} // Invokes the mount life-cycles on a previously never rendered instance. + try { + return mountReducer(reducer, initialArg, init); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useRef: function (initialValue) { + currentHookNameInDev = "useRef"; + mountHookTypesDev(); + return mountRef(initialValue); + }, + useState: function (initialState) { + currentHookNameInDev = "useState"; + mountHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnMountInDEV; + + try { + return mountState(initialState); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useDebugValue: function (value, formatterFn) { + currentHookNameInDev = "useDebugValue"; + mountHookTypesDev(); + return mountDebugValue(); + }, + useDeferredValue: function (value) { + currentHookNameInDev = "useDeferredValue"; + mountHookTypesDev(); + return mountDeferredValue(value); + }, + useTransition: function () { + currentHookNameInDev = "useTransition"; + mountHookTypesDev(); + return mountTransition(); + }, + useMutableSource: function (source, getSnapshot, subscribe) { + currentHookNameInDev = "useMutableSource"; + mountHookTypesDev(); + return mountMutableSource(source, getSnapshot, subscribe); + }, + useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { + currentHookNameInDev = "useSyncExternalStore"; + mountHookTypesDev(); + return mountSyncExternalStore(subscribe, getSnapshot); + }, + useId: function () { + currentHookNameInDev = "useId"; + mountHookTypesDev(); + return mountId(); + } + }; -function mountClassInstance(workInProgress, ctor, newProps, renderLanes) { { - checkClassInstance(workInProgress, ctor, newProps); + HooksDispatcherOnMountInDEV.use = use; } - var instance = workInProgress.stateNode; - instance.props = newProps; - instance.state = workInProgress.memoizedState; - instance.refs = {}; - initializeUpdateQueue(workInProgress); - var contextType = ctor.contextType; - - if (typeof contextType === "object" && contextType !== null) { - instance.context = readContext(contextType); - } else { - var unmaskedContext = getUnmaskedContext(workInProgress, ctor, true); - instance.context = getMaskedContext(workInProgress, unmaskedContext); + { + HooksDispatcherOnMountInDEV.useMemoCache = useMemoCache; } - { - if (instance.state === newProps) { - var componentName = getComponentNameFromType(ctor) || "Component"; + HooksDispatcherOnMountWithHookTypesInDEV = { + readContext: function (context) { + return readContext(context); + }, + useCallback: function (callback, deps) { + currentHookNameInDev = "useCallback"; + updateHookTypesDev(); + return mountCallback(callback, deps); + }, + useContext: function (context) { + currentHookNameInDev = "useContext"; + updateHookTypesDev(); + return readContext(context); + }, + useEffect: function (create, deps) { + currentHookNameInDev = "useEffect"; + updateHookTypesDev(); + return mountEffect(create, deps); + }, + useImperativeHandle: function (ref, create, deps) { + currentHookNameInDev = "useImperativeHandle"; + updateHookTypesDev(); + return mountImperativeHandle(ref, create, deps); + }, + useInsertionEffect: function (create, deps) { + currentHookNameInDev = "useInsertionEffect"; + updateHookTypesDev(); + return mountInsertionEffect(create, deps); + }, + useLayoutEffect: function (create, deps) { + currentHookNameInDev = "useLayoutEffect"; + updateHookTypesDev(); + return mountLayoutEffect(create, deps); + }, + useMemo: function (create, deps) { + currentHookNameInDev = "useMemo"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnMountInDEV; - if (!didWarnAboutDirectlyAssigningPropsToState.has(componentName)) { - didWarnAboutDirectlyAssigningPropsToState.add(componentName); + try { + return mountMemo(create, deps); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useReducer: function (reducer, initialArg, init) { + currentHookNameInDev = "useReducer"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnMountInDEV; - error( - "%s: It is not recommended to assign props directly to state " + - "because updates to props won't be reflected in state. " + - "In most cases, it is better to use props directly.", - componentName - ); + try { + return mountReducer(reducer, initialArg, init); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; } - } + }, + useRef: function (initialValue) { + currentHookNameInDev = "useRef"; + updateHookTypesDev(); + return mountRef(initialValue); + }, + useState: function (initialState) { + currentHookNameInDev = "useState"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnMountInDEV; - if (workInProgress.mode & StrictLegacyMode) { - ReactStrictModeWarnings.recordLegacyContextWarning( - workInProgress, - instance - ); + try { + return mountState(initialState); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useDebugValue: function (value, formatterFn) { + currentHookNameInDev = "useDebugValue"; + updateHookTypesDev(); + return mountDebugValue(); + }, + useDeferredValue: function (value) { + currentHookNameInDev = "useDeferredValue"; + updateHookTypesDev(); + return mountDeferredValue(value); + }, + useTransition: function () { + currentHookNameInDev = "useTransition"; + updateHookTypesDev(); + return mountTransition(); + }, + useMutableSource: function (source, getSnapshot, subscribe) { + currentHookNameInDev = "useMutableSource"; + updateHookTypesDev(); + return mountMutableSource(source, getSnapshot, subscribe); + }, + useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { + currentHookNameInDev = "useSyncExternalStore"; + updateHookTypesDev(); + return mountSyncExternalStore(subscribe, getSnapshot); + }, + useId: function () { + currentHookNameInDev = "useId"; + updateHookTypesDev(); + return mountId(); } + }; - ReactStrictModeWarnings.recordUnsafeLifecycleWarnings( - workInProgress, - instance - ); - } - - instance.state = workInProgress.memoizedState; - var getDerivedStateFromProps = ctor.getDerivedStateFromProps; - - if (typeof getDerivedStateFromProps === "function") { - applyDerivedStateFromProps( - workInProgress, - ctor, - getDerivedStateFromProps, - newProps - ); - instance.state = workInProgress.memoizedState; - } // In order to support react-lifecycles-compat polyfilled components, - // Unsafe lifecycles should not be invoked for components using the new APIs. - - if ( - typeof ctor.getDerivedStateFromProps !== "function" && - typeof instance.getSnapshotBeforeUpdate !== "function" && - (typeof instance.UNSAFE_componentWillMount === "function" || - typeof instance.componentWillMount === "function") - ) { - callComponentWillMount(workInProgress, instance); // If we had additional state updates during this life-cycle, let's - // process them now. - - processUpdateQueue(workInProgress, newProps, instance, renderLanes); - instance.state = workInProgress.memoizedState; - } - - if (typeof instance.componentDidMount === "function") { - var fiberFlags = Update | LayoutStatic; - - if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { - fiberFlags |= MountLayoutDev; - } - - workInProgress.flags |= fiberFlags; - } -} - -function resumeMountClassInstance(workInProgress, ctor, newProps, renderLanes) { - var instance = workInProgress.stateNode; - var oldProps = workInProgress.memoizedProps; - instance.props = oldProps; - var oldContext = instance.context; - var contextType = ctor.contextType; - var nextContext = emptyContextObject; - - if (typeof contextType === "object" && contextType !== null) { - nextContext = readContext(contextType); - } else { - var nextLegacyUnmaskedContext = getUnmaskedContext( - workInProgress, - ctor, - true - ); - nextContext = getMaskedContext(workInProgress, nextLegacyUnmaskedContext); + { + HooksDispatcherOnMountWithHookTypesInDEV.use = use; } - var getDerivedStateFromProps = ctor.getDerivedStateFromProps; - var hasNewLifecycles = - typeof getDerivedStateFromProps === "function" || - typeof instance.getSnapshotBeforeUpdate === "function"; // Note: During these life-cycles, instance.props/instance.state are what - // ever the previously attempted to render - not the "current". However, - // during componentDidUpdate we pass the "current" props. - // In order to support react-lifecycles-compat polyfilled components, - // Unsafe lifecycles should not be invoked for components using the new APIs. - - if ( - !hasNewLifecycles && - (typeof instance.UNSAFE_componentWillReceiveProps === "function" || - typeof instance.componentWillReceiveProps === "function") - ) { - if (oldProps !== newProps || oldContext !== nextContext) { - callComponentWillReceiveProps( - workInProgress, - instance, - newProps, - nextContext - ); - } + { + HooksDispatcherOnMountWithHookTypesInDEV.useMemoCache = useMemoCache; } - resetHasForceUpdateBeforeProcessing(); - var oldState = workInProgress.memoizedState; - var newState = (instance.state = oldState); - processUpdateQueue(workInProgress, newProps, instance, renderLanes); - newState = workInProgress.memoizedState; + HooksDispatcherOnUpdateInDEV = { + readContext: function (context) { + return readContext(context); + }, + useCallback: function (callback, deps) { + currentHookNameInDev = "useCallback"; + updateHookTypesDev(); + return updateCallback(callback, deps); + }, + useContext: function (context) { + currentHookNameInDev = "useContext"; + updateHookTypesDev(); + return readContext(context); + }, + useEffect: function (create, deps) { + currentHookNameInDev = "useEffect"; + updateHookTypesDev(); + return updateEffect(create, deps); + }, + useImperativeHandle: function (ref, create, deps) { + currentHookNameInDev = "useImperativeHandle"; + updateHookTypesDev(); + return updateImperativeHandle(ref, create, deps); + }, + useInsertionEffect: function (create, deps) { + currentHookNameInDev = "useInsertionEffect"; + updateHookTypesDev(); + return updateInsertionEffect(create, deps); + }, + useLayoutEffect: function (create, deps) { + currentHookNameInDev = "useLayoutEffect"; + updateHookTypesDev(); + return updateLayoutEffect(create, deps); + }, + useMemo: function (create, deps) { + currentHookNameInDev = "useMemo"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnUpdateInDEV; - if ( - oldProps === newProps && - oldState === newState && - !hasContextChanged() && - !checkHasForceUpdateAfterProcessing() - ) { - // If an update was already in progress, we should schedule an Update - // effect even though we're bailing out, so that cWU/cDU are called. - if (typeof instance.componentDidMount === "function") { - var fiberFlags = Update | LayoutStatic; + try { + return updateMemo(create, deps); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useReducer: function (reducer, initialArg, init) { + currentHookNameInDev = "useReducer"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnUpdateInDEV; - if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { - fiberFlags |= MountLayoutDev; + try { + return updateReducer(reducer, initialArg, init); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; } + }, + useRef: function (initialValue) { + currentHookNameInDev = "useRef"; + updateHookTypesDev(); + return updateRef(); + }, + useState: function (initialState) { + currentHookNameInDev = "useState"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnUpdateInDEV; - workInProgress.flags |= fiberFlags; + try { + return updateState(initialState); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useDebugValue: function (value, formatterFn) { + currentHookNameInDev = "useDebugValue"; + updateHookTypesDev(); + return updateDebugValue(); + }, + useDeferredValue: function (value) { + currentHookNameInDev = "useDeferredValue"; + updateHookTypesDev(); + return updateDeferredValue(value); + }, + useTransition: function () { + currentHookNameInDev = "useTransition"; + updateHookTypesDev(); + return updateTransition(); + }, + useMutableSource: function (source, getSnapshot, subscribe) { + currentHookNameInDev = "useMutableSource"; + updateHookTypesDev(); + return updateMutableSource(source, getSnapshot, subscribe); + }, + useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { + currentHookNameInDev = "useSyncExternalStore"; + updateHookTypesDev(); + return updateSyncExternalStore(subscribe, getSnapshot); + }, + useId: function () { + currentHookNameInDev = "useId"; + updateHookTypesDev(); + return updateId(); } + }; - return false; + { + HooksDispatcherOnUpdateInDEV.use = use; } - if (typeof getDerivedStateFromProps === "function") { - applyDerivedStateFromProps( - workInProgress, - ctor, - getDerivedStateFromProps, - newProps - ); - newState = workInProgress.memoizedState; + { + HooksDispatcherOnUpdateInDEV.useMemoCache = useMemoCache; } - var shouldUpdate = - checkHasForceUpdateAfterProcessing() || - checkShouldComponentUpdate( - workInProgress, - ctor, - oldProps, - newProps, - oldState, - newState, - nextContext - ); - - if (shouldUpdate) { - // In order to support react-lifecycles-compat polyfilled components, - // Unsafe lifecycles should not be invoked for components using the new APIs. - if ( - !hasNewLifecycles && - (typeof instance.UNSAFE_componentWillMount === "function" || - typeof instance.componentWillMount === "function") - ) { - if (typeof instance.componentWillMount === "function") { - instance.componentWillMount(); - } - - if (typeof instance.UNSAFE_componentWillMount === "function") { - instance.UNSAFE_componentWillMount(); - } - } - - if (typeof instance.componentDidMount === "function") { - var _fiberFlags = Update | LayoutStatic; - - if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { - _fiberFlags |= MountLayoutDev; - } - - workInProgress.flags |= _fiberFlags; - } - } else { - // If an update was already in progress, we should schedule an Update - // effect even though we're bailing out, so that cWU/cDU are called. - if (typeof instance.componentDidMount === "function") { - var _fiberFlags2 = Update | LayoutStatic; + HooksDispatcherOnRerenderInDEV = { + readContext: function (context) { + return readContext(context); + }, + useCallback: function (callback, deps) { + currentHookNameInDev = "useCallback"; + updateHookTypesDev(); + return updateCallback(callback, deps); + }, + useContext: function (context) { + currentHookNameInDev = "useContext"; + updateHookTypesDev(); + return readContext(context); + }, + useEffect: function (create, deps) { + currentHookNameInDev = "useEffect"; + updateHookTypesDev(); + return updateEffect(create, deps); + }, + useImperativeHandle: function (ref, create, deps) { + currentHookNameInDev = "useImperativeHandle"; + updateHookTypesDev(); + return updateImperativeHandle(ref, create, deps); + }, + useInsertionEffect: function (create, deps) { + currentHookNameInDev = "useInsertionEffect"; + updateHookTypesDev(); + return updateInsertionEffect(create, deps); + }, + useLayoutEffect: function (create, deps) { + currentHookNameInDev = "useLayoutEffect"; + updateHookTypesDev(); + return updateLayoutEffect(create, deps); + }, + useMemo: function (create, deps) { + currentHookNameInDev = "useMemo"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnRerenderInDEV; - if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { - _fiberFlags2 |= MountLayoutDev; + try { + return updateMemo(create, deps); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; } + }, + useReducer: function (reducer, initialArg, init) { + currentHookNameInDev = "useReducer"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnRerenderInDEV; - workInProgress.flags |= _fiberFlags2; - } // If shouldComponentUpdate returned false, we should still update the - // memoized state to indicate that this work can be reused. - - workInProgress.memoizedProps = newProps; - workInProgress.memoizedState = newState; - } // Update the existing instance's state, props, and context pointers even - // if shouldComponentUpdate returns false. - - instance.props = newProps; - instance.state = newState; - instance.context = nextContext; - return shouldUpdate; -} // Invokes the update life-cycles and returns false if it shouldn't rerender. - -function updateClassInstance( - current, - workInProgress, - ctor, - newProps, - renderLanes -) { - var instance = workInProgress.stateNode; - cloneUpdateQueue(current, workInProgress); - var unresolvedOldProps = workInProgress.memoizedProps; - var oldProps = - workInProgress.type === workInProgress.elementType - ? unresolvedOldProps - : resolveDefaultProps(workInProgress.type, unresolvedOldProps); - instance.props = oldProps; - var unresolvedNewProps = workInProgress.pendingProps; - var oldContext = instance.context; - var contextType = ctor.contextType; - var nextContext = emptyContextObject; - - if (typeof contextType === "object" && contextType !== null) { - nextContext = readContext(contextType); - } else { - var nextUnmaskedContext = getUnmaskedContext(workInProgress, ctor, true); - nextContext = getMaskedContext(workInProgress, nextUnmaskedContext); - } - - var getDerivedStateFromProps = ctor.getDerivedStateFromProps; - var hasNewLifecycles = - typeof getDerivedStateFromProps === "function" || - typeof instance.getSnapshotBeforeUpdate === "function"; // Note: During these life-cycles, instance.props/instance.state are what - // ever the previously attempted to render - not the "current". However, - // during componentDidUpdate we pass the "current" props. - // In order to support react-lifecycles-compat polyfilled components, - // Unsafe lifecycles should not be invoked for components using the new APIs. - - if ( - !hasNewLifecycles && - (typeof instance.UNSAFE_componentWillReceiveProps === "function" || - typeof instance.componentWillReceiveProps === "function") - ) { - if ( - unresolvedOldProps !== unresolvedNewProps || - oldContext !== nextContext - ) { - callComponentWillReceiveProps( - workInProgress, - instance, - newProps, - nextContext - ); - } - } - - resetHasForceUpdateBeforeProcessing(); - var oldState = workInProgress.memoizedState; - var newState = (instance.state = oldState); - processUpdateQueue(workInProgress, newProps, instance, renderLanes); - newState = workInProgress.memoizedState; - - if ( - unresolvedOldProps === unresolvedNewProps && - oldState === newState && - !hasContextChanged() && - !checkHasForceUpdateAfterProcessing() && - !enableLazyContextPropagation - ) { - // If an update was already in progress, we should schedule an Update - // effect even though we're bailing out, so that cWU/cDU are called. - if (typeof instance.componentDidUpdate === "function") { - if ( - unresolvedOldProps !== current.memoizedProps || - oldState !== current.memoizedState - ) { - workInProgress.flags |= Update; + try { + return rerenderReducer(reducer, initialArg, init); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; } - } + }, + useRef: function (initialValue) { + currentHookNameInDev = "useRef"; + updateHookTypesDev(); + return updateRef(); + }, + useState: function (initialState) { + currentHookNameInDev = "useState"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnRerenderInDEV; - if (typeof instance.getSnapshotBeforeUpdate === "function") { - if ( - unresolvedOldProps !== current.memoizedProps || - oldState !== current.memoizedState - ) { - workInProgress.flags |= Snapshot; + try { + return rerenderState(initialState); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; } + }, + useDebugValue: function (value, formatterFn) { + currentHookNameInDev = "useDebugValue"; + updateHookTypesDev(); + return updateDebugValue(); + }, + useDeferredValue: function (value) { + currentHookNameInDev = "useDeferredValue"; + updateHookTypesDev(); + return rerenderDeferredValue(value); + }, + useTransition: function () { + currentHookNameInDev = "useTransition"; + updateHookTypesDev(); + return rerenderTransition(); + }, + useMutableSource: function (source, getSnapshot, subscribe) { + currentHookNameInDev = "useMutableSource"; + updateHookTypesDev(); + return updateMutableSource(source, getSnapshot, subscribe); + }, + useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { + currentHookNameInDev = "useSyncExternalStore"; + updateHookTypesDev(); + return updateSyncExternalStore(subscribe, getSnapshot); + }, + useId: function () { + currentHookNameInDev = "useId"; + updateHookTypesDev(); + return updateId(); } + }; - return false; + { + HooksDispatcherOnRerenderInDEV.use = use; } - if (typeof getDerivedStateFromProps === "function") { - applyDerivedStateFromProps( - workInProgress, - ctor, - getDerivedStateFromProps, - newProps - ); - newState = workInProgress.memoizedState; + { + HooksDispatcherOnRerenderInDEV.useMemoCache = useMemoCache; } - var shouldUpdate = - checkHasForceUpdateAfterProcessing() || - checkShouldComponentUpdate( - workInProgress, - ctor, - oldProps, - newProps, - oldState, - newState, - nextContext - ) || // TODO: In some cases, we'll end up checking if context has changed twice, - // both before and after `shouldComponentUpdate` has been called. Not ideal, - // but I'm loath to refactor this function. This only happens for memoized - // components so it's not that common. - enableLazyContextPropagation; - - if (shouldUpdate) { - // In order to support react-lifecycles-compat polyfilled components, - // Unsafe lifecycles should not be invoked for components using the new APIs. - if ( - !hasNewLifecycles && - (typeof instance.UNSAFE_componentWillUpdate === "function" || - typeof instance.componentWillUpdate === "function") - ) { - if (typeof instance.componentWillUpdate === "function") { - instance.componentWillUpdate(newProps, newState, nextContext); - } - - if (typeof instance.UNSAFE_componentWillUpdate === "function") { - instance.UNSAFE_componentWillUpdate(newProps, newState, nextContext); - } - } - - if (typeof instance.componentDidUpdate === "function") { - workInProgress.flags |= Update; - } + InvalidNestedHooksDispatcherOnMountInDEV = { + readContext: function (context) { + warnInvalidContextAccess(); + return readContext(context); + }, + useCallback: function (callback, deps) { + currentHookNameInDev = "useCallback"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountCallback(callback, deps); + }, + useContext: function (context) { + currentHookNameInDev = "useContext"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return readContext(context); + }, + useEffect: function (create, deps) { + currentHookNameInDev = "useEffect"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountEffect(create, deps); + }, + useImperativeHandle: function (ref, create, deps) { + currentHookNameInDev = "useImperativeHandle"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountImperativeHandle(ref, create, deps); + }, + useInsertionEffect: function (create, deps) { + currentHookNameInDev = "useInsertionEffect"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountInsertionEffect(create, deps); + }, + useLayoutEffect: function (create, deps) { + currentHookNameInDev = "useLayoutEffect"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountLayoutEffect(create, deps); + }, + useMemo: function (create, deps) { + currentHookNameInDev = "useMemo"; + warnInvalidHookAccess(); + mountHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnMountInDEV; - if (typeof instance.getSnapshotBeforeUpdate === "function") { - workInProgress.flags |= Snapshot; - } - } else { - // If an update was already in progress, we should schedule an Update - // effect even though we're bailing out, so that cWU/cDU are called. - if (typeof instance.componentDidUpdate === "function") { - if ( - unresolvedOldProps !== current.memoizedProps || - oldState !== current.memoizedState - ) { - workInProgress.flags |= Update; + try { + return mountMemo(create, deps); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; } - } + }, + useReducer: function (reducer, initialArg, init) { + currentHookNameInDev = "useReducer"; + warnInvalidHookAccess(); + mountHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnMountInDEV; - if (typeof instance.getSnapshotBeforeUpdate === "function") { - if ( - unresolvedOldProps !== current.memoizedProps || - oldState !== current.memoizedState - ) { - workInProgress.flags |= Snapshot; + try { + return mountReducer(reducer, initialArg, init); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; } - } // If shouldComponentUpdate returned false, we should still update the - // memoized props/state to indicate that this work can be reused. - - workInProgress.memoizedProps = newProps; - workInProgress.memoizedState = newState; - } // Update the existing instance's state, props, and context pointers even - // if shouldComponentUpdate returns false. - - instance.props = newProps; - instance.state = newState; - instance.context = nextContext; - return shouldUpdate; -} - -function createCapturedValueAtFiber(value, source) { - // If the value is an error, call this function immediately after it is thrown - // so the stack is accurate. - return { - value: value, - source: source, - stack: getStackByFiberInDevAndProd(source), - digest: null - }; -} -function createCapturedValue(value, digest, stack) { - return { - value: value, - source: null, - stack: stack != null ? stack : null, - digest: digest != null ? digest : null - }; -} - -if ( - typeof ReactNativePrivateInterface.ReactFiberErrorDialog.showErrorDialog !== - "function" -) { - throw new Error( - "Expected ReactFiberErrorDialog.showErrorDialog to be a function." - ); -} - -function showErrorDialog(boundary, errorInfo) { - var capturedError = { - componentStack: errorInfo.stack !== null ? errorInfo.stack : "", - error: errorInfo.value, - errorBoundary: - boundary !== null && boundary.tag === ClassComponent - ? boundary.stateNode - : null - }; - return ReactNativePrivateInterface.ReactFiberErrorDialog.showErrorDialog( - capturedError - ); -} - -function logCapturedError(boundary, errorInfo) { - try { - var logError = showErrorDialog(boundary, errorInfo); // Allow injected showErrorDialog() to prevent default console.error logging. - // This enables renderers like ReactNative to better manage redbox behavior. + }, + useRef: function (initialValue) { + currentHookNameInDev = "useRef"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountRef(initialValue); + }, + useState: function (initialState) { + currentHookNameInDev = "useState"; + warnInvalidHookAccess(); + mountHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnMountInDEV; - if (logError === false) { - return; + try { + return mountState(initialState); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useDebugValue: function (value, formatterFn) { + currentHookNameInDev = "useDebugValue"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountDebugValue(); + }, + useDeferredValue: function (value) { + currentHookNameInDev = "useDeferredValue"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountDeferredValue(value); + }, + useTransition: function () { + currentHookNameInDev = "useTransition"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountTransition(); + }, + useMutableSource: function (source, getSnapshot, subscribe) { + currentHookNameInDev = "useMutableSource"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountMutableSource(source, getSnapshot, subscribe); + }, + useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { + currentHookNameInDev = "useSyncExternalStore"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountSyncExternalStore(subscribe, getSnapshot); + }, + useId: function () { + currentHookNameInDev = "useId"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountId(); } + }; - var error = errorInfo.value; + { + InvalidNestedHooksDispatcherOnMountInDEV.use = function (usable) { + warnInvalidHookAccess(); + return use(usable); + }; + } - if (true) { - var source = errorInfo.source; - var stack = errorInfo.stack; - var componentStack = stack !== null ? stack : ""; // Browsers support silencing uncaught errors by calling - // `preventDefault()` in window `error` handler. - // We record this information as an expando on the error. + { + InvalidNestedHooksDispatcherOnMountInDEV.useMemoCache = function (size) { + warnInvalidHookAccess(); + return useMemoCache(size); + }; + } - if (error != null && error._suppressLogging) { - if (boundary.tag === ClassComponent) { - // The error is recoverable and was silenced. - // Ignore it and don't print the stack addendum. - // This is handy for testing error boundaries without noise. - return; - } // The error is fatal. Since the silencing might have - // been accidental, we'll surface it anyway. - // However, the browser would have silenced the original error - // so we'll print it first, and then print the stack addendum. + InvalidNestedHooksDispatcherOnUpdateInDEV = { + readContext: function (context) { + warnInvalidContextAccess(); + return readContext(context); + }, + useCallback: function (callback, deps) { + currentHookNameInDev = "useCallback"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateCallback(callback, deps); + }, + useContext: function (context) { + currentHookNameInDev = "useContext"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return readContext(context); + }, + useEffect: function (create, deps) { + currentHookNameInDev = "useEffect"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateEffect(create, deps); + }, + useImperativeHandle: function (ref, create, deps) { + currentHookNameInDev = "useImperativeHandle"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateImperativeHandle(ref, create, deps); + }, + useInsertionEffect: function (create, deps) { + currentHookNameInDev = "useInsertionEffect"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateInsertionEffect(create, deps); + }, + useLayoutEffect: function (create, deps) { + currentHookNameInDev = "useLayoutEffect"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateLayoutEffect(create, deps); + }, + useMemo: function (create, deps) { + currentHookNameInDev = "useMemo"; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnUpdateInDEV; - console["error"](error); // Don't transform to our wrapper - // For a more detailed description of this block, see: - // https://github.com/facebook/react/pull/13384 + try { + return updateMemo(create, deps); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; } + }, + useReducer: function (reducer, initialArg, init) { + currentHookNameInDev = "useReducer"; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnUpdateInDEV; - var componentName = source ? getComponentNameFromFiber(source) : null; - var componentNameMessage = componentName - ? "The above error occurred in the <" + componentName + "> component:" - : "The above error occurred in one of your React components:"; - var errorBoundaryMessage; - - if (boundary.tag === HostRoot) { - errorBoundaryMessage = - "Consider adding an error boundary to your tree to customize error handling behavior.\n" + - "Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries."; - } else { - var errorBoundaryName = - getComponentNameFromFiber(boundary) || "Anonymous"; - errorBoundaryMessage = - "React will try to recreate this component tree from scratch " + - ("using the error boundary you provided, " + errorBoundaryName + "."); + try { + return updateReducer(reducer, initialArg, init); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; } + }, + useRef: function (initialValue) { + currentHookNameInDev = "useRef"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateRef(); + }, + useState: function (initialState) { + currentHookNameInDev = "useState"; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnUpdateInDEV; - var combinedMessage = - componentNameMessage + - "\n" + - componentStack + - "\n\n" + - ("" + errorBoundaryMessage); // In development, we provide our own message with just the component stack. - // We don't include the original error message and JS stack because the browser - // has already printed it. Even if the application swallows the error, it is still - // displayed by the browser thanks to the DEV-only fake event trick in ReactErrorUtils. - - console["error"](combinedMessage); // Don't transform to our wrapper - } - } catch (e) { - // This method must not throw, or React internal state will get messed up. - // If console.error is overridden, or logCapturedError() shows a dialog that throws, - // we want to report this error outside of the normal stack as a last resort. - // https://github.com/facebook/react/issues/13188 - setTimeout(function () { - throw e; - }); - } -} - -function createRootErrorUpdate(fiber, errorInfo, lane) { - var update = createUpdate(lane); // Unmount the root by rendering null. - - update.tag = CaptureUpdate; // Caution: React DevTools currently depends on this property - // being called "element". - - update.payload = { - element: null + try { + return updateState(initialState); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useDebugValue: function (value, formatterFn) { + currentHookNameInDev = "useDebugValue"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateDebugValue(); + }, + useDeferredValue: function (value) { + currentHookNameInDev = "useDeferredValue"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateDeferredValue(value); + }, + useTransition: function () { + currentHookNameInDev = "useTransition"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateTransition(); + }, + useMutableSource: function (source, getSnapshot, subscribe) { + currentHookNameInDev = "useMutableSource"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateMutableSource(source, getSnapshot, subscribe); + }, + useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { + currentHookNameInDev = "useSyncExternalStore"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateSyncExternalStore(subscribe, getSnapshot); + }, + useId: function () { + currentHookNameInDev = "useId"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateId(); + } }; - var error = errorInfo.value; - update.callback = function () { - onUncaughtError(error); - logCapturedError(fiber, errorInfo); - }; + { + InvalidNestedHooksDispatcherOnUpdateInDEV.use = function (usable) { + warnInvalidHookAccess(); + return use(usable); + }; + } - return update; -} + { + InvalidNestedHooksDispatcherOnUpdateInDEV.useMemoCache = function (size) { + warnInvalidHookAccess(); + return useMemoCache(size); + }; + } -function createClassErrorUpdate(fiber, errorInfo, lane) { - var update = createUpdate(lane); - update.tag = CaptureUpdate; - var getDerivedStateFromError = fiber.type.getDerivedStateFromError; + InvalidNestedHooksDispatcherOnRerenderInDEV = { + readContext: function (context) { + warnInvalidContextAccess(); + return readContext(context); + }, + useCallback: function (callback, deps) { + currentHookNameInDev = "useCallback"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateCallback(callback, deps); + }, + useContext: function (context) { + currentHookNameInDev = "useContext"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return readContext(context); + }, + useEffect: function (create, deps) { + currentHookNameInDev = "useEffect"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateEffect(create, deps); + }, + useImperativeHandle: function (ref, create, deps) { + currentHookNameInDev = "useImperativeHandle"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateImperativeHandle(ref, create, deps); + }, + useInsertionEffect: function (create, deps) { + currentHookNameInDev = "useInsertionEffect"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateInsertionEffect(create, deps); + }, + useLayoutEffect: function (create, deps) { + currentHookNameInDev = "useLayoutEffect"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateLayoutEffect(create, deps); + }, + useMemo: function (create, deps) { + currentHookNameInDev = "useMemo"; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnUpdateInDEV; - if (typeof getDerivedStateFromError === "function") { - var error$1 = errorInfo.value; + try { + return updateMemo(create, deps); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useReducer: function (reducer, initialArg, init) { + currentHookNameInDev = "useReducer"; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnUpdateInDEV; - update.payload = function () { - return getDerivedStateFromError(error$1); - }; + try { + return rerenderReducer(reducer, initialArg, init); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useRef: function (initialValue) { + currentHookNameInDev = "useRef"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateRef(); + }, + useState: function (initialState) { + currentHookNameInDev = "useState"; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnUpdateInDEV; - update.callback = function () { - { - markFailedErrorBoundaryForHotReloading(fiber); + try { + return rerenderState(initialState); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; } + }, + useDebugValue: function (value, formatterFn) { + currentHookNameInDev = "useDebugValue"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateDebugValue(); + }, + useDeferredValue: function (value) { + currentHookNameInDev = "useDeferredValue"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return rerenderDeferredValue(value); + }, + useTransition: function () { + currentHookNameInDev = "useTransition"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return rerenderTransition(); + }, + useMutableSource: function (source, getSnapshot, subscribe) { + currentHookNameInDev = "useMutableSource"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateMutableSource(source, getSnapshot, subscribe); + }, + useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { + currentHookNameInDev = "useSyncExternalStore"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateSyncExternalStore(subscribe, getSnapshot); + }, + useId: function () { + currentHookNameInDev = "useId"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateId(); + } + }; - logCapturedError(fiber, errorInfo); + { + InvalidNestedHooksDispatcherOnRerenderInDEV.use = function (usable) { + warnInvalidHookAccess(); + return use(usable); }; } - var inst = fiber.stateNode; + { + InvalidNestedHooksDispatcherOnRerenderInDEV.useMemoCache = function (size) { + warnInvalidHookAccess(); + return useMemoCache(size); + }; + } +} - if (inst !== null && typeof inst.componentDidCatch === "function") { - // $FlowFixMe[missing-this-annot] - update.callback = function callback() { - { - markFailedErrorBoundaryForHotReloading(fiber); - } +var now = Scheduler.unstable_now; +var commitTime = 0; +var layoutEffectStartTime = -1; +var profilerStartTime = -1; +var passiveEffectStartTime = -1; +/** + * Tracks whether the current update was a nested/cascading update (scheduled from a layout effect). + * + * The overall sequence is: + * 1. render + * 2. commit (and call `onRender`, `onCommit`) + * 3. check for nested updates + * 4. flush passive effects (and call `onPostCommit`) + * + * Nested updates are identified in step 3 above, + * but step 4 still applies to the work that was just committed. + * We use two flags to track nested updates then: + * one tracks whether the upcoming update is a nested update, + * and the other tracks whether the current update was a nested update. + * The first value gets synced to the second at the start of the render phase. + */ - logCapturedError(fiber, errorInfo); +var currentUpdateIsNested = false; +var nestedUpdateScheduled = false; - if (typeof getDerivedStateFromError !== "function") { - // To preserve the preexisting retry behavior of error boundaries, - // we keep track of which ones already failed during this batch. - // This gets reset before we yield back to the browser. - // TODO: Warn in strict mode if getDerivedStateFromError is - // not defined. - markLegacyErrorBoundaryAsFailed(this); - } +function isCurrentUpdateNested() { + return currentUpdateIsNested; +} - var error$1 = errorInfo.value; - var stack = errorInfo.stack; - this.componentDidCatch(error$1, { - componentStack: stack !== null ? stack : "" - }); +function markNestedUpdateScheduled() { + { + nestedUpdateScheduled = true; + } +} - { - if (typeof getDerivedStateFromError !== "function") { - // If componentDidCatch is the only error boundary method defined, - // then it needs to call setState to recover from errors. - // If no state update is scheduled then the boundary will swallow the error. - if (!includesSomeLane(fiber.lanes, SyncLane)) { - error( - "%s: Error boundaries should implement getDerivedStateFromError(). " + - "In that method, return a state update to display an error message or fallback UI.", - getComponentNameFromFiber(fiber) || "Unknown" - ); - } - } - } - }; +function resetNestedUpdateFlag() { + { + currentUpdateIsNested = false; + nestedUpdateScheduled = false; } +} - return update; +function syncNestedUpdateFlag() { + { + currentUpdateIsNested = nestedUpdateScheduled; + nestedUpdateScheduled = false; + } } -function resetSuspendedComponent(sourceFiber, rootRenderLanes) { - // A legacy mode Suspense quirk, only relevant to hook components. +function getCommitTime() { + return commitTime; +} - var tag = sourceFiber.tag; +function recordCommitTime() { + commitTime = now(); +} - if ( - (sourceFiber.mode & ConcurrentMode) === NoMode && - (tag === FunctionComponent || - tag === ForwardRef || - tag === SimpleMemoComponent) - ) { - var currentSource = sourceFiber.alternate; +function startProfilerTimer(fiber) { + profilerStartTime = now(); - if (currentSource) { - sourceFiber.updateQueue = currentSource.updateQueue; - sourceFiber.memoizedState = currentSource.memoizedState; - sourceFiber.lanes = currentSource.lanes; - } else { - sourceFiber.updateQueue = null; - sourceFiber.memoizedState = null; - } + if (fiber.actualStartTime < 0) { + fiber.actualStartTime = now(); } } -function markSuspenseBoundaryShouldCapture( - suspenseBoundary, - returnFiber, - sourceFiber, - root, - rootRenderLanes -) { - // This marks a Suspense boundary so that when we're unwinding the stack, - // it captures the suspended "exception" and does a second (fallback) pass. - if ((suspenseBoundary.mode & ConcurrentMode) === NoMode) { - // Legacy Mode Suspense - // - // If the boundary is in legacy mode, we should *not* - // suspend the commit. Pretend as if the suspended component rendered - // null and keep rendering. When the Suspense boundary completes, - // we'll do a second pass to render the fallback. - if (suspenseBoundary === returnFiber) { - // Special case where we suspended while reconciling the children of - // a Suspense boundary's inner Offscreen wrapper fiber. This happens - // when a React.lazy component is a direct child of a - // Suspense boundary. - // - // Suspense boundaries are implemented as multiple fibers, but they - // are a single conceptual unit. The legacy mode behavior where we - // pretend the suspended fiber committed as `null` won't work, - // because in this case the "suspended" fiber is the inner - // Offscreen wrapper. - // - // Because the contents of the boundary haven't started rendering - // yet (i.e. nothing in the tree has partially rendered) we can - // switch to the regular, concurrent mode behavior: mark the - // boundary with ShouldCapture and enter the unwind phase. - suspenseBoundary.flags |= ShouldCapture; - } else { - suspenseBoundary.flags |= DidCapture; - sourceFiber.flags |= ForceUpdateForLegacySuspense; // We're going to commit this fiber even though it didn't complete. - // But we shouldn't call any lifecycle methods or callbacks. Remove - // all lifecycle effect tags. - - sourceFiber.flags &= ~(LifecycleEffectMask | Incomplete); - - if (sourceFiber.tag === ClassComponent) { - var currentSourceFiber = sourceFiber.alternate; +function stopProfilerTimerIfRunning(fiber) { + profilerStartTime = -1; +} - if (currentSourceFiber === null) { - // This is a new mount. Change the tag so it's not mistaken for a - // completed class component. For example, we should not call - // componentWillUnmount if it is deleted. - sourceFiber.tag = IncompleteClassComponent; - } else { - // When we try rendering again, we should not reuse the current fiber, - // since it's known to be in an inconsistent state. Use a force update to - // prevent a bail out. - var update = createUpdate(SyncLane); - update.tag = ForceUpdate; - enqueueUpdate(sourceFiber, update, SyncLane); - } - } // The source fiber did not complete. Mark it with Sync priority to - // indicate that it still has pending work. +function stopProfilerTimerIfRunningAndRecordDelta(fiber, overrideBaseTime) { + if (profilerStartTime >= 0) { + var elapsedTime = now() - profilerStartTime; + fiber.actualDuration += elapsedTime; - sourceFiber.lanes = mergeLanes(sourceFiber.lanes, SyncLane); + if (overrideBaseTime) { + fiber.selfBaseDuration = elapsedTime; } - return suspenseBoundary; - } // Confirmed that the boundary is in a concurrent mode tree. Continue - // with the normal suspend path. - // - // After this we'll use a set of heuristics to determine whether this - // render pass will run to completion or restart or "suspend" the commit. - // The actual logic for this is spread out in different places. - // - // This first principle is that if we're going to suspend when we complete - // a root, then we should also restart if we get an update or ping that - // might unsuspend it, and vice versa. The only reason to suspend is - // because you think you might want to restart before committing. However, - // it doesn't make sense to restart only while in the period we're suspended. - // - // Restarting too aggressively is also not good because it starves out any - // intermediate loading state. So we use heuristics to determine when. - // Suspense Heuristics - // - // If nothing threw a Promise or all the same fallbacks are already showing, - // then don't suspend/restart. - // - // If this is an initial render of a new tree of Suspense boundaries and - // those trigger a fallback, then don't suspend/restart. We want to ensure - // that we can show the initial loading state as quickly as possible. - // - // If we hit a "Delayed" case, such as when we'd switch from content back into - // a fallback, then we should always suspend/restart. Transitions apply - // to this case. If none is defined, JND is used instead. - // - // If we're already showing a fallback and it gets "retried", allowing us to show - // another level, but there's still an inner boundary that would show a fallback, - // then we suspend/restart for 500ms since the last time we showed a fallback - // anywhere in the tree. This effectively throttles progressive loading into a - // consistent train of commits. This also gives us an opportunity to restart to - // get to the completed state slightly earlier. - // - // If there's ambiguity due to batching it's resolved in preference of: - // 1) "delayed", 2) "initial render", 3) "retry". - // - // We want to ensure that a "busy" state doesn't get force committed. We want to - // ensure that new initial loading states can commit as soon as possible. + profilerStartTime = -1; + } +} - suspenseBoundary.flags |= ShouldCapture; // TODO: I think we can remove this, since we now use `DidCapture` in - // the begin phase to prevent an early bailout. +function recordLayoutEffectDuration(fiber) { + if (layoutEffectStartTime >= 0) { + var elapsedTime = now() - layoutEffectStartTime; + layoutEffectStartTime = -1; // Store duration on the next nearest Profiler ancestor + // Or the root (for the DevTools Profiler to read) - suspenseBoundary.lanes = rootRenderLanes; - return suspenseBoundary; -} + var parentFiber = fiber.return; -function throwException( - root, - returnFiber, - sourceFiber, - value, - rootRenderLanes -) { - // The source fiber did not complete. - sourceFiber.flags |= Incomplete; + while (parentFiber !== null) { + switch (parentFiber.tag) { + case HostRoot: + var root = parentFiber.stateNode; + root.effectDuration += elapsedTime; + return; - { - if (isDevToolsPresent) { - // If we have pending work still, restore the original updaters - restorePendingUpdaters(root, rootRenderLanes); + case Profiler: + var parentStateNode = parentFiber.stateNode; + parentStateNode.effectDuration += elapsedTime; + return; + } + + parentFiber = parentFiber.return; } } +} - if ( - value !== null && - typeof value === "object" && - typeof value.then === "function" - ) { - // This is a wakeable. The component suspended. - var wakeable = value; - resetSuspendedComponent(sourceFiber); - - var suspenseBoundary = getSuspenseHandler(); - - if (suspenseBoundary !== null) { - switch (suspenseBoundary.tag) { - case SuspenseComponent: { - // If this suspense boundary is not already showing a fallback, mark - // the in-progress render as suspended. We try to perform this logic - // as soon as soon as possible during the render phase, so the work - // loop can know things like whether it's OK to switch to other tasks, - // or whether it can wait for data to resolve before continuing. - // TODO: Most of these checks are already performed when entering a - // Suspense boundary. We should track the information on the stack so - // we don't have to recompute it on demand. This would also allow us - // to unify with `use` which needs to perform this logic even sooner, - // before `throwException` is called. - if (sourceFiber.mode & ConcurrentMode) { - if (getShellBoundary() === null) { - // Suspended in the "shell" of the app. This is an undesirable - // loading state. We should avoid committing this tree. - renderDidSuspendDelayIfPossible(); - } else { - // If we suspended deeper than the shell, we don't need to delay - // the commmit. However, we still call renderDidSuspend if this is - // a new boundary, to tell the work loop that a new fallback has - // appeared during this render. - // TODO: Theoretically we should be able to delete this branch. - // It's currently used for two things: 1) to throttle the - // appearance of successive loading states, and 2) in - // SuspenseList, to determine whether the children include any - // pending fallbacks. For 1, we should apply throttling to all - // retries, not just ones that render an additional fallback. For - // 2, we should check subtreeFlags instead. Then we can delete - // this branch. - var current = suspenseBoundary.alternate; +function recordPassiveEffectDuration(fiber) { + if (passiveEffectStartTime >= 0) { + var elapsedTime = now() - passiveEffectStartTime; + passiveEffectStartTime = -1; // Store duration on the next nearest Profiler ancestor + // Or the root (for the DevTools Profiler to read) - if (current === null) { - renderDidSuspend(); - } - } - } + var parentFiber = fiber.return; - suspenseBoundary.flags &= ~ForceClientRender; - markSuspenseBoundaryShouldCapture( - suspenseBoundary, - returnFiber, - sourceFiber, - root, - rootRenderLanes - ); // Retry listener - // - // If the fallback does commit, we need to attach a different type of - // listener. This one schedules an update on the Suspense boundary to - // turn the fallback state off. - // - // Stash the wakeable on the boundary fiber so we can access it in the - // commit phase. - // - // When the wakeable resolves, we'll attempt to render the boundary - // again ("retry"). - // Check if this is a Suspensey resource. We do not attach retry - // listeners to these, because we don't actually need them for - // rendering. Only for committing. Instead, if a fallback commits - // and the only thing that suspended was a Suspensey resource, we - // retry immediately. - // TODO: Refactor throwException so that we don't have to do this type - // check. The caller already knows what the cause was. + while (parentFiber !== null) { + switch (parentFiber.tag) { + case HostRoot: + var root = parentFiber.stateNode; - var isSuspenseyResource = wakeable === noopSuspenseyCommitThenable; + if (root !== null) { + root.passiveEffectDuration += elapsedTime; + } - if (isSuspenseyResource) { - suspenseBoundary.flags |= ScheduleRetry; - } else { - var retryQueue = suspenseBoundary.updateQueue; + return; - if (retryQueue === null) { - suspenseBoundary.updateQueue = new Set([wakeable]); - } else { - retryQueue.add(wakeable); - } - } + case Profiler: + var parentStateNode = parentFiber.stateNode; - break; - } + if (parentStateNode !== null) { + // Detached fibers have their state node cleared out. + // In this case, the return pointer is also cleared out, + // so we won't be able to report the time spent in this Profiler's subtree. + parentStateNode.passiveEffectDuration += elapsedTime; + } - case OffscreenComponent: { - if (suspenseBoundary.mode & ConcurrentMode) { - suspenseBoundary.flags |= ShouldCapture; + return; + } - var _isSuspenseyResource = wakeable === noopSuspenseyCommitThenable; + parentFiber = parentFiber.return; + } + } +} - if (_isSuspenseyResource) { - suspenseBoundary.flags |= ScheduleRetry; - } else { - var offscreenQueue = suspenseBoundary.updateQueue; +function startLayoutEffectTimer() { + layoutEffectStartTime = now(); +} - if (offscreenQueue === null) { - var newOffscreenQueue = { - transitions: null, - markerInstances: null, - retryQueue: new Set([wakeable]) - }; - suspenseBoundary.updateQueue = newOffscreenQueue; - } else { - var _retryQueue = offscreenQueue.retryQueue; +function startPassiveEffectTimer() { + passiveEffectStartTime = now(); +} - if (_retryQueue === null) { - offscreenQueue.retryQueue = new Set([wakeable]); - } else { - _retryQueue.add(wakeable); - } - } - } +function transferActualDuration(fiber) { + // Transfer time spent rendering these children so we don't lose it + // after we rerender. This is used as a helper in special cases + // where we should count the work of multiple passes. + var child = fiber.child; - break; - } - } - // eslint-disable-next-line no-fallthrough + while (child) { + // $FlowFixMe[unsafe-addition] addition with possible null/undefined value + fiber.actualDuration += child.actualDuration; + child = child.sibling; + } +} - default: { - throw new Error( - "Unexpected Suspense handler tag (" + - suspenseBoundary.tag + - "). This " + - "is a bug in React." - ); - } - } // We only attach ping listeners in concurrent mode. Legacy Suspense always - // commits fallbacks synchronously, so there are no pings. +function resolveDefaultProps(Component, baseProps) { + if (Component && Component.defaultProps) { + // Resolve default props. Taken from ReactElement + var props = assign({}, baseProps); + var defaultProps = Component.defaultProps; - if (suspenseBoundary.mode & ConcurrentMode) { - attachPingListener(root, wakeable, rootRenderLanes); + for (var propName in defaultProps) { + if (props[propName] === undefined) { + props[propName] = defaultProps[propName]; } + } + + return props; + } + + return baseProps; +} + +var fakeInternalInstance = {}; +var didWarnAboutStateAssignmentForComponent; +var didWarnAboutUninitializedState; +var didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate; +var didWarnAboutLegacyLifecyclesAndDerivedState; +var didWarnAboutUndefinedDerivedState; +var didWarnAboutDirectlyAssigningPropsToState; +var didWarnAboutContextTypeAndContextTypes; +var didWarnAboutInvalidateContextType; +var didWarnOnInvalidCallback; + +{ + didWarnAboutStateAssignmentForComponent = new Set(); + didWarnAboutUninitializedState = new Set(); + didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate = new Set(); + didWarnAboutLegacyLifecyclesAndDerivedState = new Set(); + didWarnAboutDirectlyAssigningPropsToState = new Set(); + didWarnAboutUndefinedDerivedState = new Set(); + didWarnAboutContextTypeAndContextTypes = new Set(); + didWarnAboutInvalidateContextType = new Set(); + didWarnOnInvalidCallback = new Set(); // This is so gross but it's at least non-critical and can be removed if + // it causes problems. This is meant to give a nicer error message for + // ReactDOM15.unstable_renderSubtreeIntoContainer(reactDOM16Component, + // ...)) which otherwise throws a "_processChildContext is not a function" + // exception. + + Object.defineProperty(fakeInternalInstance, "_processChildContext", { + enumerable: false, + value: function () { + throw new Error( + "_processChildContext is not available in React 16+. This likely " + + "means you have multiple copies of React and are attempting to nest " + + "a React 15 tree inside a React 16 tree using " + + "unstable_renderSubtreeIntoContainer, which isn't supported. Try " + + "to make sure you have only one copy of React (and ideally, switch " + + "to ReactDOM.createPortal)." + ); + } + }); + Object.freeze(fakeInternalInstance); +} +function warnOnInvalidCallback(callback, callerName) { + { + if (callback === null || typeof callback === "function") { return; - } else { - // No boundary was found. Unless this is a sync update, this is OK. - // We can suspend and wait for more data to arrive. - if (root.tag === ConcurrentRoot) { - // In a concurrent root, suspending without a Suspense boundary is - // allowed. It will suspend indefinitely without committing. - // - // TODO: Should we have different behavior for discrete updates? What - // about flushSync? Maybe it should put the tree into an inert state, - // and potentially log a warning. Revisit this for a future release. - attachPingListener(root, wakeable, rootRenderLanes); - renderDidSuspendDelayIfPossible(); - return; - } else { - // In a legacy root, suspending without a boundary is always an error. - var uncaughtSuspenseError = new Error( - "A component suspended while responding to synchronous input. This " + - "will cause the UI to be replaced with a loading indicator. To " + - "fix, updates that suspend should be wrapped " + - "with startTransition." + } + + var key = callerName + "_" + callback; + + if (!didWarnOnInvalidCallback.has(key)) { + didWarnOnInvalidCallback.add(key); + + error( + "%s(...): Expected the last optional `callback` argument to be a " + + "function. Instead received: %s.", + callerName, + callback + ); + } + } +} + +function warnOnUndefinedDerivedState(type, partialState) { + { + if (partialState === undefined) { + var componentName = getComponentNameFromType(type) || "Component"; + + if (!didWarnAboutUndefinedDerivedState.has(componentName)) { + didWarnAboutUndefinedDerivedState.add(componentName); + + error( + "%s.getDerivedStateFromProps(): A valid state object (or null) must be returned. " + + "You have returned undefined.", + componentName ); - value = uncaughtSuspenseError; } } } +} - value = createCapturedValueAtFiber(value, sourceFiber); - renderDidError(value); // We didn't find a boundary that could handle this type of exception. Start - // over and traverse parent path again, this time treating the exception - // as an error. +function applyDerivedStateFromProps( + workInProgress, + ctor, + getDerivedStateFromProps, + nextProps +) { + var prevState = workInProgress.memoizedState; + var partialState = getDerivedStateFromProps(nextProps, prevState); - var workInProgress = returnFiber; + { + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); - do { - switch (workInProgress.tag) { - case HostRoot: { - var _errorInfo = value; - workInProgress.flags |= ShouldCapture; - var lane = pickArbitraryLane(rootRenderLanes); - workInProgress.lanes = mergeLanes(workInProgress.lanes, lane); - var update = createRootErrorUpdate(workInProgress, _errorInfo, lane); - enqueueCapturedUpdate(workInProgress, update); - return; + try { + // Invoke the function an extra time to help detect side-effects. + partialState = getDerivedStateFromProps(nextProps, prevState); + } finally { + setIsStrictModeForDevtools(false); + } + } + + warnOnUndefinedDerivedState(ctor, partialState); + } // Merge the partial state and the previous state. + + var memoizedState = + partialState === null || partialState === undefined + ? prevState + : assign({}, prevState, partialState); + workInProgress.memoizedState = memoizedState; // Once the update queue is empty, persist the derived state onto the + // base state. + + if (workInProgress.lanes === NoLanes) { + // Queue is always non-null for classes + var updateQueue = workInProgress.updateQueue; + updateQueue.baseState = memoizedState; + } +} + +var classComponentUpdater = { + isMounted: isMounted, + // $FlowFixMe[missing-local-annot] + enqueueSetState: function (inst, payload, callback) { + var fiber = get(inst); + var lane = requestUpdateLane(fiber); + var update = createUpdate(lane); + update.payload = payload; + + if (callback !== undefined && callback !== null) { + { + warnOnInvalidCallback(callback, "setState"); } - case ClassComponent: - // Capture and retry - var errorInfo = value; - var ctor = workInProgress.type; - var instance = workInProgress.stateNode; + update.callback = callback; + } - if ( - (workInProgress.flags & DidCapture) === NoFlags$1 && - (typeof ctor.getDerivedStateFromError === "function" || - (instance !== null && - typeof instance.componentDidCatch === "function" && - !isAlreadyFailedLegacyErrorBoundary(instance))) - ) { - workInProgress.flags |= ShouldCapture; + var root = enqueueUpdate(fiber, update, lane); - var _lane = pickArbitraryLane(rootRenderLanes); + if (root !== null) { + var eventTime = requestEventTime(); + scheduleUpdateOnFiber(root, fiber, lane, eventTime); + entangleTransitions(root, fiber, lane); + } - workInProgress.lanes = mergeLanes(workInProgress.lanes, _lane); // Schedule the error boundary to re-render using updated state + { + markStateUpdateScheduled(fiber, lane); + } + }, + enqueueReplaceState: function (inst, payload, callback) { + var fiber = get(inst); + var lane = requestUpdateLane(fiber); + var update = createUpdate(lane); + update.tag = ReplaceState; + update.payload = payload; - var _update = createClassErrorUpdate( - workInProgress, - errorInfo, - _lane - ); + if (callback !== undefined && callback !== null) { + { + warnOnInvalidCallback(callback, "replaceState"); + } - enqueueCapturedUpdate(workInProgress, _update); - return; - } + update.callback = callback; + } - break; - } // $FlowFixMe[incompatible-type] we bail out when we get a null + var root = enqueueUpdate(fiber, update, lane); - workInProgress = workInProgress.return; - } while (workInProgress !== null); -} + if (root !== null) { + var eventTime = requestEventTime(); + scheduleUpdateOnFiber(root, fiber, lane, eventTime); + entangleTransitions(root, fiber, lane); + } -var ReactCurrentOwner$2 = ReactSharedInternals.ReactCurrentOwner; // A special exception that's used to unwind the stack when an update flows -// into a dehydrated boundary. + { + markStateUpdateScheduled(fiber, lane); + } + }, + // $FlowFixMe[missing-local-annot] + enqueueForceUpdate: function (inst, callback) { + var fiber = get(inst); + var lane = requestUpdateLane(fiber); + var update = createUpdate(lane); + update.tag = ForceUpdate; -var SelectiveHydrationException = new Error( - "This is not a real error. It's an implementation detail of React's " + - "selective hydration feature. If this leaks into userspace, it's a bug in " + - "React. Please file an issue." -); -var didReceiveUpdate = false; -var didWarnAboutBadClass; -var didWarnAboutModulePatternComponent; -var didWarnAboutContextTypeOnFunctionComponent; -var didWarnAboutGetDerivedStateOnFunctionComponent; -var didWarnAboutFunctionRefs; -var didWarnAboutReassigningProps; -var didWarnAboutRevealOrder; -var didWarnAboutTailOptions; -var didWarnAboutDefaultPropsOnFunctionComponent; + if (callback !== undefined && callback !== null) { + { + warnOnInvalidCallback(callback, "forceUpdate"); + } -{ - didWarnAboutBadClass = {}; - didWarnAboutModulePatternComponent = {}; - didWarnAboutContextTypeOnFunctionComponent = {}; - didWarnAboutGetDerivedStateOnFunctionComponent = {}; - didWarnAboutFunctionRefs = {}; - didWarnAboutReassigningProps = false; - didWarnAboutRevealOrder = {}; - didWarnAboutTailOptions = {}; - didWarnAboutDefaultPropsOnFunctionComponent = {}; -} + update.callback = callback; + } -function reconcileChildren(current, workInProgress, nextChildren, renderLanes) { - if (current === null) { - // If this is a fresh new component that hasn't been rendered yet, we - // won't update its child set by applying minimal side-effects. Instead, - // we will add them all to the child before it gets rendered. That means - // we can optimize this reconciliation pass by not tracking side-effects. - workInProgress.child = mountChildFibers( - workInProgress, - null, - nextChildren, - renderLanes - ); - } else { - // If the current child is the same as the work in progress, it means that - // we haven't yet started any work on these children. Therefore, we use - // the clone algorithm to create a copy of all the current children. - // If we had any progressed work already, that is invalid at this point so - // let's throw it out. - workInProgress.child = reconcileChildFibers( - workInProgress, - current.child, - nextChildren, - renderLanes - ); + var root = enqueueUpdate(fiber, update, lane); + + if (root !== null) { + var eventTime = requestEventTime(); + scheduleUpdateOnFiber(root, fiber, lane, eventTime); + entangleTransitions(root, fiber, lane); + } + + { + markForceUpdateScheduled(fiber, lane); + } } -} +}; -function forceUnmountCurrentAndReconcile( - current, +function checkShouldComponentUpdate( workInProgress, - nextChildren, - renderLanes + ctor, + oldProps, + newProps, + oldState, + newState, + nextContext ) { - // This function is fork of reconcileChildren. It's used in cases where we - // want to reconcile without matching against the existing set. This has the - // effect of all current children being unmounted; even if the type and key - // are the same, the old child is unmounted and a new child is created. - // - // To do this, we're going to go through the reconcile algorithm twice. In - // the first pass, we schedule a deletion for all the current children by - // passing null. - workInProgress.child = reconcileChildFibers( - workInProgress, - current.child, - null, - renderLanes - ); // In the second pass, we mount the new children. The trick here is that we - // pass null in place of where we usually pass the current child set. This has - // the effect of remounting all children regardless of whether their - // identities match. + var instance = workInProgress.stateNode; - workInProgress.child = reconcileChildFibers( - workInProgress, - null, - nextChildren, - renderLanes - ); -} + if (typeof instance.shouldComponentUpdate === "function") { + var shouldUpdate = instance.shouldComponentUpdate( + newProps, + newState, + nextContext + ); -function updateForwardRef( - current, - workInProgress, - Component, - nextProps, - renderLanes -) { - // TODO: current can be non-null here even if the component - // hasn't yet mounted. This happens after the first render suspends. - // We'll need to figure out if this is fine or can cause issues. - { - if (workInProgress.type !== workInProgress.elementType) { - // Lazy component props can't be validated in createElement - // because they're only guaranteed to be resolved here. - var innerPropTypes = Component.propTypes; + { + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); - if (innerPropTypes) { - checkPropTypes( - innerPropTypes, - nextProps, // Resolved props - "prop", - getComponentNameFromType(Component) + try { + // Invoke the function an extra time to help detect side-effects. + shouldUpdate = instance.shouldComponentUpdate( + newProps, + newState, + nextContext + ); + } finally { + setIsStrictModeForDevtools(false); + } + } + + if (shouldUpdate === undefined) { + error( + "%s.shouldComponentUpdate(): Returned undefined instead of a " + + "boolean value. Make sure to return true or false.", + getComponentNameFromType(ctor) || "Component" ); } } - } - - var render = Component.render; - var ref = workInProgress.ref; // The rest is a fork of updateFunctionComponent - - var nextChildren; - prepareToReadContext(workInProgress, renderLanes); - - { - markComponentRenderStarted(workInProgress); - } - - { - ReactCurrentOwner$2.current = workInProgress; - setIsRendering(true); - nextChildren = renderWithHooks( - current, - workInProgress, - render, - nextProps, - ref, - renderLanes - ); - setIsRendering(false); - } - { - markComponentRenderStopped(); + return shouldUpdate; } - if (current !== null && !didReceiveUpdate) { - bailoutHooks(current, workInProgress, renderLanes); - return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); + if (ctor.prototype && ctor.prototype.isPureReactComponent) { + return ( + !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState) + ); } - workInProgress.flags |= PerformedWork; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; + return true; } -function updateMemoComponent( - current, - workInProgress, - Component, - nextProps, - renderLanes -) { - if (current === null) { - var type = Component.type; +function checkClassInstance(workInProgress, ctor, newProps) { + var instance = workInProgress.stateNode; + + { + var name = getComponentNameFromType(ctor) || "Component"; + var renderPresent = instance.render; + + if (!renderPresent) { + if (ctor.prototype && typeof ctor.prototype.render === "function") { + error( + "%s(...): No `render` method found on the returned component " + + "instance: did you accidentally return an object from the constructor?", + name + ); + } else { + error( + "%s(...): No `render` method found on the returned component " + + "instance: you may have forgotten to define `render`.", + name + ); + } + } if ( - isSimpleFunctionComponent(type) && - Component.compare === null && // SimpleMemoComponent codepath doesn't resolve outer props either. - Component.defaultProps === undefined + instance.getInitialState && + !instance.getInitialState.isReactClassApproved && + !instance.state ) { - var resolvedType = type; - - { - resolvedType = resolveFunctionForHotReloading(type); - } // If this is a plain function component without default props, - // and with only the default shallow comparison, we upgrade it - // to a SimpleMemoComponent to allow fast path updates. + error( + "getInitialState was defined on %s, a plain JavaScript class. " + + "This is only supported for classes created using React.createClass. " + + "Did you mean to define a state property instead?", + name + ); + } - workInProgress.tag = SimpleMemoComponent; - workInProgress.type = resolvedType; + if ( + instance.getDefaultProps && + !instance.getDefaultProps.isReactClassApproved + ) { + error( + "getDefaultProps was defined on %s, a plain JavaScript class. " + + "This is only supported for classes created using React.createClass. " + + "Use a static property to define defaultProps instead.", + name + ); + } - { - validateFunctionComponentInDev(workInProgress, type); - } + if (instance.propTypes) { + error( + "propTypes was defined as an instance property on %s. Use a static " + + "property to define propTypes instead.", + name + ); + } - return updateSimpleMemoComponent( - current, - workInProgress, - resolvedType, - nextProps, - renderLanes + if (instance.contextType) { + error( + "contextType was defined as an instance property on %s. Use a static " + + "property to define contextType instead.", + name ); } { - var innerPropTypes = type.propTypes; - - if (innerPropTypes) { - // Inner memo component props aren't currently validated in createElement. - // We could move it there, but we'd still need this for lazy code path. - checkPropTypes( - innerPropTypes, - nextProps, // Resolved props - "prop", - getComponentNameFromType(type) + if (instance.contextTypes) { + error( + "contextTypes was defined as an instance property on %s. Use a static " + + "property to define contextTypes instead.", + name ); } - if (Component.defaultProps !== undefined) { - var componentName = getComponentNameFromType(type) || "Unknown"; - - if (!didWarnAboutDefaultPropsOnFunctionComponent[componentName]) { - error( - "%s: Support for defaultProps will be removed from memo components " + - "in a future major release. Use JavaScript default parameters instead.", - componentName - ); + if ( + ctor.contextType && + ctor.contextTypes && + !didWarnAboutContextTypeAndContextTypes.has(ctor) + ) { + didWarnAboutContextTypeAndContextTypes.add(ctor); - didWarnAboutDefaultPropsOnFunctionComponent[componentName] = true; - } + error( + "%s declares both contextTypes and contextType static properties. " + + "The legacy contextTypes property will be ignored.", + name + ); } } - var child = createFiberFromTypeAndProps( - Component.type, - null, - nextProps, - workInProgress, - workInProgress.mode, - renderLanes - ); - child.ref = workInProgress.ref; - child.return = workInProgress; - workInProgress.child = child; - return child; - } - - { - var _type = Component.type; - var _innerPropTypes = _type.propTypes; - - if (_innerPropTypes) { - // Inner memo component props aren't currently validated in createElement. - // We could move it there, but we'd still need this for lazy code path. - checkPropTypes( - _innerPropTypes, - nextProps, // Resolved props - "prop", - getComponentNameFromType(_type) + if (typeof instance.componentShouldUpdate === "function") { + error( + "%s has a method called " + + "componentShouldUpdate(). Did you mean shouldComponentUpdate()? " + + "The name is phrased as a question because the function is " + + "expected to return a value.", + name ); } - } - - var currentChild = current.child; // This is always exactly one child - - var hasScheduledUpdateOrContext = checkScheduledUpdateOrContext( - current, - renderLanes - ); - - if (!hasScheduledUpdateOrContext) { - // This will be the props with resolved defaultProps, - // unlike current.memoizedProps which will be the unresolved ones. - var prevProps = currentChild.memoizedProps; // Default to shallow comparison - - var compare = Component.compare; - compare = compare !== null ? compare : shallowEqual; - if (compare(prevProps, nextProps) && current.ref === workInProgress.ref) { - return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); + if ( + ctor.prototype && + ctor.prototype.isPureReactComponent && + typeof instance.shouldComponentUpdate !== "undefined" + ) { + error( + "%s has a method called shouldComponentUpdate(). " + + "shouldComponentUpdate should not be used when extending React.PureComponent. " + + "Please extend React.Component if shouldComponentUpdate is used.", + getComponentNameFromType(ctor) || "A pure component" + ); } - } // React DevTools reads this flag. - workInProgress.flags |= PerformedWork; - var newChild = createWorkInProgress(currentChild, nextProps); - newChild.ref = workInProgress.ref; - newChild.return = workInProgress; - workInProgress.child = newChild; - return newChild; -} + if (typeof instance.componentDidUnmount === "function") { + error( + "%s has a method called " + + "componentDidUnmount(). But there is no such lifecycle method. " + + "Did you mean componentWillUnmount()?", + name + ); + } -function updateSimpleMemoComponent( - current, - workInProgress, - Component, - nextProps, - renderLanes -) { - // TODO: current can be non-null here even if the component - // hasn't yet mounted. This happens when the inner render suspends. - // We'll need to figure out if this is fine or can cause issues. - { - if (workInProgress.type !== workInProgress.elementType) { - // Lazy component props can't be validated in createElement - // because they're only guaranteed to be resolved here. - var outerMemoType = workInProgress.elementType; + if (typeof instance.componentDidReceiveProps === "function") { + error( + "%s has a method called " + + "componentDidReceiveProps(). But there is no such lifecycle method. " + + "If you meant to update the state in response to changing props, " + + "use componentWillReceiveProps(). If you meant to fetch data or " + + "run side-effects or mutations after React has updated the UI, use componentDidUpdate().", + name + ); + } - if (outerMemoType.$$typeof === REACT_LAZY_TYPE) { - // We warn when you define propTypes on lazy() - // so let's just skip over it to find memo() outer wrapper. - // Inner props for memo are validated later. - var lazyComponent = outerMemoType; - var payload = lazyComponent._payload; - var init = lazyComponent._init; + if (typeof instance.componentWillRecieveProps === "function") { + error( + "%s has a method called " + + "componentWillRecieveProps(). Did you mean componentWillReceiveProps()?", + name + ); + } - try { - outerMemoType = init(payload); - } catch (x) { - outerMemoType = null; - } // Inner propTypes will be validated in the function component path. + if (typeof instance.UNSAFE_componentWillRecieveProps === "function") { + error( + "%s has a method called " + + "UNSAFE_componentWillRecieveProps(). Did you mean UNSAFE_componentWillReceiveProps()?", + name + ); + } - var outerPropTypes = outerMemoType && outerMemoType.propTypes; + var hasMutatedProps = instance.props !== newProps; - if (outerPropTypes) { - checkPropTypes( - outerPropTypes, - nextProps, // Resolved (SimpleMemoComponent has no defaultProps) - "prop", - getComponentNameFromType(outerMemoType) - ); - } - } + if (instance.props !== undefined && hasMutatedProps) { + error( + "%s(...): When calling super() in `%s`, make sure to pass " + + "up the same props that your component's constructor was passed.", + name, + name + ); } - } - if (current !== null) { - var prevProps = current.memoizedProps; + if (instance.defaultProps) { + error( + "Setting defaultProps as an instance property on %s is not supported and will be ignored." + + " Instead, define defaultProps as a static property on %s.", + name, + name + ); + } if ( - shallowEqual(prevProps, nextProps) && - current.ref === workInProgress.ref && // Prevent bailout if the implementation changed due to hot reload. - workInProgress.type === current.type + typeof instance.getSnapshotBeforeUpdate === "function" && + typeof instance.componentDidUpdate !== "function" && + !didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.has(ctor) ) { - didReceiveUpdate = false; // The props are shallowly equal. Reuse the previous props object, like we - // would during a normal fiber bailout. - // - // We don't have strong guarantees that the props object is referentially - // equal during updates where we can't bail out anyway — like if the props - // are shallowly equal, but there's a local state or context update in the - // same batch. - // - // However, as a principle, we should aim to make the behavior consistent - // across different ways of memoizing a component. For example, React.memo - // has a different internal Fiber layout if you pass a normal function - // component (SimpleMemoComponent) versus if you pass a different type - // like forwardRef (MemoComponent). But this is an implementation detail. - // Wrapping a component in forwardRef (or React.lazy, etc) shouldn't - // affect whether the props object is reused during a bailout. - - workInProgress.pendingProps = nextProps = prevProps; + didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.add(ctor); - if (!checkScheduledUpdateOrContext(current, renderLanes)) { - // The pending lanes were cleared at the beginning of beginWork. We're - // about to bail out, but there might be other lanes that weren't - // included in the current render. Usually, the priority level of the - // remaining updates is accumulated during the evaluation of the - // component (i.e. when processing the update queue). But since since - // we're bailing out early *without* evaluating the component, we need - // to account for it here, too. Reset to the value of the current fiber. - // NOTE: This only applies to SimpleMemoComponent, not MemoComponent, - // because a MemoComponent fiber does not have hooks or an update queue; - // rather, it wraps around an inner component, which may or may not - // contains hooks. - // TODO: Move the reset at in beginWork out of the common path so that - // this is no longer necessary. - workInProgress.lanes = current.lanes; - return bailoutOnAlreadyFinishedWork( - current, - workInProgress, - renderLanes - ); - } else if ((current.flags & ForceUpdateForLegacySuspense) !== NoFlags$1) { - // This is a special case that only exists for legacy mode. - // See https://github.com/facebook/react/pull/19216. - didReceiveUpdate = true; - } + error( + "%s: getSnapshotBeforeUpdate() should be used with componentDidUpdate(). " + + "This component defines getSnapshotBeforeUpdate() only.", + getComponentNameFromType(ctor) + ); } - } - return updateFunctionComponent( - current, - workInProgress, - Component, - nextProps, - renderLanes - ); -} + if (typeof instance.getDerivedStateFromProps === "function") { + error( + "%s: getDerivedStateFromProps() is defined as an instance method " + + "and will be ignored. Instead, declare it as a static method.", + name + ); + } -function updateOffscreenComponent(current, workInProgress, renderLanes) { - var nextProps = workInProgress.pendingProps; - var nextChildren = nextProps.children; - var nextIsDetached = - (workInProgress.stateNode._pendingVisibility & OffscreenDetached) !== 0; - var prevState = current !== null ? current.memoizedState : null; - markRef$1(current, workInProgress); + if (typeof instance.getDerivedStateFromError === "function") { + error( + "%s: getDerivedStateFromError() is defined as an instance method " + + "and will be ignored. Instead, declare it as a static method.", + name + ); + } - if ( - nextProps.mode === "hidden" || - nextProps.mode === "unstable-defer-without-hiding" || - nextIsDetached - ) { - // Rendering a hidden tree. - var didSuspend = (workInProgress.flags & DidCapture) !== NoFlags$1; + if (typeof ctor.getSnapshotBeforeUpdate === "function") { + error( + "%s: getSnapshotBeforeUpdate() is defined as a static method " + + "and will be ignored. Instead, declare it as an instance method.", + name + ); + } - if (didSuspend) { - // Something suspended inside a hidden tree - // Include the base lanes from the last render - var nextBaseLanes = - prevState !== null - ? mergeLanes(prevState.baseLanes, renderLanes) - : renderLanes; + var state = instance.state; - if (current !== null) { - // Reset to the current children - var currentChild = (workInProgress.child = current.child); // The current render suspended, but there may be other lanes with - // pending work. We can't read `childLanes` from the current Offscreen - // fiber because we reset it when it was deferred; however, we can read - // the pending lanes from the child fibers. + if (state && (typeof state !== "object" || isArray(state))) { + error("%s.state: must be set to an object or null", name); + } - var currentChildLanes = NoLanes; + if ( + typeof instance.getChildContext === "function" && + typeof ctor.childContextTypes !== "object" + ) { + error( + "%s.getChildContext(): childContextTypes must be defined in order to " + + "use getChildContext().", + name + ); + } + } +} - while (currentChild !== null) { - currentChildLanes = mergeLanes( - mergeLanes(currentChildLanes, currentChild.lanes), - currentChild.childLanes - ); - currentChild = currentChild.sibling; - } +function adoptClassInstance(workInProgress, instance) { + instance.updater = classComponentUpdater; + workInProgress.stateNode = instance; // The instance needs access to the fiber so that it can schedule updates - var lanesWeJustAttempted = nextBaseLanes; - var remainingChildLanes = removeLanes( - currentChildLanes, - lanesWeJustAttempted - ); - workInProgress.childLanes = remainingChildLanes; - } else { - workInProgress.childLanes = NoLanes; - workInProgress.child = null; - } + set(instance, workInProgress); - return deferHiddenOffscreenComponent( - current, - workInProgress, - nextBaseLanes - ); - } + { + instance._reactInternalInstance = fakeInternalInstance; + } +} - if ((workInProgress.mode & ConcurrentMode) === NoMode) { - // In legacy sync mode, don't defer the subtree. Render it now. - // TODO: Consider how Offscreen should work with transitions in the future - var nextState = { - baseLanes: NoLanes, - cachePool: null - }; - workInProgress.memoizedState = nextState; +function constructClassInstance(workInProgress, ctor, props) { + var isLegacyContextConsumer = false; + var unmaskedContext = emptyContextObject; + var context = emptyContextObject; + var contextType = ctor.contextType; - reuseHiddenContextOnStack(workInProgress); - pushOffscreenSuspenseHandler(workInProgress); - } else if (!includesSomeLane(renderLanes, OffscreenLane)) { - // We're hidden, and we're not rendering at Offscreen. We will bail out - // and resume this tree later. - // Schedule this fiber to re-render at Offscreen priority - workInProgress.lanes = workInProgress.childLanes = - laneToLanes(OffscreenLane); // Include the base lanes from the last render + { + if ("contextType" in ctor) { + var isValid = // Allow null for conditional declaration + contextType === null || + (contextType !== undefined && + contextType.$$typeof === REACT_CONTEXT_TYPE && + contextType._context === undefined); // Not a - var _nextBaseLanes = - prevState !== null - ? mergeLanes(prevState.baseLanes, renderLanes) - : renderLanes; + if (!isValid && !didWarnAboutInvalidateContextType.has(ctor)) { + didWarnAboutInvalidateContextType.add(ctor); + var addendum = ""; - return deferHiddenOffscreenComponent( - current, - workInProgress, - _nextBaseLanes - ); - } else { - // This is the second render. The surrounding visible content has already - // committed. Now we resume rendering the hidden tree. - // Rendering at offscreen, so we can clear the base lanes. - var _nextState = { - baseLanes: NoLanes, - cachePool: null - }; - workInProgress.memoizedState = _nextState; + if (contextType === undefined) { + addendum = + " However, it is set to undefined. " + + "This can be caused by a typo or by mixing up named and default imports. " + + "This can also happen due to a circular dependency, so " + + "try moving the createContext() call to a separate file."; + } else if (typeof contextType !== "object") { + addendum = " However, it is set to a " + typeof contextType + "."; + } else if (contextType.$$typeof === REACT_PROVIDER_TYPE) { + addendum = " Did you accidentally pass the Context.Provider instead?"; + } else if (contextType._context !== undefined) { + // + addendum = " Did you accidentally pass the Context.Consumer instead?"; + } else { + addendum = + " However, it is set to an object with keys {" + + Object.keys(contextType).join(", ") + + "}."; + } - if (prevState !== null) { - pushHiddenContext(workInProgress, prevState); - } else { - reuseHiddenContextOnStack(workInProgress); + error( + "%s defines an invalid contextType. " + + "contextType should point to the Context object returned by React.createContext().%s", + getComponentNameFromType(ctor) || "Component", + addendum + ); } - - pushOffscreenSuspenseHandler(workInProgress); } + } + + if (typeof contextType === "object" && contextType !== null) { + context = readContext(contextType); } else { - // Rendering a visible tree. - if (prevState !== null) { - pushHiddenContext(workInProgress, prevState); - reuseSuspenseHandlerOnStack(workInProgress); // Since we're not hidden anymore, reset the state + unmaskedContext = getUnmaskedContext(workInProgress, ctor, true); + var contextTypes = ctor.contextTypes; + isLegacyContextConsumer = + contextTypes !== null && contextTypes !== undefined; + context = isLegacyContextConsumer + ? getMaskedContext(workInProgress, unmaskedContext) + : emptyContextObject; + } - workInProgress.memoizedState = null; - } else { - // to avoid a push/pop misalignment. + var instance = new ctor(props, context); // Instantiate twice to help detect side-effects. - reuseHiddenContextOnStack(workInProgress); - reuseSuspenseHandlerOnStack(workInProgress); + { + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); + + try { + instance = new ctor(props, context); // eslint-disable-line no-new + } finally { + setIsStrictModeForDevtools(false); + } } } - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; -} - -function deferHiddenOffscreenComponent( - current, - workInProgress, - nextBaseLanes, - renderLanes -) { - var nextState = { - baseLanes: nextBaseLanes, - // Save the cache pool so we can resume later. - cachePool: null - }; - workInProgress.memoizedState = nextState; - // to avoid a push/pop misalignment. - - reuseHiddenContextOnStack(workInProgress); - pushOffscreenSuspenseHandler(workInProgress); + var state = (workInProgress.memoizedState = + instance.state !== null && instance.state !== undefined + ? instance.state + : null); + adoptClassInstance(workInProgress, instance); - return null; -} // Note: These happen to have identical begin phases, for now. We shouldn't hold -// ourselves to this constraint, though. If the behavior diverges, we should -// fork the function. + { + if (typeof ctor.getDerivedStateFromProps === "function" && state === null) { + var componentName = getComponentNameFromType(ctor) || "Component"; -var updateLegacyHiddenComponent = updateOffscreenComponent; + if (!didWarnAboutUninitializedState.has(componentName)) { + didWarnAboutUninitializedState.add(componentName); -function updateFragment(current, workInProgress, renderLanes) { - var nextChildren = workInProgress.pendingProps; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; -} + error( + "`%s` uses `getDerivedStateFromProps` but its initial state is " + + "%s. This is not recommended. Instead, define the initial state by " + + "assigning an object to `this.state` in the constructor of `%s`. " + + "This ensures that `getDerivedStateFromProps` arguments have a consistent shape.", + componentName, + instance.state === null ? "null" : "undefined", + componentName + ); + } + } // If new component APIs are defined, "unsafe" lifecycles won't be called. + // Warn about these lifecycles if they are present. + // Don't warn about react-lifecycles-compat polyfilled methods though. -function updateMode(current, workInProgress, renderLanes) { - var nextChildren = workInProgress.pendingProps.children; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; -} + if ( + typeof ctor.getDerivedStateFromProps === "function" || + typeof instance.getSnapshotBeforeUpdate === "function" + ) { + var foundWillMountName = null; + var foundWillReceivePropsName = null; + var foundWillUpdateName = null; -function updateProfiler(current, workInProgress, renderLanes) { - { - workInProgress.flags |= Update; + if ( + typeof instance.componentWillMount === "function" && + instance.componentWillMount.__suppressDeprecationWarning !== true + ) { + foundWillMountName = "componentWillMount"; + } else if (typeof instance.UNSAFE_componentWillMount === "function") { + foundWillMountName = "UNSAFE_componentWillMount"; + } - { - // Reset effect durations for the next eventual effect phase. - // These are reset during render to allow the DevTools commit hook a chance to read them, - var stateNode = workInProgress.stateNode; - stateNode.effectDuration = 0; - stateNode.passiveEffectDuration = 0; - } - } + if ( + typeof instance.componentWillReceiveProps === "function" && + instance.componentWillReceiveProps.__suppressDeprecationWarning !== true + ) { + foundWillReceivePropsName = "componentWillReceiveProps"; + } else if ( + typeof instance.UNSAFE_componentWillReceiveProps === "function" + ) { + foundWillReceivePropsName = "UNSAFE_componentWillReceiveProps"; + } - var nextProps = workInProgress.pendingProps; - var nextChildren = nextProps.children; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; -} + if ( + typeof instance.componentWillUpdate === "function" && + instance.componentWillUpdate.__suppressDeprecationWarning !== true + ) { + foundWillUpdateName = "componentWillUpdate"; + } else if (typeof instance.UNSAFE_componentWillUpdate === "function") { + foundWillUpdateName = "UNSAFE_componentWillUpdate"; + } -function markRef$1(current, workInProgress) { - var ref = workInProgress.ref; + if ( + foundWillMountName !== null || + foundWillReceivePropsName !== null || + foundWillUpdateName !== null + ) { + var _componentName = getComponentNameFromType(ctor) || "Component"; - if ( - (current === null && ref !== null) || - (current !== null && current.ref !== ref) - ) { - // Schedule a Ref effect - workInProgress.flags |= Ref; - workInProgress.flags |= RefStatic; - } -} + var newApiName = + typeof ctor.getDerivedStateFromProps === "function" + ? "getDerivedStateFromProps()" + : "getSnapshotBeforeUpdate()"; -function updateFunctionComponent( - current, - workInProgress, - Component, - nextProps, - renderLanes -) { - { - if (workInProgress.type !== workInProgress.elementType) { - // Lazy component props can't be validated in createElement - // because they're only guaranteed to be resolved here. - var innerPropTypes = Component.propTypes; + if (!didWarnAboutLegacyLifecyclesAndDerivedState.has(_componentName)) { + didWarnAboutLegacyLifecyclesAndDerivedState.add(_componentName); - if (innerPropTypes) { - checkPropTypes( - innerPropTypes, - nextProps, // Resolved props - "prop", - getComponentNameFromType(Component) - ); + error( + "Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n" + + "%s uses %s but also contains the following legacy lifecycles:%s%s%s\n\n" + + "The above lifecycles should be removed. Learn more about this warning here:\n" + + "https://reactjs.org/link/unsafe-component-lifecycles", + _componentName, + newApiName, + foundWillMountName !== null ? "\n " + foundWillMountName : "", + foundWillReceivePropsName !== null + ? "\n " + foundWillReceivePropsName + : "", + foundWillUpdateName !== null ? "\n " + foundWillUpdateName : "" + ); + } } } - } - - var context; + } // Cache unmasked context so we can avoid recreating masked context unless necessary. + // ReactFiberContext usually updates this cache but can't for newly-created instances. - { - var unmaskedContext = getUnmaskedContext(workInProgress, Component, true); - context = getMaskedContext(workInProgress, unmaskedContext); + if (isLegacyContextConsumer) { + cacheContext(workInProgress, unmaskedContext, context); } - var nextChildren; - prepareToReadContext(workInProgress, renderLanes); + return instance; +} - { - markComponentRenderStarted(workInProgress); - } +function callComponentWillMount(workInProgress, instance) { + var oldState = instance.state; - { - ReactCurrentOwner$2.current = workInProgress; - setIsRendering(true); - nextChildren = renderWithHooks( - current, - workInProgress, - Component, - nextProps, - context, - renderLanes - ); - setIsRendering(false); + if (typeof instance.componentWillMount === "function") { + instance.componentWillMount(); } - { - markComponentRenderStopped(); + if (typeof instance.UNSAFE_componentWillMount === "function") { + instance.UNSAFE_componentWillMount(); } - if (current !== null && !didReceiveUpdate) { - bailoutHooks(current, workInProgress, renderLanes); - return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); + if (oldState !== instance.state) { + { + error( + "%s.componentWillMount(): Assigning directly to this.state is " + + "deprecated (except inside a component's " + + "constructor). Use setState instead.", + getComponentNameFromFiber(workInProgress) || "Component" + ); + } + + classComponentUpdater.enqueueReplaceState(instance, instance.state, null); } - - workInProgress.flags |= PerformedWork; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; } -function replayFunctionComponent( - current, +function callComponentWillReceiveProps( workInProgress, - nextProps, - Component, - renderLanes + instance, + newProps, + nextContext ) { - // This function is used to replay a component that previously suspended, - // after its data resolves. It's a simplified version of - // updateFunctionComponent that reuses the hooks from the previous attempt. - var context; + var oldState = instance.state; - { - var unmaskedContext = getUnmaskedContext(workInProgress, Component, true); - context = getMaskedContext(workInProgress, unmaskedContext); + if (typeof instance.componentWillReceiveProps === "function") { + instance.componentWillReceiveProps(newProps, nextContext); } - prepareToReadContext(workInProgress, renderLanes); - - { - markComponentRenderStarted(workInProgress); + if (typeof instance.UNSAFE_componentWillReceiveProps === "function") { + instance.UNSAFE_componentWillReceiveProps(newProps, nextContext); } - var nextChildren = replaySuspendedComponentWithHooks( - current, - workInProgress, - Component, - nextProps, - context - ); + if (instance.state !== oldState) { + { + var componentName = + getComponentNameFromFiber(workInProgress) || "Component"; - { - markComponentRenderStopped(); + if (!didWarnAboutStateAssignmentForComponent.has(componentName)) { + didWarnAboutStateAssignmentForComponent.add(componentName); + + error( + "%s.componentWillReceiveProps(): Assigning directly to " + + "this.state is deprecated (except inside a component's " + + "constructor). Use setState instead.", + componentName + ); + } + } + + classComponentUpdater.enqueueReplaceState(instance, instance.state, null); } +} // Invokes the mount life-cycles on a previously never rendered instance. - if (current !== null && !didReceiveUpdate) { - bailoutHooks(current, workInProgress, renderLanes); - return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); +function mountClassInstance(workInProgress, ctor, newProps, renderLanes) { + { + checkClassInstance(workInProgress, ctor, newProps); } - workInProgress.flags |= PerformedWork; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; -} + var instance = workInProgress.stateNode; + instance.props = newProps; + instance.state = workInProgress.memoizedState; + instance.refs = {}; + initializeUpdateQueue(workInProgress); + var contextType = ctor.contextType; + + if (typeof contextType === "object" && contextType !== null) { + instance.context = readContext(contextType); + } else { + var unmaskedContext = getUnmaskedContext(workInProgress, ctor, true); + instance.context = getMaskedContext(workInProgress, unmaskedContext); + } -function updateClassComponent( - current, - workInProgress, - Component, - nextProps, - renderLanes -) { { - // This is used by DevTools to force a boundary to error. - switch (shouldError(workInProgress)) { - case false: { - var _instance = workInProgress.stateNode; - var ctor = workInProgress.type; // TODO This way of resetting the error boundary state is a hack. - // Is there a better way to do this? + if (instance.state === newProps) { + var componentName = getComponentNameFromType(ctor) || "Component"; - var tempInstance = new ctor( - workInProgress.memoizedProps, - _instance.context + if (!didWarnAboutDirectlyAssigningPropsToState.has(componentName)) { + didWarnAboutDirectlyAssigningPropsToState.add(componentName); + + error( + "%s: It is not recommended to assign props directly to state " + + "because updates to props won't be reflected in state. " + + "In most cases, it is better to use props directly.", + componentName ); - var state = tempInstance.state; + } + } - _instance.updater.enqueueSetState(_instance, state, null); + if (workInProgress.mode & StrictLegacyMode) { + ReactStrictModeWarnings.recordLegacyContextWarning( + workInProgress, + instance + ); + } - break; - } + ReactStrictModeWarnings.recordUnsafeLifecycleWarnings( + workInProgress, + instance + ); + } - case true: { - workInProgress.flags |= DidCapture; - workInProgress.flags |= ShouldCapture; // eslint-disable-next-line react-internal/prod-error-codes + instance.state = workInProgress.memoizedState; + var getDerivedStateFromProps = ctor.getDerivedStateFromProps; - var error$1 = new Error("Simulated error coming from DevTools"); - var lane = pickArbitraryLane(renderLanes); - workInProgress.lanes = mergeLanes(workInProgress.lanes, lane); // Schedule the error boundary to re-render using updated state + if (typeof getDerivedStateFromProps === "function") { + applyDerivedStateFromProps( + workInProgress, + ctor, + getDerivedStateFromProps, + newProps + ); + instance.state = workInProgress.memoizedState; + } // In order to support react-lifecycles-compat polyfilled components, + // Unsafe lifecycles should not be invoked for components using the new APIs. - var update = createClassErrorUpdate( - workInProgress, - createCapturedValueAtFiber(error$1, workInProgress), - lane - ); - enqueueCapturedUpdate(workInProgress, update); - break; - } - } + if ( + typeof ctor.getDerivedStateFromProps !== "function" && + typeof instance.getSnapshotBeforeUpdate !== "function" && + (typeof instance.UNSAFE_componentWillMount === "function" || + typeof instance.componentWillMount === "function") + ) { + callComponentWillMount(workInProgress, instance); // If we had additional state updates during this life-cycle, let's + // process them now. - if (workInProgress.type !== workInProgress.elementType) { - // Lazy component props can't be validated in createElement - // because they're only guaranteed to be resolved here. - var innerPropTypes = Component.propTypes; + processUpdateQueue(workInProgress, newProps, instance, renderLanes); + instance.state = workInProgress.memoizedState; + } - if (innerPropTypes) { - checkPropTypes( - innerPropTypes, - nextProps, // Resolved props - "prop", - getComponentNameFromType(Component) - ); - } - } - } // Push context providers early to prevent context stack mismatches. - // During mounting we don't know the child context yet as the instance doesn't exist. - // We will invalidate the child context in finishClassComponent() right after rendering. + if (typeof instance.componentDidMount === "function") { + var fiberFlags = Update | LayoutStatic; - var hasContext; + if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { + fiberFlags |= MountLayoutDev; + } - if (isContextProvider(Component)) { - hasContext = true; - pushContextProvider(workInProgress); - } else { - hasContext = false; + workInProgress.flags |= fiberFlags; } +} - prepareToReadContext(workInProgress, renderLanes); +function resumeMountClassInstance(workInProgress, ctor, newProps, renderLanes) { var instance = workInProgress.stateNode; - var shouldUpdate; - - if (instance === null) { - resetSuspendedCurrentOnMountInLegacyMode(current, workInProgress); // In the initial pass we might need to construct the instance. + var oldProps = workInProgress.memoizedProps; + instance.props = oldProps; + var oldContext = instance.context; + var contextType = ctor.contextType; + var nextContext = emptyContextObject; - constructClassInstance(workInProgress, Component, nextProps); - mountClassInstance(workInProgress, Component, nextProps, renderLanes); - shouldUpdate = true; - } else if (current === null) { - // In a resume, we'll already have an instance we can reuse. - shouldUpdate = resumeMountClassInstance( - workInProgress, - Component, - nextProps, - renderLanes - ); + if (typeof contextType === "object" && contextType !== null) { + nextContext = readContext(contextType); } else { - shouldUpdate = updateClassInstance( - current, + var nextLegacyUnmaskedContext = getUnmaskedContext( workInProgress, - Component, - nextProps, - renderLanes + ctor, + true ); + nextContext = getMaskedContext(workInProgress, nextLegacyUnmaskedContext); } - var nextUnitOfWork = finishClassComponent( - current, - workInProgress, - Component, - shouldUpdate, - hasContext, - renderLanes - ); - - { - var inst = workInProgress.stateNode; - - if (shouldUpdate && inst.props !== nextProps) { - if (!didWarnAboutReassigningProps) { - error( - "It looks like %s is reassigning its own `this.props` while rendering. " + - "This is not supported and can lead to confusing bugs.", - getComponentNameFromFiber(workInProgress) || "a component" - ); - } + var getDerivedStateFromProps = ctor.getDerivedStateFromProps; + var hasNewLifecycles = + typeof getDerivedStateFromProps === "function" || + typeof instance.getSnapshotBeforeUpdate === "function"; // Note: During these life-cycles, instance.props/instance.state are what + // ever the previously attempted to render - not the "current". However, + // during componentDidUpdate we pass the "current" props. + // In order to support react-lifecycles-compat polyfilled components, + // Unsafe lifecycles should not be invoked for components using the new APIs. - didWarnAboutReassigningProps = true; + if ( + !hasNewLifecycles && + (typeof instance.UNSAFE_componentWillReceiveProps === "function" || + typeof instance.componentWillReceiveProps === "function") + ) { + if (oldProps !== newProps || oldContext !== nextContext) { + callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + nextContext + ); } } - return nextUnitOfWork; -} + resetHasForceUpdateBeforeProcessing(); + var oldState = workInProgress.memoizedState; + var newState = (instance.state = oldState); + processUpdateQueue(workInProgress, newProps, instance, renderLanes); + newState = workInProgress.memoizedState; -function finishClassComponent( - current, - workInProgress, - Component, - shouldUpdate, - hasContext, - renderLanes -) { - // Refs should update even if shouldComponentUpdate returns false - markRef$1(current, workInProgress); - var didCaptureError = (workInProgress.flags & DidCapture) !== NoFlags$1; + if ( + oldProps === newProps && + oldState === newState && + !hasContextChanged() && + !checkHasForceUpdateAfterProcessing() + ) { + // If an update was already in progress, we should schedule an Update + // effect even though we're bailing out, so that cWU/cDU are called. + if (typeof instance.componentDidMount === "function") { + var fiberFlags = Update | LayoutStatic; - if (!shouldUpdate && !didCaptureError) { - // Context providers should defer to sCU for rendering - if (hasContext) { - invalidateContextProvider(workInProgress, Component, false); + if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { + fiberFlags |= MountLayoutDev; + } + + workInProgress.flags |= fiberFlags; } - return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); + return false; } - var instance = workInProgress.stateNode; // Rerender + if (typeof getDerivedStateFromProps === "function") { + applyDerivedStateFromProps( + workInProgress, + ctor, + getDerivedStateFromProps, + newProps + ); + newState = workInProgress.memoizedState; + } - ReactCurrentOwner$2.current = workInProgress; - var nextChildren; + var shouldUpdate = + checkHasForceUpdateAfterProcessing() || + checkShouldComponentUpdate( + workInProgress, + ctor, + oldProps, + newProps, + oldState, + newState, + nextContext + ); - if ( - didCaptureError && - typeof Component.getDerivedStateFromError !== "function" - ) { - // If we captured an error, but getDerivedStateFromError is not defined, - // unmount all the children. componentDidCatch will schedule an update to - // re-render a fallback. This is temporary until we migrate everyone to - // the new API. - // TODO: Warn in a future release. - nextChildren = null; + if (shouldUpdate) { + // In order to support react-lifecycles-compat polyfilled components, + // Unsafe lifecycles should not be invoked for components using the new APIs. + if ( + !hasNewLifecycles && + (typeof instance.UNSAFE_componentWillMount === "function" || + typeof instance.componentWillMount === "function") + ) { + if (typeof instance.componentWillMount === "function") { + instance.componentWillMount(); + } - { - stopProfilerTimerIfRunning(); - } - } else { - { - markComponentRenderStarted(workInProgress); + if (typeof instance.UNSAFE_componentWillMount === "function") { + instance.UNSAFE_componentWillMount(); + } } - { - setIsRendering(true); - nextChildren = instance.render(); - - if (workInProgress.mode & StrictLegacyMode) { - setIsStrictModeForDevtools(true); + if (typeof instance.componentDidMount === "function") { + var _fiberFlags = Update | LayoutStatic; - try { - instance.render(); - } finally { - setIsStrictModeForDevtools(false); - } + if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { + _fiberFlags |= MountLayoutDev; } - setIsRendering(false); + workInProgress.flags |= _fiberFlags; } + } else { + // If an update was already in progress, we should schedule an Update + // effect even though we're bailing out, so that cWU/cDU are called. + if (typeof instance.componentDidMount === "function") { + var _fiberFlags2 = Update | LayoutStatic; - { - markComponentRenderStopped(); - } - } // React DevTools reads this flag. + if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { + _fiberFlags2 |= MountLayoutDev; + } - workInProgress.flags |= PerformedWork; + workInProgress.flags |= _fiberFlags2; + } // If shouldComponentUpdate returned false, we should still update the + // memoized state to indicate that this work can be reused. - if (current !== null && didCaptureError) { - // If we're recovering from an error, reconcile without reusing any of - // the existing children. Conceptually, the normal children and the children - // that are shown on error are two different sets, so we shouldn't reuse - // normal children even if their identities match. - forceUnmountCurrentAndReconcile( - current, - workInProgress, - nextChildren, - renderLanes - ); - } else { - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - } // Memoize state using the values we just used to render. - // TODO: Restructure so we never read values from the instance. + workInProgress.memoizedProps = newProps; + workInProgress.memoizedState = newState; + } // Update the existing instance's state, props, and context pointers even + // if shouldComponentUpdate returns false. - workInProgress.memoizedState = instance.state; // The context might have changed so we need to recalculate it. + instance.props = newProps; + instance.state = newState; + instance.context = nextContext; + return shouldUpdate; +} // Invokes the update life-cycles and returns false if it shouldn't rerender. - if (hasContext) { - invalidateContextProvider(workInProgress, Component, true); - } +function updateClassInstance( + current, + workInProgress, + ctor, + newProps, + renderLanes +) { + var instance = workInProgress.stateNode; + cloneUpdateQueue(current, workInProgress); + var unresolvedOldProps = workInProgress.memoizedProps; + var oldProps = + workInProgress.type === workInProgress.elementType + ? unresolvedOldProps + : resolveDefaultProps(workInProgress.type, unresolvedOldProps); + instance.props = oldProps; + var unresolvedNewProps = workInProgress.pendingProps; + var oldContext = instance.context; + var contextType = ctor.contextType; + var nextContext = emptyContextObject; - return workInProgress.child; -} + if (typeof contextType === "object" && contextType !== null) { + nextContext = readContext(contextType); + } else { + var nextUnmaskedContext = getUnmaskedContext(workInProgress, ctor, true); + nextContext = getMaskedContext(workInProgress, nextUnmaskedContext); + } -function pushHostRootContext(workInProgress) { - var root = workInProgress.stateNode; + var getDerivedStateFromProps = ctor.getDerivedStateFromProps; + var hasNewLifecycles = + typeof getDerivedStateFromProps === "function" || + typeof instance.getSnapshotBeforeUpdate === "function"; // Note: During these life-cycles, instance.props/instance.state are what + // ever the previously attempted to render - not the "current". However, + // during componentDidUpdate we pass the "current" props. + // In order to support react-lifecycles-compat polyfilled components, + // Unsafe lifecycles should not be invoked for components using the new APIs. - if (root.pendingContext) { - pushTopLevelContextObject( - workInProgress, - root.pendingContext, - root.pendingContext !== root.context - ); - } else if (root.context) { - // Should always be set - pushTopLevelContextObject(workInProgress, root.context, false); + if ( + !hasNewLifecycles && + (typeof instance.UNSAFE_componentWillReceiveProps === "function" || + typeof instance.componentWillReceiveProps === "function") + ) { + if ( + unresolvedOldProps !== unresolvedNewProps || + oldContext !== nextContext + ) { + callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + nextContext + ); + } } - pushHostContainer(workInProgress, root.containerInfo); -} + resetHasForceUpdateBeforeProcessing(); + var oldState = workInProgress.memoizedState; + var newState = (instance.state = oldState); + processUpdateQueue(workInProgress, newProps, instance, renderLanes); + newState = workInProgress.memoizedState; + + if ( + unresolvedOldProps === unresolvedNewProps && + oldState === newState && + !hasContextChanged() && + !checkHasForceUpdateAfterProcessing() && + !enableLazyContextPropagation + ) { + // If an update was already in progress, we should schedule an Update + // effect even though we're bailing out, so that cWU/cDU are called. + if (typeof instance.componentDidUpdate === "function") { + if ( + unresolvedOldProps !== current.memoizedProps || + oldState !== current.memoizedState + ) { + workInProgress.flags |= Update; + } + } + + if (typeof instance.getSnapshotBeforeUpdate === "function") { + if ( + unresolvedOldProps !== current.memoizedProps || + oldState !== current.memoizedState + ) { + workInProgress.flags |= Snapshot; + } + } -function updateHostRoot(current, workInProgress, renderLanes) { - pushHostRootContext(workInProgress); + return false; + } - if (current === null) { - throw new Error("Should have a current fiber. This is a bug in React."); + if (typeof getDerivedStateFromProps === "function") { + applyDerivedStateFromProps( + workInProgress, + ctor, + getDerivedStateFromProps, + newProps + ); + newState = workInProgress.memoizedState; } - var nextProps = workInProgress.pendingProps; - var prevState = workInProgress.memoizedState; - var prevChildren = prevState.element; - cloneUpdateQueue(current, workInProgress); - processUpdateQueue(workInProgress, nextProps, null, renderLanes); - var nextState = workInProgress.memoizedState; - // being called "element". + var shouldUpdate = + checkHasForceUpdateAfterProcessing() || + checkShouldComponentUpdate( + workInProgress, + ctor, + oldProps, + newProps, + oldState, + newState, + nextContext + ) || // TODO: In some cases, we'll end up checking if context has changed twice, + // both before and after `shouldComponentUpdate` has been called. Not ideal, + // but I'm loath to refactor this function. This only happens for memoized + // components so it's not that common. + enableLazyContextPropagation; - var nextChildren = nextState.element; + if (shouldUpdate) { + // In order to support react-lifecycles-compat polyfilled components, + // Unsafe lifecycles should not be invoked for components using the new APIs. + if ( + !hasNewLifecycles && + (typeof instance.UNSAFE_componentWillUpdate === "function" || + typeof instance.componentWillUpdate === "function") + ) { + if (typeof instance.componentWillUpdate === "function") { + instance.componentWillUpdate(newProps, newState, nextContext); + } - { - if (nextChildren === prevChildren) { - return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); + if (typeof instance.UNSAFE_componentWillUpdate === "function") { + instance.UNSAFE_componentWillUpdate(newProps, newState, nextContext); + } } - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - } + if (typeof instance.componentDidUpdate === "function") { + workInProgress.flags |= Update; + } - return workInProgress.child; -} + if (typeof instance.getSnapshotBeforeUpdate === "function") { + workInProgress.flags |= Snapshot; + } + } else { + // If an update was already in progress, we should schedule an Update + // effect even though we're bailing out, so that cWU/cDU are called. + if (typeof instance.componentDidUpdate === "function") { + if ( + unresolvedOldProps !== current.memoizedProps || + oldState !== current.memoizedState + ) { + workInProgress.flags |= Update; + } + } -function updateHostComponent$1(current, workInProgress, renderLanes) { - pushHostContext(workInProgress); - var nextProps = workInProgress.pendingProps; - var prevProps = current !== null ? current.memoizedProps : null; - var nextChildren = nextProps.children; + if (typeof instance.getSnapshotBeforeUpdate === "function") { + if ( + unresolvedOldProps !== current.memoizedProps || + oldState !== current.memoizedState + ) { + workInProgress.flags |= Snapshot; + } + } // If shouldComponentUpdate returned false, we should still update the + // memoized props/state to indicate that this work can be reused. - if (prevProps !== null && shouldSetTextContent()) { - // If we're switching from a direct text child to a normal child, or to - // empty, we need to schedule the text content to be reset. - workInProgress.flags |= ContentReset; - } + workInProgress.memoizedProps = newProps; + workInProgress.memoizedState = newState; + } // Update the existing instance's state, props, and context pointers even + // if shouldComponentUpdate returns false. - markRef$1(current, workInProgress); - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; + instance.props = newProps; + instance.state = newState; + instance.context = nextContext; + return shouldUpdate; } -function updateHostText$1(current, workInProgress) { - // immediately after. - - return null; +function createCapturedValueAtFiber(value, source) { + // If the value is an error, call this function immediately after it is thrown + // so the stack is accurate. + return { + value: value, + source: source, + stack: getStackByFiberInDevAndProd(source), + digest: null + }; +} +function createCapturedValue(value, digest, stack) { + return { + value: value, + source: null, + stack: stack != null ? stack : null, + digest: digest != null ? digest : null + }; } -function mountLazyComponent( - _current, - workInProgress, - elementType, - renderLanes +if ( + typeof ReactNativePrivateInterface.ReactFiberErrorDialog.showErrorDialog !== + "function" ) { - resetSuspendedCurrentOnMountInLegacyMode(_current, workInProgress); - var props = workInProgress.pendingProps; - var lazyComponent = elementType; - var payload = lazyComponent._payload; - var init = lazyComponent._init; - var Component = init(payload); // Store the unwrapped component in the type. - - workInProgress.type = Component; - var resolvedTag = (workInProgress.tag = resolveLazyComponentTag(Component)); - var resolvedProps = resolveDefaultProps(Component, props); - var child; - - switch (resolvedTag) { - case FunctionComponent: { - { - validateFunctionComponentInDev(workInProgress, Component); - workInProgress.type = Component = - resolveFunctionForHotReloading(Component); - } + throw new Error( + "Expected ReactFiberErrorDialog.showErrorDialog to be a function." + ); +} - child = updateFunctionComponent( - null, - workInProgress, - Component, - resolvedProps, - renderLanes - ); - return child; - } +function showErrorDialog(boundary, errorInfo) { + var capturedError = { + componentStack: errorInfo.stack !== null ? errorInfo.stack : "", + error: errorInfo.value, + errorBoundary: + boundary !== null && boundary.tag === ClassComponent + ? boundary.stateNode + : null + }; + return ReactNativePrivateInterface.ReactFiberErrorDialog.showErrorDialog( + capturedError + ); +} - case ClassComponent: { - { - workInProgress.type = Component = - resolveClassForHotReloading(Component); - } +function logCapturedError(boundary, errorInfo) { + try { + var logError = showErrorDialog(boundary, errorInfo); // Allow injected showErrorDialog() to prevent default console.error logging. + // This enables renderers like ReactNative to better manage redbox behavior. - child = updateClassComponent( - null, - workInProgress, - Component, - resolvedProps, - renderLanes - ); - return child; + if (logError === false) { + return; } - case ForwardRef: { - { - workInProgress.type = Component = - resolveForwardRefForHotReloading(Component); - } + var error = errorInfo.value; - child = updateForwardRef( - null, - workInProgress, - Component, - resolvedProps, - renderLanes - ); - return child; - } + if (true) { + var source = errorInfo.source; + var stack = errorInfo.stack; + var componentStack = stack !== null ? stack : ""; // Browsers support silencing uncaught errors by calling + // `preventDefault()` in window `error` handler. + // We record this information as an expando on the error. - case MemoComponent: { - { - if (workInProgress.type !== workInProgress.elementType) { - var outerPropTypes = Component.propTypes; + if (error != null && error._suppressLogging) { + if (boundary.tag === ClassComponent) { + // The error is recoverable and was silenced. + // Ignore it and don't print the stack addendum. + // This is handy for testing error boundaries without noise. + return; + } // The error is fatal. Since the silencing might have + // been accidental, we'll surface it anyway. + // However, the browser would have silenced the original error + // so we'll print it first, and then print the stack addendum. - if (outerPropTypes) { - checkPropTypes( - outerPropTypes, - resolvedProps, // Resolved for outer only - "prop", - getComponentNameFromType(Component) - ); - } - } + console["error"](error); // Don't transform to our wrapper + // For a more detailed description of this block, see: + // https://github.com/facebook/react/pull/13384 } - child = updateMemoComponent( - null, - workInProgress, - Component, - resolveDefaultProps(Component.type, resolvedProps), // The inner type can have defaults too - renderLanes - ); - return child; - } - } + var componentName = source ? getComponentNameFromFiber(source) : null; + var componentNameMessage = componentName + ? "The above error occurred in the <" + componentName + "> component:" + : "The above error occurred in one of your React components:"; + var errorBoundaryMessage; + + if (boundary.tag === HostRoot) { + errorBoundaryMessage = + "Consider adding an error boundary to your tree to customize error handling behavior.\n" + + "Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries."; + } else { + var errorBoundaryName = + getComponentNameFromFiber(boundary) || "Anonymous"; + errorBoundaryMessage = + "React will try to recreate this component tree from scratch " + + ("using the error boundary you provided, " + errorBoundaryName + "."); + } - var hint = ""; + var combinedMessage = + componentNameMessage + + "\n" + + componentStack + + "\n\n" + + ("" + errorBoundaryMessage); // In development, we provide our own message with just the component stack. + // We don't include the original error message and JS stack because the browser + // has already printed it. Even if the application swallows the error, it is still + // displayed by the browser thanks to the DEV-only fake event trick in ReactErrorUtils. - { - if ( - Component !== null && - typeof Component === "object" && - Component.$$typeof === REACT_LAZY_TYPE - ) { - hint = " Did you wrap a component in React.lazy() more than once?"; + console["error"](combinedMessage); // Don't transform to our wrapper } - } // This message intentionally doesn't mention ForwardRef or MemoComponent - // because the fact that it's a separate type of work is an - // implementation detail. - - throw new Error( - "Element type is invalid. Received a promise that resolves to: " + - Component + - ". " + - ("Lazy element type must resolve to a class or function." + hint) - ); + } catch (e) { + // This method must not throw, or React internal state will get messed up. + // If console.error is overridden, or logCapturedError() shows a dialog that throws, + // we want to report this error outside of the normal stack as a last resort. + // https://github.com/facebook/react/issues/13188 + setTimeout(function () { + throw e; + }); + } } -function mountIncompleteClassComponent( - _current, - workInProgress, - Component, - nextProps, - renderLanes -) { - resetSuspendedCurrentOnMountInLegacyMode(_current, workInProgress); // Promote the fiber to a class and try rendering again. +function createRootErrorUpdate(fiber, errorInfo, lane) { + var update = createUpdate(lane); // Unmount the root by rendering null. - workInProgress.tag = ClassComponent; // The rest of this function is a fork of `updateClassComponent` - // Push context providers early to prevent context stack mismatches. - // During mounting we don't know the child context yet as the instance doesn't exist. - // We will invalidate the child context in finishClassComponent() right after rendering. + update.tag = CaptureUpdate; // Caution: React DevTools currently depends on this property + // being called "element". - var hasContext; + update.payload = { + element: null + }; + var error = errorInfo.value; - if (isContextProvider(Component)) { - hasContext = true; - pushContextProvider(workInProgress); - } else { - hasContext = false; - } + update.callback = function () { + onUncaughtError(error); + logCapturedError(fiber, errorInfo); + }; - prepareToReadContext(workInProgress, renderLanes); - constructClassInstance(workInProgress, Component, nextProps); - mountClassInstance(workInProgress, Component, nextProps, renderLanes); - return finishClassComponent( - null, - workInProgress, - Component, - true, - hasContext, - renderLanes - ); + return update; } -function mountIndeterminateComponent( - _current, - workInProgress, - Component, - renderLanes -) { - resetSuspendedCurrentOnMountInLegacyMode(_current, workInProgress); - var props = workInProgress.pendingProps; - var context; - - { - var unmaskedContext = getUnmaskedContext(workInProgress, Component, false); - context = getMaskedContext(workInProgress, unmaskedContext); - } - - prepareToReadContext(workInProgress, renderLanes); - var value; - - { - markComponentRenderStarted(workInProgress); - } +function createClassErrorUpdate(fiber, errorInfo, lane) { + var update = createUpdate(lane); + update.tag = CaptureUpdate; + var getDerivedStateFromError = fiber.type.getDerivedStateFromError; - { - if ( - Component.prototype && - typeof Component.prototype.render === "function" - ) { - var componentName = getComponentNameFromType(Component) || "Unknown"; + if (typeof getDerivedStateFromError === "function") { + var error$1 = errorInfo.value; - if (!didWarnAboutBadClass[componentName]) { - error( - "The <%s /> component appears to have a render method, but doesn't extend React.Component. " + - "This is likely to cause errors. Change %s to extend React.Component instead.", - componentName, - componentName - ); + update.payload = function () { + return getDerivedStateFromError(error$1); + }; - didWarnAboutBadClass[componentName] = true; + update.callback = function () { + { + markFailedErrorBoundaryForHotReloading(fiber); } - } - - if (workInProgress.mode & StrictLegacyMode) { - ReactStrictModeWarnings.recordLegacyContextWarning(workInProgress, null); - } - setIsRendering(true); - ReactCurrentOwner$2.current = workInProgress; - value = renderWithHooks( - null, - workInProgress, - Component, - props, - context, - renderLanes - ); - setIsRendering(false); + logCapturedError(fiber, errorInfo); + }; } - { - markComponentRenderStopped(); - } // React DevTools reads this flag. - - workInProgress.flags |= PerformedWork; + var inst = fiber.stateNode; - { - // Support for module components is deprecated and is removed behind a flag. - // Whether or not it would crash later, we want to show a good message in DEV first. - if ( - typeof value === "object" && - value !== null && - typeof value.render === "function" && - value.$$typeof === undefined - ) { - var _componentName = getComponentNameFromType(Component) || "Unknown"; + if (inst !== null && typeof inst.componentDidCatch === "function") { + // $FlowFixMe[missing-this-annot] + update.callback = function callback() { + { + markFailedErrorBoundaryForHotReloading(fiber); + } - if (!didWarnAboutModulePatternComponent[_componentName]) { - error( - "The <%s /> component appears to be a function component that returns a class instance. " + - "Change %s to a class that extends React.Component instead. " + - "If you can't use a class try assigning the prototype on the function as a workaround. " + - "`%s.prototype = React.Component.prototype`. Don't use an arrow function since it " + - "cannot be called with `new` by React.", - _componentName, - _componentName, - _componentName - ); + logCapturedError(fiber, errorInfo); - didWarnAboutModulePatternComponent[_componentName] = true; + if (typeof getDerivedStateFromError !== "function") { + // To preserve the preexisting retry behavior of error boundaries, + // we keep track of which ones already failed during this batch. + // This gets reset before we yield back to the browser. + // TODO: Warn in strict mode if getDerivedStateFromError is + // not defined. + markLegacyErrorBoundaryAsFailed(this); } - } - } - - if ( - // Run these checks in production only if the flag is off. - // Eventually we'll delete this branch altogether. - typeof value === "object" && - value !== null && - typeof value.render === "function" && - value.$$typeof === undefined - ) { - { - var _componentName2 = getComponentNameFromType(Component) || "Unknown"; - if (!didWarnAboutModulePatternComponent[_componentName2]) { - error( - "The <%s /> component appears to be a function component that returns a class instance. " + - "Change %s to a class that extends React.Component instead. " + - "If you can't use a class try assigning the prototype on the function as a workaround. " + - "`%s.prototype = React.Component.prototype`. Don't use an arrow function since it " + - "cannot be called with `new` by React.", - _componentName2, - _componentName2, - _componentName2 - ); + var error$1 = errorInfo.value; + var stack = errorInfo.stack; + this.componentDidCatch(error$1, { + componentStack: stack !== null ? stack : "" + }); - didWarnAboutModulePatternComponent[_componentName2] = true; + { + if (typeof getDerivedStateFromError !== "function") { + // If componentDidCatch is the only error boundary method defined, + // then it needs to call setState to recover from errors. + // If no state update is scheduled then the boundary will swallow the error. + if (!includesSomeLane(fiber.lanes, SyncLane)) { + error( + "%s: Error boundaries should implement getDerivedStateFromError(). " + + "In that method, return a state update to display an error message or fallback UI.", + getComponentNameFromFiber(fiber) || "Unknown" + ); + } + } } - } // Proceed under the assumption that this is a class instance + }; + } - workInProgress.tag = ClassComponent; // Throw out any hooks that were used. + return update; +} - workInProgress.memoizedState = null; - workInProgress.updateQueue = null; // Push context providers early to prevent context stack mismatches. - // During mounting we don't know the child context yet as the instance doesn't exist. - // We will invalidate the child context in finishClassComponent() right after rendering. +function resetSuspendedComponent(sourceFiber, rootRenderLanes) { + // A legacy mode Suspense quirk, only relevant to hook components. - var hasContext = false; + var tag = sourceFiber.tag; - if (isContextProvider(Component)) { - hasContext = true; - pushContextProvider(workInProgress); + if ( + (sourceFiber.mode & ConcurrentMode) === NoMode && + (tag === FunctionComponent || + tag === ForwardRef || + tag === SimpleMemoComponent) + ) { + var currentSource = sourceFiber.alternate; + + if (currentSource) { + sourceFiber.updateQueue = currentSource.updateQueue; + sourceFiber.memoizedState = currentSource.memoizedState; + sourceFiber.lanes = currentSource.lanes; } else { - hasContext = false; + sourceFiber.updateQueue = null; + sourceFiber.memoizedState = null; } + } +} - workInProgress.memoizedState = - value.state !== null && value.state !== undefined ? value.state : null; - initializeUpdateQueue(workInProgress); - adoptClassInstance(workInProgress, value); - mountClassInstance(workInProgress, Component, props, renderLanes); - return finishClassComponent( - null, - workInProgress, - Component, - true, - hasContext, - renderLanes - ); - } else { - // Proceed under the assumption that this is a function component - workInProgress.tag = FunctionComponent; +function markSuspenseBoundaryShouldCapture( + suspenseBoundary, + returnFiber, + sourceFiber, + root, + rootRenderLanes +) { + // This marks a Suspense boundary so that when we're unwinding the stack, + // it captures the suspended "exception" and does a second (fallback) pass. + if ((suspenseBoundary.mode & ConcurrentMode) === NoMode) { + // Legacy Mode Suspense + // + // If the boundary is in legacy mode, we should *not* + // suspend the commit. Pretend as if the suspended component rendered + // null and keep rendering. When the Suspense boundary completes, + // we'll do a second pass to render the fallback. + if (suspenseBoundary === returnFiber) { + // Special case where we suspended while reconciling the children of + // a Suspense boundary's inner Offscreen wrapper fiber. This happens + // when a React.lazy component is a direct child of a + // Suspense boundary. + // + // Suspense boundaries are implemented as multiple fibers, but they + // are a single conceptual unit. The legacy mode behavior where we + // pretend the suspended fiber committed as `null` won't work, + // because in this case the "suspended" fiber is the inner + // Offscreen wrapper. + // + // Because the contents of the boundary haven't started rendering + // yet (i.e. nothing in the tree has partially rendered) we can + // switch to the regular, concurrent mode behavior: mark the + // boundary with ShouldCapture and enter the unwind phase. + suspenseBoundary.flags |= ShouldCapture; + } else { + suspenseBoundary.flags |= DidCapture; + sourceFiber.flags |= ForceUpdateForLegacySuspense; // We're going to commit this fiber even though it didn't complete. + // But we shouldn't call any lifecycle methods or callbacks. Remove + // all lifecycle effect tags. - reconcileChildren(null, workInProgress, value, renderLanes); + sourceFiber.flags &= ~(LifecycleEffectMask | Incomplete); - { - validateFunctionComponentInDev(workInProgress, Component); - } + if (sourceFiber.tag === ClassComponent) { + var currentSourceFiber = sourceFiber.alternate; - return workInProgress.child; - } -} + if (currentSourceFiber === null) { + // This is a new mount. Change the tag so it's not mistaken for a + // completed class component. For example, we should not call + // componentWillUnmount if it is deleted. + sourceFiber.tag = IncompleteClassComponent; + } else { + // When we try rendering again, we should not reuse the current fiber, + // since it's known to be in an inconsistent state. Use a force update to + // prevent a bail out. + var update = createUpdate(SyncLane); + update.tag = ForceUpdate; + enqueueUpdate(sourceFiber, update, SyncLane); + } + } // The source fiber did not complete. Mark it with Sync priority to + // indicate that it still has pending work. -function validateFunctionComponentInDev(workInProgress, Component) { - { - if (Component) { - if (Component.childContextTypes) { - error( - "%s(...): childContextTypes cannot be defined on a function component.", - Component.displayName || Component.name || "Component" - ); - } + sourceFiber.lanes = mergeLanes(sourceFiber.lanes, SyncLane); } - if (workInProgress.ref !== null) { - var info = ""; - var ownerName = getCurrentFiberOwnerNameInDevOrNull(); - - if (ownerName) { - info += "\n\nCheck the render method of `" + ownerName + "`."; - } + return suspenseBoundary; + } // Confirmed that the boundary is in a concurrent mode tree. Continue + // with the normal suspend path. + // + // After this we'll use a set of heuristics to determine whether this + // render pass will run to completion or restart or "suspend" the commit. + // The actual logic for this is spread out in different places. + // + // This first principle is that if we're going to suspend when we complete + // a root, then we should also restart if we get an update or ping that + // might unsuspend it, and vice versa. The only reason to suspend is + // because you think you might want to restart before committing. However, + // it doesn't make sense to restart only while in the period we're suspended. + // + // Restarting too aggressively is also not good because it starves out any + // intermediate loading state. So we use heuristics to determine when. + // Suspense Heuristics + // + // If nothing threw a Promise or all the same fallbacks are already showing, + // then don't suspend/restart. + // + // If this is an initial render of a new tree of Suspense boundaries and + // those trigger a fallback, then don't suspend/restart. We want to ensure + // that we can show the initial loading state as quickly as possible. + // + // If we hit a "Delayed" case, such as when we'd switch from content back into + // a fallback, then we should always suspend/restart. Transitions apply + // to this case. If none is defined, JND is used instead. + // + // If we're already showing a fallback and it gets "retried", allowing us to show + // another level, but there's still an inner boundary that would show a fallback, + // then we suspend/restart for 500ms since the last time we showed a fallback + // anywhere in the tree. This effectively throttles progressive loading into a + // consistent train of commits. This also gives us an opportunity to restart to + // get to the completed state slightly earlier. + // + // If there's ambiguity due to batching it's resolved in preference of: + // 1) "delayed", 2) "initial render", 3) "retry". + // + // We want to ensure that a "busy" state doesn't get force committed. We want to + // ensure that new initial loading states can commit as soon as possible. - var warningKey = ownerName || ""; - var debugSource = workInProgress._debugSource; + suspenseBoundary.flags |= ShouldCapture; // TODO: I think we can remove this, since we now use `DidCapture` in + // the begin phase to prevent an early bailout. - if (debugSource) { - warningKey = debugSource.fileName + ":" + debugSource.lineNumber; - } + suspenseBoundary.lanes = rootRenderLanes; + return suspenseBoundary; +} - if (!didWarnAboutFunctionRefs[warningKey]) { - didWarnAboutFunctionRefs[warningKey] = true; +function throwException( + root, + returnFiber, + sourceFiber, + value, + rootRenderLanes +) { + // The source fiber did not complete. + sourceFiber.flags |= Incomplete; - error( - "Function components cannot be given refs. " + - "Attempts to access this ref will fail. " + - "Did you mean to use React.forwardRef()?%s", - info - ); - } + { + if (isDevToolsPresent) { + // If we have pending work still, restore the original updaters + restorePendingUpdaters(root, rootRenderLanes); } + } - if (Component.defaultProps !== undefined) { - var componentName = getComponentNameFromType(Component) || "Unknown"; - - if (!didWarnAboutDefaultPropsOnFunctionComponent[componentName]) { - error( - "%s: Support for defaultProps will be removed from function components " + - "in a future major release. Use JavaScript default parameters instead.", - componentName - ); + if ( + value !== null && + typeof value === "object" && + typeof value.then === "function" + ) { + // This is a wakeable. The component suspended. + var wakeable = value; + resetSuspendedComponent(sourceFiber); - didWarnAboutDefaultPropsOnFunctionComponent[componentName] = true; - } - } + var suspenseBoundary = getSuspenseHandler(); - if (typeof Component.getDerivedStateFromProps === "function") { - var _componentName3 = getComponentNameFromType(Component) || "Unknown"; + if (suspenseBoundary !== null) { + switch (suspenseBoundary.tag) { + case SuspenseComponent: { + // If this suspense boundary is not already showing a fallback, mark + // the in-progress render as suspended. We try to perform this logic + // as soon as soon as possible during the render phase, so the work + // loop can know things like whether it's OK to switch to other tasks, + // or whether it can wait for data to resolve before continuing. + // TODO: Most of these checks are already performed when entering a + // Suspense boundary. We should track the information on the stack so + // we don't have to recompute it on demand. This would also allow us + // to unify with `use` which needs to perform this logic even sooner, + // before `throwException` is called. + if (sourceFiber.mode & ConcurrentMode) { + if (getShellBoundary() === null) { + // Suspended in the "shell" of the app. This is an undesirable + // loading state. We should avoid committing this tree. + renderDidSuspendDelayIfPossible(); + } else { + // If we suspended deeper than the shell, we don't need to delay + // the commmit. However, we still call renderDidSuspend if this is + // a new boundary, to tell the work loop that a new fallback has + // appeared during this render. + // TODO: Theoretically we should be able to delete this branch. + // It's currently used for two things: 1) to throttle the + // appearance of successive loading states, and 2) in + // SuspenseList, to determine whether the children include any + // pending fallbacks. For 1, we should apply throttling to all + // retries, not just ones that render an additional fallback. For + // 2, we should check subtreeFlags instead. Then we can delete + // this branch. + var current = suspenseBoundary.alternate; - if (!didWarnAboutGetDerivedStateOnFunctionComponent[_componentName3]) { - error( - "%s: Function components do not support getDerivedStateFromProps.", - _componentName3 - ); + if (current === null) { + renderDidSuspend(); + } + } + } - didWarnAboutGetDerivedStateOnFunctionComponent[_componentName3] = true; - } - } + suspenseBoundary.flags &= ~ForceClientRender; + markSuspenseBoundaryShouldCapture( + suspenseBoundary, + returnFiber, + sourceFiber, + root, + rootRenderLanes + ); // Retry listener + // + // If the fallback does commit, we need to attach a different type of + // listener. This one schedules an update on the Suspense boundary to + // turn the fallback state off. + // + // Stash the wakeable on the boundary fiber so we can access it in the + // commit phase. + // + // When the wakeable resolves, we'll attempt to render the boundary + // again ("retry"). + // Check if this is a Suspensey resource. We do not attach retry + // listeners to these, because we don't actually need them for + // rendering. Only for committing. Instead, if a fallback commits + // and the only thing that suspended was a Suspensey resource, we + // retry immediately. + // TODO: Refactor throwException so that we don't have to do this type + // check. The caller already knows what the cause was. - if ( - typeof Component.contextType === "object" && - Component.contextType !== null - ) { - var _componentName4 = getComponentNameFromType(Component) || "Unknown"; + var isSuspenseyResource = wakeable === noopSuspenseyCommitThenable; - if (!didWarnAboutContextTypeOnFunctionComponent[_componentName4]) { - error( - "%s: Function components do not support contextType.", - _componentName4 - ); + if (isSuspenseyResource) { + suspenseBoundary.flags |= ScheduleRetry; + } else { + var retryQueue = suspenseBoundary.updateQueue; - didWarnAboutContextTypeOnFunctionComponent[_componentName4] = true; - } - } - } -} + if (retryQueue === null) { + suspenseBoundary.updateQueue = new Set([wakeable]); + } else { + retryQueue.add(wakeable); + } + } -var SUSPENDED_MARKER = { - dehydrated: null, - treeContext: null, - retryLane: NoLane -}; + break; + } -function mountSuspenseOffscreenState(renderLanes) { - return { - baseLanes: renderLanes, - cachePool: getSuspendedCache() - }; -} + case OffscreenComponent: { + if (suspenseBoundary.mode & ConcurrentMode) { + suspenseBoundary.flags |= ShouldCapture; -function updateSuspenseOffscreenState(prevOffscreenState, renderLanes) { - var cachePool = null; + var _isSuspenseyResource = wakeable === noopSuspenseyCommitThenable; - return { - baseLanes: mergeLanes(prevOffscreenState.baseLanes, renderLanes), - cachePool: cachePool - }; -} // TODO: Probably should inline this back + if (_isSuspenseyResource) { + suspenseBoundary.flags |= ScheduleRetry; + } else { + var offscreenQueue = suspenseBoundary.updateQueue; -function shouldRemainOnFallback(current, workInProgress, renderLanes) { - // If we're already showing a fallback, there are cases where we need to - // remain on that fallback regardless of whether the content has resolved. - // For example, SuspenseList coordinates when nested content appears. - // TODO: For compatibility with offscreen prerendering, this should also check - // whether the current fiber (if it exists) was visible in the previous tree. - if (current !== null) { - var suspenseState = current.memoizedState; + if (offscreenQueue === null) { + var newOffscreenQueue = { + transitions: null, + markerInstances: null, + retryQueue: new Set([wakeable]) + }; + suspenseBoundary.updateQueue = newOffscreenQueue; + } else { + var _retryQueue = offscreenQueue.retryQueue; - if (suspenseState === null) { - // Currently showing content. Don't hide it, even if ForceSuspenseFallback - // is true. More precise name might be "ForceRemainSuspenseFallback". - // Note: This is a factoring smell. Can't remain on a fallback if there's - // no fallback to remain on. - return false; - } - } // Not currently showing content. Consult the Suspense context. + if (_retryQueue === null) { + offscreenQueue.retryQueue = new Set([wakeable]); + } else { + _retryQueue.add(wakeable); + } + } + } - var suspenseContext = suspenseStackCursor.current; - return hasSuspenseListContext(suspenseContext, ForceSuspenseFallback); -} + break; + } + } + // eslint-disable-next-line no-fallthrough -function getRemainingWorkInPrimaryTree(current, renderLanes) { - // TODO: Should not remove render lanes that were pinged during this render - return removeLanes(current.childLanes, renderLanes); -} + default: { + throw new Error( + "Unexpected Suspense handler tag (" + + suspenseBoundary.tag + + "). This " + + "is a bug in React." + ); + } + } // We only attach ping listeners in concurrent mode. Legacy Suspense always + // commits fallbacks synchronously, so there are no pings. -function updateSuspenseComponent(current, workInProgress, renderLanes) { - var nextProps = workInProgress.pendingProps; // This is used by DevTools to force a boundary to suspend. + if (suspenseBoundary.mode & ConcurrentMode) { + attachPingListener(root, wakeable, rootRenderLanes); + } - { - if (shouldSuspend(workInProgress)) { - workInProgress.flags |= DidCapture; + return; + } else { + // No boundary was found. Unless this is a sync update, this is OK. + // We can suspend and wait for more data to arrive. + if (root.tag === ConcurrentRoot) { + // In a concurrent root, suspending without a Suspense boundary is + // allowed. It will suspend indefinitely without committing. + // + // TODO: Should we have different behavior for discrete updates? What + // about flushSync? Maybe it should put the tree into an inert state, + // and potentially log a warning. Revisit this for a future release. + attachPingListener(root, wakeable, rootRenderLanes); + renderDidSuspendDelayIfPossible(); + return; + } else { + // In a legacy root, suspending without a boundary is always an error. + var uncaughtSuspenseError = new Error( + "A component suspended while responding to synchronous input. This " + + "will cause the UI to be replaced with a loading indicator. To " + + "fix, updates that suspend should be wrapped " + + "with startTransition." + ); + value = uncaughtSuspenseError; + } } } - var showFallback = false; - var didSuspend = (workInProgress.flags & DidCapture) !== NoFlags$1; + value = createCapturedValueAtFiber(value, sourceFiber); + renderDidError(value); // We didn't find a boundary that could handle this type of exception. Start + // over and traverse parent path again, this time treating the exception + // as an error. - if (didSuspend || shouldRemainOnFallback(current)) { - // Something in this boundary's subtree already suspended. Switch to - // rendering the fallback children. - showFallback = true; - workInProgress.flags &= ~DidCapture; - } // OK, the next part is confusing. We're about to reconcile the Suspense - // boundary's children. This involves some custom reconciliation logic. Two - // main reasons this is so complicated. - // - // First, Legacy Mode has different semantics for backwards compatibility. The - // primary tree will commit in an inconsistent state, so when we do the - // second pass to render the fallback, we do some exceedingly, uh, clever - // hacks to make that not totally break. Like transferring effects and - // deletions from hidden tree. In Concurrent Mode, it's much simpler, - // because we bailout on the primary tree completely and leave it in its old - // state, no effects. Same as what we do for Offscreen (except that - // Offscreen doesn't have the first render pass). - // - // Second is hydration. During hydration, the Suspense fiber has a slightly - // different layout, where the child points to a dehydrated fragment, which - // contains the DOM rendered by the server. - // - // Third, even if you set all that aside, Suspense is like error boundaries in - // that we first we try to render one tree, and if that fails, we render again - // and switch to a different tree. Like a try/catch block. So we have to track - // which branch we're currently rendering. Ideally we would model this using - // a stack. + var workInProgress = returnFiber; - if (current === null) { - var nextPrimaryChildren = nextProps.children; - var nextFallbackChildren = nextProps.fallback; + do { + switch (workInProgress.tag) { + case HostRoot: { + var _errorInfo = value; + workInProgress.flags |= ShouldCapture; + var lane = pickArbitraryLane(rootRenderLanes); + workInProgress.lanes = mergeLanes(workInProgress.lanes, lane); + var update = createRootErrorUpdate(workInProgress, _errorInfo, lane); + enqueueCapturedUpdate(workInProgress, update); + return; + } - if (showFallback) { - pushFallbackTreeSuspenseHandler(workInProgress); - var fallbackFragment = mountSuspenseFallbackChildren( - workInProgress, - nextPrimaryChildren, - nextFallbackChildren, - renderLanes - ); - var primaryChildFragment = workInProgress.child; - primaryChildFragment.memoizedState = - mountSuspenseOffscreenState(renderLanes); - workInProgress.memoizedState = SUSPENDED_MARKER; + case ClassComponent: + // Capture and retry + var errorInfo = value; + var ctor = workInProgress.type; + var instance = workInProgress.stateNode; - return fallbackFragment; - } else if (typeof nextProps.unstable_expectedLoadTime === "number") { - // This is a CPU-bound tree. Skip this tree and show a placeholder to - // unblock the surrounding content. Then immediately retry after the - // initial commit. - pushFallbackTreeSuspenseHandler(workInProgress); + if ( + (workInProgress.flags & DidCapture) === NoFlags$1 && + (typeof ctor.getDerivedStateFromError === "function" || + (instance !== null && + typeof instance.componentDidCatch === "function" && + !isAlreadyFailedLegacyErrorBoundary(instance))) + ) { + workInProgress.flags |= ShouldCapture; - var _fallbackFragment = mountSuspenseFallbackChildren( - workInProgress, - nextPrimaryChildren, - nextFallbackChildren, - renderLanes - ); + var _lane = pickArbitraryLane(rootRenderLanes); - var _primaryChildFragment = workInProgress.child; - _primaryChildFragment.memoizedState = - mountSuspenseOffscreenState(renderLanes); - workInProgress.memoizedState = SUSPENDED_MARKER; // TODO: Transition Tracing is not yet implemented for CPU Suspense. - // Since nothing actually suspended, there will nothing to ping this to - // get it started back up to attempt the next item. While in terms of - // priority this work has the same priority as this current render, it's - // not part of the same transition once the transition has committed. If - // it's sync, we still want to yield so that it can be painted. - // Conceptually, this is really the same as pinging. We can use any - // RetryLane even if it's the one currently rendering since we're leaving - // it behind on this node. + workInProgress.lanes = mergeLanes(workInProgress.lanes, _lane); // Schedule the error boundary to re-render using updated state - workInProgress.lanes = SomeRetryLane; - return _fallbackFragment; - } else { - pushPrimaryTreeSuspenseHandler(workInProgress); - return mountSuspensePrimaryChildren(workInProgress, nextPrimaryChildren); - } - } else { - // This is an update. - // Special path for hydration - var prevState = current.memoizedState; + var _update = createClassErrorUpdate( + workInProgress, + errorInfo, + _lane + ); - if (prevState !== null) { - var _dehydrated = prevState.dehydrated; + enqueueCapturedUpdate(workInProgress, _update); + return; + } - if (_dehydrated !== null) { - return updateDehydratedSuspenseComponent( - current, - workInProgress, - didSuspend, - nextProps, - _dehydrated, - prevState, - renderLanes - ); - } - } + break; + } // $FlowFixMe[incompatible-type] we bail out when we get a null - if (showFallback) { - pushFallbackTreeSuspenseHandler(workInProgress); - var _nextFallbackChildren = nextProps.fallback; - var _nextPrimaryChildren = nextProps.children; - var fallbackChildFragment = updateSuspenseFallbackChildren( - current, - workInProgress, - _nextPrimaryChildren, - _nextFallbackChildren, - renderLanes - ); - var _primaryChildFragment2 = workInProgress.child; - var prevOffscreenState = current.child.memoizedState; - _primaryChildFragment2.memoizedState = - prevOffscreenState === null - ? mountSuspenseOffscreenState(renderLanes) - : updateSuspenseOffscreenState(prevOffscreenState, renderLanes); + workInProgress = workInProgress.return; + } while (workInProgress !== null); +} - _primaryChildFragment2.childLanes = getRemainingWorkInPrimaryTree( - current, - renderLanes - ); - workInProgress.memoizedState = SUSPENDED_MARKER; - return fallbackChildFragment; - } else { - pushPrimaryTreeSuspenseHandler(workInProgress); - var _nextPrimaryChildren2 = nextProps.children; +var ReactCurrentOwner$2 = ReactSharedInternals.ReactCurrentOwner; // A special exception that's used to unwind the stack when an update flows +// into a dehydrated boundary. - var _primaryChildFragment3 = updateSuspensePrimaryChildren( - current, - workInProgress, - _nextPrimaryChildren2, - renderLanes - ); +var SelectiveHydrationException = new Error( + "This is not a real error. It's an implementation detail of React's " + + "selective hydration feature. If this leaks into userspace, it's a bug in " + + "React. Please file an issue." +); +var didReceiveUpdate = false; +var didWarnAboutBadClass; +var didWarnAboutModulePatternComponent; +var didWarnAboutContextTypeOnFunctionComponent; +var didWarnAboutGetDerivedStateOnFunctionComponent; +var didWarnAboutFunctionRefs; +var didWarnAboutReassigningProps; +var didWarnAboutRevealOrder; +var didWarnAboutTailOptions; +var didWarnAboutDefaultPropsOnFunctionComponent; - workInProgress.memoizedState = null; - return _primaryChildFragment3; - } +{ + didWarnAboutBadClass = {}; + didWarnAboutModulePatternComponent = {}; + didWarnAboutContextTypeOnFunctionComponent = {}; + didWarnAboutGetDerivedStateOnFunctionComponent = {}; + didWarnAboutFunctionRefs = {}; + didWarnAboutReassigningProps = false; + didWarnAboutRevealOrder = {}; + didWarnAboutTailOptions = {}; + didWarnAboutDefaultPropsOnFunctionComponent = {}; +} + +function reconcileChildren(current, workInProgress, nextChildren, renderLanes) { + if (current === null) { + // If this is a fresh new component that hasn't been rendered yet, we + // won't update its child set by applying minimal side-effects. Instead, + // we will add them all to the child before it gets rendered. That means + // we can optimize this reconciliation pass by not tracking side-effects. + workInProgress.child = mountChildFibers( + workInProgress, + null, + nextChildren, + renderLanes + ); + } else { + // If the current child is the same as the work in progress, it means that + // we haven't yet started any work on these children. Therefore, we use + // the clone algorithm to create a copy of all the current children. + // If we had any progressed work already, that is invalid at this point so + // let's throw it out. + workInProgress.child = reconcileChildFibers( + workInProgress, + current.child, + nextChildren, + renderLanes + ); } } -function mountSuspensePrimaryChildren( +function forceUnmountCurrentAndReconcile( + current, workInProgress, - primaryChildren, + nextChildren, renderLanes ) { - var mode = workInProgress.mode; - var primaryChildProps = { - mode: "visible", - children: primaryChildren - }; - var primaryChildFragment = mountWorkInProgressOffscreenFiber( - primaryChildProps, - mode + // This function is fork of reconcileChildren. It's used in cases where we + // want to reconcile without matching against the existing set. This has the + // effect of all current children being unmounted; even if the type and key + // are the same, the old child is unmounted and a new child is created. + // + // To do this, we're going to go through the reconcile algorithm twice. In + // the first pass, we schedule a deletion for all the current children by + // passing null. + workInProgress.child = reconcileChildFibers( + workInProgress, + current.child, + null, + renderLanes + ); // In the second pass, we mount the new children. The trick here is that we + // pass null in place of where we usually pass the current child set. This has + // the effect of remounting all children regardless of whether their + // identities match. + + workInProgress.child = reconcileChildFibers( + workInProgress, + null, + nextChildren, + renderLanes ); - primaryChildFragment.return = workInProgress; - workInProgress.child = primaryChildFragment; - return primaryChildFragment; } -function mountSuspenseFallbackChildren( +function updateForwardRef( + current, workInProgress, - primaryChildren, - fallbackChildren, + Component, + nextProps, renderLanes ) { - var mode = workInProgress.mode; - var progressedPrimaryFragment = workInProgress.child; - var primaryChildProps = { - mode: "hidden", - children: primaryChildren - }; - var primaryChildFragment; - var fallbackChildFragment; - - if ( - (mode & ConcurrentMode) === NoMode && - progressedPrimaryFragment !== null - ) { - // In legacy mode, we commit the primary tree as if it successfully - // completed, even though it's in an inconsistent state. - primaryChildFragment = progressedPrimaryFragment; - primaryChildFragment.childLanes = NoLanes; - primaryChildFragment.pendingProps = primaryChildProps; + // TODO: current can be non-null here even if the component + // hasn't yet mounted. This happens after the first render suspends. + // We'll need to figure out if this is fine or can cause issues. + { + if (workInProgress.type !== workInProgress.elementType) { + // Lazy component props can't be validated in createElement + // because they're only guaranteed to be resolved here. + var innerPropTypes = Component.propTypes; - if (workInProgress.mode & ProfileMode) { - // Reset the durations from the first pass so they aren't included in the - // final amounts. This seems counterintuitive, since we're intentionally - // not measuring part of the render phase, but this makes it match what we - // do in Concurrent Mode. - primaryChildFragment.actualDuration = 0; - primaryChildFragment.actualStartTime = -1; - primaryChildFragment.selfBaseDuration = 0; - primaryChildFragment.treeBaseDuration = 0; + if (innerPropTypes) { + checkPropTypes( + innerPropTypes, + nextProps, // Resolved props + "prop", + getComponentNameFromType(Component) + ); + } } + } - fallbackChildFragment = createFiberFromFragment( - fallbackChildren, - mode, - renderLanes, - null - ); - } else { - primaryChildFragment = mountWorkInProgressOffscreenFiber( - primaryChildProps, - mode - ); - fallbackChildFragment = createFiberFromFragment( - fallbackChildren, - mode, - renderLanes, - null + var render = Component.render; + var ref = workInProgress.ref; // The rest is a fork of updateFunctionComponent + + var nextChildren; + prepareToReadContext(workInProgress, renderLanes); + + { + markComponentRenderStarted(workInProgress); + } + + { + ReactCurrentOwner$2.current = workInProgress; + setIsRendering(true); + nextChildren = renderWithHooks( + current, + workInProgress, + render, + nextProps, + ref, + renderLanes ); + setIsRendering(false); } - primaryChildFragment.return = workInProgress; - fallbackChildFragment.return = workInProgress; - primaryChildFragment.sibling = fallbackChildFragment; - workInProgress.child = primaryChildFragment; - return fallbackChildFragment; -} + { + markComponentRenderStopped(); + } -function mountWorkInProgressOffscreenFiber(offscreenProps, mode, renderLanes) { - // The props argument to `createFiberFromOffscreen` is `any` typed, so we use - // this wrapper function to constrain it. - return createFiberFromOffscreen(offscreenProps, mode, NoLanes, null); -} + if (current !== null && !didReceiveUpdate) { + bailoutHooks(current, workInProgress, renderLanes); + return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); + } -function updateWorkInProgressOffscreenFiber(current, offscreenProps) { - // The props argument to `createWorkInProgress` is `any` typed, so we use this - // wrapper function to constrain it. - return createWorkInProgress(current, offscreenProps); + workInProgress.flags |= PerformedWork; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; } -function updateSuspensePrimaryChildren( +function updateMemoComponent( current, workInProgress, - primaryChildren, + Component, + nextProps, renderLanes ) { - var currentPrimaryChildFragment = current.child; - var currentFallbackChildFragment = currentPrimaryChildFragment.sibling; - var primaryChildFragment = updateWorkInProgressOffscreenFiber( - currentPrimaryChildFragment, + if (current === null) { + var type = Component.type; + + if ( + isSimpleFunctionComponent(type) && + Component.compare === null && // SimpleMemoComponent codepath doesn't resolve outer props either. + Component.defaultProps === undefined + ) { + var resolvedType = type; + + { + resolvedType = resolveFunctionForHotReloading(type); + } // If this is a plain function component without default props, + // and with only the default shallow comparison, we upgrade it + // to a SimpleMemoComponent to allow fast path updates. + + workInProgress.tag = SimpleMemoComponent; + workInProgress.type = resolvedType; + + { + validateFunctionComponentInDev(workInProgress, type); + } + + return updateSimpleMemoComponent( + current, + workInProgress, + resolvedType, + nextProps, + renderLanes + ); + } + { - mode: "visible", - children: primaryChildren + var innerPropTypes = type.propTypes; + + if (innerPropTypes) { + // Inner memo component props aren't currently validated in createElement. + // We could move it there, but we'd still need this for lazy code path. + checkPropTypes( + innerPropTypes, + nextProps, // Resolved props + "prop", + getComponentNameFromType(type) + ); + } + + if (Component.defaultProps !== undefined) { + var componentName = getComponentNameFromType(type) || "Unknown"; + + if (!didWarnAboutDefaultPropsOnFunctionComponent[componentName]) { + error( + "%s: Support for defaultProps will be removed from memo components " + + "in a future major release. Use JavaScript default parameters instead.", + componentName + ); + + didWarnAboutDefaultPropsOnFunctionComponent[componentName] = true; + } + } } - ); - if ((workInProgress.mode & ConcurrentMode) === NoMode) { - primaryChildFragment.lanes = renderLanes; + var child = createFiberFromTypeAndProps( + Component.type, + null, + nextProps, + workInProgress, + workInProgress.mode, + renderLanes + ); + child.ref = workInProgress.ref; + child.return = workInProgress; + workInProgress.child = child; + return child; } - primaryChildFragment.return = workInProgress; - primaryChildFragment.sibling = null; - - if (currentFallbackChildFragment !== null) { - // Delete the fallback child fragment - var deletions = workInProgress.deletions; + { + var _type = Component.type; + var _innerPropTypes = _type.propTypes; - if (deletions === null) { - workInProgress.deletions = [currentFallbackChildFragment]; - workInProgress.flags |= ChildDeletion; - } else { - deletions.push(currentFallbackChildFragment); + if (_innerPropTypes) { + // Inner memo component props aren't currently validated in createElement. + // We could move it there, but we'd still need this for lazy code path. + checkPropTypes( + _innerPropTypes, + nextProps, // Resolved props + "prop", + getComponentNameFromType(_type) + ); } } - workInProgress.child = primaryChildFragment; - return primaryChildFragment; + var currentChild = current.child; // This is always exactly one child + + var hasScheduledUpdateOrContext = checkScheduledUpdateOrContext( + current, + renderLanes + ); + + if (!hasScheduledUpdateOrContext) { + // This will be the props with resolved defaultProps, + // unlike current.memoizedProps which will be the unresolved ones. + var prevProps = currentChild.memoizedProps; // Default to shallow comparison + + var compare = Component.compare; + compare = compare !== null ? compare : shallowEqual; + + if (compare(prevProps, nextProps) && current.ref === workInProgress.ref) { + return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); + } + } // React DevTools reads this flag. + + workInProgress.flags |= PerformedWork; + var newChild = createWorkInProgress(currentChild, nextProps); + newChild.ref = workInProgress.ref; + newChild.return = workInProgress; + workInProgress.child = newChild; + return newChild; } -function updateSuspenseFallbackChildren( +function updateSimpleMemoComponent( current, workInProgress, - primaryChildren, - fallbackChildren, + Component, + nextProps, renderLanes ) { - var mode = workInProgress.mode; - var currentPrimaryChildFragment = current.child; - var currentFallbackChildFragment = currentPrimaryChildFragment.sibling; - var primaryChildProps = { - mode: "hidden", - children: primaryChildren - }; - var primaryChildFragment; + // TODO: current can be non-null here even if the component + // hasn't yet mounted. This happens when the inner render suspends. + // We'll need to figure out if this is fine or can cause issues. + { + if (workInProgress.type !== workInProgress.elementType) { + // Lazy component props can't be validated in createElement + // because they're only guaranteed to be resolved here. + var outerMemoType = workInProgress.elementType; - if ( - // In legacy mode, we commit the primary tree as if it successfully - // completed, even though it's in an inconsistent state. - (mode & ConcurrentMode) === NoMode && // Make sure we're on the second pass, i.e. the primary child fragment was - // already cloned. In legacy mode, the only case where this isn't true is - // when DevTools forces us to display a fallback; we skip the first render - // pass entirely and go straight to rendering the fallback. (In Concurrent - // Mode, SuspenseList can also trigger this scenario, but this is a legacy- - // only codepath.) - workInProgress.child !== currentPrimaryChildFragment - ) { - var progressedPrimaryFragment = workInProgress.child; - primaryChildFragment = progressedPrimaryFragment; - primaryChildFragment.childLanes = NoLanes; - primaryChildFragment.pendingProps = primaryChildProps; + if (outerMemoType.$$typeof === REACT_LAZY_TYPE) { + // We warn when you define propTypes on lazy() + // so let's just skip over it to find memo() outer wrapper. + // Inner props for memo are validated later. + var lazyComponent = outerMemoType; + var payload = lazyComponent._payload; + var init = lazyComponent._init; - if (workInProgress.mode & ProfileMode) { - // Reset the durations from the first pass so they aren't included in the - // final amounts. This seems counterintuitive, since we're intentionally - // not measuring part of the render phase, but this makes it match what we - // do in Concurrent Mode. - primaryChildFragment.actualDuration = 0; - primaryChildFragment.actualStartTime = -1; - primaryChildFragment.selfBaseDuration = - currentPrimaryChildFragment.selfBaseDuration; - primaryChildFragment.treeBaseDuration = - currentPrimaryChildFragment.treeBaseDuration; - } // The fallback fiber was added as a deletion during the first pass. - // However, since we're going to remain on the fallback, we no longer want - // to delete it. + try { + outerMemoType = init(payload); + } catch (x) { + outerMemoType = null; + } // Inner propTypes will be validated in the function component path. - workInProgress.deletions = null; - } else { - primaryChildFragment = updateWorkInProgressOffscreenFiber( - currentPrimaryChildFragment, - primaryChildProps - ); // Since we're reusing a current tree, we need to reuse the flags, too. - // (We don't do this in legacy mode, because in legacy mode we don't re-use - // the current tree; see previous branch.) + var outerPropTypes = outerMemoType && outerMemoType.propTypes; - primaryChildFragment.subtreeFlags = - currentPrimaryChildFragment.subtreeFlags & StaticMask; + if (outerPropTypes) { + checkPropTypes( + outerPropTypes, + nextProps, // Resolved (SimpleMemoComponent has no defaultProps) + "prop", + getComponentNameFromType(outerMemoType) + ); + } + } + } } - var fallbackChildFragment; + if (current !== null) { + var prevProps = current.memoizedProps; - if (currentFallbackChildFragment !== null) { - fallbackChildFragment = createWorkInProgress( - currentFallbackChildFragment, - fallbackChildren - ); - } else { - fallbackChildFragment = createFiberFromFragment( - fallbackChildren, - mode, - renderLanes, - null - ); // Needs a placement effect because the parent (the Suspense boundary) already - // mounted but this is a new fiber. + if ( + shallowEqual(prevProps, nextProps) && + current.ref === workInProgress.ref && // Prevent bailout if the implementation changed due to hot reload. + workInProgress.type === current.type + ) { + didReceiveUpdate = false; // The props are shallowly equal. Reuse the previous props object, like we + // would during a normal fiber bailout. + // + // We don't have strong guarantees that the props object is referentially + // equal during updates where we can't bail out anyway — like if the props + // are shallowly equal, but there's a local state or context update in the + // same batch. + // + // However, as a principle, we should aim to make the behavior consistent + // across different ways of memoizing a component. For example, React.memo + // has a different internal Fiber layout if you pass a normal function + // component (SimpleMemoComponent) versus if you pass a different type + // like forwardRef (MemoComponent). But this is an implementation detail. + // Wrapping a component in forwardRef (or React.lazy, etc) shouldn't + // affect whether the props object is reused during a bailout. - fallbackChildFragment.flags |= Placement; + workInProgress.pendingProps = nextProps = prevProps; + + if (!checkScheduledUpdateOrContext(current, renderLanes)) { + // The pending lanes were cleared at the beginning of beginWork. We're + // about to bail out, but there might be other lanes that weren't + // included in the current render. Usually, the priority level of the + // remaining updates is accumulated during the evaluation of the + // component (i.e. when processing the update queue). But since since + // we're bailing out early *without* evaluating the component, we need + // to account for it here, too. Reset to the value of the current fiber. + // NOTE: This only applies to SimpleMemoComponent, not MemoComponent, + // because a MemoComponent fiber does not have hooks or an update queue; + // rather, it wraps around an inner component, which may or may not + // contains hooks. + // TODO: Move the reset at in beginWork out of the common path so that + // this is no longer necessary. + workInProgress.lanes = current.lanes; + return bailoutOnAlreadyFinishedWork( + current, + workInProgress, + renderLanes + ); + } else if ((current.flags & ForceUpdateForLegacySuspense) !== NoFlags$1) { + // This is a special case that only exists for legacy mode. + // See https://github.com/facebook/react/pull/19216. + didReceiveUpdate = true; + } + } } - fallbackChildFragment.return = workInProgress; - primaryChildFragment.return = workInProgress; - primaryChildFragment.sibling = fallbackChildFragment; - workInProgress.child = primaryChildFragment; - return fallbackChildFragment; + return updateFunctionComponent( + current, + workInProgress, + Component, + nextProps, + renderLanes + ); } -function retrySuspenseComponentWithoutHydrating( - current, - workInProgress, - renderLanes, - recoverableError -) { - // Falling back to client rendering. Because this has performance - // implications, it's considered a recoverable error, even though the user - // likely won't observe anything wrong with the UI. - // - // The error is passed in as an argument to enforce that every caller provide - // a custom message, or explicitly opt out (currently the only path that opts - // out is legacy mode; every concurrent path provides an error). - if (recoverableError !== null) { - queueHydrationError(recoverableError); - } // This will add the old fiber to the deletion list - - reconcileChildFibers(workInProgress, current.child, null, renderLanes); // We're now not suspended nor dehydrated. - +function updateOffscreenComponent(current, workInProgress, renderLanes) { var nextProps = workInProgress.pendingProps; - var primaryChildren = nextProps.children; - var primaryChildFragment = mountSuspensePrimaryChildren( - workInProgress, - primaryChildren - ); // Needs a placement effect because the parent (the Suspense boundary) already - // mounted but this is a new fiber. + var nextChildren = nextProps.children; + var nextIsDetached = + (workInProgress.stateNode._pendingVisibility & OffscreenDetached) !== 0; + var prevState = current !== null ? current.memoizedState : null; + markRef$1(current, workInProgress); - primaryChildFragment.flags |= Placement; - workInProgress.memoizedState = null; - return primaryChildFragment; -} + if ( + nextProps.mode === "hidden" || + nextProps.mode === "unstable-defer-without-hiding" || + nextIsDetached + ) { + // Rendering a hidden tree. + var didSuspend = (workInProgress.flags & DidCapture) !== NoFlags$1; -function mountSuspenseFallbackAfterRetryWithoutHydrating( - current, - workInProgress, - primaryChildren, - fallbackChildren, - renderLanes -) { - var fiberMode = workInProgress.mode; - var primaryChildProps = { - mode: "visible", - children: primaryChildren - }; - var primaryChildFragment = mountWorkInProgressOffscreenFiber( - primaryChildProps, - fiberMode - ); - var fallbackChildFragment = createFiberFromFragment( - fallbackChildren, - fiberMode, - renderLanes, - null - ); // Needs a placement effect because the parent (the Suspense - // boundary) already mounted but this is a new fiber. + if (didSuspend) { + // Something suspended inside a hidden tree + // Include the base lanes from the last render + var nextBaseLanes = + prevState !== null + ? mergeLanes(prevState.baseLanes, renderLanes) + : renderLanes; - fallbackChildFragment.flags |= Placement; - primaryChildFragment.return = workInProgress; - fallbackChildFragment.return = workInProgress; - primaryChildFragment.sibling = fallbackChildFragment; - workInProgress.child = primaryChildFragment; + if (current !== null) { + // Reset to the current children + var currentChild = (workInProgress.child = current.child); // The current render suspended, but there may be other lanes with + // pending work. We can't read `childLanes` from the current Offscreen + // fiber because we reset it when it was deferred; however, we can read + // the pending lanes from the child fibers. - if ((workInProgress.mode & ConcurrentMode) !== NoMode) { - // We will have dropped the effect list which contains the - // deletion. We need to reconcile to delete the current child. - reconcileChildFibers(workInProgress, current.child, null, renderLanes); - } + var currentChildLanes = NoLanes; - return fallbackChildFragment; -} + while (currentChild !== null) { + currentChildLanes = mergeLanes( + mergeLanes(currentChildLanes, currentChild.lanes), + currentChild.childLanes + ); + currentChild = currentChild.sibling; + } -function updateDehydratedSuspenseComponent( - current, - workInProgress, - didSuspend, - nextProps, - suspenseInstance, - suspenseState, - renderLanes -) { - if (!didSuspend) { - // This is the first render pass. Attempt to hydrate. - pushPrimaryTreeSuspenseHandler(workInProgress); // We should never be hydrating at this point because it is the first pass, + var lanesWeJustAttempted = nextBaseLanes; + var remainingChildLanes = removeLanes( + currentChildLanes, + lanesWeJustAttempted + ); + workInProgress.childLanes = remainingChildLanes; + } else { + workInProgress.childLanes = NoLanes; + workInProgress.child = null; + } - if ((workInProgress.mode & ConcurrentMode) === NoMode) { - return retrySuspenseComponentWithoutHydrating( + return deferHiddenOffscreenComponent( current, workInProgress, - renderLanes, - null + nextBaseLanes ); } - if (isSuspenseInstanceFallback()) { - // This boundary is in a permanent fallback state. In this case, we'll never - // get an update and we'll never be able to hydrate the final content. Let's just try the - // client side render instead. - var digest, message, stack; - - { - var _getSuspenseInstanceF = getSuspenseInstanceFallbackErrorDetails(); + if ((workInProgress.mode & ConcurrentMode) === NoMode) { + // In legacy sync mode, don't defer the subtree. Render it now. + // TODO: Consider how Offscreen should work with transitions in the future + var nextState = { + baseLanes: NoLanes, + cachePool: null + }; + workInProgress.memoizedState = nextState; - digest = _getSuspenseInstanceF.digest; - message = _getSuspenseInstanceF.message; - stack = _getSuspenseInstanceF.stack; - } + reuseHiddenContextOnStack(workInProgress); + pushOffscreenSuspenseHandler(workInProgress); + } else if (!includesSomeLane(renderLanes, OffscreenLane)) { + // We're hidden, and we're not rendering at Offscreen. We will bail out + // and resume this tree later. + // Schedule this fiber to re-render at Offscreen priority + workInProgress.lanes = workInProgress.childLanes = + laneToLanes(OffscreenLane); // Include the base lanes from the last render - var error; + var _nextBaseLanes = + prevState !== null + ? mergeLanes(prevState.baseLanes, renderLanes) + : renderLanes; - if (message) { - // eslint-disable-next-line react-internal/prod-error-codes - error = new Error(message); + return deferHiddenOffscreenComponent( + current, + workInProgress, + _nextBaseLanes + ); + } else { + // This is the second render. The surrounding visible content has already + // committed. Now we resume rendering the hidden tree. + // Rendering at offscreen, so we can clear the base lanes. + var _nextState = { + baseLanes: NoLanes, + cachePool: null + }; + workInProgress.memoizedState = _nextState; + + if (prevState !== null) { + pushHiddenContext(workInProgress, prevState); } else { - error = new Error( - "The server could not finish this Suspense boundary, likely " + - "due to an error during server rendering. Switched to " + - "client rendering." - ); + reuseHiddenContextOnStack(workInProgress); } - error.digest = digest; - var capturedValue = createCapturedValue(error, digest, stack); - return retrySuspenseComponentWithoutHydrating( - current, - workInProgress, - renderLanes, - capturedValue - ); + pushOffscreenSuspenseHandler(workInProgress); } - // any context has changed, we need to treat is as if the input might have changed. + } else { + // Rendering a visible tree. + if (prevState !== null) { + pushHiddenContext(workInProgress, prevState); + reuseSuspenseHandlerOnStack(workInProgress); // Since we're not hidden anymore, reset the state - var hasContextChanged = includesSomeLane(renderLanes, current.childLanes); + workInProgress.memoizedState = null; + } else { + // to avoid a push/pop misalignment. - if (didReceiveUpdate || hasContextChanged) { - // This boundary has changed since the first render. This means that we are now unable to - // hydrate it. We might still be able to hydrate it using a higher priority lane. - var root = getWorkInProgressRoot(); + reuseHiddenContextOnStack(workInProgress); + reuseSuspenseHandlerOnStack(workInProgress); + } + } - if (root !== null) { - var attemptHydrationAtLane = getBumpedLaneForHydration( - root, - renderLanes - ); + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} - if ( - attemptHydrationAtLane !== NoLane && - attemptHydrationAtLane !== suspenseState.retryLane - ) { - // Intentionally mutating since this render will get interrupted. This - // is one of the very rare times where we mutate the current tree - // during the render phase. - suspenseState.retryLane = attemptHydrationAtLane; // TODO: Ideally this would inherit the event time of the current render +function deferHiddenOffscreenComponent( + current, + workInProgress, + nextBaseLanes, + renderLanes +) { + var nextState = { + baseLanes: nextBaseLanes, + // Save the cache pool so we can resume later. + cachePool: null + }; + workInProgress.memoizedState = nextState; + // to avoid a push/pop misalignment. - var eventTime = NoTimestamp; - enqueueConcurrentRenderForLane(current, attemptHydrationAtLane); - scheduleUpdateOnFiber( - root, - current, - attemptHydrationAtLane, - eventTime - ); // Throw a special object that signals to the work loop that it should - // interrupt the current render. - // - // Because we're inside a React-only execution stack, we don't - // strictly need to throw here — we could instead modify some internal - // work loop state. But using an exception means we don't need to - // check for this case on every iteration of the work loop. So doing - // it this way moves the check out of the fast path. + reuseHiddenContextOnStack(workInProgress); + pushOffscreenSuspenseHandler(workInProgress); - throw SelectiveHydrationException; - } - } // If we did not selectively hydrate, we'll continue rendering without - // hydrating. Mark this tree as suspended to prevent it from committing - // outside a transition. - // - // This path should only happen if the hydration lane already suspended. - // Currently, it also happens during sync updates because there is no - // hydration lane for sync updates. - // TODO: We should ideally have a sync hydration lane that we can apply to do - // a pass where we hydrate this subtree in place using the previous Context and then - // reapply the update afterwards. + return null; +} // Note: These happen to have identical begin phases, for now. We shouldn't hold +// ourselves to this constraint, though. If the behavior diverges, we should +// fork the function. - renderDidSuspendDelayIfPossible(); - return retrySuspenseComponentWithoutHydrating( - current, - workInProgress, - renderLanes, - null - ); - } else if (isSuspenseInstancePending()) { - // This component is still pending more data from the server, so we can't hydrate its - // content. We treat it as if this component suspended itself. It might seem as if - // we could just try to render it client-side instead. However, this will perform a - // lot of unnecessary work and is unlikely to complete since it often will suspend - // on missing data anyway. Additionally, the server might be able to render more - // than we can on the client yet. In that case we'd end up with more fallback states - // on the client than if we just leave it alone. If the server times out or errors - // these should update this boundary to the permanent Fallback state instead. - // Mark it as having captured (i.e. suspended). - workInProgress.flags |= DidCapture; // Leave the child in place. I.e. the dehydrated fragment. +var updateLegacyHiddenComponent = updateOffscreenComponent; - workInProgress.child = current.child; // Register a callback to retry this boundary once the server has sent the result. +function updateFragment(current, workInProgress, renderLanes) { + var nextChildren = workInProgress.pendingProps; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} - retryDehydratedSuspenseBoundary.bind(null, current); - registerSuspenseInstanceRetry(); - return null; - } else { - var primaryChildren = nextProps.children; - var primaryChildFragment = mountSuspensePrimaryChildren( - workInProgress, - primaryChildren - ); // Mark the children as hydrating. This is a fast path to know whether this - // tree is part of a hydrating tree. This is used to determine if a child - // node has fully mounted yet, and for scheduling event replaying. - // Conceptually this is similar to Placement in that a new subtree is - // inserted into the React tree here. It just happens to not need DOM - // mutations because it already exists. +function updateMode(current, workInProgress, renderLanes) { + var nextChildren = workInProgress.pendingProps.children; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} - primaryChildFragment.flags |= Hydrating; - return primaryChildFragment; +function updateProfiler(current, workInProgress, renderLanes) { + { + workInProgress.flags |= Update; + + { + // Reset effect durations for the next eventual effect phase. + // These are reset during render to allow the DevTools commit hook a chance to read them, + var stateNode = workInProgress.stateNode; + stateNode.effectDuration = 0; + stateNode.passiveEffectDuration = 0; } - } else { - // This is the second render pass. We already attempted to hydrated, but - // something either suspended or errored. - if (workInProgress.flags & ForceClientRender) { - // Something errored during hydration. Try again without hydrating. - pushPrimaryTreeSuspenseHandler(workInProgress); - workInProgress.flags &= ~ForceClientRender; + } - var _capturedValue = createCapturedValue( - new Error( - "There was an error while hydrating this Suspense boundary. " + - "Switched to client rendering." - ) - ); + var nextProps = workInProgress.pendingProps; + var nextChildren = nextProps.children; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} - return retrySuspenseComponentWithoutHydrating( - current, - workInProgress, - renderLanes, - _capturedValue - ); - } else if (workInProgress.memoizedState !== null) { - // Something suspended and we should still be in dehydrated mode. - // Leave the existing child in place. - // Push to avoid a mismatch - pushFallbackTreeSuspenseHandler(workInProgress); - workInProgress.child = current.child; // The dehydrated completion pass expects this flag to be there - // but the normal suspense pass doesn't. +function markRef$1(current, workInProgress) { + var ref = workInProgress.ref; - workInProgress.flags |= DidCapture; - return null; - } else { - // Suspended but we should no longer be in dehydrated mode. - // Therefore we now have to render the fallback. - pushFallbackTreeSuspenseHandler(workInProgress); - var nextPrimaryChildren = nextProps.children; - var nextFallbackChildren = nextProps.fallback; - var fallbackChildFragment = - mountSuspenseFallbackAfterRetryWithoutHydrating( - current, - workInProgress, - nextPrimaryChildren, - nextFallbackChildren, - renderLanes + if ( + (current === null && ref !== null) || + (current !== null && current.ref !== ref) + ) { + // Schedule a Ref effect + workInProgress.flags |= Ref; + workInProgress.flags |= RefStatic; + } +} + +function updateFunctionComponent( + current, + workInProgress, + Component, + nextProps, + renderLanes +) { + { + if (workInProgress.type !== workInProgress.elementType) { + // Lazy component props can't be validated in createElement + // because they're only guaranteed to be resolved here. + var innerPropTypes = Component.propTypes; + + if (innerPropTypes) { + checkPropTypes( + innerPropTypes, + nextProps, // Resolved props + "prop", + getComponentNameFromType(Component) ); - var _primaryChildFragment4 = workInProgress.child; - _primaryChildFragment4.memoizedState = - mountSuspenseOffscreenState(renderLanes); - workInProgress.memoizedState = SUSPENDED_MARKER; - return fallbackChildFragment; + } } } -} -function scheduleSuspenseWorkOnFiber(fiber, renderLanes, propagationRoot) { - fiber.lanes = mergeLanes(fiber.lanes, renderLanes); - var alternate = fiber.alternate; + var context; + + { + var unmaskedContext = getUnmaskedContext(workInProgress, Component, true); + context = getMaskedContext(workInProgress, unmaskedContext); + } + + var nextChildren; + prepareToReadContext(workInProgress, renderLanes); + + { + markComponentRenderStarted(workInProgress); + } + + { + ReactCurrentOwner$2.current = workInProgress; + setIsRendering(true); + nextChildren = renderWithHooks( + current, + workInProgress, + Component, + nextProps, + context, + renderLanes + ); + setIsRendering(false); + } + + { + markComponentRenderStopped(); + } - if (alternate !== null) { - alternate.lanes = mergeLanes(alternate.lanes, renderLanes); + if (current !== null && !didReceiveUpdate) { + bailoutHooks(current, workInProgress, renderLanes); + return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); } - scheduleContextWorkOnParentPath(fiber.return, renderLanes, propagationRoot); + workInProgress.flags |= PerformedWork; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; } -function propagateSuspenseContextChange( +function replayFunctionComponent( + current, workInProgress, - firstChild, + nextProps, + Component, renderLanes ) { - // Mark any Suspense boundaries with fallbacks as having work to do. - // If they were previously forced into fallbacks, they may now be able - // to unblock. - var node = firstChild; - - while (node !== null) { - if (node.tag === SuspenseComponent) { - var state = node.memoizedState; - - if (state !== null) { - scheduleSuspenseWorkOnFiber(node, renderLanes, workInProgress); - } - } else if (node.tag === SuspenseListComponent) { - // If the tail is hidden there might not be an Suspense boundaries - // to schedule work on. In this case we have to schedule it on the - // list itself. - // We don't have to traverse to the children of the list since - // the list will propagate the change when it rerenders. - scheduleSuspenseWorkOnFiber(node, renderLanes, workInProgress); - } else if (node.child !== null) { - node.child.return = node; - node = node.child; - continue; - } - - if (node === workInProgress) { - return; - } // $FlowFixMe[incompatible-use] found when upgrading Flow + // This function is used to replay a component that previously suspended, + // after its data resolves. It's a simplified version of + // updateFunctionComponent that reuses the hooks from the previous attempt. + var context; - while (node.sibling === null) { - // $FlowFixMe[incompatible-use] found when upgrading Flow - if (node.return === null || node.return === workInProgress) { - return; - } + { + var unmaskedContext = getUnmaskedContext(workInProgress, Component, true); + context = getMaskedContext(workInProgress, unmaskedContext); + } - node = node.return; - } // $FlowFixMe[incompatible-use] found when upgrading Flow + prepareToReadContext(workInProgress, renderLanes); - node.sibling.return = node.return; - node = node.sibling; + { + markComponentRenderStarted(workInProgress); } -} - -function findLastContentRow(firstChild) { - // This is going to find the last row among these children that is already - // showing content on the screen, as opposed to being in fallback state or - // new. If a row has multiple Suspense boundaries, any of them being in the - // fallback state, counts as the whole row being in a fallback state. - // Note that the "rows" will be workInProgress, but any nested children - // will still be current since we haven't rendered them yet. The mounted - // order may not be the same as the new order. We use the new order. - var row = firstChild; - var lastContentRow = null; - while (row !== null) { - var currentRow = row.alternate; // New rows can't be content rows. + var nextChildren = replaySuspendedComponentWithHooks( + current, + workInProgress, + Component, + nextProps, + context + ); - if (currentRow !== null && findFirstSuspended(currentRow) === null) { - lastContentRow = row; - } + { + markComponentRenderStopped(); + } - row = row.sibling; + if (current !== null && !didReceiveUpdate) { + bailoutHooks(current, workInProgress, renderLanes); + return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); } - return lastContentRow; + workInProgress.flags |= PerformedWork; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; } -function validateRevealOrder(revealOrder) { +function updateClassComponent( + current, + workInProgress, + Component, + nextProps, + renderLanes +) { { - if ( - revealOrder !== undefined && - revealOrder !== "forwards" && - revealOrder !== "backwards" && - revealOrder !== "together" && - !didWarnAboutRevealOrder[revealOrder] - ) { - didWarnAboutRevealOrder[revealOrder] = true; + // This is used by DevTools to force a boundary to error. + switch (shouldError(workInProgress)) { + case false: { + var _instance = workInProgress.stateNode; + var ctor = workInProgress.type; // TODO This way of resetting the error boundary state is a hack. + // Is there a better way to do this? - if (typeof revealOrder === "string") { - switch (revealOrder.toLowerCase()) { - case "together": - case "forwards": - case "backwards": { - error( - '"%s" is not a valid value for revealOrder on . ' + - 'Use lowercase "%s" instead.', - revealOrder, - revealOrder.toLowerCase() - ); + var tempInstance = new ctor( + workInProgress.memoizedProps, + _instance.context + ); + var state = tempInstance.state; - break; - } + _instance.updater.enqueueSetState(_instance, state, null); - case "forward": - case "backward": { - error( - '"%s" is not a valid value for revealOrder on . ' + - 'React uses the -s suffix in the spelling. Use "%ss" instead.', - revealOrder, - revealOrder.toLowerCase() - ); + break; + } - break; - } + case true: { + workInProgress.flags |= DidCapture; + workInProgress.flags |= ShouldCapture; // eslint-disable-next-line react-internal/prod-error-codes - default: - error( - '"%s" is not a supported revealOrder on . ' + - 'Did you mean "together", "forwards" or "backwards"?', - revealOrder - ); + var error$1 = new Error("Simulated error coming from DevTools"); + var lane = pickArbitraryLane(renderLanes); + workInProgress.lanes = mergeLanes(workInProgress.lanes, lane); // Schedule the error boundary to re-render using updated state - break; - } - } else { - error( - "%s is not a supported value for revealOrder on . " + - 'Did you mean "together", "forwards" or "backwards"?', - revealOrder + var update = createClassErrorUpdate( + workInProgress, + createCapturedValueAtFiber(error$1, workInProgress), + lane + ); + enqueueCapturedUpdate(workInProgress, update); + break; + } + } + + if (workInProgress.type !== workInProgress.elementType) { + // Lazy component props can't be validated in createElement + // because they're only guaranteed to be resolved here. + var innerPropTypes = Component.propTypes; + + if (innerPropTypes) { + checkPropTypes( + innerPropTypes, + nextProps, // Resolved props + "prop", + getComponentNameFromType(Component) ); } } + } // Push context providers early to prevent context stack mismatches. + // During mounting we don't know the child context yet as the instance doesn't exist. + // We will invalidate the child context in finishClassComponent() right after rendering. + + var hasContext; + + if (isContextProvider(Component)) { + hasContext = true; + pushContextProvider(workInProgress); + } else { + hasContext = false; } -} -function validateTailOptions(tailMode, revealOrder) { + prepareToReadContext(workInProgress, renderLanes); + var instance = workInProgress.stateNode; + var shouldUpdate; + + if (instance === null) { + resetSuspendedCurrentOnMountInLegacyMode(current, workInProgress); // In the initial pass we might need to construct the instance. + + constructClassInstance(workInProgress, Component, nextProps); + mountClassInstance(workInProgress, Component, nextProps, renderLanes); + shouldUpdate = true; + } else if (current === null) { + // In a resume, we'll already have an instance we can reuse. + shouldUpdate = resumeMountClassInstance( + workInProgress, + Component, + nextProps, + renderLanes + ); + } else { + shouldUpdate = updateClassInstance( + current, + workInProgress, + Component, + nextProps, + renderLanes + ); + } + + var nextUnitOfWork = finishClassComponent( + current, + workInProgress, + Component, + shouldUpdate, + hasContext, + renderLanes + ); + { - if (tailMode !== undefined && !didWarnAboutTailOptions[tailMode]) { - if (tailMode !== "collapsed" && tailMode !== "hidden") { - didWarnAboutTailOptions[tailMode] = true; - - error( - '"%s" is not a supported value for tail on . ' + - 'Did you mean "collapsed" or "hidden"?', - tailMode - ); - } else if (revealOrder !== "forwards" && revealOrder !== "backwards") { - didWarnAboutTailOptions[tailMode] = true; + var inst = workInProgress.stateNode; + if (shouldUpdate && inst.props !== nextProps) { + if (!didWarnAboutReassigningProps) { error( - ' is only valid if revealOrder is ' + - '"forwards" or "backwards". ' + - 'Did you mean to specify revealOrder="forwards"?', - tailMode + "It looks like %s is reassigning its own `this.props` while rendering. " + + "This is not supported and can lead to confusing bugs.", + getComponentNameFromFiber(workInProgress) || "a component" ); } + + didWarnAboutReassigningProps = true; } } -} - -function validateSuspenseListNestedChild(childSlot, index) { - { - var isAnArray = isArray(childSlot); - var isIterable = - !isAnArray && typeof getIteratorFn(childSlot) === "function"; - if (isAnArray || isIterable) { - var type = isAnArray ? "array" : "iterable"; + return nextUnitOfWork; +} - error( - "A nested %s was passed to row #%s in . Wrap it in " + - "an additional SuspenseList to configure its revealOrder: " + - " ... " + - "{%s} ... " + - "", - type, - index, - type - ); +function finishClassComponent( + current, + workInProgress, + Component, + shouldUpdate, + hasContext, + renderLanes +) { + // Refs should update even if shouldComponentUpdate returns false + markRef$1(current, workInProgress); + var didCaptureError = (workInProgress.flags & DidCapture) !== NoFlags$1; - return false; + if (!shouldUpdate && !didCaptureError) { + // Context providers should defer to sCU for rendering + if (hasContext) { + invalidateContextProvider(workInProgress, Component, false); } + + return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); } - return true; -} + var instance = workInProgress.stateNode; // Rerender -function validateSuspenseListChildren(children, revealOrder) { - { - if ( - (revealOrder === "forwards" || revealOrder === "backwards") && - children !== undefined && - children !== null && - children !== false - ) { - if (isArray(children)) { - for (var i = 0; i < children.length; i++) { - if (!validateSuspenseListNestedChild(children[i], i)) { - return; - } - } - } else { - var iteratorFn = getIteratorFn(children); + ReactCurrentOwner$2.current = workInProgress; + var nextChildren; - if (typeof iteratorFn === "function") { - var childrenIterator = iteratorFn.call(children); + if ( + didCaptureError && + typeof Component.getDerivedStateFromError !== "function" + ) { + // If we captured an error, but getDerivedStateFromError is not defined, + // unmount all the children. componentDidCatch will schedule an update to + // re-render a fallback. This is temporary until we migrate everyone to + // the new API. + // TODO: Warn in a future release. + nextChildren = null; - if (childrenIterator) { - var step = childrenIterator.next(); - var _i = 0; + { + stopProfilerTimerIfRunning(); + } + } else { + { + markComponentRenderStarted(workInProgress); + } - for (; !step.done; step = childrenIterator.next()) { - if (!validateSuspenseListNestedChild(step.value, _i)) { - return; - } + { + setIsRendering(true); + nextChildren = instance.render(); - _i++; - } - } - } else { - error( - 'A single row was passed to a . ' + - "This is not useful since it needs multiple rows. " + - "Did you mean to pass multiple children or an array?", - revealOrder - ); + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); + + try { + instance.render(); + } finally { + setIsStrictModeForDevtools(false); } } - } - } -} -function initSuspenseListRenderState( - workInProgress, - isBackwards, - tail, - lastContentRow, - tailMode -) { - var renderState = workInProgress.memoizedState; + setIsRendering(false); + } - if (renderState === null) { - workInProgress.memoizedState = { - isBackwards: isBackwards, - rendering: null, - renderingStartTime: 0, - last: lastContentRow, - tail: tail, - tailMode: tailMode - }; - } else { - // We can reuse the existing object from previous renders. - renderState.isBackwards = isBackwards; - renderState.rendering = null; - renderState.renderingStartTime = 0; - renderState.last = lastContentRow; - renderState.tail = tail; - renderState.tailMode = tailMode; - } -} // This can end up rendering this component multiple passes. -// The first pass splits the children fibers into two sets. A head and tail. -// We first render the head. If anything is in fallback state, we do another -// pass through beginWork to rerender all children (including the tail) with -// the force suspend context. If the first render didn't have anything in -// in fallback state. Then we render each row in the tail one-by-one. -// That happens in the completeWork phase without going back to beginWork. + { + markComponentRenderStopped(); + } + } // React DevTools reads this flag. -function updateSuspenseListComponent(current, workInProgress, renderLanes) { - var nextProps = workInProgress.pendingProps; - var revealOrder = nextProps.revealOrder; - var tailMode = nextProps.tail; - var newChildren = nextProps.children; - validateRevealOrder(revealOrder); - validateTailOptions(tailMode, revealOrder); - validateSuspenseListChildren(newChildren, revealOrder); - reconcileChildren(current, workInProgress, newChildren, renderLanes); - var suspenseContext = suspenseStackCursor.current; - var shouldForceFallback = hasSuspenseListContext( - suspenseContext, - ForceSuspenseFallback - ); + workInProgress.flags |= PerformedWork; - if (shouldForceFallback) { - suspenseContext = setShallowSuspenseListContext( - suspenseContext, - ForceSuspenseFallback + if (current !== null && didCaptureError) { + // If we're recovering from an error, reconcile without reusing any of + // the existing children. Conceptually, the normal children and the children + // that are shown on error are two different sets, so we shouldn't reuse + // normal children even if their identities match. + forceUnmountCurrentAndReconcile( + current, + workInProgress, + nextChildren, + renderLanes ); - workInProgress.flags |= DidCapture; } else { - var didSuspendBefore = - current !== null && (current.flags & DidCapture) !== NoFlags$1; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + } // Memoize state using the values we just used to render. + // TODO: Restructure so we never read values from the instance. - if (didSuspendBefore) { - // If we previously forced a fallback, we need to schedule work - // on any nested boundaries to let them know to try to render - // again. This is the same as context updating. - propagateSuspenseContextChange( - workInProgress, - workInProgress.child, - renderLanes - ); - } + workInProgress.memoizedState = instance.state; // The context might have changed so we need to recalculate it. - suspenseContext = setDefaultShallowSuspenseListContext(suspenseContext); + if (hasContext) { + invalidateContextProvider(workInProgress, Component, true); } - pushSuspenseListContext(workInProgress, suspenseContext); - - if ((workInProgress.mode & ConcurrentMode) === NoMode) { - // In legacy mode, SuspenseList doesn't work so we just - // use make it a noop by treating it as the default revealOrder. - workInProgress.memoizedState = null; - } else { - switch (revealOrder) { - case "forwards": { - var lastContentRow = findLastContentRow(workInProgress.child); - var tail; - - if (lastContentRow === null) { - // The whole list is part of the tail. - // TODO: We could fast path by just rendering the tail now. - tail = workInProgress.child; - workInProgress.child = null; - } else { - // Disconnect the tail rows after the content row. - // We're going to render them separately later. - tail = lastContentRow.sibling; - lastContentRow.sibling = null; - } - - initSuspenseListRenderState( - workInProgress, - false, // isBackwards - tail, - lastContentRow, - tailMode - ); - break; - } + return workInProgress.child; +} - case "backwards": { - // We're going to find the first row that has existing content. - // At the same time we're going to reverse the list of everything - // we pass in the meantime. That's going to be our tail in reverse - // order. - var _tail = null; - var row = workInProgress.child; - workInProgress.child = null; +function pushHostRootContext(workInProgress) { + var root = workInProgress.stateNode; - while (row !== null) { - var currentRow = row.alternate; // New rows can't be content rows. + if (root.pendingContext) { + pushTopLevelContextObject( + workInProgress, + root.pendingContext, + root.pendingContext !== root.context + ); + } else if (root.context) { + // Should always be set + pushTopLevelContextObject(workInProgress, root.context, false); + } - if (currentRow !== null && findFirstSuspended(currentRow) === null) { - // This is the beginning of the main content. - workInProgress.child = row; - break; - } + pushHostContainer(workInProgress, root.containerInfo); +} - var nextRow = row.sibling; - row.sibling = _tail; - _tail = row; - row = nextRow; - } // TODO: If workInProgress.child is null, we can continue on the tail immediately. +function updateHostRoot(current, workInProgress, renderLanes) { + pushHostRootContext(workInProgress); - initSuspenseListRenderState( - workInProgress, - true, // isBackwards - _tail, - null, // last - tailMode - ); - break; - } + if (current === null) { + throw new Error("Should have a current fiber. This is a bug in React."); + } - case "together": { - initSuspenseListRenderState( - workInProgress, - false, // isBackwards - null, // tail - null, // last - undefined - ); - break; - } + var nextProps = workInProgress.pendingProps; + var prevState = workInProgress.memoizedState; + var prevChildren = prevState.element; + cloneUpdateQueue(current, workInProgress); + processUpdateQueue(workInProgress, nextProps, null, renderLanes); + var nextState = workInProgress.memoizedState; + // being called "element". - default: { - // The default reveal order is the same as not having - // a boundary. - workInProgress.memoizedState = null; - } + var nextChildren = nextState.element; + + { + if (nextChildren === prevChildren) { + return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); } + + reconcileChildren(current, workInProgress, nextChildren, renderLanes); } return workInProgress.child; } -function updatePortalComponent(current, workInProgress, renderLanes) { - pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); - var nextChildren = workInProgress.pendingProps; +function updateHostComponent$1(current, workInProgress, renderLanes) { + pushHostContext(workInProgress); + var nextProps = workInProgress.pendingProps; + var prevProps = current !== null ? current.memoizedProps : null; + var nextChildren = nextProps.children; - if (current === null) { - // Portals are special because we don't append the children during mount - // but at commit. Therefore we need to track insertions which the normal - // flow doesn't do during mount. This doesn't happen at the root because - // the root always starts with a "current" with a null child. - // TODO: Consider unifying this with how the root works. - workInProgress.child = reconcileChildFibers( - workInProgress, - null, - nextChildren, - renderLanes - ); - } else { - reconcileChildren(current, workInProgress, nextChildren, renderLanes); + if (prevProps !== null && shouldSetTextContent()) { + // If we're switching from a direct text child to a normal child, or to + // empty, we need to schedule the text content to be reset. + workInProgress.flags |= ContentReset; } + markRef$1(current, workInProgress); + reconcileChildren(current, workInProgress, nextChildren, renderLanes); return workInProgress.child; } -var hasWarnedAboutUsingNoValuePropOnContextProvider = false; +function updateHostText$1(current, workInProgress) { + // immediately after. -function updateContextProvider(current, workInProgress, renderLanes) { - var providerType = workInProgress.type; - var context = providerType._context; - var newProps = workInProgress.pendingProps; - var oldProps = workInProgress.memoizedProps; - var newValue = newProps.value; + return null; +} - { - if (!("value" in newProps)) { - if (!hasWarnedAboutUsingNoValuePropOnContextProvider) { - hasWarnedAboutUsingNoValuePropOnContextProvider = true; +function mountLazyComponent( + _current, + workInProgress, + elementType, + renderLanes +) { + resetSuspendedCurrentOnMountInLegacyMode(_current, workInProgress); + var props = workInProgress.pendingProps; + var lazyComponent = elementType; + var payload = lazyComponent._payload; + var init = lazyComponent._init; + var Component = init(payload); // Store the unwrapped component in the type. - error( - "The `value` prop is required for the ``. Did you misspell it or forget to pass it?" - ); + workInProgress.type = Component; + var resolvedTag = (workInProgress.tag = resolveLazyComponentTag(Component)); + var resolvedProps = resolveDefaultProps(Component, props); + var child; + + switch (resolvedTag) { + case FunctionComponent: { + { + validateFunctionComponentInDev(workInProgress, Component); + workInProgress.type = Component = + resolveFunctionForHotReloading(Component); } + + child = updateFunctionComponent( + null, + workInProgress, + Component, + resolvedProps, + renderLanes + ); + return child; } - var providerPropTypes = workInProgress.type.propTypes; + case ClassComponent: { + { + workInProgress.type = Component = + resolveClassForHotReloading(Component); + } - if (providerPropTypes) { - checkPropTypes(providerPropTypes, newProps, "prop", "Context.Provider"); + child = updateClassComponent( + null, + workInProgress, + Component, + resolvedProps, + renderLanes + ); + return child; } - } - pushProvider(workInProgress, context, newValue); + case ForwardRef: { + { + workInProgress.type = Component = + resolveForwardRefForHotReloading(Component); + } - { - if (oldProps !== null) { - var oldValue = oldProps.value; + child = updateForwardRef( + null, + workInProgress, + Component, + resolvedProps, + renderLanes + ); + return child; + } - if (objectIs(oldValue, newValue)) { - // No change. Bailout early if children are the same. - if (oldProps.children === newProps.children && !hasContextChanged()) { - return bailoutOnAlreadyFinishedWork( - current, - workInProgress, - renderLanes - ); + case MemoComponent: { + { + if (workInProgress.type !== workInProgress.elementType) { + var outerPropTypes = Component.propTypes; + + if (outerPropTypes) { + checkPropTypes( + outerPropTypes, + resolvedProps, // Resolved for outer only + "prop", + getComponentNameFromType(Component) + ); + } } - } else { - // The context value changed. Search for matching consumers and schedule - // them to update. - propagateContextChange(workInProgress, context, renderLanes); } + + child = updateMemoComponent( + null, + workInProgress, + Component, + resolveDefaultProps(Component.type, resolvedProps), // The inner type can have defaults too + renderLanes + ); + return child; } } - var newChildren = newProps.children; - reconcileChildren(current, workInProgress, newChildren, renderLanes); - return workInProgress.child; + var hint = ""; + + { + if ( + Component !== null && + typeof Component === "object" && + Component.$$typeof === REACT_LAZY_TYPE + ) { + hint = " Did you wrap a component in React.lazy() more than once?"; + } + } // This message intentionally doesn't mention ForwardRef or MemoComponent + // because the fact that it's a separate type of work is an + // implementation detail. + + throw new Error( + "Element type is invalid. Received a promise that resolves to: " + + Component + + ". " + + ("Lazy element type must resolve to a class or function." + hint) + ); } -var hasWarnedAboutUsingContextAsConsumer = false; +function mountIncompleteClassComponent( + _current, + workInProgress, + Component, + nextProps, + renderLanes +) { + resetSuspendedCurrentOnMountInLegacyMode(_current, workInProgress); // Promote the fiber to a class and try rendering again. -function updateContextConsumer(current, workInProgress, renderLanes) { - var context = workInProgress.type; // The logic below for Context differs depending on PROD or DEV mode. In - // DEV mode, we create a separate object for Context.Consumer that acts - // like a proxy to Context. This proxy object adds unnecessary code in PROD - // so we use the old behaviour (Context.Consumer references Context) to - // reduce size and overhead. The separate object references context via - // a property called "_context", which also gives us the ability to check - // in DEV mode if this property exists or not and warn if it does not. + workInProgress.tag = ClassComponent; // The rest of this function is a fork of `updateClassComponent` + // Push context providers early to prevent context stack mismatches. + // During mounting we don't know the child context yet as the instance doesn't exist. + // We will invalidate the child context in finishClassComponent() right after rendering. - { - if (context._context === undefined) { - // This may be because it's a Context (rather than a Consumer). - // Or it may be because it's older React where they're the same thing. - // We only want to warn if we're sure it's a new React. - if (context !== context.Consumer) { - if (!hasWarnedAboutUsingContextAsConsumer) { - hasWarnedAboutUsingContextAsConsumer = true; + var hasContext; - error( - "Rendering directly is not supported and will be removed in " + - "a future major release. Did you mean to render instead?" - ); - } - } - } else { - context = context._context; - } + if (isContextProvider(Component)) { + hasContext = true; + pushContextProvider(workInProgress); + } else { + hasContext = false; } - var newProps = workInProgress.pendingProps; - var render = newProps.children; + prepareToReadContext(workInProgress, renderLanes); + constructClassInstance(workInProgress, Component, nextProps); + mountClassInstance(workInProgress, Component, nextProps, renderLanes); + return finishClassComponent( + null, + workInProgress, + Component, + true, + hasContext, + renderLanes + ); +} + +function mountIndeterminateComponent( + _current, + workInProgress, + Component, + renderLanes +) { + resetSuspendedCurrentOnMountInLegacyMode(_current, workInProgress); + var props = workInProgress.pendingProps; + var context; { - if (typeof render !== "function") { - error( - "A context consumer was rendered with multiple children, or a child " + - "that isn't a function. A context consumer expects a single child " + - "that is a function. If you did pass a function, make sure there " + - "is no trailing or leading whitespace around it." - ); - } + var unmaskedContext = getUnmaskedContext(workInProgress, Component, false); + context = getMaskedContext(workInProgress, unmaskedContext); } prepareToReadContext(workInProgress, renderLanes); - var newValue = readContext(context); + var value; { markComponentRenderStarted(workInProgress); } - var newChildren; - { - ReactCurrentOwner$2.current = workInProgress; + if ( + Component.prototype && + typeof Component.prototype.render === "function" + ) { + var componentName = getComponentNameFromType(Component) || "Unknown"; + + if (!didWarnAboutBadClass[componentName]) { + error( + "The <%s /> component appears to have a render method, but doesn't extend React.Component. " + + "This is likely to cause errors. Change %s to extend React.Component instead.", + componentName, + componentName + ); + + didWarnAboutBadClass[componentName] = true; + } + } + + if (workInProgress.mode & StrictLegacyMode) { + ReactStrictModeWarnings.recordLegacyContextWarning(workInProgress, null); + } + setIsRendering(true); - newChildren = render(newValue); + ReactCurrentOwner$2.current = workInProgress; + value = renderWithHooks( + null, + workInProgress, + Component, + props, + context, + renderLanes + ); setIsRendering(false); } @@ -16950,10845 +16041,11600 @@ function updateContextConsumer(current, workInProgress, renderLanes) { } // React DevTools reads this flag. workInProgress.flags |= PerformedWork; - reconcileChildren(current, workInProgress, newChildren, renderLanes); - return workInProgress.child; -} -function markWorkInProgressReceivedUpdate() { - didReceiveUpdate = true; -} + { + // Support for module components is deprecated and is removed behind a flag. + // Whether or not it would crash later, we want to show a good message in DEV first. + if ( + typeof value === "object" && + value !== null && + typeof value.render === "function" && + value.$$typeof === undefined + ) { + var _componentName = getComponentNameFromType(Component) || "Unknown"; -function resetSuspendedCurrentOnMountInLegacyMode(current, workInProgress) { - if ((workInProgress.mode & ConcurrentMode) === NoMode) { - if (current !== null) { - // A lazy component only mounts if it suspended inside a non- - // concurrent tree, in an inconsistent state. We want to treat it like - // a new mount, even though an empty version of it already committed. - // Disconnect the alternate pointers. - current.alternate = null; - workInProgress.alternate = null; // Since this is conceptually a new fiber, schedule a Placement effect + if (!didWarnAboutModulePatternComponent[_componentName]) { + error( + "The <%s /> component appears to be a function component that returns a class instance. " + + "Change %s to a class that extends React.Component instead. " + + "If you can't use a class try assigning the prototype on the function as a workaround. " + + "`%s.prototype = React.Component.prototype`. Don't use an arrow function since it " + + "cannot be called with `new` by React.", + _componentName, + _componentName, + _componentName + ); - workInProgress.flags |= Placement; + didWarnAboutModulePatternComponent[_componentName] = true; + } } } -} -function bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes) { - if (current !== null) { - // Reuse previous dependencies - workInProgress.dependencies = current.dependencies; - } + if ( + // Run these checks in production only if the flag is off. + // Eventually we'll delete this branch altogether. + typeof value === "object" && + value !== null && + typeof value.render === "function" && + value.$$typeof === undefined + ) { + { + var _componentName2 = getComponentNameFromType(Component) || "Unknown"; - { - // Don't update "base" render times for bailouts. - stopProfilerTimerIfRunning(); - } + if (!didWarnAboutModulePatternComponent[_componentName2]) { + error( + "The <%s /> component appears to be a function component that returns a class instance. " + + "Change %s to a class that extends React.Component instead. " + + "If you can't use a class try assigning the prototype on the function as a workaround. " + + "`%s.prototype = React.Component.prototype`. Don't use an arrow function since it " + + "cannot be called with `new` by React.", + _componentName2, + _componentName2, + _componentName2 + ); - markSkippedUpdateLanes(workInProgress.lanes); // Check if the children have any pending work. + didWarnAboutModulePatternComponent[_componentName2] = true; + } + } // Proceed under the assumption that this is a class instance + + workInProgress.tag = ClassComponent; // Throw out any hooks that were used. + + workInProgress.memoizedState = null; + workInProgress.updateQueue = null; // Push context providers early to prevent context stack mismatches. + // During mounting we don't know the child context yet as the instance doesn't exist. + // We will invalidate the child context in finishClassComponent() right after rendering. + + var hasContext = false; + + if (isContextProvider(Component)) { + hasContext = true; + pushContextProvider(workInProgress); + } else { + hasContext = false; + } + + workInProgress.memoizedState = + value.state !== null && value.state !== undefined ? value.state : null; + initializeUpdateQueue(workInProgress); + adoptClassInstance(workInProgress, value); + mountClassInstance(workInProgress, Component, props, renderLanes); + return finishClassComponent( + null, + workInProgress, + Component, + true, + hasContext, + renderLanes + ); + } else { + // Proceed under the assumption that this is a function component + workInProgress.tag = FunctionComponent; + + reconcileChildren(null, workInProgress, value, renderLanes); - if (!includesSomeLane(renderLanes, workInProgress.childLanes)) { - // The children don't have any work either. We can skip them. - // TODO: Once we add back resuming, we should check if the children are - // a work-in-progress set. If so, we need to transfer their effects. { - return null; + validateFunctionComponentInDev(workInProgress, Component); } - } // This fiber doesn't have work, but its subtree does. Clone the child - // fibers and continue. - cloneChildFibers(current, workInProgress); - return workInProgress.child; + return workInProgress.child; + } } -function remountFiber(current, oldWorkInProgress, newWorkInProgress) { +function validateFunctionComponentInDev(workInProgress, Component) { { - var returnFiber = oldWorkInProgress.return; + if (Component) { + if (Component.childContextTypes) { + error( + "%s(...): childContextTypes cannot be defined on a function component.", + Component.displayName || Component.name || "Component" + ); + } + } - if (returnFiber === null) { - // eslint-disable-next-line react-internal/prod-error-codes - throw new Error("Cannot swap the root fiber."); - } // Disconnect from the old current. - // It will get deleted. + if (workInProgress.ref !== null) { + var info = ""; + var ownerName = getCurrentFiberOwnerNameInDevOrNull(); - current.alternate = null; - oldWorkInProgress.alternate = null; // Connect to the new tree. + if (ownerName) { + info += "\n\nCheck the render method of `" + ownerName + "`."; + } + + var warningKey = ownerName || ""; + var debugSource = workInProgress._debugSource; - newWorkInProgress.index = oldWorkInProgress.index; - newWorkInProgress.sibling = oldWorkInProgress.sibling; - newWorkInProgress.return = oldWorkInProgress.return; - newWorkInProgress.ref = oldWorkInProgress.ref; // Replace the child/sibling pointers above it. + if (debugSource) { + warningKey = debugSource.fileName + ":" + debugSource.lineNumber; + } - if (oldWorkInProgress === returnFiber.child) { - returnFiber.child = newWorkInProgress; - } else { - var prevSibling = returnFiber.child; + if (!didWarnAboutFunctionRefs[warningKey]) { + didWarnAboutFunctionRefs[warningKey] = true; - if (prevSibling === null) { - // eslint-disable-next-line react-internal/prod-error-codes - throw new Error("Expected parent to have a child."); - } // $FlowFixMe[incompatible-use] found when upgrading Flow + error( + "Function components cannot be given refs. " + + "Attempts to access this ref will fail. " + + "Did you mean to use React.forwardRef()?%s", + info + ); + } + } - while (prevSibling.sibling !== oldWorkInProgress) { - // $FlowFixMe[incompatible-use] found when upgrading Flow - prevSibling = prevSibling.sibling; + if (Component.defaultProps !== undefined) { + var componentName = getComponentNameFromType(Component) || "Unknown"; - if (prevSibling === null) { - // eslint-disable-next-line react-internal/prod-error-codes - throw new Error("Expected to find the previous sibling."); - } - } // $FlowFixMe[incompatible-use] found when upgrading Flow + if (!didWarnAboutDefaultPropsOnFunctionComponent[componentName]) { + error( + "%s: Support for defaultProps will be removed from function components " + + "in a future major release. Use JavaScript default parameters instead.", + componentName + ); - prevSibling.sibling = newWorkInProgress; - } // Delete the old fiber and place the new one. - // Since the old fiber is disconnected, we have to schedule it manually. + didWarnAboutDefaultPropsOnFunctionComponent[componentName] = true; + } + } - var deletions = returnFiber.deletions; + if (typeof Component.getDerivedStateFromProps === "function") { + var _componentName3 = getComponentNameFromType(Component) || "Unknown"; - if (deletions === null) { - returnFiber.deletions = [current]; - returnFiber.flags |= ChildDeletion; - } else { - deletions.push(current); + if (!didWarnAboutGetDerivedStateOnFunctionComponent[_componentName3]) { + error( + "%s: Function components do not support getDerivedStateFromProps.", + _componentName3 + ); + + didWarnAboutGetDerivedStateOnFunctionComponent[_componentName3] = true; + } } - newWorkInProgress.flags |= Placement; // Restart work from the new fiber. + if ( + typeof Component.contextType === "object" && + Component.contextType !== null + ) { + var _componentName4 = getComponentNameFromType(Component) || "Unknown"; - return newWorkInProgress; + if (!didWarnAboutContextTypeOnFunctionComponent[_componentName4]) { + error( + "%s: Function components do not support contextType.", + _componentName4 + ); + + didWarnAboutContextTypeOnFunctionComponent[_componentName4] = true; + } + } } } -function checkScheduledUpdateOrContext(current, renderLanes) { - // Before performing an early bailout, we must check if there are pending - // updates or context. - var updateLanes = current.lanes; - - if (includesSomeLane(updateLanes, renderLanes)) { - return true; - } // No pending update, but because context is propagated lazily, we need +var SUSPENDED_MARKER = { + dehydrated: null, + treeContext: null, + retryLane: NoLane +}; - return false; +function mountSuspenseOffscreenState(renderLanes) { + return { + baseLanes: renderLanes, + cachePool: getSuspendedCache() + }; } -function attemptEarlyBailoutIfNoScheduledUpdate( - current, - workInProgress, - renderLanes -) { - // This fiber does not have any pending work. Bailout without entering - // the begin phase. There's still some bookkeeping we that needs to be done - // in this optimized path, mostly pushing stuff onto the stack. - switch (workInProgress.tag) { - case HostRoot: - pushHostRootContext(workInProgress); - break; - - case HostSingleton: - case HostComponent: - pushHostContext(workInProgress); - break; +function updateSuspenseOffscreenState(prevOffscreenState, renderLanes) { + var cachePool = null; - case ClassComponent: { - var Component = workInProgress.type; + return { + baseLanes: mergeLanes(prevOffscreenState.baseLanes, renderLanes), + cachePool: cachePool + }; +} // TODO: Probably should inline this back - if (isContextProvider(Component)) { - pushContextProvider(workInProgress); - } +function shouldRemainOnFallback(current, workInProgress, renderLanes) { + // If we're already showing a fallback, there are cases where we need to + // remain on that fallback regardless of whether the content has resolved. + // For example, SuspenseList coordinates when nested content appears. + // TODO: For compatibility with offscreen prerendering, this should also check + // whether the current fiber (if it exists) was visible in the previous tree. + if (current !== null) { + var suspenseState = current.memoizedState; - break; + if (suspenseState === null) { + // Currently showing content. Don't hide it, even if ForceSuspenseFallback + // is true. More precise name might be "ForceRemainSuspenseFallback". + // Note: This is a factoring smell. Can't remain on a fallback if there's + // no fallback to remain on. + return false; } + } // Not currently showing content. Consult the Suspense context. - case HostPortal: - pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); - break; + var suspenseContext = suspenseStackCursor.current; + return hasSuspenseListContext(suspenseContext, ForceSuspenseFallback); +} - case ContextProvider: { - var newValue = workInProgress.memoizedProps.value; - var context = workInProgress.type._context; - pushProvider(workInProgress, context, newValue); - break; - } +function getRemainingWorkInPrimaryTree(current, renderLanes) { + // TODO: Should not remove render lanes that were pinged during this render + return removeLanes(current.childLanes, renderLanes); +} - case Profiler: - { - // Profiler should only call onRender when one of its descendants actually rendered. - var hasChildWork = includesSomeLane( - renderLanes, - workInProgress.childLanes - ); +function updateSuspenseComponent(current, workInProgress, renderLanes) { + var nextProps = workInProgress.pendingProps; // This is used by DevTools to force a boundary to suspend. - if (hasChildWork) { - workInProgress.flags |= Update; - } + { + if (shouldSuspend(workInProgress)) { + workInProgress.flags |= DidCapture; + } + } - { - // Reset effect durations for the next eventual effect phase. - // These are reset during render to allow the DevTools commit hook a chance to read them, - var stateNode = workInProgress.stateNode; - stateNode.effectDuration = 0; - stateNode.passiveEffectDuration = 0; - } - } + var showFallback = false; + var didSuspend = (workInProgress.flags & DidCapture) !== NoFlags$1; - break; + if (didSuspend || shouldRemainOnFallback(current)) { + // Something in this boundary's subtree already suspended. Switch to + // rendering the fallback children. + showFallback = true; + workInProgress.flags &= ~DidCapture; + } // OK, the next part is confusing. We're about to reconcile the Suspense + // boundary's children. This involves some custom reconciliation logic. Two + // main reasons this is so complicated. + // + // First, Legacy Mode has different semantics for backwards compatibility. The + // primary tree will commit in an inconsistent state, so when we do the + // second pass to render the fallback, we do some exceedingly, uh, clever + // hacks to make that not totally break. Like transferring effects and + // deletions from hidden tree. In Concurrent Mode, it's much simpler, + // because we bailout on the primary tree completely and leave it in its old + // state, no effects. Same as what we do for Offscreen (except that + // Offscreen doesn't have the first render pass). + // + // Second is hydration. During hydration, the Suspense fiber has a slightly + // different layout, where the child points to a dehydrated fragment, which + // contains the DOM rendered by the server. + // + // Third, even if you set all that aside, Suspense is like error boundaries in + // that we first we try to render one tree, and if that fails, we render again + // and switch to a different tree. Like a try/catch block. So we have to track + // which branch we're currently rendering. Ideally we would model this using + // a stack. - case SuspenseComponent: { - var state = workInProgress.memoizedState; + if (current === null) { + var nextPrimaryChildren = nextProps.children; + var nextFallbackChildren = nextProps.fallback; - if (state !== null) { - if (state.dehydrated !== null) { - // We're not going to render the children, so this is just to maintain - // push/pop symmetry - pushPrimaryTreeSuspenseHandler(workInProgress); // We know that this component will suspend again because if it has - // been unsuspended it has committed as a resolved Suspense component. - // If it needs to be retried, it should have work scheduled on it. + if (showFallback) { + pushFallbackTreeSuspenseHandler(workInProgress); + var fallbackFragment = mountSuspenseFallbackChildren( + workInProgress, + nextPrimaryChildren, + nextFallbackChildren, + renderLanes + ); + var primaryChildFragment = workInProgress.child; + primaryChildFragment.memoizedState = + mountSuspenseOffscreenState(renderLanes); + workInProgress.memoizedState = SUSPENDED_MARKER; - workInProgress.flags |= DidCapture; // We should never render the children of a dehydrated boundary until we - // upgrade it. We return null instead of bailoutOnAlreadyFinishedWork. + return fallbackFragment; + } else if (typeof nextProps.unstable_expectedLoadTime === "number") { + // This is a CPU-bound tree. Skip this tree and show a placeholder to + // unblock the surrounding content. Then immediately retry after the + // initial commit. + pushFallbackTreeSuspenseHandler(workInProgress); - return null; - } // If this boundary is currently timed out, we need to decide - // whether to retry the primary children, or to skip over it and - // go straight to the fallback. Check the priority of the primary - // child fragment. + var _fallbackFragment = mountSuspenseFallbackChildren( + workInProgress, + nextPrimaryChildren, + nextFallbackChildren, + renderLanes + ); - var primaryChildFragment = workInProgress.child; - var primaryChildLanes = primaryChildFragment.childLanes; + var _primaryChildFragment = workInProgress.child; + _primaryChildFragment.memoizedState = + mountSuspenseOffscreenState(renderLanes); + workInProgress.memoizedState = SUSPENDED_MARKER; // TODO: Transition Tracing is not yet implemented for CPU Suspense. + // Since nothing actually suspended, there will nothing to ping this to + // get it started back up to attempt the next item. While in terms of + // priority this work has the same priority as this current render, it's + // not part of the same transition once the transition has committed. If + // it's sync, we still want to yield so that it can be painted. + // Conceptually, this is really the same as pinging. We can use any + // RetryLane even if it's the one currently rendering since we're leaving + // it behind on this node. - if (includesSomeLane(renderLanes, primaryChildLanes)) { - // The primary children have pending work. Use the normal path - // to attempt to render the primary children again. - return updateSuspenseComponent(current, workInProgress, renderLanes); - } else { - // The primary child fragment does not have pending work marked - // on it - pushPrimaryTreeSuspenseHandler(workInProgress); // The primary children do not have pending work with sufficient - // priority. Bailout. + workInProgress.lanes = SomeRetryLane; + return _fallbackFragment; + } else { + pushPrimaryTreeSuspenseHandler(workInProgress); + return mountSuspensePrimaryChildren(workInProgress, nextPrimaryChildren); + } + } else { + // This is an update. + // Special path for hydration + var prevState = current.memoizedState; - var child = bailoutOnAlreadyFinishedWork( - current, - workInProgress, - renderLanes - ); + if (prevState !== null) { + var _dehydrated = prevState.dehydrated; - if (child !== null) { - // The fallback children have pending work. Skip over the - // primary children and work on the fallback. - return child.sibling; - } else { - // Note: We can return `null` here because we already checked - // whether there were nested context consumers, via the call to - // `bailoutOnAlreadyFinishedWork` above. - return null; - } - } - } else { - pushPrimaryTreeSuspenseHandler(workInProgress); + if (_dehydrated !== null) { + return updateDehydratedSuspenseComponent( + current, + workInProgress, + didSuspend, + nextProps, + _dehydrated, + prevState, + renderLanes + ); } - - break; } - case SuspenseListComponent: { - var didSuspendBefore = (current.flags & DidCapture) !== NoFlags$1; + if (showFallback) { + pushFallbackTreeSuspenseHandler(workInProgress); + var _nextFallbackChildren = nextProps.fallback; + var _nextPrimaryChildren = nextProps.children; + var fallbackChildFragment = updateSuspenseFallbackChildren( + current, + workInProgress, + _nextPrimaryChildren, + _nextFallbackChildren, + renderLanes + ); + var _primaryChildFragment2 = workInProgress.child; + var prevOffscreenState = current.child.memoizedState; + _primaryChildFragment2.memoizedState = + prevOffscreenState === null + ? mountSuspenseOffscreenState(renderLanes) + : updateSuspenseOffscreenState(prevOffscreenState, renderLanes); - var _hasChildWork = includesSomeLane( - renderLanes, - workInProgress.childLanes + _primaryChildFragment2.childLanes = getRemainingWorkInPrimaryTree( + current, + renderLanes ); + workInProgress.memoizedState = SUSPENDED_MARKER; + return fallbackChildFragment; + } else { + pushPrimaryTreeSuspenseHandler(workInProgress); + var _nextPrimaryChildren2 = nextProps.children; - if (didSuspendBefore) { - if (_hasChildWork) { - // If something was in fallback state last time, and we have all the - // same children then we're still in progressive loading state. - // Something might get unblocked by state updates or retries in the - // tree which will affect the tail. So we need to use the normal - // path to compute the correct tail. - return updateSuspenseListComponent( - current, - workInProgress, - renderLanes - ); - } // If none of the children had any work, that means that none of - // them got retried so they'll still be blocked in the same way - // as before. We can fast bail out. + var _primaryChildFragment3 = updateSuspensePrimaryChildren( + current, + workInProgress, + _nextPrimaryChildren2, + renderLanes + ); - workInProgress.flags |= DidCapture; - } // If nothing suspended before and we're rendering the same children, - // then the tail doesn't matter. Anything new that suspends will work - // in the "together" mode, so we can continue from the state we had. + workInProgress.memoizedState = null; + return _primaryChildFragment3; + } + } +} - var renderState = workInProgress.memoizedState; +function mountSuspensePrimaryChildren( + workInProgress, + primaryChildren, + renderLanes +) { + var mode = workInProgress.mode; + var primaryChildProps = { + mode: "visible", + children: primaryChildren + }; + var primaryChildFragment = mountWorkInProgressOffscreenFiber( + primaryChildProps, + mode + ); + primaryChildFragment.return = workInProgress; + workInProgress.child = primaryChildFragment; + return primaryChildFragment; +} - if (renderState !== null) { - // Reset to the "together" mode in case we've started a different - // update in the past but didn't complete it. - renderState.rendering = null; - renderState.tail = null; - renderState.lastEffect = null; - } +function mountSuspenseFallbackChildren( + workInProgress, + primaryChildren, + fallbackChildren, + renderLanes +) { + var mode = workInProgress.mode; + var progressedPrimaryFragment = workInProgress.child; + var primaryChildProps = { + mode: "hidden", + children: primaryChildren + }; + var primaryChildFragment; + var fallbackChildFragment; - pushSuspenseListContext(workInProgress, suspenseStackCursor.current); + if ( + (mode & ConcurrentMode) === NoMode && + progressedPrimaryFragment !== null + ) { + // In legacy mode, we commit the primary tree as if it successfully + // completed, even though it's in an inconsistent state. + primaryChildFragment = progressedPrimaryFragment; + primaryChildFragment.childLanes = NoLanes; + primaryChildFragment.pendingProps = primaryChildProps; - if (_hasChildWork) { - break; - } else { - // If none of the children had any work, that means that none of - // them got retried so they'll still be blocked in the same way - // as before. We can fast bail out. - return null; - } + if (workInProgress.mode & ProfileMode) { + // Reset the durations from the first pass so they aren't included in the + // final amounts. This seems counterintuitive, since we're intentionally + // not measuring part of the render phase, but this makes it match what we + // do in Concurrent Mode. + primaryChildFragment.actualDuration = 0; + primaryChildFragment.actualStartTime = -1; + primaryChildFragment.selfBaseDuration = 0; + primaryChildFragment.treeBaseDuration = 0; } - case OffscreenComponent: - case LegacyHiddenComponent: { - // Need to check if the tree still needs to be deferred. This is - // almost identical to the logic used in the normal update path, - // so we'll just enter that. The only difference is we'll bail out - // at the next level instead of this one, because the child props - // have not changed. Which is fine. - // TODO: Probably should refactor `beginWork` to split the bailout - // path from the normal path. I'm tempted to do a labeled break here - // but I won't :) - workInProgress.lanes = NoLanes; - return updateOffscreenComponent(current, workInProgress, renderLanes); + fallbackChildFragment = createFiberFromFragment( + fallbackChildren, + mode, + renderLanes, + null + ); + } else { + primaryChildFragment = mountWorkInProgressOffscreenFiber( + primaryChildProps, + mode + ); + fallbackChildFragment = createFiberFromFragment( + fallbackChildren, + mode, + renderLanes, + null + ); + } + + primaryChildFragment.return = workInProgress; + fallbackChildFragment.return = workInProgress; + primaryChildFragment.sibling = fallbackChildFragment; + workInProgress.child = primaryChildFragment; + return fallbackChildFragment; +} + +function mountWorkInProgressOffscreenFiber(offscreenProps, mode, renderLanes) { + // The props argument to `createFiberFromOffscreen` is `any` typed, so we use + // this wrapper function to constrain it. + return createFiberFromOffscreen(offscreenProps, mode, NoLanes, null); +} + +function updateWorkInProgressOffscreenFiber(current, offscreenProps) { + // The props argument to `createWorkInProgress` is `any` typed, so we use this + // wrapper function to constrain it. + return createWorkInProgress(current, offscreenProps); +} + +function updateSuspensePrimaryChildren( + current, + workInProgress, + primaryChildren, + renderLanes +) { + var currentPrimaryChildFragment = current.child; + var currentFallbackChildFragment = currentPrimaryChildFragment.sibling; + var primaryChildFragment = updateWorkInProgressOffscreenFiber( + currentPrimaryChildFragment, + { + mode: "visible", + children: primaryChildren } + ); + + if ((workInProgress.mode & ConcurrentMode) === NoMode) { + primaryChildFragment.lanes = renderLanes; } - return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); -} + primaryChildFragment.return = workInProgress; + primaryChildFragment.sibling = null; -function beginWork$1(current, workInProgress, renderLanes) { - { - if (workInProgress._debugNeedsRemount && current !== null) { - // This will restart the begin phase with a new fiber. - return remountFiber( - current, - workInProgress, - createFiberFromTypeAndProps( - workInProgress.type, - workInProgress.key, - workInProgress.pendingProps, - workInProgress._debugOwner || null, - workInProgress.mode, - workInProgress.lanes - ) - ); + if (currentFallbackChildFragment !== null) { + // Delete the fallback child fragment + var deletions = workInProgress.deletions; + + if (deletions === null) { + workInProgress.deletions = [currentFallbackChildFragment]; + workInProgress.flags |= ChildDeletion; + } else { + deletions.push(currentFallbackChildFragment); } } - if (current !== null) { - var oldProps = current.memoizedProps; - var newProps = workInProgress.pendingProps; + workInProgress.child = primaryChildFragment; + return primaryChildFragment; +} - if ( - oldProps !== newProps || - hasContextChanged() || // Force a re-render if the implementation changed due to hot reload: - workInProgress.type !== current.type - ) { - // If props or context changed, mark the fiber as having performed work. - // This may be unset if the props are determined to be equal later (memo). - didReceiveUpdate = true; - } else { - // Neither props nor legacy context changes. Check if there's a pending - // update or context change. - var hasScheduledUpdateOrContext = checkScheduledUpdateOrContext( - current, - renderLanes - ); +function updateSuspenseFallbackChildren( + current, + workInProgress, + primaryChildren, + fallbackChildren, + renderLanes +) { + var mode = workInProgress.mode; + var currentPrimaryChildFragment = current.child; + var currentFallbackChildFragment = currentPrimaryChildFragment.sibling; + var primaryChildProps = { + mode: "hidden", + children: primaryChildren + }; + var primaryChildFragment; - if ( - !hasScheduledUpdateOrContext && // If this is the second pass of an error or suspense boundary, there - // may not be work scheduled on `current`, so we check for this flag. - (workInProgress.flags & DidCapture) === NoFlags$1 - ) { - // No pending updates or context. Bail out now. - didReceiveUpdate = false; - return attemptEarlyBailoutIfNoScheduledUpdate( - current, - workInProgress, - renderLanes - ); - } + if ( + // In legacy mode, we commit the primary tree as if it successfully + // completed, even though it's in an inconsistent state. + (mode & ConcurrentMode) === NoMode && // Make sure we're on the second pass, i.e. the primary child fragment was + // already cloned. In legacy mode, the only case where this isn't true is + // when DevTools forces us to display a fallback; we skip the first render + // pass entirely and go straight to rendering the fallback. (In Concurrent + // Mode, SuspenseList can also trigger this scenario, but this is a legacy- + // only codepath.) + workInProgress.child !== currentPrimaryChildFragment + ) { + var progressedPrimaryFragment = workInProgress.child; + primaryChildFragment = progressedPrimaryFragment; + primaryChildFragment.childLanes = NoLanes; + primaryChildFragment.pendingProps = primaryChildProps; - if ((current.flags & ForceUpdateForLegacySuspense) !== NoFlags$1) { - // This is a special case that only exists for legacy mode. - // See https://github.com/facebook/react/pull/19216. - didReceiveUpdate = true; - } else { - // An update was scheduled on this fiber, but there are no new props - // nor legacy context. Set this to false. If an update queue or context - // consumer produces a changed value, it will set this to true. Otherwise, - // the component will assume the children have not changed and bail out. - didReceiveUpdate = false; - } - } + if (workInProgress.mode & ProfileMode) { + // Reset the durations from the first pass so they aren't included in the + // final amounts. This seems counterintuitive, since we're intentionally + // not measuring part of the render phase, but this makes it match what we + // do in Concurrent Mode. + primaryChildFragment.actualDuration = 0; + primaryChildFragment.actualStartTime = -1; + primaryChildFragment.selfBaseDuration = + currentPrimaryChildFragment.selfBaseDuration; + primaryChildFragment.treeBaseDuration = + currentPrimaryChildFragment.treeBaseDuration; + } // The fallback fiber was added as a deletion during the first pass. + // However, since we're going to remain on the fallback, we no longer want + // to delete it. + + workInProgress.deletions = null; } else { - didReceiveUpdate = false; - } // Before entering the begin phase, clear pending update priority. - // TODO: This assumes that we're about to evaluate the component and process - // the update queue. However, there's an exception: SimpleMemoComponent - // sometimes bails out later in the begin phase. This indicates that we should - // move this assignment out of the common path and into each branch. + primaryChildFragment = updateWorkInProgressOffscreenFiber( + currentPrimaryChildFragment, + primaryChildProps + ); // Since we're reusing a current tree, we need to reuse the flags, too. + // (We don't do this in legacy mode, because in legacy mode we don't re-use + // the current tree; see previous branch.) - workInProgress.lanes = NoLanes; + primaryChildFragment.subtreeFlags = + currentPrimaryChildFragment.subtreeFlags & StaticMask; + } - switch (workInProgress.tag) { - case IndeterminateComponent: { - return mountIndeterminateComponent( - current, - workInProgress, - workInProgress.type, - renderLanes - ); - } + var fallbackChildFragment; - case LazyComponent: { - var elementType = workInProgress.elementType; - return mountLazyComponent( - current, - workInProgress, - elementType, - renderLanes - ); - } + if (currentFallbackChildFragment !== null) { + fallbackChildFragment = createWorkInProgress( + currentFallbackChildFragment, + fallbackChildren + ); + } else { + fallbackChildFragment = createFiberFromFragment( + fallbackChildren, + mode, + renderLanes, + null + ); // Needs a placement effect because the parent (the Suspense boundary) already + // mounted but this is a new fiber. - case FunctionComponent: { - var Component = workInProgress.type; - var unresolvedProps = workInProgress.pendingProps; - var resolvedProps = - workInProgress.elementType === Component - ? unresolvedProps - : resolveDefaultProps(Component, unresolvedProps); - return updateFunctionComponent( - current, - workInProgress, - Component, - resolvedProps, - renderLanes - ); - } + fallbackChildFragment.flags |= Placement; + } + + fallbackChildFragment.return = workInProgress; + primaryChildFragment.return = workInProgress; + primaryChildFragment.sibling = fallbackChildFragment; + workInProgress.child = primaryChildFragment; + return fallbackChildFragment; +} + +function retrySuspenseComponentWithoutHydrating( + current, + workInProgress, + renderLanes, + recoverableError +) { + // Falling back to client rendering. Because this has performance + // implications, it's considered a recoverable error, even though the user + // likely won't observe anything wrong with the UI. + // + // The error is passed in as an argument to enforce that every caller provide + // a custom message, or explicitly opt out (currently the only path that opts + // out is legacy mode; every concurrent path provides an error). + if (recoverableError !== null) { + queueHydrationError(recoverableError); + } // This will add the old fiber to the deletion list + + reconcileChildFibers(workInProgress, current.child, null, renderLanes); // We're now not suspended nor dehydrated. + + var nextProps = workInProgress.pendingProps; + var primaryChildren = nextProps.children; + var primaryChildFragment = mountSuspensePrimaryChildren( + workInProgress, + primaryChildren + ); // Needs a placement effect because the parent (the Suspense boundary) already + // mounted but this is a new fiber. + + primaryChildFragment.flags |= Placement; + workInProgress.memoizedState = null; + return primaryChildFragment; +} + +function mountSuspenseFallbackAfterRetryWithoutHydrating( + current, + workInProgress, + primaryChildren, + fallbackChildren, + renderLanes +) { + var fiberMode = workInProgress.mode; + var primaryChildProps = { + mode: "visible", + children: primaryChildren + }; + var primaryChildFragment = mountWorkInProgressOffscreenFiber( + primaryChildProps, + fiberMode + ); + var fallbackChildFragment = createFiberFromFragment( + fallbackChildren, + fiberMode, + renderLanes, + null + ); // Needs a placement effect because the parent (the Suspense + // boundary) already mounted but this is a new fiber. + + fallbackChildFragment.flags |= Placement; + primaryChildFragment.return = workInProgress; + fallbackChildFragment.return = workInProgress; + primaryChildFragment.sibling = fallbackChildFragment; + workInProgress.child = primaryChildFragment; - case ClassComponent: { - var _Component = workInProgress.type; - var _unresolvedProps = workInProgress.pendingProps; + if ((workInProgress.mode & ConcurrentMode) !== NoMode) { + // We will have dropped the effect list which contains the + // deletion. We need to reconcile to delete the current child. + reconcileChildFibers(workInProgress, current.child, null, renderLanes); + } - var _resolvedProps = - workInProgress.elementType === _Component - ? _unresolvedProps - : resolveDefaultProps(_Component, _unresolvedProps); + return fallbackChildFragment; +} - return updateClassComponent( +function updateDehydratedSuspenseComponent( + current, + workInProgress, + didSuspend, + nextProps, + suspenseInstance, + suspenseState, + renderLanes +) { + if (!didSuspend) { + // This is the first render pass. Attempt to hydrate. + pushPrimaryTreeSuspenseHandler(workInProgress); // We should never be hydrating at this point because it is the first pass, + + if ((workInProgress.mode & ConcurrentMode) === NoMode) { + return retrySuspenseComponentWithoutHydrating( current, workInProgress, - _Component, - _resolvedProps, - renderLanes + renderLanes, + null ); } - case HostRoot: - return updateHostRoot(current, workInProgress, renderLanes); - - case HostHoistable: - - // eslint-disable-next-line no-fallthrough - - case HostSingleton: - - // eslint-disable-next-line no-fallthrough - - case HostComponent: - return updateHostComponent$1(current, workInProgress, renderLanes); - - case HostText: - return updateHostText$1(); + if (isSuspenseInstanceFallback()) { + // This boundary is in a permanent fallback state. In this case, we'll never + // get an update and we'll never be able to hydrate the final content. Let's just try the + // client side render instead. + var digest, message, stack; - case SuspenseComponent: - return updateSuspenseComponent(current, workInProgress, renderLanes); + { + var _getSuspenseInstanceF = getSuspenseInstanceFallbackErrorDetails(); - case HostPortal: - return updatePortalComponent(current, workInProgress, renderLanes); + digest = _getSuspenseInstanceF.digest; + message = _getSuspenseInstanceF.message; + stack = _getSuspenseInstanceF.stack; + } - case ForwardRef: { - var type = workInProgress.type; - var _unresolvedProps2 = workInProgress.pendingProps; + var error; - var _resolvedProps2 = - workInProgress.elementType === type - ? _unresolvedProps2 - : resolveDefaultProps(type, _unresolvedProps2); + if (message) { + // eslint-disable-next-line react-internal/prod-error-codes + error = new Error(message); + } else { + error = new Error( + "The server could not finish this Suspense boundary, likely " + + "due to an error during server rendering. Switched to " + + "client rendering." + ); + } - return updateForwardRef( + error.digest = digest; + var capturedValue = createCapturedValue(error, digest, stack); + return retrySuspenseComponentWithoutHydrating( current, workInProgress, - type, - _resolvedProps2, - renderLanes + renderLanes, + capturedValue ); } + // any context has changed, we need to treat is as if the input might have changed. - case Fragment: - return updateFragment(current, workInProgress, renderLanes); - - case Mode: - return updateMode(current, workInProgress, renderLanes); - - case Profiler: - return updateProfiler(current, workInProgress, renderLanes); - - case ContextProvider: - return updateContextProvider(current, workInProgress, renderLanes); + var hasContextChanged = includesSomeLane(renderLanes, current.childLanes); - case ContextConsumer: - return updateContextConsumer(current, workInProgress, renderLanes); + if (didReceiveUpdate || hasContextChanged) { + // This boundary has changed since the first render. This means that we are now unable to + // hydrate it. We might still be able to hydrate it using a higher priority lane. + var root = getWorkInProgressRoot(); - case MemoComponent: { - var _type2 = workInProgress.type; - var _unresolvedProps3 = workInProgress.pendingProps; // Resolve outer props first, then resolve inner props. + if (root !== null) { + var attemptHydrationAtLane = getBumpedLaneForHydration( + root, + renderLanes + ); - var _resolvedProps3 = resolveDefaultProps(_type2, _unresolvedProps3); + if ( + attemptHydrationAtLane !== NoLane && + attemptHydrationAtLane !== suspenseState.retryLane + ) { + // Intentionally mutating since this render will get interrupted. This + // is one of the very rare times where we mutate the current tree + // during the render phase. + suspenseState.retryLane = attemptHydrationAtLane; // TODO: Ideally this would inherit the event time of the current render - { - if (workInProgress.type !== workInProgress.elementType) { - var outerPropTypes = _type2.propTypes; + var eventTime = NoTimestamp; + enqueueConcurrentRenderForLane(current, attemptHydrationAtLane); + scheduleUpdateOnFiber( + root, + current, + attemptHydrationAtLane, + eventTime + ); // Throw a special object that signals to the work loop that it should + // interrupt the current render. + // + // Because we're inside a React-only execution stack, we don't + // strictly need to throw here — we could instead modify some internal + // work loop state. But using an exception means we don't need to + // check for this case on every iteration of the work loop. So doing + // it this way moves the check out of the fast path. - if (outerPropTypes) { - checkPropTypes( - outerPropTypes, - _resolvedProps3, // Resolved for outer only - "prop", - getComponentNameFromType(_type2) - ); - } + throw SelectiveHydrationException; } - } - - _resolvedProps3 = resolveDefaultProps(_type2.type, _resolvedProps3); - return updateMemoComponent( - current, - workInProgress, - _type2, - _resolvedProps3, - renderLanes - ); - } + } // If we did not selectively hydrate, we'll continue rendering without + // hydrating. Mark this tree as suspended to prevent it from committing + // outside a transition. + // + // This path should only happen if the hydration lane already suspended. + // Currently, it also happens during sync updates because there is no + // hydration lane for sync updates. + // TODO: We should ideally have a sync hydration lane that we can apply to do + // a pass where we hydrate this subtree in place using the previous Context and then + // reapply the update afterwards. - case SimpleMemoComponent: { - return updateSimpleMemoComponent( + renderDidSuspendDelayIfPossible(); + return retrySuspenseComponentWithoutHydrating( current, workInProgress, - workInProgress.type, - workInProgress.pendingProps, - renderLanes + renderLanes, + null ); - } - - case IncompleteClassComponent: { - var _Component2 = workInProgress.type; - var _unresolvedProps4 = workInProgress.pendingProps; + } else if (isSuspenseInstancePending()) { + // This component is still pending more data from the server, so we can't hydrate its + // content. We treat it as if this component suspended itself. It might seem as if + // we could just try to render it client-side instead. However, this will perform a + // lot of unnecessary work and is unlikely to complete since it often will suspend + // on missing data anyway. Additionally, the server might be able to render more + // than we can on the client yet. In that case we'd end up with more fallback states + // on the client than if we just leave it alone. If the server times out or errors + // these should update this boundary to the permanent Fallback state instead. + // Mark it as having captured (i.e. suspended). + workInProgress.flags |= DidCapture; // Leave the child in place. I.e. the dehydrated fragment. - var _resolvedProps4 = - workInProgress.elementType === _Component2 - ? _unresolvedProps4 - : resolveDefaultProps(_Component2, _unresolvedProps4); + workInProgress.child = current.child; // Register a callback to retry this boundary once the server has sent the result. - return mountIncompleteClassComponent( - current, + retryDehydratedSuspenseBoundary.bind(null, current); + registerSuspenseInstanceRetry(); + return null; + } else { + var primaryChildren = nextProps.children; + var primaryChildFragment = mountSuspensePrimaryChildren( workInProgress, - _Component2, - _resolvedProps4, - renderLanes - ); - } + primaryChildren + ); // Mark the children as hydrating. This is a fast path to know whether this + // tree is part of a hydrating tree. This is used to determine if a child + // node has fully mounted yet, and for scheduling event replaying. + // Conceptually this is similar to Placement in that a new subtree is + // inserted into the React tree here. It just happens to not need DOM + // mutations because it already exists. - case SuspenseListComponent: { - return updateSuspenseListComponent(current, workInProgress, renderLanes); + primaryChildFragment.flags |= Hydrating; + return primaryChildFragment; } + } else { + // This is the second render pass. We already attempted to hydrated, but + // something either suspended or errored. + if (workInProgress.flags & ForceClientRender) { + // Something errored during hydration. Try again without hydrating. + pushPrimaryTreeSuspenseHandler(workInProgress); + workInProgress.flags &= ~ForceClientRender; - case ScopeComponent: { - break; - } + var _capturedValue = createCapturedValue( + new Error( + "There was an error while hydrating this Suspense boundary. " + + "Switched to client rendering." + ) + ); - case OffscreenComponent: { - return updateOffscreenComponent(current, workInProgress, renderLanes); - } + return retrySuspenseComponentWithoutHydrating( + current, + workInProgress, + renderLanes, + _capturedValue + ); + } else if (workInProgress.memoizedState !== null) { + // Something suspended and we should still be in dehydrated mode. + // Leave the existing child in place. + // Push to avoid a mismatch + pushFallbackTreeSuspenseHandler(workInProgress); + workInProgress.child = current.child; // The dehydrated completion pass expects this flag to be there + // but the normal suspense pass doesn't. - case LegacyHiddenComponent: { - { - return updateLegacyHiddenComponent( + workInProgress.flags |= DidCapture; + return null; + } else { + // Suspended but we should no longer be in dehydrated mode. + // Therefore we now have to render the fallback. + pushFallbackTreeSuspenseHandler(workInProgress); + var nextPrimaryChildren = nextProps.children; + var nextFallbackChildren = nextProps.fallback; + var fallbackChildFragment = + mountSuspenseFallbackAfterRetryWithoutHydrating( current, workInProgress, + nextPrimaryChildren, + nextFallbackChildren, renderLanes ); - } + var _primaryChildFragment4 = workInProgress.child; + _primaryChildFragment4.memoizedState = + mountSuspenseOffscreenState(renderLanes); + workInProgress.memoizedState = SUSPENDED_MARKER; + return fallbackChildFragment; } } - - throw new Error( - "Unknown unit of work tag (" + - workInProgress.tag + - "). This error is likely caused by a bug in " + - "React. Please file an issue." - ); } -var valueCursor = createCursor(null); +function scheduleSuspenseWorkOnFiber(fiber, renderLanes, propagationRoot) { + fiber.lanes = mergeLanes(fiber.lanes, renderLanes); + var alternate = fiber.alternate; -var renderer2CursorDEV; + if (alternate !== null) { + alternate.lanes = mergeLanes(alternate.lanes, renderLanes); + } -{ - renderer2CursorDEV = createCursor(null); + scheduleContextWorkOnParentPath(fiber.return, renderLanes, propagationRoot); } -var rendererSigil; +function propagateSuspenseContextChange( + workInProgress, + firstChild, + renderLanes +) { + // Mark any Suspense boundaries with fallbacks as having work to do. + // If they were previously forced into fallbacks, they may now be able + // to unblock. + var node = firstChild; -{ - // Use this to detect multiple renderers using the same context - rendererSigil = {}; -} + while (node !== null) { + if (node.tag === SuspenseComponent) { + var state = node.memoizedState; -var currentlyRenderingFiber = null; -var lastContextDependency = null; -var lastFullyObservedContext = null; -var isDisallowedContextReadInDEV = false; -function resetContextDependencies() { - // This is called right before React yields execution, to ensure `readContext` - // cannot be called outside the render phase. - currentlyRenderingFiber = null; - lastContextDependency = null; - lastFullyObservedContext = null; + if (state !== null) { + scheduleSuspenseWorkOnFiber(node, renderLanes, workInProgress); + } + } else if (node.tag === SuspenseListComponent) { + // If the tail is hidden there might not be an Suspense boundaries + // to schedule work on. In this case we have to schedule it on the + // list itself. + // We don't have to traverse to the children of the list since + // the list will propagate the change when it rerenders. + scheduleSuspenseWorkOnFiber(node, renderLanes, workInProgress); + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } - { - isDisallowedContextReadInDEV = false; - } -} -function enterDisallowedContextReadInDEV() { - { - isDisallowedContextReadInDEV = true; - } -} -function exitDisallowedContextReadInDEV() { - { - isDisallowedContextReadInDEV = false; + if (node === workInProgress) { + return; + } // $FlowFixMe[incompatible-use] found when upgrading Flow + + while (node.sibling === null) { + // $FlowFixMe[incompatible-use] found when upgrading Flow + if (node.return === null || node.return === workInProgress) { + return; + } + + node = node.return; + } // $FlowFixMe[incompatible-use] found when upgrading Flow + + node.sibling.return = node.return; + node = node.sibling; } } -function pushProvider(providerFiber, context, nextValue) { - { - push(valueCursor, context._currentValue2, providerFiber); - context._currentValue2 = nextValue; - { - push(renderer2CursorDEV, context._currentRenderer2, providerFiber); +function findLastContentRow(firstChild) { + // This is going to find the last row among these children that is already + // showing content on the screen, as opposed to being in fallback state or + // new. If a row has multiple Suspense boundaries, any of them being in the + // fallback state, counts as the whole row being in a fallback state. + // Note that the "rows" will be workInProgress, but any nested children + // will still be current since we haven't rendered them yet. The mounted + // order may not be the same as the new order. We use the new order. + var row = firstChild; + var lastContentRow = null; - if ( - context._currentRenderer2 !== undefined && - context._currentRenderer2 !== null && - context._currentRenderer2 !== rendererSigil - ) { - error( - "Detected multiple renderers concurrently rendering the " + - "same context provider. This is currently unsupported." - ); - } + while (row !== null) { + var currentRow = row.alternate; // New rows can't be content rows. - context._currentRenderer2 = rendererSigil; + if (currentRow !== null && findFirstSuspended(currentRow) === null) { + lastContentRow = row; } + + row = row.sibling; } + + return lastContentRow; } -function popProvider(context, providerFiber) { - var currentValue = valueCursor.current; +function validateRevealOrder(revealOrder) { { - if (currentValue === REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED) { - context._currentValue2 = context._defaultValue; - } else { - context._currentValue2 = currentValue; - } + if ( + revealOrder !== undefined && + revealOrder !== "forwards" && + revealOrder !== "backwards" && + revealOrder !== "together" && + !didWarnAboutRevealOrder[revealOrder] + ) { + didWarnAboutRevealOrder[revealOrder] = true; - { - var currentRenderer2 = renderer2CursorDEV.current; - pop(renderer2CursorDEV, providerFiber); - context._currentRenderer2 = currentRenderer2; + if (typeof revealOrder === "string") { + switch (revealOrder.toLowerCase()) { + case "together": + case "forwards": + case "backwards": { + error( + '"%s" is not a valid value for revealOrder on . ' + + 'Use lowercase "%s" instead.', + revealOrder, + revealOrder.toLowerCase() + ); + + break; + } + + case "forward": + case "backward": { + error( + '"%s" is not a valid value for revealOrder on . ' + + 'React uses the -s suffix in the spelling. Use "%ss" instead.', + revealOrder, + revealOrder.toLowerCase() + ); + + break; + } + + default: + error( + '"%s" is not a supported revealOrder on . ' + + 'Did you mean "together", "forwards" or "backwards"?', + revealOrder + ); + + break; + } + } else { + error( + "%s is not a supported value for revealOrder on . " + + 'Did you mean "together", "forwards" or "backwards"?', + revealOrder + ); + } } } - - pop(valueCursor, providerFiber); } -function scheduleContextWorkOnParentPath(parent, renderLanes, propagationRoot) { - // Update the child lanes of all the ancestors, including the alternates. - var node = parent; - while (node !== null) { - var alternate = node.alternate; +function validateTailOptions(tailMode, revealOrder) { + { + if (tailMode !== undefined && !didWarnAboutTailOptions[tailMode]) { + if (tailMode !== "collapsed" && tailMode !== "hidden") { + didWarnAboutTailOptions[tailMode] = true; - if (!isSubsetOfLanes(node.childLanes, renderLanes)) { - node.childLanes = mergeLanes(node.childLanes, renderLanes); + error( + '"%s" is not a supported value for tail on . ' + + 'Did you mean "collapsed" or "hidden"?', + tailMode + ); + } else if (revealOrder !== "forwards" && revealOrder !== "backwards") { + didWarnAboutTailOptions[tailMode] = true; - if (alternate !== null) { - alternate.childLanes = mergeLanes(alternate.childLanes, renderLanes); + error( + ' is only valid if revealOrder is ' + + '"forwards" or "backwards". ' + + 'Did you mean to specify revealOrder="forwards"?', + tailMode + ); } - } else if ( - alternate !== null && - !isSubsetOfLanes(alternate.childLanes, renderLanes) - ) { - alternate.childLanes = mergeLanes(alternate.childLanes, renderLanes); - } else; - - if (node === propagationRoot) { - break; } - - node = node.return; } +} +function validateSuspenseListNestedChild(childSlot, index) { { - if (node !== propagationRoot) { + var isAnArray = isArray(childSlot); + var isIterable = + !isAnArray && typeof getIteratorFn(childSlot) === "function"; + + if (isAnArray || isIterable) { + var type = isAnArray ? "array" : "iterable"; + error( - "Expected to find the propagation root when scheduling context work. " + - "This error is likely caused by a bug in React. Please file an issue." + "A nested %s was passed to row #%s in . Wrap it in " + + "an additional SuspenseList to configure its revealOrder: " + + " ... " + + "{%s} ... " + + "", + type, + index, + type ); + + return false; } } + + return true; } -function propagateContextChange(workInProgress, context, renderLanes) { + +function validateSuspenseListChildren(children, revealOrder) { { - propagateContextChange_eager(workInProgress, context, renderLanes); + if ( + (revealOrder === "forwards" || revealOrder === "backwards") && + children !== undefined && + children !== null && + children !== false + ) { + if (isArray(children)) { + for (var i = 0; i < children.length; i++) { + if (!validateSuspenseListNestedChild(children[i], i)) { + return; + } + } + } else { + var iteratorFn = getIteratorFn(children); + + if (typeof iteratorFn === "function") { + var childrenIterator = iteratorFn.call(children); + + if (childrenIterator) { + var step = childrenIterator.next(); + var _i = 0; + + for (; !step.done; step = childrenIterator.next()) { + if (!validateSuspenseListNestedChild(step.value, _i)) { + return; + } + + _i++; + } + } + } else { + error( + 'A single row was passed to a . ' + + "This is not useful since it needs multiple rows. " + + "Did you mean to pass multiple children or an array?", + revealOrder + ); + } + } + } } } -function propagateContextChange_eager(workInProgress, context, renderLanes) { - var fiber = workInProgress.child; +function initSuspenseListRenderState( + workInProgress, + isBackwards, + tail, + lastContentRow, + tailMode +) { + var renderState = workInProgress.memoizedState; - if (fiber !== null) { - // Set the return pointer of the child to the work-in-progress fiber. - fiber.return = workInProgress; + if (renderState === null) { + workInProgress.memoizedState = { + isBackwards: isBackwards, + rendering: null, + renderingStartTime: 0, + last: lastContentRow, + tail: tail, + tailMode: tailMode + }; + } else { + // We can reuse the existing object from previous renders. + renderState.isBackwards = isBackwards; + renderState.rendering = null; + renderState.renderingStartTime = 0; + renderState.last = lastContentRow; + renderState.tail = tail; + renderState.tailMode = tailMode; } +} // This can end up rendering this component multiple passes. +// The first pass splits the children fibers into two sets. A head and tail. +// We first render the head. If anything is in fallback state, we do another +// pass through beginWork to rerender all children (including the tail) with +// the force suspend context. If the first render didn't have anything in +// in fallback state. Then we render each row in the tail one-by-one. +// That happens in the completeWork phase without going back to beginWork. - while (fiber !== null) { - var nextFiber = void 0; // Visit this fiber. - - var list = fiber.dependencies; +function updateSuspenseListComponent(current, workInProgress, renderLanes) { + var nextProps = workInProgress.pendingProps; + var revealOrder = nextProps.revealOrder; + var tailMode = nextProps.tail; + var newChildren = nextProps.children; + validateRevealOrder(revealOrder); + validateTailOptions(tailMode, revealOrder); + validateSuspenseListChildren(newChildren, revealOrder); + reconcileChildren(current, workInProgress, newChildren, renderLanes); + var suspenseContext = suspenseStackCursor.current; + var shouldForceFallback = hasSuspenseListContext( + suspenseContext, + ForceSuspenseFallback + ); - if (list !== null) { - nextFiber = fiber.child; - var dependency = list.firstContext; + if (shouldForceFallback) { + suspenseContext = setShallowSuspenseListContext( + suspenseContext, + ForceSuspenseFallback + ); + workInProgress.flags |= DidCapture; + } else { + var didSuspendBefore = + current !== null && (current.flags & DidCapture) !== NoFlags$1; - while (dependency !== null) { - // Check if the context matches. - if (dependency.context === context) { - // Match! Schedule an update on this fiber. - if (fiber.tag === ClassComponent) { - // Schedule a force update on the work-in-progress. - var lane = pickArbitraryLane(renderLanes); - var update = createUpdate(lane); - update.tag = ForceUpdate; // TODO: Because we don't have a work-in-progress, this will add the - // update to the current fiber, too, which means it will persist even if - // this render is thrown away. Since it's a race condition, not sure it's - // worth fixing. - // Inlined `enqueueUpdate` to remove interleaved update check + if (didSuspendBefore) { + // If we previously forced a fallback, we need to schedule work + // on any nested boundaries to let them know to try to render + // again. This is the same as context updating. + propagateSuspenseContextChange( + workInProgress, + workInProgress.child, + renderLanes + ); + } - var updateQueue = fiber.updateQueue; + suspenseContext = setDefaultShallowSuspenseListContext(suspenseContext); + } - if (updateQueue === null); - else { - var sharedQueue = updateQueue.shared; - var pending = sharedQueue.pending; + pushSuspenseListContext(workInProgress, suspenseContext); - if (pending === null) { - // This is the first update. Create a circular list. - update.next = update; - } else { - update.next = pending.next; - pending.next = update; - } + if ((workInProgress.mode & ConcurrentMode) === NoMode) { + // In legacy mode, SuspenseList doesn't work so we just + // use make it a noop by treating it as the default revealOrder. + workInProgress.memoizedState = null; + } else { + switch (revealOrder) { + case "forwards": { + var lastContentRow = findLastContentRow(workInProgress.child); + var tail; - sharedQueue.pending = update; - } - } + if (lastContentRow === null) { + // The whole list is part of the tail. + // TODO: We could fast path by just rendering the tail now. + tail = workInProgress.child; + workInProgress.child = null; + } else { + // Disconnect the tail rows after the content row. + // We're going to render them separately later. + tail = lastContentRow.sibling; + lastContentRow.sibling = null; + } - fiber.lanes = mergeLanes(fiber.lanes, renderLanes); - var alternate = fiber.alternate; + initSuspenseListRenderState( + workInProgress, + false, // isBackwards + tail, + lastContentRow, + tailMode + ); + break; + } - if (alternate !== null) { - alternate.lanes = mergeLanes(alternate.lanes, renderLanes); - } + case "backwards": { + // We're going to find the first row that has existing content. + // At the same time we're going to reverse the list of everything + // we pass in the meantime. That's going to be our tail in reverse + // order. + var _tail = null; + var row = workInProgress.child; + workInProgress.child = null; - scheduleContextWorkOnParentPath( - fiber.return, - renderLanes, - workInProgress - ); // Mark the updated lanes on the list, too. + while (row !== null) { + var currentRow = row.alternate; // New rows can't be content rows. - list.lanes = mergeLanes(list.lanes, renderLanes); // Since we already found a match, we can stop traversing the - // dependency list. + if (currentRow !== null && findFirstSuspended(currentRow) === null) { + // This is the beginning of the main content. + workInProgress.child = row; + break; + } - break; - } + var nextRow = row.sibling; + row.sibling = _tail; + _tail = row; + row = nextRow; + } // TODO: If workInProgress.child is null, we can continue on the tail immediately. - dependency = dependency.next; - } - } else if (fiber.tag === ContextProvider) { - // Don't scan deeper if this is a matching provider - nextFiber = fiber.type === workInProgress.type ? null : fiber.child; - } else if (fiber.tag === DehydratedFragment) { - // If a dehydrated suspense boundary is in this subtree, we don't know - // if it will have any context consumers in it. The best we can do is - // mark it as having updates. - var parentSuspense = fiber.return; + initSuspenseListRenderState( + workInProgress, + true, // isBackwards + _tail, + null, // last + tailMode + ); + break; + } - if (parentSuspense === null) { - throw new Error( - "We just came from a parent so we must have had a parent. This is a bug in React." + case "together": { + initSuspenseListRenderState( + workInProgress, + false, // isBackwards + null, // tail + null, // last + undefined ); + break; } - parentSuspense.lanes = mergeLanes(parentSuspense.lanes, renderLanes); - var _alternate = parentSuspense.alternate; + default: { + // The default reveal order is the same as not having + // a boundary. + workInProgress.memoizedState = null; + } + } + } - if (_alternate !== null) { - _alternate.lanes = mergeLanes(_alternate.lanes, renderLanes); - } // This is intentionally passing this fiber as the parent - // because we want to schedule this fiber as having work - // on its children. We'll use the childLanes on - // this fiber to indicate that a context has changed. + return workInProgress.child; +} - scheduleContextWorkOnParentPath( - parentSuspense, - renderLanes, - workInProgress - ); - nextFiber = fiber.sibling; - } else { - // Traverse down. - nextFiber = fiber.child; - } +function updatePortalComponent(current, workInProgress, renderLanes) { + pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); + var nextChildren = workInProgress.pendingProps; - if (nextFiber !== null) { - // Set the return pointer of the child to the work-in-progress fiber. - nextFiber.return = fiber; - } else { - // No child. Traverse to next sibling. - nextFiber = fiber; + if (current === null) { + // Portals are special because we don't append the children during mount + // but at commit. Therefore we need to track insertions which the normal + // flow doesn't do during mount. This doesn't happen at the root because + // the root always starts with a "current" with a null child. + // TODO: Consider unifying this with how the root works. + workInProgress.child = reconcileChildFibers( + workInProgress, + null, + nextChildren, + renderLanes + ); + } else { + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + } - while (nextFiber !== null) { - if (nextFiber === workInProgress) { - // We're back to the root of this subtree. Exit. - nextFiber = null; - break; - } + return workInProgress.child; +} - var sibling = nextFiber.sibling; +var hasWarnedAboutUsingNoValuePropOnContextProvider = false; - if (sibling !== null) { - // Set the return pointer of the sibling to the work-in-progress fiber. - sibling.return = nextFiber.return; - nextFiber = sibling; - break; - } // No more siblings. Traverse up. +function updateContextProvider(current, workInProgress, renderLanes) { + var providerType = workInProgress.type; + var context = providerType._context; + var newProps = workInProgress.pendingProps; + var oldProps = workInProgress.memoizedProps; + var newValue = newProps.value; - nextFiber = nextFiber.return; + { + if (!("value" in newProps)) { + if (!hasWarnedAboutUsingNoValuePropOnContextProvider) { + hasWarnedAboutUsingNoValuePropOnContextProvider = true; + + error( + "The `value` prop is required for the ``. Did you misspell it or forget to pass it?" + ); } } - fiber = nextFiber; + var providerPropTypes = workInProgress.type.propTypes; + + if (providerPropTypes) { + checkPropTypes(providerPropTypes, newProps, "prop", "Context.Provider"); + } } -} -function prepareToReadContext(workInProgress, renderLanes) { - currentlyRenderingFiber = workInProgress; - lastContextDependency = null; - lastFullyObservedContext = null; - var dependencies = workInProgress.dependencies; - if (dependencies !== null) { - { - var firstContext = dependencies.firstContext; + pushProvider(workInProgress, context, newValue); - if (firstContext !== null) { - if (includesSomeLane(dependencies.lanes, renderLanes)) { - // Context list has a pending update. Mark that this fiber performed work. - markWorkInProgressReceivedUpdate(); - } // Reset the work-in-progress list + { + if (oldProps !== null) { + var oldValue = oldProps.value; - dependencies.firstContext = null; + if (objectIs(oldValue, newValue)) { + // No change. Bailout early if children are the same. + if (oldProps.children === newProps.children && !hasContextChanged()) { + return bailoutOnAlreadyFinishedWork( + current, + workInProgress, + renderLanes + ); + } + } else { + // The context value changed. Search for matching consumers and schedule + // them to update. + propagateContextChange(workInProgress, context, renderLanes); } } } -} -function readContext(context) { - { - // This warning would fire if you read context inside a Hook like useMemo. - // Unlike the class check below, it's not enforced in production for perf. - if (isDisallowedContextReadInDEV) { - error( - "Context can only be read while React is rendering. " + - "In classes, you can read it in the render method or getDerivedStateFromProps. " + - "In function components, you can read it directly in the function body, but not " + - "inside Hooks like useReducer() or useMemo()." - ); - } - } - - return readContextForConsumer(currentlyRenderingFiber, context); -} -function readContextDuringReconcilation(consumer, context, renderLanes) { - if (currentlyRenderingFiber === null) { - prepareToReadContext(consumer, renderLanes); - } - return readContextForConsumer(consumer, context); + var newChildren = newProps.children; + reconcileChildren(current, workInProgress, newChildren, renderLanes); + return workInProgress.child; } -function readContextForConsumer(consumer, context) { - var value = isPrimaryRenderer - ? context._currentValue - : context._currentValue2; +var hasWarnedAboutUsingContextAsConsumer = false; - if (lastFullyObservedContext === context); - else { - var contextItem = { - context: context, - memoizedValue: value, - next: null - }; +function updateContextConsumer(current, workInProgress, renderLanes) { + var context = workInProgress.type; // The logic below for Context differs depending on PROD or DEV mode. In + // DEV mode, we create a separate object for Context.Consumer that acts + // like a proxy to Context. This proxy object adds unnecessary code in PROD + // so we use the old behaviour (Context.Consumer references Context) to + // reduce size and overhead. The separate object references context via + // a property called "_context", which also gives us the ability to check + // in DEV mode if this property exists or not and warn if it does not. - if (lastContextDependency === null) { - if (consumer === null) { - throw new Error( - "Context can only be read while React is rendering. " + - "In classes, you can read it in the render method or getDerivedStateFromProps. " + - "In function components, you can read it directly in the function body, but not " + - "inside Hooks like useReducer() or useMemo()." - ); - } // This is the first dependency for this component. Create a new list. + { + if (context._context === undefined) { + // This may be because it's a Context (rather than a Consumer). + // Or it may be because it's older React where they're the same thing. + // We only want to warn if we're sure it's a new React. + if (context !== context.Consumer) { + if (!hasWarnedAboutUsingContextAsConsumer) { + hasWarnedAboutUsingContextAsConsumer = true; - lastContextDependency = contextItem; - consumer.dependencies = { - lanes: NoLanes, - firstContext: contextItem - }; + error( + "Rendering directly is not supported and will be removed in " + + "a future major release. Did you mean to render instead?" + ); + } + } } else { - // Append a new context item. - lastContextDependency = lastContextDependency.next = contextItem; + context = context._context; } } - return value; -} + var newProps = workInProgress.pendingProps; + var render = newProps.children; -var ReactCurrentBatchConfig$1 = ReactSharedInternals.ReactCurrentBatchConfig; -var NoTransition = null; -function requestCurrentTransition() { - return ReactCurrentBatchConfig$1.transition; -} // When retrying a Suspense/Offscreen boundary, we restore the cache that was -function getSuspendedCache() { { - return null; - } // This function is called when a Suspense boundary suspends. It returns the -} + if (typeof render !== "function") { + error( + "A context consumer was rendered with multiple children, or a child " + + "that isn't a function. A context consumer expects a single child " + + "that is a function. If you did pass a function, make sure there " + + "is no trailing or leading whitespace around it." + ); + } + } -function markUpdate(workInProgress) { - // Tag the fiber with an update effect. This turns a Placement into - // a PlacementAndUpdate. - workInProgress.flags |= Update; -} + prepareToReadContext(workInProgress, renderLanes); + var newValue = readContext(context); -function markRef(workInProgress) { - workInProgress.flags |= Ref | RefStatic; -} + { + markComponentRenderStarted(workInProgress); + } -function hadNoMutationsEffects(current, completedWork) { - var didBailout = current !== null && current.child === completedWork.child; + var newChildren; - if (didBailout) { - return true; + { + ReactCurrentOwner$2.current = workInProgress; + setIsRendering(true); + newChildren = render(newValue); + setIsRendering(false); } - if ((completedWork.flags & ChildDeletion) !== NoFlags$1) { - return false; - } // TODO: If we move the `hadNoMutationsEffects` call after `bubbleProperties` - // then we only have to check the `completedWork.subtreeFlags`. + { + markComponentRenderStopped(); + } // React DevTools reads this flag. + + workInProgress.flags |= PerformedWork; + reconcileChildren(current, workInProgress, newChildren, renderLanes); + return workInProgress.child; +} + +function markWorkInProgressReceivedUpdate() { + didReceiveUpdate = true; +} - var child = completedWork.child; +function resetSuspendedCurrentOnMountInLegacyMode(current, workInProgress) { + if ((workInProgress.mode & ConcurrentMode) === NoMode) { + if (current !== null) { + // A lazy component only mounts if it suspended inside a non- + // concurrent tree, in an inconsistent state. We want to treat it like + // a new mount, even though an empty version of it already committed. + // Disconnect the alternate pointers. + current.alternate = null; + workInProgress.alternate = null; // Since this is conceptually a new fiber, schedule a Placement effect - while (child !== null) { - if ( - (child.flags & MutationMask) !== NoFlags$1 || - (child.subtreeFlags & MutationMask) !== NoFlags$1 - ) { - return false; + workInProgress.flags |= Placement; } - - child = child.sibling; } - - return true; } -function appendAllChildren( - parent, - workInProgress, - needsVisibilityToggle, - isHidden -) { +function bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes) { + if (current !== null) { + // Reuse previous dependencies + workInProgress.dependencies = current.dependencies; + } + { - // We only have the top Fiber that was created but we need recurse down its - // children to find all the terminal nodes. - var _node = workInProgress.child; + // Don't update "base" render times for bailouts. + stopProfilerTimerIfRunning(); + } - while (_node !== null) { - // eslint-disable-next-line no-labels - if (_node.tag === HostComponent) { - var instance = _node.stateNode; + markSkippedUpdateLanes(workInProgress.lanes); // Check if the children have any pending work. - if (needsVisibilityToggle && isHidden) { - instance = cloneHiddenInstance(instance); - } + if (!includesSomeLane(renderLanes, workInProgress.childLanes)) { + // The children don't have any work either. We can skip them. + // TODO: Once we add back resuming, we should check if the children are + // a work-in-progress set. If so, we need to transfer their effects. + { + return null; + } + } // This fiber doesn't have work, but its subtree does. Clone the child + // fibers and continue. - appendInitialChild(parent, instance); - } else if (_node.tag === HostText) { - var _instance = _node.stateNode; + cloneChildFibers(current, workInProgress); + return workInProgress.child; +} - if (needsVisibilityToggle && isHidden) { - _instance = cloneHiddenTextInstance(); - } +function remountFiber(current, oldWorkInProgress, newWorkInProgress) { + { + var returnFiber = oldWorkInProgress.return; - appendInitialChild(parent, _instance); - } else if (_node.tag === HostPortal); - else if ( - _node.tag === OffscreenComponent && - _node.memoizedState !== null - ) { - // The children in this boundary are hidden. Toggle their visibility - // before appending. - var child = _node.child; + if (returnFiber === null) { + // eslint-disable-next-line react-internal/prod-error-codes + throw new Error("Cannot swap the root fiber."); + } // Disconnect from the old current. + // It will get deleted. - if (child !== null) { - child.return = _node; - } + current.alternate = null; + oldWorkInProgress.alternate = null; // Connect to the new tree. - appendAllChildren(parent, _node, true, true); - } else if (_node.child !== null) { - _node.child.return = _node; - _node = _node.child; - continue; - } + newWorkInProgress.index = oldWorkInProgress.index; + newWorkInProgress.sibling = oldWorkInProgress.sibling; + newWorkInProgress.return = oldWorkInProgress.return; + newWorkInProgress.ref = oldWorkInProgress.ref; // Replace the child/sibling pointers above it. - _node = _node; + if (oldWorkInProgress === returnFiber.child) { + returnFiber.child = newWorkInProgress; + } else { + var prevSibling = returnFiber.child; - if (_node === workInProgress) { - return; + if (prevSibling === null) { + // eslint-disable-next-line react-internal/prod-error-codes + throw new Error("Expected parent to have a child."); } // $FlowFixMe[incompatible-use] found when upgrading Flow - while (_node.sibling === null) { + while (prevSibling.sibling !== oldWorkInProgress) { // $FlowFixMe[incompatible-use] found when upgrading Flow - if (_node.return === null || _node.return === workInProgress) { - return; - } + prevSibling = prevSibling.sibling; - _node = _node.return; + if (prevSibling === null) { + // eslint-disable-next-line react-internal/prod-error-codes + throw new Error("Expected to find the previous sibling."); + } } // $FlowFixMe[incompatible-use] found when upgrading Flow - _node.sibling.return = _node.return; - _node = _node.sibling; + prevSibling.sibling = newWorkInProgress; + } // Delete the old fiber and place the new one. + // Since the old fiber is disconnected, we have to schedule it manually. + + var deletions = returnFiber.deletions; + + if (deletions === null) { + returnFiber.deletions = [current]; + returnFiber.flags |= ChildDeletion; + } else { + deletions.push(current); } + + newWorkInProgress.flags |= Placement; // Restart work from the new fiber. + + return newWorkInProgress; } -} // An unfortunate fork of appendAllChildren because we have two different parent types. +} -function appendAllChildrenToContainer( - containerChildSet, +function checkScheduledUpdateOrContext(current, renderLanes) { + // Before performing an early bailout, we must check if there are pending + // updates or context. + var updateLanes = current.lanes; + + if (includesSomeLane(updateLanes, renderLanes)) { + return true; + } // No pending update, but because context is propagated lazily, we need + + return false; +} + +function attemptEarlyBailoutIfNoScheduledUpdate( + current, workInProgress, - needsVisibilityToggle, - isHidden + renderLanes ) { - { - // We only have the top Fiber that was created but we need recurse down its - // children to find all the terminal nodes. - var node = workInProgress.child; - - while (node !== null) { - // eslint-disable-next-line no-labels - if (node.tag === HostComponent) { - var instance = node.stateNode; + // This fiber does not have any pending work. Bailout without entering + // the begin phase. There's still some bookkeeping we that needs to be done + // in this optimized path, mostly pushing stuff onto the stack. + switch (workInProgress.tag) { + case HostRoot: + pushHostRootContext(workInProgress); + break; - if (needsVisibilityToggle && isHidden) { - instance = cloneHiddenInstance(instance); - } + case HostSingleton: + case HostComponent: + pushHostContext(workInProgress); + break; - appendChildToContainerChildSet(containerChildSet, instance); - } else if (node.tag === HostText) { - var _instance2 = node.stateNode; + case ClassComponent: { + var Component = workInProgress.type; - if (needsVisibilityToggle && isHidden) { - _instance2 = cloneHiddenTextInstance(); - } + if (isContextProvider(Component)) { + pushContextProvider(workInProgress); + } - appendChildToContainerChildSet(containerChildSet, _instance2); - } else if (node.tag === HostPortal); - else if (node.tag === OffscreenComponent && node.memoizedState !== null) { - // The children in this boundary are hidden. Toggle their visibility - // before appending. - var child = node.child; + break; + } - if (child !== null) { - child.return = node; - } // If Offscreen is not in manual mode, detached tree is hidden from user space. + case HostPortal: + pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); + break; - var _needsVisibilityToggle = !isOffscreenManual(node); + case ContextProvider: { + var newValue = workInProgress.memoizedProps.value; + var context = workInProgress.type._context; + pushProvider(workInProgress, context, newValue); + break; + } - appendAllChildrenToContainer( - containerChildSet, - node, - _needsVisibilityToggle, - true + case Profiler: + { + // Profiler should only call onRender when one of its descendants actually rendered. + var hasChildWork = includesSomeLane( + renderLanes, + workInProgress.childLanes ); - } else if (node.child !== null) { - node.child.return = node; - node = node.child; - continue; - } - - node = node; - if (node === workInProgress) { - return; - } // $FlowFixMe[incompatible-use] found when upgrading Flow + if (hasChildWork) { + workInProgress.flags |= Update; + } - while (node.sibling === null) { - // $FlowFixMe[incompatible-use] found when upgrading Flow - if (node.return === null || node.return === workInProgress) { - return; + { + // Reset effect durations for the next eventual effect phase. + // These are reset during render to allow the DevTools commit hook a chance to read them, + var stateNode = workInProgress.stateNode; + stateNode.effectDuration = 0; + stateNode.passiveEffectDuration = 0; } + } - node = node.return; - } // $FlowFixMe[incompatible-use] found when upgrading Flow - - node.sibling.return = node.return; - node = node.sibling; - } - } -} + break; -function updateHostContainer(current, workInProgress) { - { - var portalOrRoot = workInProgress.stateNode; - var childrenUnchanged = hadNoMutationsEffects(current, workInProgress); + case SuspenseComponent: { + var state = workInProgress.memoizedState; - if (childrenUnchanged); - else { - var container = portalOrRoot.containerInfo; - var newChildSet = createContainerChildSet(container); // If children might have changed, we have to add them all to the set. + if (state !== null) { + if (state.dehydrated !== null) { + // We're not going to render the children, so this is just to maintain + // push/pop symmetry + pushPrimaryTreeSuspenseHandler(workInProgress); // We know that this component will suspend again because if it has + // been unsuspended it has committed as a resolved Suspense component. + // If it needs to be retried, it should have work scheduled on it. - appendAllChildrenToContainer(newChildSet, workInProgress, false, false); - portalOrRoot.pendingChildren = newChildSet; // Schedule an update on the container to swap out the container. + workInProgress.flags |= DidCapture; // We should never render the children of a dehydrated boundary until we + // upgrade it. We return null instead of bailoutOnAlreadyFinishedWork. - markUpdate(workInProgress); - finalizeContainerChildren(container, newChildSet); - } - } -} + return null; + } // If this boundary is currently timed out, we need to decide + // whether to retry the primary children, or to skip over it and + // go straight to the fallback. Check the priority of the primary + // child fragment. -function updateHostComponent( - current, - workInProgress, - type, - newProps, - renderLanes -) { - { - var currentInstance = current.stateNode; - var _oldProps = current.memoizedProps; // If there are no effects associated with this node, then none of our children had any updates. - // This guarantees that we can reuse all of them. + var primaryChildFragment = workInProgress.child; + var primaryChildLanes = primaryChildFragment.childLanes; - var childrenUnchanged = hadNoMutationsEffects(current, workInProgress); + if (includesSomeLane(renderLanes, primaryChildLanes)) { + // The primary children have pending work. Use the normal path + // to attempt to render the primary children again. + return updateSuspenseComponent(current, workInProgress, renderLanes); + } else { + // The primary child fragment does not have pending work marked + // on it + pushPrimaryTreeSuspenseHandler(workInProgress); // The primary children do not have pending work with sufficient + // priority. Bailout. - if (childrenUnchanged && _oldProps === newProps) { - // No changes, just reuse the existing instance. - // Note that this might release a previous clone. - workInProgress.stateNode = currentInstance; - return; - } + var child = bailoutOnAlreadyFinishedWork( + current, + workInProgress, + renderLanes + ); - var recyclableInstance = workInProgress.stateNode; + if (child !== null) { + // The fallback children have pending work. Skip over the + // primary children and work on the fallback. + return child.sibling; + } else { + // Note: We can return `null` here because we already checked + // whether there were nested context consumers, via the call to + // `bailoutOnAlreadyFinishedWork` above. + return null; + } + } + } else { + pushPrimaryTreeSuspenseHandler(workInProgress); + } - getHostContext(); + break; + } - var _updatePayload = null; + case SuspenseListComponent: { + var didSuspendBefore = (current.flags & DidCapture) !== NoFlags$1; - if (_oldProps !== newProps) { - _updatePayload = prepareUpdate( - recyclableInstance, - type, - _oldProps, - newProps + var _hasChildWork = includesSomeLane( + renderLanes, + workInProgress.childLanes ); - } - if (childrenUnchanged && _updatePayload === null) { - // No changes, just reuse the existing instance. - // Note that this might release a previous clone. - workInProgress.stateNode = currentInstance; - return; - } + if (didSuspendBefore) { + if (_hasChildWork) { + // If something was in fallback state last time, and we have all the + // same children then we're still in progressive loading state. + // Something might get unblocked by state updates or retries in the + // tree which will affect the tail. So we need to use the normal + // path to compute the correct tail. + return updateSuspenseListComponent( + current, + workInProgress, + renderLanes + ); + } // If none of the children had any work, that means that none of + // them got retried so they'll still be blocked in the same way + // as before. We can fast bail out. - var newInstance = cloneInstance( - currentInstance, - _updatePayload, - type, - _oldProps, - newProps, - workInProgress, - childrenUnchanged - ); + workInProgress.flags |= DidCapture; + } // If nothing suspended before and we're rendering the same children, + // then the tail doesn't matter. Anything new that suspends will work + // in the "together" mode, so we can continue from the state we had. - workInProgress.stateNode = newInstance; + var renderState = workInProgress.memoizedState; - if (childrenUnchanged) { - // If there are no other effects in this tree, we need to flag this node as having one. - // Even though we're not going to use it for anything. - // Otherwise parents won't know that there are new children to propagate upwards. - markUpdate(workInProgress); - } else { - // If children might have changed, we have to add them all to the set. - appendAllChildren(newInstance, workInProgress, false, false); - } - } -} // TODO: This should ideally move to begin phase, but currently the instance is -// not created until the complete phase. For our existing use cases, host nodes -// that suspend don't have children, so it doesn't matter. But that might not -// always be true in the future. + if (renderState !== null) { + // Reset to the "together" mode in case we've started a different + // update in the past but didn't complete it. + renderState.rendering = null; + renderState.tail = null; + renderState.lastEffect = null; + } -function preloadInstanceAndSuspendIfNeeded( - workInProgress, - type, - props, - renderLanes -) { - // Ask the renderer if this instance should suspend the commit. - { - // If this flag was set previously, we can remove it. The flag represents - // whether this particular set of props might ever need to suspend. The - // safest thing to do is for maySuspendCommit to always return true, but - // if the renderer is reasonably confident that the underlying resource - // won't be evicted, it can return false as a performance optimization. - workInProgress.flags &= ~SuspenseyCommit; - return; - } // Mark this fiber with a flag. We use this right before the commit phase to -} + pushSuspenseListContext(workInProgress, suspenseStackCursor.current); -function scheduleRetryEffect(workInProgress, retryQueue) { - var wakeables = retryQueue; + if (_hasChildWork) { + break; + } else { + // If none of the children had any work, that means that none of + // them got retried so they'll still be blocked in the same way + // as before. We can fast bail out. + return null; + } + } - if (wakeables !== null) { - // Schedule an effect to attach a retry listener to the promise. - // TODO: Move to passive phase - workInProgress.flags |= Update; - } else { - // This boundary suspended, but no wakeables were added to the retry - // queue. Check if the renderer suspended commit. If so, this means - // that once the fallback is committed, we can immediately retry - // rendering again, because rendering wasn't actually blocked. Only - // the commit phase. - // TODO: Consider a model where we always schedule an immediate retry, even - // for normal Suspense. That way the retry can partially render up to the - // first thing that suspends. - if (workInProgress.flags & ScheduleRetry) { - var retryLane = // TODO: This check should probably be moved into claimNextRetryLane - // I also suspect that we need some further consolidation of offscreen - // and retry lanes. - workInProgress.tag !== OffscreenComponent - ? claimNextRetryLane() - : OffscreenLane; - workInProgress.lanes = mergeLanes(workInProgress.lanes, retryLane); + case OffscreenComponent: + case LegacyHiddenComponent: { + // Need to check if the tree still needs to be deferred. This is + // almost identical to the logic used in the normal update path, + // so we'll just enter that. The only difference is we'll bail out + // at the next level instead of this one, because the child props + // have not changed. Which is fine. + // TODO: Probably should refactor `beginWork` to split the bailout + // path from the normal path. I'm tempted to do a labeled break here + // but I won't :) + workInProgress.lanes = NoLanes; + return updateOffscreenComponent(current, workInProgress, renderLanes); } } + + return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); } -function updateHostText(current, workInProgress, oldText, newText) { +function beginWork$1(current, workInProgress, renderLanes) { { - if (oldText !== newText) { - // If the text content differs, we'll create a new text instance for it. - var rootContainerInstance = getRootHostContainer(); - var currentHostContext = getHostContext(); - workInProgress.stateNode = createTextInstance( - newText, - rootContainerInstance, - currentHostContext, - workInProgress - ); // We'll have to mark it as having an effect, even though we won't use the effect for anything. - // This lets the parents know that at least one of their children has changed. - - markUpdate(workInProgress); - } else { - workInProgress.stateNode = current.stateNode; + if (workInProgress._debugNeedsRemount && current !== null) { + // This will restart the begin phase with a new fiber. + return remountFiber( + current, + workInProgress, + createFiberFromTypeAndProps( + workInProgress.type, + workInProgress.key, + workInProgress.pendingProps, + workInProgress._debugOwner || null, + workInProgress.mode, + workInProgress.lanes + ) + ); } } -} -function cutOffTailIfNeeded(renderState, hasRenderedATailFallback) { - switch (renderState.tailMode) { - case "hidden": { - // Any insertions at the end of the tail list after this point - // should be invisible. If there are already mounted boundaries - // anything before them are not considered for collapsing. - // Therefore we need to go through the whole tail to find if - // there are any. - var tailNode = renderState.tail; - var lastTailNode = null; + if (current !== null) { + var oldProps = current.memoizedProps; + var newProps = workInProgress.pendingProps; - while (tailNode !== null) { - if (tailNode.alternate !== null) { - lastTailNode = tailNode; - } + if ( + oldProps !== newProps || + hasContextChanged() || // Force a re-render if the implementation changed due to hot reload: + workInProgress.type !== current.type + ) { + // If props or context changed, mark the fiber as having performed work. + // This may be unset if the props are determined to be equal later (memo). + didReceiveUpdate = true; + } else { + // Neither props nor legacy context changes. Check if there's a pending + // update or context change. + var hasScheduledUpdateOrContext = checkScheduledUpdateOrContext( + current, + renderLanes + ); - tailNode = tailNode.sibling; - } // Next we're simply going to delete all insertions after the - // last rendered item. + if ( + !hasScheduledUpdateOrContext && // If this is the second pass of an error or suspense boundary, there + // may not be work scheduled on `current`, so we check for this flag. + (workInProgress.flags & DidCapture) === NoFlags$1 + ) { + // No pending updates or context. Bail out now. + didReceiveUpdate = false; + return attemptEarlyBailoutIfNoScheduledUpdate( + current, + workInProgress, + renderLanes + ); + } - if (lastTailNode === null) { - // All remaining items in the tail are insertions. - renderState.tail = null; + if ((current.flags & ForceUpdateForLegacySuspense) !== NoFlags$1) { + // This is a special case that only exists for legacy mode. + // See https://github.com/facebook/react/pull/19216. + didReceiveUpdate = true; } else { - // Detach the insertion after the last node that was already - // inserted. - lastTailNode.sibling = null; + // An update was scheduled on this fiber, but there are no new props + // nor legacy context. Set this to false. If an update queue or context + // consumer produces a changed value, it will set this to true. Otherwise, + // the component will assume the children have not changed and bail out. + didReceiveUpdate = false; } + } + } else { + didReceiveUpdate = false; + } // Before entering the begin phase, clear pending update priority. + // TODO: This assumes that we're about to evaluate the component and process + // the update queue. However, there's an exception: SimpleMemoComponent + // sometimes bails out later in the begin phase. This indicates that we should + // move this assignment out of the common path and into each branch. - break; + workInProgress.lanes = NoLanes; + + switch (workInProgress.tag) { + case IndeterminateComponent: { + return mountIndeterminateComponent( + current, + workInProgress, + workInProgress.type, + renderLanes + ); } - case "collapsed": { - // Any insertions at the end of the tail list after this point - // should be invisible. If there are already mounted boundaries - // anything before them are not considered for collapsing. - // Therefore we need to go through the whole tail to find if - // there are any. - var _tailNode = renderState.tail; - var _lastTailNode = null; + case LazyComponent: { + var elementType = workInProgress.elementType; + return mountLazyComponent( + current, + workInProgress, + elementType, + renderLanes + ); + } - while (_tailNode !== null) { - if (_tailNode.alternate !== null) { - _lastTailNode = _tailNode; - } + case FunctionComponent: { + var Component = workInProgress.type; + var unresolvedProps = workInProgress.pendingProps; + var resolvedProps = + workInProgress.elementType === Component + ? unresolvedProps + : resolveDefaultProps(Component, unresolvedProps); + return updateFunctionComponent( + current, + workInProgress, + Component, + resolvedProps, + renderLanes + ); + } - _tailNode = _tailNode.sibling; - } // Next we're simply going to delete all insertions after the - // last rendered item. + case ClassComponent: { + var _Component = workInProgress.type; + var _unresolvedProps = workInProgress.pendingProps; - if (_lastTailNode === null) { - // All remaining items in the tail are insertions. - if (!hasRenderedATailFallback && renderState.tail !== null) { - // We suspended during the head. We want to show at least one - // row at the tail. So we'll keep on and cut off the rest. - renderState.tail.sibling = null; - } else { - renderState.tail = null; - } - } else { - // Detach the insertion after the last node that was already - // inserted. - _lastTailNode.sibling = null; - } + var _resolvedProps = + workInProgress.elementType === _Component + ? _unresolvedProps + : resolveDefaultProps(_Component, _unresolvedProps); - break; + return updateClassComponent( + current, + workInProgress, + _Component, + _resolvedProps, + renderLanes + ); } - } -} -function bubbleProperties(completedWork) { - var didBailout = - completedWork.alternate !== null && - completedWork.alternate.child === completedWork.child; - var newChildLanes = NoLanes; - var subtreeFlags = NoFlags$1; + case HostRoot: + return updateHostRoot(current, workInProgress, renderLanes); - if (!didBailout) { - // Bubble up the earliest expiration time. - if ((completedWork.mode & ProfileMode) !== NoMode) { - // In profiling mode, resetChildExpirationTime is also used to reset - // profiler durations. - var actualDuration = completedWork.actualDuration; - var treeBaseDuration = completedWork.selfBaseDuration; - var child = completedWork.child; + case HostHoistable: - while (child !== null) { - newChildLanes = mergeLanes( - newChildLanes, - mergeLanes(child.lanes, child.childLanes) - ); - subtreeFlags |= child.subtreeFlags; - subtreeFlags |= child.flags; // When a fiber is cloned, its actualDuration is reset to 0. This value will - // only be updated if work is done on the fiber (i.e. it doesn't bailout). - // When work is done, it should bubble to the parent's actualDuration. If - // the fiber has not been cloned though, (meaning no work was done), then - // this value will reflect the amount of time spent working on a previous - // render. In that case it should not bubble. We determine whether it was - // cloned by comparing the child pointer. - // $FlowFixMe[unsafe-addition] addition with possible null/undefined value + // eslint-disable-next-line no-fallthrough - actualDuration += child.actualDuration; // $FlowFixMe[unsafe-addition] addition with possible null/undefined value + case HostSingleton: - treeBaseDuration += child.treeBaseDuration; - child = child.sibling; - } + // eslint-disable-next-line no-fallthrough - completedWork.actualDuration = actualDuration; - completedWork.treeBaseDuration = treeBaseDuration; - } else { - var _child = completedWork.child; + case HostComponent: + return updateHostComponent$1(current, workInProgress, renderLanes); - while (_child !== null) { - newChildLanes = mergeLanes( - newChildLanes, - mergeLanes(_child.lanes, _child.childLanes) - ); - subtreeFlags |= _child.subtreeFlags; - subtreeFlags |= _child.flags; // Update the return pointer so the tree is consistent. This is a code - // smell because it assumes the commit phase is never concurrent with - // the render phase. Will address during refactor to alternate model. + case HostText: + return updateHostText$1(); - _child.return = completedWork; - _child = _child.sibling; - } + case SuspenseComponent: + return updateSuspenseComponent(current, workInProgress, renderLanes); + + case HostPortal: + return updatePortalComponent(current, workInProgress, renderLanes); + + case ForwardRef: { + var type = workInProgress.type; + var _unresolvedProps2 = workInProgress.pendingProps; + + var _resolvedProps2 = + workInProgress.elementType === type + ? _unresolvedProps2 + : resolveDefaultProps(type, _unresolvedProps2); + + return updateForwardRef( + current, + workInProgress, + type, + _resolvedProps2, + renderLanes + ); } - completedWork.subtreeFlags |= subtreeFlags; - } else { - // Bubble up the earliest expiration time. - if ((completedWork.mode & ProfileMode) !== NoMode) { - // In profiling mode, resetChildExpirationTime is also used to reset - // profiler durations. - var _treeBaseDuration = completedWork.selfBaseDuration; - var _child2 = completedWork.child; + case Fragment: + return updateFragment(current, workInProgress, renderLanes); + + case Mode: + return updateMode(current, workInProgress, renderLanes); + + case Profiler: + return updateProfiler(current, workInProgress, renderLanes); + + case ContextProvider: + return updateContextProvider(current, workInProgress, renderLanes); + + case ContextConsumer: + return updateContextConsumer(current, workInProgress, renderLanes); - while (_child2 !== null) { - newChildLanes = mergeLanes( - newChildLanes, - mergeLanes(_child2.lanes, _child2.childLanes) - ); // "Static" flags share the lifetime of the fiber/hook they belong to, - // so we should bubble those up even during a bailout. All the other - // flags have a lifetime only of a single render + commit, so we should - // ignore them. + case MemoComponent: { + var _type2 = workInProgress.type; + var _unresolvedProps3 = workInProgress.pendingProps; // Resolve outer props first, then resolve inner props. - subtreeFlags |= _child2.subtreeFlags & StaticMask; - subtreeFlags |= _child2.flags & StaticMask; // $FlowFixMe[unsafe-addition] addition with possible null/undefined value + var _resolvedProps3 = resolveDefaultProps(_type2, _unresolvedProps3); - _treeBaseDuration += _child2.treeBaseDuration; - _child2 = _child2.sibling; + { + if (workInProgress.type !== workInProgress.elementType) { + var outerPropTypes = _type2.propTypes; + + if (outerPropTypes) { + checkPropTypes( + outerPropTypes, + _resolvedProps3, // Resolved for outer only + "prop", + getComponentNameFromType(_type2) + ); + } + } } - completedWork.treeBaseDuration = _treeBaseDuration; - } else { - var _child3 = completedWork.child; + _resolvedProps3 = resolveDefaultProps(_type2.type, _resolvedProps3); + return updateMemoComponent( + current, + workInProgress, + _type2, + _resolvedProps3, + renderLanes + ); + } - while (_child3 !== null) { - newChildLanes = mergeLanes( - newChildLanes, - mergeLanes(_child3.lanes, _child3.childLanes) - ); // "Static" flags share the lifetime of the fiber/hook they belong to, - // so we should bubble those up even during a bailout. All the other - // flags have a lifetime only of a single render + commit, so we should - // ignore them. + case SimpleMemoComponent: { + return updateSimpleMemoComponent( + current, + workInProgress, + workInProgress.type, + workInProgress.pendingProps, + renderLanes + ); + } - subtreeFlags |= _child3.subtreeFlags & StaticMask; - subtreeFlags |= _child3.flags & StaticMask; // Update the return pointer so the tree is consistent. This is a code - // smell because it assumes the commit phase is never concurrent with - // the render phase. Will address during refactor to alternate model. + case IncompleteClassComponent: { + var _Component2 = workInProgress.type; + var _unresolvedProps4 = workInProgress.pendingProps; - _child3.return = completedWork; - _child3 = _child3.sibling; - } + var _resolvedProps4 = + workInProgress.elementType === _Component2 + ? _unresolvedProps4 + : resolveDefaultProps(_Component2, _unresolvedProps4); + + return mountIncompleteClassComponent( + current, + workInProgress, + _Component2, + _resolvedProps4, + renderLanes + ); } - completedWork.subtreeFlags |= subtreeFlags; - } + case SuspenseListComponent: { + return updateSuspenseListComponent(current, workInProgress, renderLanes); + } - completedWork.childLanes = newChildLanes; - return didBailout; -} + case ScopeComponent: { + break; + } -function completeDehydratedSuspenseBoundary( - current, - workInProgress, - nextState -) { - var wasHydrated = popHydrationState(); + case OffscreenComponent: { + return updateOffscreenComponent(current, workInProgress, renderLanes); + } - if (nextState !== null && nextState.dehydrated !== null) { - // We might be inside a hydration state the first time we're picking up this - // Suspense boundary, and also after we've reentered it for further hydration. - if (current === null) { - if (!wasHydrated) { - throw new Error( - "A dehydrated suspense component was completed without a hydrated node. " + - "This is probably a bug in React." + case LegacyHiddenComponent: { + { + return updateLegacyHiddenComponent( + current, + workInProgress, + renderLanes ); } + } + } - prepareToHydrateHostSuspenseInstance(); - bubbleProperties(workInProgress); + throw new Error( + "Unknown unit of work tag (" + + workInProgress.tag + + "). This error is likely caused by a bug in " + + "React. Please file an issue." + ); +} - { - if ((workInProgress.mode & ProfileMode) !== NoMode) { - var isTimedOutSuspense = nextState !== null; +var valueCursor = createCursor(null); - if (isTimedOutSuspense) { - // Don't count time spent in a timed out Suspense subtree as part of the base duration. - var primaryChildFragment = workInProgress.child; +var renderer2CursorDEV; - if (primaryChildFragment !== null) { - // $FlowFixMe Flow doesn't support type casting in combination with the -= operator - workInProgress.treeBaseDuration -= - primaryChildFragment.treeBaseDuration; - } - } - } - } +{ + renderer2CursorDEV = createCursor(null); +} - return false; - } else { - if ((workInProgress.flags & DidCapture) === NoFlags$1) { - // This boundary did not suspend so it's now hydrated and unsuspended. - workInProgress.memoizedState = null; - } // If nothing suspended, we need to schedule an effect to mark this boundary - // as having hydrated so events know that they're free to be invoked. - // It's also a signal to replay events and the suspense callback. - // If something suspended, schedule an effect to attach retry listeners. - // So we might as well always mark this. +var rendererSigil; - workInProgress.flags |= Update; - bubbleProperties(workInProgress); +{ + // Use this to detect multiple renderers using the same context + rendererSigil = {}; +} - { - if ((workInProgress.mode & ProfileMode) !== NoMode) { - var _isTimedOutSuspense = nextState !== null; +var currentlyRenderingFiber = null; +var lastContextDependency = null; +var lastFullyObservedContext = null; +var isDisallowedContextReadInDEV = false; +function resetContextDependencies() { + // This is called right before React yields execution, to ensure `readContext` + // cannot be called outside the render phase. + currentlyRenderingFiber = null; + lastContextDependency = null; + lastFullyObservedContext = null; - if (_isTimedOutSuspense) { - // Don't count time spent in a timed out Suspense subtree as part of the base duration. - var _primaryChildFragment = workInProgress.child; + { + isDisallowedContextReadInDEV = false; + } +} +function enterDisallowedContextReadInDEV() { + { + isDisallowedContextReadInDEV = true; + } +} +function exitDisallowedContextReadInDEV() { + { + isDisallowedContextReadInDEV = false; + } +} +function pushProvider(providerFiber, context, nextValue) { + { + push(valueCursor, context._currentValue2, providerFiber); + context._currentValue2 = nextValue; - if (_primaryChildFragment !== null) { - // $FlowFixMe Flow doesn't support type casting in combination with the -= operator - workInProgress.treeBaseDuration -= - _primaryChildFragment.treeBaseDuration; - } - } - } + { + push(renderer2CursorDEV, context._currentRenderer2, providerFiber); + + if ( + context._currentRenderer2 !== undefined && + context._currentRenderer2 !== null && + context._currentRenderer2 !== rendererSigil + ) { + error( + "Detected multiple renderers concurrently rendering the " + + "same context provider. This is currently unsupported." + ); } - return false; + context._currentRenderer2 = rendererSigil; } - } else { - // Successfully completed this tree. If this was a forced client render, - // there may have been recoverable errors during first hydration - // attempt. If so, add them to a queue so we can log them in the - // commit phase. - upgradeHydrationErrorsToRecoverable(); // Fall through to normal Suspense path - - return true; } } +function popProvider(context, providerFiber) { + var currentValue = valueCursor.current; -function completeWork(current, workInProgress, renderLanes) { - var newProps = workInProgress.pendingProps; // Note: This intentionally doesn't check if we're hydrating because comparing - - switch (workInProgress.tag) { - case IndeterminateComponent: - case LazyComponent: - case SimpleMemoComponent: - case FunctionComponent: - case ForwardRef: - case Fragment: - case Mode: - case Profiler: - case ContextConsumer: - case MemoComponent: - bubbleProperties(workInProgress); - return null; + { + if (currentValue === REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED) { + context._currentValue2 = context._defaultValue; + } else { + context._currentValue2 = currentValue; + } - case ClassComponent: { - var Component = workInProgress.type; + { + var currentRenderer2 = renderer2CursorDEV.current; + pop(renderer2CursorDEV, providerFiber); + context._currentRenderer2 = currentRenderer2; + } + } - if (isContextProvider(Component)) { - popContext(workInProgress); - } + pop(valueCursor, providerFiber); +} +function scheduleContextWorkOnParentPath(parent, renderLanes, propagationRoot) { + // Update the child lanes of all the ancestors, including the alternates. + var node = parent; - bubbleProperties(workInProgress); - return null; - } + while (node !== null) { + var alternate = node.alternate; - case HostRoot: { - var fiberRoot = workInProgress.stateNode; - popHostContainer(workInProgress); - popTopLevelContextObject(workInProgress); - resetWorkInProgressVersions(); + if (!isSubsetOfLanes(node.childLanes, renderLanes)) { + node.childLanes = mergeLanes(node.childLanes, renderLanes); - if (fiberRoot.pendingContext) { - fiberRoot.context = fiberRoot.pendingContext; - fiberRoot.pendingContext = null; + if (alternate !== null) { + alternate.childLanes = mergeLanes(alternate.childLanes, renderLanes); } + } else if ( + alternate !== null && + !isSubsetOfLanes(alternate.childLanes, renderLanes) + ) { + alternate.childLanes = mergeLanes(alternate.childLanes, renderLanes); + } else; - if (current === null || current.child === null) { - // If we hydrated, pop so that we can delete any remaining children - // that weren't hydrated. - var wasHydrated = popHydrationState(); + if (node === propagationRoot) { + break; + } - if (wasHydrated) { - // If we hydrated, then we'll need to schedule an update for - // the commit side-effects on the root. - markUpdate(workInProgress); - } else { - if (current !== null) { - var prevState = current.memoizedState; + node = node.return; + } - if ( - // Check if this is a client root - !prevState.isDehydrated || // Check if we reverted to client rendering (e.g. due to an error) - (workInProgress.flags & ForceClientRender) !== NoFlags$1 - ) { - // Schedule an effect to clear this container at the start of the - // next commit. This handles the case of React rendering into a - // container with previous children. It's also safe to do for - // updates too, because current.child would only be null if the - // previous render was null (so the container would already - // be empty). - workInProgress.flags |= Snapshot; // If this was a forced client render, there may have been - // recoverable errors during first hydration attempt. If so, add - // them to a queue so we can log them in the commit phase. + { + if (node !== propagationRoot) { + error( + "Expected to find the propagation root when scheduling context work. " + + "This error is likely caused by a bug in React. Please file an issue." + ); + } + } +} +function propagateContextChange(workInProgress, context, renderLanes) { + { + propagateContextChange_eager(workInProgress, context, renderLanes); + } +} - upgradeHydrationErrorsToRecoverable(); - } - } - } - } +function propagateContextChange_eager(workInProgress, context, renderLanes) { + var fiber = workInProgress.child; - updateHostContainer(current, workInProgress); - bubbleProperties(workInProgress); + if (fiber !== null) { + // Set the return pointer of the child to the work-in-progress fiber. + fiber.return = workInProgress; + } - return null; - } + while (fiber !== null) { + var nextFiber = void 0; // Visit this fiber. - case HostHoistable: - // eslint-disable-next-line-no-fallthrough + var list = fiber.dependencies; - case HostSingleton: - // eslint-disable-next-line-no-fallthrough + if (list !== null) { + nextFiber = fiber.child; + var dependency = list.firstContext; - case HostComponent: { - popHostContext(workInProgress); - var _type = workInProgress.type; + while (dependency !== null) { + // Check if the context matches. + if (dependency.context === context) { + // Match! Schedule an update on this fiber. + if (fiber.tag === ClassComponent) { + // Schedule a force update on the work-in-progress. + var lane = pickArbitraryLane(renderLanes); + var update = createUpdate(lane); + update.tag = ForceUpdate; // TODO: Because we don't have a work-in-progress, this will add the + // update to the current fiber, too, which means it will persist even if + // this render is thrown away. Since it's a race condition, not sure it's + // worth fixing. + // Inlined `enqueueUpdate` to remove interleaved update check - if (current !== null && workInProgress.stateNode != null) { - updateHostComponent(current, workInProgress, _type, newProps); + var updateQueue = fiber.updateQueue; - if (current.ref !== workInProgress.ref) { - markRef(workInProgress); - } - } else { - if (!newProps) { - if (workInProgress.stateNode === null) { - throw new Error( - "We must have new props for new mounts. This error is likely " + - "caused by a bug in React. Please file an issue." - ); - } // This can happen when we abort work. + if (updateQueue === null); + else { + var sharedQueue = updateQueue.shared; + var pending = sharedQueue.pending; - bubbleProperties(workInProgress); - return null; - } + if (pending === null) { + // This is the first update. Create a circular list. + update.next = update; + } else { + update.next = pending.next; + pending.next = update; + } - var _currentHostContext2 = getHostContext(); // TODO: Move createInstance to beginWork and keep it on a context - // "stack" as the parent. Then append children as we go in beginWork - // or completeWork depending on whether we want to add them top->down or - // bottom->up. Top->down is faster in IE11. + sharedQueue.pending = update; + } + } - var _wasHydrated2 = popHydrationState(); + fiber.lanes = mergeLanes(fiber.lanes, renderLanes); + var alternate = fiber.alternate; - if (_wasHydrated2) { - // TODO: Move this and createInstance step into the beginPhase - // to consolidate. - if (prepareToHydrateHostInstance()) { - // If changes to the hydrated node need to be applied at the - // commit-phase we mark this as such. - markUpdate(workInProgress); + if (alternate !== null) { + alternate.lanes = mergeLanes(alternate.lanes, renderLanes); } - } else { - var _rootContainerInstance = getRootHostContainer(); - var _instance3 = createInstance( - _type, - newProps, - _rootContainerInstance, - _currentHostContext2, + scheduleContextWorkOnParentPath( + fiber.return, + renderLanes, workInProgress - ); + ); // Mark the updated lanes on the list, too. - appendAllChildren(_instance3, workInProgress, false, false); - workInProgress.stateNode = _instance3; // Certain renderers require commit-time effects for initial mount. - } + list.lanes = mergeLanes(list.lanes, renderLanes); // Since we already found a match, we can stop traversing the + // dependency list. - if (workInProgress.ref !== null) { - // If there is a ref on a host node we need to schedule a callback - markRef(workInProgress); + break; } + + dependency = dependency.next; + } + } else if (fiber.tag === ContextProvider) { + // Don't scan deeper if this is a matching provider + nextFiber = fiber.type === workInProgress.type ? null : fiber.child; + } else if (fiber.tag === DehydratedFragment) { + // If a dehydrated suspense boundary is in this subtree, we don't know + // if it will have any context consumers in it. The best we can do is + // mark it as having updates. + var parentSuspense = fiber.return; + + if (parentSuspense === null) { + throw new Error( + "We just came from a parent so we must have had a parent. This is a bug in React." + ); } - bubbleProperties(workInProgress); // This must come at the very end of the complete phase, because it might - // throw to suspend, and if the resource immediately loads, the work loop - // will resume rendering as if the work-in-progress completed. So it must - // fully complete. + parentSuspense.lanes = mergeLanes(parentSuspense.lanes, renderLanes); + var _alternate = parentSuspense.alternate; - preloadInstanceAndSuspendIfNeeded(workInProgress); - return null; - } + if (_alternate !== null) { + _alternate.lanes = mergeLanes(_alternate.lanes, renderLanes); + } // This is intentionally passing this fiber as the parent + // because we want to schedule this fiber as having work + // on its children. We'll use the childLanes on + // this fiber to indicate that a context has changed. - case HostText: { - var newText = newProps; + scheduleContextWorkOnParentPath( + parentSuspense, + renderLanes, + workInProgress + ); + nextFiber = fiber.sibling; + } else { + // Traverse down. + nextFiber = fiber.child; + } - if (current && workInProgress.stateNode != null) { - var oldText = current.memoizedProps; // If we have an alternate, that means this is an update and we need - // to schedule a side-effect to do the updates. + if (nextFiber !== null) { + // Set the return pointer of the child to the work-in-progress fiber. + nextFiber.return = fiber; + } else { + // No child. Traverse to next sibling. + nextFiber = fiber; - updateHostText(current, workInProgress, oldText, newText); - } else { - if (typeof newText !== "string") { - if (workInProgress.stateNode === null) { - throw new Error( - "We must have new props for new mounts. This error is likely " + - "caused by a bug in React. Please file an issue." - ); - } // This can happen when we abort work. + while (nextFiber !== null) { + if (nextFiber === workInProgress) { + // We're back to the root of this subtree. Exit. + nextFiber = null; + break; } - var _rootContainerInstance2 = getRootHostContainer(); + var sibling = nextFiber.sibling; + + if (sibling !== null) { + // Set the return pointer of the sibling to the work-in-progress fiber. + sibling.return = nextFiber.return; + nextFiber = sibling; + break; + } // No more siblings. Traverse up. + + nextFiber = nextFiber.return; + } + } - var _currentHostContext3 = getHostContext(); + fiber = nextFiber; + } +} +function prepareToReadContext(workInProgress, renderLanes) { + currentlyRenderingFiber = workInProgress; + lastContextDependency = null; + lastFullyObservedContext = null; + var dependencies = workInProgress.dependencies; - var _wasHydrated3 = popHydrationState(); + if (dependencies !== null) { + { + var firstContext = dependencies.firstContext; - if (_wasHydrated3) { - if (prepareToHydrateHostTextInstance()) { - markUpdate(workInProgress); - } - } else { - workInProgress.stateNode = createTextInstance( - newText, - _rootContainerInstance2, - _currentHostContext3, - workInProgress - ); - } - } + if (firstContext !== null) { + if (includesSomeLane(dependencies.lanes, renderLanes)) { + // Context list has a pending update. Mark that this fiber performed work. + markWorkInProgressReceivedUpdate(); + } // Reset the work-in-progress list - bubbleProperties(workInProgress); - return null; + dependencies.firstContext = null; + } + } + } +} +function readContext(context) { + { + // This warning would fire if you read context inside a Hook like useMemo. + // Unlike the class check below, it's not enforced in production for perf. + if (isDisallowedContextReadInDEV) { + error( + "Context can only be read while React is rendering. " + + "In classes, you can read it in the render method or getDerivedStateFromProps. " + + "In function components, you can read it directly in the function body, but not " + + "inside Hooks like useReducer() or useMemo()." + ); } + } - case SuspenseComponent: { - popSuspenseHandler(workInProgress); - var nextState = workInProgress.memoizedState; // Special path for dehydrated boundaries. We may eventually move this - // to its own fiber type so that we can add other kinds of hydration - // boundaries that aren't associated with a Suspense tree. In anticipation - // of such a refactor, all the hydration logic is contained in - // this branch. + return readContextForConsumer(currentlyRenderingFiber, context); +} +function readContextDuringReconcilation(consumer, context, renderLanes) { + if (currentlyRenderingFiber === null) { + prepareToReadContext(consumer, renderLanes); + } - if ( - current === null || - (current.memoizedState !== null && - current.memoizedState.dehydrated !== null) - ) { - var fallthroughToNormalSuspensePath = - completeDehydratedSuspenseBoundary( - current, - workInProgress, - nextState - ); + return readContextForConsumer(consumer, context); +} - if (!fallthroughToNormalSuspensePath) { - if (workInProgress.flags & ForceClientRender) { - // Special case. There were remaining unhydrated nodes. We treat - // this as a mismatch. Revert to client rendering. - return workInProgress; - } else { - // Did not finish hydrating, either because this is the initial - // render or because something suspended. - return null; - } - } // Continue with the normal Suspense path. - } +function readContextForConsumer(consumer, context) { + var value = context._currentValue2; - if ((workInProgress.flags & DidCapture) !== NoFlags$1) { - // Something suspended. Re-render with the fallback children. - workInProgress.lanes = renderLanes; // Do not reset the effect list. + if (lastFullyObservedContext === context); + else { + var contextItem = { + context: context, + memoizedValue: value, + next: null + }; - if ((workInProgress.mode & ProfileMode) !== NoMode) { - transferActualDuration(workInProgress); - } // Don't bubble properties in this case. + if (lastContextDependency === null) { + if (consumer === null) { + throw new Error( + "Context can only be read while React is rendering. " + + "In classes, you can read it in the render method or getDerivedStateFromProps. " + + "In function components, you can read it directly in the function body, but not " + + "inside Hooks like useReducer() or useMemo()." + ); + } // This is the first dependency for this component. Create a new list. - return workInProgress; - } + lastContextDependency = contextItem; + consumer.dependencies = { + lanes: NoLanes, + firstContext: contextItem + }; + } else { + // Append a new context item. + lastContextDependency = lastContextDependency.next = contextItem; + } + } - var nextDidTimeout = nextState !== null; - var prevDidTimeout = current !== null && current.memoizedState !== null; - // a passive effect, which is when we process the transitions + return value; +} - if (nextDidTimeout !== prevDidTimeout) { - // an effect to toggle the subtree's visibility. When we switch from - // fallback -> primary, the inner Offscreen fiber schedules this effect - // as part of its normal complete phase. But when we switch from - // primary -> fallback, the inner Offscreen fiber does not have a complete - // phase. So we need to schedule its effect here. - // - // We also use this flag to connect/disconnect the effects, but the same - // logic applies: when re-connecting, the Offscreen fiber's complete - // phase will handle scheduling the effect. It's only when the fallback - // is active that we have to do anything special. +var ReactCurrentBatchConfig$1 = ReactSharedInternals.ReactCurrentBatchConfig; +var NoTransition = null; +function requestCurrentTransition() { + return ReactCurrentBatchConfig$1.transition; +} // When retrying a Suspense/Offscreen boundary, we restore the cache that was +function getSuspendedCache() { + { + return null; + } // This function is called when a Suspense boundary suspends. It returns the +} - if (nextDidTimeout) { - var _offscreenFiber2 = workInProgress.child; - _offscreenFiber2.flags |= Visibility; - } - } +function markUpdate(workInProgress) { + // Tag the fiber with an update effect. This turns a Placement into + // a PlacementAndUpdate. + workInProgress.flags |= Update; +} - var retryQueue = workInProgress.updateQueue; - scheduleRetryEffect(workInProgress, retryQueue); +function markRef(workInProgress) { + workInProgress.flags |= Ref | RefStatic; +} - bubbleProperties(workInProgress); +function hadNoMutationsEffects(current, completedWork) { + var didBailout = current !== null && current.child === completedWork.child; - { - if ((workInProgress.mode & ProfileMode) !== NoMode) { - if (nextDidTimeout) { - // Don't count time spent in a timed out Suspense subtree as part of the base duration. - var primaryChildFragment = workInProgress.child; + if (didBailout) { + return true; + } - if (primaryChildFragment !== null) { - // $FlowFixMe Flow doesn't support type casting in combination with the -= operator - workInProgress.treeBaseDuration -= - primaryChildFragment.treeBaseDuration; - } - } - } - } + if ((completedWork.flags & ChildDeletion) !== NoFlags$1) { + return false; + } // TODO: If we move the `hadNoMutationsEffects` call after `bubbleProperties` + // then we only have to check the `completedWork.subtreeFlags`. - return null; + var child = completedWork.child; + + while (child !== null) { + if ( + (child.flags & MutationMask) !== NoFlags$1 || + (child.subtreeFlags & MutationMask) !== NoFlags$1 + ) { + return false; } - case HostPortal: - popHostContainer(workInProgress); - updateHostContainer(current, workInProgress); + child = child.sibling; + } - bubbleProperties(workInProgress); - return null; + return true; +} - case ContextProvider: - // Pop provider fiber - var context = workInProgress.type._context; - popProvider(context, workInProgress); - bubbleProperties(workInProgress); - return null; +function appendAllChildren( + parent, + workInProgress, + needsVisibilityToggle, + isHidden +) { + { + // We only have the top Fiber that was created but we need recurse down its + // children to find all the terminal nodes. + var _node = workInProgress.child; - case IncompleteClassComponent: { - // Same as class component case. I put it down here so that the tags are - // sequential to ensure this switch is compiled to a jump table. - var _Component = workInProgress.type; + while (_node !== null) { + // eslint-disable-next-line no-labels + if (_node.tag === HostComponent) { + var instance = _node.stateNode; - if (isContextProvider(_Component)) { - popContext(workInProgress); - } + if (needsVisibilityToggle && isHidden) { + instance = cloneHiddenInstance(instance); + } - bubbleProperties(workInProgress); - return null; - } + appendInitialChild(parent, instance); + } else if (_node.tag === HostText) { + var _instance = _node.stateNode; + + if (needsVisibilityToggle && isHidden) { + _instance = cloneHiddenTextInstance(); + } + + appendInitialChild(parent, _instance); + } else if (_node.tag === HostPortal); + else if ( + _node.tag === OffscreenComponent && + _node.memoizedState !== null + ) { + // The children in this boundary are hidden. Toggle their visibility + // before appending. + var child = _node.child; - case SuspenseListComponent: { - popSuspenseListContext(workInProgress); - var renderState = workInProgress.memoizedState; + if (child !== null) { + child.return = _node; + } - if (renderState === null) { - // We're running in the default, "independent" mode. - // We don't do anything in this mode. - bubbleProperties(workInProgress); - return null; + appendAllChildren(parent, _node, true, true); + } else if (_node.child !== null) { + _node.child.return = _node; + _node = _node.child; + continue; } - var didSuspendAlready = (workInProgress.flags & DidCapture) !== NoFlags$1; - var renderedTail = renderState.rendering; + _node = _node; - if (renderedTail === null) { - // We just rendered the head. - if (!didSuspendAlready) { - // This is the first pass. We need to figure out if anything is still - // suspended in the rendered set. - // If new content unsuspended, but there's still some content that - // didn't. Then we need to do a second pass that forces everything - // to keep showing their fallbacks. - // We might be suspended if something in this render pass suspended, or - // something in the previous committed pass suspended. Otherwise, - // there's no chance so we can skip the expensive call to - // findFirstSuspended. - var cannotBeSuspended = - renderHasNotSuspendedYet() && - (current === null || (current.flags & DidCapture) === NoFlags$1); + if (_node === workInProgress) { + return; + } // $FlowFixMe[incompatible-use] found when upgrading Flow - if (!cannotBeSuspended) { - var row = workInProgress.child; + while (_node.sibling === null) { + // $FlowFixMe[incompatible-use] found when upgrading Flow + if (_node.return === null || _node.return === workInProgress) { + return; + } - while (row !== null) { - var suspended = findFirstSuspended(row); + _node = _node.return; + } // $FlowFixMe[incompatible-use] found when upgrading Flow - if (suspended !== null) { - didSuspendAlready = true; - workInProgress.flags |= DidCapture; - cutOffTailIfNeeded(renderState, false); // If this is a newly suspended tree, it might not get committed as - // part of the second pass. In that case nothing will subscribe to - // its thenables. Instead, we'll transfer its thenables to the - // SuspenseList so that it can retry if they resolve. - // There might be multiple of these in the list but since we're - // going to wait for all of them anyway, it doesn't really matter - // which ones gets to ping. In theory we could get clever and keep - // track of how many dependencies remain but it gets tricky because - // in the meantime, we can add/remove/change items and dependencies. - // We might bail out of the loop before finding any but that - // doesn't matter since that means that the other boundaries that - // we did find already has their listeners attached. + _node.sibling.return = _node.return; + _node = _node.sibling; + } + } +} // An unfortunate fork of appendAllChildren because we have two different parent types. - var _retryQueue = suspended.updateQueue; - workInProgress.updateQueue = _retryQueue; - scheduleRetryEffect(workInProgress, _retryQueue); // Rerender the whole list, but this time, we'll force fallbacks - // to stay in place. - // Reset the effect flags before doing the second pass since that's now invalid. - // Reset the child fibers to their original state. +function appendAllChildrenToContainer( + containerChildSet, + workInProgress, + needsVisibilityToggle, + isHidden +) { + { + // We only have the top Fiber that was created but we need recurse down its + // children to find all the terminal nodes. + var node = workInProgress.child; - workInProgress.subtreeFlags = NoFlags$1; - resetChildFibers(workInProgress, renderLanes); // Set up the Suspense List Context to force suspense and - // immediately rerender the children. + while (node !== null) { + // eslint-disable-next-line no-labels + if (node.tag === HostComponent) { + var instance = node.stateNode; - pushSuspenseListContext( - workInProgress, - setShallowSuspenseListContext( - suspenseStackCursor.current, - ForceSuspenseFallback - ) - ); // Don't bubble properties in this case. + if (needsVisibilityToggle && isHidden) { + instance = cloneHiddenInstance(instance); + } - return workInProgress.child; - } + appendChildToContainerChildSet(containerChildSet, instance); + } else if (node.tag === HostText) { + var _instance2 = node.stateNode; - row = row.sibling; - } - } + if (needsVisibilityToggle && isHidden) { + _instance2 = cloneHiddenTextInstance(); + } - if (renderState.tail !== null && now$1() > getRenderTargetTime()) { - // We have already passed our CPU deadline but we still have rows - // left in the tail. We'll just give up further attempts to render - // the main content and only render fallbacks. - workInProgress.flags |= DidCapture; - didSuspendAlready = true; - cutOffTailIfNeeded(renderState, false); // Since nothing actually suspended, there will nothing to ping this - // to get it started back up to attempt the next item. While in terms - // of priority this work has the same priority as this current render, - // it's not part of the same transition once the transition has - // committed. If it's sync, we still want to yield so that it can be - // painted. Conceptually, this is really the same as pinging. - // We can use any RetryLane even if it's the one currently rendering - // since we're leaving it behind on this node. + appendChildToContainerChildSet(containerChildSet, _instance2); + } else if (node.tag === HostPortal); + else if (node.tag === OffscreenComponent && node.memoizedState !== null) { + // The children in this boundary are hidden. Toggle their visibility + // before appending. + var child = node.child; - workInProgress.lanes = SomeRetryLane; - } - } else { - cutOffTailIfNeeded(renderState, false); - } // Next we're going to render the tail. - } else { - // Append the rendered row to the child list. - if (!didSuspendAlready) { - var _suspended = findFirstSuspended(renderedTail); + if (child !== null) { + child.return = node; + } // If Offscreen is not in manual mode, detached tree is hidden from user space. - if (_suspended !== null) { - workInProgress.flags |= DidCapture; - didSuspendAlready = true; // Ensure we transfer the update queue to the parent so that it doesn't - // get lost if this row ends up dropped during a second pass. + var _needsVisibilityToggle = !isOffscreenManual(node); - var _retryQueue2 = _suspended.updateQueue; - workInProgress.updateQueue = _retryQueue2; - scheduleRetryEffect(workInProgress, _retryQueue2); - cutOffTailIfNeeded(renderState, true); // This might have been modified. + appendAllChildrenToContainer( + containerChildSet, + node, + _needsVisibilityToggle, + true + ); + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } - if ( - renderState.tail === null && - renderState.tailMode === "hidden" && - !renderedTail.alternate && - !getIsHydrating() // We don't cut it if we're hydrating. - ) { - // We're done. - bubbleProperties(workInProgress); - return null; - } - } else if ( - // The time it took to render last row is greater than the remaining - // time we have to render. So rendering one more row would likely - // exceed it. - now$1() * 2 - renderState.renderingStartTime > - getRenderTargetTime() && - renderLanes !== OffscreenLane - ) { - // We have now passed our CPU deadline and we'll just give up further - // attempts to render the main content and only render fallbacks. - // The assumption is that this is usually faster. - workInProgress.flags |= DidCapture; - didSuspendAlready = true; - cutOffTailIfNeeded(renderState, false); // Since nothing actually suspended, there will nothing to ping this - // to get it started back up to attempt the next item. While in terms - // of priority this work has the same priority as this current render, - // it's not part of the same transition once the transition has - // committed. If it's sync, we still want to yield so that it can be - // painted. Conceptually, this is really the same as pinging. - // We can use any RetryLane even if it's the one currently rendering - // since we're leaving it behind on this node. + node = node; - workInProgress.lanes = SomeRetryLane; - } + if (node === workInProgress) { + return; + } // $FlowFixMe[incompatible-use] found when upgrading Flow + + while (node.sibling === null) { + // $FlowFixMe[incompatible-use] found when upgrading Flow + if (node.return === null || node.return === workInProgress) { + return; } - if (renderState.isBackwards) { - // The effect list of the backwards tail will have been added - // to the end. This breaks the guarantee that life-cycles fire in - // sibling order but that isn't a strong guarantee promised by React. - // Especially since these might also just pop in during future commits. - // Append to the beginning of the list. - renderedTail.sibling = workInProgress.child; - workInProgress.child = renderedTail; - } else { - var previousSibling = renderState.last; + node = node.return; + } // $FlowFixMe[incompatible-use] found when upgrading Flow - if (previousSibling !== null) { - previousSibling.sibling = renderedTail; - } else { - workInProgress.child = renderedTail; - } + node.sibling.return = node.return; + node = node.sibling; + } + } +} - renderState.last = renderedTail; - } - } +function updateHostContainer(current, workInProgress) { + { + var portalOrRoot = workInProgress.stateNode; + var childrenUnchanged = hadNoMutationsEffects(current, workInProgress); - if (renderState.tail !== null) { - // We still have tail rows to render. - // Pop a row. - var next = renderState.tail; - renderState.rendering = next; - renderState.tail = next.sibling; - renderState.renderingStartTime = now$1(); - next.sibling = null; // Restore the context. - // TODO: We can probably just avoid popping it instead and only - // setting it the first time we go from not suspended to suspended. + if (childrenUnchanged); + else { + var container = portalOrRoot.containerInfo; + var newChildSet = createContainerChildSet(container); // If children might have changed, we have to add them all to the set. - var suspenseContext = suspenseStackCursor.current; + appendAllChildrenToContainer(newChildSet, workInProgress, false, false); + portalOrRoot.pendingChildren = newChildSet; // Schedule an update on the container to swap out the container. - if (didSuspendAlready) { - suspenseContext = setShallowSuspenseListContext( - suspenseContext, - ForceSuspenseFallback - ); - } else { - suspenseContext = - setDefaultShallowSuspenseListContext(suspenseContext); - } + markUpdate(workInProgress); + finalizeContainerChildren(container, newChildSet); + } + } +} - pushSuspenseListContext(workInProgress, suspenseContext); // Do a pass over the next row. - // Don't bubble properties in this case. +function updateHostComponent( + current, + workInProgress, + type, + newProps, + renderLanes +) { + { + var currentInstance = current.stateNode; + var _oldProps = current.memoizedProps; // If there are no effects associated with this node, then none of our children had any updates. + // This guarantees that we can reuse all of them. - return next; - } + var childrenUnchanged = hadNoMutationsEffects(current, workInProgress); - bubbleProperties(workInProgress); - return null; + if (childrenUnchanged && _oldProps === newProps) { + // No changes, just reuse the existing instance. + // Note that this might release a previous clone. + workInProgress.stateNode = currentInstance; + return; } - case ScopeComponent: { - break; - } + var recyclableInstance = workInProgress.stateNode; - case OffscreenComponent: - case LegacyHiddenComponent: { - popSuspenseHandler(workInProgress); - popHiddenContext(workInProgress); - var _nextState = workInProgress.memoizedState; - var nextIsHidden = _nextState !== null; // Schedule a Visibility effect if the visibility has changed + getHostContext(); - if (workInProgress.tag === LegacyHiddenComponent); - else { - if (current !== null) { - var _prevState = current.memoizedState; - var prevIsHidden = _prevState !== null; + var _updatePayload = null; - if (prevIsHidden !== nextIsHidden) { - workInProgress.flags |= Visibility; - } - } else { - // On initial mount, we only need a Visibility effect if the tree - // is hidden. - if (nextIsHidden) { - workInProgress.flags |= Visibility; - } - } - } + if (_oldProps !== newProps) { + _updatePayload = prepareUpdate( + recyclableInstance, + type, + _oldProps, + newProps + ); + } - if (!nextIsHidden || (workInProgress.mode & ConcurrentMode) === NoMode) { - bubbleProperties(workInProgress); - } else { - // Don't bubble properties for hidden children unless we're rendering - // at offscreen priority. - if ( - includesSomeLane(renderLanes, OffscreenLane) && // Also don't bubble if the tree suspended - (workInProgress.flags & DidCapture) === NoLanes - ) { - bubbleProperties(workInProgress); // Check if there was an insertion or update in the hidden subtree. - // If so, we need to hide those nodes in the commit phase, so - // schedule a visibility effect. + if (childrenUnchanged && _updatePayload === null) { + // No changes, just reuse the existing instance. + // Note that this might release a previous clone. + workInProgress.stateNode = currentInstance; + return; + } - if ( - workInProgress.tag !== LegacyHiddenComponent && - workInProgress.subtreeFlags & (Placement | Update) - ) { - workInProgress.flags |= Visibility; - } - } - } + var newInstance = cloneInstance( + currentInstance, + _updatePayload, + type, + _oldProps, + newProps, + workInProgress, + childrenUnchanged + ); - var offscreenQueue = workInProgress.updateQueue; + workInProgress.stateNode = newInstance; - if (offscreenQueue !== null) { - var _retryQueue3 = offscreenQueue.retryQueue; - scheduleRetryEffect(workInProgress, _retryQueue3); - } - return null; + if (childrenUnchanged) { + // If there are no other effects in this tree, we need to flag this node as having one. + // Even though we're not going to use it for anything. + // Otherwise parents won't know that there are new children to propagate upwards. + markUpdate(workInProgress); + } else { + // If children might have changed, we have to add them all to the set. + appendAllChildren(newInstance, workInProgress, false, false); } + } +} // TODO: This should ideally move to begin phase, but currently the instance is +// not created until the complete phase. For our existing use cases, host nodes +// that suspend don't have children, so it doesn't matter. But that might not +// always be true in the future. - case CacheComponent: { - return null; - } +function preloadInstanceAndSuspendIfNeeded( + workInProgress, + type, + props, + renderLanes +) { + // Ask the renderer if this instance should suspend the commit. + { + // If this flag was set previously, we can remove it. The flag represents + // whether this particular set of props might ever need to suspend. The + // safest thing to do is for maySuspendCommit to always return true, but + // if the renderer is reasonably confident that the underlying resource + // won't be evicted, it can return false as a performance optimization. + workInProgress.flags &= ~SuspenseyCommit; + return; + } // Mark this fiber with a flag. We use this right before the commit phase to +} - case TracingMarkerComponent: { - return null; +function scheduleRetryEffect(workInProgress, retryQueue) { + var wakeables = retryQueue; + + if (wakeables !== null) { + // Schedule an effect to attach a retry listener to the promise. + // TODO: Move to passive phase + workInProgress.flags |= Update; + } else { + // This boundary suspended, but no wakeables were added to the retry + // queue. Check if the renderer suspended commit. If so, this means + // that once the fallback is committed, we can immediately retry + // rendering again, because rendering wasn't actually blocked. Only + // the commit phase. + // TODO: Consider a model where we always schedule an immediate retry, even + // for normal Suspense. That way the retry can partially render up to the + // first thing that suspends. + if (workInProgress.flags & ScheduleRetry) { + var retryLane = // TODO: This check should probably be moved into claimNextRetryLane + // I also suspect that we need some further consolidation of offscreen + // and retry lanes. + workInProgress.tag !== OffscreenComponent + ? claimNextRetryLane() + : OffscreenLane; + workInProgress.lanes = mergeLanes(workInProgress.lanes, retryLane); } } +} - throw new Error( - "Unknown unit of work tag (" + - workInProgress.tag + - "). This error is likely caused by a bug in " + - "React. Please file an issue." - ); +function updateHostText(current, workInProgress, oldText, newText) { + { + if (oldText !== newText) { + // If the text content differs, we'll create a new text instance for it. + var rootContainerInstance = getRootHostContainer(); + var currentHostContext = getHostContext(); + workInProgress.stateNode = createTextInstance( + newText, + rootContainerInstance, + currentHostContext, + workInProgress + ); // We'll have to mark it as having an effect, even though we won't use the effect for anything. + // This lets the parents know that at least one of their children has changed. + + markUpdate(workInProgress); + } else { + workInProgress.stateNode = current.stateNode; + } + } } -function unwindWork(current, workInProgress, renderLanes) { - switch (workInProgress.tag) { - case ClassComponent: { - var Component = workInProgress.type; +function cutOffTailIfNeeded(renderState, hasRenderedATailFallback) { + switch (renderState.tailMode) { + case "hidden": { + // Any insertions at the end of the tail list after this point + // should be invisible. If there are already mounted boundaries + // anything before them are not considered for collapsing. + // Therefore we need to go through the whole tail to find if + // there are any. + var tailNode = renderState.tail; + var lastTailNode = null; - if (isContextProvider(Component)) { - popContext(workInProgress); + while (tailNode !== null) { + if (tailNode.alternate !== null) { + lastTailNode = tailNode; + } + + tailNode = tailNode.sibling; + } // Next we're simply going to delete all insertions after the + // last rendered item. + + if (lastTailNode === null) { + // All remaining items in the tail are insertions. + renderState.tail = null; + } else { + // Detach the insertion after the last node that was already + // inserted. + lastTailNode.sibling = null; } - var flags = workInProgress.flags; + break; + } - if (flags & ShouldCapture) { - workInProgress.flags = (flags & ~ShouldCapture) | DidCapture; + case "collapsed": { + // Any insertions at the end of the tail list after this point + // should be invisible. If there are already mounted boundaries + // anything before them are not considered for collapsing. + // Therefore we need to go through the whole tail to find if + // there are any. + var _tailNode = renderState.tail; + var _lastTailNode = null; + + while (_tailNode !== null) { + if (_tailNode.alternate !== null) { + _lastTailNode = _tailNode; + } + + _tailNode = _tailNode.sibling; + } // Next we're simply going to delete all insertions after the + // last rendered item. - if ((workInProgress.mode & ProfileMode) !== NoMode) { - transferActualDuration(workInProgress); + if (_lastTailNode === null) { + // All remaining items in the tail are insertions. + if (!hasRenderedATailFallback && renderState.tail !== null) { + // We suspended during the head. We want to show at least one + // row at the tail. So we'll keep on and cut off the rest. + renderState.tail.sibling = null; + } else { + renderState.tail = null; } - - return workInProgress; + } else { + // Detach the insertion after the last node that was already + // inserted. + _lastTailNode.sibling = null; } - return null; + break; } + } +} - case HostRoot: { - popHostContainer(workInProgress); - popTopLevelContextObject(workInProgress); - resetWorkInProgressVersions(); - var _flags = workInProgress.flags; - - if ( - (_flags & ShouldCapture) !== NoFlags$1 && - (_flags & DidCapture) === NoFlags$1 - ) { - // There was an error during render that wasn't captured by a suspense - // boundary. Do a second pass on the root to unmount the children. - workInProgress.flags = (_flags & ~ShouldCapture) | DidCapture; - return workInProgress; - } // We unwound to the root without completing it. Exit. +function bubbleProperties(completedWork) { + var didBailout = + completedWork.alternate !== null && + completedWork.alternate.child === completedWork.child; + var newChildLanes = NoLanes; + var subtreeFlags = NoFlags$1; - return null; - } + if (!didBailout) { + // Bubble up the earliest expiration time. + if ((completedWork.mode & ProfileMode) !== NoMode) { + // In profiling mode, resetChildExpirationTime is also used to reset + // profiler durations. + var actualDuration = completedWork.actualDuration; + var treeBaseDuration = completedWork.selfBaseDuration; + var child = completedWork.child; - case HostHoistable: - case HostSingleton: - case HostComponent: { - // TODO: popHydrationState - popHostContext(workInProgress); - return null; - } + while (child !== null) { + newChildLanes = mergeLanes( + newChildLanes, + mergeLanes(child.lanes, child.childLanes) + ); + subtreeFlags |= child.subtreeFlags; + subtreeFlags |= child.flags; // When a fiber is cloned, its actualDuration is reset to 0. This value will + // only be updated if work is done on the fiber (i.e. it doesn't bailout). + // When work is done, it should bubble to the parent's actualDuration. If + // the fiber has not been cloned though, (meaning no work was done), then + // this value will reflect the amount of time spent working on a previous + // render. In that case it should not bubble. We determine whether it was + // cloned by comparing the child pointer. + // $FlowFixMe[unsafe-addition] addition with possible null/undefined value - case SuspenseComponent: { - popSuspenseHandler(workInProgress); - var suspenseState = workInProgress.memoizedState; + actualDuration += child.actualDuration; // $FlowFixMe[unsafe-addition] addition with possible null/undefined value - if (suspenseState !== null && suspenseState.dehydrated !== null) { - if (workInProgress.alternate === null) { - throw new Error( - "Threw in newly mounted dehydrated component. This is likely a bug in " + - "React. Please file an issue." - ); - } + treeBaseDuration += child.treeBaseDuration; + child = child.sibling; } - var _flags2 = workInProgress.flags; - - if (_flags2 & ShouldCapture) { - workInProgress.flags = (_flags2 & ~ShouldCapture) | DidCapture; // Captured a suspense effect. Re-render the boundary. + completedWork.actualDuration = actualDuration; + completedWork.treeBaseDuration = treeBaseDuration; + } else { + var _child = completedWork.child; - if ((workInProgress.mode & ProfileMode) !== NoMode) { - transferActualDuration(workInProgress); - } + while (_child !== null) { + newChildLanes = mergeLanes( + newChildLanes, + mergeLanes(_child.lanes, _child.childLanes) + ); + subtreeFlags |= _child.subtreeFlags; + subtreeFlags |= _child.flags; // Update the return pointer so the tree is consistent. This is a code + // smell because it assumes the commit phase is never concurrent with + // the render phase. Will address during refactor to alternate model. - return workInProgress; + _child.return = completedWork; + _child = _child.sibling; } - - return null; } - case SuspenseListComponent: { - popSuspenseListContext(workInProgress); // SuspenseList doesn't actually catch anything. It should've been - // caught by a nested boundary. If not, it should bubble through. + completedWork.subtreeFlags |= subtreeFlags; + } else { + // Bubble up the earliest expiration time. + if ((completedWork.mode & ProfileMode) !== NoMode) { + // In profiling mode, resetChildExpirationTime is also used to reset + // profiler durations. + var _treeBaseDuration = completedWork.selfBaseDuration; + var _child2 = completedWork.child; - return null; - } + while (_child2 !== null) { + newChildLanes = mergeLanes( + newChildLanes, + mergeLanes(_child2.lanes, _child2.childLanes) + ); // "Static" flags share the lifetime of the fiber/hook they belong to, + // so we should bubble those up even during a bailout. All the other + // flags have a lifetime only of a single render + commit, so we should + // ignore them. - case HostPortal: - popHostContainer(workInProgress); - return null; + subtreeFlags |= _child2.subtreeFlags & StaticMask; + subtreeFlags |= _child2.flags & StaticMask; // $FlowFixMe[unsafe-addition] addition with possible null/undefined value - case ContextProvider: - var context = workInProgress.type._context; - popProvider(context, workInProgress); - return null; + _treeBaseDuration += _child2.treeBaseDuration; + _child2 = _child2.sibling; + } - case OffscreenComponent: - case LegacyHiddenComponent: { - popSuspenseHandler(workInProgress); - popHiddenContext(workInProgress); - var _flags3 = workInProgress.flags; + completedWork.treeBaseDuration = _treeBaseDuration; + } else { + var _child3 = completedWork.child; - if (_flags3 & ShouldCapture) { - workInProgress.flags = (_flags3 & ~ShouldCapture) | DidCapture; // Captured a suspense effect. Re-render the boundary. + while (_child3 !== null) { + newChildLanes = mergeLanes( + newChildLanes, + mergeLanes(_child3.lanes, _child3.childLanes) + ); // "Static" flags share the lifetime of the fiber/hook they belong to, + // so we should bubble those up even during a bailout. All the other + // flags have a lifetime only of a single render + commit, so we should + // ignore them. - if ((workInProgress.mode & ProfileMode) !== NoMode) { - transferActualDuration(workInProgress); - } + subtreeFlags |= _child3.subtreeFlags & StaticMask; + subtreeFlags |= _child3.flags & StaticMask; // Update the return pointer so the tree is consistent. This is a code + // smell because it assumes the commit phase is never concurrent with + // the render phase. Will address during refactor to alternate model. - return workInProgress; + _child3.return = completedWork; + _child3 = _child3.sibling; } - - return null; } - case CacheComponent: - return null; - - case TracingMarkerComponent: - return null; - - default: - return null; + completedWork.subtreeFlags |= subtreeFlags; } + + completedWork.childLanes = newChildLanes; + return didBailout; } -function unwindInterruptedWork(current, interruptedWork, renderLanes) { - switch (interruptedWork.tag) { - case ClassComponent: { - var childContextTypes = interruptedWork.type.childContextTypes; +function completeDehydratedSuspenseBoundary( + current, + workInProgress, + nextState +) { + var wasHydrated = popHydrationState(); - if (childContextTypes !== null && childContextTypes !== undefined) { - popContext(interruptedWork); + if (nextState !== null && nextState.dehydrated !== null) { + // We might be inside a hydration state the first time we're picking up this + // Suspense boundary, and also after we've reentered it for further hydration. + if (current === null) { + if (!wasHydrated) { + throw new Error( + "A dehydrated suspense component was completed without a hydrated node. " + + "This is probably a bug in React." + ); } - break; - } + prepareToHydrateHostSuspenseInstance(); + bubbleProperties(workInProgress); - case HostRoot: { - popHostContainer(interruptedWork); - popTopLevelContextObject(interruptedWork); - resetWorkInProgressVersions(); - break; - } + { + if ((workInProgress.mode & ProfileMode) !== NoMode) { + var isTimedOutSuspense = nextState !== null; - case HostHoistable: - case HostSingleton: - case HostComponent: { - popHostContext(interruptedWork); - break; - } + if (isTimedOutSuspense) { + // Don't count time spent in a timed out Suspense subtree as part of the base duration. + var primaryChildFragment = workInProgress.child; - case HostPortal: - popHostContainer(interruptedWork); - break; + if (primaryChildFragment !== null) { + // $FlowFixMe Flow doesn't support type casting in combination with the -= operator + workInProgress.treeBaseDuration -= + primaryChildFragment.treeBaseDuration; + } + } + } + } + + return false; + } else { + if ((workInProgress.flags & DidCapture) === NoFlags$1) { + // This boundary did not suspend so it's now hydrated and unsuspended. + workInProgress.memoizedState = null; + } // If nothing suspended, we need to schedule an effect to mark this boundary + // as having hydrated so events know that they're free to be invoked. + // It's also a signal to replay events and the suspense callback. + // If something suspended, schedule an effect to attach retry listeners. + // So we might as well always mark this. + + workInProgress.flags |= Update; + bubbleProperties(workInProgress); + + { + if ((workInProgress.mode & ProfileMode) !== NoMode) { + var _isTimedOutSuspense = nextState !== null; - case SuspenseComponent: - popSuspenseHandler(interruptedWork); - break; + if (_isTimedOutSuspense) { + // Don't count time spent in a timed out Suspense subtree as part of the base duration. + var _primaryChildFragment = workInProgress.child; - case SuspenseListComponent: - popSuspenseListContext(interruptedWork); - break; + if (_primaryChildFragment !== null) { + // $FlowFixMe Flow doesn't support type casting in combination with the -= operator + workInProgress.treeBaseDuration -= + _primaryChildFragment.treeBaseDuration; + } + } + } + } - case ContextProvider: - var context = interruptedWork.type._context; - popProvider(context, interruptedWork); - break; + return false; + } + } else { + // Successfully completed this tree. If this was a forced client render, + // there may have been recoverable errors during first hydration + // attempt. If so, add them to a queue so we can log them in the + // commit phase. + upgradeHydrationErrorsToRecoverable(); // Fall through to normal Suspense path - case OffscreenComponent: - case LegacyHiddenComponent: - popSuspenseHandler(interruptedWork); - popHiddenContext(interruptedWork); - break; + return true; } } -var didWarnAboutUndefinedSnapshotBeforeUpdate = null; - -{ - didWarnAboutUndefinedSnapshotBeforeUpdate = new Set(); -} // Used during the commit phase to track the state of the Offscreen component stack. -// Allows us to avoid traversing the return path to find the nearest Offscreen ancestor. - -var offscreenSubtreeIsHidden = false; -var offscreenSubtreeWasHidden = false; -var PossiblyWeakSet = typeof WeakSet === "function" ? WeakSet : Set; -var nextEffect = null; // Used for Profiling builds to track updaters. - -var inProgressLanes = null; -var inProgressRoot = null; +function completeWork(current, workInProgress, renderLanes) { + var newProps = workInProgress.pendingProps; // Note: This intentionally doesn't check if we're hydrating because comparing -function shouldProfile(current) { - return ( - (current.mode & ProfileMode) !== NoMode && - (getExecutionContext() & CommitContext) !== NoContext - ); -} + switch (workInProgress.tag) { + case IndeterminateComponent: + case LazyComponent: + case SimpleMemoComponent: + case FunctionComponent: + case ForwardRef: + case Fragment: + case Mode: + case Profiler: + case ContextConsumer: + case MemoComponent: + bubbleProperties(workInProgress); + return null; -function reportUncaughtErrorInDEV(error) { - // Wrapping each small part of the commit phase into a guarded - // callback is a bit too slow (https://github.com/facebook/react/pull/21666). - // But we rely on it to surface errors to DEV tools like overlays - // (https://github.com/facebook/react/issues/21712). - // As a compromise, rethrow only caught errors in a guard. - { - invokeGuardedCallback(null, function () { - throw error; - }); - clearCaughtError(); - } -} + case ClassComponent: { + var Component = workInProgress.type; -function callComponentWillUnmountWithTimer(current, instance) { - instance.props = current.memoizedProps; - instance.state = current.memoizedState; + if (isContextProvider(Component)) { + popContext(workInProgress); + } - if (shouldProfile(current)) { - try { - startLayoutEffectTimer(); - instance.componentWillUnmount(); - } finally { - recordLayoutEffectDuration(current); + bubbleProperties(workInProgress); + return null; } - } else { - instance.componentWillUnmount(); - } -} // Capture errors so they don't interrupt unmounting. -function safelyCallComponentWillUnmount( - current, - nearestMountedAncestor, - instance -) { - try { - callComponentWillUnmountWithTimer(current, instance); - } catch (error) { - captureCommitPhaseError(current, nearestMountedAncestor, error); - } -} // Capture errors so they don't interrupt mounting. + case HostRoot: { + var fiberRoot = workInProgress.stateNode; + popHostContainer(workInProgress); + popTopLevelContextObject(workInProgress); + resetWorkInProgressVersions(); -function safelyAttachRef(current, nearestMountedAncestor) { - try { - commitAttachRef(current); - } catch (error) { - captureCommitPhaseError(current, nearestMountedAncestor, error); - } -} + if (fiberRoot.pendingContext) { + fiberRoot.context = fiberRoot.pendingContext; + fiberRoot.pendingContext = null; + } -function safelyDetachRef(current, nearestMountedAncestor) { - var ref = current.ref; - var refCleanup = current.refCleanup; + if (current === null || current.child === null) { + // If we hydrated, pop so that we can delete any remaining children + // that weren't hydrated. + var wasHydrated = popHydrationState(); - if (ref !== null) { - if (typeof refCleanup === "function") { - try { - if (shouldProfile(current)) { - try { - startLayoutEffectTimer(); - refCleanup(); - } finally { - recordLayoutEffectDuration(current); - } + if (wasHydrated) { + // If we hydrated, then we'll need to schedule an update for + // the commit side-effects on the root. + markUpdate(workInProgress); } else { - refCleanup(); - } - } catch (error) { - captureCommitPhaseError(current, nearestMountedAncestor, error); - } finally { - // `refCleanup` has been called. Nullify all references to it to prevent double invocation. - current.refCleanup = null; - var finishedWork = current.alternate; + if (current !== null) { + var prevState = current.memoizedState; - if (finishedWork != null) { - finishedWork.refCleanup = null; - } - } - } else if (typeof ref === "function") { - var retVal; + if ( + // Check if this is a client root + !prevState.isDehydrated || // Check if we reverted to client rendering (e.g. due to an error) + (workInProgress.flags & ForceClientRender) !== NoFlags$1 + ) { + // Schedule an effect to clear this container at the start of the + // next commit. This handles the case of React rendering into a + // container with previous children. It's also safe to do for + // updates too, because current.child would only be null if the + // previous render was null (so the container would already + // be empty). + workInProgress.flags |= Snapshot; // If this was a forced client render, there may have been + // recoverable errors during first hydration attempt. If so, add + // them to a queue so we can log them in the commit phase. - try { - if (shouldProfile(current)) { - try { - startLayoutEffectTimer(); - retVal = ref(null); - } finally { - recordLayoutEffectDuration(current); + upgradeHydrationErrorsToRecoverable(); + } } - } else { - retVal = ref(null); } - } catch (error) { - captureCommitPhaseError(current, nearestMountedAncestor, error); } - { - if (typeof retVal === "function") { - error( - "Unexpected return value from a callback ref in %s. " + - "A callback ref should not return a function.", - getComponentNameFromFiber(current) - ); - } - } - } else { - // $FlowFixMe unable to narrow type to RefObject - ref.current = null; + updateHostContainer(current, workInProgress); + bubbleProperties(workInProgress); + + return null; } - } -} -function safelyCallDestroy(current, nearestMountedAncestor, destroy) { - try { - destroy(); - } catch (error) { - captureCommitPhaseError(current, nearestMountedAncestor, error); - } -} -var shouldFireAfterActiveInstanceBlur = false; -function commitBeforeMutationEffects(root, firstChild) { - nextEffect = firstChild; - commitBeforeMutationEffects_begin(); // We no longer need to track the active instance fiber + case HostHoistable: + // eslint-disable-next-line-no-fallthrough - var shouldFire = shouldFireAfterActiveInstanceBlur; - shouldFireAfterActiveInstanceBlur = false; - return shouldFire; -} + case HostSingleton: + // eslint-disable-next-line-no-fallthrough -function commitBeforeMutationEffects_begin() { - while (nextEffect !== null) { - var fiber = nextEffect; // This phase is only used for beforeActiveInstanceBlur. + case HostComponent: { + popHostContext(workInProgress); + var _type = workInProgress.type; - var child = fiber.child; + if (current !== null && workInProgress.stateNode != null) { + updateHostComponent(current, workInProgress, _type, newProps); - if ( - (fiber.subtreeFlags & BeforeMutationMask) !== NoFlags$1 && - child !== null - ) { - child.return = fiber; - nextEffect = child; - } else { - commitBeforeMutationEffects_complete(); - } - } -} + if (current.ref !== workInProgress.ref) { + markRef(workInProgress); + } + } else { + if (!newProps) { + if (workInProgress.stateNode === null) { + throw new Error( + "We must have new props for new mounts. This error is likely " + + "caused by a bug in React. Please file an issue." + ); + } // This can happen when we abort work. -function commitBeforeMutationEffects_complete() { - while (nextEffect !== null) { - var fiber = nextEffect; - setCurrentFiber(fiber); + bubbleProperties(workInProgress); + return null; + } - try { - commitBeforeMutationEffectsOnFiber(fiber); - } catch (error) { - captureCommitPhaseError(fiber, fiber.return, error); - } + var _currentHostContext2 = getHostContext(); // TODO: Move createInstance to beginWork and keep it on a context + // "stack" as the parent. Then append children as we go in beginWork + // or completeWork depending on whether we want to add them top->down or + // bottom->up. Top->down is faster in IE11. - resetCurrentFiber(); - var sibling = fiber.sibling; + var _wasHydrated2 = popHydrationState(); - if (sibling !== null) { - sibling.return = fiber.return; - nextEffect = sibling; - return; - } + if (_wasHydrated2) { + // TODO: Move this and createInstance step into the beginPhase + // to consolidate. + if (prepareToHydrateHostInstance()) { + // If changes to the hydrated node need to be applied at the + // commit-phase we mark this as such. + markUpdate(workInProgress); + } + } else { + var _rootContainerInstance = getRootHostContainer(); - nextEffect = fiber.return; - } -} + var _instance3 = createInstance( + _type, + newProps, + _rootContainerInstance, + _currentHostContext2, + workInProgress + ); -function commitBeforeMutationEffectsOnFiber(finishedWork) { - var current = finishedWork.alternate; - var flags = finishedWork.flags; + appendAllChildren(_instance3, workInProgress, false, false); + workInProgress.stateNode = _instance3; // Certain renderers require commit-time effects for initial mount. + } - if ((flags & Snapshot) !== NoFlags$1) { - setCurrentFiber(finishedWork); - } + if (workInProgress.ref !== null) { + // If there is a ref on a host node we need to schedule a callback + markRef(workInProgress); + } + } - switch (finishedWork.tag) { - case FunctionComponent: { - break; - } + bubbleProperties(workInProgress); // This must come at the very end of the complete phase, because it might + // throw to suspend, and if the resource immediately loads, the work loop + // will resume rendering as if the work-in-progress completed. So it must + // fully complete. - case ForwardRef: - case SimpleMemoComponent: { - break; + preloadInstanceAndSuspendIfNeeded(workInProgress); + return null; } - case ClassComponent: { - if ((flags & Snapshot) !== NoFlags$1) { - if (current !== null) { - var prevProps = current.memoizedProps; - var prevState = current.memoizedState; - var instance = finishedWork.stateNode; // We could update instance props and state here, - // but instead we rely on them being set during last render. - // TODO: revisit this when we implement resuming. + case HostText: { + var newText = newProps; - { - if ( - finishedWork.type === finishedWork.elementType && - !didWarnAboutReassigningProps - ) { - if (instance.props !== finishedWork.memoizedProps) { - error( - "Expected %s props to match memoized props before " + - "getSnapshotBeforeUpdate. " + - "This might either be because of a bug in React, or because " + - "a component reassigns its own `this.props`. " + - "Please file an issue.", - getComponentNameFromFiber(finishedWork) || "instance" - ); - } + if (current && workInProgress.stateNode != null) { + var oldText = current.memoizedProps; // If we have an alternate, that means this is an update and we need + // to schedule a side-effect to do the updates. - if (instance.state !== finishedWork.memoizedState) { - error( - "Expected %s state to match memoized state before " + - "getSnapshotBeforeUpdate. " + - "This might either be because of a bug in React, or because " + - "a component reassigns its own `this.state`. " + - "Please file an issue.", - getComponentNameFromFiber(finishedWork) || "instance" - ); - } - } - } + updateHostText(current, workInProgress, oldText, newText); + } else { + if (typeof newText !== "string") { + if (workInProgress.stateNode === null) { + throw new Error( + "We must have new props for new mounts. This error is likely " + + "caused by a bug in React. Please file an issue." + ); + } // This can happen when we abort work. + } - var snapshot = instance.getSnapshotBeforeUpdate( - finishedWork.elementType === finishedWork.type - ? prevProps - : resolveDefaultProps(finishedWork.type, prevProps), - prevState - ); + var _rootContainerInstance2 = getRootHostContainer(); - { - var didWarnSet = didWarnAboutUndefinedSnapshotBeforeUpdate; + var _currentHostContext3 = getHostContext(); - if (snapshot === undefined && !didWarnSet.has(finishedWork.type)) { - didWarnSet.add(finishedWork.type); + var _wasHydrated3 = popHydrationState(); - error( - "%s.getSnapshotBeforeUpdate(): A snapshot value (or null) " + - "must be returned. You have returned undefined.", - getComponentNameFromFiber(finishedWork) - ); - } + if (_wasHydrated3) { + if (prepareToHydrateHostTextInstance()) { + markUpdate(workInProgress); } - - instance.__reactInternalSnapshotBeforeUpdate = snapshot; + } else { + workInProgress.stateNode = createTextInstance( + newText, + _rootContainerInstance2, + _currentHostContext3, + workInProgress + ); } } - break; + bubbleProperties(workInProgress); + return null; } - case HostRoot: { - break; - } + case SuspenseComponent: { + popSuspenseHandler(workInProgress); + var nextState = workInProgress.memoizedState; // Special path for dehydrated boundaries. We may eventually move this + // to its own fiber type so that we can add other kinds of hydration + // boundaries that aren't associated with a Suspense tree. In anticipation + // of such a refactor, all the hydration logic is contained in + // this branch. - case HostComponent: - case HostHoistable: - case HostSingleton: - case HostText: - case HostPortal: - case IncompleteClassComponent: - // Nothing to do for these component types - break; + if ( + current === null || + (current.memoizedState !== null && + current.memoizedState.dehydrated !== null) + ) { + var fallthroughToNormalSuspensePath = + completeDehydratedSuspenseBoundary( + current, + workInProgress, + nextState + ); - default: { - if ((flags & Snapshot) !== NoFlags$1) { - throw new Error( - "This unit of work tag should not have side-effects. This error is " + - "likely caused by a bug in React. Please file an issue." - ); + if (!fallthroughToNormalSuspensePath) { + if (workInProgress.flags & ForceClientRender) { + // Special case. There were remaining unhydrated nodes. We treat + // this as a mismatch. Revert to client rendering. + return workInProgress; + } else { + // Did not finish hydrating, either because this is the initial + // render or because something suspended. + return null; + } + } // Continue with the normal Suspense path. } - } - } - if ((flags & Snapshot) !== NoFlags$1) { - resetCurrentFiber(); - } -} + if ((workInProgress.flags & DidCapture) !== NoFlags$1) { + // Something suspended. Re-render with the fallback children. + workInProgress.lanes = renderLanes; // Do not reset the effect list. -function commitHookEffectListUnmount( - flags, - finishedWork, - nearestMountedAncestor -) { - var updateQueue = finishedWork.updateQueue; - var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null; + if ((workInProgress.mode & ProfileMode) !== NoMode) { + transferActualDuration(workInProgress); + } // Don't bubble properties in this case. - if (lastEffect !== null) { - var firstEffect = lastEffect.next; - var effect = firstEffect; + return workInProgress; + } - do { - if ((effect.tag & flags) === flags) { - // Unmount - var destroy = effect.destroy; - effect.destroy = undefined; + var nextDidTimeout = nextState !== null; + var prevDidTimeout = current !== null && current.memoizedState !== null; + // a passive effect, which is when we process the transitions - if (destroy !== undefined) { - { - if ((flags & Passive) !== NoFlags) { - markComponentPassiveEffectUnmountStarted(finishedWork); - } else if ((flags & Layout) !== NoFlags) { - markComponentLayoutEffectUnmountStarted(finishedWork); - } - } + if (nextDidTimeout !== prevDidTimeout) { + // an effect to toggle the subtree's visibility. When we switch from + // fallback -> primary, the inner Offscreen fiber schedules this effect + // as part of its normal complete phase. But when we switch from + // primary -> fallback, the inner Offscreen fiber does not have a complete + // phase. So we need to schedule its effect here. + // + // We also use this flag to connect/disconnect the effects, but the same + // logic applies: when re-connecting, the Offscreen fiber's complete + // phase will handle scheduling the effect. It's only when the fallback + // is active that we have to do anything special. - { - if ((flags & Insertion) !== NoFlags) { - setIsRunningInsertionEffect(true); - } - } + if (nextDidTimeout) { + var _offscreenFiber2 = workInProgress.child; + _offscreenFiber2.flags |= Visibility; + } + } - safelyCallDestroy(finishedWork, nearestMountedAncestor, destroy); + var retryQueue = workInProgress.updateQueue; + scheduleRetryEffect(workInProgress, retryQueue); - { - if ((flags & Insertion) !== NoFlags) { - setIsRunningInsertionEffect(false); - } - } + bubbleProperties(workInProgress); - { - if ((flags & Passive) !== NoFlags) { - markComponentPassiveEffectUnmountStopped(); - } else if ((flags & Layout) !== NoFlags) { - markComponentLayoutEffectUnmountStopped(); + { + if ((workInProgress.mode & ProfileMode) !== NoMode) { + if (nextDidTimeout) { + // Don't count time spent in a timed out Suspense subtree as part of the base duration. + var primaryChildFragment = workInProgress.child; + + if (primaryChildFragment !== null) { + // $FlowFixMe Flow doesn't support type casting in combination with the -= operator + workInProgress.treeBaseDuration -= + primaryChildFragment.treeBaseDuration; } } } } - effect = effect.next; - } while (effect !== firstEffect); - } -} + return null; + } -function commitHookEffectListMount(flags, finishedWork) { - var updateQueue = finishedWork.updateQueue; - var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null; + case HostPortal: + popHostContainer(workInProgress); + updateHostContainer(current, workInProgress); - if (lastEffect !== null) { - var firstEffect = lastEffect.next; - var effect = firstEffect; + bubbleProperties(workInProgress); + return null; - do { - if ((effect.tag & flags) === flags) { - { - if ((flags & Passive) !== NoFlags) { - markComponentPassiveEffectMountStarted(finishedWork); - } else if ((flags & Layout) !== NoFlags) { - markComponentLayoutEffectMountStarted(finishedWork); - } - } // Mount + case ContextProvider: + // Pop provider fiber + var context = workInProgress.type._context; + popProvider(context, workInProgress); + bubbleProperties(workInProgress); + return null; - var create = effect.create; + case IncompleteClassComponent: { + // Same as class component case. I put it down here so that the tags are + // sequential to ensure this switch is compiled to a jump table. + var _Component = workInProgress.type; - { - if ((flags & Insertion) !== NoFlags) { - setIsRunningInsertionEffect(true); - } - } + if (isContextProvider(_Component)) { + popContext(workInProgress); + } - effect.destroy = create(); + bubbleProperties(workInProgress); + return null; + } - { - if ((flags & Insertion) !== NoFlags) { - setIsRunningInsertionEffect(false); - } - } + case SuspenseListComponent: { + popSuspenseListContext(workInProgress); + var renderState = workInProgress.memoizedState; - { - if ((flags & Passive) !== NoFlags) { - markComponentPassiveEffectMountStopped(); - } else if ((flags & Layout) !== NoFlags) { - markComponentLayoutEffectMountStopped(); - } - } + if (renderState === null) { + // We're running in the default, "independent" mode. + // We don't do anything in this mode. + bubbleProperties(workInProgress); + return null; + } - { - var destroy = effect.destroy; + var didSuspendAlready = (workInProgress.flags & DidCapture) !== NoFlags$1; + var renderedTail = renderState.rendering; - if (destroy !== undefined && typeof destroy !== "function") { - var hookName = void 0; + if (renderedTail === null) { + // We just rendered the head. + if (!didSuspendAlready) { + // This is the first pass. We need to figure out if anything is still + // suspended in the rendered set. + // If new content unsuspended, but there's still some content that + // didn't. Then we need to do a second pass that forces everything + // to keep showing their fallbacks. + // We might be suspended if something in this render pass suspended, or + // something in the previous committed pass suspended. Otherwise, + // there's no chance so we can skip the expensive call to + // findFirstSuspended. + var cannotBeSuspended = + renderHasNotSuspendedYet() && + (current === null || (current.flags & DidCapture) === NoFlags$1); - if ((effect.tag & Layout) !== NoFlags$1) { - hookName = "useLayoutEffect"; - } else if ((effect.tag & Insertion) !== NoFlags$1) { - hookName = "useInsertionEffect"; - } else { - hookName = "useEffect"; - } + if (!cannotBeSuspended) { + var row = workInProgress.child; - var addendum = void 0; + while (row !== null) { + var suspended = findFirstSuspended(row); - if (destroy === null) { - addendum = - " You returned null. If your effect does not require clean " + - "up, return undefined (or nothing)."; - } else if (typeof destroy.then === "function") { - addendum = - "\n\nIt looks like you wrote " + - hookName + - "(async () => ...) or returned a Promise. " + - "Instead, write the async function inside your effect " + - "and call it immediately:\n\n" + - hookName + - "(() => {\n" + - " async function fetchData() {\n" + - " // You can await here\n" + - " const response = await MyAPI.getData(someId);\n" + - " // ...\n" + - " }\n" + - " fetchData();\n" + - "}, [someId]); // Or [] if effect doesn't need props or state\n\n" + - "Learn more about data fetching with Hooks: https://reactjs.org/link/hooks-data-fetching"; - } else { - addendum = " You returned: " + destroy; - } + if (suspended !== null) { + didSuspendAlready = true; + workInProgress.flags |= DidCapture; + cutOffTailIfNeeded(renderState, false); // If this is a newly suspended tree, it might not get committed as + // part of the second pass. In that case nothing will subscribe to + // its thenables. Instead, we'll transfer its thenables to the + // SuspenseList so that it can retry if they resolve. + // There might be multiple of these in the list but since we're + // going to wait for all of them anyway, it doesn't really matter + // which ones gets to ping. In theory we could get clever and keep + // track of how many dependencies remain but it gets tricky because + // in the meantime, we can add/remove/change items and dependencies. + // We might bail out of the loop before finding any but that + // doesn't matter since that means that the other boundaries that + // we did find already has their listeners attached. - error( - "%s must not return anything besides a function, " + - "which is used for clean-up.%s", - hookName, - addendum - ); + var _retryQueue = suspended.updateQueue; + workInProgress.updateQueue = _retryQueue; + scheduleRetryEffect(workInProgress, _retryQueue); // Rerender the whole list, but this time, we'll force fallbacks + // to stay in place. + // Reset the effect flags before doing the second pass since that's now invalid. + // Reset the child fibers to their original state. + + workInProgress.subtreeFlags = NoFlags$1; + resetChildFibers(workInProgress, renderLanes); // Set up the Suspense List Context to force suspense and + // immediately rerender the children. + + pushSuspenseListContext( + workInProgress, + setShallowSuspenseListContext( + suspenseStackCursor.current, + ForceSuspenseFallback + ) + ); // Don't bubble properties in this case. + + return workInProgress.child; + } + + row = row.sibling; + } } - } - } - effect = effect.next; - } while (effect !== firstEffect); - } -} + if (renderState.tail !== null && now$1() > getRenderTargetTime()) { + // We have already passed our CPU deadline but we still have rows + // left in the tail. We'll just give up further attempts to render + // the main content and only render fallbacks. + workInProgress.flags |= DidCapture; + didSuspendAlready = true; + cutOffTailIfNeeded(renderState, false); // Since nothing actually suspended, there will nothing to ping this + // to get it started back up to attempt the next item. While in terms + // of priority this work has the same priority as this current render, + // it's not part of the same transition once the transition has + // committed. If it's sync, we still want to yield so that it can be + // painted. Conceptually, this is really the same as pinging. + // We can use any RetryLane even if it's the one currently rendering + // since we're leaving it behind on this node. -function commitPassiveEffectDurations(finishedRoot, finishedWork) { - if (getExecutionContext() & CommitContext) { - // Only Profilers with work in their subtree will have an Update effect scheduled. - if ((finishedWork.flags & Update) !== NoFlags$1) { - switch (finishedWork.tag) { - case Profiler: { - var passiveEffectDuration = - finishedWork.stateNode.passiveEffectDuration; - var _finishedWork$memoize = finishedWork.memoizedProps, - id = _finishedWork$memoize.id, - onPostCommit = _finishedWork$memoize.onPostCommit; // This value will still reflect the previous commit phase. - // It does not get reset until the start of the next commit phase. + workInProgress.lanes = SomeRetryLane; + } + } else { + cutOffTailIfNeeded(renderState, false); + } // Next we're going to render the tail. + } else { + // Append the rendered row to the child list. + if (!didSuspendAlready) { + var _suspended = findFirstSuspended(renderedTail); + + if (_suspended !== null) { + workInProgress.flags |= DidCapture; + didSuspendAlready = true; // Ensure we transfer the update queue to the parent so that it doesn't + // get lost if this row ends up dropped during a second pass. - var commitTime = getCommitTime(); - var phase = finishedWork.alternate === null ? "mount" : "update"; + var _retryQueue2 = _suspended.updateQueue; + workInProgress.updateQueue = _retryQueue2; + scheduleRetryEffect(workInProgress, _retryQueue2); + cutOffTailIfNeeded(renderState, true); // This might have been modified. - { - if (isCurrentUpdateNested()) { - phase = "nested-update"; + if ( + renderState.tail === null && + renderState.tailMode === "hidden" && + !renderedTail.alternate && + !getIsHydrating() // We don't cut it if we're hydrating. + ) { + // We're done. + bubbleProperties(workInProgress); + return null; } - } - - if (typeof onPostCommit === "function") { - onPostCommit(id, phase, passiveEffectDuration, commitTime); - } // Bubble times to the next nearest ancestor Profiler. - // After we process that Profiler, we'll bubble further up. - - var parentFiber = finishedWork.return; + } else if ( + // The time it took to render last row is greater than the remaining + // time we have to render. So rendering one more row would likely + // exceed it. + now$1() * 2 - renderState.renderingStartTime > + getRenderTargetTime() && + renderLanes !== OffscreenLane + ) { + // We have now passed our CPU deadline and we'll just give up further + // attempts to render the main content and only render fallbacks. + // The assumption is that this is usually faster. + workInProgress.flags |= DidCapture; + didSuspendAlready = true; + cutOffTailIfNeeded(renderState, false); // Since nothing actually suspended, there will nothing to ping this + // to get it started back up to attempt the next item. While in terms + // of priority this work has the same priority as this current render, + // it's not part of the same transition once the transition has + // committed. If it's sync, we still want to yield so that it can be + // painted. Conceptually, this is really the same as pinging. + // We can use any RetryLane even if it's the one currently rendering + // since we're leaving it behind on this node. - outer: while (parentFiber !== null) { - switch (parentFiber.tag) { - case HostRoot: - var root = parentFiber.stateNode; - root.passiveEffectDuration += passiveEffectDuration; - break outer; + workInProgress.lanes = SomeRetryLane; + } + } - case Profiler: - var parentStateNode = parentFiber.stateNode; - parentStateNode.passiveEffectDuration += passiveEffectDuration; - break outer; - } + if (renderState.isBackwards) { + // The effect list of the backwards tail will have been added + // to the end. This breaks the guarantee that life-cycles fire in + // sibling order but that isn't a strong guarantee promised by React. + // Especially since these might also just pop in during future commits. + // Append to the beginning of the list. + renderedTail.sibling = workInProgress.child; + workInProgress.child = renderedTail; + } else { + var previousSibling = renderState.last; - parentFiber = parentFiber.return; + if (previousSibling !== null) { + previousSibling.sibling = renderedTail; + } else { + workInProgress.child = renderedTail; } - break; + renderState.last = renderedTail; } } - } - } -} - -function commitHookLayoutEffects(finishedWork, hookFlags) { - // At this point layout effects have already been destroyed (during mutation phase). - // This is done to prevent sibling component effects from interfering with each other, - // e.g. a destroy function in one component should never override a ref set - // by a create function in another component during the same commit. - if (shouldProfile(finishedWork)) { - try { - startLayoutEffectTimer(); - commitHookEffectListMount(hookFlags, finishedWork); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } - recordLayoutEffectDuration(finishedWork); - } else { - try { - commitHookEffectListMount(hookFlags, finishedWork); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } - } -} + if (renderState.tail !== null) { + // We still have tail rows to render. + // Pop a row. + var next = renderState.tail; + renderState.rendering = next; + renderState.tail = next.sibling; + renderState.renderingStartTime = now$1(); + next.sibling = null; // Restore the context. + // TODO: We can probably just avoid popping it instead and only + // setting it the first time we go from not suspended to suspended. -function commitClassLayoutLifecycles(finishedWork, current) { - var instance = finishedWork.stateNode; + var suspenseContext = suspenseStackCursor.current; - if (current === null) { - // We could update instance props and state here, - // but instead we rely on them being set during last render. - // TODO: revisit this when we implement resuming. - { - if ( - finishedWork.type === finishedWork.elementType && - !didWarnAboutReassigningProps - ) { - if (instance.props !== finishedWork.memoizedProps) { - error( - "Expected %s props to match memoized props before " + - "componentDidMount. " + - "This might either be because of a bug in React, or because " + - "a component reassigns its own `this.props`. " + - "Please file an issue.", - getComponentNameFromFiber(finishedWork) || "instance" + if (didSuspendAlready) { + suspenseContext = setShallowSuspenseListContext( + suspenseContext, + ForceSuspenseFallback ); + } else { + suspenseContext = + setDefaultShallowSuspenseListContext(suspenseContext); } - if (instance.state !== finishedWork.memoizedState) { - error( - "Expected %s state to match memoized state before " + - "componentDidMount. " + - "This might either be because of a bug in React, or because " + - "a component reassigns its own `this.state`. " + - "Please file an issue.", - getComponentNameFromFiber(finishedWork) || "instance" - ); - } - } - } + pushSuspenseListContext(workInProgress, suspenseContext); // Do a pass over the next row. + // Don't bubble properties in this case. - if (shouldProfile(finishedWork)) { - try { - startLayoutEffectTimer(); - instance.componentDidMount(); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); + return next; } - recordLayoutEffectDuration(finishedWork); - } else { - try { - instance.componentDidMount(); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } + bubbleProperties(workInProgress); + return null; } - } else { - var prevProps = - finishedWork.elementType === finishedWork.type - ? current.memoizedProps - : resolveDefaultProps(finishedWork.type, current.memoizedProps); - var prevState = current.memoizedState; // We could update instance props and state here, - // but instead we rely on them being set during last render. - // TODO: revisit this when we implement resuming. - { - if ( - finishedWork.type === finishedWork.elementType && - !didWarnAboutReassigningProps - ) { - if (instance.props !== finishedWork.memoizedProps) { - error( - "Expected %s props to match memoized props before " + - "componentDidUpdate. " + - "This might either be because of a bug in React, or because " + - "a component reassigns its own `this.props`. " + - "Please file an issue.", - getComponentNameFromFiber(finishedWork) || "instance" - ); - } + case ScopeComponent: { + break; + } - if (instance.state !== finishedWork.memoizedState) { - error( - "Expected %s state to match memoized state before " + - "componentDidUpdate. " + - "This might either be because of a bug in React, or because " + - "a component reassigns its own `this.state`. " + - "Please file an issue.", - getComponentNameFromFiber(finishedWork) || "instance" - ); + case OffscreenComponent: + case LegacyHiddenComponent: { + popSuspenseHandler(workInProgress); + popHiddenContext(workInProgress); + var _nextState = workInProgress.memoizedState; + var nextIsHidden = _nextState !== null; // Schedule a Visibility effect if the visibility has changed + + if (workInProgress.tag === LegacyHiddenComponent); + else { + if (current !== null) { + var _prevState = current.memoizedState; + var prevIsHidden = _prevState !== null; + + if (prevIsHidden !== nextIsHidden) { + workInProgress.flags |= Visibility; + } + } else { + // On initial mount, we only need a Visibility effect if the tree + // is hidden. + if (nextIsHidden) { + workInProgress.flags |= Visibility; + } } } - } - if (shouldProfile(finishedWork)) { - try { - startLayoutEffectTimer(); - instance.componentDidUpdate( - prevProps, - prevState, - instance.__reactInternalSnapshotBeforeUpdate - ); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); + if (!nextIsHidden || (workInProgress.mode & ConcurrentMode) === NoMode) { + bubbleProperties(workInProgress); + } else { + // Don't bubble properties for hidden children unless we're rendering + // at offscreen priority. + if ( + includesSomeLane(renderLanes, OffscreenLane) && // Also don't bubble if the tree suspended + (workInProgress.flags & DidCapture) === NoLanes + ) { + bubbleProperties(workInProgress); // Check if there was an insertion or update in the hidden subtree. + // If so, we need to hide those nodes in the commit phase, so + // schedule a visibility effect. + + if ( + workInProgress.tag !== LegacyHiddenComponent && + workInProgress.subtreeFlags & (Placement | Update) + ) { + workInProgress.flags |= Visibility; + } + } } - recordLayoutEffectDuration(finishedWork); - } else { - try { - instance.componentDidUpdate( - prevProps, - prevState, - instance.__reactInternalSnapshotBeforeUpdate - ); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); + var offscreenQueue = workInProgress.updateQueue; + + if (offscreenQueue !== null) { + var _retryQueue3 = offscreenQueue.retryQueue; + scheduleRetryEffect(workInProgress, _retryQueue3); } + return null; + } + + case CacheComponent: { + return null; + } + + case TracingMarkerComponent: { + return null; } } + + throw new Error( + "Unknown unit of work tag (" + + workInProgress.tag + + "). This error is likely caused by a bug in " + + "React. Please file an issue." + ); } -function commitClassCallbacks(finishedWork) { - // TODO: I think this is now always non-null by the time it reaches the - // commit phase. Consider removing the type check. - var updateQueue = finishedWork.updateQueue; +function unwindWork(current, workInProgress, renderLanes) { + switch (workInProgress.tag) { + case ClassComponent: { + var Component = workInProgress.type; - if (updateQueue !== null) { - var instance = finishedWork.stateNode; + if (isContextProvider(Component)) { + popContext(workInProgress); + } - { - if ( - finishedWork.type === finishedWork.elementType && - !didWarnAboutReassigningProps - ) { - if (instance.props !== finishedWork.memoizedProps) { - error( - "Expected %s props to match memoized props before " + - "processing the update queue. " + - "This might either be because of a bug in React, or because " + - "a component reassigns its own `this.props`. " + - "Please file an issue.", - getComponentNameFromFiber(finishedWork) || "instance" - ); - } + var flags = workInProgress.flags; - if (instance.state !== finishedWork.memoizedState) { - error( - "Expected %s state to match memoized state before " + - "processing the update queue. " + - "This might either be because of a bug in React, or because " + - "a component reassigns its own `this.state`. " + - "Please file an issue.", - getComponentNameFromFiber(finishedWork) || "instance" - ); + if (flags & ShouldCapture) { + workInProgress.flags = (flags & ~ShouldCapture) | DidCapture; + + if ((workInProgress.mode & ProfileMode) !== NoMode) { + transferActualDuration(workInProgress); } + + return workInProgress; } - } // We could update instance props and state here, - // but instead we rely on them being set during last render. - // TODO: revisit this when we implement resuming. - try { - commitCallbacks(updateQueue, instance); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); + return null; } - } -} -function commitHostComponentMount(finishedWork) { - var type = finishedWork.type; - var props = finishedWork.memoizedProps; - var instance = finishedWork.stateNode; + case HostRoot: { + popHostContainer(workInProgress); + popTopLevelContextObject(workInProgress); + resetWorkInProgressVersions(); + var _flags = workInProgress.flags; - try { - commitMount(instance, type, props, finishedWork); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } -} + if ( + (_flags & ShouldCapture) !== NoFlags$1 && + (_flags & DidCapture) === NoFlags$1 + ) { + // There was an error during render that wasn't captured by a suspense + // boundary. Do a second pass on the root to unmount the children. + workInProgress.flags = (_flags & ~ShouldCapture) | DidCapture; + return workInProgress; + } // We unwound to the root without completing it. Exit. -function commitProfilerUpdate(finishedWork, current) { - if (getExecutionContext() & CommitContext) { - try { - var _finishedWork$memoize2 = finishedWork.memoizedProps, - onCommit = _finishedWork$memoize2.onCommit, - onRender = _finishedWork$memoize2.onRender; - var effectDuration = finishedWork.stateNode.effectDuration; - var commitTime = getCommitTime(); - var phase = current === null ? "mount" : "update"; + return null; + } - if (enableProfilerNestedUpdatePhase) { - if (isCurrentUpdateNested()) { - phase = "nested-update"; + case HostHoistable: + case HostSingleton: + case HostComponent: { + // TODO: popHydrationState + popHostContext(workInProgress); + return null; + } + + case SuspenseComponent: { + popSuspenseHandler(workInProgress); + var suspenseState = workInProgress.memoizedState; + + if (suspenseState !== null && suspenseState.dehydrated !== null) { + if (workInProgress.alternate === null) { + throw new Error( + "Threw in newly mounted dehydrated component. This is likely a bug in " + + "React. Please file an issue." + ); } } - if (typeof onRender === "function") { - onRender( - finishedWork.memoizedProps.id, - phase, - finishedWork.actualDuration, - finishedWork.treeBaseDuration, - finishedWork.actualStartTime, - commitTime - ); - } + var _flags2 = workInProgress.flags; - if (enableProfilerCommitHooks) { - if (typeof onCommit === "function") { - onCommit( - finishedWork.memoizedProps.id, - phase, - effectDuration, - commitTime - ); - } // Schedule a passive effect for this Profiler to call onPostCommit hooks. - // This effect should be scheduled even if there is no onPostCommit callback for this Profiler, - // because the effect is also where times bubble to parent Profilers. + if (_flags2 & ShouldCapture) { + workInProgress.flags = (_flags2 & ~ShouldCapture) | DidCapture; // Captured a suspense effect. Re-render the boundary. - enqueuePendingPassiveProfilerEffect(finishedWork); // Propagate layout effect durations to the next nearest Profiler ancestor. - // Do not reset these values until the next render so DevTools has a chance to read them first. + if ((workInProgress.mode & ProfileMode) !== NoMode) { + transferActualDuration(workInProgress); + } - var parentFiber = finishedWork.return; + return workInProgress; + } - outer: while (parentFiber !== null) { - switch (parentFiber.tag) { - case HostRoot: - var root = parentFiber.stateNode; - root.effectDuration += effectDuration; - break outer; + return null; + } - case Profiler: - var parentStateNode = parentFiber.stateNode; - parentStateNode.effectDuration += effectDuration; - break outer; - } + case SuspenseListComponent: { + popSuspenseListContext(workInProgress); // SuspenseList doesn't actually catch anything. It should've been + // caught by a nested boundary. If not, it should bubble through. - parentFiber = parentFiber.return; - } - } - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); + return null; } - } -} -function commitLayoutEffectOnFiber( - finishedRoot, - current, - finishedWork, - committedLanes -) { - // When updating this function, also update reappearLayoutEffects, which does - // most of the same things when an offscreen tree goes from hidden -> visible. - var flags = finishedWork.flags; + case HostPortal: + popHostContainer(workInProgress); + return null; - switch (finishedWork.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); + case ContextProvider: + var context = workInProgress.type._context; + popProvider(context, workInProgress); + return null; - if (flags & Update) { - commitHookLayoutEffects(finishedWork, Layout | HasEffect); + case OffscreenComponent: + case LegacyHiddenComponent: { + popSuspenseHandler(workInProgress); + popHiddenContext(workInProgress); + var _flags3 = workInProgress.flags; + + if (_flags3 & ShouldCapture) { + workInProgress.flags = (_flags3 & ~ShouldCapture) | DidCapture; // Captured a suspense effect. Re-render the boundary. + + if ((workInProgress.mode & ProfileMode) !== NoMode) { + transferActualDuration(workInProgress); + } + + return workInProgress; } - break; + return null; } - case ClassComponent: { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); + case CacheComponent: + return null; - if (flags & Update) { - commitClassLayoutLifecycles(finishedWork, current); - } + case TracingMarkerComponent: + return null; - if (flags & Callback) { - commitClassCallbacks(finishedWork); - } + default: + return null; + } +} + +function unwindInterruptedWork(current, interruptedWork, renderLanes) { + switch (interruptedWork.tag) { + case ClassComponent: { + var childContextTypes = interruptedWork.type.childContextTypes; - if (flags & Ref) { - safelyAttachRef(finishedWork, finishedWork.return); + if (childContextTypes !== null && childContextTypes !== undefined) { + popContext(interruptedWork); } break; } case HostRoot: { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); - - if (flags & Callback) { - // TODO: I think this is now always non-null by the time it reaches the - // commit phase. Consider removing the type check. - var updateQueue = finishedWork.updateQueue; - - if (updateQueue !== null) { - var instance = null; - - if (finishedWork.child !== null) { - switch (finishedWork.child.tag) { - case HostSingleton: - case HostComponent: - instance = getPublicInstance(finishedWork.child.stateNode); - break; - - case ClassComponent: - instance = finishedWork.child.stateNode; - break; - } - } - - try { - commitCallbacks(updateQueue, instance); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } - } - } - + popHostContainer(interruptedWork); + popTopLevelContextObject(interruptedWork); + resetWorkInProgressVersions(); break; } case HostHoistable: - // eslint-disable-next-line-no-fallthrough - case HostSingleton: case HostComponent: { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); // Renderers may schedule work to be done after host components are mounted - // (eg DOM renderer may schedule auto-focus for inputs and form controls). - // These effects should only be committed when components are first mounted, - // aka when there is no current/alternate. - - if (current === null && flags & Update) { - commitHostComponentMount(finishedWork); - } - - if (flags & Ref) { - safelyAttachRef(finishedWork, finishedWork.return); - } - + popHostContext(interruptedWork); break; } - case Profiler: { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); // TODO: Should this fire inside an offscreen tree? Or should it wait to - // fire when the tree becomes visible again. + case HostPortal: + popHostContainer(interruptedWork); + break; - if (flags & Update) { - commitProfilerUpdate(finishedWork, current); - } + case SuspenseComponent: + popSuspenseHandler(interruptedWork); + break; + case SuspenseListComponent: + popSuspenseListContext(interruptedWork); break; - } - case SuspenseComponent: { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); + case ContextProvider: + var context = interruptedWork.type._context; + popProvider(context, interruptedWork); + break; + case OffscreenComponent: + case LegacyHiddenComponent: + popSuspenseHandler(interruptedWork); + popHiddenContext(interruptedWork); break; - } + } +} - case OffscreenComponent: { - var isModernRoot = (finishedWork.mode & ConcurrentMode) !== NoMode; +var didWarnAboutUndefinedSnapshotBeforeUpdate = null; - if (isModernRoot) { - var isHidden = finishedWork.memoizedState !== null; - var newOffscreenSubtreeIsHidden = isHidden || offscreenSubtreeIsHidden; +{ + didWarnAboutUndefinedSnapshotBeforeUpdate = new Set(); +} // Used during the commit phase to track the state of the Offscreen component stack. +// Allows us to avoid traversing the return path to find the nearest Offscreen ancestor. - if (newOffscreenSubtreeIsHidden); - else { - // The Offscreen tree is visible. - var wasHidden = current !== null && current.memoizedState !== null; - var newOffscreenSubtreeWasHidden = - wasHidden || offscreenSubtreeWasHidden; - var prevOffscreenSubtreeIsHidden = offscreenSubtreeIsHidden; - var prevOffscreenSubtreeWasHidden = offscreenSubtreeWasHidden; - offscreenSubtreeIsHidden = newOffscreenSubtreeIsHidden; - offscreenSubtreeWasHidden = newOffscreenSubtreeWasHidden; +var offscreenSubtreeIsHidden = false; +var offscreenSubtreeWasHidden = false; +var PossiblyWeakSet = typeof WeakSet === "function" ? WeakSet : Set; +var nextEffect = null; // Used for Profiling builds to track updaters. - if (offscreenSubtreeWasHidden && !prevOffscreenSubtreeWasHidden) { - // This is the root of a reappearing boundary. As we continue - // traversing the layout effects, we must also re-mount layout - // effects that were unmounted when the Offscreen subtree was - // hidden. So this is a superset of the normal commitLayoutEffects. - var includeWorkInProgressEffects = - (finishedWork.subtreeFlags & LayoutMask) !== NoFlags$1; - recursivelyTraverseReappearLayoutEffects( - finishedRoot, - finishedWork, - includeWorkInProgressEffects - ); - } else { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); - } +var inProgressLanes = null; +var inProgressRoot = null; - offscreenSubtreeIsHidden = prevOffscreenSubtreeIsHidden; - offscreenSubtreeWasHidden = prevOffscreenSubtreeWasHidden; - } - } else { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); - } +function shouldProfile(current) { + return ( + (current.mode & ProfileMode) !== NoMode && + (getExecutionContext() & CommitContext) !== NoContext + ); +} - if (flags & Ref) { - var props = finishedWork.memoizedProps; +function reportUncaughtErrorInDEV(error) { + // Wrapping each small part of the commit phase into a guarded + // callback is a bit too slow (https://github.com/facebook/react/pull/21666). + // But we rely on it to surface errors to DEV tools like overlays + // (https://github.com/facebook/react/issues/21712). + // As a compromise, rethrow only caught errors in a guard. + { + invokeGuardedCallback(null, function () { + throw error; + }); + clearCaughtError(); + } +} - if (props.mode === "manual") { - safelyAttachRef(finishedWork, finishedWork.return); - } else { - safelyDetachRef(finishedWork, finishedWork.return); - } - } +function callComponentWillUnmountWithTimer(current, instance) { + instance.props = current.memoizedProps; + instance.state = current.memoizedState; - break; + if (shouldProfile(current)) { + try { + startLayoutEffectTimer(); + instance.componentWillUnmount(); + } finally { + recordLayoutEffectDuration(current); } + } else { + instance.componentWillUnmount(); + } +} // Capture errors so they don't interrupt unmounting. - default: { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); - break; - } +function safelyCallComponentWillUnmount( + current, + nearestMountedAncestor, + instance +) { + try { + callComponentWillUnmountWithTimer(current, instance); + } catch (error) { + captureCommitPhaseError(current, nearestMountedAncestor, error); + } +} // Capture errors so they don't interrupt mounting. + +function safelyAttachRef(current, nearestMountedAncestor) { + try { + commitAttachRef(current); + } catch (error) { + captureCommitPhaseError(current, nearestMountedAncestor, error); } } -function commitAttachRef(finishedWork) { - var ref = finishedWork.ref; +function safelyDetachRef(current, nearestMountedAncestor) { + var ref = current.ref; + var refCleanup = current.refCleanup; if (ref !== null) { - var instance = finishedWork.stateNode; - var instanceToUse; - - switch (finishedWork.tag) { - case HostHoistable: - case HostSingleton: - case HostComponent: - instanceToUse = getPublicInstance(instance); - break; + if (typeof refCleanup === "function") { + try { + if (shouldProfile(current)) { + try { + startLayoutEffectTimer(); + refCleanup(); + } finally { + recordLayoutEffectDuration(current); + } + } else { + refCleanup(); + } + } catch (error) { + captureCommitPhaseError(current, nearestMountedAncestor, error); + } finally { + // `refCleanup` has been called. Nullify all references to it to prevent double invocation. + current.refCleanup = null; + var finishedWork = current.alternate; - default: - instanceToUse = instance; - } // Moved outside to ensure DCE works with this flag + if (finishedWork != null) { + finishedWork.refCleanup = null; + } + } + } else if (typeof ref === "function") { + var retVal; - if (typeof ref === "function") { - if (shouldProfile(finishedWork)) { - try { - startLayoutEffectTimer(); - finishedWork.refCleanup = ref(instanceToUse); - } finally { - recordLayoutEffectDuration(finishedWork); + try { + if (shouldProfile(current)) { + try { + startLayoutEffectTimer(); + retVal = ref(null); + } finally { + recordLayoutEffectDuration(current); + } + } else { + retVal = ref(null); } - } else { - finishedWork.refCleanup = ref(instanceToUse); + } catch (error) { + captureCommitPhaseError(current, nearestMountedAncestor, error); } - } else { + { - if (!ref.hasOwnProperty("current")) { + if (typeof retVal === "function") { error( - "Unexpected ref object provided for %s. " + - "Use either a ref-setter function or React.createRef().", - getComponentNameFromFiber(finishedWork) + "Unexpected return value from a callback ref in %s. " + + "A callback ref should not return a function.", + getComponentNameFromFiber(current) ); } - } // $FlowFixMe unable to narrow type to the non-function case - - ref.current = instanceToUse; + } + } else { + // $FlowFixMe unable to narrow type to RefObject + ref.current = null; } } } -function detachFiberMutation(fiber) { - // Cut off the return pointer to disconnect it from the tree. - // This enables us to detect and warn against state updates on an unmounted component. - // It also prevents events from bubbling from within disconnected components. - // - // Ideally, we should also clear the child pointer of the parent alternate to let this - // get GC:ed but we don't know which for sure which parent is the current - // one so we'll settle for GC:ing the subtree of this child. - // This child itself will be GC:ed when the parent updates the next time. - // - // Note that we can't clear child or sibling pointers yet. - // They're needed for passive effects and for findDOMNode. - // We defer those fields, and all other cleanup, to the passive phase (see detachFiberAfterEffects). - // - // Don't reset the alternate yet, either. We need that so we can detach the - // alternate's fields in the passive phase. Clearing the return pointer is - // sufficient for findDOMNode semantics. - var alternate = fiber.alternate; - - if (alternate !== null) { - alternate.return = null; +function safelyCallDestroy(current, nearestMountedAncestor, destroy) { + try { + destroy(); + } catch (error) { + captureCommitPhaseError(current, nearestMountedAncestor, error); } - - fiber.return = null; -} - -function detachFiberAfterEffects(fiber) { - var alternate = fiber.alternate; - - if (alternate !== null) { - fiber.alternate = null; - detachFiberAfterEffects(alternate); - } // Clear cyclical Fiber fields. This level alone is designed to roughly - // approximate the planned Fiber refactor. In that world, `setState` will be - // bound to a special "instance" object instead of a Fiber. The Instance - // object will not have any of these fields. It will only be connected to - // the fiber tree via a single link at the root. So if this level alone is - // sufficient to fix memory issues, that bodes well for our plans. - - fiber.child = null; - fiber.deletions = null; - fiber.sibling = null; // The `stateNode` is cyclical because on host nodes it points to the host - - fiber.stateNode = null; - - { - fiber._debugOwner = null; - } // Theoretically, nothing in here should be necessary, because we already - // disconnected the fiber from the tree. So even if something leaks this - // particular fiber, it won't leak anything else. - - fiber.return = null; - fiber.dependencies = null; - fiber.memoizedProps = null; - fiber.memoizedState = null; - fiber.pendingProps = null; - fiber.stateNode = null; // TODO: Move to `commitPassiveUnmountInsideDeletedTreeOnFiber` instead. - - fiber.updateQueue = null; -} - -function emptyPortalContainer(current) { - var portal = current.stateNode; - var containerInfo = portal.containerInfo; - createContainerChildSet(containerInfo); } +var shouldFireAfterActiveInstanceBlur = false; +function commitBeforeMutationEffects(root, firstChild) { + nextEffect = firstChild; + commitBeforeMutationEffects_begin(); // We no longer need to track the active instance fiber -function commitPlacement(finishedWork) { - { - return; - } + var shouldFire = shouldFireAfterActiveInstanceBlur; + shouldFireAfterActiveInstanceBlur = false; + return shouldFire; } -function commitDeletionEffects(root, returnFiber, deletedFiber) { - { - // Detach refs and call componentWillUnmount() on the whole subtree. - commitDeletionEffectsOnFiber(root, returnFiber, deletedFiber); - } - - detachFiberMutation(deletedFiber); -} +function commitBeforeMutationEffects_begin() { + while (nextEffect !== null) { + var fiber = nextEffect; // This phase is only used for beforeActiveInstanceBlur. -function recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - parent -) { - // TODO: Use a static flag to skip trees that don't have unmount effects - var child = parent.child; + var child = fiber.child; - while (child !== null) { - commitDeletionEffectsOnFiber(finishedRoot, nearestMountedAncestor, child); - child = child.sibling; + if ( + (fiber.subtreeFlags & BeforeMutationMask) !== NoFlags$1 && + child !== null + ) { + child.return = fiber; + nextEffect = child; + } else { + commitBeforeMutationEffects_complete(); + } } } -function commitDeletionEffectsOnFiber( - finishedRoot, - nearestMountedAncestor, - deletedFiber -) { - onCommitUnmount(deletedFiber); // The cases in this outer switch modify the stack before they traverse - // into their subtree. There are simpler cases in the inner switch - // that don't modify the stack. - - switch (deletedFiber.tag) { - case HostHoistable: - // eslint-disable-next-line no-fallthrough - - case HostSingleton: - // eslint-disable-next-line no-fallthrough +function commitBeforeMutationEffects_complete() { + while (nextEffect !== null) { + var fiber = nextEffect; + setCurrentFiber(fiber); - case HostComponent: { - if (!offscreenSubtreeWasHidden) { - safelyDetachRef(deletedFiber, nearestMountedAncestor); - } // Intentional fallthrough to next branch + try { + commitBeforeMutationEffectsOnFiber(fiber); + } catch (error) { + captureCommitPhaseError(fiber, fiber.return, error); } - // eslint-disable-next-line-no-fallthrough - case HostText: { - // We only need to remove the nearest host child. Set the host parent - // to `null` on the stack to indicate that nested children don't - // need to be removed. - { - recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - deletedFiber - ); - } + resetCurrentFiber(); + var sibling = fiber.sibling; + if (sibling !== null) { + sibling.return = fiber.return; + nextEffect = sibling; return; } - case DehydratedFragment: { - return; - } + nextEffect = fiber.return; + } +} - case HostPortal: { - { - emptyPortalContainer(deletedFiber); - recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - deletedFiber - ); - } +function commitBeforeMutationEffectsOnFiber(finishedWork) { + var current = finishedWork.alternate; + var flags = finishedWork.flags; - return; + if ((flags & Snapshot) !== NoFlags$1) { + setCurrentFiber(finishedWork); + } + + switch (finishedWork.tag) { + case FunctionComponent: { + break; } - case FunctionComponent: case ForwardRef: - case MemoComponent: case SimpleMemoComponent: { - if (!offscreenSubtreeWasHidden) { - var updateQueue = deletedFiber.updateQueue; - - if (updateQueue !== null) { - var lastEffect = updateQueue.lastEffect; - - if (lastEffect !== null) { - var firstEffect = lastEffect.next; - var effect = firstEffect; - - do { - var _effect = effect, - destroy = _effect.destroy, - tag = _effect.tag; - - if (destroy !== undefined) { - if ((tag & Insertion) !== NoFlags) { - safelyCallDestroy( - deletedFiber, - nearestMountedAncestor, - destroy - ); - } else if ((tag & Layout) !== NoFlags) { - { - markComponentLayoutEffectUnmountStarted(deletedFiber); - } - - if (shouldProfile(deletedFiber)) { - startLayoutEffectTimer(); - safelyCallDestroy( - deletedFiber, - nearestMountedAncestor, - destroy - ); - recordLayoutEffectDuration(deletedFiber); - } else { - safelyCallDestroy( - deletedFiber, - nearestMountedAncestor, - destroy - ); - } + break; + } - { - markComponentLayoutEffectUnmountStopped(); - } - } + case ClassComponent: { + if ((flags & Snapshot) !== NoFlags$1) { + if (current !== null) { + var prevProps = current.memoizedProps; + var prevState = current.memoizedState; + var instance = finishedWork.stateNode; // We could update instance props and state here, + // but instead we rely on them being set during last render. + // TODO: revisit this when we implement resuming. + + { + if ( + finishedWork.type === finishedWork.elementType && + !didWarnAboutReassigningProps + ) { + if (instance.props !== finishedWork.memoizedProps) { + error( + "Expected %s props to match memoized props before " + + "getSnapshotBeforeUpdate. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentNameFromFiber(finishedWork) || "instance" + ); } - effect = effect.next; - } while (effect !== firstEffect); + if (instance.state !== finishedWork.memoizedState) { + error( + "Expected %s state to match memoized state before " + + "getSnapshotBeforeUpdate. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.state`. " + + "Please file an issue.", + getComponentNameFromFiber(finishedWork) || "instance" + ); + } + } } - } - } - recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - deletedFiber - ); - return; - } + var snapshot = instance.getSnapshotBeforeUpdate( + finishedWork.elementType === finishedWork.type + ? prevProps + : resolveDefaultProps(finishedWork.type, prevProps), + prevState + ); - case ClassComponent: { - if (!offscreenSubtreeWasHidden) { - safelyDetachRef(deletedFiber, nearestMountedAncestor); - var instance = deletedFiber.stateNode; + { + var didWarnSet = didWarnAboutUndefinedSnapshotBeforeUpdate; - if (typeof instance.componentWillUnmount === "function") { - safelyCallComponentWillUnmount( - deletedFiber, - nearestMountedAncestor, - instance - ); + if (snapshot === undefined && !didWarnSet.has(finishedWork.type)) { + didWarnSet.add(finishedWork.type); + + error( + "%s.getSnapshotBeforeUpdate(): A snapshot value (or null) " + + "must be returned. You have returned undefined.", + getComponentNameFromFiber(finishedWork) + ); + } + } + + instance.__reactInternalSnapshotBeforeUpdate = snapshot; } } - recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - deletedFiber - ); - return; + break; } - case ScopeComponent: { - recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - deletedFiber - ); - return; + case HostRoot: { + break; } - case OffscreenComponent: { - safelyDetachRef(deletedFiber, nearestMountedAncestor); + case HostComponent: + case HostHoistable: + case HostSingleton: + case HostText: + case HostPortal: + case IncompleteClassComponent: + // Nothing to do for these component types + break; - if (deletedFiber.mode & ConcurrentMode) { - // If this offscreen component is hidden, we already unmounted it. Before - // deleting the children, track that it's already unmounted so that we - // don't attempt to unmount the effects again. - // TODO: If the tree is hidden, in most cases we should be able to skip - // over the nested children entirely. An exception is we haven't yet found - // the topmost host node to delete, which we already track on the stack. - // But the other case is portals, which need to be detached no matter how - // deeply they are nested. We should use a subtree flag to track whether a - // subtree includes a nested portal. - var prevOffscreenSubtreeWasHidden = offscreenSubtreeWasHidden; - offscreenSubtreeWasHidden = - prevOffscreenSubtreeWasHidden || deletedFiber.memoizedState !== null; - recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - deletedFiber - ); - offscreenSubtreeWasHidden = prevOffscreenSubtreeWasHidden; - } else { - recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - deletedFiber + default: { + if ((flags & Snapshot) !== NoFlags$1) { + throw new Error( + "This unit of work tag should not have side-effects. This error is " + + "likely caused by a bug in React. Please file an issue." ); } - - break; } + } - default: { - recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - deletedFiber - ); - return; - } + if ((flags & Snapshot) !== NoFlags$1) { + resetCurrentFiber(); } } -function commitSuspenseCallback(finishedWork) {} +function commitHookEffectListUnmount( + flags, + finishedWork, + nearestMountedAncestor +) { + var updateQueue = finishedWork.updateQueue; + var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null; -function getRetryCache(finishedWork) { - // TODO: Unify the interface for the retry cache so we don't have to switch - // on the tag like this. - switch (finishedWork.tag) { - case SuspenseComponent: - case SuspenseListComponent: { - var retryCache = finishedWork.stateNode; + if (lastEffect !== null) { + var firstEffect = lastEffect.next; + var effect = firstEffect; - if (retryCache === null) { - retryCache = finishedWork.stateNode = new PossiblyWeakSet(); - } + do { + if ((effect.tag & flags) === flags) { + // Unmount + var destroy = effect.destroy; + effect.destroy = undefined; - return retryCache; - } + if (destroy !== undefined) { + { + if ((flags & Passive) !== NoFlags) { + markComponentPassiveEffectUnmountStarted(finishedWork); + } else if ((flags & Layout) !== NoFlags) { + markComponentLayoutEffectUnmountStarted(finishedWork); + } + } - case OffscreenComponent: { - var instance = finishedWork.stateNode; - var _retryCache = instance._retryCache; + { + if ((flags & Insertion) !== NoFlags) { + setIsRunningInsertionEffect(true); + } + } - if (_retryCache === null) { - _retryCache = instance._retryCache = new PossiblyWeakSet(); - } + safelyCallDestroy(finishedWork, nearestMountedAncestor, destroy); - return _retryCache; - } + { + if ((flags & Insertion) !== NoFlags) { + setIsRunningInsertionEffect(false); + } + } - default: { - throw new Error( - "Unexpected Suspense handler tag (" + - finishedWork.tag + - "). This is a " + - "bug in React." - ); - } + { + if ((flags & Passive) !== NoFlags) { + markComponentPassiveEffectUnmountStopped(); + } else if ((flags & Layout) !== NoFlags) { + markComponentLayoutEffectUnmountStopped(); + } + } + } + } + + effect = effect.next; + } while (effect !== firstEffect); } } -function detachOffscreenInstance(instance) { - var fiber = instance._current; +function commitHookEffectListMount(flags, finishedWork) { + var updateQueue = finishedWork.updateQueue; + var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null; - if (fiber === null) { - throw new Error( - "Calling Offscreen.detach before instance handle has been set." - ); - } + if (lastEffect !== null) { + var firstEffect = lastEffect.next; + var effect = firstEffect; - if ((instance._pendingVisibility & OffscreenDetached) !== NoFlags$1) { - // The instance is already detached, this is a noop. - return; - } // TODO: There is an opportunity to optimise this by not entering commit phase - // and unmounting effects directly. + do { + if ((effect.tag & flags) === flags) { + { + if ((flags & Passive) !== NoFlags) { + markComponentPassiveEffectMountStarted(finishedWork); + } else if ((flags & Layout) !== NoFlags) { + markComponentLayoutEffectMountStarted(finishedWork); + } + } // Mount - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + var create = effect.create; - if (root !== null) { - instance._pendingVisibility |= OffscreenDetached; - scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); - } -} -function attachOffscreenInstance(instance) { - var fiber = instance._current; + { + if ((flags & Insertion) !== NoFlags) { + setIsRunningInsertionEffect(true); + } + } + + effect.destroy = create(); + + { + if ((flags & Insertion) !== NoFlags) { + setIsRunningInsertionEffect(false); + } + } - if (fiber === null) { - throw new Error( - "Calling Offscreen.detach before instance handle has been set." - ); - } + { + if ((flags & Passive) !== NoFlags) { + markComponentPassiveEffectMountStopped(); + } else if ((flags & Layout) !== NoFlags) { + markComponentLayoutEffectMountStopped(); + } + } - if ((instance._pendingVisibility & OffscreenDetached) === NoFlags$1) { - // The instance is already attached, this is a noop. - return; - } + { + var destroy = effect.destroy; - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + if (destroy !== undefined && typeof destroy !== "function") { + var hookName = void 0; - if (root !== null) { - instance._pendingVisibility &= ~OffscreenDetached; - scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); - } -} + if ((effect.tag & Layout) !== NoFlags$1) { + hookName = "useLayoutEffect"; + } else if ((effect.tag & Insertion) !== NoFlags$1) { + hookName = "useInsertionEffect"; + } else { + hookName = "useEffect"; + } -function attachSuspenseRetryListeners(finishedWork, wakeables) { - // If this boundary just timed out, then it will have a set of wakeables. - // For each wakeable, attach a listener so that when it resolves, React - // attempts to re-render the boundary in the primary (pre-timeout) state. - var retryCache = getRetryCache(finishedWork); - wakeables.forEach(function (wakeable) { - // Memoize using the boundary fiber to prevent redundant listeners. - var retry = resolveRetryWakeable.bind(null, finishedWork, wakeable); + var addendum = void 0; - if (!retryCache.has(wakeable)) { - retryCache.add(wakeable); + if (destroy === null) { + addendum = + " You returned null. If your effect does not require clean " + + "up, return undefined (or nothing)."; + } else if (typeof destroy.then === "function") { + addendum = + "\n\nIt looks like you wrote " + + hookName + + "(async () => ...) or returned a Promise. " + + "Instead, write the async function inside your effect " + + "and call it immediately:\n\n" + + hookName + + "(() => {\n" + + " async function fetchData() {\n" + + " // You can await here\n" + + " const response = await MyAPI.getData(someId);\n" + + " // ...\n" + + " }\n" + + " fetchData();\n" + + "}, [someId]); // Or [] if effect doesn't need props or state\n\n" + + "Learn more about data fetching with Hooks: https://reactjs.org/link/hooks-data-fetching"; + } else { + addendum = " You returned: " + destroy; + } - { - if (isDevToolsPresent) { - if (inProgressLanes !== null && inProgressRoot !== null) { - // If we have pending work still, associate the original updaters with it. - restorePendingUpdaters(inProgressRoot, inProgressLanes); - } else { - throw Error( - "Expected finished root and lanes to be set. This is a bug in React." + error( + "%s must not return anything besides a function, " + + "which is used for clean-up.%s", + hookName, + addendum ); } } } - wakeable.then(retry, retry); - } - }); -} // This function detects when a Suspense boundary goes from visible to hidden. -function commitMutationEffects(root, finishedWork, committedLanes) { - inProgressLanes = committedLanes; - inProgressRoot = root; - setCurrentFiber(finishedWork); - commitMutationEffectsOnFiber(finishedWork, root); - setCurrentFiber(finishedWork); - inProgressLanes = null; - inProgressRoot = null; + effect = effect.next; + } while (effect !== firstEffect); + } } -function recursivelyTraverseMutationEffects(root, parentFiber, lanes) { - // Deletions effects can be scheduled on any fiber type. They need to happen - // before the children effects hae fired. - var deletions = parentFiber.deletions; +function commitPassiveEffectDurations(finishedRoot, finishedWork) { + if (getExecutionContext() & CommitContext) { + // Only Profilers with work in their subtree will have an Update effect scheduled. + if ((finishedWork.flags & Update) !== NoFlags$1) { + switch (finishedWork.tag) { + case Profiler: { + var passiveEffectDuration = + finishedWork.stateNode.passiveEffectDuration; + var _finishedWork$memoize = finishedWork.memoizedProps, + id = _finishedWork$memoize.id, + onPostCommit = _finishedWork$memoize.onPostCommit; // This value will still reflect the previous commit phase. + // It does not get reset until the start of the next commit phase. - if (deletions !== null) { - for (var i = 0; i < deletions.length; i++) { - var childToDelete = deletions[i]; + var commitTime = getCommitTime(); + var phase = finishedWork.alternate === null ? "mount" : "update"; - try { - commitDeletionEffects(root, parentFiber, childToDelete); - } catch (error) { - captureCommitPhaseError(childToDelete, parentFiber, error); + { + if (isCurrentUpdateNested()) { + phase = "nested-update"; + } + } + + if (typeof onPostCommit === "function") { + onPostCommit(id, phase, passiveEffectDuration, commitTime); + } // Bubble times to the next nearest ancestor Profiler. + // After we process that Profiler, we'll bubble further up. + + var parentFiber = finishedWork.return; + + outer: while (parentFiber !== null) { + switch (parentFiber.tag) { + case HostRoot: + var root = parentFiber.stateNode; + root.passiveEffectDuration += passiveEffectDuration; + break outer; + + case Profiler: + var parentStateNode = parentFiber.stateNode; + parentStateNode.passiveEffectDuration += passiveEffectDuration; + break outer; + } + + parentFiber = parentFiber.return; + } + + break; + } } } } +} - var prevDebugFiber = getCurrentFiber(); - - if (parentFiber.subtreeFlags & MutationMask) { - var child = parentFiber.child; +function commitHookLayoutEffects(finishedWork, hookFlags) { + // At this point layout effects have already been destroyed (during mutation phase). + // This is done to prevent sibling component effects from interfering with each other, + // e.g. a destroy function in one component should never override a ref set + // by a create function in another component during the same commit. + if (shouldProfile(finishedWork)) { + try { + startLayoutEffectTimer(); + commitHookEffectListMount(hookFlags, finishedWork); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } - while (child !== null) { - setCurrentFiber(child); - commitMutationEffectsOnFiber(child, root); - child = child.sibling; + recordLayoutEffectDuration(finishedWork); + } else { + try { + commitHookEffectListMount(hookFlags, finishedWork); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); } } - - setCurrentFiber(prevDebugFiber); } -function commitMutationEffectsOnFiber(finishedWork, root, lanes) { - var current = finishedWork.alternate; - var flags = finishedWork.flags; // The effect flag should be checked *after* we refine the type of fiber, - // because the fiber tag is more specific. An exception is any flag related - // to reconciliation, because those can be set on all fiber types. - - switch (finishedWork.tag) { - case FunctionComponent: - case ForwardRef: - case MemoComponent: - case SimpleMemoComponent: { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); +function commitClassLayoutLifecycles(finishedWork, current) { + var instance = finishedWork.stateNode; - if (flags & Update) { - try { - commitHookEffectListUnmount( - Insertion | HasEffect, - finishedWork, - finishedWork.return + if (current === null) { + // We could update instance props and state here, + // but instead we rely on them being set during last render. + // TODO: revisit this when we implement resuming. + { + if ( + finishedWork.type === finishedWork.elementType && + !didWarnAboutReassigningProps + ) { + if (instance.props !== finishedWork.memoizedProps) { + error( + "Expected %s props to match memoized props before " + + "componentDidMount. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentNameFromFiber(finishedWork) || "instance" ); - commitHookEffectListMount(Insertion | HasEffect, finishedWork); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } // Layout effects are destroyed during the mutation phase so that all - // destroy functions for all fibers are called before any create functions. - // This prevents sibling component effects from interfering with each other, - // e.g. a destroy function in one component should never override a ref set - // by a create function in another component during the same commit. - - if (shouldProfile(finishedWork)) { - try { - startLayoutEffectTimer(); - commitHookEffectListUnmount( - Layout | HasEffect, - finishedWork, - finishedWork.return - ); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } + } - recordLayoutEffectDuration(finishedWork); - } else { - try { - commitHookEffectListUnmount( - Layout | HasEffect, - finishedWork, - finishedWork.return - ); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } + if (instance.state !== finishedWork.memoizedState) { + error( + "Expected %s state to match memoized state before " + + "componentDidMount. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.state`. " + + "Please file an issue.", + getComponentNameFromFiber(finishedWork) || "instance" + ); } } - - return; } - case ClassComponent: { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); - - if (flags & Ref) { - if (current !== null) { - safelyDetachRef(current, current.return); - } + if (shouldProfile(finishedWork)) { + try { + startLayoutEffectTimer(); + instance.componentDidMount(); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); } - if (flags & Callback && offscreenSubtreeIsHidden) { - var updateQueue = finishedWork.updateQueue; - - if (updateQueue !== null) { - deferHiddenCallbacks(updateQueue); - } + recordLayoutEffectDuration(finishedWork); + } else { + try { + instance.componentDidMount(); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); } - - return; } + } else { + var prevProps = + finishedWork.elementType === finishedWork.type + ? current.memoizedProps + : resolveDefaultProps(finishedWork.type, current.memoizedProps); + var prevState = current.memoizedState; // We could update instance props and state here, + // but instead we rely on them being set during last render. + // TODO: revisit this when we implement resuming. - case HostHoistable: - // eslint-disable-next-line-no-fallthrough - - case HostSingleton: - // eslint-disable-next-line-no-fallthrough - - case HostComponent: { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); + { + if ( + finishedWork.type === finishedWork.elementType && + !didWarnAboutReassigningProps + ) { + if (instance.props !== finishedWork.memoizedProps) { + error( + "Expected %s props to match memoized props before " + + "componentDidUpdate. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentNameFromFiber(finishedWork) || "instance" + ); + } - if (flags & Ref) { - if (current !== null) { - safelyDetachRef(current, current.return); + if (instance.state !== finishedWork.memoizedState) { + error( + "Expected %s state to match memoized state before " + + "componentDidUpdate. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.state`. " + + "Please file an issue.", + getComponentNameFromFiber(finishedWork) || "instance" + ); } } - - return; } - case HostText: { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); + if (shouldProfile(finishedWork)) { + try { + startLayoutEffectTimer(); + instance.componentDidUpdate( + prevProps, + prevState, + instance.__reactInternalSnapshotBeforeUpdate + ); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } - return; + recordLayoutEffectDuration(finishedWork); + } else { + try { + instance.componentDidUpdate( + prevProps, + prevState, + instance.__reactInternalSnapshotBeforeUpdate + ); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } } + } +} - case HostRoot: { - { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); - } +function commitClassCallbacks(finishedWork) { + // TODO: I think this is now always non-null by the time it reaches the + // commit phase. Consider removing the type check. + var updateQueue = finishedWork.updateQueue; - if (flags & Update) { - { - var containerInfo = root.containerInfo; - var pendingChildren = root.pendingChildren; + if (updateQueue !== null) { + var instance = finishedWork.stateNode; - try { - replaceContainerChildren(containerInfo, pendingChildren); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } + { + if ( + finishedWork.type === finishedWork.elementType && + !didWarnAboutReassigningProps + ) { + if (instance.props !== finishedWork.memoizedProps) { + error( + "Expected %s props to match memoized props before " + + "processing the update queue. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentNameFromFiber(finishedWork) || "instance" + ); + } + + if (instance.state !== finishedWork.memoizedState) { + error( + "Expected %s state to match memoized state before " + + "processing the update queue. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.state`. " + + "Please file an issue.", + getComponentNameFromFiber(finishedWork) || "instance" + ); } } + } // We could update instance props and state here, + // but instead we rely on them being set during last render. + // TODO: revisit this when we implement resuming. - return; + try { + commitCallbacks(updateQueue, instance); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); } + } +} - case HostPortal: { - { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); - } +function commitHostComponentMount(finishedWork) { + var type = finishedWork.type; + var props = finishedWork.memoizedProps; + var instance = finishedWork.stateNode; - if (flags & Update) { - { - var portal = finishedWork.stateNode; - var _containerInfo = portal.containerInfo; - var _pendingChildren = portal.pendingChildren; + try { + commitMount(instance, type, props, finishedWork); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } +} - try { - replaceContainerChildren(_containerInfo, _pendingChildren); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } +function commitProfilerUpdate(finishedWork, current) { + if (getExecutionContext() & CommitContext) { + try { + var _finishedWork$memoize2 = finishedWork.memoizedProps, + onCommit = _finishedWork$memoize2.onCommit, + onRender = _finishedWork$memoize2.onRender; + var effectDuration = finishedWork.stateNode.effectDuration; + var commitTime = getCommitTime(); + var phase = current === null ? "mount" : "update"; + + if (enableProfilerNestedUpdatePhase) { + if (isCurrentUpdateNested()) { + phase = "nested-update"; } } - return; - } + if (typeof onRender === "function") { + onRender( + finishedWork.memoizedProps.id, + phase, + finishedWork.actualDuration, + finishedWork.treeBaseDuration, + finishedWork.actualStartTime, + commitTime + ); + } - case SuspenseComponent: { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); - var offscreenFiber = finishedWork.child; + if (enableProfilerCommitHooks) { + if (typeof onCommit === "function") { + onCommit( + finishedWork.memoizedProps.id, + phase, + effectDuration, + commitTime + ); + } // Schedule a passive effect for this Profiler to call onPostCommit hooks. + // This effect should be scheduled even if there is no onPostCommit callback for this Profiler, + // because the effect is also where times bubble to parent Profilers. - if (offscreenFiber.flags & Visibility) { - var newState = offscreenFiber.memoizedState; - var isHidden = newState !== null; + enqueuePendingPassiveProfilerEffect(finishedWork); // Propagate layout effect durations to the next nearest Profiler ancestor. + // Do not reset these values until the next render so DevTools has a chance to read them first. - if (isHidden) { - var wasHidden = - offscreenFiber.alternate !== null && - offscreenFiber.alternate.memoizedState !== null; + var parentFiber = finishedWork.return; - if (!wasHidden) { - // TODO: Move to passive phase - markCommitTimeOfFallback(); + outer: while (parentFiber !== null) { + switch (parentFiber.tag) { + case HostRoot: + var root = parentFiber.stateNode; + root.effectDuration += effectDuration; + break outer; + + case Profiler: + var parentStateNode = parentFiber.stateNode; + parentStateNode.effectDuration += effectDuration; + break outer; } + + parentFiber = parentFiber.return; } } + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } + } +} - if (flags & Update) { - try { - commitSuspenseCallback(finishedWork); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } +function commitLayoutEffectOnFiber( + finishedRoot, + current, + finishedWork, + committedLanes +) { + // When updating this function, also update reappearLayoutEffects, which does + // most of the same things when an offscreen tree goes from hidden -> visible. + var flags = finishedWork.flags; - var retryQueue = finishedWork.updateQueue; + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: { + recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); - if (retryQueue !== null) { - finishedWork.updateQueue = null; - attachSuspenseRetryListeners(finishedWork, retryQueue); - } + if (flags & Update) { + commitHookLayoutEffects(finishedWork, Layout | HasEffect); } - return; + break; } - case OffscreenComponent: { - if (flags & Ref) { - if (current !== null) { - safelyDetachRef(current, current.return); - } - } - - var _newState = finishedWork.memoizedState; + case ClassComponent: { + recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); - var _isHidden = _newState !== null; + if (flags & Update) { + commitClassLayoutLifecycles(finishedWork, current); + } - var _wasHidden = current !== null && current.memoizedState !== null; + if (flags & Callback) { + commitClassCallbacks(finishedWork); + } - if (finishedWork.mode & ConcurrentMode) { - // Before committing the children, track on the stack whether this - // offscreen subtree was already hidden, so that we don't unmount the - // effects again. - var prevOffscreenSubtreeIsHidden = offscreenSubtreeIsHidden; - var prevOffscreenSubtreeWasHidden = offscreenSubtreeWasHidden; - offscreenSubtreeIsHidden = prevOffscreenSubtreeIsHidden || _isHidden; - offscreenSubtreeWasHidden = prevOffscreenSubtreeWasHidden || _wasHidden; - recursivelyTraverseMutationEffects(root, finishedWork); - offscreenSubtreeWasHidden = prevOffscreenSubtreeWasHidden; - offscreenSubtreeIsHidden = prevOffscreenSubtreeIsHidden; - } else { - recursivelyTraverseMutationEffects(root, finishedWork); + if (flags & Ref) { + safelyAttachRef(finishedWork, finishedWork.return); } - commitReconciliationEffects(finishedWork); - var offscreenInstance = finishedWork.stateNode; // TODO: Add explicit effect flag to set _current. + break; + } - offscreenInstance._current = finishedWork; // Offscreen stores pending changes to visibility in `_pendingVisibility`. This is - // to support batching of `attach` and `detach` calls. + case HostRoot: { + recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); - offscreenInstance._visibility &= ~OffscreenDetached; - offscreenInstance._visibility |= - offscreenInstance._pendingVisibility & OffscreenDetached; + if (flags & Callback) { + // TODO: I think this is now always non-null by the time it reaches the + // commit phase. Consider removing the type check. + var updateQueue = finishedWork.updateQueue; - if (flags & Visibility) { - // Track the current state on the Offscreen instance so we can - // read it during an event - if (_isHidden) { - offscreenInstance._visibility &= ~OffscreenVisible; - } else { - offscreenInstance._visibility |= OffscreenVisible; - } + if (updateQueue !== null) { + var instance = null; - if (_isHidden) { - var isUpdate = current !== null; - var wasHiddenByAncestorOffscreen = - offscreenSubtreeIsHidden || offscreenSubtreeWasHidden; // Only trigger disapper layout effects if: - // - This is an update, not first mount. - // - This Offscreen was not hidden before. - // - Ancestor Offscreen was not hidden in previous commit. + if (finishedWork.child !== null) { + switch (finishedWork.child.tag) { + case HostSingleton: + case HostComponent: + instance = getPublicInstance(finishedWork.child.stateNode); + break; - if (isUpdate && !_wasHidden && !wasHiddenByAncestorOffscreen) { - if ((finishedWork.mode & ConcurrentMode) !== NoMode) { - // Disappear the layout effects of all the children - recursivelyTraverseDisappearLayoutEffects(finishedWork); + case ClassComponent: + instance = finishedWork.child.stateNode; + break; } } - } // Offscreen with manual mode manages visibility manually. - } // TODO: Move to passive phase - - if (flags & Update) { - var offscreenQueue = finishedWork.updateQueue; - - if (offscreenQueue !== null) { - var _retryQueue = offscreenQueue.retryQueue; - if (_retryQueue !== null) { - offscreenQueue.retryQueue = null; - attachSuspenseRetryListeners(finishedWork, _retryQueue); + try { + commitCallbacks(updateQueue, instance); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); } } } - return; + break; } - case SuspenseListComponent: { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); + case HostHoistable: + // eslint-disable-next-line-no-fallthrough - if (flags & Update) { - var _retryQueue2 = finishedWork.updateQueue; + case HostSingleton: + case HostComponent: { + recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); // Renderers may schedule work to be done after host components are mounted + // (eg DOM renderer may schedule auto-focus for inputs and form controls). + // These effects should only be committed when components are first mounted, + // aka when there is no current/alternate. - if (_retryQueue2 !== null) { - finishedWork.updateQueue = null; - attachSuspenseRetryListeners(finishedWork, _retryQueue2); - } + if (current === null && flags & Update) { + commitHostComponentMount(finishedWork); } - return; + if (flags & Ref) { + safelyAttachRef(finishedWork, finishedWork.return); + } + + break; } - case ScopeComponent: { - return; + case Profiler: { + recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); // TODO: Should this fire inside an offscreen tree? Or should it wait to + // fire when the tree becomes visible again. + + if (flags & Update) { + commitProfilerUpdate(finishedWork, current); + } + + break; } - default: { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); - return; + case SuspenseComponent: { + recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); + + break; } - } -} -function commitReconciliationEffects(finishedWork) { - // Placement effects (insertions, reorders) can be scheduled on any fiber - // type. They needs to happen after the children effects have fired, but - // before the effects on this fiber have fired. - var flags = finishedWork.flags; + case OffscreenComponent: { + var isModernRoot = (finishedWork.mode & ConcurrentMode) !== NoMode; - if (flags & Placement) { - try { - commitPlacement(finishedWork); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } // Clear the "placement" from effect tag so that we know that this is - // inserted, before any life-cycles like componentDidMount gets called. - // TODO: findDOMNode doesn't rely on this any more but isMounted does - // and isMounted is deprecated anyway so we should be able to kill this. + if (isModernRoot) { + var isHidden = finishedWork.memoizedState !== null; + var newOffscreenSubtreeIsHidden = isHidden || offscreenSubtreeIsHidden; - finishedWork.flags &= ~Placement; - } + if (newOffscreenSubtreeIsHidden); + else { + // The Offscreen tree is visible. + var wasHidden = current !== null && current.memoizedState !== null; + var newOffscreenSubtreeWasHidden = + wasHidden || offscreenSubtreeWasHidden; + var prevOffscreenSubtreeIsHidden = offscreenSubtreeIsHidden; + var prevOffscreenSubtreeWasHidden = offscreenSubtreeWasHidden; + offscreenSubtreeIsHidden = newOffscreenSubtreeIsHidden; + offscreenSubtreeWasHidden = newOffscreenSubtreeWasHidden; - if (flags & Hydrating) { - finishedWork.flags &= ~Hydrating; - } -} + if (offscreenSubtreeWasHidden && !prevOffscreenSubtreeWasHidden) { + // This is the root of a reappearing boundary. As we continue + // traversing the layout effects, we must also re-mount layout + // effects that were unmounted when the Offscreen subtree was + // hidden. So this is a superset of the normal commitLayoutEffects. + var includeWorkInProgressEffects = + (finishedWork.subtreeFlags & LayoutMask) !== NoFlags$1; + recursivelyTraverseReappearLayoutEffects( + finishedRoot, + finishedWork, + includeWorkInProgressEffects + ); + } else { + recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); + } -function commitLayoutEffects(finishedWork, root, committedLanes) { - inProgressLanes = committedLanes; - inProgressRoot = root; - var current = finishedWork.alternate; - commitLayoutEffectOnFiber(root, current, finishedWork); - inProgressLanes = null; - inProgressRoot = null; + offscreenSubtreeIsHidden = prevOffscreenSubtreeIsHidden; + offscreenSubtreeWasHidden = prevOffscreenSubtreeWasHidden; + } + } else { + recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); + } + + if (flags & Ref) { + var props = finishedWork.memoizedProps; + + if (props.mode === "manual") { + safelyAttachRef(finishedWork, finishedWork.return); + } else { + safelyDetachRef(finishedWork, finishedWork.return); + } + } + + break; + } + + default: { + recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); + break; + } + } } -function recursivelyTraverseLayoutEffects(root, parentFiber, lanes) { - var prevDebugFiber = getCurrentFiber(); +function commitAttachRef(finishedWork) { + var ref = finishedWork.ref; - if (parentFiber.subtreeFlags & LayoutMask) { - var child = parentFiber.child; + if (ref !== null) { + var instance = finishedWork.stateNode; + var instanceToUse; - while (child !== null) { - setCurrentFiber(child); - var current = child.alternate; - commitLayoutEffectOnFiber(root, current, child); - child = child.sibling; - } - } + switch (finishedWork.tag) { + case HostHoistable: + case HostSingleton: + case HostComponent: + instanceToUse = getPublicInstance(instance); + break; - setCurrentFiber(prevDebugFiber); -} + default: + instanceToUse = instance; + } // Moved outside to ensure DCE works with this flag -function disappearLayoutEffects(finishedWork) { - switch (finishedWork.tag) { - case FunctionComponent: - case ForwardRef: - case MemoComponent: - case SimpleMemoComponent: { - // TODO (Offscreen) Check: flags & LayoutStatic + if (typeof ref === "function") { if (shouldProfile(finishedWork)) { try { startLayoutEffectTimer(); - commitHookEffectListUnmount( - Layout, - finishedWork, - finishedWork.return - ); + finishedWork.refCleanup = ref(instanceToUse); } finally { recordLayoutEffectDuration(finishedWork); } } else { - commitHookEffectListUnmount(Layout, finishedWork, finishedWork.return); + finishedWork.refCleanup = ref(instanceToUse); } + } else { + { + if (!ref.hasOwnProperty("current")) { + error( + "Unexpected ref object provided for %s. " + + "Use either a ref-setter function or React.createRef().", + getComponentNameFromFiber(finishedWork) + ); + } + } // $FlowFixMe unable to narrow type to the non-function case - recursivelyTraverseDisappearLayoutEffects(finishedWork); - break; + ref.current = instanceToUse; } + } +} - case ClassComponent: { - // TODO (Offscreen) Check: flags & RefStatic - safelyDetachRef(finishedWork, finishedWork.return); - var instance = finishedWork.stateNode; +function detachFiberMutation(fiber) { + // Cut off the return pointer to disconnect it from the tree. + // This enables us to detect and warn against state updates on an unmounted component. + // It also prevents events from bubbling from within disconnected components. + // + // Ideally, we should also clear the child pointer of the parent alternate to let this + // get GC:ed but we don't know which for sure which parent is the current + // one so we'll settle for GC:ing the subtree of this child. + // This child itself will be GC:ed when the parent updates the next time. + // + // Note that we can't clear child or sibling pointers yet. + // They're needed for passive effects and for findDOMNode. + // We defer those fields, and all other cleanup, to the passive phase (see detachFiberAfterEffects). + // + // Don't reset the alternate yet, either. We need that so we can detach the + // alternate's fields in the passive phase. Clearing the return pointer is + // sufficient for findDOMNode semantics. + var alternate = fiber.alternate; - if (typeof instance.componentWillUnmount === "function") { - safelyCallComponentWillUnmount( - finishedWork, - finishedWork.return, - instance - ); - } + if (alternate !== null) { + alternate.return = null; + } - recursivelyTraverseDisappearLayoutEffects(finishedWork); - break; - } + fiber.return = null; +} - case HostHoistable: - case HostSingleton: - case HostComponent: { - // TODO (Offscreen) Check: flags & RefStatic - safelyDetachRef(finishedWork, finishedWork.return); - recursivelyTraverseDisappearLayoutEffects(finishedWork); - break; - } +function detachFiberAfterEffects(fiber) { + var alternate = fiber.alternate; - case OffscreenComponent: { - // TODO (Offscreen) Check: flags & RefStatic - safelyDetachRef(finishedWork, finishedWork.return); - var isHidden = finishedWork.memoizedState !== null; + if (alternate !== null) { + fiber.alternate = null; + detachFiberAfterEffects(alternate); + } // Clear cyclical Fiber fields. This level alone is designed to roughly + // approximate the planned Fiber refactor. In that world, `setState` will be + // bound to a special "instance" object instead of a Fiber. The Instance + // object will not have any of these fields. It will only be connected to + // the fiber tree via a single link at the root. So if this level alone is + // sufficient to fix memory issues, that bodes well for our plans. - if (isHidden); - else { - recursivelyTraverseDisappearLayoutEffects(finishedWork); - } + fiber.child = null; + fiber.deletions = null; + fiber.sibling = null; // The `stateNode` is cyclical because on host nodes it points to the host - break; - } + fiber.stateNode = null; - default: { - recursivelyTraverseDisappearLayoutEffects(finishedWork); - break; - } + { + fiber._debugOwner = null; + } // Theoretically, nothing in here should be necessary, because we already + // disconnected the fiber from the tree. So even if something leaks this + // particular fiber, it won't leak anything else. + + fiber.return = null; + fiber.dependencies = null; + fiber.memoizedProps = null; + fiber.memoizedState = null; + fiber.pendingProps = null; + fiber.stateNode = null; // TODO: Move to `commitPassiveUnmountInsideDeletedTreeOnFiber` instead. + + fiber.updateQueue = null; +} + +function emptyPortalContainer(current) { + var portal = current.stateNode; + var containerInfo = portal.containerInfo; + createContainerChildSet(containerInfo); +} + +function commitPlacement(finishedWork) { + { + return; } } -function recursivelyTraverseDisappearLayoutEffects(parentFiber) { - // TODO (Offscreen) Check: flags & (RefStatic | LayoutStatic) - var child = parentFiber.child; +function commitDeletionEffects(root, returnFiber, deletedFiber) { + { + // Detach refs and call componentWillUnmount() on the whole subtree. + commitDeletionEffectsOnFiber(root, returnFiber, deletedFiber); + } + + detachFiberMutation(deletedFiber); +} + +function recursivelyTraverseDeletionEffects( + finishedRoot, + nearestMountedAncestor, + parent +) { + // TODO: Use a static flag to skip trees that don't have unmount effects + var child = parent.child; while (child !== null) { - disappearLayoutEffects(child); + commitDeletionEffectsOnFiber(finishedRoot, nearestMountedAncestor, child); child = child.sibling; } } -function reappearLayoutEffects( +function commitDeletionEffectsOnFiber( finishedRoot, - current, - finishedWork, // This function visits both newly finished work and nodes that were re-used - // from a previously committed tree. We cannot check non-static flags if the - // node was reused. - includeWorkInProgressEffects + nearestMountedAncestor, + deletedFiber ) { - // Turn on layout effects in a tree that previously disappeared. - var flags = finishedWork.flags; + onCommitUnmount(deletedFiber); // The cases in this outer switch modify the stack before they traverse + // into their subtree. There are simpler cases in the inner switch + // that don't modify the stack. - switch (finishedWork.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - recursivelyTraverseReappearLayoutEffects( - finishedRoot, - finishedWork, - includeWorkInProgressEffects - ); // TODO: Check flags & LayoutStatic + switch (deletedFiber.tag) { + case HostHoistable: + // eslint-disable-next-line no-fallthrough - commitHookLayoutEffects(finishedWork, Layout); - break; + case HostSingleton: + // eslint-disable-next-line no-fallthrough + + case HostComponent: { + if (!offscreenSubtreeWasHidden) { + safelyDetachRef(deletedFiber, nearestMountedAncestor); + } // Intentional fallthrough to next branch } + // eslint-disable-next-line-no-fallthrough - case ClassComponent: { - recursivelyTraverseReappearLayoutEffects( - finishedRoot, - finishedWork, - includeWorkInProgressEffects - ); // TODO: Check for LayoutStatic flag + case HostText: { + // We only need to remove the nearest host child. Set the host parent + // to `null` on the stack to indicate that nested children don't + // need to be removed. + { + recursivelyTraverseDeletionEffects( + finishedRoot, + nearestMountedAncestor, + deletedFiber + ); + } - var instance = finishedWork.stateNode; + return; + } + + case DehydratedFragment: { + return; + } + + case HostPortal: { + { + emptyPortalContainer(deletedFiber); + recursivelyTraverseDeletionEffects( + finishedRoot, + nearestMountedAncestor, + deletedFiber + ); + } + + return; + } + + case FunctionComponent: + case ForwardRef: + case MemoComponent: + case SimpleMemoComponent: { + if (!offscreenSubtreeWasHidden) { + var updateQueue = deletedFiber.updateQueue; - if (typeof instance.componentDidMount === "function") { - try { - instance.componentDidMount(); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } - } // Commit any callbacks that would have fired while the component - // was hidden. + if (updateQueue !== null) { + var lastEffect = updateQueue.lastEffect; - var updateQueue = finishedWork.updateQueue; + if (lastEffect !== null) { + var firstEffect = lastEffect.next; + var effect = firstEffect; - if (updateQueue !== null) { - commitHiddenCallbacks(updateQueue, instance); - } // If this is newly finished work, check for setState callbacks + do { + var _effect = effect, + destroy = _effect.destroy, + tag = _effect.tag; - if (includeWorkInProgressEffects && flags & Callback) { - commitClassCallbacks(finishedWork); - } // TODO: Check flags & RefStatic + if (destroy !== undefined) { + if ((tag & Insertion) !== NoFlags) { + safelyCallDestroy( + deletedFiber, + nearestMountedAncestor, + destroy + ); + } else if ((tag & Layout) !== NoFlags) { + { + markComponentLayoutEffectUnmountStarted(deletedFiber); + } - safelyAttachRef(finishedWork, finishedWork.return); - break; - } - // Unlike commitLayoutEffectsOnFiber, we don't need to handle HostRoot - // because this function only visits nodes that are inside an - // Offscreen fiber. - // case HostRoot: { - // ... - // } + if (shouldProfile(deletedFiber)) { + startLayoutEffectTimer(); + safelyCallDestroy( + deletedFiber, + nearestMountedAncestor, + destroy + ); + recordLayoutEffectDuration(deletedFiber); + } else { + safelyCallDestroy( + deletedFiber, + nearestMountedAncestor, + destroy + ); + } - case HostHoistable: - case HostSingleton: - case HostComponent: { - recursivelyTraverseReappearLayoutEffects( - finishedRoot, - finishedWork, - includeWorkInProgressEffects - ); // Renderers may schedule work to be done after host components are mounted - // (eg DOM renderer may schedule auto-focus for inputs and form controls). - // These effects should only be committed when components are first mounted, - // aka when there is no current/alternate. + { + markComponentLayoutEffectUnmountStopped(); + } + } + } - if (includeWorkInProgressEffects && current === null && flags & Update) { - commitHostComponentMount(finishedWork); - } // TODO: Check flags & Ref + effect = effect.next; + } while (effect !== firstEffect); + } + } + } - safelyAttachRef(finishedWork, finishedWork.return); - break; + recursivelyTraverseDeletionEffects( + finishedRoot, + nearestMountedAncestor, + deletedFiber + ); + return; } - case Profiler: { - recursivelyTraverseReappearLayoutEffects( - finishedRoot, - finishedWork, - includeWorkInProgressEffects - ); // TODO: Figure out how Profiler updates should work with Offscreen + case ClassComponent: { + if (!offscreenSubtreeWasHidden) { + safelyDetachRef(deletedFiber, nearestMountedAncestor); + var instance = deletedFiber.stateNode; - if (includeWorkInProgressEffects && flags & Update) { - commitProfilerUpdate(finishedWork, current); + if (typeof instance.componentWillUnmount === "function") { + safelyCallComponentWillUnmount( + deletedFiber, + nearestMountedAncestor, + instance + ); + } } - break; + recursivelyTraverseDeletionEffects( + finishedRoot, + nearestMountedAncestor, + deletedFiber + ); + return; } - case SuspenseComponent: { - recursivelyTraverseReappearLayoutEffects( + case ScopeComponent: { + recursivelyTraverseDeletionEffects( finishedRoot, - finishedWork, - includeWorkInProgressEffects - ); // TODO: Figure out how Suspense hydration callbacks should work - - break; + nearestMountedAncestor, + deletedFiber + ); + return; } case OffscreenComponent: { - var offscreenState = finishedWork.memoizedState; - var isHidden = offscreenState !== null; + safelyDetachRef(deletedFiber, nearestMountedAncestor); - if (isHidden); - else { - recursivelyTraverseReappearLayoutEffects( + if (deletedFiber.mode & ConcurrentMode) { + // If this offscreen component is hidden, we already unmounted it. Before + // deleting the children, track that it's already unmounted so that we + // don't attempt to unmount the effects again. + // TODO: If the tree is hidden, in most cases we should be able to skip + // over the nested children entirely. An exception is we haven't yet found + // the topmost host node to delete, which we already track on the stack. + // But the other case is portals, which need to be detached no matter how + // deeply they are nested. We should use a subtree flag to track whether a + // subtree includes a nested portal. + var prevOffscreenSubtreeWasHidden = offscreenSubtreeWasHidden; + offscreenSubtreeWasHidden = + prevOffscreenSubtreeWasHidden || deletedFiber.memoizedState !== null; + recursivelyTraverseDeletionEffects( finishedRoot, - finishedWork, - includeWorkInProgressEffects + nearestMountedAncestor, + deletedFiber ); - } // TODO: Check flags & Ref + offscreenSubtreeWasHidden = prevOffscreenSubtreeWasHidden; + } else { + recursivelyTraverseDeletionEffects( + finishedRoot, + nearestMountedAncestor, + deletedFiber + ); + } - safelyAttachRef(finishedWork, finishedWork.return); break; } default: { - recursivelyTraverseReappearLayoutEffects( + recursivelyTraverseDeletionEffects( finishedRoot, - finishedWork, - includeWorkInProgressEffects + nearestMountedAncestor, + deletedFiber ); - break; - } - } -} - -function recursivelyTraverseReappearLayoutEffects( - finishedRoot, - parentFiber, - includeWorkInProgressEffects -) { - // This function visits both newly finished work and nodes that were re-used - // from a previously committed tree. We cannot check non-static flags if the - // node was reused. - var childShouldIncludeWorkInProgressEffects = - includeWorkInProgressEffects && - (parentFiber.subtreeFlags & LayoutMask) !== NoFlags$1; // TODO (Offscreen) Check: flags & (RefStatic | LayoutStatic) - - var prevDebugFiber = getCurrentFiber(); - var child = parentFiber.child; - - while (child !== null) { - var current = child.alternate; - reappearLayoutEffects( - finishedRoot, - current, - child, - childShouldIncludeWorkInProgressEffects - ); - child = child.sibling; - } - - setCurrentFiber(prevDebugFiber); -} - -function commitHookPassiveMountEffects(finishedWork, hookFlags) { - if (shouldProfile(finishedWork)) { - startPassiveEffectTimer(); - - try { - commitHookEffectListMount(hookFlags, finishedWork); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } - - recordPassiveEffectDuration(finishedWork); - } else { - try { - commitHookEffectListMount(hookFlags, finishedWork); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } - } -} - -function commitPassiveMountEffects( - root, - finishedWork, - committedLanes, - committedTransitions -) { - setCurrentFiber(finishedWork); - commitPassiveMountOnFiber(root, finishedWork); - resetCurrentFiber(); -} - -function recursivelyTraversePassiveMountEffects( - root, - parentFiber, - committedLanes, - committedTransitions -) { - var prevDebugFiber = getCurrentFiber(); - - if (parentFiber.subtreeFlags & PassiveMask) { - var child = parentFiber.child; - - while (child !== null) { - setCurrentFiber(child); - commitPassiveMountOnFiber(root, child); - child = child.sibling; + return; } } - - setCurrentFiber(prevDebugFiber); } -function commitPassiveMountOnFiber( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions -) { - // When updating this function, also update reconnectPassiveEffects, which does - // most of the same things when an offscreen tree goes from hidden -> visible, - // or when toggling effects inside a hidden tree. - var flags = finishedWork.flags; +function commitSuspenseCallback(finishedWork) {} +function getRetryCache(finishedWork) { + // TODO: Unify the interface for the retry cache so we don't have to switch + // on the tag like this. switch (finishedWork.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork); + case SuspenseComponent: + case SuspenseListComponent: { + var retryCache = finishedWork.stateNode; - if (flags & Passive$1) { - commitHookPassiveMountEffects(finishedWork, Passive | HasEffect); + if (retryCache === null) { + retryCache = finishedWork.stateNode = new PossiblyWeakSet(); } - break; + return retryCache; } - case HostRoot: { - recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork); - - break; - } + case OffscreenComponent: { + var instance = finishedWork.stateNode; + var _retryCache = instance._retryCache; - case LegacyHiddenComponent: { - { - recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork); + if (_retryCache === null) { + _retryCache = instance._retryCache = new PossiblyWeakSet(); } - break; + return _retryCache; } - case OffscreenComponent: { - // TODO: Pass `current` as argument to this function - var _instance3 = finishedWork.stateNode; - var nextState = finishedWork.memoizedState; - var isHidden = nextState !== null; + default: { + throw new Error( + "Unexpected Suspense handler tag (" + + finishedWork.tag + + "). This is a " + + "bug in React." + ); + } + } +} - if (isHidden) { - if (_instance3._visibility & OffscreenPassiveEffectsConnected) { - // The effects are currently connected. Update them. - recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork); - } else { - if (finishedWork.mode & ConcurrentMode); - else { - // Legacy Mode: Fire the effects even if the tree is hidden. - _instance3._visibility |= OffscreenPassiveEffectsConnected; - recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork); +function detachOffscreenInstance(instance) { + var fiber = instance._current; + + if (fiber === null) { + throw new Error( + "Calling Offscreen.detach before instance handle has been set." + ); + } + + if ((instance._pendingVisibility & OffscreenDetached) !== NoFlags$1) { + // The instance is already detached, this is a noop. + return; + } // TODO: There is an opportunity to optimise this by not entering commit phase + // and unmounting effects directly. + + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + + if (root !== null) { + instance._pendingVisibility |= OffscreenDetached; + scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); + } +} +function attachOffscreenInstance(instance) { + var fiber = instance._current; + + if (fiber === null) { + throw new Error( + "Calling Offscreen.detach before instance handle has been set." + ); + } + + if ((instance._pendingVisibility & OffscreenDetached) === NoFlags$1) { + // The instance is already attached, this is a noop. + return; + } + + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + + if (root !== null) { + instance._pendingVisibility &= ~OffscreenDetached; + scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); + } +} + +function attachSuspenseRetryListeners(finishedWork, wakeables) { + // If this boundary just timed out, then it will have a set of wakeables. + // For each wakeable, attach a listener so that when it resolves, React + // attempts to re-render the boundary in the primary (pre-timeout) state. + var retryCache = getRetryCache(finishedWork); + wakeables.forEach(function (wakeable) { + // Memoize using the boundary fiber to prevent redundant listeners. + var retry = resolveRetryWakeable.bind(null, finishedWork, wakeable); + + if (!retryCache.has(wakeable)) { + retryCache.add(wakeable); + + { + if (isDevToolsPresent) { + if (inProgressLanes !== null && inProgressRoot !== null) { + // If we have pending work still, associate the original updaters with it. + restorePendingUpdaters(inProgressRoot, inProgressLanes); + } else { + throw Error( + "Expected finished root and lanes to be set. This is a bug in React." + ); } } - } else { - // Tree is visible - if (_instance3._visibility & OffscreenPassiveEffectsConnected) { - // The effects are currently connected. Update them. - recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork); - } else { - // The effects are currently disconnected. Reconnect them, while also - // firing effects inside newly mounted trees. This also applies to - // the initial render. - _instance3._visibility |= OffscreenPassiveEffectsConnected; - recursivelyTraverseReconnectPassiveEffects( - finishedRoot, - finishedWork - ); - } } - break; + wakeable.then(retry, retry); } + }); +} // This function detects when a Suspense boundary goes from visible to hidden. +function commitMutationEffects(root, finishedWork, committedLanes) { + inProgressLanes = committedLanes; + inProgressRoot = root; + setCurrentFiber(finishedWork); + commitMutationEffectsOnFiber(finishedWork, root); + setCurrentFiber(finishedWork); + inProgressLanes = null; + inProgressRoot = null; +} - case CacheComponent: { - recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork); - - break; - } +function recursivelyTraverseMutationEffects(root, parentFiber, lanes) { + // Deletions effects can be scheduled on any fiber type. They need to happen + // before the children effects hae fired. + var deletions = parentFiber.deletions; - case TracingMarkerComponent: - // eslint-disable-next-line-no-fallthrough + if (deletions !== null) { + for (var i = 0; i < deletions.length; i++) { + var childToDelete = deletions[i]; - default: { - recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork); - break; + try { + commitDeletionEffects(root, parentFiber, childToDelete); + } catch (error) { + captureCommitPhaseError(childToDelete, parentFiber, error); + } } } -} -function recursivelyTraverseReconnectPassiveEffects( - finishedRoot, - parentFiber, - committedLanes, - committedTransitions, - includeWorkInProgressEffects -) { var prevDebugFiber = getCurrentFiber(); - var child = parentFiber.child; - while (child !== null) { - reconnectPassiveEffects(finishedRoot, child); - child = child.sibling; + if (parentFiber.subtreeFlags & MutationMask) { + var child = parentFiber.child; + + while (child !== null) { + setCurrentFiber(child); + commitMutationEffectsOnFiber(child, root); + child = child.sibling; + } } setCurrentFiber(prevDebugFiber); } -function reconnectPassiveEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions, // This function visits both newly finished work and nodes that were re-used - // from a previously committed tree. We cannot check non-static flags if the - // node was reused. - includeWorkInProgressEffects -) { +function commitMutationEffectsOnFiber(finishedWork, root, lanes) { + var current = finishedWork.alternate; + var flags = finishedWork.flags; // The effect flag should be checked *after* we refine the type of fiber, + // because the fiber tag is more specific. An exception is any flag related + // to reconciliation, because those can be set on all fiber types. + switch (finishedWork.tag) { case FunctionComponent: case ForwardRef: + case MemoComponent: case SimpleMemoComponent: { - recursivelyTraverseReconnectPassiveEffects(finishedRoot, finishedWork); // TODO: Check for PassiveStatic flag + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); - commitHookPassiveMountEffects(finishedWork, Passive); - break; - } - // Unlike commitPassiveMountOnFiber, we don't need to handle HostRoot - // because this function only visits nodes that are inside an - // Offscreen fiber. - // case HostRoot: { - // ... - // } + if (flags & Update) { + try { + commitHookEffectListUnmount( + Insertion | HasEffect, + finishedWork, + finishedWork.return + ); + commitHookEffectListMount(Insertion | HasEffect, finishedWork); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } // Layout effects are destroyed during the mutation phase so that all + // destroy functions for all fibers are called before any create functions. + // This prevents sibling component effects from interfering with each other, + // e.g. a destroy function in one component should never override a ref set + // by a create function in another component during the same commit. + + if (shouldProfile(finishedWork)) { + try { + startLayoutEffectTimer(); + commitHookEffectListUnmount( + Layout | HasEffect, + finishedWork, + finishedWork.return + ); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } - case LegacyHiddenComponent: { - { - recursivelyTraverseReconnectPassiveEffects(finishedRoot, finishedWork); + recordLayoutEffectDuration(finishedWork); + } else { + try { + commitHookEffectListUnmount( + Layout | HasEffect, + finishedWork, + finishedWork.return + ); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } + } } - break; + return; } - case OffscreenComponent: { - var _instance4 = finishedWork.stateNode; - var nextState = finishedWork.memoizedState; - var isHidden = nextState !== null; + case ClassComponent: { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); - if (isHidden) { - if (_instance4._visibility & OffscreenPassiveEffectsConnected) { - // The effects are currently connected. Update them. - recursivelyTraverseReconnectPassiveEffects( - finishedRoot, - finishedWork - ); - } else { - if (finishedWork.mode & ConcurrentMode); - else { - // Legacy Mode: Fire the effects even if the tree is hidden. - _instance4._visibility |= OffscreenPassiveEffectsConnected; - recursivelyTraverseReconnectPassiveEffects( - finishedRoot, - finishedWork - ); - } + if (flags & Ref) { + if (current !== null) { + safelyDetachRef(current, current.return); } - } else { - // Tree is visible - // Since we're already inside a reconnecting tree, it doesn't matter - // whether the effects are currently connected. In either case, we'll - // continue traversing the tree and firing all the effects. - // - // We do need to set the "connected" flag on the instance, though. - _instance4._visibility |= OffscreenPassiveEffectsConnected; - recursivelyTraverseReconnectPassiveEffects(finishedRoot, finishedWork); } - break; - } + if (flags & Callback && offscreenSubtreeIsHidden) { + var updateQueue = finishedWork.updateQueue; - case CacheComponent: { - recursivelyTraverseReconnectPassiveEffects(finishedRoot, finishedWork); + if (updateQueue !== null) { + deferHiddenCallbacks(updateQueue); + } + } - break; + return; } - case TracingMarkerComponent: + case HostHoistable: // eslint-disable-next-line-no-fallthrough - default: { - recursivelyTraverseReconnectPassiveEffects(finishedRoot, finishedWork); - break; - } - } -} - -function commitPassiveUnmountEffects(finishedWork) { - setCurrentFiber(finishedWork); - commitPassiveUnmountOnFiber(finishedWork); - resetCurrentFiber(); -} + case HostSingleton: + // eslint-disable-next-line-no-fallthrough -function detachAlternateSiblings(parentFiber) { - // A fiber was deleted from this parent fiber, but it's still part of the - // previous (alternate) parent fiber's list of children. Because children - // are a linked list, an earlier sibling that's still alive will be - // connected to the deleted fiber via its `alternate`: - // - // live fiber --alternate--> previous live fiber --sibling--> deleted - // fiber - // - // We can't disconnect `alternate` on nodes that haven't been deleted yet, - // but we can disconnect the `sibling` and `child` pointers. - var previousFiber = parentFiber.alternate; + case HostComponent: { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); - if (previousFiber !== null) { - var detachedChild = previousFiber.child; + if (flags & Ref) { + if (current !== null) { + safelyDetachRef(current, current.return); + } + } - if (detachedChild !== null) { - previousFiber.child = null; + return; + } - do { - // $FlowFixMe[incompatible-use] found when upgrading Flow - var detachedSibling = detachedChild.sibling; // $FlowFixMe[incompatible-use] found when upgrading Flow + case HostText: { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); - detachedChild.sibling = null; - detachedChild = detachedSibling; - } while (detachedChild !== null); + return; } - } -} - -function commitHookPassiveUnmountEffects( - finishedWork, - nearestMountedAncestor, - hookFlags -) { - if (shouldProfile(finishedWork)) { - startPassiveEffectTimer(); - commitHookEffectListUnmount( - hookFlags, - finishedWork, - nearestMountedAncestor - ); - recordPassiveEffectDuration(finishedWork); - } else { - commitHookEffectListUnmount( - hookFlags, - finishedWork, - nearestMountedAncestor - ); - } -} -function recursivelyTraversePassiveUnmountEffects(parentFiber) { - // Deletions effects can be scheduled on any fiber type. They need to happen - // before the children effects have fired. - var deletions = parentFiber.deletions; + case HostRoot: { + { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); + } - if ((parentFiber.flags & ChildDeletion) !== NoFlags$1) { - if (deletions !== null) { - for (var i = 0; i < deletions.length; i++) { - var childToDelete = deletions[i]; // TODO: Convert this to use recursion + if (flags & Update) { + { + var containerInfo = root.containerInfo; + var pendingChildren = root.pendingChildren; - nextEffect = childToDelete; - commitPassiveUnmountEffectsInsideOfDeletedTree_begin( - childToDelete, - parentFiber - ); + try { + replaceContainerChildren(containerInfo, pendingChildren); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } + } } + + return; } - detachAlternateSiblings(parentFiber); - } + case HostPortal: { + { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); + } - var prevDebugFiber = getCurrentFiber(); // TODO: Split PassiveMask into separate masks for mount and unmount? + if (flags & Update) { + { + var portal = finishedWork.stateNode; + var _containerInfo = portal.containerInfo; + var _pendingChildren = portal.pendingChildren; - if (parentFiber.subtreeFlags & PassiveMask) { - var child = parentFiber.child; + try { + replaceContainerChildren(_containerInfo, _pendingChildren); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } + } + } - while (child !== null) { - setCurrentFiber(child); - commitPassiveUnmountOnFiber(child); - child = child.sibling; + return; } - } - - setCurrentFiber(prevDebugFiber); -} -function commitPassiveUnmountOnFiber(finishedWork) { - switch (finishedWork.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - recursivelyTraversePassiveUnmountEffects(finishedWork); + case SuspenseComponent: { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); + var offscreenFiber = finishedWork.child; - if (finishedWork.flags & Passive$1) { - commitHookPassiveUnmountEffects( - finishedWork, - finishedWork.return, - Passive | HasEffect - ); - } + if (offscreenFiber.flags & Visibility) { + var newState = offscreenFiber.memoizedState; + var isHidden = newState !== null; - break; - } + if (isHidden) { + var wasHidden = + offscreenFiber.alternate !== null && + offscreenFiber.alternate.memoizedState !== null; - case OffscreenComponent: { - var instance = finishedWork.stateNode; - var nextState = finishedWork.memoizedState; - var isHidden = nextState !== null; + if (!wasHidden) { + // TODO: Move to passive phase + markCommitTimeOfFallback(); + } + } + } - if ( - isHidden && - instance._visibility & OffscreenPassiveEffectsConnected && // For backwards compatibility, don't unmount when a tree suspends. In - // the future we may change this to unmount after a delay. - (finishedWork.return === null || - finishedWork.return.tag !== SuspenseComponent) - ) { - // The effects are currently connected. Disconnect them. - // TODO: Add option or heuristic to delay before disconnecting the - // effects. Then if the tree reappears before the delay has elapsed, we - // can skip toggling the effects entirely. - instance._visibility &= ~OffscreenPassiveEffectsConnected; - recursivelyTraverseDisconnectPassiveEffects(finishedWork); - } else { - recursivelyTraversePassiveUnmountEffects(finishedWork); + if (flags & Update) { + try { + commitSuspenseCallback(finishedWork); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } + + var retryQueue = finishedWork.updateQueue; + + if (retryQueue !== null) { + finishedWork.updateQueue = null; + attachSuspenseRetryListeners(finishedWork, retryQueue); + } } - break; + return; } - default: { - recursivelyTraversePassiveUnmountEffects(finishedWork); - break; - } - } -} + case OffscreenComponent: { + if (flags & Ref) { + if (current !== null) { + safelyDetachRef(current, current.return); + } + } -function recursivelyTraverseDisconnectPassiveEffects(parentFiber) { - // Deletions effects can be scheduled on any fiber type. They need to happen - // before the children effects have fired. - var deletions = parentFiber.deletions; + var _newState = finishedWork.memoizedState; - if ((parentFiber.flags & ChildDeletion) !== NoFlags$1) { - if (deletions !== null) { - for (var i = 0; i < deletions.length; i++) { - var childToDelete = deletions[i]; // TODO: Convert this to use recursion + var _isHidden = _newState !== null; - nextEffect = childToDelete; - commitPassiveUnmountEffectsInsideOfDeletedTree_begin( - childToDelete, - parentFiber - ); + var _wasHidden = current !== null && current.memoizedState !== null; + + if (finishedWork.mode & ConcurrentMode) { + // Before committing the children, track on the stack whether this + // offscreen subtree was already hidden, so that we don't unmount the + // effects again. + var prevOffscreenSubtreeIsHidden = offscreenSubtreeIsHidden; + var prevOffscreenSubtreeWasHidden = offscreenSubtreeWasHidden; + offscreenSubtreeIsHidden = prevOffscreenSubtreeIsHidden || _isHidden; + offscreenSubtreeWasHidden = prevOffscreenSubtreeWasHidden || _wasHidden; + recursivelyTraverseMutationEffects(root, finishedWork); + offscreenSubtreeWasHidden = prevOffscreenSubtreeWasHidden; + offscreenSubtreeIsHidden = prevOffscreenSubtreeIsHidden; + } else { + recursivelyTraverseMutationEffects(root, finishedWork); } - } - detachAlternateSiblings(parentFiber); - } + commitReconciliationEffects(finishedWork); + var offscreenInstance = finishedWork.stateNode; // TODO: Add explicit effect flag to set _current. - var prevDebugFiber = getCurrentFiber(); // TODO: Check PassiveStatic flag + offscreenInstance._current = finishedWork; // Offscreen stores pending changes to visibility in `_pendingVisibility`. This is + // to support batching of `attach` and `detach` calls. - var child = parentFiber.child; + offscreenInstance._visibility &= ~OffscreenDetached; + offscreenInstance._visibility |= + offscreenInstance._pendingVisibility & OffscreenDetached; - while (child !== null) { - setCurrentFiber(child); - disconnectPassiveEffect(child); - child = child.sibling; - } + if (flags & Visibility) { + // Track the current state on the Offscreen instance so we can + // read it during an event + if (_isHidden) { + offscreenInstance._visibility &= ~OffscreenVisible; + } else { + offscreenInstance._visibility |= OffscreenVisible; + } - setCurrentFiber(prevDebugFiber); -} + if (_isHidden) { + var isUpdate = current !== null; + var wasHiddenByAncestorOffscreen = + offscreenSubtreeIsHidden || offscreenSubtreeWasHidden; // Only trigger disapper layout effects if: + // - This is an update, not first mount. + // - This Offscreen was not hidden before. + // - Ancestor Offscreen was not hidden in previous commit. -function disconnectPassiveEffect(finishedWork) { - switch (finishedWork.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - // TODO: Check PassiveStatic flag - commitHookPassiveUnmountEffects( - finishedWork, - finishedWork.return, - Passive - ); // When disconnecting passive effects, we fire the effects in the same - // order as during a deletiong: parent before child + if (isUpdate && !_wasHidden && !wasHiddenByAncestorOffscreen) { + if ((finishedWork.mode & ConcurrentMode) !== NoMode) { + // Disappear the layout effects of all the children + recursivelyTraverseDisappearLayoutEffects(finishedWork); + } + } + } // Offscreen with manual mode manages visibility manually. + } // TODO: Move to passive phase - recursivelyTraverseDisconnectPassiveEffects(finishedWork); - break; - } + if (flags & Update) { + var offscreenQueue = finishedWork.updateQueue; - case OffscreenComponent: { - var instance = finishedWork.stateNode; + if (offscreenQueue !== null) { + var _retryQueue = offscreenQueue.retryQueue; - if (instance._visibility & OffscreenPassiveEffectsConnected) { - instance._visibility &= ~OffscreenPassiveEffectsConnected; - recursivelyTraverseDisconnectPassiveEffects(finishedWork); + if (_retryQueue !== null) { + offscreenQueue.retryQueue = null; + attachSuspenseRetryListeners(finishedWork, _retryQueue); + } + } } - break; + return; } - default: { - recursivelyTraverseDisconnectPassiveEffects(finishedWork); - break; - } - } -} + case SuspenseListComponent: { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); -function commitPassiveUnmountEffectsInsideOfDeletedTree_begin( - deletedSubtreeRoot, - nearestMountedAncestor -) { - while (nextEffect !== null) { - var fiber = nextEffect; // Deletion effects fire in parent -> child order - // TODO: Check if fiber has a PassiveStatic flag + if (flags & Update) { + var _retryQueue2 = finishedWork.updateQueue; - setCurrentFiber(fiber); - commitPassiveUnmountInsideDeletedTreeOnFiber(fiber, nearestMountedAncestor); - resetCurrentFiber(); - var child = fiber.child; // TODO: Only traverse subtree if it has a PassiveStatic flag. + if (_retryQueue2 !== null) { + finishedWork.updateQueue = null; + attachSuspenseRetryListeners(finishedWork, _retryQueue2); + } + } - if (child !== null) { - child.return = fiber; - nextEffect = child; - } else { - commitPassiveUnmountEffectsInsideOfDeletedTree_complete( - deletedSubtreeRoot - ); + return; } - } -} - -function commitPassiveUnmountEffectsInsideOfDeletedTree_complete( - deletedSubtreeRoot -) { - while (nextEffect !== null) { - var fiber = nextEffect; - var sibling = fiber.sibling; - var returnFiber = fiber.return; // Recursively traverse the entire deleted tree and clean up fiber fields. - // This is more aggressive than ideal, and the long term goal is to only - // have to detach the deleted tree at the root. - - detachFiberAfterEffects(fiber); - if (fiber === deletedSubtreeRoot) { - nextEffect = null; + case ScopeComponent: { return; } - if (sibling !== null) { - sibling.return = returnFiber; - nextEffect = sibling; + default: { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); return; } - - nextEffect = returnFiber; } } -function commitPassiveUnmountInsideDeletedTreeOnFiber( - current, - nearestMountedAncestor -) { - switch (current.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - commitHookPassiveUnmountEffects(current, nearestMountedAncestor, Passive); - break; - } - } -} +function commitReconciliationEffects(finishedWork) { + // Placement effects (insertions, reorders) can be scheduled on any fiber + // type. They needs to happen after the children effects have fired, but + // before the effects on this fiber have fired. + var flags = finishedWork.flags; -function invokeLayoutEffectMountInDEV(fiber) { - { - // We don't need to re-check StrictEffectsMode here. - // This function is only called if that check has already passed. - switch (fiber.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - try { - commitHookEffectListMount(Layout | HasEffect, fiber); - } catch (error) { - captureCommitPhaseError(fiber, fiber.return, error); - } + if (flags & Placement) { + try { + commitPlacement(finishedWork); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } // Clear the "placement" from effect tag so that we know that this is + // inserted, before any life-cycles like componentDidMount gets called. + // TODO: findDOMNode doesn't rely on this any more but isMounted does + // and isMounted is deprecated anyway so we should be able to kill this. - break; - } + finishedWork.flags &= ~Placement; + } - case ClassComponent: { - var instance = fiber.stateNode; + if (flags & Hydrating) { + finishedWork.flags &= ~Hydrating; + } +} - try { - instance.componentDidMount(); - } catch (error) { - captureCommitPhaseError(fiber, fiber.return, error); - } +function commitLayoutEffects(finishedWork, root, committedLanes) { + inProgressLanes = committedLanes; + inProgressRoot = root; + var current = finishedWork.alternate; + commitLayoutEffectOnFiber(root, current, finishedWork); + inProgressLanes = null; + inProgressRoot = null; +} + +function recursivelyTraverseLayoutEffects(root, parentFiber, lanes) { + var prevDebugFiber = getCurrentFiber(); - break; - } + if (parentFiber.subtreeFlags & LayoutMask) { + var child = parentFiber.child; + + while (child !== null) { + setCurrentFiber(child); + var current = child.alternate; + commitLayoutEffectOnFiber(root, current, child); + child = child.sibling; } } + + setCurrentFiber(prevDebugFiber); } -function invokePassiveEffectMountInDEV(fiber) { - { - // We don't need to re-check StrictEffectsMode here. - // This function is only called if that check has already passed. - switch (fiber.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { +function disappearLayoutEffects(finishedWork) { + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case MemoComponent: + case SimpleMemoComponent: { + // TODO (Offscreen) Check: flags & LayoutStatic + if (shouldProfile(finishedWork)) { try { - commitHookEffectListMount(Passive | HasEffect, fiber); - } catch (error) { - captureCommitPhaseError(fiber, fiber.return, error); + startLayoutEffectTimer(); + commitHookEffectListUnmount( + Layout, + finishedWork, + finishedWork.return + ); + } finally { + recordLayoutEffectDuration(finishedWork); } - - break; + } else { + commitHookEffectListUnmount(Layout, finishedWork, finishedWork.return); } + + recursivelyTraverseDisappearLayoutEffects(finishedWork); + break; } - } -} -function invokeLayoutEffectUnmountInDEV(fiber) { - { - // We don't need to re-check StrictEffectsMode here. - // This function is only called if that check has already passed. - switch (fiber.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - try { - commitHookEffectListUnmount(Layout | HasEffect, fiber, fiber.return); - } catch (error) { - captureCommitPhaseError(fiber, fiber.return, error); - } + case ClassComponent: { + // TODO (Offscreen) Check: flags & RefStatic + safelyDetachRef(finishedWork, finishedWork.return); + var instance = finishedWork.stateNode; - break; + if (typeof instance.componentWillUnmount === "function") { + safelyCallComponentWillUnmount( + finishedWork, + finishedWork.return, + instance + ); } - case ClassComponent: { - var instance = fiber.stateNode; + recursivelyTraverseDisappearLayoutEffects(finishedWork); + break; + } - if (typeof instance.componentWillUnmount === "function") { - safelyCallComponentWillUnmount(fiber, fiber.return, instance); - } + case HostHoistable: + case HostSingleton: + case HostComponent: { + // TODO (Offscreen) Check: flags & RefStatic + safelyDetachRef(finishedWork, finishedWork.return); + recursivelyTraverseDisappearLayoutEffects(finishedWork); + break; + } - break; + case OffscreenComponent: { + // TODO (Offscreen) Check: flags & RefStatic + safelyDetachRef(finishedWork, finishedWork.return); + var isHidden = finishedWork.memoizedState !== null; + + if (isHidden); + else { + recursivelyTraverseDisappearLayoutEffects(finishedWork); } + + break; } - } -} -function invokePassiveEffectUnmountInDEV(fiber) { - { - // We don't need to re-check StrictEffectsMode here. - // This function is only called if that check has already passed. - switch (fiber.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - try { - commitHookEffectListUnmount(Passive | HasEffect, fiber, fiber.return); - } catch (error) { - captureCommitPhaseError(fiber, fiber.return, error); - } - } + default: { + recursivelyTraverseDisappearLayoutEffects(finishedWork); + break; } } } -if (typeof Symbol === "function" && Symbol.for) { - var symbolFor = Symbol.for; - symbolFor("selector.component"); - symbolFor("selector.has_pseudo_class"); - symbolFor("selector.role"); - symbolFor("selector.test_id"); - symbolFor("selector.text"); -} +function recursivelyTraverseDisappearLayoutEffects(parentFiber) { + // TODO (Offscreen) Check: flags & (RefStatic | LayoutStatic) + var child = parentFiber.child; -var ReactCurrentActQueue$1 = ReactSharedInternals.ReactCurrentActQueue; -function isLegacyActEnvironment(fiber) { - { - // Legacy mode. We preserve the behavior of React 17's act. It assumes an - // act environment whenever `jest` is defined, but you can still turn off - // spurious warnings by setting IS_REACT_ACT_ENVIRONMENT explicitly - // to false. - // $FlowFixMe[cannot-resolve-name] Flow doesn't know about IS_REACT_ACT_ENVIRONMENT global - typeof IS_REACT_ACT_ENVIRONMENT !== "undefined" // $FlowFixMe[cannot-resolve-name] - ? IS_REACT_ACT_ENVIRONMENT - : undefined; // $FlowFixMe - Flow doesn't know about jest - return warnsIfNotActing; + while (child !== null) { + disappearLayoutEffects(child); + child = child.sibling; } } -function isConcurrentActEnvironment() { - { - var isReactActEnvironmentGlobal = // $FlowFixMe[cannot-resolve-name] Flow doesn't know about IS_REACT_ACT_ENVIRONMENT global - typeof IS_REACT_ACT_ENVIRONMENT !== "undefined" // $FlowFixMe[cannot-resolve-name] - ? IS_REACT_ACT_ENVIRONMENT - : undefined; - if ( - !isReactActEnvironmentGlobal && - ReactCurrentActQueue$1.current !== null - ) { - // TODO: Include link to relevant documentation page. - error( - "The current testing environment is not configured to support " + - "act(...)" - ); +function reappearLayoutEffects( + finishedRoot, + current, + finishedWork, // This function visits both newly finished work and nodes that were re-used + // from a previously committed tree. We cannot check non-static flags if the + // node was reused. + includeWorkInProgressEffects +) { + // Turn on layout effects in a tree that previously disappeared. + var flags = finishedWork.flags; + + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: { + recursivelyTraverseReappearLayoutEffects( + finishedRoot, + finishedWork, + includeWorkInProgressEffects + ); // TODO: Check flags & LayoutStatic + + commitHookLayoutEffects(finishedWork, Layout); + break; } - return isReactActEnvironmentGlobal; - } -} + case ClassComponent: { + recursivelyTraverseReappearLayoutEffects( + finishedRoot, + finishedWork, + includeWorkInProgressEffects + ); // TODO: Check for LayoutStatic flag -var ceil = Math.ceil; -var PossiblyWeakMap = typeof WeakMap === "function" ? WeakMap : Map; -var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher, - ReactCurrentOwner$1 = ReactSharedInternals.ReactCurrentOwner, - ReactCurrentBatchConfig = ReactSharedInternals.ReactCurrentBatchConfig, - ReactCurrentActQueue = ReactSharedInternals.ReactCurrentActQueue; -var NoContext = - /* */ - 0; -var BatchedContext = - /* */ - 1; -var RenderContext = - /* */ - 2; -var CommitContext = - /* */ - 4; -var RootInProgress = 0; -var RootFatalErrored = 1; -var RootErrored = 2; -var RootSuspended = 3; -var RootSuspendedWithDelay = 4; -var RootCompleted = 5; -var RootDidNotComplete = 6; // Describes where we are in the React execution stack + var instance = finishedWork.stateNode; -var executionContext = NoContext; // The root we're working on + if (typeof instance.componentDidMount === "function") { + try { + instance.componentDidMount(); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } + } // Commit any callbacks that would have fired while the component + // was hidden. -var workInProgressRoot = null; // The fiber we're working on + var updateQueue = finishedWork.updateQueue; -var workInProgress = null; // The lanes we're rendering + if (updateQueue !== null) { + commitHiddenCallbacks(updateQueue, instance); + } // If this is newly finished work, check for setState callbacks + + if (includeWorkInProgressEffects && flags & Callback) { + commitClassCallbacks(finishedWork); + } // TODO: Check flags & RefStatic + + safelyAttachRef(finishedWork, finishedWork.return); + break; + } + // Unlike commitLayoutEffectsOnFiber, we don't need to handle HostRoot + // because this function only visits nodes that are inside an + // Offscreen fiber. + // case HostRoot: { + // ... + // } + + case HostHoistable: + case HostSingleton: + case HostComponent: { + recursivelyTraverseReappearLayoutEffects( + finishedRoot, + finishedWork, + includeWorkInProgressEffects + ); // Renderers may schedule work to be done after host components are mounted + // (eg DOM renderer may schedule auto-focus for inputs and form controls). + // These effects should only be committed when components are first mounted, + // aka when there is no current/alternate. -var workInProgressRootRenderLanes = NoLanes; -var NotSuspended = 0; -var SuspendedOnError = 1; -var SuspendedOnData = 2; -var SuspendedOnImmediate = 3; -var SuspendedOnInstance = 4; -var SuspendedOnInstanceAndReadyToContinue = 5; -var SuspendedOnDeprecatedThrowPromise = 6; -var SuspendedAndReadyToContinue = 7; -var SuspendedOnHydration = 8; // When this is true, the work-in-progress fiber just suspended (or errored) and -// we've yet to unwind the stack. In some cases, we may yield to the main thread -// after this happens. If the fiber is pinged before we resume, we can retry -// immediately instead of unwinding the stack. + if (includeWorkInProgressEffects && current === null && flags & Update) { + commitHostComponentMount(finishedWork); + } // TODO: Check flags & Ref -var workInProgressSuspendedReason = NotSuspended; -var workInProgressThrownValue = null; // Whether a ping listener was attached during this render. This is slightly -// different that whether something suspended, because we don't add multiple -// listeners to a promise we've already seen (per root and lane). + safelyAttachRef(finishedWork, finishedWork.return); + break; + } -var workInProgressRootDidAttachPingListener = false; // A contextual version of workInProgressRootRenderLanes. It is a superset of -// the lanes that we started working on at the root. When we enter a subtree -// that is currently hidden, we add the lanes that would have committed if -// the hidden tree hadn't been deferred. This is modified by the -// HiddenContext module. -// -// Most things in the work loop should deal with workInProgressRootRenderLanes. -// Most things in begin/complete phases should deal with renderLanes. + case Profiler: { + recursivelyTraverseReappearLayoutEffects( + finishedRoot, + finishedWork, + includeWorkInProgressEffects + ); // TODO: Figure out how Profiler updates should work with Offscreen -var renderLanes = NoLanes; // Whether to root completed, errored, suspended, etc. + if (includeWorkInProgressEffects && flags & Update) { + commitProfilerUpdate(finishedWork, current); + } -var workInProgressRootExitStatus = RootInProgress; // A fatal error, if one is thrown + break; + } -var workInProgressRootFatalError = null; // The work left over by components that were visited during this render. Only -// includes unprocessed updates, not work in bailed out children. + case SuspenseComponent: { + recursivelyTraverseReappearLayoutEffects( + finishedRoot, + finishedWork, + includeWorkInProgressEffects + ); // TODO: Figure out how Suspense hydration callbacks should work -var workInProgressRootSkippedLanes = NoLanes; // Lanes that were updated (in an interleaved event) during this render. + break; + } -var workInProgressRootInterleavedUpdatedLanes = NoLanes; // Lanes that were updated during the render phase (*not* an interleaved event). + case OffscreenComponent: { + var offscreenState = finishedWork.memoizedState; + var isHidden = offscreenState !== null; -var workInProgressRootPingedLanes = NoLanes; // Errors that are thrown during the render phase. + if (isHidden); + else { + recursivelyTraverseReappearLayoutEffects( + finishedRoot, + finishedWork, + includeWorkInProgressEffects + ); + } // TODO: Check flags & Ref -var workInProgressRootConcurrentErrors = null; // These are errors that we recovered from without surfacing them to the UI. -// We will log them once the tree commits. + safelyAttachRef(finishedWork, finishedWork.return); + break; + } -var workInProgressRootRecoverableErrors = null; // The most recent time we committed a fallback. This lets us ensure a train -// model where we don't commit new loading states in too quick succession. + default: { + recursivelyTraverseReappearLayoutEffects( + finishedRoot, + finishedWork, + includeWorkInProgressEffects + ); + break; + } + } +} -var globalMostRecentFallbackTime = 0; -var FALLBACK_THROTTLE_MS = 500; // The absolute time for when we should start giving up on rendering -// more and prefer CPU suspense heuristics instead. +function recursivelyTraverseReappearLayoutEffects( + finishedRoot, + parentFiber, + includeWorkInProgressEffects +) { + // This function visits both newly finished work and nodes that were re-used + // from a previously committed tree. We cannot check non-static flags if the + // node was reused. + var childShouldIncludeWorkInProgressEffects = + includeWorkInProgressEffects && + (parentFiber.subtreeFlags & LayoutMask) !== NoFlags$1; // TODO (Offscreen) Check: flags & (RefStatic | LayoutStatic) -var workInProgressRootRenderTargetTime = Infinity; // How long a render is supposed to take before we start following CPU -// suspense heuristics and opt out of rendering more content. + var prevDebugFiber = getCurrentFiber(); + var child = parentFiber.child; -var RENDER_TIMEOUT_MS = 500; -var workInProgressTransitions = null; + while (child !== null) { + var current = child.alternate; + reappearLayoutEffects( + finishedRoot, + current, + child, + childShouldIncludeWorkInProgressEffects + ); + child = child.sibling; + } -function resetRenderTimer() { - workInProgressRootRenderTargetTime = now$1() + RENDER_TIMEOUT_MS; + setCurrentFiber(prevDebugFiber); } -function getRenderTargetTime() { - return workInProgressRootRenderTargetTime; -} -var hasUncaughtError = false; -var firstUncaughtError = null; -var legacyErrorBoundariesThatAlreadyFailed = null; // Only used when enableProfilerNestedUpdateScheduledHook is true; -var rootDoesHavePassiveEffects = false; -var rootWithPendingPassiveEffects = null; -var pendingPassiveEffectsLanes = NoLanes; -var pendingPassiveProfilerEffects = []; +function commitHookPassiveMountEffects(finishedWork, hookFlags) { + if (shouldProfile(finishedWork)) { + startPassiveEffectTimer(); -var NESTED_UPDATE_LIMIT = 50; -var nestedUpdateCount = 0; -var rootWithNestedUpdates = null; -var isFlushingPassiveEffects = false; -var didScheduleUpdateDuringPassiveEffects = false; -var NESTED_PASSIVE_UPDATE_LIMIT = 50; -var nestedPassiveUpdateCount = 0; -var rootWithPassiveNestedUpdates = null; // If two updates are scheduled within the same event, we should treat their -// event times as simultaneous, even if the actual clock time has advanced -// between the first and second call. + try { + commitHookEffectListMount(hookFlags, finishedWork); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } -var currentEventTime = NoTimestamp; -var currentEventTransitionLane = NoLanes; -var isRunningInsertionEffect = false; -function getWorkInProgressRoot() { - return workInProgressRoot; + recordPassiveEffectDuration(finishedWork); + } else { + try { + commitHookEffectListMount(hookFlags, finishedWork); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } + } } -function getWorkInProgressRootRenderLanes() { - return workInProgressRootRenderLanes; + +function commitPassiveMountEffects( + root, + finishedWork, + committedLanes, + committedTransitions +) { + setCurrentFiber(finishedWork); + commitPassiveMountOnFiber(root, finishedWork); + resetCurrentFiber(); } -function requestEventTime() { - if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { - // We're inside React, so it's fine to read the actual time. - return now$1(); - } // We're not inside React, so we may be in the middle of a browser event. - if (currentEventTime !== NoTimestamp) { - // Use the same start time for all updates until we enter React again. - return currentEventTime; - } // This is the first update since React yielded. Compute a new start time. +function recursivelyTraversePassiveMountEffects( + root, + parentFiber, + committedLanes, + committedTransitions +) { + var prevDebugFiber = getCurrentFiber(); - currentEventTime = now$1(); - return currentEventTime; -} -function requestUpdateLane(fiber) { - // Special cases - var mode = fiber.mode; + if (parentFiber.subtreeFlags & PassiveMask) { + var child = parentFiber.child; - if ((mode & ConcurrentMode) === NoMode) { - return SyncLane; - } else if ( - (executionContext & RenderContext) !== NoContext && - workInProgressRootRenderLanes !== NoLanes - ) { - // This is a render phase update. These are not officially supported. The - // old behavior is to give this the same "thread" (lanes) as - // whatever is currently rendering. So if you call `setState` on a component - // that happens later in the same render, it will flush. Ideally, we want to - // remove the special case and treat them as if they came from an - // interleaved event. Regardless, this pattern is not officially supported. - // This behavior is only a fallback. The flag only exists until we can roll - // out the setState warning, since existing code might accidentally rely on - // the current behavior. - return pickArbitraryLane(workInProgressRootRenderLanes); + while (child !== null) { + setCurrentFiber(child); + commitPassiveMountOnFiber(root, child); + child = child.sibling; + } } - var isTransition = requestCurrentTransition() !== NoTransition; + setCurrentFiber(prevDebugFiber); +} - if (isTransition) { - if (ReactCurrentBatchConfig.transition !== null) { - var transition = ReactCurrentBatchConfig.transition; +function commitPassiveMountOnFiber( + finishedRoot, + finishedWork, + committedLanes, + committedTransitions +) { + // When updating this function, also update reconnectPassiveEffects, which does + // most of the same things when an offscreen tree goes from hidden -> visible, + // or when toggling effects inside a hidden tree. + var flags = finishedWork.flags; - if (!transition._updatedFibers) { - transition._updatedFibers = new Set(); + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: { + recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork); + + if (flags & Passive$1) { + commitHookPassiveMountEffects(finishedWork, Passive | HasEffect); } - transition._updatedFibers.add(fiber); - } // The algorithm for assigning an update to a lane should be stable for all - // updates at the same priority within the same event. To do this, the - // inputs to the algorithm must be the same. - // - // The trick we use is to cache the first of each of these inputs within an - // event. Then reset the cached values once we can be sure the event is - // over. Our heuristic for that is whenever we enter a concurrent work loop. + break; + } + + case HostRoot: { + recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork); - if (currentEventTransitionLane === NoLane) { - // All transitions within the same event are assigned the same lane. - currentEventTransitionLane = claimNextTransitionLane(); + break; } - return currentEventTransitionLane; - } // Updates originating inside certain React methods, like flushSync, have - // their priority set by tracking it with a context variable. - // - // The opaque type returned by the host config is internally a lane, so we can - // use that directly. - // TODO: Move this type conversion to the event priority module. + case LegacyHiddenComponent: { + { + recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork); + } - var updateLane = getCurrentUpdatePriority(); + break; + } - if (updateLane !== NoLane) { - return updateLane; - } // This update originated outside React. Ask the host environment for an - // appropriate priority, based on the type of event. - // - // The opaque type returned by the host config is internally a lane, so we can - // use that directly. - // TODO: Move this type conversion to the event priority module. + case OffscreenComponent: { + // TODO: Pass `current` as argument to this function + var _instance3 = finishedWork.stateNode; + var nextState = finishedWork.memoizedState; + var isHidden = nextState !== null; - var eventLane = getCurrentEventPriority(); - return eventLane; -} + if (isHidden) { + if (_instance3._visibility & OffscreenPassiveEffectsConnected) { + // The effects are currently connected. Update them. + recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork); + } else { + if (finishedWork.mode & ConcurrentMode); + else { + // Legacy Mode: Fire the effects even if the tree is hidden. + _instance3._visibility |= OffscreenPassiveEffectsConnected; + recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork); + } + } + } else { + // Tree is visible + if (_instance3._visibility & OffscreenPassiveEffectsConnected) { + // The effects are currently connected. Update them. + recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork); + } else { + // The effects are currently disconnected. Reconnect them, while also + // firing effects inside newly mounted trees. This also applies to + // the initial render. + _instance3._visibility |= OffscreenPassiveEffectsConnected; + recursivelyTraverseReconnectPassiveEffects( + finishedRoot, + finishedWork + ); + } + } -function requestRetryLane(fiber) { - // This is a fork of `requestUpdateLane` designed specifically for Suspense - // "retries" — a special update that attempts to flip a Suspense boundary - // from its placeholder state to its primary/resolved state. - // Special cases - var mode = fiber.mode; + break; + } - if ((mode & ConcurrentMode) === NoMode) { - return SyncLane; - } + case CacheComponent: { + recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork); - return claimNextRetryLane(); -} + break; + } -function scheduleUpdateOnFiber(root, fiber, lane, eventTime) { - { - if (isRunningInsertionEffect) { - error("useInsertionEffect must not schedule updates."); + case TracingMarkerComponent: + // eslint-disable-next-line-no-fallthrough + + default: { + recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork); + break; } } +} - { - if (isFlushingPassiveEffects) { - didScheduleUpdateDuringPassiveEffects = true; - } - } // Check if the work loop is currently suspended and waiting for data to - // finish loading. +function recursivelyTraverseReconnectPassiveEffects( + finishedRoot, + parentFiber, + committedLanes, + committedTransitions, + includeWorkInProgressEffects +) { + var prevDebugFiber = getCurrentFiber(); + var child = parentFiber.child; - if ( - workInProgressSuspendedReason === SuspendedOnData && - root === workInProgressRoot - ) { - // The incoming update might unblock the current render. Interrupt the - // current attempt and restart from the top. - prepareFreshStack(root, NoLanes); - markRootSuspended(root, workInProgressRootRenderLanes); - } // Mark that the root has a pending update. + while (child !== null) { + reconnectPassiveEffects(finishedRoot, child); + child = child.sibling; + } - markRootUpdated(root, lane, eventTime); + setCurrentFiber(prevDebugFiber); +} - if ( - (executionContext & RenderContext) !== NoLanes && - root === workInProgressRoot - ) { - // This update was dispatched during the render phase. This is a mistake - // if the update originates from user space (with the exception of local - // hook updates, which are handled differently and don't reach this - // function), but there are some internal React features that use this as - // an implementation detail, like selective hydration. - warnAboutRenderPhaseUpdatesInDEV(fiber); // Track lanes that were updated during the render phase - } else { - // This is a normal update, scheduled from outside the render phase. For - // example, during an input event. - { - if (isDevToolsPresent) { - addFiberToLanesMap(root, fiber, lane); - } - } +function reconnectPassiveEffects( + finishedRoot, + finishedWork, + committedLanes, + committedTransitions, // This function visits both newly finished work and nodes that were re-used + // from a previously committed tree. We cannot check non-static flags if the + // node was reused. + includeWorkInProgressEffects +) { + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: { + recursivelyTraverseReconnectPassiveEffects(finishedRoot, finishedWork); // TODO: Check for PassiveStatic flag - warnIfUpdatesNotWrappedWithActDEV(fiber); + commitHookPassiveMountEffects(finishedWork, Passive); + break; + } + // Unlike commitPassiveMountOnFiber, we don't need to handle HostRoot + // because this function only visits nodes that are inside an + // Offscreen fiber. + // case HostRoot: { + // ... + // } - if (root === workInProgressRoot) { - // Received an update to a tree that's in the middle of rendering. Mark - // that there was an interleaved update work on this root. Unless the - // `deferRenderPhaseUpdateToNextBatch` flag is off and this is a render - // phase update. In that case, we don't treat render phase updates as if - // they were interleaved, for backwards compat reasons. - if ((executionContext & RenderContext) === NoContext) { - workInProgressRootInterleavedUpdatedLanes = mergeLanes( - workInProgressRootInterleavedUpdatedLanes, - lane - ); + case LegacyHiddenComponent: { + { + recursivelyTraverseReconnectPassiveEffects(finishedRoot, finishedWork); } - if (workInProgressRootExitStatus === RootSuspendedWithDelay) { - // The root already suspended with a delay, which means this render - // definitely won't finish. Since we have a new update, let's mark it as - // suspended now, right before marking the incoming update. This has the - // effect of interrupting the current render and switching to the update. - // TODO: Make sure this doesn't override pings that happen while we've - // already started rendering. - markRootSuspended(root, workInProgressRootRenderLanes); - } + break; } - ensureRootIsScheduled(root, eventTime); - - if ( - lane === SyncLane && - executionContext === NoContext && - (fiber.mode & ConcurrentMode) === NoMode && // Treat `act` as if it's inside `batchedUpdates`, even in legacy mode. - !ReactCurrentActQueue.isBatchingLegacy - ) { - // Flush the synchronous work now, unless we're already working or inside - // a batch. This is intentionally inside scheduleUpdateOnFiber instead of - // scheduleCallbackForFiber to preserve the ability to schedule a callback - // without immediately flushing it. We only do this for user-initiated - // updates, to preserve historical behavior of legacy mode. - resetRenderTimer(); - flushSyncCallbacksOnlyInLegacyMode(); - } - } -} -function isUnsafeClassRenderPhaseUpdate(fiber) { - // Check if this is a render phase update. Only called by class components, - // which special (deprecated) behavior for UNSAFE_componentWillReceive props. - return ( - // TODO: Remove outdated deferRenderPhaseUpdateToNextBatch experiment. We - // decided not to enable it. - (executionContext & RenderContext) !== NoContext - ); -} // Use this function to schedule a task for a root. There's only one task per -// root; if a task was already scheduled, we'll check to make sure the priority -// of the existing task is the same as the priority of the next level that the -// root has work on. This function is called on every update, and right before -// exiting a task. + case OffscreenComponent: { + var _instance4 = finishedWork.stateNode; + var nextState = finishedWork.memoizedState; + var isHidden = nextState !== null; -function ensureRootIsScheduled(root, currentTime) { - var existingCallbackNode = root.callbackNode; // Check if any lanes are being starved by other work. If so, mark them as - // expired so we know to work on those next. + if (isHidden) { + if (_instance4._visibility & OffscreenPassiveEffectsConnected) { + // The effects are currently connected. Update them. + recursivelyTraverseReconnectPassiveEffects( + finishedRoot, + finishedWork + ); + } else { + if (finishedWork.mode & ConcurrentMode); + else { + // Legacy Mode: Fire the effects even if the tree is hidden. + _instance4._visibility |= OffscreenPassiveEffectsConnected; + recursivelyTraverseReconnectPassiveEffects( + finishedRoot, + finishedWork + ); + } + } + } else { + // Tree is visible + // Since we're already inside a reconnecting tree, it doesn't matter + // whether the effects are currently connected. In either case, we'll + // continue traversing the tree and firing all the effects. + // + // We do need to set the "connected" flag on the instance, though. + _instance4._visibility |= OffscreenPassiveEffectsConnected; + recursivelyTraverseReconnectPassiveEffects(finishedRoot, finishedWork); + } - markStarvedLanesAsExpired(root, currentTime); // Determine the next lanes to work on, and their priority. + break; + } - var nextLanes = getNextLanes( - root, - root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes - ); + case CacheComponent: { + recursivelyTraverseReconnectPassiveEffects(finishedRoot, finishedWork); - if (nextLanes === NoLanes) { - // Special case: There's nothing to work on. - if (existingCallbackNode !== null) { - cancelCallback(existingCallbackNode); + break; } - root.callbackNode = null; - root.callbackPriority = NoLane; - return; - } // If this root is currently suspended and waiting for data to resolve, don't - // schedule a task to render it. We'll either wait for a ping, or wait to - // receive an update. + case TracingMarkerComponent: + // eslint-disable-next-line-no-fallthrough - if ( - workInProgressSuspendedReason === SuspendedOnData && - workInProgressRoot === root - ) { - root.callbackPriority = NoLane; - root.callbackNode = null; - return; + default: { + recursivelyTraverseReconnectPassiveEffects(finishedRoot, finishedWork); + break; + } } +} - var cancelPendingCommit = root.cancelPendingCommit; +function commitPassiveUnmountEffects(finishedWork) { + setCurrentFiber(finishedWork); + commitPassiveUnmountOnFiber(finishedWork); + resetCurrentFiber(); +} - if (cancelPendingCommit !== null) { - // We should only interrupt a pending commit if the new update - // is urgent. - if (includesOnlyNonUrgentLanes(nextLanes)) { - // The new update is not urgent. Don't interrupt the pending commit. - root.callbackPriority = NoLane; - root.callbackNode = null; - return; +function detachAlternateSiblings(parentFiber) { + // A fiber was deleted from this parent fiber, but it's still part of the + // previous (alternate) parent fiber's list of children. Because children + // are a linked list, an earlier sibling that's still alive will be + // connected to the deleted fiber via its `alternate`: + // + // live fiber --alternate--> previous live fiber --sibling--> deleted + // fiber + // + // We can't disconnect `alternate` on nodes that haven't been deleted yet, + // but we can disconnect the `sibling` and `child` pointers. + var previousFiber = parentFiber.alternate; + + if (previousFiber !== null) { + var detachedChild = previousFiber.child; + + if (detachedChild !== null) { + previousFiber.child = null; + + do { + // $FlowFixMe[incompatible-use] found when upgrading Flow + var detachedSibling = detachedChild.sibling; // $FlowFixMe[incompatible-use] found when upgrading Flow + + detachedChild.sibling = null; + detachedChild = detachedSibling; + } while (detachedChild !== null); } - } // We use the highest priority lane to represent the priority of the callback. + } +} - var newCallbackPriority = getHighestPriorityLane(nextLanes); // Check if there's an existing task. We may be able to reuse it. +function commitHookPassiveUnmountEffects( + finishedWork, + nearestMountedAncestor, + hookFlags +) { + if (shouldProfile(finishedWork)) { + startPassiveEffectTimer(); + commitHookEffectListUnmount( + hookFlags, + finishedWork, + nearestMountedAncestor + ); + recordPassiveEffectDuration(finishedWork); + } else { + commitHookEffectListUnmount( + hookFlags, + finishedWork, + nearestMountedAncestor + ); + } +} - var existingCallbackPriority = root.callbackPriority; +function recursivelyTraversePassiveUnmountEffects(parentFiber) { + // Deletions effects can be scheduled on any fiber type. They need to happen + // before the children effects have fired. + var deletions = parentFiber.deletions; - if ( - existingCallbackPriority === newCallbackPriority && // Special case related to `act`. If the currently scheduled task is a - // Scheduler task, rather than an `act` task, cancel it and re-scheduled - // on the `act` queue. - !( - ReactCurrentActQueue.current !== null && - existingCallbackNode !== fakeActCallbackNode - ) - ) { - { - // If we're going to re-use an existing task, it needs to exist. - // Assume that discrete update microtasks are non-cancellable and null. - // TODO: Temporary until we confirm this warning is not fired. - if ( - existingCallbackNode == null && - !includesSyncLane(existingCallbackPriority) - ) { - error( - "Expected scheduled callback to exist. This error is likely caused by a bug in React. Please file an issue." + if ((parentFiber.flags & ChildDeletion) !== NoFlags$1) { + if (deletions !== null) { + for (var i = 0; i < deletions.length; i++) { + var childToDelete = deletions[i]; // TODO: Convert this to use recursion + + nextEffect = childToDelete; + commitPassiveUnmountEffectsInsideOfDeletedTree_begin( + childToDelete, + parentFiber ); } - } // The priority hasn't changed. We can reuse the existing task. Exit. + } - return; + detachAlternateSiblings(parentFiber); } - if (existingCallbackNode != null) { - // Cancel the existing callback. We'll schedule a new one below. - cancelCallback(existingCallbackNode); - } // Schedule a new callback. - - var newCallbackNode; + var prevDebugFiber = getCurrentFiber(); // TODO: Split PassiveMask into separate masks for mount and unmount? - if (includesSyncLane(newCallbackPriority)) { - // Special case: Sync React callbacks are scheduled on a special - // internal queue - if (root.tag === LegacyRoot) { - if (ReactCurrentActQueue.isBatchingLegacy !== null) { - ReactCurrentActQueue.didScheduleLegacyUpdate = true; - } + if (parentFiber.subtreeFlags & PassiveMask) { + var child = parentFiber.child; - scheduleLegacySyncCallback(performSyncWorkOnRoot.bind(null, root)); - } else { - scheduleSyncCallback(performSyncWorkOnRoot.bind(null, root)); + while (child !== null) { + setCurrentFiber(child); + commitPassiveUnmountOnFiber(child); + child = child.sibling; } + } - { - // Flush the queue in an Immediate task. - scheduleCallback(ImmediatePriority, flushSyncCallbacks); - } + setCurrentFiber(prevDebugFiber); +} - newCallbackNode = null; - } else { - var schedulerPriorityLevel; +function commitPassiveUnmountOnFiber(finishedWork) { + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: { + recursivelyTraversePassiveUnmountEffects(finishedWork); - switch (lanesToEventPriority(nextLanes)) { - case DiscreteEventPriority: - schedulerPriorityLevel = ImmediatePriority; - break; + if (finishedWork.flags & Passive$1) { + commitHookPassiveUnmountEffects( + finishedWork, + finishedWork.return, + Passive | HasEffect + ); + } - case ContinuousEventPriority: - schedulerPriorityLevel = UserBlockingPriority; - break; + break; + } - case DefaultEventPriority: - schedulerPriorityLevel = NormalPriority; - break; + case OffscreenComponent: { + var instance = finishedWork.stateNode; + var nextState = finishedWork.memoizedState; + var isHidden = nextState !== null; - case IdleEventPriority: - schedulerPriorityLevel = IdlePriority; - break; + if ( + isHidden && + instance._visibility & OffscreenPassiveEffectsConnected && // For backwards compatibility, don't unmount when a tree suspends. In + // the future we may change this to unmount after a delay. + (finishedWork.return === null || + finishedWork.return.tag !== SuspenseComponent) + ) { + // The effects are currently connected. Disconnect them. + // TODO: Add option or heuristic to delay before disconnecting the + // effects. Then if the tree reappears before the delay has elapsed, we + // can skip toggling the effects entirely. + instance._visibility &= ~OffscreenPassiveEffectsConnected; + recursivelyTraverseDisconnectPassiveEffects(finishedWork); + } else { + recursivelyTraversePassiveUnmountEffects(finishedWork); + } - default: - schedulerPriorityLevel = NormalPriority; - break; + break; } - newCallbackNode = scheduleCallback( - schedulerPriorityLevel, - performConcurrentWorkOnRoot.bind(null, root) - ); + default: { + recursivelyTraversePassiveUnmountEffects(finishedWork); + break; + } } +} - root.callbackPriority = newCallbackPriority; - root.callbackNode = newCallbackNode; -} // This is the entry point for every concurrent task, i.e. anything that -// goes through Scheduler. +function recursivelyTraverseDisconnectPassiveEffects(parentFiber) { + // Deletions effects can be scheduled on any fiber type. They need to happen + // before the children effects have fired. + var deletions = parentFiber.deletions; -function performConcurrentWorkOnRoot(root, didTimeout) { - { - resetNestedUpdateFlag(); - } // Since we know we're in a React event, we can clear the current - // event time. The next update will compute a new event time. + if ((parentFiber.flags & ChildDeletion) !== NoFlags$1) { + if (deletions !== null) { + for (var i = 0; i < deletions.length; i++) { + var childToDelete = deletions[i]; // TODO: Convert this to use recursion - currentEventTime = NoTimestamp; - currentEventTransitionLane = NoLanes; + nextEffect = childToDelete; + commitPassiveUnmountEffectsInsideOfDeletedTree_begin( + childToDelete, + parentFiber + ); + } + } + + detachAlternateSiblings(parentFiber); + } - if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { - throw new Error("Should not already be working."); - } // Flush any pending passive effects before deciding which lanes to work on, - // in case they schedule additional work. + var prevDebugFiber = getCurrentFiber(); // TODO: Check PassiveStatic flag - var originalCallbackNode = root.callbackNode; - var didFlushPassiveEffects = flushPassiveEffects(); + var child = parentFiber.child; - if (didFlushPassiveEffects) { - // Something in the passive effect phase may have canceled the current task. - // Check if the task node for this root was changed. - if (root.callbackNode !== originalCallbackNode) { - // The current task was canceled. Exit. We don't need to call - // `ensureRootIsScheduled` because the check above implies either that - // there's a new task, or that there's no remaining work on this root. - return null; - } - } // Determine the next lanes to work on, using the fields stored - // on the root. + while (child !== null) { + setCurrentFiber(child); + disconnectPassiveEffect(child); + child = child.sibling; + } - var lanes = getNextLanes( - root, - root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes - ); + setCurrentFiber(prevDebugFiber); +} - if (lanes === NoLanes) { - // Defensive coding. This is never expected to happen. - return null; - } // We disable time-slicing in some cases: if the work has been CPU-bound - // for too long ("expired" work, to prevent starvation), or we're in - // sync-updates-by-default mode. - // TODO: We only check `didTimeout` defensively, to account for a Scheduler - // bug we're still investigating. Once the bug in Scheduler is fixed, - // we can remove this, since we track expiration ourselves. +function disconnectPassiveEffect(finishedWork) { + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: { + // TODO: Check PassiveStatic flag + commitHookPassiveUnmountEffects( + finishedWork, + finishedWork.return, + Passive + ); // When disconnecting passive effects, we fire the effects in the same + // order as during a deletiong: parent before child - var shouldTimeSlice = - !includesBlockingLane(root, lanes) && - !includesExpiredLane(root, lanes) && - !didTimeout; - var exitStatus = shouldTimeSlice - ? renderRootConcurrent(root, lanes) - : renderRootSync(root, lanes); + recursivelyTraverseDisconnectPassiveEffects(finishedWork); + break; + } - if (exitStatus !== RootInProgress) { - if (exitStatus === RootErrored) { - // If something threw an error, try rendering one more time. We'll - // render synchronously to block concurrent data mutations, and we'll - // includes all pending updates are included. If it still fails after - // the second attempt, we'll give up and commit the resulting tree. - var originallyAttemptedLanes = lanes; - var errorRetryLanes = getLanesToRetrySynchronouslyOnError( - root, - originallyAttemptedLanes - ); + case OffscreenComponent: { + var instance = finishedWork.stateNode; - if (errorRetryLanes !== NoLanes) { - lanes = errorRetryLanes; - exitStatus = recoverFromConcurrentError( - root, - originallyAttemptedLanes, - errorRetryLanes - ); + if (instance._visibility & OffscreenPassiveEffectsConnected) { + instance._visibility &= ~OffscreenPassiveEffectsConnected; + recursivelyTraverseDisconnectPassiveEffects(finishedWork); } + + break; } - if (exitStatus === RootFatalErrored) { - var fatalError = workInProgressRootFatalError; - prepareFreshStack(root, NoLanes); - markRootSuspended(root, lanes); - ensureRootIsScheduled(root, now$1()); - throw fatalError; + default: { + recursivelyTraverseDisconnectPassiveEffects(finishedWork); + break; } + } +} - if (exitStatus === RootDidNotComplete) { - // The render unwound without completing the tree. This happens in special - // cases where need to exit the current render without producing a - // consistent tree or committing. - markRootSuspended(root, lanes); +function commitPassiveUnmountEffectsInsideOfDeletedTree_begin( + deletedSubtreeRoot, + nearestMountedAncestor +) { + while (nextEffect !== null) { + var fiber = nextEffect; // Deletion effects fire in parent -> child order + // TODO: Check if fiber has a PassiveStatic flag + + setCurrentFiber(fiber); + commitPassiveUnmountInsideDeletedTreeOnFiber(fiber, nearestMountedAncestor); + resetCurrentFiber(); + var child = fiber.child; // TODO: Only traverse subtree if it has a PassiveStatic flag. + + if (child !== null) { + child.return = fiber; + nextEffect = child; } else { - // The render completed. - // Check if this render may have yielded to a concurrent event, and if so, - // confirm that any newly rendered stores are consistent. - // TODO: It's possible that even a concurrent render may never have yielded - // to the main thread, if it was fast enough, or if it expired. We could - // skip the consistency check in that case, too. - var renderWasConcurrent = !includesBlockingLane(root, lanes); - var finishedWork = root.current.alternate; + commitPassiveUnmountEffectsInsideOfDeletedTree_complete( + deletedSubtreeRoot + ); + } + } +} - if ( - renderWasConcurrent && - !isRenderConsistentWithExternalStores(finishedWork) - ) { - // A store was mutated in an interleaved event. Render again, - // synchronously, to block further mutations. - exitStatus = renderRootSync(root, lanes); // We need to check again if something threw +function commitPassiveUnmountEffectsInsideOfDeletedTree_complete( + deletedSubtreeRoot +) { + while (nextEffect !== null) { + var fiber = nextEffect; + var sibling = fiber.sibling; + var returnFiber = fiber.return; // Recursively traverse the entire deleted tree and clean up fiber fields. + // This is more aggressive than ideal, and the long term goal is to only + // have to detach the deleted tree at the root. - if (exitStatus === RootErrored) { - var _originallyAttemptedLanes = lanes; + detachFiberAfterEffects(fiber); - var _errorRetryLanes = getLanesToRetrySynchronouslyOnError( - root, - _originallyAttemptedLanes - ); + if (fiber === deletedSubtreeRoot) { + nextEffect = null; + return; + } - if (_errorRetryLanes !== NoLanes) { - lanes = _errorRetryLanes; - exitStatus = recoverFromConcurrentError( - root, - _originallyAttemptedLanes, - _errorRetryLanes - ); // We assume the tree is now consistent because we didn't yield to any - // concurrent events. - } - } + if (sibling !== null) { + sibling.return = returnFiber; + nextEffect = sibling; + return; + } - if (exitStatus === RootFatalErrored) { - var _fatalError = workInProgressRootFatalError; - prepareFreshStack(root, NoLanes); - markRootSuspended(root, lanes); - ensureRootIsScheduled(root, now$1()); - throw _fatalError; - } // FIXME: Need to check for RootDidNotComplete again. The factoring here - // isn't ideal. - } // We now have a consistent tree. The next step is either to commit it, - // or, if something suspended, wait to commit it after a timeout. + nextEffect = returnFiber; + } +} - root.finishedWork = finishedWork; - root.finishedLanes = lanes; - finishConcurrentRender(root, exitStatus, finishedWork, lanes); +function commitPassiveUnmountInsideDeletedTreeOnFiber( + current, + nearestMountedAncestor +) { + switch (current.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: { + commitHookPassiveUnmountEffects(current, nearestMountedAncestor, Passive); + break; } } +} - ensureRootIsScheduled(root, now$1()); +function invokeLayoutEffectMountInDEV(fiber) { + { + // We don't need to re-check StrictEffectsMode here. + // This function is only called if that check has already passed. + switch (fiber.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: { + try { + commitHookEffectListMount(Layout | HasEffect, fiber); + } catch (error) { + captureCommitPhaseError(fiber, fiber.return, error); + } - if (root.callbackNode === originalCallbackNode) { - // The task node scheduled for this root is the same one that's - // currently executed. Need to return a continuation. - return performConcurrentWorkOnRoot.bind(null, root); - } + break; + } - return null; -} + case ClassComponent: { + var instance = fiber.stateNode; -function recoverFromConcurrentError( - root, - originallyAttemptedLanes, - errorRetryLanes -) { - // If an error occurred during hydration, discard server response and fall - // back to client side render. - // Before rendering again, save the errors from the previous attempt. - var errorsFromFirstAttempt = workInProgressRootConcurrentErrors; - var wasRootDehydrated = isRootDehydrated(root); + try { + instance.componentDidMount(); + } catch (error) { + captureCommitPhaseError(fiber, fiber.return, error); + } - if (wasRootDehydrated) { - // The shell failed to hydrate. Set a flag to force a client rendering - // during the next attempt. To do this, we call prepareFreshStack now - // to create the root work-in-progress fiber. This is a bit weird in terms - // of factoring, because it relies on renderRootSync not calling - // prepareFreshStack again in the call below, which happens because the - // root and lanes haven't changed. - // - // TODO: I think what we should do is set ForceClientRender inside - // throwException, like we do for nested Suspense boundaries. The reason - // it's here instead is so we can switch to the synchronous work loop, too. - // Something to consider for a future refactor. - var rootWorkInProgress = prepareFreshStack(root, errorRetryLanes); - rootWorkInProgress.flags |= ForceClientRender; + break; + } + } + } +} - { - errorHydratingContainer(); +function invokePassiveEffectMountInDEV(fiber) { + { + // We don't need to re-check StrictEffectsMode here. + // This function is only called if that check has already passed. + switch (fiber.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: { + try { + commitHookEffectListMount(Passive | HasEffect, fiber); + } catch (error) { + captureCommitPhaseError(fiber, fiber.return, error); + } + + break; + } } } +} - var exitStatus = renderRootSync(root, errorRetryLanes); +function invokeLayoutEffectUnmountInDEV(fiber) { + { + // We don't need to re-check StrictEffectsMode here. + // This function is only called if that check has already passed. + switch (fiber.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: { + try { + commitHookEffectListUnmount(Layout | HasEffect, fiber, fiber.return); + } catch (error) { + captureCommitPhaseError(fiber, fiber.return, error); + } - if (exitStatus !== RootErrored) { - // Successfully finished rendering on retry - if (workInProgressRootDidAttachPingListener && !wasRootDehydrated) { - // During the synchronous render, we attached additional ping listeners. - // This is highly suggestive of an uncached promise (though it's not the - // only reason this would happen). If it was an uncached promise, then - // it may have masked a downstream error from ocurring without actually - // fixing it. Example: - // - // use(Promise.resolve('uncached')) - // throw new Error('Oops!') - // - // When this happens, there's a conflict between blocking potential - // concurrent data races and unwrapping uncached promise values. We - // have to choose one or the other. Because the data race recovery is - // a last ditch effort, we'll disable it. - root.errorRecoveryDisabledLanes = mergeLanes( - root.errorRecoveryDisabledLanes, - originallyAttemptedLanes - ); // Mark the current render as suspended and force it to restart. Once - // these lanes finish successfully, we'll re-enable the error recovery - // mechanism for subsequent updates. + break; + } - workInProgressRootInterleavedUpdatedLanes |= originallyAttemptedLanes; - return RootSuspendedWithDelay; - } // The errors from the failed first attempt have been recovered. Add - // them to the collection of recoverable errors. We'll log them in the - // commit phase. + case ClassComponent: { + var instance = fiber.stateNode; - var errorsFromSecondAttempt = workInProgressRootRecoverableErrors; - workInProgressRootRecoverableErrors = errorsFromFirstAttempt; // The errors from the second attempt should be queued after the errors - // from the first attempt, to preserve the causal sequence. + if (typeof instance.componentWillUnmount === "function") { + safelyCallComponentWillUnmount(fiber, fiber.return, instance); + } - if (errorsFromSecondAttempt !== null) { - queueRecoverableErrors(errorsFromSecondAttempt); + break; + } } } - - return exitStatus; } -function queueRecoverableErrors(errors) { - if (workInProgressRootRecoverableErrors === null) { - workInProgressRootRecoverableErrors = errors; - } else { - // $FlowFixMe[method-unbinding] - workInProgressRootRecoverableErrors.push.apply( - workInProgressRootRecoverableErrors, - errors - ); +function invokePassiveEffectUnmountInDEV(fiber) { + { + // We don't need to re-check StrictEffectsMode here. + // This function is only called if that check has already passed. + switch (fiber.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: { + try { + commitHookEffectListUnmount(Passive | HasEffect, fiber, fiber.return); + } catch (error) { + captureCommitPhaseError(fiber, fiber.return, error); + } + } + } } } -function finishConcurrentRender(root, exitStatus, finishedWork, lanes) { - switch (exitStatus) { - case RootInProgress: - case RootFatalErrored: { - throw new Error("Root did not complete. This is a bug in React."); - } - // Flow knows about invariant, so it complains if I add a break - // statement, but eslint doesn't know about invariant, so it complains - // if I do. eslint-disable-next-line no-fallthrough +if (typeof Symbol === "function" && Symbol.for) { + var symbolFor = Symbol.for; + symbolFor("selector.component"); + symbolFor("selector.has_pseudo_class"); + symbolFor("selector.role"); + symbolFor("selector.test_id"); + symbolFor("selector.text"); +} - case RootErrored: { - // We should have already attempted to retry this tree. If we reached - // this point, it errored again. Commit it. - commitRootWhenReady( - root, - finishedWork, - workInProgressRootRecoverableErrors, - workInProgressTransitions, - lanes +var ReactCurrentActQueue$1 = ReactSharedInternals.ReactCurrentActQueue; +function isLegacyActEnvironment(fiber) { + { + // Legacy mode. We preserve the behavior of React 17's act. It assumes an + // act environment whenever `jest` is defined, but you can still turn off + // spurious warnings by setting IS_REACT_ACT_ENVIRONMENT explicitly + // to false. + // $FlowFixMe[cannot-resolve-name] Flow doesn't know about IS_REACT_ACT_ENVIRONMENT global + typeof IS_REACT_ACT_ENVIRONMENT !== "undefined" // $FlowFixMe[cannot-resolve-name] + ? IS_REACT_ACT_ENVIRONMENT + : undefined; // $FlowFixMe - Flow doesn't know about jest + return warnsIfNotActing; + } +} +function isConcurrentActEnvironment() { + { + var isReactActEnvironmentGlobal = // $FlowFixMe[cannot-resolve-name] Flow doesn't know about IS_REACT_ACT_ENVIRONMENT global + typeof IS_REACT_ACT_ENVIRONMENT !== "undefined" // $FlowFixMe[cannot-resolve-name] + ? IS_REACT_ACT_ENVIRONMENT + : undefined; + + if ( + !isReactActEnvironmentGlobal && + ReactCurrentActQueue$1.current !== null + ) { + // TODO: Include link to relevant documentation page. + error( + "The current testing environment is not configured to support " + + "act(...)" ); - break; } - case RootSuspended: { - markRootSuspended(root, lanes); // We have an acceptable loading state. We need to figure out if we - // should immediately commit it or wait a bit. + return isReactActEnvironmentGlobal; + } +} - if ( - includesOnlyRetries(lanes) && // do not delay if we're inside an act() scope - !shouldForceFlushFallbacksInDEV() - ) { - // This render only included retries, no updates. Throttle committing - // retries so that we don't show too many loading states too quickly. - var msUntilTimeout = - globalMostRecentFallbackTime + FALLBACK_THROTTLE_MS - now$1(); // Don't bother with a very short suspense time. +var ceil = Math.ceil; +var PossiblyWeakMap = typeof WeakMap === "function" ? WeakMap : Map; +var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher, + ReactCurrentOwner$1 = ReactSharedInternals.ReactCurrentOwner, + ReactCurrentBatchConfig = ReactSharedInternals.ReactCurrentBatchConfig, + ReactCurrentActQueue = ReactSharedInternals.ReactCurrentActQueue; +var NoContext = + /* */ + 0; +var BatchedContext = + /* */ + 1; +var RenderContext = + /* */ + 2; +var CommitContext = + /* */ + 4; +var RootInProgress = 0; +var RootFatalErrored = 1; +var RootErrored = 2; +var RootSuspended = 3; +var RootSuspendedWithDelay = 4; +var RootCompleted = 5; +var RootDidNotComplete = 6; // Describes where we are in the React execution stack - if (msUntilTimeout > 10) { - var nextLanes = getNextLanes(root, NoLanes); +var executionContext = NoContext; // The root we're working on - if (nextLanes !== NoLanes) { - // There's additional work on this root. - break; - } // The render is suspended, it hasn't timed out, and there's no - // lower priority work to do. Instead of committing the fallback - // immediately, wait for more data to arrive. +var workInProgressRoot = null; // The fiber we're working on - root.timeoutHandle = scheduleTimeout( - commitRootWhenReady.bind( - null, - root, - finishedWork, - workInProgressRootRecoverableErrors, - workInProgressTransitions, - lanes - ), - msUntilTimeout - ); - break; - } - } // The work expired. Commit immediately. +var workInProgress = null; // The lanes we're rendering - commitRootWhenReady( - root, - finishedWork, - workInProgressRootRecoverableErrors, - workInProgressTransitions, - lanes - ); - break; - } +var workInProgressRootRenderLanes = NoLanes; +var NotSuspended = 0; +var SuspendedOnError = 1; +var SuspendedOnData = 2; +var SuspendedOnImmediate = 3; +var SuspendedOnInstance = 4; +var SuspendedOnInstanceAndReadyToContinue = 5; +var SuspendedOnDeprecatedThrowPromise = 6; +var SuspendedAndReadyToContinue = 7; +var SuspendedOnHydration = 8; // When this is true, the work-in-progress fiber just suspended (or errored) and +// we've yet to unwind the stack. In some cases, we may yield to the main thread +// after this happens. If the fiber is pinged before we resume, we can retry +// immediately instead of unwinding the stack. + +var workInProgressSuspendedReason = NotSuspended; +var workInProgressThrownValue = null; // Whether a ping listener was attached during this render. This is slightly +// different that whether something suspended, because we don't add multiple +// listeners to a promise we've already seen (per root and lane). + +var workInProgressRootDidAttachPingListener = false; // A contextual version of workInProgressRootRenderLanes. It is a superset of +// the lanes that we started working on at the root. When we enter a subtree +// that is currently hidden, we add the lanes that would have committed if +// the hidden tree hadn't been deferred. This is modified by the +// HiddenContext module. +// +// Most things in the work loop should deal with workInProgressRootRenderLanes. +// Most things in begin/complete phases should deal with renderLanes. - case RootSuspendedWithDelay: { - markRootSuspended(root, lanes); +var renderLanes = NoLanes; // Whether to root completed, errored, suspended, etc. - if (includesOnlyTransitions(lanes)) { - // This is a transition, so we should exit without committing a - // placeholder and without scheduling a timeout. Delay indefinitely - // until we receive more data. - break; - } +var workInProgressRootExitStatus = RootInProgress; // A fatal error, if one is thrown - if (!shouldForceFlushFallbacksInDEV()) { - // This is not a transition, but we did trigger an avoided state. - // Schedule a placeholder to display after a short delay, using the Just - // Noticeable Difference. - // TODO: Is the JND optimization worth the added complexity? If this is - // the only reason we track the event time, then probably not. - // Consider removing. - var mostRecentEventTime = getMostRecentEventTime(root, lanes); - var eventTimeMs = mostRecentEventTime; - var timeElapsedMs = now$1() - eventTimeMs; +var workInProgressRootFatalError = null; // The work left over by components that were visited during this render. Only +// includes unprocessed updates, not work in bailed out children. - var _msUntilTimeout = jnd(timeElapsedMs) - timeElapsedMs; // Don't bother with a very short suspense time. +var workInProgressRootSkippedLanes = NoLanes; // Lanes that were updated (in an interleaved event) during this render. - if (_msUntilTimeout > 10) { - // Instead of committing the fallback immediately, wait for more data - // to arrive. - root.timeoutHandle = scheduleTimeout( - commitRootWhenReady.bind( - null, - root, - finishedWork, - workInProgressRootRecoverableErrors, - workInProgressTransitions, - lanes - ), - _msUntilTimeout - ); - break; - } - } // Commit the placeholder. +var workInProgressRootInterleavedUpdatedLanes = NoLanes; // Lanes that were updated during the render phase (*not* an interleaved event). - commitRootWhenReady( - root, - finishedWork, - workInProgressRootRecoverableErrors, - workInProgressTransitions, - lanes - ); - break; - } +var workInProgressRootPingedLanes = NoLanes; // Errors that are thrown during the render phase. - case RootCompleted: { - // The work completed. - commitRootWhenReady( - root, - finishedWork, - workInProgressRootRecoverableErrors, - workInProgressTransitions, - lanes - ); - break; - } +var workInProgressRootConcurrentErrors = null; // These are errors that we recovered from without surfacing them to the UI. +// We will log them once the tree commits. - default: { - throw new Error("Unknown root exit status."); - } - } -} +var workInProgressRootRecoverableErrors = null; // The most recent time we committed a fallback. This lets us ensure a train +// model where we don't commit new loading states in too quick succession. -function commitRootWhenReady( - root, - finishedWork, - recoverableErrors, - transitions, - lanes -) { - if (includesOnlyNonUrgentLanes(lanes)) { - // suspend. If it's not ready, it will return a callback to subscribe to - // a ready event. +var globalMostRecentFallbackTime = 0; +var FALLBACK_THROTTLE_MS = 500; // The absolute time for when we should start giving up on rendering +// more and prefer CPU suspense heuristics instead. - var schedulePendingCommit = waitForCommitToBeReady(); +var workInProgressRootRenderTargetTime = Infinity; // How long a render is supposed to take before we start following CPU +// suspense heuristics and opt out of rendering more content. - if (schedulePendingCommit !== null) { - // NOTE: waitForCommitToBeReady returns a subscribe function so that we - // only allocate a function if the commit isn't ready yet. The other - // pattern would be to always pass a callback to waitForCommitToBeReady. - // Not yet ready to commit. Delay the commit until the renderer notifies - // us that it's ready. This will be canceled if we start work on the - // root again. - root.cancelPendingCommit = schedulePendingCommit( - commitRoot.bind( - null, - root, - workInProgressRootRecoverableErrors, - workInProgressTransitions - ) - ); - return; - } - } // Otherwise, commit immediately. +var RENDER_TIMEOUT_MS = 500; +var workInProgressTransitions = null; - commitRoot( - root, - workInProgressRootRecoverableErrors, - workInProgressTransitions - ); +function resetRenderTimer() { + workInProgressRootRenderTargetTime = now$1() + RENDER_TIMEOUT_MS; } -function isRenderConsistentWithExternalStores(finishedWork) { - // Search the rendered tree for external store reads, and check whether the - // stores were mutated in a concurrent event. Intentionally using an iterative - // loop instead of recursion so we can exit early. - var node = finishedWork; +function getRenderTargetTime() { + return workInProgressRootRenderTargetTime; +} +var hasUncaughtError = false; +var firstUncaughtError = null; +var legacyErrorBoundariesThatAlreadyFailed = null; // Only used when enableProfilerNestedUpdateScheduledHook is true; +var rootDoesHavePassiveEffects = false; +var rootWithPendingPassiveEffects = null; +var pendingPassiveEffectsLanes = NoLanes; +var pendingPassiveProfilerEffects = []; - while (true) { - if (node.flags & StoreConsistency) { - var updateQueue = node.updateQueue; +var NESTED_UPDATE_LIMIT = 50; +var nestedUpdateCount = 0; +var rootWithNestedUpdates = null; +var isFlushingPassiveEffects = false; +var didScheduleUpdateDuringPassiveEffects = false; +var NESTED_PASSIVE_UPDATE_LIMIT = 50; +var nestedPassiveUpdateCount = 0; +var rootWithPassiveNestedUpdates = null; // If two updates are scheduled within the same event, we should treat their +// event times as simultaneous, even if the actual clock time has advanced +// between the first and second call. - if (updateQueue !== null) { - var checks = updateQueue.stores; +var currentEventTime = NoTimestamp; +var currentEventTransitionLane = NoLanes; +var isRunningInsertionEffect = false; +function getWorkInProgressRoot() { + return workInProgressRoot; +} +function getWorkInProgressRootRenderLanes() { + return workInProgressRootRenderLanes; +} +function requestEventTime() { + if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { + // We're inside React, so it's fine to read the actual time. + return now$1(); + } // We're not inside React, so we may be in the middle of a browser event. - if (checks !== null) { - for (var i = 0; i < checks.length; i++) { - var check = checks[i]; - var getSnapshot = check.getSnapshot; - var renderedValue = check.value; + if (currentEventTime !== NoTimestamp) { + // Use the same start time for all updates until we enter React again. + return currentEventTime; + } // This is the first update since React yielded. Compute a new start time. - try { - if (!objectIs(getSnapshot(), renderedValue)) { - // Found an inconsistent store. - return false; - } - } catch (error) { - // If `getSnapshot` throws, return `false`. This will schedule - // a re-render, and the error will be rethrown during render. - return false; - } - } - } - } - } + currentEventTime = now$1(); + return currentEventTime; +} +function requestUpdateLane(fiber) { + // Special cases + var mode = fiber.mode; - var child = node.child; + if ((mode & ConcurrentMode) === NoMode) { + return SyncLane; + } else if ( + (executionContext & RenderContext) !== NoContext && + workInProgressRootRenderLanes !== NoLanes + ) { + // This is a render phase update. These are not officially supported. The + // old behavior is to give this the same "thread" (lanes) as + // whatever is currently rendering. So if you call `setState` on a component + // that happens later in the same render, it will flush. Ideally, we want to + // remove the special case and treat them as if they came from an + // interleaved event. Regardless, this pattern is not officially supported. + // This behavior is only a fallback. The flag only exists until we can roll + // out the setState warning, since existing code might accidentally rely on + // the current behavior. + return pickArbitraryLane(workInProgressRootRenderLanes); + } - if (node.subtreeFlags & StoreConsistency && child !== null) { - child.return = node; - node = child; - continue; - } + var isTransition = requestCurrentTransition() !== NoTransition; - if (node === finishedWork) { - return true; - } + if (isTransition) { + if (ReactCurrentBatchConfig.transition !== null) { + var transition = ReactCurrentBatchConfig.transition; - while (node.sibling === null) { - if (node.return === null || node.return === finishedWork) { - return true; + if (!transition._updatedFibers) { + transition._updatedFibers = new Set(); } - node = node.return; + transition._updatedFibers.add(fiber); + } // The algorithm for assigning an update to a lane should be stable for all + // updates at the same priority within the same event. To do this, the + // inputs to the algorithm must be the same. + // + // The trick we use is to cache the first of each of these inputs within an + // event. Then reset the cached values once we can be sure the event is + // over. Our heuristic for that is whenever we enter a concurrent work loop. + + if (currentEventTransitionLane === NoLane) { + // All transitions within the same event are assigned the same lane. + currentEventTransitionLane = claimNextTransitionLane(); } - node.sibling.return = node.return; - node = node.sibling; - } // Flow doesn't know this is unreachable, but eslint does - // eslint-disable-next-line no-unreachable + return currentEventTransitionLane; + } // Updates originating inside certain React methods, like flushSync, have + // their priority set by tracking it with a context variable. + // + // The opaque type returned by the host config is internally a lane, so we can + // use that directly. + // TODO: Move this type conversion to the event priority module. + + var updateLane = getCurrentUpdatePriority(); + + if (updateLane !== NoLane) { + return updateLane; + } // This update originated outside React. Ask the host environment for an + // appropriate priority, based on the type of event. + // + // The opaque type returned by the host config is internally a lane, so we can + // use that directly. + // TODO: Move this type conversion to the event priority module. - return true; + var eventLane = getCurrentEventPriority(); + return eventLane; } -function markRootSuspended(root, suspendedLanes) { - // When suspending, we should always exclude lanes that were pinged or (more - // rarely, since we try to avoid it) updated during the render phase. - // TODO: Lol maybe there's a better way to factor this besides this - // obnoxiously named function :) - suspendedLanes = removeLanes(suspendedLanes, workInProgressRootPingedLanes); - suspendedLanes = removeLanes( - suspendedLanes, - workInProgressRootInterleavedUpdatedLanes - ); - markRootSuspended$1(root, suspendedLanes); -} // This is the entry point for synchronous tasks that don't go -// through Scheduler - -function performSyncWorkOnRoot(root) { - { - syncNestedUpdateFlag(); - } +function requestRetryLane(fiber) { + // This is a fork of `requestUpdateLane` designed specifically for Suspense + // "retries" — a special update that attempts to flip a Suspense boundary + // from its placeholder state to its primary/resolved state. + // Special cases + var mode = fiber.mode; - if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { - throw new Error("Should not already be working."); + if ((mode & ConcurrentMode) === NoMode) { + return SyncLane; } - flushPassiveEffects(); - var lanes = getNextLanes(root, NoLanes); + return claimNextRetryLane(); +} - if (!includesSyncLane(lanes)) { - // There's no remaining sync work left. - ensureRootIsScheduled(root, now$1()); - return null; +function scheduleUpdateOnFiber(root, fiber, lane, eventTime) { + { + if (isRunningInsertionEffect) { + error("useInsertionEffect must not schedule updates."); + } } - var exitStatus = renderRootSync(root, lanes); - - if (root.tag !== LegacyRoot && exitStatus === RootErrored) { - // If something threw an error, try rendering one more time. We'll render - // synchronously to block concurrent data mutations, and we'll includes - // all pending updates are included. If it still fails after the second - // attempt, we'll give up and commit the resulting tree. - var originallyAttemptedLanes = lanes; - var errorRetryLanes = getLanesToRetrySynchronouslyOnError( - root, - originallyAttemptedLanes - ); - - if (errorRetryLanes !== NoLanes) { - lanes = errorRetryLanes; - exitStatus = recoverFromConcurrentError( - root, - originallyAttemptedLanes, - errorRetryLanes - ); + { + if (isFlushingPassiveEffects) { + didScheduleUpdateDuringPassiveEffects = true; } - } + } // Check if the work loop is currently suspended and waiting for data to + // finish loading. - if (exitStatus === RootFatalErrored) { - var fatalError = workInProgressRootFatalError; + if ( + workInProgressSuspendedReason === SuspendedOnData && + root === workInProgressRoot + ) { + // The incoming update might unblock the current render. Interrupt the + // current attempt and restart from the top. prepareFreshStack(root, NoLanes); - markRootSuspended(root, lanes); - ensureRootIsScheduled(root, now$1()); - throw fatalError; - } + markRootSuspended(root, workInProgressRootRenderLanes); + } // Mark that the root has a pending update. - if (exitStatus === RootDidNotComplete) { - // The render unwound without completing the tree. This happens in special - // cases where need to exit the current render without producing a - // consistent tree or committing. - markRootSuspended(root, lanes); - ensureRootIsScheduled(root, now$1()); - return null; - } // We now have a consistent tree. Because this is a sync render, we - // will commit it even if something suspended. + markRootUpdated(root, lane, eventTime); - var finishedWork = root.current.alternate; - root.finishedWork = finishedWork; - root.finishedLanes = lanes; - commitRoot( - root, - workInProgressRootRecoverableErrors, - workInProgressTransitions - ); // Before exiting, make sure there's a callback scheduled for the next - // pending level. + if ( + (executionContext & RenderContext) !== NoLanes && + root === workInProgressRoot + ) { + // This update was dispatched during the render phase. This is a mistake + // if the update originates from user space (with the exception of local + // hook updates, which are handled differently and don't reach this + // function), but there are some internal React features that use this as + // an implementation detail, like selective hydration. + warnAboutRenderPhaseUpdatesInDEV(fiber); // Track lanes that were updated during the render phase + } else { + // This is a normal update, scheduled from outside the render phase. For + // example, during an input event. + { + if (isDevToolsPresent) { + addFiberToLanesMap(root, fiber, lane); + } + } - ensureRootIsScheduled(root, now$1()); - return null; -} -function getExecutionContext() { - return executionContext; -} -function batchedUpdates$1(fn, a) { - var prevExecutionContext = executionContext; - executionContext |= BatchedContext; + warnIfUpdatesNotWrappedWithActDEV(fiber); - try { - return fn(a); - } finally { - executionContext = prevExecutionContext; // If there were legacy sync updates, flush them at the end of the outer - // most batchedUpdates-like method. + if (root === workInProgressRoot) { + // Received an update to a tree that's in the middle of rendering. Mark + // that there was an interleaved update work on this root. Unless the + // `deferRenderPhaseUpdateToNextBatch` flag is off and this is a render + // phase update. In that case, we don't treat render phase updates as if + // they were interleaved, for backwards compat reasons. + if ((executionContext & RenderContext) === NoContext) { + workInProgressRootInterleavedUpdatedLanes = mergeLanes( + workInProgressRootInterleavedUpdatedLanes, + lane + ); + } + + if (workInProgressRootExitStatus === RootSuspendedWithDelay) { + // The root already suspended with a delay, which means this render + // definitely won't finish. Since we have a new update, let's mark it as + // suspended now, right before marking the incoming update. This has the + // effect of interrupting the current render and switching to the update. + // TODO: Make sure this doesn't override pings that happen while we've + // already started rendering. + markRootSuspended(root, workInProgressRootRenderLanes); + } + } + + ensureRootIsScheduled(root, eventTime); if ( - executionContext === NoContext && // Treat `act` as if it's inside `batchedUpdates`, even in legacy mode. + lane === SyncLane && + executionContext === NoContext && + (fiber.mode & ConcurrentMode) === NoMode && // Treat `act` as if it's inside `batchedUpdates`, even in legacy mode. !ReactCurrentActQueue.isBatchingLegacy ) { + // Flush the synchronous work now, unless we're already working or inside + // a batch. This is intentionally inside scheduleUpdateOnFiber instead of + // scheduleCallbackForFiber to preserve the ability to schedule a callback + // without immediately flushing it. We only do this for user-initiated + // updates, to preserve historical behavior of legacy mode. resetRenderTimer(); flushSyncCallbacksOnlyInLegacyMode(); } } } -// Warning, this opts-out of checking the function body. -// eslint-disable-next-line no-unused-vars -// eslint-disable-next-line no-redeclare -// eslint-disable-next-line no-redeclare - -function flushSync(fn) { - // In legacy mode, we flush pending passive effects at the beginning of the - // next event, not at the end of the previous one. - if ( - rootWithPendingPassiveEffects !== null && - rootWithPendingPassiveEffects.tag === LegacyRoot && - (executionContext & (RenderContext | CommitContext)) === NoContext - ) { - flushPassiveEffects(); - } - - var prevExecutionContext = executionContext; - executionContext |= BatchedContext; - var prevTransition = ReactCurrentBatchConfig.transition; - var previousPriority = getCurrentUpdatePriority(); - - try { - ReactCurrentBatchConfig.transition = null; - setCurrentUpdatePriority(DiscreteEventPriority); - - if (fn) { - return fn(); - } else { - return undefined; - } - } finally { - setCurrentUpdatePriority(previousPriority); - ReactCurrentBatchConfig.transition = prevTransition; - executionContext = prevExecutionContext; // Flush the immediate callbacks that were scheduled during this batch. - // Note that this will happen even if batchedUpdates is higher up - // the stack. - - if ((executionContext & (RenderContext | CommitContext)) === NoContext) { - flushSyncCallbacks(); - } - } -} -// hidden subtree. The stack logic is managed there because that's the only -// place that ever modifies it. Which module it lives in doesn't matter for -// performance because this function will get inlined regardless - -function setRenderLanes(subtreeRenderLanes) { - renderLanes = subtreeRenderLanes; -} -function getRenderLanes() { - return renderLanes; -} - -function resetWorkInProgressStack() { - if (workInProgress === null) return; - var interruptedWork; - - if (workInProgressSuspendedReason === NotSuspended) { - // Normal case. Work-in-progress hasn't started yet. Unwind all - // its parents. - interruptedWork = workInProgress.return; - } else { - // Work-in-progress is in suspended state. Reset the work loop and unwind - // both the suspended fiber and all its parents. - resetSuspendedWorkLoopOnUnwind(); - interruptedWork = workInProgress; - } +function isUnsafeClassRenderPhaseUpdate(fiber) { + // Check if this is a render phase update. Only called by class components, + // which special (deprecated) behavior for UNSAFE_componentWillReceive props. + return ( + // TODO: Remove outdated deferRenderPhaseUpdateToNextBatch experiment. We + // decided not to enable it. + (executionContext & RenderContext) !== NoContext + ); +} // Use this function to schedule a task for a root. There's only one task per +// root; if a task was already scheduled, we'll check to make sure the priority +// of the existing task is the same as the priority of the next level that the +// root has work on. This function is called on every update, and right before +// exiting a task. - while (interruptedWork !== null) { - var current = interruptedWork.alternate; - unwindInterruptedWork(current, interruptedWork); - interruptedWork = interruptedWork.return; - } +function ensureRootIsScheduled(root, currentTime) { + var existingCallbackNode = root.callbackNode; // Check if any lanes are being starved by other work. If so, mark them as + // expired so we know to work on those next. - workInProgress = null; -} + markStarvedLanesAsExpired(root, currentTime); // Determine the next lanes to work on, and their priority. -function prepareFreshStack(root, lanes) { - root.finishedWork = null; - root.finishedLanes = NoLanes; - var timeoutHandle = root.timeoutHandle; + var nextLanes = getNextLanes( + root, + root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes + ); - if (timeoutHandle !== noTimeout) { - // The root previous suspended and scheduled a timeout to commit a fallback - // state. Now that we have additional work, cancel the timeout. - root.timeoutHandle = noTimeout; // $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above + if (nextLanes === NoLanes) { + // Special case: There's nothing to work on. + if (existingCallbackNode !== null) { + cancelCallback(existingCallbackNode); + } - cancelTimeout(timeoutHandle); + root.callbackNode = null; + root.callbackPriority = NoLane; + return; + } // If this root is currently suspended and waiting for data to resolve, don't + // schedule a task to render it. We'll either wait for a ping, or wait to + // receive an update. + + if ( + workInProgressSuspendedReason === SuspendedOnData && + workInProgressRoot === root + ) { + root.callbackPriority = NoLane; + root.callbackNode = null; + return; } var cancelPendingCommit = root.cancelPendingCommit; if (cancelPendingCommit !== null) { - root.cancelPendingCommit = null; - cancelPendingCommit(); - } - - resetWorkInProgressStack(); - workInProgressRoot = root; - var rootWorkInProgress = createWorkInProgress(root.current, null); - workInProgress = rootWorkInProgress; - workInProgressRootRenderLanes = renderLanes = lanes; - workInProgressSuspendedReason = NotSuspended; - workInProgressThrownValue = null; - workInProgressRootDidAttachPingListener = false; - workInProgressRootExitStatus = RootInProgress; - workInProgressRootFatalError = null; - workInProgressRootSkippedLanes = NoLanes; - workInProgressRootInterleavedUpdatedLanes = NoLanes; - workInProgressRootPingedLanes = NoLanes; - workInProgressRootConcurrentErrors = null; - workInProgressRootRecoverableErrors = null; - finishQueueingConcurrentUpdates(); - - { - ReactStrictModeWarnings.discardPendingWarnings(); - } - - return rootWorkInProgress; -} - -function resetSuspendedWorkLoopOnUnwind() { - // Reset module-level state that was set during the render phase. - resetContextDependencies(); - resetHooksOnUnwind(); - resetChildReconcilerOnUnwind(); -} + // We should only interrupt a pending commit if the new update + // is urgent. + if (includesOnlyNonUrgentLanes(nextLanes)) { + // The new update is not urgent. Don't interrupt the pending commit. + root.callbackPriority = NoLane; + root.callbackNode = null; + return; + } + } // We use the highest priority lane to represent the priority of the callback. -function handleThrow(root, thrownValue) { - // A component threw an exception. Usually this is because it suspended, but - // it also includes regular program errors. - // - // We're either going to unwind the stack to show a Suspense or error - // boundary, or we're going to replay the component again. Like after a - // promise resolves. - // - // Until we decide whether we're going to unwind or replay, we should preserve - // the current state of the work loop without resetting anything. - // - // If we do decide to unwind the stack, module-level variables will be reset - // in resetSuspendedWorkLoopOnUnwind. - // These should be reset immediately because they're only supposed to be set - // when React is executing user code. - resetHooksAfterThrow(); - resetCurrentFiber(); - ReactCurrentOwner$1.current = null; + var newCallbackPriority = getHighestPriorityLane(nextLanes); // Check if there's an existing task. We may be able to reuse it. - if (thrownValue === SuspenseException) { - // This is a special type of exception used for Suspense. For historical - // reasons, the rest of the Suspense implementation expects the thrown value - // to be a thenable, because before `use` existed that was the (unstable) - // API for suspending. This implementation detail can change later, once we - // deprecate the old API in favor of `use`. - thrownValue = getSuspendedThenable(); - workInProgressSuspendedReason = - shouldRemainOnPreviousScreen() && // Check if there are other pending updates that might possibly unblock this - // component from suspending. This mirrors the check in - // renderDidSuspendDelayIfPossible. We should attempt to unify them somehow. - // TODO: Consider unwinding immediately, using the - // SuspendedOnHydration mechanism. - !includesNonIdleWork(workInProgressRootSkippedLanes) && - !includesNonIdleWork(workInProgressRootInterleavedUpdatedLanes) // Suspend work loop until data resolves - ? SuspendedOnData // Don't suspend work loop, except to check if the data has - : // immediately resolved (i.e. in a microtask). Otherwise, trigger the - // nearest Suspense fallback. - SuspendedOnImmediate; - } else if (thrownValue === SuspenseyCommitException) { - thrownValue = getSuspendedThenable(); - workInProgressSuspendedReason = SuspendedOnInstance; - } else if (thrownValue === SelectiveHydrationException) { - // An update flowed into a dehydrated boundary. Before we can apply the - // update, we need to finish hydrating. Interrupt the work-in-progress - // render so we can restart at the hydration lane. - // - // The ideal implementation would be able to switch contexts without - // unwinding the current stack. - // - // We could name this something more general but as of now it's the only - // case where we think this should happen. - workInProgressSuspendedReason = SuspendedOnHydration; - } else { - // This is a regular error. - var isWakeable = - thrownValue !== null && - typeof thrownValue === "object" && - typeof thrownValue.then === "function"; - workInProgressSuspendedReason = isWakeable // A wakeable object was thrown by a legacy Suspense implementation. - ? // This has slightly different behavior than suspending with `use`. - SuspendedOnDeprecatedThrowPromise // This is a regular error. If something earlier in the component already - : // suspended, we must clear the thenable state to unblock the work loop. - SuspendedOnError; - } + var existingCallbackPriority = root.callbackPriority; - workInProgressThrownValue = thrownValue; - var erroredWork = workInProgress; + if ( + existingCallbackPriority === newCallbackPriority && // Special case related to `act`. If the currently scheduled task is a + // Scheduler task, rather than an `act` task, cancel it and re-scheduled + // on the `act` queue. + !( + ReactCurrentActQueue.current !== null && + existingCallbackNode !== fakeActCallbackNode + ) + ) { + { + // If we're going to re-use an existing task, it needs to exist. + // Assume that discrete update microtasks are non-cancellable and null. + // TODO: Temporary until we confirm this warning is not fired. + if ( + existingCallbackNode == null && + !includesSyncLane(existingCallbackPriority) + ) { + error( + "Expected scheduled callback to exist. This error is likely caused by a bug in React. Please file an issue." + ); + } + } // The priority hasn't changed. We can reuse the existing task. Exit. - if (erroredWork === null) { - // This is a fatal error - workInProgressRootExitStatus = RootFatalErrored; - workInProgressRootFatalError = thrownValue; return; } - if (erroredWork.mode & ProfileMode) { - // Record the time spent rendering before an error was thrown. This - // avoids inaccurate Profiler durations in the case of a - // suspended render. - stopProfilerTimerIfRunningAndRecordDelta(erroredWork, true); - } + if (existingCallbackNode != null) { + // Cancel the existing callback. We'll schedule a new one below. + cancelCallback(existingCallbackNode); + } // Schedule a new callback. - { - markComponentRenderStopped(); + var newCallbackNode; - switch (workInProgressSuspendedReason) { - case SuspendedOnError: { - markComponentErrored( - erroredWork, - thrownValue, - workInProgressRootRenderLanes - ); - break; + if (includesSyncLane(newCallbackPriority)) { + // Special case: Sync React callbacks are scheduled on a special + // internal queue + if (root.tag === LegacyRoot) { + if (ReactCurrentActQueue.isBatchingLegacy !== null) { + ReactCurrentActQueue.didScheduleLegacyUpdate = true; } - case SuspendedOnData: - case SuspendedOnImmediate: - case SuspendedOnDeprecatedThrowPromise: - case SuspendedAndReadyToContinue: { - var wakeable = thrownValue; - markComponentSuspended( - erroredWork, - wakeable, - workInProgressRootRenderLanes - ); - break; - } + scheduleLegacySyncCallback(performSyncWorkOnRoot.bind(null, root)); + } else { + scheduleSyncCallback(performSyncWorkOnRoot.bind(null, root)); } - } -} -function shouldRemainOnPreviousScreen() { - // This is asking whether it's better to suspend the transition and remain - // on the previous screen, versus showing a fallback as soon as possible. It - // takes into account both the priority of render and also whether showing a - // fallback would produce a desirable user experience. - // TODO: Once `use` has fully replaced the `throw promise` pattern, we should - // be able to remove the equivalent check in finishConcurrentRender, and rely - // just on this one. - if (includesOnlyTransitions(workInProgressRootRenderLanes)) { - if (getShellBoundary() === null) { - // We're rendering inside the "shell" of the app. Activating the nearest - // fallback would cause visible content to disappear. It's better to - // suspend the transition and remain on the previous screen. - return true; - } else { - // We're rendering content that wasn't part of the previous screen. - // Rather than block the transition, it's better to show a fallback as - // soon as possible. The appearance of any nested fallbacks will be - // throttled to avoid jank. - return false; + { + // Flush the queue in an Immediate task. + scheduleCallback(ImmediatePriority, flushSyncCallbacks); } - } - var handler = getSuspenseHandler(); + newCallbackNode = null; + } else { + var schedulerPriorityLevel; + + switch (lanesToEventPriority(nextLanes)) { + case DiscreteEventPriority: + schedulerPriorityLevel = ImmediatePriority; + break; + + case ContinuousEventPriority: + schedulerPriorityLevel = UserBlockingPriority; + break; - if (handler === null); - else { - if (includesOnlyRetries(workInProgressRootRenderLanes)) { - // During a retry, we can suspend rendering if the nearest Suspense boundary - // is the boundary of the "shell", because we're guaranteed not to block - // any new content from appearing. - return handler === getShellBoundary(); - } - } // For all other Lanes besides Transitions and Retries, we should not wait - // for the data to load. - // TODO: We should wait during Offscreen prerendering, too. + case DefaultEventPriority: + schedulerPriorityLevel = NormalPriority; + break; - return false; -} + case IdleEventPriority: + schedulerPriorityLevel = IdlePriority; + break; -function pushDispatcher(container) { - var prevDispatcher = ReactCurrentDispatcher.current; - ReactCurrentDispatcher.current = ContextOnlyDispatcher; + default: + schedulerPriorityLevel = NormalPriority; + break; + } - if (prevDispatcher === null) { - // The React isomorphic package does not include a default dispatcher. - // Instead the first renderer will lazily attach one, in order to give - // nicer error messages. - return ContextOnlyDispatcher; - } else { - return prevDispatcher; + newCallbackNode = scheduleCallback( + schedulerPriorityLevel, + performConcurrentWorkOnRoot.bind(null, root) + ); } -} -function popDispatcher(prevDispatcher) { - ReactCurrentDispatcher.current = prevDispatcher; -} + root.callbackPriority = newCallbackPriority; + root.callbackNode = newCallbackNode; +} // This is the entry point for every concurrent task, i.e. anything that +// goes through Scheduler. -function markCommitTimeOfFallback() { - globalMostRecentFallbackTime = now$1(); -} -function markSkippedUpdateLanes(lane) { - workInProgressRootSkippedLanes = mergeLanes( - lane, - workInProgressRootSkippedLanes - ); -} -function renderDidSuspend() { - if (workInProgressRootExitStatus === RootInProgress) { - workInProgressRootExitStatus = RootSuspended; - } -} -function renderDidSuspendDelayIfPossible() { - workInProgressRootExitStatus = RootSuspendedWithDelay; // Check if there are updates that we skipped tree that might have unblocked - // this render. +function performConcurrentWorkOnRoot(root, didTimeout) { + { + resetNestedUpdateFlag(); + } // Since we know we're in a React event, we can clear the current + // event time. The next update will compute a new event time. - if ( - workInProgressRoot !== null && - (includesNonIdleWork(workInProgressRootSkippedLanes) || - includesNonIdleWork(workInProgressRootInterleavedUpdatedLanes)) - ) { - // Mark the current render as suspended so that we switch to working on - // the updates that were skipped. Usually we only suspend at the end of - // the render phase. - // TODO: We should probably always mark the root as suspended immediately - // (inside this function), since by suspending at the end of the render - // phase introduces a potential mistake where we suspend lanes that were - // pinged or updated while we were rendering. - // TODO: Consider unwinding immediately, using the - // SuspendedOnHydration mechanism. - // $FlowFixMe[incompatible-call] need null check workInProgressRoot - markRootSuspended(workInProgressRoot, workInProgressRootRenderLanes); - } -} -function renderDidError(error) { - if (workInProgressRootExitStatus !== RootSuspendedWithDelay) { - workInProgressRootExitStatus = RootErrored; - } + currentEventTime = NoTimestamp; + currentEventTransitionLane = NoLanes; - if (workInProgressRootConcurrentErrors === null) { - workInProgressRootConcurrentErrors = [error]; - } else { - workInProgressRootConcurrentErrors.push(error); - } -} // Called during render to determine if anything has suspended. -// Returns false if we're not sure. + if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { + throw new Error("Should not already be working."); + } // Flush any pending passive effects before deciding which lanes to work on, + // in case they schedule additional work. -function renderHasNotSuspendedYet() { - // If something errored or completed, we can't really be sure, - // so those are false. - return workInProgressRootExitStatus === RootInProgress; -} // TODO: Over time, this function and renderRootConcurrent have become more -// and more similar. Not sure it makes sense to maintain forked paths. Consider -// unifying them again. + var originalCallbackNode = root.callbackNode; + var didFlushPassiveEffects = flushPassiveEffects(); -function renderRootSync(root, lanes) { - var prevExecutionContext = executionContext; - executionContext |= RenderContext; - var prevDispatcher = pushDispatcher(); - // and prepare a fresh one. Otherwise we'll continue where we left off. + if (didFlushPassiveEffects) { + // Something in the passive effect phase may have canceled the current task. + // Check if the task node for this root was changed. + if (root.callbackNode !== originalCallbackNode) { + // The current task was canceled. Exit. We don't need to call + // `ensureRootIsScheduled` because the check above implies either that + // there's a new task, or that there's no remaining work on this root. + return null; + } + } // Determine the next lanes to work on, using the fields stored + // on the root. - if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) { - { - if (isDevToolsPresent) { - var memoizedUpdaters = root.memoizedUpdaters; + var lanes = getNextLanes( + root, + root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes + ); - if (memoizedUpdaters.size > 0) { - restorePendingUpdaters(root, workInProgressRootRenderLanes); - memoizedUpdaters.clear(); - } // At this point, move Fibers that scheduled the upcoming work from the Map to the Set. - // If we bailout on this work, we'll move them back (like above). - // It's important to move them now in case the work spawns more work at the same priority with different updaters. - // That way we can keep the current update and future updates separate. + if (lanes === NoLanes) { + // Defensive coding. This is never expected to happen. + return null; + } // We disable time-slicing in some cases: if the work has been CPU-bound + // for too long ("expired" work, to prevent starvation), or we're in + // sync-updates-by-default mode. + // TODO: We only check `didTimeout` defensively, to account for a Scheduler + // bug we're still investigating. Once the bug in Scheduler is fixed, + // we can remove this, since we track expiration ourselves. - movePendingFibersToMemoized(root, lanes); + var shouldTimeSlice = + !includesBlockingLane(root, lanes) && + !includesExpiredLane(root, lanes) && + !didTimeout; + var exitStatus = shouldTimeSlice + ? renderRootConcurrent(root, lanes) + : renderRootSync(root, lanes); + + if (exitStatus !== RootInProgress) { + if (exitStatus === RootErrored) { + // If something threw an error, try rendering one more time. We'll + // render synchronously to block concurrent data mutations, and we'll + // includes all pending updates are included. If it still fails after + // the second attempt, we'll give up and commit the resulting tree. + var originallyAttemptedLanes = lanes; + var errorRetryLanes = getLanesToRetrySynchronouslyOnError( + root, + originallyAttemptedLanes + ); + + if (errorRetryLanes !== NoLanes) { + lanes = errorRetryLanes; + exitStatus = recoverFromConcurrentError( + root, + originallyAttemptedLanes, + errorRetryLanes + ); } } - workInProgressTransitions = getTransitionsForLanes(); - prepareFreshStack(root, lanes); - } + if (exitStatus === RootFatalErrored) { + var fatalError = workInProgressRootFatalError; + prepareFreshStack(root, NoLanes); + markRootSuspended(root, lanes); + ensureRootIsScheduled(root, now$1()); + throw fatalError; + } - { - markRenderStarted(lanes); - } + if (exitStatus === RootDidNotComplete) { + // The render unwound without completing the tree. This happens in special + // cases where need to exit the current render without producing a + // consistent tree or committing. + markRootSuspended(root, lanes); + } else { + // The render completed. + // Check if this render may have yielded to a concurrent event, and if so, + // confirm that any newly rendered stores are consistent. + // TODO: It's possible that even a concurrent render may never have yielded + // to the main thread, if it was fast enough, or if it expired. We could + // skip the consistency check in that case, too. + var renderWasConcurrent = !includesBlockingLane(root, lanes); + var finishedWork = root.current.alternate; - outer: do { - try { if ( - workInProgressSuspendedReason !== NotSuspended && - workInProgress !== null + renderWasConcurrent && + !isRenderConsistentWithExternalStores(finishedWork) ) { - // The work loop is suspended. During a synchronous render, we don't - // yield to the main thread. Immediately unwind the stack. This will - // trigger either a fallback or an error boundary. - // TODO: For discrete and "default" updates (anything that's not - // flushSync), we want to wait for the microtasks the flush before - // unwinding. Will probably implement this using renderRootConcurrent, - // or merge renderRootSync and renderRootConcurrent into the same - // function and fork the behavior some other way. - var unitOfWork = workInProgress; - var thrownValue = workInProgressThrownValue; + // A store was mutated in an interleaved event. Render again, + // synchronously, to block further mutations. + exitStatus = renderRootSync(root, lanes); // We need to check again if something threw - switch (workInProgressSuspendedReason) { - case SuspendedOnHydration: { - // Selective hydration. An update flowed into a dehydrated tree. - // Interrupt the current render so the work loop can switch to the - // hydration lane. - resetWorkInProgressStack(); - workInProgressRootExitStatus = RootDidNotComplete; - break outer; - } + if (exitStatus === RootErrored) { + var _originallyAttemptedLanes = lanes; - default: { - // Unwind then continue with the normal work loop. - workInProgressSuspendedReason = NotSuspended; - workInProgressThrownValue = null; - throwAndUnwindWorkLoop(unitOfWork, thrownValue); - break; + var _errorRetryLanes = getLanesToRetrySynchronouslyOnError( + root, + _originallyAttemptedLanes + ); + + if (_errorRetryLanes !== NoLanes) { + lanes = _errorRetryLanes; + exitStatus = recoverFromConcurrentError( + root, + _originallyAttemptedLanes, + _errorRetryLanes + ); // We assume the tree is now consistent because we didn't yield to any + // concurrent events. } } - } - workLoopSync(); - break; - } catch (thrownValue) { - handleThrow(root, thrownValue); + if (exitStatus === RootFatalErrored) { + var _fatalError = workInProgressRootFatalError; + prepareFreshStack(root, NoLanes); + markRootSuspended(root, lanes); + ensureRootIsScheduled(root, now$1()); + throw _fatalError; + } // FIXME: Need to check for RootDidNotComplete again. The factoring here + // isn't ideal. + } // We now have a consistent tree. The next step is either to commit it, + // or, if something suspended, wait to commit it after a timeout. + + root.finishedWork = finishedWork; + root.finishedLanes = lanes; + finishConcurrentRender(root, exitStatus, finishedWork, lanes); } - } while (true); + } - resetContextDependencies(); - executionContext = prevExecutionContext; - popDispatcher(prevDispatcher); + ensureRootIsScheduled(root, now$1()); - if (workInProgress !== null) { - // This is a sync render, so we should have finished the whole tree. - throw new Error( - "Cannot commit an incomplete root. This error is likely caused by a " + - "bug in React. Please file an issue." - ); + if (root.callbackNode === originalCallbackNode) { + // The task node scheduled for this root is the same one that's + // currently executed. Need to return a continuation. + return performConcurrentWorkOnRoot.bind(null, root); } - { - markRenderStopped(); - } // Set this to null to indicate there's no in-progress render. - - workInProgressRoot = null; - workInProgressRootRenderLanes = NoLanes; // It's safe to process the queue now that the render phase is complete. + return null; +} - finishQueueingConcurrentUpdates(); - return workInProgressRootExitStatus; -} // The work loop is an extremely hot path. Tell Closure not to inline it. +function recoverFromConcurrentError( + root, + originallyAttemptedLanes, + errorRetryLanes +) { + // If an error occurred during hydration, discard server response and fall + // back to client side render. + // Before rendering again, save the errors from the previous attempt. + var errorsFromFirstAttempt = workInProgressRootConcurrentErrors; + var wasRootDehydrated = isRootDehydrated(root); -/** @noinline */ + if (wasRootDehydrated) { + // The shell failed to hydrate. Set a flag to force a client rendering + // during the next attempt. To do this, we call prepareFreshStack now + // to create the root work-in-progress fiber. This is a bit weird in terms + // of factoring, because it relies on renderRootSync not calling + // prepareFreshStack again in the call below, which happens because the + // root and lanes haven't changed. + // + // TODO: I think what we should do is set ForceClientRender inside + // throwException, like we do for nested Suspense boundaries. The reason + // it's here instead is so we can switch to the synchronous work loop, too. + // Something to consider for a future refactor. + var rootWorkInProgress = prepareFreshStack(root, errorRetryLanes); + rootWorkInProgress.flags |= ForceClientRender; -function workLoopSync() { - // Perform work without checking if we need to yield between fiber. - while (workInProgress !== null) { - performUnitOfWork(workInProgress); + { + errorHydratingContainer(); + } } -} -function renderRootConcurrent(root, lanes) { - var prevExecutionContext = executionContext; - executionContext |= RenderContext; - var prevDispatcher = pushDispatcher(); - // and prepare a fresh one. Otherwise we'll continue where we left off. + var exitStatus = renderRootSync(root, errorRetryLanes); - if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) { - { - if (isDevToolsPresent) { - var memoizedUpdaters = root.memoizedUpdaters; + if (exitStatus !== RootErrored) { + // Successfully finished rendering on retry + if (workInProgressRootDidAttachPingListener && !wasRootDehydrated) { + // During the synchronous render, we attached additional ping listeners. + // This is highly suggestive of an uncached promise (though it's not the + // only reason this would happen). If it was an uncached promise, then + // it may have masked a downstream error from ocurring without actually + // fixing it. Example: + // + // use(Promise.resolve('uncached')) + // throw new Error('Oops!') + // + // When this happens, there's a conflict between blocking potential + // concurrent data races and unwrapping uncached promise values. We + // have to choose one or the other. Because the data race recovery is + // a last ditch effort, we'll disable it. + root.errorRecoveryDisabledLanes = mergeLanes( + root.errorRecoveryDisabledLanes, + originallyAttemptedLanes + ); // Mark the current render as suspended and force it to restart. Once + // these lanes finish successfully, we'll re-enable the error recovery + // mechanism for subsequent updates. - if (memoizedUpdaters.size > 0) { - restorePendingUpdaters(root, workInProgressRootRenderLanes); - memoizedUpdaters.clear(); - } // At this point, move Fibers that scheduled the upcoming work from the Map to the Set. - // If we bailout on this work, we'll move them back (like above). - // It's important to move them now in case the work spawns more work at the same priority with different updaters. - // That way we can keep the current update and future updates separate. + workInProgressRootInterleavedUpdatedLanes |= originallyAttemptedLanes; + return RootSuspendedWithDelay; + } // The errors from the failed first attempt have been recovered. Add + // them to the collection of recoverable errors. We'll log them in the + // commit phase. - movePendingFibersToMemoized(root, lanes); - } - } + var errorsFromSecondAttempt = workInProgressRootRecoverableErrors; + workInProgressRootRecoverableErrors = errorsFromFirstAttempt; // The errors from the second attempt should be queued after the errors + // from the first attempt, to preserve the causal sequence. - workInProgressTransitions = getTransitionsForLanes(); - resetRenderTimer(); - prepareFreshStack(root, lanes); + if (errorsFromSecondAttempt !== null) { + queueRecoverableErrors(errorsFromSecondAttempt); + } } - { - markRenderStarted(lanes); + return exitStatus; +} + +function queueRecoverableErrors(errors) { + if (workInProgressRootRecoverableErrors === null) { + workInProgressRootRecoverableErrors = errors; + } else { + // $FlowFixMe[method-unbinding] + workInProgressRootRecoverableErrors.push.apply( + workInProgressRootRecoverableErrors, + errors + ); } +} - outer: do { - try { - if ( - workInProgressSuspendedReason !== NotSuspended && - workInProgress !== null - ) { - // The work loop is suspended. We need to either unwind the stack or - // replay the suspended component. - var unitOfWork = workInProgress; - var thrownValue = workInProgressThrownValue; +function finishConcurrentRender(root, exitStatus, finishedWork, lanes) { + switch (exitStatus) { + case RootInProgress: + case RootFatalErrored: { + throw new Error("Root did not complete. This is a bug in React."); + } + // Flow knows about invariant, so it complains if I add a break + // statement, but eslint doesn't know about invariant, so it complains + // if I do. eslint-disable-next-line no-fallthrough - resumeOrUnwind: switch (workInProgressSuspendedReason) { - case SuspendedOnError: { - // Unwind then continue with the normal work loop. - workInProgressSuspendedReason = NotSuspended; - workInProgressThrownValue = null; - throwAndUnwindWorkLoop(unitOfWork, thrownValue); - break; - } + case RootErrored: { + // We should have already attempted to retry this tree. If we reached + // this point, it errored again. Commit it. + commitRootWhenReady( + root, + finishedWork, + workInProgressRootRecoverableErrors, + workInProgressTransitions, + lanes + ); + break; + } - case SuspendedOnData: { - var thenable = thrownValue; + case RootSuspended: { + markRootSuspended(root, lanes); // We have an acceptable loading state. We need to figure out if we + // should immediately commit it or wait a bit. - if (isThenableResolved(thenable)) { - // The data resolved. Try rendering the component again. - workInProgressSuspendedReason = NotSuspended; - workInProgressThrownValue = null; - replaySuspendedUnitOfWork(unitOfWork); - break; - } // The work loop is suspended on data. We should wait for it to - // resolve before continuing to render. - // TODO: Handle the case where the promise resolves synchronously. - // Usually this is handled when we instrument the promise to add a - // `status` field, but if the promise already has a status, we won't - // have added a listener until right here. + if ( + includesOnlyRetries(lanes) && // do not delay if we're inside an act() scope + !shouldForceFlushFallbacksInDEV() + ) { + // This render only included retries, no updates. Throttle committing + // retries so that we don't show too many loading states too quickly. + var msUntilTimeout = + globalMostRecentFallbackTime + FALLBACK_THROTTLE_MS - now$1(); // Don't bother with a very short suspense time. - var onResolution = function () { - // Check if the root is still suspended on this promise. - if ( - workInProgressSuspendedReason === SuspendedOnData && - workInProgressRoot === root - ) { - // Mark the root as ready to continue rendering. - workInProgressSuspendedReason = SuspendedAndReadyToContinue; - } // Ensure the root is scheduled. We should do this even if we're - // currently working on a different root, so that we resume - // rendering later. + if (msUntilTimeout > 10) { + var nextLanes = getNextLanes(root, NoLanes); - ensureRootIsScheduled(root, now$1()); - }; + if (nextLanes !== NoLanes) { + // There's additional work on this root. + break; + } // The render is suspended, it hasn't timed out, and there's no + // lower priority work to do. Instead of committing the fallback + // immediately, wait for more data to arrive. - thenable.then(onResolution, onResolution); - break outer; - } + root.timeoutHandle = scheduleTimeout( + commitRootWhenReady.bind( + null, + root, + finishedWork, + workInProgressRootRecoverableErrors, + workInProgressTransitions, + lanes + ), + msUntilTimeout + ); + break; + } + } // The work expired. Commit immediately. + + commitRootWhenReady( + root, + finishedWork, + workInProgressRootRecoverableErrors, + workInProgressTransitions, + lanes + ); + break; + } - case SuspendedOnImmediate: { - // If this fiber just suspended, it's possible the data is already - // cached. Yield to the main thread to give it a chance to ping. If - // it does, we can retry immediately without unwinding the stack. - workInProgressSuspendedReason = SuspendedAndReadyToContinue; - break outer; - } + case RootSuspendedWithDelay: { + markRootSuspended(root, lanes); - case SuspendedOnInstance: { - workInProgressSuspendedReason = - SuspendedOnInstanceAndReadyToContinue; - break outer; - } + if (includesOnlyTransitions(lanes)) { + // This is a transition, so we should exit without committing a + // placeholder and without scheduling a timeout. Delay indefinitely + // until we receive more data. + break; + } - case SuspendedAndReadyToContinue: { - var _thenable = thrownValue; + if (!shouldForceFlushFallbacksInDEV()) { + // This is not a transition, but we did trigger an avoided state. + // Schedule a placeholder to display after a short delay, using the Just + // Noticeable Difference. + // TODO: Is the JND optimization worth the added complexity? If this is + // the only reason we track the event time, then probably not. + // Consider removing. + var mostRecentEventTime = getMostRecentEventTime(root, lanes); + var eventTimeMs = mostRecentEventTime; + var timeElapsedMs = now$1() - eventTimeMs; - if (isThenableResolved(_thenable)) { - // The data resolved. Try rendering the component again. - workInProgressSuspendedReason = NotSuspended; - workInProgressThrownValue = null; - replaySuspendedUnitOfWork(unitOfWork); - } else { - // Otherwise, unwind then continue with the normal work loop. - workInProgressSuspendedReason = NotSuspended; - workInProgressThrownValue = null; - throwAndUnwindWorkLoop(unitOfWork, thrownValue); - } + var _msUntilTimeout = jnd(timeElapsedMs) - timeElapsedMs; // Don't bother with a very short suspense time. - break; - } + if (_msUntilTimeout > 10) { + // Instead of committing the fallback immediately, wait for more data + // to arrive. + root.timeoutHandle = scheduleTimeout( + commitRootWhenReady.bind( + null, + root, + finishedWork, + workInProgressRootRecoverableErrors, + workInProgressTransitions, + lanes + ), + _msUntilTimeout + ); + break; + } + } // Commit the placeholder. - case SuspendedOnInstanceAndReadyToContinue: { - switch (workInProgress.tag) { - case HostComponent: - case HostHoistable: - case HostSingleton: { - // Before unwinding the stack, check one more time if the - // instance is ready. It may have loaded when React yielded to - // the main thread. - // Assigning this to a constant so Flow knows the binding won't - // be mutated by `preloadInstance`. - var hostFiber = workInProgress; - var type = hostFiber.type; - var props = hostFiber.pendingProps; - var isReady = preloadInstance(type, props); + commitRootWhenReady( + root, + finishedWork, + workInProgressRootRecoverableErrors, + workInProgressTransitions, + lanes + ); + break; + } - if (isReady) { - // The data resolved. Resume the work loop as if nothing - // suspended. Unlike when a user component suspends, we don't - // have to replay anything because the host fiber - // already completed. - workInProgressSuspendedReason = NotSuspended; - workInProgressThrownValue = null; - var sibling = hostFiber.sibling; + case RootCompleted: { + // The work completed. + commitRootWhenReady( + root, + finishedWork, + workInProgressRootRecoverableErrors, + workInProgressTransitions, + lanes + ); + break; + } - if (sibling !== null) { - workInProgress = sibling; - } else { - var returnFiber = hostFiber.return; + default: { + throw new Error("Unknown root exit status."); + } + } +} - if (returnFiber !== null) { - workInProgress = returnFiber; - completeUnitOfWork(returnFiber); - } else { - workInProgress = null; - } - } +function commitRootWhenReady( + root, + finishedWork, + recoverableErrors, + transitions, + lanes +) { + if (includesOnlyNonUrgentLanes(lanes)) { + // suspend. If it's not ready, it will return a callback to subscribe to + // a ready event. - break resumeOrUnwind; - } + var schedulePendingCommit = waitForCommitToBeReady(); - break; - } + if (schedulePendingCommit !== null) { + // NOTE: waitForCommitToBeReady returns a subscribe function so that we + // only allocate a function if the commit isn't ready yet. The other + // pattern would be to always pass a callback to waitForCommitToBeReady. + // Not yet ready to commit. Delay the commit until the renderer notifies + // us that it's ready. This will be canceled if we start work on the + // root again. + root.cancelPendingCommit = schedulePendingCommit( + commitRoot.bind( + null, + root, + workInProgressRootRecoverableErrors, + workInProgressTransitions + ) + ); + return; + } + } // Otherwise, commit immediately. - default: { - // This will fail gracefully but it's not correct, so log a - // warning in dev. - if (true) { - error( - "Unexpected type of fiber triggered a suspensey commit. " + - "This is a bug in React." - ); - } + commitRoot( + root, + workInProgressRootRecoverableErrors, + workInProgressTransitions + ); +} - break; - } - } // Otherwise, unwind then continue with the normal work loop. +function isRenderConsistentWithExternalStores(finishedWork) { + // Search the rendered tree for external store reads, and check whether the + // stores were mutated in a concurrent event. Intentionally using an iterative + // loop instead of recursion so we can exit early. + var node = finishedWork; - workInProgressSuspendedReason = NotSuspended; - workInProgressThrownValue = null; - throwAndUnwindWorkLoop(unitOfWork, thrownValue); - break; - } + while (true) { + if (node.flags & StoreConsistency) { + var updateQueue = node.updateQueue; - case SuspendedOnDeprecatedThrowPromise: { - // Suspended by an old implementation that uses the `throw promise` - // pattern. The newer replaying behavior can cause subtle issues - // like infinite ping loops. So we maintain the old behavior and - // always unwind. - workInProgressSuspendedReason = NotSuspended; - workInProgressThrownValue = null; - throwAndUnwindWorkLoop(unitOfWork, thrownValue); - break; - } + if (updateQueue !== null) { + var checks = updateQueue.stores; - case SuspendedOnHydration: { - // Selective hydration. An update flowed into a dehydrated tree. - // Interrupt the current render so the work loop can switch to the - // hydration lane. - resetWorkInProgressStack(); - workInProgressRootExitStatus = RootDidNotComplete; - break outer; - } + if (checks !== null) { + for (var i = 0; i < checks.length; i++) { + var check = checks[i]; + var getSnapshot = check.getSnapshot; + var renderedValue = check.value; - default: { - throw new Error( - "Unexpected SuspendedReason. This is a bug in React." - ); + try { + if (!objectIs(getSnapshot(), renderedValue)) { + // Found an inconsistent store. + return false; + } + } catch (error) { + // If `getSnapshot` throws, return `false`. This will schedule + // a re-render, and the error will be rethrown during render. + return false; + } } } } + } - if (true && ReactCurrentActQueue.current !== null) { - // `act` special case: If we're inside an `act` scope, don't consult - // `shouldYield`. Always keep working until the render is complete. - // This is not just an optimization: in a unit test environment, we - // can't trust the result of `shouldYield`, because the host I/O is - // likely mocked. - workLoopSync(); - } else { - workLoopConcurrent(); - } + var child = node.child; - break; - } catch (thrownValue) { - handleThrow(root, thrownValue); + if (node.subtreeFlags & StoreConsistency && child !== null) { + child.return = node; + node = child; + continue; + } + + if (node === finishedWork) { + return true; } - } while (true); - resetContextDependencies(); - popDispatcher(prevDispatcher); - executionContext = prevExecutionContext; + while (node.sibling === null) { + if (node.return === null || node.return === finishedWork) { + return true; + } - if (workInProgress !== null) { - // Still work remaining. - { - markRenderYielded(); + node = node.return; } - return RootInProgress; - } else { - // Completed the tree. - { - markRenderStopped(); - } // Set this to null to indicate there's no in-progress render. + node.sibling.return = node.return; + node = node.sibling; + } // Flow doesn't know this is unreachable, but eslint does + // eslint-disable-next-line no-unreachable - workInProgressRoot = null; - workInProgressRootRenderLanes = NoLanes; // It's safe to process the queue now that the render phase is complete. + return true; +} - finishQueueingConcurrentUpdates(); // Return the final exit status. +function markRootSuspended(root, suspendedLanes) { + // When suspending, we should always exclude lanes that were pinged or (more + // rarely, since we try to avoid it) updated during the render phase. + // TODO: Lol maybe there's a better way to factor this besides this + // obnoxiously named function :) + suspendedLanes = removeLanes(suspendedLanes, workInProgressRootPingedLanes); + suspendedLanes = removeLanes( + suspendedLanes, + workInProgressRootInterleavedUpdatedLanes + ); + markRootSuspended$1(root, suspendedLanes); +} // This is the entry point for synchronous tasks that don't go +// through Scheduler - return workInProgressRootExitStatus; +function performSyncWorkOnRoot(root) { + { + syncNestedUpdateFlag(); } -} -/** @noinline */ -function workLoopConcurrent() { - // Perform work until Scheduler asks us to yield - while (workInProgress !== null && !shouldYield()) { - // $FlowFixMe[incompatible-call] found when upgrading Flow - performUnitOfWork(workInProgress); + if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { + throw new Error("Should not already be working."); } -} -function performUnitOfWork(unitOfWork) { - // The current, flushed, state of this fiber is the alternate. Ideally - // nothing should rely on this, but relying on it here means that we don't - // need an additional field on the work in progress. - var current = unitOfWork.alternate; - setCurrentFiber(unitOfWork); - var next; + flushPassiveEffects(); + var lanes = getNextLanes(root, NoLanes); - if ((unitOfWork.mode & ProfileMode) !== NoMode) { - startProfilerTimer(unitOfWork); - next = beginWork(current, unitOfWork, renderLanes); - stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true); - } else { - next = beginWork(current, unitOfWork, renderLanes); + if (!includesSyncLane(lanes)) { + // There's no remaining sync work left. + ensureRootIsScheduled(root, now$1()); + return null; } - resetCurrentFiber(); - unitOfWork.memoizedProps = unitOfWork.pendingProps; + var exitStatus = renderRootSync(root, lanes); - if (next === null) { - // If this doesn't spawn new work, complete the current work. - completeUnitOfWork(unitOfWork); - } else { - workInProgress = next; + if (root.tag !== LegacyRoot && exitStatus === RootErrored) { + // If something threw an error, try rendering one more time. We'll render + // synchronously to block concurrent data mutations, and we'll includes + // all pending updates are included. If it still fails after the second + // attempt, we'll give up and commit the resulting tree. + var originallyAttemptedLanes = lanes; + var errorRetryLanes = getLanesToRetrySynchronouslyOnError( + root, + originallyAttemptedLanes + ); + + if (errorRetryLanes !== NoLanes) { + lanes = errorRetryLanes; + exitStatus = recoverFromConcurrentError( + root, + originallyAttemptedLanes, + errorRetryLanes + ); + } } - ReactCurrentOwner$1.current = null; + if (exitStatus === RootFatalErrored) { + var fatalError = workInProgressRootFatalError; + prepareFreshStack(root, NoLanes); + markRootSuspended(root, lanes); + ensureRootIsScheduled(root, now$1()); + throw fatalError; + } + + if (exitStatus === RootDidNotComplete) { + // The render unwound without completing the tree. This happens in special + // cases where need to exit the current render without producing a + // consistent tree or committing. + markRootSuspended(root, lanes); + ensureRootIsScheduled(root, now$1()); + return null; + } // We now have a consistent tree. Because this is a sync render, we + // will commit it even if something suspended. + + var finishedWork = root.current.alternate; + root.finishedWork = finishedWork; + root.finishedLanes = lanes; + commitRoot( + root, + workInProgressRootRecoverableErrors, + workInProgressTransitions + ); // Before exiting, make sure there's a callback scheduled for the next + // pending level. + + ensureRootIsScheduled(root, now$1()); + return null; } +function getExecutionContext() { + return executionContext; +} +function batchedUpdates(fn, a) { + var prevExecutionContext = executionContext; + executionContext |= BatchedContext; -function replaySuspendedUnitOfWork(unitOfWork) { - // This is a fork of performUnitOfWork specifcally for replaying a fiber that - // just suspended. - // - var current = unitOfWork.alternate; - setCurrentFiber(unitOfWork); - var next; - setCurrentFiber(unitOfWork); - var isProfilingMode = (unitOfWork.mode & ProfileMode) !== NoMode; + try { + return fn(a); + } finally { + executionContext = prevExecutionContext; // If there were legacy sync updates, flush them at the end of the outer + // most batchedUpdates-like method. - if (isProfilingMode) { - startProfilerTimer(unitOfWork); + if ( + executionContext === NoContext && // Treat `act` as if it's inside `batchedUpdates`, even in legacy mode. + !ReactCurrentActQueue.isBatchingLegacy + ) { + resetRenderTimer(); + flushSyncCallbacksOnlyInLegacyMode(); + } } +} +// Warning, this opts-out of checking the function body. +// eslint-disable-next-line no-unused-vars +// eslint-disable-next-line no-redeclare +// eslint-disable-next-line no-redeclare - switch (unitOfWork.tag) { - case IndeterminateComponent: { - // Because it suspended with `use`, we can assume it's a - // function component. - unitOfWork.tag = FunctionComponent; // Fallthrough to the next branch. +function flushSync(fn) { + // In legacy mode, we flush pending passive effects at the beginning of the + // next event, not at the end of the previous one. + if ( + rootWithPendingPassiveEffects !== null && + rootWithPendingPassiveEffects.tag === LegacyRoot && + (executionContext & (RenderContext | CommitContext)) === NoContext + ) { + flushPassiveEffects(); + } + + var prevExecutionContext = executionContext; + executionContext |= BatchedContext; + var prevTransition = ReactCurrentBatchConfig.transition; + var previousPriority = getCurrentUpdatePriority(); + + try { + ReactCurrentBatchConfig.transition = null; + setCurrentUpdatePriority(DiscreteEventPriority); + + if (fn) { + return fn(); + } else { + return undefined; } - // eslint-disable-next-line no-fallthrough + } finally { + setCurrentUpdatePriority(previousPriority); + ReactCurrentBatchConfig.transition = prevTransition; + executionContext = prevExecutionContext; // Flush the immediate callbacks that were scheduled during this batch. + // Note that this will happen even if batchedUpdates is higher up + // the stack. - case FunctionComponent: - case ForwardRef: { - // Resolve `defaultProps`. This logic is copied from `beginWork`. - // TODO: Consider moving this switch statement into that module. Also, - // could maybe use this as an opportunity to say `use` doesn't work with - // `defaultProps` :) - var Component = unitOfWork.type; - var unresolvedProps = unitOfWork.pendingProps; - var resolvedProps = - unitOfWork.elementType === Component - ? unresolvedProps - : resolveDefaultProps(Component, unresolvedProps); - next = replayFunctionComponent( - current, - unitOfWork, - resolvedProps, - Component, - workInProgressRootRenderLanes - ); - break; + if ((executionContext & (RenderContext | CommitContext)) === NoContext) { + flushSyncCallbacks(); } + } +} +// hidden subtree. The stack logic is managed there because that's the only +// place that ever modifies it. Which module it lives in doesn't matter for +// performance because this function will get inlined regardless + +function setRenderLanes(subtreeRenderLanes) { + renderLanes = subtreeRenderLanes; +} +function getRenderLanes() { + return renderLanes; +} + +function resetWorkInProgressStack() { + if (workInProgress === null) return; + var interruptedWork; + + if (workInProgressSuspendedReason === NotSuspended) { + // Normal case. Work-in-progress hasn't started yet. Unwind all + // its parents. + interruptedWork = workInProgress.return; + } else { + // Work-in-progress is in suspended state. Reset the work loop and unwind + // both the suspended fiber and all its parents. + resetSuspendedWorkLoopOnUnwind(); + interruptedWork = workInProgress; + } + + while (interruptedWork !== null) { + var current = interruptedWork.alternate; + unwindInterruptedWork(current, interruptedWork); + interruptedWork = interruptedWork.return; + } - case SimpleMemoComponent: { - var _Component = unitOfWork.type; - var nextProps = unitOfWork.pendingProps; - next = replayFunctionComponent( - current, - unitOfWork, - nextProps, - _Component, - workInProgressRootRenderLanes - ); - break; - } + workInProgress = null; +} - default: { - // Other types besides function components are reset completely before - // being replayed. Currently this only happens when a Usable type is - // reconciled — the reconciler will suspend. - // - // We reset the fiber back to its original state; however, this isn't - // a full "unwind" because we're going to reuse the promises that were - // reconciled previously. So it's intentional that we don't call - // resetSuspendedWorkLoopOnUnwind here. - unwindInterruptedWork(current, unitOfWork); - unitOfWork = workInProgress = resetWorkInProgress( - unitOfWork, - renderLanes - ); - next = beginWork(current, unitOfWork, renderLanes); - break; - } +function prepareFreshStack(root, lanes) { + root.finishedWork = null; + root.finishedLanes = NoLanes; + var timeoutHandle = root.timeoutHandle; + + if (timeoutHandle !== noTimeout) { + // The root previous suspended and scheduled a timeout to commit a fallback + // state. Now that we have additional work, cancel the timeout. + root.timeoutHandle = noTimeout; // $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above + + cancelTimeout(timeoutHandle); } - if (isProfilingMode) { - stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true); - } // The begin phase finished successfully without suspending. Return to the - // normal work loop. + var cancelPendingCommit = root.cancelPendingCommit; - resetCurrentFiber(); - unitOfWork.memoizedProps = unitOfWork.pendingProps; + if (cancelPendingCommit !== null) { + root.cancelPendingCommit = null; + cancelPendingCommit(); + } - if (next === null) { - // If this doesn't spawn new work, complete the current work. - completeUnitOfWork(unitOfWork); - } else { - workInProgress = next; + resetWorkInProgressStack(); + workInProgressRoot = root; + var rootWorkInProgress = createWorkInProgress(root.current, null); + workInProgress = rootWorkInProgress; + workInProgressRootRenderLanes = renderLanes = lanes; + workInProgressSuspendedReason = NotSuspended; + workInProgressThrownValue = null; + workInProgressRootDidAttachPingListener = false; + workInProgressRootExitStatus = RootInProgress; + workInProgressRootFatalError = null; + workInProgressRootSkippedLanes = NoLanes; + workInProgressRootInterleavedUpdatedLanes = NoLanes; + workInProgressRootPingedLanes = NoLanes; + workInProgressRootConcurrentErrors = null; + workInProgressRootRecoverableErrors = null; + finishQueueingConcurrentUpdates(); + + { + ReactStrictModeWarnings.discardPendingWarnings(); } - ReactCurrentOwner$1.current = null; + return rootWorkInProgress; } -function throwAndUnwindWorkLoop(unitOfWork, thrownValue) { - // This is a fork of performUnitOfWork specifcally for unwinding a fiber - // that threw an exception. - // - // Return to the normal work loop. This will unwind the stack, and potentially - // result in showing a fallback. - resetSuspendedWorkLoopOnUnwind(); - var returnFiber = unitOfWork.return; +function resetSuspendedWorkLoopOnUnwind() { + // Reset module-level state that was set during the render phase. + resetContextDependencies(); + resetHooksOnUnwind(); + resetChildReconcilerOnUnwind(); +} - if (returnFiber === null || workInProgressRoot === null) { - // Expected to be working on a non-root fiber. This is a fatal error - // because there's no ancestor that can handle it; the root is - // supposed to capture all errors that weren't caught by an error - // boundary. - workInProgressRootExitStatus = RootFatalErrored; - workInProgressRootFatalError = thrownValue; // Set `workInProgress` to null. This represents advancing to the next - // sibling, or the parent if there are no siblings. But since the root - // has no siblings nor a parent, we set it to null. Usually this is - // handled by `completeUnitOfWork` or `unwindWork`, but since we're - // intentionally not calling those, we need set it here. - // TODO: Consider calling `unwindWork` to pop the contexts. +function handleThrow(root, thrownValue) { + // A component threw an exception. Usually this is because it suspended, but + // it also includes regular program errors. + // + // We're either going to unwind the stack to show a Suspense or error + // boundary, or we're going to replay the component again. Like after a + // promise resolves. + // + // Until we decide whether we're going to unwind or replay, we should preserve + // the current state of the work loop without resetting anything. + // + // If we do decide to unwind the stack, module-level variables will be reset + // in resetSuspendedWorkLoopOnUnwind. + // These should be reset immediately because they're only supposed to be set + // when React is executing user code. + resetHooksAfterThrow(); + resetCurrentFiber(); + ReactCurrentOwner$1.current = null; - workInProgress = null; - return; + if (thrownValue === SuspenseException) { + // This is a special type of exception used for Suspense. For historical + // reasons, the rest of the Suspense implementation expects the thrown value + // to be a thenable, because before `use` existed that was the (unstable) + // API for suspending. This implementation detail can change later, once we + // deprecate the old API in favor of `use`. + thrownValue = getSuspendedThenable(); + workInProgressSuspendedReason = + shouldRemainOnPreviousScreen() && // Check if there are other pending updates that might possibly unblock this + // component from suspending. This mirrors the check in + // renderDidSuspendDelayIfPossible. We should attempt to unify them somehow. + // TODO: Consider unwinding immediately, using the + // SuspendedOnHydration mechanism. + !includesNonIdleWork(workInProgressRootSkippedLanes) && + !includesNonIdleWork(workInProgressRootInterleavedUpdatedLanes) // Suspend work loop until data resolves + ? SuspendedOnData // Don't suspend work loop, except to check if the data has + : // immediately resolved (i.e. in a microtask). Otherwise, trigger the + // nearest Suspense fallback. + SuspendedOnImmediate; + } else if (thrownValue === SuspenseyCommitException) { + thrownValue = getSuspendedThenable(); + workInProgressSuspendedReason = SuspendedOnInstance; + } else if (thrownValue === SelectiveHydrationException) { + // An update flowed into a dehydrated boundary. Before we can apply the + // update, we need to finish hydrating. Interrupt the work-in-progress + // render so we can restart at the hydration lane. + // + // The ideal implementation would be able to switch contexts without + // unwinding the current stack. + // + // We could name this something more general but as of now it's the only + // case where we think this should happen. + workInProgressSuspendedReason = SuspendedOnHydration; + } else { + // This is a regular error. + var isWakeable = + thrownValue !== null && + typeof thrownValue === "object" && + typeof thrownValue.then === "function"; + workInProgressSuspendedReason = isWakeable // A wakeable object was thrown by a legacy Suspense implementation. + ? // This has slightly different behavior than suspending with `use`. + SuspendedOnDeprecatedThrowPromise // This is a regular error. If something earlier in the component already + : // suspended, we must clear the thenable state to unblock the work loop. + SuspendedOnError; } - try { - // Find and mark the nearest Suspense or error boundary that can handle - // this "exception". - throwException( - workInProgressRoot, - returnFiber, - unitOfWork, - thrownValue, - workInProgressRootRenderLanes - ); - } catch (error) { - // We had trouble processing the error. An example of this happening is - // when accessing the `componentDidCatch` property of an error boundary - // throws an error. A weird edge case. There's a regression test for this. - // To prevent an infinite loop, bubble the error up to the next parent. - workInProgress = returnFiber; - throw error; + workInProgressThrownValue = thrownValue; + var erroredWork = workInProgress; + + if (erroredWork === null) { + // This is a fatal error + workInProgressRootExitStatus = RootFatalErrored; + workInProgressRootFatalError = thrownValue; + return; } - if (unitOfWork.flags & Incomplete) { - // Unwind the stack until we reach the nearest boundary. - unwindUnitOfWork(unitOfWork); - } else { - // Although the fiber suspended, we're intentionally going to commit it in - // an inconsistent state. We can do this safely in cases where we know the - // inconsistent tree will be hidden. - // - // This currently only applies to Legacy Suspense implementation, but we may - // port a version of this to concurrent roots, too, when performing a - // synchronous render. Because that will allow us to mutate the tree as we - // go instead of buffering mutations until the end. Though it's unclear if - // this particular path is how that would be implemented. - completeUnitOfWork(unitOfWork); + if (erroredWork.mode & ProfileMode) { + // Record the time spent rendering before an error was thrown. This + // avoids inaccurate Profiler durations in the case of a + // suspended render. + stopProfilerTimerIfRunningAndRecordDelta(erroredWork, true); } -} -function completeUnitOfWork(unitOfWork) { - // Attempt to complete the current unit of work, then move to the next - // sibling. If there are no more siblings, return to the parent fiber. - var completedWork = unitOfWork; + { + markComponentRenderStopped(); - do { - { - { - if ((completedWork.flags & Incomplete) !== NoFlags$1) { - // NOTE: If we re-enable sibling prerendering in some cases, this branch - // is where we would switch to the unwinding path. - error( - "Internal React error: Expected this fiber to be complete, but " + - "it isn't. It should have been unwound. This is a bug in React." - ); - } + switch (workInProgressSuspendedReason) { + case SuspendedOnError: { + markComponentErrored( + erroredWork, + thrownValue, + workInProgressRootRenderLanes + ); + break; } - } // The current, flushed, state of this fiber is the alternate. Ideally - // nothing should rely on this, but relying on it here means that we don't - // need an additional field on the work in progress. - var current = completedWork.alternate; - var returnFiber = completedWork.return; - setCurrentFiber(completedWork); - var next = void 0; + case SuspendedOnData: + case SuspendedOnImmediate: + case SuspendedOnDeprecatedThrowPromise: + case SuspendedAndReadyToContinue: { + var wakeable = thrownValue; + markComponentSuspended( + erroredWork, + wakeable, + workInProgressRootRenderLanes + ); + break; + } + } + } +} - if ((completedWork.mode & ProfileMode) === NoMode) { - next = completeWork(current, completedWork, renderLanes); +function shouldRemainOnPreviousScreen() { + // This is asking whether it's better to suspend the transition and remain + // on the previous screen, versus showing a fallback as soon as possible. It + // takes into account both the priority of render and also whether showing a + // fallback would produce a desirable user experience. + // TODO: Once `use` has fully replaced the `throw promise` pattern, we should + // be able to remove the equivalent check in finishConcurrentRender, and rely + // just on this one. + if (includesOnlyTransitions(workInProgressRootRenderLanes)) { + if (getShellBoundary() === null) { + // We're rendering inside the "shell" of the app. Activating the nearest + // fallback would cause visible content to disappear. It's better to + // suspend the transition and remain on the previous screen. + return true; } else { - startProfilerTimer(completedWork); - next = completeWork(current, completedWork, renderLanes); // Update render duration assuming we didn't error. - - stopProfilerTimerIfRunningAndRecordDelta(completedWork, false); + // We're rendering content that wasn't part of the previous screen. + // Rather than block the transition, it's better to show a fallback as + // soon as possible. The appearance of any nested fallbacks will be + // throttled to avoid jank. + return false; } + } - resetCurrentFiber(); + var handler = getSuspenseHandler(); - if (next !== null) { - // Completing this fiber spawned new work. Work on that next. - workInProgress = next; - return; + if (handler === null); + else { + if (includesOnlyRetries(workInProgressRootRenderLanes)) { + // During a retry, we can suspend rendering if the nearest Suspense boundary + // is the boundary of the "shell", because we're guaranteed not to block + // any new content from appearing. + return handler === getShellBoundary(); } + } // For all other Lanes besides Transitions and Retries, we should not wait + // for the data to load. + // TODO: We should wait during Offscreen prerendering, too. - var siblingFiber = completedWork.sibling; + return false; +} - if (siblingFiber !== null) { - // If there is more work to do in this returnFiber, do that next. - workInProgress = siblingFiber; - return; - } // Otherwise, return to the parent - // $FlowFixMe[incompatible-type] we bail out when we get a null +function pushDispatcher(container) { + var prevDispatcher = ReactCurrentDispatcher.current; + ReactCurrentDispatcher.current = ContextOnlyDispatcher; - completedWork = returnFiber; // Update the next thing we're working on in case something throws. + if (prevDispatcher === null) { + // The React isomorphic package does not include a default dispatcher. + // Instead the first renderer will lazily attach one, in order to give + // nicer error messages. + return ContextOnlyDispatcher; + } else { + return prevDispatcher; + } +} - workInProgress = completedWork; - } while (completedWork !== null); // We've reached the root. +function popDispatcher(prevDispatcher) { + ReactCurrentDispatcher.current = prevDispatcher; +} +function markCommitTimeOfFallback() { + globalMostRecentFallbackTime = now$1(); +} +function markSkippedUpdateLanes(lane) { + workInProgressRootSkippedLanes = mergeLanes( + lane, + workInProgressRootSkippedLanes + ); +} +function renderDidSuspend() { if (workInProgressRootExitStatus === RootInProgress) { - workInProgressRootExitStatus = RootCompleted; + workInProgressRootExitStatus = RootSuspended; } } +function renderDidSuspendDelayIfPossible() { + workInProgressRootExitStatus = RootSuspendedWithDelay; // Check if there are updates that we skipped tree that might have unblocked + // this render. -function unwindUnitOfWork(unitOfWork) { - var incompleteWork = unitOfWork; + if ( + workInProgressRoot !== null && + (includesNonIdleWork(workInProgressRootSkippedLanes) || + includesNonIdleWork(workInProgressRootInterleavedUpdatedLanes)) + ) { + // Mark the current render as suspended so that we switch to working on + // the updates that were skipped. Usually we only suspend at the end of + // the render phase. + // TODO: We should probably always mark the root as suspended immediately + // (inside this function), since by suspending at the end of the render + // phase introduces a potential mistake where we suspend lanes that were + // pinged or updated while we were rendering. + // TODO: Consider unwinding immediately, using the + // SuspendedOnHydration mechanism. + // $FlowFixMe[incompatible-call] need null check workInProgressRoot + markRootSuspended(workInProgressRoot, workInProgressRootRenderLanes); + } +} +function renderDidError(error) { + if (workInProgressRootExitStatus !== RootSuspendedWithDelay) { + workInProgressRootExitStatus = RootErrored; + } - do { - // The current, flushed, state of this fiber is the alternate. Ideally - // nothing should rely on this, but relying on it here means that we don't - // need an additional field on the work in progress. - var current = incompleteWork.alternate; // This fiber did not complete because something threw. Pop values off - // the stack without entering the complete phase. If this is a boundary, - // capture values if possible. + if (workInProgressRootConcurrentErrors === null) { + workInProgressRootConcurrentErrors = [error]; + } else { + workInProgressRootConcurrentErrors.push(error); + } +} // Called during render to determine if anything has suspended. +// Returns false if we're not sure. - var next = unwindWork(current, incompleteWork); // Because this fiber did not complete, don't reset its lanes. +function renderHasNotSuspendedYet() { + // If something errored or completed, we can't really be sure, + // so those are false. + return workInProgressRootExitStatus === RootInProgress; +} // TODO: Over time, this function and renderRootConcurrent have become more +// and more similar. Not sure it makes sense to maintain forked paths. Consider +// unifying them again. - if (next !== null) { - // Found a boundary that can handle this exception. Re-renter the - // begin phase. This branch will return us to the normal work loop. - // - // Since we're restarting, remove anything that is not a host effect - // from the effect tag. - next.flags &= HostEffectMask; - workInProgress = next; - return; - } // Keep unwinding until we reach either a boundary or the root. +function renderRootSync(root, lanes) { + var prevExecutionContext = executionContext; + executionContext |= RenderContext; + var prevDispatcher = pushDispatcher(); + // and prepare a fresh one. Otherwise we'll continue where we left off. - if ((incompleteWork.mode & ProfileMode) !== NoMode) { - // Record the render duration for the fiber that errored. - stopProfilerTimerIfRunningAndRecordDelta(incompleteWork, false); // Include the time spent working on failed children before continuing. + if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) { + { + if (isDevToolsPresent) { + var memoizedUpdaters = root.memoizedUpdaters; - var actualDuration = incompleteWork.actualDuration; - var child = incompleteWork.child; + if (memoizedUpdaters.size > 0) { + restorePendingUpdaters(root, workInProgressRootRenderLanes); + memoizedUpdaters.clear(); + } // At this point, move Fibers that scheduled the upcoming work from the Map to the Set. + // If we bailout on this work, we'll move them back (like above). + // It's important to move them now in case the work spawns more work at the same priority with different updaters. + // That way we can keep the current update and future updates separate. - while (child !== null) { - // $FlowFixMe[unsafe-addition] addition with possible null/undefined value - actualDuration += child.actualDuration; - child = child.sibling; + movePendingFibersToMemoized(root, lanes); } + } - incompleteWork.actualDuration = actualDuration; - } // TODO: Once we stop prerendering siblings, instead of resetting the parent - // of the node being unwound, we should be able to reset node itself as we - // unwind the stack. Saves an additional null check. - - var returnFiber = incompleteWork.return; + workInProgressTransitions = getTransitionsForLanes(); + prepareFreshStack(root, lanes); + } - if (returnFiber !== null) { - // Mark the parent fiber as incomplete and clear its subtree flags. - // TODO: Once we stop prerendering siblings, we may be able to get rid of - // the Incomplete flag because unwinding to the nearest boundary will - // happen synchronously. - returnFiber.flags |= Incomplete; - returnFiber.subtreeFlags = NoFlags$1; - returnFiber.deletions = null; - } - // $FlowFixMe[incompatible-type] we bail out when we get a null + { + markRenderStarted(lanes); + } - incompleteWork = returnFiber; // Update the next thing we're working on in case something throws. + outer: do { + try { + if ( + workInProgressSuspendedReason !== NotSuspended && + workInProgress !== null + ) { + // The work loop is suspended. During a synchronous render, we don't + // yield to the main thread. Immediately unwind the stack. This will + // trigger either a fallback or an error boundary. + // TODO: For discrete and "default" updates (anything that's not + // flushSync), we want to wait for the microtasks the flush before + // unwinding. Will probably implement this using renderRootConcurrent, + // or merge renderRootSync and renderRootConcurrent into the same + // function and fork the behavior some other way. + var unitOfWork = workInProgress; + var thrownValue = workInProgressThrownValue; - workInProgress = incompleteWork; - } while (incompleteWork !== null); // We've unwound all the way to the root. + switch (workInProgressSuspendedReason) { + case SuspendedOnHydration: { + // Selective hydration. An update flowed into a dehydrated tree. + // Interrupt the current render so the work loop can switch to the + // hydration lane. + resetWorkInProgressStack(); + workInProgressRootExitStatus = RootDidNotComplete; + break outer; + } - workInProgressRootExitStatus = RootDidNotComplete; - workInProgress = null; -} + default: { + // Unwind then continue with the normal work loop. + workInProgressSuspendedReason = NotSuspended; + workInProgressThrownValue = null; + throwAndUnwindWorkLoop(unitOfWork, thrownValue); + break; + } + } + } -function commitRoot(root, recoverableErrors, transitions) { - // TODO: This no longer makes any sense. We already wrap the mutation and - // layout phases. Should be able to remove. - var previousUpdateLanePriority = getCurrentUpdatePriority(); - var prevTransition = ReactCurrentBatchConfig.transition; + workLoopSync(); + break; + } catch (thrownValue) { + handleThrow(root, thrownValue); + } + } while (true); - try { - ReactCurrentBatchConfig.transition = null; - setCurrentUpdatePriority(DiscreteEventPriority); - commitRootImpl( - root, - recoverableErrors, - transitions, - previousUpdateLanePriority + resetContextDependencies(); + executionContext = prevExecutionContext; + popDispatcher(prevDispatcher); + + if (workInProgress !== null) { + // This is a sync render, so we should have finished the whole tree. + throw new Error( + "Cannot commit an incomplete root. This error is likely caused by a " + + "bug in React. Please file an issue." ); - } finally { - ReactCurrentBatchConfig.transition = prevTransition; - setCurrentUpdatePriority(previousUpdateLanePriority); } - return null; -} - -function commitRootImpl( - root, - recoverableErrors, - transitions, - renderPriorityLevel -) { - do { - // `flushPassiveEffects` will call `flushSyncUpdateQueue` at the end, which - // means `flushPassiveEffects` will sometimes result in additional - // passive effects. So we need to keep flushing in a loop until there are - // no more pending effects. - // TODO: Might be better if `flushPassiveEffects` did not automatically - // flush synchronous work at the end, to avoid factoring hazards like this. - flushPassiveEffects(); - } while (rootWithPendingPassiveEffects !== null); + { + markRenderStopped(); + } // Set this to null to indicate there's no in-progress render. - flushRenderPhaseStrictModeWarningsInDEV(); + workInProgressRoot = null; + workInProgressRootRenderLanes = NoLanes; // It's safe to process the queue now that the render phase is complete. - if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { - throw new Error("Should not already be working."); - } + finishQueueingConcurrentUpdates(); + return workInProgressRootExitStatus; +} // The work loop is an extremely hot path. Tell Closure not to inline it. - var finishedWork = root.finishedWork; - var lanes = root.finishedLanes; +/** @noinline */ - { - markCommitStarted(lanes); +function workLoopSync() { + // Perform work without checking if we need to yield between fiber. + while (workInProgress !== null) { + performUnitOfWork(workInProgress); } +} - if (finishedWork === null) { - { - markCommitStopped(); - } +function renderRootConcurrent(root, lanes) { + var prevExecutionContext = executionContext; + executionContext |= RenderContext; + var prevDispatcher = pushDispatcher(); + // and prepare a fresh one. Otherwise we'll continue where we left off. - return null; - } else { + if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) { { - if (lanes === NoLanes) { - error( - "root.finishedLanes should not be empty during a commit. This is a " + - "bug in React." - ); + if (isDevToolsPresent) { + var memoizedUpdaters = root.memoizedUpdaters; + + if (memoizedUpdaters.size > 0) { + restorePendingUpdaters(root, workInProgressRootRenderLanes); + memoizedUpdaters.clear(); + } // At this point, move Fibers that scheduled the upcoming work from the Map to the Set. + // If we bailout on this work, we'll move them back (like above). + // It's important to move them now in case the work spawns more work at the same priority with different updaters. + // That way we can keep the current update and future updates separate. + + movePendingFibersToMemoized(root, lanes); } } + + workInProgressTransitions = getTransitionsForLanes(); + resetRenderTimer(); + prepareFreshStack(root, lanes); } - root.finishedWork = null; - root.finishedLanes = NoLanes; + { + markRenderStarted(lanes); + } - if (finishedWork === root.current) { - throw new Error( - "Cannot commit the same tree as before. This error is likely caused by " + - "a bug in React. Please file an issue." - ); - } // commitRoot never returns a continuation; it always finishes synchronously. - // So we can clear these now to allow a new callback to be scheduled. + outer: do { + try { + if ( + workInProgressSuspendedReason !== NotSuspended && + workInProgress !== null + ) { + // The work loop is suspended. We need to either unwind the stack or + // replay the suspended component. + var unitOfWork = workInProgress; + var thrownValue = workInProgressThrownValue; - root.callbackNode = null; - root.callbackPriority = NoLane; - root.cancelPendingCommit = null; // Check which lanes no longer have any work scheduled on them, and mark - // those as finished. + resumeOrUnwind: switch (workInProgressSuspendedReason) { + case SuspendedOnError: { + // Unwind then continue with the normal work loop. + workInProgressSuspendedReason = NotSuspended; + workInProgressThrownValue = null; + throwAndUnwindWorkLoop(unitOfWork, thrownValue); + break; + } - var remainingLanes = mergeLanes(finishedWork.lanes, finishedWork.childLanes); // Make sure to account for lanes that were updated by a concurrent event - // during the render phase; don't mark them as finished. + case SuspendedOnData: { + var thenable = thrownValue; - var concurrentlyUpdatedLanes = getConcurrentlyUpdatedLanes(); - remainingLanes = mergeLanes(remainingLanes, concurrentlyUpdatedLanes); - markRootFinished(root, remainingLanes); + if (isThenableResolved(thenable)) { + // The data resolved. Try rendering the component again. + workInProgressSuspendedReason = NotSuspended; + workInProgressThrownValue = null; + replaySuspendedUnitOfWork(unitOfWork); + break; + } // The work loop is suspended on data. We should wait for it to + // resolve before continuing to render. + // TODO: Handle the case where the promise resolves synchronously. + // Usually this is handled when we instrument the promise to add a + // `status` field, but if the promise already has a status, we won't + // have added a listener until right here. - if (root === workInProgressRoot) { - // We can reset these now that they are finished. - workInProgressRoot = null; - workInProgress = null; - workInProgressRootRenderLanes = NoLanes; - } // If there are pending passive effects, schedule a callback to process them. - // Do this as early as possible, so it is queued before anything else that - // might get scheduled in the commit phase. (See #16714.) - // TODO: Delete all other places that schedule the passive effect callback - // They're redundant. + var onResolution = function () { + // Check if the root is still suspended on this promise. + if ( + workInProgressSuspendedReason === SuspendedOnData && + workInProgressRoot === root + ) { + // Mark the root as ready to continue rendering. + workInProgressSuspendedReason = SuspendedAndReadyToContinue; + } // Ensure the root is scheduled. We should do this even if we're + // currently working on a different root, so that we resume + // rendering later. - if ( - (finishedWork.subtreeFlags & PassiveMask) !== NoFlags$1 || - (finishedWork.flags & PassiveMask) !== NoFlags$1 - ) { - if (!rootDoesHavePassiveEffects) { - rootDoesHavePassiveEffects = true; - scheduleCallback(NormalPriority, function () { - flushPassiveEffects(); // This render triggered passive effects: release the root cache pool - // *after* passive effects fire to avoid freeing a cache pool that may - // be referenced by a node in the tree (HostRoot, Cache boundary etc) + ensureRootIsScheduled(root, now$1()); + }; - return null; - }); - } - } // Check if there are any effects in the whole tree. - // TODO: This is left over from the effect list implementation, where we had - // to check for the existence of `firstEffect` to satisfy Flow. I think the - // only other reason this optimization exists is because it affects profiling. - // Reconsider whether this is necessary. + thenable.then(onResolution, onResolution); + break outer; + } - var subtreeHasEffects = - (finishedWork.subtreeFlags & - (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !== - NoFlags$1; - var rootHasEffect = - (finishedWork.flags & - (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !== - NoFlags$1; + case SuspendedOnImmediate: { + // If this fiber just suspended, it's possible the data is already + // cached. Yield to the main thread to give it a chance to ping. If + // it does, we can retry immediately without unwinding the stack. + workInProgressSuspendedReason = SuspendedAndReadyToContinue; + break outer; + } + + case SuspendedOnInstance: { + workInProgressSuspendedReason = + SuspendedOnInstanceAndReadyToContinue; + break outer; + } + + case SuspendedAndReadyToContinue: { + var _thenable = thrownValue; + + if (isThenableResolved(_thenable)) { + // The data resolved. Try rendering the component again. + workInProgressSuspendedReason = NotSuspended; + workInProgressThrownValue = null; + replaySuspendedUnitOfWork(unitOfWork); + } else { + // Otherwise, unwind then continue with the normal work loop. + workInProgressSuspendedReason = NotSuspended; + workInProgressThrownValue = null; + throwAndUnwindWorkLoop(unitOfWork, thrownValue); + } + + break; + } + + case SuspendedOnInstanceAndReadyToContinue: { + switch (workInProgress.tag) { + case HostComponent: + case HostHoistable: + case HostSingleton: { + // Before unwinding the stack, check one more time if the + // instance is ready. It may have loaded when React yielded to + // the main thread. + // Assigning this to a constant so Flow knows the binding won't + // be mutated by `preloadInstance`. + var hostFiber = workInProgress; + var type = hostFiber.type; + var props = hostFiber.pendingProps; + var isReady = preloadInstance(type, props); + + if (isReady) { + // The data resolved. Resume the work loop as if nothing + // suspended. Unlike when a user component suspends, we don't + // have to replay anything because the host fiber + // already completed. + workInProgressSuspendedReason = NotSuspended; + workInProgressThrownValue = null; + var sibling = hostFiber.sibling; + + if (sibling !== null) { + workInProgress = sibling; + } else { + var returnFiber = hostFiber.return; + + if (returnFiber !== null) { + workInProgress = returnFiber; + completeUnitOfWork(returnFiber); + } else { + workInProgress = null; + } + } + + break resumeOrUnwind; + } - if (subtreeHasEffects || rootHasEffect) { - var prevTransition = ReactCurrentBatchConfig.transition; - ReactCurrentBatchConfig.transition = null; - var previousPriority = getCurrentUpdatePriority(); - setCurrentUpdatePriority(DiscreteEventPriority); - var prevExecutionContext = executionContext; - executionContext |= CommitContext; // Reset this to null before calling lifecycles + break; + } - ReactCurrentOwner$1.current = null; // The commit phase is broken into several sub-phases. We do a separate pass - // of the effect list for each phase: all mutation effects come before all - // layout effects, and so on. - // The first phase a "before mutation" phase. We use this phase to read the - // state of the host tree right before we mutate it. This is where - // getSnapshotBeforeUpdate is called. + default: { + // This will fail gracefully but it's not correct, so log a + // warning in dev. + if (true) { + error( + "Unexpected type of fiber triggered a suspensey commit. " + + "This is a bug in React." + ); + } - commitBeforeMutationEffects(root, finishedWork); + break; + } + } // Otherwise, unwind then continue with the normal work loop. - { - // Mark the current commit time to be shared by all Profilers in this - // batch. This enables them to be grouped later. - recordCommitTime(); - } + workInProgressSuspendedReason = NotSuspended; + workInProgressThrownValue = null; + throwAndUnwindWorkLoop(unitOfWork, thrownValue); + break; + } - commitMutationEffects(root, finishedWork, lanes); - // the mutation phase, so that the previous tree is still current during - // componentWillUnmount, but before the layout phase, so that the finished - // work is current during componentDidMount/Update. + case SuspendedOnDeprecatedThrowPromise: { + // Suspended by an old implementation that uses the `throw promise` + // pattern. The newer replaying behavior can cause subtle issues + // like infinite ping loops. So we maintain the old behavior and + // always unwind. + workInProgressSuspendedReason = NotSuspended; + workInProgressThrownValue = null; + throwAndUnwindWorkLoop(unitOfWork, thrownValue); + break; + } - root.current = finishedWork; // The next phase is the layout phase, where we call effects that read + case SuspendedOnHydration: { + // Selective hydration. An update flowed into a dehydrated tree. + // Interrupt the current render so the work loop can switch to the + // hydration lane. + resetWorkInProgressStack(); + workInProgressRootExitStatus = RootDidNotComplete; + break outer; + } - { - markLayoutEffectsStarted(lanes); - } + default: { + throw new Error( + "Unexpected SuspendedReason. This is a bug in React." + ); + } + } + } - commitLayoutEffects(finishedWork, root, lanes); + if (true && ReactCurrentActQueue.current !== null) { + // `act` special case: If we're inside an `act` scope, don't consult + // `shouldYield`. Always keep working until the render is complete. + // This is not just an optimization: in a unit test environment, we + // can't trust the result of `shouldYield`, because the host I/O is + // likely mocked. + workLoopSync(); + } else { + workLoopConcurrent(); + } - { - markLayoutEffectsStopped(); + break; + } catch (thrownValue) { + handleThrow(root, thrownValue); } - // opportunity to paint. - - requestPaint(); - executionContext = prevExecutionContext; // Reset the priority to the previous non-sync value. + } while (true); - setCurrentUpdatePriority(previousPriority); - ReactCurrentBatchConfig.transition = prevTransition; - } else { - // No effects. - root.current = finishedWork; // Measure these anyway so the flamegraph explicitly shows that there were - // no effects. - // TODO: Maybe there's a better way to report this. + resetContextDependencies(); + popDispatcher(prevDispatcher); + executionContext = prevExecutionContext; + if (workInProgress !== null) { + // Still work remaining. { - recordCommitTime(); + markRenderYielded(); } - } - - var rootDidHavePassiveEffects = rootDoesHavePassiveEffects; - if (rootDoesHavePassiveEffects) { - // This commit has passive effects. Stash a reference to them. But don't - // schedule a callback until after flushing layout work. - rootDoesHavePassiveEffects = false; - rootWithPendingPassiveEffects = root; - pendingPassiveEffectsLanes = lanes; + return RootInProgress; } else { + // Completed the tree. { - nestedPassiveUpdateCount = 0; - rootWithPassiveNestedUpdates = null; - } - } // Read this again, since an effect might have updated it + markRenderStopped(); + } // Set this to null to indicate there's no in-progress render. - remainingLanes = root.pendingLanes; // Check if there's remaining work on this root - // TODO: This is part of the `componentDidCatch` implementation. Its purpose - // is to detect whether something might have called setState inside - // `componentDidCatch`. The mechanism is known to be flawed because `setState` - // inside `componentDidCatch` is itself flawed — that's why we recommend - // `getDerivedStateFromError` instead. However, it could be improved by - // checking if remainingLanes includes Sync work, instead of whether there's - // any work remaining at all (which would also include stuff like Suspense - // retries or transitions). It's been like this for a while, though, so fixing - // it probably isn't that urgent. + workInProgressRoot = null; + workInProgressRootRenderLanes = NoLanes; // It's safe to process the queue now that the render phase is complete. - if (remainingLanes === NoLanes) { - // If there's no remaining work, we can clear the set of already failed - // error boundaries. - legacyErrorBoundariesThatAlreadyFailed = null; - } + finishQueueingConcurrentUpdates(); // Return the final exit status. - { - if (!rootDidHavePassiveEffects) { - commitDoubleInvokeEffectsInDEV(root, false); - } + return workInProgressRootExitStatus; } +} +/** @noinline */ - onCommitRoot(finishedWork.stateNode, renderPriorityLevel); - - { - if (isDevToolsPresent) { - root.memoizedUpdaters.clear(); - } +function workLoopConcurrent() { + // Perform work until Scheduler asks us to yield + while (workInProgress !== null && !shouldYield()) { + // $FlowFixMe[incompatible-call] found when upgrading Flow + performUnitOfWork(workInProgress); } - // additional work on this root is scheduled. - - ensureRootIsScheduled(root, now$1()); +} - if (recoverableErrors !== null) { - // There were errors during this render, but recovered from them without - // needing to surface it to the UI. We log them here. - var onRecoverableError = root.onRecoverableError; +function performUnitOfWork(unitOfWork) { + // The current, flushed, state of this fiber is the alternate. Ideally + // nothing should rely on this, but relying on it here means that we don't + // need an additional field on the work in progress. + var current = unitOfWork.alternate; + setCurrentFiber(unitOfWork); + var next; - for (var i = 0; i < recoverableErrors.length; i++) { - var recoverableError = recoverableErrors[i]; - var errorInfo = makeErrorInfo( - recoverableError.digest, - recoverableError.stack - ); - onRecoverableError(recoverableError.value, errorInfo); - } + if ((unitOfWork.mode & ProfileMode) !== NoMode) { + startProfilerTimer(unitOfWork); + next = beginWork(current, unitOfWork, renderLanes); + stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true); + } else { + next = beginWork(current, unitOfWork, renderLanes); } - if (hasUncaughtError) { - hasUncaughtError = false; - var error$1 = firstUncaughtError; - firstUncaughtError = null; - throw error$1; - } // If the passive effects are the result of a discrete render, flush them - // synchronously at the end of the current task so that the result is - // immediately observable. Otherwise, we assume that they are not - // order-dependent and do not need to be observed by external systems, so we - // can wait until after paint. - // TODO: We can optimize this by not scheduling the callback earlier. Since we - // currently schedule the callback in multiple places, will wait until those - // are consolidated. - - if (includesSyncLane(pendingPassiveEffectsLanes) && root.tag !== LegacyRoot) { - flushPassiveEffects(); - } // Read this again, since a passive effect might have updated it - - remainingLanes = root.pendingLanes; - - if (includesSyncLane(remainingLanes)) { - { - markNestedUpdateScheduled(); - } // Count the number of times the root synchronously re-renders without - // finishing. If there are too many, it indicates an infinite update loop. + resetCurrentFiber(); + unitOfWork.memoizedProps = unitOfWork.pendingProps; - if (root === rootWithNestedUpdates) { - nestedUpdateCount++; - } else { - nestedUpdateCount = 0; - rootWithNestedUpdates = root; - } + if (next === null) { + // If this doesn't spawn new work, complete the current work. + completeUnitOfWork(unitOfWork); } else { - nestedUpdateCount = 0; - } // If layout work was scheduled, flush it now. - - flushSyncCallbacks(); - - { - markCommitStopped(); + workInProgress = next; } - return null; + ReactCurrentOwner$1.current = null; } -function makeErrorInfo(digest, componentStack) { - { - var errorInfo = { - componentStack: componentStack, - digest: digest - }; - Object.defineProperty(errorInfo, "digest", { - configurable: false, - enumerable: true, - get: function () { - error( - 'You are accessing "digest" from the errorInfo object passed to onRecoverableError.' + - " This property is deprecated and will be removed in a future version of React." + - " To access the digest of an Error look for this property on the Error instance itself." - ); +function replaySuspendedUnitOfWork(unitOfWork) { + // This is a fork of performUnitOfWork specifcally for replaying a fiber that + // just suspended. + // + var current = unitOfWork.alternate; + setCurrentFiber(unitOfWork); + var next; + setCurrentFiber(unitOfWork); + var isProfilingMode = (unitOfWork.mode & ProfileMode) !== NoMode; - return digest; - } - }); - return errorInfo; + if (isProfilingMode) { + startProfilerTimer(unitOfWork); } -} -function flushPassiveEffects() { - // Returns whether passive effects were flushed. - // TODO: Combine this check with the one in flushPassiveEFfectsImpl. We should - // probably just combine the two functions. I believe they were only separate - // in the first place because we used to wrap it with - // `Scheduler.runWithPriority`, which accepts a function. But now we track the - // priority within React itself, so we can mutate the variable directly. - if (rootWithPendingPassiveEffects !== null) { - var renderPriority = lanesToEventPriority(pendingPassiveEffectsLanes); - var priority = lowerEventPriority(DefaultEventPriority, renderPriority); - var prevTransition = ReactCurrentBatchConfig.transition; - var previousPriority = getCurrentUpdatePriority(); + switch (unitOfWork.tag) { + case IndeterminateComponent: { + // Because it suspended with `use`, we can assume it's a + // function component. + unitOfWork.tag = FunctionComponent; // Fallthrough to the next branch. + } + // eslint-disable-next-line no-fallthrough - try { - ReactCurrentBatchConfig.transition = null; - setCurrentUpdatePriority(priority); - return flushPassiveEffectsImpl(); - } finally { - setCurrentUpdatePriority(previousPriority); - ReactCurrentBatchConfig.transition = prevTransition; // Once passive effects have run for the tree - giving components a + case FunctionComponent: + case ForwardRef: { + // Resolve `defaultProps`. This logic is copied from `beginWork`. + // TODO: Consider moving this switch statement into that module. Also, + // could maybe use this as an opportunity to say `use` doesn't work with + // `defaultProps` :) + var Component = unitOfWork.type; + var unresolvedProps = unitOfWork.pendingProps; + var resolvedProps = + unitOfWork.elementType === Component + ? unresolvedProps + : resolveDefaultProps(Component, unresolvedProps); + next = replayFunctionComponent( + current, + unitOfWork, + resolvedProps, + Component, + workInProgressRootRenderLanes + ); + break; } - } - return false; -} -function enqueuePendingPassiveProfilerEffect(fiber) { - { - pendingPassiveProfilerEffects.push(fiber); + case SimpleMemoComponent: { + var _Component = unitOfWork.type; + var nextProps = unitOfWork.pendingProps; + next = replayFunctionComponent( + current, + unitOfWork, + nextProps, + _Component, + workInProgressRootRenderLanes + ); + break; + } - if (!rootDoesHavePassiveEffects) { - rootDoesHavePassiveEffects = true; - scheduleCallback(NormalPriority, function () { - flushPassiveEffects(); - return null; - }); + default: { + // Other types besides function components are reset completely before + // being replayed. Currently this only happens when a Usable type is + // reconciled — the reconciler will suspend. + // + // We reset the fiber back to its original state; however, this isn't + // a full "unwind" because we're going to reuse the promises that were + // reconciled previously. So it's intentional that we don't call + // resetSuspendedWorkLoopOnUnwind here. + unwindInterruptedWork(current, unitOfWork); + unitOfWork = workInProgress = resetWorkInProgress( + unitOfWork, + renderLanes + ); + next = beginWork(current, unitOfWork, renderLanes); + break; } } -} - -function flushPassiveEffectsImpl() { - if (rootWithPendingPassiveEffects === null) { - return false; - } // Cache and clear the transitions flag - var root = rootWithPendingPassiveEffects; - var lanes = pendingPassiveEffectsLanes; - rootWithPendingPassiveEffects = null; // TODO: This is sometimes out of sync with rootWithPendingPassiveEffects. - // Figure out why and fix it. It's not causing any known issues (probably - // because it's only used for profiling), but it's a refactor hazard. - pendingPassiveEffectsLanes = NoLanes; + if (isProfilingMode) { + stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true); + } // The begin phase finished successfully without suspending. Return to the + // normal work loop. - if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { - throw new Error("Cannot flush passive effects while already rendering."); - } + resetCurrentFiber(); + unitOfWork.memoizedProps = unitOfWork.pendingProps; - { - isFlushingPassiveEffects = true; - didScheduleUpdateDuringPassiveEffects = false; + if (next === null) { + // If this doesn't spawn new work, complete the current work. + completeUnitOfWork(unitOfWork); + } else { + workInProgress = next; } - { - markPassiveEffectsStarted(lanes); - } + ReactCurrentOwner$1.current = null; +} - var prevExecutionContext = executionContext; - executionContext |= CommitContext; - commitPassiveUnmountEffects(root.current); - commitPassiveMountEffects(root, root.current); // TODO: Move to commitPassiveMountEffects +function throwAndUnwindWorkLoop(unitOfWork, thrownValue) { + // This is a fork of performUnitOfWork specifcally for unwinding a fiber + // that threw an exception. + // + // Return to the normal work loop. This will unwind the stack, and potentially + // result in showing a fallback. + resetSuspendedWorkLoopOnUnwind(); + var returnFiber = unitOfWork.return; - { - var profilerEffects = pendingPassiveProfilerEffects; - pendingPassiveProfilerEffects = []; + if (returnFiber === null || workInProgressRoot === null) { + // Expected to be working on a non-root fiber. This is a fatal error + // because there's no ancestor that can handle it; the root is + // supposed to capture all errors that weren't caught by an error + // boundary. + workInProgressRootExitStatus = RootFatalErrored; + workInProgressRootFatalError = thrownValue; // Set `workInProgress` to null. This represents advancing to the next + // sibling, or the parent if there are no siblings. But since the root + // has no siblings nor a parent, we set it to null. Usually this is + // handled by `completeUnitOfWork` or `unwindWork`, but since we're + // intentionally not calling those, we need set it here. + // TODO: Consider calling `unwindWork` to pop the contexts. - for (var i = 0; i < profilerEffects.length; i++) { - var fiber = profilerEffects[i]; - commitPassiveEffectDurations(root, fiber); - } + workInProgress = null; + return; } - { - markPassiveEffectsStopped(); + try { + // Find and mark the nearest Suspense or error boundary that can handle + // this "exception". + throwException( + workInProgressRoot, + returnFiber, + unitOfWork, + thrownValue, + workInProgressRootRenderLanes + ); + } catch (error) { + // We had trouble processing the error. An example of this happening is + // when accessing the `componentDidCatch` property of an error boundary + // throws an error. A weird edge case. There's a regression test for this. + // To prevent an infinite loop, bubble the error up to the next parent. + workInProgress = returnFiber; + throw error; } - { - commitDoubleInvokeEffectsInDEV(root, true); + if (unitOfWork.flags & Incomplete) { + // Unwind the stack until we reach the nearest boundary. + unwindUnitOfWork(unitOfWork); + } else { + // Although the fiber suspended, we're intentionally going to commit it in + // an inconsistent state. We can do this safely in cases where we know the + // inconsistent tree will be hidden. + // + // This currently only applies to Legacy Suspense implementation, but we may + // port a version of this to concurrent roots, too, when performing a + // synchronous render. Because that will allow us to mutate the tree as we + // go instead of buffering mutations until the end. Though it's unclear if + // this particular path is how that would be implemented. + completeUnitOfWork(unitOfWork); } +} - executionContext = prevExecutionContext; - flushSyncCallbacks(); +function completeUnitOfWork(unitOfWork) { + // Attempt to complete the current unit of work, then move to the next + // sibling. If there are no more siblings, return to the parent fiber. + var completedWork = unitOfWork; - { - // If additional passive effects were scheduled, increment a counter. If this - // exceeds the limit, we'll fire a warning. - if (didScheduleUpdateDuringPassiveEffects) { - if (root === rootWithPassiveNestedUpdates) { - nestedPassiveUpdateCount++; - } else { - nestedPassiveUpdateCount = 0; - rootWithPassiveNestedUpdates = root; + do { + { + { + if ((completedWork.flags & Incomplete) !== NoFlags$1) { + // NOTE: If we re-enable sibling prerendering in some cases, this branch + // is where we would switch to the unwinding path. + error( + "Internal React error: Expected this fiber to be complete, but " + + "it isn't. It should have been unwound. This is a bug in React." + ); + } } - } else { - nestedPassiveUpdateCount = 0; - } + } // The current, flushed, state of this fiber is the alternate. Ideally + // nothing should rely on this, but relying on it here means that we don't + // need an additional field on the work in progress. - isFlushingPassiveEffects = false; - didScheduleUpdateDuringPassiveEffects = false; - } // TODO: Move to commitPassiveMountEffects + var current = completedWork.alternate; + var returnFiber = completedWork.return; + setCurrentFiber(completedWork); + var next = void 0; - onPostCommitRoot(root); + if ((completedWork.mode & ProfileMode) === NoMode) { + next = completeWork(current, completedWork, renderLanes); + } else { + startProfilerTimer(completedWork); + next = completeWork(current, completedWork, renderLanes); // Update render duration assuming we didn't error. - { - var stateNode = root.current.stateNode; - stateNode.effectDuration = 0; - stateNode.passiveEffectDuration = 0; - } + stopProfilerTimerIfRunningAndRecordDelta(completedWork, false); + } - return true; -} + resetCurrentFiber(); + + if (next !== null) { + // Completing this fiber spawned new work. Work on that next. + workInProgress = next; + return; + } -function isAlreadyFailedLegacyErrorBoundary(instance) { - return ( - legacyErrorBoundariesThatAlreadyFailed !== null && - legacyErrorBoundariesThatAlreadyFailed.has(instance) - ); -} -function markLegacyErrorBoundaryAsFailed(instance) { - if (legacyErrorBoundariesThatAlreadyFailed === null) { - legacyErrorBoundariesThatAlreadyFailed = new Set([instance]); - } else { - legacyErrorBoundariesThatAlreadyFailed.add(instance); - } -} + var siblingFiber = completedWork.sibling; -function prepareToThrowUncaughtError(error) { - if (!hasUncaughtError) { - hasUncaughtError = true; - firstUncaughtError = error; - } -} + if (siblingFiber !== null) { + // If there is more work to do in this returnFiber, do that next. + workInProgress = siblingFiber; + return; + } // Otherwise, return to the parent + // $FlowFixMe[incompatible-type] we bail out when we get a null -var onUncaughtError = prepareToThrowUncaughtError; + completedWork = returnFiber; // Update the next thing we're working on in case something throws. -function captureCommitPhaseErrorOnRoot(rootFiber, sourceFiber, error) { - var errorInfo = createCapturedValueAtFiber(error, sourceFiber); - var update = createRootErrorUpdate(rootFiber, errorInfo, SyncLane); - var root = enqueueUpdate(rootFiber, update, SyncLane); - var eventTime = requestEventTime(); + workInProgress = completedWork; + } while (completedWork !== null); // We've reached the root. - if (root !== null) { - markRootUpdated(root, SyncLane, eventTime); - ensureRootIsScheduled(root, eventTime); + if (workInProgressRootExitStatus === RootInProgress) { + workInProgressRootExitStatus = RootCompleted; } } -function captureCommitPhaseError(sourceFiber, nearestMountedAncestor, error$1) { - { - reportUncaughtErrorInDEV(error$1); - setIsRunningInsertionEffect(false); - } - - if (sourceFiber.tag === HostRoot) { - // Error was thrown at the root. There is no parent, so the root - // itself should capture it. - captureCommitPhaseErrorOnRoot(sourceFiber, sourceFiber, error$1); - return; - } +function unwindUnitOfWork(unitOfWork) { + var incompleteWork = unitOfWork; - var fiber = null; + do { + // The current, flushed, state of this fiber is the alternate. Ideally + // nothing should rely on this, but relying on it here means that we don't + // need an additional field on the work in progress. + var current = incompleteWork.alternate; // This fiber did not complete because something threw. Pop values off + // the stack without entering the complete phase. If this is a boundary, + // capture values if possible. - { - fiber = sourceFiber.return; - } + var next = unwindWork(current, incompleteWork); // Because this fiber did not complete, don't reset its lanes. - while (fiber !== null) { - if (fiber.tag === HostRoot) { - captureCommitPhaseErrorOnRoot(fiber, sourceFiber, error$1); + if (next !== null) { + // Found a boundary that can handle this exception. Re-renter the + // begin phase. This branch will return us to the normal work loop. + // + // Since we're restarting, remove anything that is not a host effect + // from the effect tag. + next.flags &= HostEffectMask; + workInProgress = next; return; - } else if (fiber.tag === ClassComponent) { - var ctor = fiber.type; - var instance = fiber.stateNode; + } // Keep unwinding until we reach either a boundary or the root. - if ( - typeof ctor.getDerivedStateFromError === "function" || - (typeof instance.componentDidCatch === "function" && - !isAlreadyFailedLegacyErrorBoundary(instance)) - ) { - var errorInfo = createCapturedValueAtFiber(error$1, sourceFiber); - var update = createClassErrorUpdate(fiber, errorInfo, SyncLane); - var root = enqueueUpdate(fiber, update, SyncLane); - var eventTime = requestEventTime(); + if ((incompleteWork.mode & ProfileMode) !== NoMode) { + // Record the render duration for the fiber that errored. + stopProfilerTimerIfRunningAndRecordDelta(incompleteWork, false); // Include the time spent working on failed children before continuing. - if (root !== null) { - markRootUpdated(root, SyncLane, eventTime); - ensureRootIsScheduled(root, eventTime); - } + var actualDuration = incompleteWork.actualDuration; + var child = incompleteWork.child; - return; + while (child !== null) { + // $FlowFixMe[unsafe-addition] addition with possible null/undefined value + actualDuration += child.actualDuration; + child = child.sibling; } - } - - fiber = fiber.return; - } - { - // TODO: Until we re-land skipUnmountedBoundaries (see #20147), this warning - // will fire for errors that are thrown by destroy functions inside deleted - // trees. What it should instead do is propagate the error to the parent of - // the deleted tree. In the meantime, do not add this warning to the - // allowlist; this is only for our internal use. - error( - "Internal React error: Attempted to capture a commit phase error " + - "inside a detached tree. This indicates a bug in React. Likely " + - "causes include deleting the same fiber more than once, committing an " + - "already-finished tree, or an inconsistent return pointer.\n\n" + - "Error message:\n\n%s", - error$1 - ); - } -} -function attachPingListener(root, wakeable, lanes) { - // Attach a ping listener - // - // The data might resolve before we have a chance to commit the fallback. Or, - // in the case of a refresh, we'll never commit a fallback. So we need to - // attach a listener now. When it resolves ("pings"), we can decide whether to - // try rendering the tree again. - // - // Only attach a listener if one does not already exist for the lanes - // we're currently rendering (which acts like a "thread ID" here). - // - // We only need to do this in concurrent mode. Legacy Suspense always - // commits fallbacks synchronously, so there are no pings. - var pingCache = root.pingCache; - var threadIDs; + incompleteWork.actualDuration = actualDuration; + } // TODO: Once we stop prerendering siblings, instead of resetting the parent + // of the node being unwound, we should be able to reset node itself as we + // unwind the stack. Saves an additional null check. - if (pingCache === null) { - pingCache = root.pingCache = new PossiblyWeakMap(); - threadIDs = new Set(); - pingCache.set(wakeable, threadIDs); - } else { - threadIDs = pingCache.get(wakeable); + var returnFiber = incompleteWork.return; - if (threadIDs === undefined) { - threadIDs = new Set(); - pingCache.set(wakeable, threadIDs); + if (returnFiber !== null) { + // Mark the parent fiber as incomplete and clear its subtree flags. + // TODO: Once we stop prerendering siblings, we may be able to get rid of + // the Incomplete flag because unwinding to the nearest boundary will + // happen synchronously. + returnFiber.flags |= Incomplete; + returnFiber.subtreeFlags = NoFlags$1; + returnFiber.deletions = null; } - } + // $FlowFixMe[incompatible-type] we bail out when we get a null - if (!threadIDs.has(lanes)) { - workInProgressRootDidAttachPingListener = true; // Memoize using the thread ID to prevent redundant listeners. + incompleteWork = returnFiber; // Update the next thing we're working on in case something throws. - threadIDs.add(lanes); - var ping = pingSuspendedRoot.bind(null, root, wakeable, lanes); + workInProgress = incompleteWork; + } while (incompleteWork !== null); // We've unwound all the way to the root. - { - if (isDevToolsPresent) { - // If we have pending work still, restore the original updaters - restorePendingUpdaters(root, lanes); - } - } + workInProgressRootExitStatus = RootDidNotComplete; + workInProgress = null; +} - wakeable.then(ping, ping); +function commitRoot(root, recoverableErrors, transitions) { + // TODO: This no longer makes any sense. We already wrap the mutation and + // layout phases. Should be able to remove. + var previousUpdateLanePriority = getCurrentUpdatePriority(); + var prevTransition = ReactCurrentBatchConfig.transition; + + try { + ReactCurrentBatchConfig.transition = null; + setCurrentUpdatePriority(DiscreteEventPriority); + commitRootImpl( + root, + recoverableErrors, + transitions, + previousUpdateLanePriority + ); + } finally { + ReactCurrentBatchConfig.transition = prevTransition; + setCurrentUpdatePriority(previousUpdateLanePriority); } + + return null; } -function pingSuspendedRoot(root, wakeable, pingedLanes) { - var pingCache = root.pingCache; +function commitRootImpl( + root, + recoverableErrors, + transitions, + renderPriorityLevel +) { + do { + // `flushPassiveEffects` will call `flushSyncUpdateQueue` at the end, which + // means `flushPassiveEffects` will sometimes result in additional + // passive effects. So we need to keep flushing in a loop until there are + // no more pending effects. + // TODO: Might be better if `flushPassiveEffects` did not automatically + // flush synchronous work at the end, to avoid factoring hazards like this. + flushPassiveEffects(); + } while (rootWithPendingPassiveEffects !== null); - if (pingCache !== null) { - // The wakeable resolved, so we no longer need to memoize, because it will - // never be thrown again. - pingCache.delete(wakeable); - } + flushRenderPhaseStrictModeWarningsInDEV(); - var eventTime = requestEventTime(); - markRootPinged(root, pingedLanes); - warnIfSuspenseResolutionNotWrappedWithActDEV(root); + if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { + throw new Error("Should not already be working."); + } - if ( - workInProgressRoot === root && - isSubsetOfLanes(workInProgressRootRenderLanes, pingedLanes) - ) { - // Received a ping at the same priority level at which we're currently - // rendering. We might want to restart this render. This should mirror - // the logic of whether or not a root suspends once it completes. - // TODO: If we're rendering sync either due to Sync, Batched or expired, - // we should probably never restart. - // If we're suspended with delay, or if it's a retry, we'll always suspend - // so we can always restart. - if ( - workInProgressRootExitStatus === RootSuspendedWithDelay || - (workInProgressRootExitStatus === RootSuspended && - includesOnlyRetries(workInProgressRootRenderLanes) && - now$1() - globalMostRecentFallbackTime < FALLBACK_THROTTLE_MS) - ) { - // Force a restart from the root by unwinding the stack. Unless this is - // being called from the render phase, because that would cause a crash. - if ((executionContext & RenderContext) === NoContext) { - prepareFreshStack(root, NoLanes); + var finishedWork = root.finishedWork; + var lanes = root.finishedLanes; + + { + markCommitStarted(lanes); + } + + if (finishedWork === null) { + { + markCommitStopped(); + } + + return null; + } else { + { + if (lanes === NoLanes) { + error( + "root.finishedLanes should not be empty during a commit. This is a " + + "bug in React." + ); } - } else { - // Even though we can't restart right now, we might get an - // opportunity later. So we mark this render as having a ping. - workInProgressRootPingedLanes = mergeLanes( - workInProgressRootPingedLanes, - pingedLanes - ); } } - ensureRootIsScheduled(root, eventTime); -} + root.finishedWork = null; + root.finishedLanes = NoLanes; -function retryTimedOutBoundary(boundaryFiber, retryLane) { - // The boundary fiber (a Suspense component or SuspenseList component) - // previously was rendered in its fallback state. One of the promises that - // suspended it has resolved, which means at least part of the tree was - // likely unblocked. Try rendering again, at a new lanes. - if (retryLane === NoLane) { - // TODO: Assign this to `suspenseState.retryLane`? to avoid - // unnecessary entanglement? - retryLane = requestRetryLane(boundaryFiber); - } // TODO: Special case idle priority? + if (finishedWork === root.current) { + throw new Error( + "Cannot commit the same tree as before. This error is likely caused by " + + "a bug in React. Please file an issue." + ); + } // commitRoot never returns a continuation; it always finishes synchronously. + // So we can clear these now to allow a new callback to be scheduled. - var eventTime = requestEventTime(); - var root = enqueueConcurrentRenderForLane(boundaryFiber, retryLane); + root.callbackNode = null; + root.callbackPriority = NoLane; + root.cancelPendingCommit = null; // Check which lanes no longer have any work scheduled on them, and mark + // those as finished. - if (root !== null) { - markRootUpdated(root, retryLane, eventTime); - ensureRootIsScheduled(root, eventTime); - } -} + var remainingLanes = mergeLanes(finishedWork.lanes, finishedWork.childLanes); // Make sure to account for lanes that were updated by a concurrent event + // during the render phase; don't mark them as finished. -function retryDehydratedSuspenseBoundary(boundaryFiber) { - var suspenseState = boundaryFiber.memoizedState; - var retryLane = NoLane; + var concurrentlyUpdatedLanes = getConcurrentlyUpdatedLanes(); + remainingLanes = mergeLanes(remainingLanes, concurrentlyUpdatedLanes); + markRootFinished(root, remainingLanes); - if (suspenseState !== null) { - retryLane = suspenseState.retryLane; - } + if (root === workInProgressRoot) { + // We can reset these now that they are finished. + workInProgressRoot = null; + workInProgress = null; + workInProgressRootRenderLanes = NoLanes; + } // If there are pending passive effects, schedule a callback to process them. + // Do this as early as possible, so it is queued before anything else that + // might get scheduled in the commit phase. (See #16714.) + // TODO: Delete all other places that schedule the passive effect callback + // They're redundant. - retryTimedOutBoundary(boundaryFiber, retryLane); -} -function resolveRetryWakeable(boundaryFiber, wakeable) { - var retryLane = NoLane; // Default + if ( + (finishedWork.subtreeFlags & PassiveMask) !== NoFlags$1 || + (finishedWork.flags & PassiveMask) !== NoFlags$1 + ) { + if (!rootDoesHavePassiveEffects) { + rootDoesHavePassiveEffects = true; + scheduleCallback(NormalPriority, function () { + flushPassiveEffects(); // This render triggered passive effects: release the root cache pool + // *after* passive effects fire to avoid freeing a cache pool that may + // be referenced by a node in the tree (HostRoot, Cache boundary etc) - var retryCache; + return null; + }); + } + } // Check if there are any effects in the whole tree. + // TODO: This is left over from the effect list implementation, where we had + // to check for the existence of `firstEffect` to satisfy Flow. I think the + // only other reason this optimization exists is because it affects profiling. + // Reconsider whether this is necessary. - switch (boundaryFiber.tag) { - case SuspenseComponent: - retryCache = boundaryFiber.stateNode; - var suspenseState = boundaryFiber.memoizedState; + var subtreeHasEffects = + (finishedWork.subtreeFlags & + (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !== + NoFlags$1; + var rootHasEffect = + (finishedWork.flags & + (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !== + NoFlags$1; - if (suspenseState !== null) { - retryLane = suspenseState.retryLane; - } + if (subtreeHasEffects || rootHasEffect) { + var prevTransition = ReactCurrentBatchConfig.transition; + ReactCurrentBatchConfig.transition = null; + var previousPriority = getCurrentUpdatePriority(); + setCurrentUpdatePriority(DiscreteEventPriority); + var prevExecutionContext = executionContext; + executionContext |= CommitContext; // Reset this to null before calling lifecycles - break; + ReactCurrentOwner$1.current = null; // The commit phase is broken into several sub-phases. We do a separate pass + // of the effect list for each phase: all mutation effects come before all + // layout effects, and so on. + // The first phase a "before mutation" phase. We use this phase to read the + // state of the host tree right before we mutate it. This is where + // getSnapshotBeforeUpdate is called. - case SuspenseListComponent: - retryCache = boundaryFiber.stateNode; - break; + commitBeforeMutationEffects(root, finishedWork); - case OffscreenComponent: { - var instance = boundaryFiber.stateNode; - retryCache = instance._retryCache; - break; + { + // Mark the current commit time to be shared by all Profilers in this + // batch. This enables them to be grouped later. + recordCommitTime(); } - default: - throw new Error( - "Pinged unknown suspense boundary type. " + - "This is probably a bug in React." - ); - } + commitMutationEffects(root, finishedWork, lanes); + // the mutation phase, so that the previous tree is still current during + // componentWillUnmount, but before the layout phase, so that the finished + // work is current during componentDidMount/Update. - if (retryCache !== null) { - // The wakeable resolved, so we no longer need to memoize, because it will - // never be thrown again. - retryCache.delete(wakeable); - } + root.current = finishedWork; // The next phase is the layout phase, where we call effects that read - retryTimedOutBoundary(boundaryFiber, retryLane); -} // Computes the next Just Noticeable Difference (JND) boundary. -// The theory is that a person can't tell the difference between small differences in time. -// Therefore, if we wait a bit longer than necessary that won't translate to a noticeable -// difference in the experience. However, waiting for longer might mean that we can avoid -// showing an intermediate loading state. The longer we have already waited, the harder it -// is to tell small differences in time. Therefore, the longer we've already waited, -// the longer we can wait additionally. At some point we have to give up though. -// We pick a train model where the next boundary commits at a consistent schedule. -// These particular numbers are vague estimates. We expect to adjust them based on research. + { + markLayoutEffectsStarted(lanes); + } -function jnd(timeElapsed) { - return timeElapsed < 120 - ? 120 - : timeElapsed < 480 - ? 480 - : timeElapsed < 1080 - ? 1080 - : timeElapsed < 1920 - ? 1920 - : timeElapsed < 3000 - ? 3000 - : timeElapsed < 4320 - ? 4320 - : ceil(timeElapsed / 1960) * 1960; -} + commitLayoutEffects(finishedWork, root, lanes); -function throwIfInfiniteUpdateLoopDetected() { - if (nestedUpdateCount > NESTED_UPDATE_LIMIT) { - nestedUpdateCount = 0; - nestedPassiveUpdateCount = 0; - rootWithNestedUpdates = null; - rootWithPassiveNestedUpdates = null; - throw new Error( - "Maximum update depth exceeded. This can happen when a component " + - "repeatedly calls setState inside componentWillUpdate or " + - "componentDidUpdate. React limits the number of nested updates to " + - "prevent infinite loops." - ); + { + markLayoutEffectsStopped(); + } + // opportunity to paint. + + requestPaint(); + executionContext = prevExecutionContext; // Reset the priority to the previous non-sync value. + + setCurrentUpdatePriority(previousPriority); + ReactCurrentBatchConfig.transition = prevTransition; + } else { + // No effects. + root.current = finishedWork; // Measure these anyway so the flamegraph explicitly shows that there were + // no effects. + // TODO: Maybe there's a better way to report this. + + { + recordCommitTime(); + } } - { - if (nestedPassiveUpdateCount > NESTED_PASSIVE_UPDATE_LIMIT) { + var rootDidHavePassiveEffects = rootDoesHavePassiveEffects; + + if (rootDoesHavePassiveEffects) { + // This commit has passive effects. Stash a reference to them. But don't + // schedule a callback until after flushing layout work. + rootDoesHavePassiveEffects = false; + rootWithPendingPassiveEffects = root; + pendingPassiveEffectsLanes = lanes; + } else { + { nestedPassiveUpdateCount = 0; rootWithPassiveNestedUpdates = null; - - error( - "Maximum update depth exceeded. This can happen when a component " + - "calls setState inside useEffect, but useEffect either doesn't " + - "have a dependency array, or one of the dependencies changes on " + - "every render." - ); } - } -} + } // Read this again, since an effect might have updated it -function flushRenderPhaseStrictModeWarningsInDEV() { - { - ReactStrictModeWarnings.flushLegacyContextWarning(); - ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings(); + remainingLanes = root.pendingLanes; // Check if there's remaining work on this root + // TODO: This is part of the `componentDidCatch` implementation. Its purpose + // is to detect whether something might have called setState inside + // `componentDidCatch`. The mechanism is known to be flawed because `setState` + // inside `componentDidCatch` is itself flawed — that's why we recommend + // `getDerivedStateFromError` instead. However, it could be improved by + // checking if remainingLanes includes Sync work, instead of whether there's + // any work remaining at all (which would also include stuff like Suspense + // retries or transitions). It's been like this for a while, though, so fixing + // it probably isn't that urgent. + + if (remainingLanes === NoLanes) { + // If there's no remaining work, we can clear the set of already failed + // error boundaries. + legacyErrorBoundariesThatAlreadyFailed = null; } -} -function commitDoubleInvokeEffectsInDEV(root, hasPassiveEffects) { { - { - legacyCommitDoubleInvokeEffectsInDEV(root.current, hasPassiveEffects); + if (!rootDidHavePassiveEffects) { + commitDoubleInvokeEffectsInDEV(root, false); } } -} - -function legacyCommitDoubleInvokeEffectsInDEV(fiber, hasPassiveEffects) { - // TODO (StrictEffects) Should we set a marker on the root if it contains strict effects - // so we don't traverse unnecessarily? similar to subtreeFlags but just at the root level. - // Maybe not a big deal since this is DEV only behavior. - setCurrentFiber(fiber); - invokeEffectsInDev(fiber, MountLayoutDev, invokeLayoutEffectUnmountInDEV); - - if (hasPassiveEffects) { - invokeEffectsInDev(fiber, MountPassiveDev, invokePassiveEffectUnmountInDEV); - } - invokeEffectsInDev(fiber, MountLayoutDev, invokeLayoutEffectMountInDEV); + onCommitRoot(finishedWork.stateNode, renderPriorityLevel); - if (hasPassiveEffects) { - invokeEffectsInDev(fiber, MountPassiveDev, invokePassiveEffectMountInDEV); + { + if (isDevToolsPresent) { + root.memoizedUpdaters.clear(); + } } + // additional work on this root is scheduled. - resetCurrentFiber(); -} - -function invokeEffectsInDev(firstChild, fiberFlags, invokeEffectFn) { - var current = firstChild; - var subtreeRoot = null; - - while (current != null) { - var primarySubtreeFlag = current.subtreeFlags & fiberFlags; + ensureRootIsScheduled(root, now$1()); - if ( - current !== subtreeRoot && - current.child != null && - primarySubtreeFlag !== NoFlags$1 - ) { - current = current.child; - } else { - if ((current.flags & fiberFlags) !== NoFlags$1) { - invokeEffectFn(current); - } + if (recoverableErrors !== null) { + // There were errors during this render, but recovered from them without + // needing to surface it to the UI. We log them here. + var onRecoverableError = root.onRecoverableError; - if (current.sibling !== null) { - current = current.sibling; - } else { - current = subtreeRoot = current.return; - } + for (var i = 0; i < recoverableErrors.length; i++) { + var recoverableError = recoverableErrors[i]; + var errorInfo = makeErrorInfo( + recoverableError.digest, + recoverableError.stack + ); + onRecoverableError(recoverableError.value, errorInfo); } } -} - -var didWarnStateUpdateForNotYetMountedComponent = null; -function warnAboutUpdateOnNotYetMountedFiberInDEV(fiber) { - { - if ((executionContext & RenderContext) !== NoContext) { - // We let the other warning about render phase updates deal with this one. - return; - } - - if (!(fiber.mode & ConcurrentMode)) { - return; - } - var tag = fiber.tag; + if (hasUncaughtError) { + hasUncaughtError = false; + var error$1 = firstUncaughtError; + firstUncaughtError = null; + throw error$1; + } // If the passive effects are the result of a discrete render, flush them + // synchronously at the end of the current task so that the result is + // immediately observable. Otherwise, we assume that they are not + // order-dependent and do not need to be observed by external systems, so we + // can wait until after paint. + // TODO: We can optimize this by not scheduling the callback earlier. Since we + // currently schedule the callback in multiple places, will wait until those + // are consolidated. - if ( - tag !== IndeterminateComponent && - tag !== HostRoot && - tag !== ClassComponent && - tag !== FunctionComponent && - tag !== ForwardRef && - tag !== MemoComponent && - tag !== SimpleMemoComponent - ) { - // Only warn for user-defined components, not internal ones like Suspense. - return; - } // We show the whole stack but dedupe on the top component's name because - // the problematic code almost always lies inside that component. + if (includesSyncLane(pendingPassiveEffectsLanes) && root.tag !== LegacyRoot) { + flushPassiveEffects(); + } // Read this again, since a passive effect might have updated it - var componentName = getComponentNameFromFiber(fiber) || "ReactComponent"; + remainingLanes = root.pendingLanes; - if (didWarnStateUpdateForNotYetMountedComponent !== null) { - if (didWarnStateUpdateForNotYetMountedComponent.has(componentName)) { - return; - } // $FlowFixMe[incompatible-use] found when upgrading Flow + if (includesSyncLane(remainingLanes)) { + { + markNestedUpdateScheduled(); + } // Count the number of times the root synchronously re-renders without + // finishing. If there are too many, it indicates an infinite update loop. - didWarnStateUpdateForNotYetMountedComponent.add(componentName); + if (root === rootWithNestedUpdates) { + nestedUpdateCount++; } else { - didWarnStateUpdateForNotYetMountedComponent = new Set([componentName]); + nestedUpdateCount = 0; + rootWithNestedUpdates = root; } + } else { + nestedUpdateCount = 0; + } // If layout work was scheduled, flush it now. - var previousFiber = current; + flushSyncCallbacks(); - try { - setCurrentFiber(fiber); + { + markCommitStopped(); + } - error( - "Can't perform a React state update on a component that hasn't mounted yet. " + - "This indicates that you have a side-effect in your render function that " + - "asynchronously later calls tries to update the component. Move this work to " + - "useEffect instead." - ); - } finally { - if (previousFiber) { - setCurrentFiber(fiber); - } else { - resetCurrentFiber(); + return null; +} + +function makeErrorInfo(digest, componentStack) { + { + var errorInfo = { + componentStack: componentStack, + digest: digest + }; + Object.defineProperty(errorInfo, "digest", { + configurable: false, + enumerable: true, + get: function () { + error( + 'You are accessing "digest" from the errorInfo object passed to onRecoverableError.' + + " This property is deprecated and will be removed in a future version of React." + + " To access the digest of an Error look for this property on the Error instance itself." + ); + + return digest; } - } + }); + return errorInfo; } } -var beginWork; -{ - var dummyFiber = null; - - beginWork = function (current, unitOfWork, lanes) { - // If a component throws an error, we replay it again in a synchronously - // dispatched event, so that the debugger will treat it as an uncaught - // error See ReactErrorUtils for more information. - // Before entering the begin phase, copy the work-in-progress onto a dummy - // fiber. If beginWork throws, we'll use this to reset the state. - var originalWorkInProgressCopy = assignFiberPropertiesInDEV( - dummyFiber, - unitOfWork - ); +function flushPassiveEffects() { + // Returns whether passive effects were flushed. + // TODO: Combine this check with the one in flushPassiveEFfectsImpl. We should + // probably just combine the two functions. I believe they were only separate + // in the first place because we used to wrap it with + // `Scheduler.runWithPriority`, which accepts a function. But now we track the + // priority within React itself, so we can mutate the variable directly. + if (rootWithPendingPassiveEffects !== null) { + var renderPriority = lanesToEventPriority(pendingPassiveEffectsLanes); + var priority = lowerEventPriority(DefaultEventPriority, renderPriority); + var prevTransition = ReactCurrentBatchConfig.transition; + var previousPriority = getCurrentUpdatePriority(); try { - return beginWork$1(current, unitOfWork, lanes); - } catch (originalError) { - if ( - didSuspendOrErrorWhileHydratingDEV() || - originalError === SuspenseException || - originalError === SelectiveHydrationException || - (originalError !== null && - typeof originalError === "object" && - typeof originalError.then === "function") - ) { - // Don't replay promises. - // Don't replay errors if we are hydrating and have already suspended or handled an error - throw originalError; - } // Don't reset current debug fiber, since we're about to work on the - // same fiber again. - // Unwind the failed stack frame - - resetSuspendedWorkLoopOnUnwind(); - unwindInterruptedWork(current, unitOfWork); // Restore the original properties of the fiber. - - assignFiberPropertiesInDEV(unitOfWork, originalWorkInProgressCopy); - - if (unitOfWork.mode & ProfileMode) { - // Reset the profiler timer. - startProfilerTimer(unitOfWork); - } // Run beginWork again. - - invokeGuardedCallback( - null, - beginWork$1, - null, - current, - unitOfWork, - lanes - ); - - if (hasCaughtError()) { - var replayError = clearCaughtError(); - - if ( - typeof replayError === "object" && - replayError !== null && - replayError._suppressLogging && - typeof originalError === "object" && - originalError !== null && - !originalError._suppressLogging - ) { - // If suppressed, let the flag carry over to the original error which is the one we'll rethrow. - originalError._suppressLogging = true; - } - } // We always throw the original error in case the second render pass is not idempotent. - // This can happen if a memoized function or CommonJS module doesn't throw after first invocation. - - throw originalError; + ReactCurrentBatchConfig.transition = null; + setCurrentUpdatePriority(priority); + return flushPassiveEffectsImpl(); + } finally { + setCurrentUpdatePriority(previousPriority); + ReactCurrentBatchConfig.transition = prevTransition; // Once passive effects have run for the tree - giving components a } - }; -} - -var didWarnAboutUpdateInRender = false; -var didWarnAboutUpdateInRenderForAnotherComponent; + } -{ - didWarnAboutUpdateInRenderForAnotherComponent = new Set(); + return false; } - -function warnAboutRenderPhaseUpdatesInDEV(fiber) { +function enqueuePendingPassiveProfilerEffect(fiber) { { - if (isRendering) { - switch (fiber.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - var renderingComponentName = - (workInProgress && getComponentNameFromFiber(workInProgress)) || - "Unknown"; // Dedupe by the rendering component because it's the one that needs to be fixed. - - var dedupeKey = renderingComponentName; - - if (!didWarnAboutUpdateInRenderForAnotherComponent.has(dedupeKey)) { - didWarnAboutUpdateInRenderForAnotherComponent.add(dedupeKey); - var setStateComponentName = - getComponentNameFromFiber(fiber) || "Unknown"; + pendingPassiveProfilerEffects.push(fiber); - error( - "Cannot update a component (`%s`) while rendering a " + - "different component (`%s`). To locate the bad setState() call inside `%s`, " + - "follow the stack trace as described in https://reactjs.org/link/setstate-in-render", - setStateComponentName, - renderingComponentName, - renderingComponentName - ); - } + if (!rootDoesHavePassiveEffects) { + rootDoesHavePassiveEffects = true; + scheduleCallback(NormalPriority, function () { + flushPassiveEffects(); + return null; + }); + } + } +} - break; - } +function flushPassiveEffectsImpl() { + if (rootWithPendingPassiveEffects === null) { + return false; + } // Cache and clear the transitions flag + var root = rootWithPendingPassiveEffects; + var lanes = pendingPassiveEffectsLanes; + rootWithPendingPassiveEffects = null; // TODO: This is sometimes out of sync with rootWithPendingPassiveEffects. + // Figure out why and fix it. It's not causing any known issues (probably + // because it's only used for profiling), but it's a refactor hazard. - case ClassComponent: { - if (!didWarnAboutUpdateInRender) { - error( - "Cannot update during an existing state transition (such as " + - "within `render`). Render methods should be a pure " + - "function of props and state." - ); + pendingPassiveEffectsLanes = NoLanes; - didWarnAboutUpdateInRender = true; - } + if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { + throw new Error("Cannot flush passive effects while already rendering."); + } - break; - } - } - } + { + isFlushingPassiveEffects = true; + didScheduleUpdateDuringPassiveEffects = false; } -} -function restorePendingUpdaters(root, lanes) { { - if (isDevToolsPresent) { - var memoizedUpdaters = root.memoizedUpdaters; - memoizedUpdaters.forEach(function (schedulingFiber) { - addFiberToLanesMap(root, schedulingFiber, lanes); - }); // This function intentionally does not clear memoized updaters. - // Those may still be relevant to the current commit - // and a future one (e.g. Suspense). - } + markPassiveEffectsStarted(lanes); } -} -var fakeActCallbackNode = {}; // $FlowFixMe[missing-local-annot] -function scheduleCallback(priorityLevel, callback) { + var prevExecutionContext = executionContext; + executionContext |= CommitContext; + commitPassiveUnmountEffects(root.current); + commitPassiveMountEffects(root, root.current); // TODO: Move to commitPassiveMountEffects + { - // If we're currently inside an `act` scope, bypass Scheduler and push to - // the `act` queue instead. - var actQueue = ReactCurrentActQueue.current; + var profilerEffects = pendingPassiveProfilerEffects; + pendingPassiveProfilerEffects = []; - if (actQueue !== null) { - actQueue.push(callback); - return fakeActCallbackNode; - } else { - return scheduleCallback$1(priorityLevel, callback); + for (var i = 0; i < profilerEffects.length; i++) { + var fiber = profilerEffects[i]; + commitPassiveEffectDurations(root, fiber); } } -} -function cancelCallback(callbackNode) { - if (callbackNode === fakeActCallbackNode) { - return; - } // In production, always call Scheduler. This function will be stripped out. + { + markPassiveEffectsStopped(); + } - return cancelCallback$1(callbackNode); -} + { + commitDoubleInvokeEffectsInDEV(root, true); + } -function shouldForceFlushFallbacksInDEV() { - // Never force flush in production. This function should get stripped out. - return ReactCurrentActQueue.current !== null; -} + executionContext = prevExecutionContext; + flushSyncCallbacks(); -function warnIfUpdatesNotWrappedWithActDEV(fiber) { { - if (fiber.mode & ConcurrentMode) { - if (!isConcurrentActEnvironment()) { - // Not in an act environment. No need to warn. - return; + // If additional passive effects were scheduled, increment a counter. If this + // exceeds the limit, we'll fire a warning. + if (didScheduleUpdateDuringPassiveEffects) { + if (root === rootWithPassiveNestedUpdates) { + nestedPassiveUpdateCount++; + } else { + nestedPassiveUpdateCount = 0; + rootWithPassiveNestedUpdates = root; } } else { - // Legacy mode has additional cases where we suppress a warning. - if (!isLegacyActEnvironment()) { - // Not in an act environment. No need to warn. - return; - } - - if (executionContext !== NoContext) { - // Legacy mode doesn't warn if the update is batched, i.e. - // batchedUpdates or flushSync. - return; - } - - if ( - fiber.tag !== FunctionComponent && - fiber.tag !== ForwardRef && - fiber.tag !== SimpleMemoComponent - ) { - // For backwards compatibility with pre-hooks code, legacy mode only - // warns for updates that originate from a hook. - return; - } + nestedPassiveUpdateCount = 0; } - if (ReactCurrentActQueue.current === null) { - var previousFiber = current; + isFlushingPassiveEffects = false; + didScheduleUpdateDuringPassiveEffects = false; + } // TODO: Move to commitPassiveMountEffects - try { - setCurrentFiber(fiber); + onPostCommitRoot(root); - error( - "An update to %s inside a test was not wrapped in act(...).\n\n" + - "When testing, code that causes React state updates should be " + - "wrapped into act(...):\n\n" + - "act(() => {\n" + - " /* fire events that update state */\n" + - "});\n" + - "/* assert on the output */\n\n" + - "This ensures that you're testing the behavior the user would see " + - "in the browser." + - " Learn more at https://reactjs.org/link/wrap-tests-with-act", - getComponentNameFromFiber(fiber) - ); - } finally { - if (previousFiber) { - setCurrentFiber(fiber); - } else { - resetCurrentFiber(); - } - } - } + { + var stateNode = root.current.stateNode; + stateNode.effectDuration = 0; + stateNode.passiveEffectDuration = 0; } + + return true; } -function warnIfSuspenseResolutionNotWrappedWithActDEV(root) { - { - if ( - root.tag !== LegacyRoot && - isConcurrentActEnvironment() && - ReactCurrentActQueue.current === null - ) { - error( - "A suspended resource finished loading inside a test, but the event " + - "was not wrapped in act(...).\n\n" + - "When testing, code that resolves suspended data should be wrapped " + - "into act(...):\n\n" + - "act(() => {\n" + - " /* finish loading suspended data */\n" + - "});\n" + - "/* assert on the output */\n\n" + - "This ensures that you're testing the behavior the user would see " + - "in the browser." + - " Learn more at https://reactjs.org/link/wrap-tests-with-act" - ); - } +function isAlreadyFailedLegacyErrorBoundary(instance) { + return ( + legacyErrorBoundariesThatAlreadyFailed !== null && + legacyErrorBoundariesThatAlreadyFailed.has(instance) + ); +} +function markLegacyErrorBoundaryAsFailed(instance) { + if (legacyErrorBoundariesThatAlreadyFailed === null) { + legacyErrorBoundariesThatAlreadyFailed = new Set([instance]); + } else { + legacyErrorBoundariesThatAlreadyFailed.add(instance); } } -function setIsRunningInsertionEffect(isRunning) { - { - isRunningInsertionEffect = isRunning; +function prepareToThrowUncaughtError(error) { + if (!hasUncaughtError) { + hasUncaughtError = true; + firstUncaughtError = error; } } -/* eslint-disable react-internal/prod-error-codes */ -// Used by React Refresh runtime through DevTools Global Hook. +var onUncaughtError = prepareToThrowUncaughtError; -var resolveFamily = null; -var failedBoundaries = null; -var setRefreshHandler = function (handler) { +function captureCommitPhaseErrorOnRoot(rootFiber, sourceFiber, error) { + var errorInfo = createCapturedValueAtFiber(error, sourceFiber); + var update = createRootErrorUpdate(rootFiber, errorInfo, SyncLane); + var root = enqueueUpdate(rootFiber, update, SyncLane); + var eventTime = requestEventTime(); + + if (root !== null) { + markRootUpdated(root, SyncLane, eventTime); + ensureRootIsScheduled(root, eventTime); + } +} + +function captureCommitPhaseError(sourceFiber, nearestMountedAncestor, error$1) { { - resolveFamily = handler; + reportUncaughtErrorInDEV(error$1); + setIsRunningInsertionEffect(false); } -}; -function resolveFunctionForHotReloading(type) { - { - if (resolveFamily === null) { - // Hot reloading is disabled. - return type; - } - var family = resolveFamily(type); + if (sourceFiber.tag === HostRoot) { + // Error was thrown at the root. There is no parent, so the root + // itself should capture it. + captureCommitPhaseErrorOnRoot(sourceFiber, sourceFiber, error$1); + return; + } - if (family === undefined) { - return type; - } // Use the latest known implementation. + var fiber = null; - return family.current; - } -} -function resolveClassForHotReloading(type) { - // No implementation differences. - return resolveFunctionForHotReloading(type); -} -function resolveForwardRefForHotReloading(type) { { - if (resolveFamily === null) { - // Hot reloading is disabled. - return type; - } + fiber = sourceFiber.return; + } - var family = resolveFamily(type); + while (fiber !== null) { + if (fiber.tag === HostRoot) { + captureCommitPhaseErrorOnRoot(fiber, sourceFiber, error$1); + return; + } else if (fiber.tag === ClassComponent) { + var ctor = fiber.type; + var instance = fiber.stateNode; - if (family === undefined) { - // Check if we're dealing with a real forwardRef. Don't want to crash early. if ( - type !== null && - type !== undefined && - typeof type.render === "function" + typeof ctor.getDerivedStateFromError === "function" || + (typeof instance.componentDidCatch === "function" && + !isAlreadyFailedLegacyErrorBoundary(instance)) ) { - // ForwardRef is special because its resolved .type is an object, - // but it's possible that we only have its inner render function in the map. - // If that inner render function is different, we'll build a new forwardRef type. - var currentRender = resolveFunctionForHotReloading(type.render); - - if (type.render !== currentRender) { - var syntheticType = { - $$typeof: REACT_FORWARD_REF_TYPE, - render: currentRender - }; - - if (type.displayName !== undefined) { - syntheticType.displayName = type.displayName; - } + var errorInfo = createCapturedValueAtFiber(error$1, sourceFiber); + var update = createClassErrorUpdate(fiber, errorInfo, SyncLane); + var root = enqueueUpdate(fiber, update, SyncLane); + var eventTime = requestEventTime(); - return syntheticType; + if (root !== null) { + markRootUpdated(root, SyncLane, eventTime); + ensureRootIsScheduled(root, eventTime); } + + return; } + } - return type; - } // Use the latest known implementation. + fiber = fiber.return; + } - return family.current; + { + // TODO: Until we re-land skipUnmountedBoundaries (see #20147), this warning + // will fire for errors that are thrown by destroy functions inside deleted + // trees. What it should instead do is propagate the error to the parent of + // the deleted tree. In the meantime, do not add this warning to the + // allowlist; this is only for our internal use. + error( + "Internal React error: Attempted to capture a commit phase error " + + "inside a detached tree. This indicates a bug in React. Likely " + + "causes include deleting the same fiber more than once, committing an " + + "already-finished tree, or an inconsistent return pointer.\n\n" + + "Error message:\n\n%s", + error$1 + ); } } -function isCompatibleFamilyForHotReloading(fiber, element) { - { - if (resolveFamily === null) { - // Hot reloading is disabled. - return false; - } - - var prevType = fiber.elementType; - var nextType = element.type; // If we got here, we know types aren't === equal. - - var needsCompareFamilies = false; - var $$typeofNextType = - typeof nextType === "object" && nextType !== null - ? nextType.$$typeof - : null; - - switch (fiber.tag) { - case ClassComponent: { - if (typeof nextType === "function") { - needsCompareFamilies = true; - } +function attachPingListener(root, wakeable, lanes) { + // Attach a ping listener + // + // The data might resolve before we have a chance to commit the fallback. Or, + // in the case of a refresh, we'll never commit a fallback. So we need to + // attach a listener now. When it resolves ("pings"), we can decide whether to + // try rendering the tree again. + // + // Only attach a listener if one does not already exist for the lanes + // we're currently rendering (which acts like a "thread ID" here). + // + // We only need to do this in concurrent mode. Legacy Suspense always + // commits fallbacks synchronously, so there are no pings. + var pingCache = root.pingCache; + var threadIDs; - break; - } + if (pingCache === null) { + pingCache = root.pingCache = new PossiblyWeakMap(); + threadIDs = new Set(); + pingCache.set(wakeable, threadIDs); + } else { + threadIDs = pingCache.get(wakeable); - case FunctionComponent: { - if (typeof nextType === "function") { - needsCompareFamilies = true; - } else if ($$typeofNextType === REACT_LAZY_TYPE) { - // We don't know the inner type yet. - // We're going to assume that the lazy inner type is stable, - // and so it is sufficient to avoid reconciling it away. - // We're not going to unwrap or actually use the new lazy type. - needsCompareFamilies = true; - } + if (threadIDs === undefined) { + threadIDs = new Set(); + pingCache.set(wakeable, threadIDs); + } + } - break; - } + if (!threadIDs.has(lanes)) { + workInProgressRootDidAttachPingListener = true; // Memoize using the thread ID to prevent redundant listeners. - case ForwardRef: { - if ($$typeofNextType === REACT_FORWARD_REF_TYPE) { - needsCompareFamilies = true; - } else if ($$typeofNextType === REACT_LAZY_TYPE) { - needsCompareFamilies = true; - } + threadIDs.add(lanes); + var ping = pingSuspendedRoot.bind(null, root, wakeable, lanes); - break; + { + if (isDevToolsPresent) { + // If we have pending work still, restore the original updaters + restorePendingUpdaters(root, lanes); } + } - case MemoComponent: - case SimpleMemoComponent: { - if ($$typeofNextType === REACT_MEMO_TYPE) { - // TODO: if it was but can no longer be simple, - // we shouldn't set this. - needsCompareFamilies = true; - } else if ($$typeofNextType === REACT_LAZY_TYPE) { - needsCompareFamilies = true; - } + wakeable.then(ping, ping); + } +} - break; - } +function pingSuspendedRoot(root, wakeable, pingedLanes) { + var pingCache = root.pingCache; - default: - return false; - } // Check if both types have a family and it's the same one. + if (pingCache !== null) { + // The wakeable resolved, so we no longer need to memoize, because it will + // never be thrown again. + pingCache.delete(wakeable); + } - if (needsCompareFamilies) { - // Note: memo() and forwardRef() we'll compare outer rather than inner type. - // This means both of them need to be registered to preserve state. - // If we unwrapped and compared the inner types for wrappers instead, - // then we would risk falsely saying two separate memo(Foo) - // calls are equivalent because they wrap the same Foo function. - var prevFamily = resolveFamily(prevType); // $FlowFixMe[not-a-function] found when upgrading Flow + var eventTime = requestEventTime(); + markRootPinged(root, pingedLanes); + warnIfSuspenseResolutionNotWrappedWithActDEV(root); - if (prevFamily !== undefined && prevFamily === resolveFamily(nextType)) { - return true; + if ( + workInProgressRoot === root && + isSubsetOfLanes(workInProgressRootRenderLanes, pingedLanes) + ) { + // Received a ping at the same priority level at which we're currently + // rendering. We might want to restart this render. This should mirror + // the logic of whether or not a root suspends once it completes. + // TODO: If we're rendering sync either due to Sync, Batched or expired, + // we should probably never restart. + // If we're suspended with delay, or if it's a retry, we'll always suspend + // so we can always restart. + if ( + workInProgressRootExitStatus === RootSuspendedWithDelay || + (workInProgressRootExitStatus === RootSuspended && + includesOnlyRetries(workInProgressRootRenderLanes) && + now$1() - globalMostRecentFallbackTime < FALLBACK_THROTTLE_MS) + ) { + // Force a restart from the root by unwinding the stack. Unless this is + // being called from the render phase, because that would cause a crash. + if ((executionContext & RenderContext) === NoContext) { + prepareFreshStack(root, NoLanes); } + } else { + // Even though we can't restart right now, we might get an + // opportunity later. So we mark this render as having a ping. + workInProgressRootPingedLanes = mergeLanes( + workInProgressRootPingedLanes, + pingedLanes + ); } - - return false; } + + ensureRootIsScheduled(root, eventTime); } -function markFailedErrorBoundaryForHotReloading(fiber) { - { - if (resolveFamily === null) { - // Hot reloading is disabled. - return; - } - if (typeof WeakSet !== "function") { - return; - } +function retryTimedOutBoundary(boundaryFiber, retryLane) { + // The boundary fiber (a Suspense component or SuspenseList component) + // previously was rendered in its fallback state. One of the promises that + // suspended it has resolved, which means at least part of the tree was + // likely unblocked. Try rendering again, at a new lanes. + if (retryLane === NoLane) { + // TODO: Assign this to `suspenseState.retryLane`? to avoid + // unnecessary entanglement? + retryLane = requestRetryLane(boundaryFiber); + } // TODO: Special case idle priority? - if (failedBoundaries === null) { - failedBoundaries = new WeakSet(); - } + var eventTime = requestEventTime(); + var root = enqueueConcurrentRenderForLane(boundaryFiber, retryLane); - failedBoundaries.add(fiber); + if (root !== null) { + markRootUpdated(root, retryLane, eventTime); + ensureRootIsScheduled(root, eventTime); } } -var scheduleRefresh = function (root, update) { - { - if (resolveFamily === null) { - // Hot reloading is disabled. - return; - } - var staleFamilies = update.staleFamilies, - updatedFamilies = update.updatedFamilies; - flushPassiveEffects(); - flushSync(function () { - scheduleFibersWithFamiliesRecursively( - root.current, - updatedFamilies, - staleFamilies - ); - }); - } -}; -var scheduleRoot = function (root, element) { - { - if (root.context !== emptyContextObject) { - // Super edge case: root has a legacy _renderSubtree context - // but we don't know the parentComponent so we can't pass it. - // Just ignore. We'll delete this with _renderSubtree code path later. - return; - } +function retryDehydratedSuspenseBoundary(boundaryFiber) { + var suspenseState = boundaryFiber.memoizedState; + var retryLane = NoLane; - flushPassiveEffects(); - flushSync(function () { - updateContainer(element, root, null, null); - }); + if (suspenseState !== null) { + retryLane = suspenseState.retryLane; } -}; -function scheduleFibersWithFamiliesRecursively( - fiber, - updatedFamilies, - staleFamilies -) { - { - var alternate = fiber.alternate, - child = fiber.child, - sibling = fiber.sibling, - tag = fiber.tag, - type = fiber.type; - var candidateType = null; + retryTimedOutBoundary(boundaryFiber, retryLane); +} +function resolveRetryWakeable(boundaryFiber, wakeable) { + var retryLane = NoLane; // Default - switch (tag) { - case FunctionComponent: - case SimpleMemoComponent: - case ClassComponent: - candidateType = type; - break; + var retryCache; - case ForwardRef: - candidateType = type.render; - break; - } + switch (boundaryFiber.tag) { + case SuspenseComponent: + retryCache = boundaryFiber.stateNode; + var suspenseState = boundaryFiber.memoizedState; - if (resolveFamily === null) { - throw new Error("Expected resolveFamily to be set during hot reload."); - } + if (suspenseState !== null) { + retryLane = suspenseState.retryLane; + } - var needsRender = false; - var needsRemount = false; + break; - if (candidateType !== null) { - var family = resolveFamily(candidateType); + case SuspenseListComponent: + retryCache = boundaryFiber.stateNode; + break; - if (family !== undefined) { - if (staleFamilies.has(family)) { - needsRemount = true; - } else if (updatedFamilies.has(family)) { - if (tag === ClassComponent) { - needsRemount = true; - } else { - needsRender = true; - } - } - } + case OffscreenComponent: { + var instance = boundaryFiber.stateNode; + retryCache = instance._retryCache; + break; } - if (failedBoundaries !== null) { - if ( - failedBoundaries.has(fiber) || // $FlowFixMe[incompatible-use] found when upgrading Flow - (alternate !== null && failedBoundaries.has(alternate)) - ) { - needsRemount = true; - } - } + default: + throw new Error( + "Pinged unknown suspense boundary type. " + + "This is probably a bug in React." + ); + } - if (needsRemount) { - fiber._debugNeedsRemount = true; - } + if (retryCache !== null) { + // The wakeable resolved, so we no longer need to memoize, because it will + // never be thrown again. + retryCache.delete(wakeable); + } - if (needsRemount || needsRender) { - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + retryTimedOutBoundary(boundaryFiber, retryLane); +} // Computes the next Just Noticeable Difference (JND) boundary. +// The theory is that a person can't tell the difference between small differences in time. +// Therefore, if we wait a bit longer than necessary that won't translate to a noticeable +// difference in the experience. However, waiting for longer might mean that we can avoid +// showing an intermediate loading state. The longer we have already waited, the harder it +// is to tell small differences in time. Therefore, the longer we've already waited, +// the longer we can wait additionally. At some point we have to give up though. +// We pick a train model where the next boundary commits at a consistent schedule. +// These particular numbers are vague estimates. We expect to adjust them based on research. - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); - } - } +function jnd(timeElapsed) { + return timeElapsed < 120 + ? 120 + : timeElapsed < 480 + ? 480 + : timeElapsed < 1080 + ? 1080 + : timeElapsed < 1920 + ? 1920 + : timeElapsed < 3000 + ? 3000 + : timeElapsed < 4320 + ? 4320 + : ceil(timeElapsed / 1960) * 1960; +} - if (child !== null && !needsRemount) { - scheduleFibersWithFamiliesRecursively( - child, - updatedFamilies, - staleFamilies - ); - } +function throwIfInfiniteUpdateLoopDetected() { + if (nestedUpdateCount > NESTED_UPDATE_LIMIT) { + nestedUpdateCount = 0; + nestedPassiveUpdateCount = 0; + rootWithNestedUpdates = null; + rootWithPassiveNestedUpdates = null; + throw new Error( + "Maximum update depth exceeded. This can happen when a component " + + "repeatedly calls setState inside componentWillUpdate or " + + "componentDidUpdate. React limits the number of nested updates to " + + "prevent infinite loops." + ); + } - if (sibling !== null) { - scheduleFibersWithFamiliesRecursively( - sibling, - updatedFamilies, - staleFamilies + { + if (nestedPassiveUpdateCount > NESTED_PASSIVE_UPDATE_LIMIT) { + nestedPassiveUpdateCount = 0; + rootWithPassiveNestedUpdates = null; + + error( + "Maximum update depth exceeded. This can happen when a component " + + "calls setState inside useEffect, but useEffect either doesn't " + + "have a dependency array, or one of the dependencies changes on " + + "every render." ); } } } -var findHostInstancesForRefresh = function (root, families) { +function flushRenderPhaseStrictModeWarningsInDEV() { { - var hostInstances = new Set(); - var types = new Set( - families.map(function (family) { - return family.current; - }) - ); - findHostInstancesForMatchingFibersRecursively( - root.current, - types, - hostInstances - ); - return hostInstances; + ReactStrictModeWarnings.flushLegacyContextWarning(); + ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings(); } -}; +} -function findHostInstancesForMatchingFibersRecursively( - fiber, - types, - hostInstances -) { +function commitDoubleInvokeEffectsInDEV(root, hasPassiveEffects) { { - var child = fiber.child, - sibling = fiber.sibling, - tag = fiber.tag, - type = fiber.type; - var candidateType = null; + { + legacyCommitDoubleInvokeEffectsInDEV(root.current, hasPassiveEffects); + } + } +} - switch (tag) { - case FunctionComponent: - case SimpleMemoComponent: - case ClassComponent: - candidateType = type; - break; +function legacyCommitDoubleInvokeEffectsInDEV(fiber, hasPassiveEffects) { + // TODO (StrictEffects) Should we set a marker on the root if it contains strict effects + // so we don't traverse unnecessarily? similar to subtreeFlags but just at the root level. + // Maybe not a big deal since this is DEV only behavior. + setCurrentFiber(fiber); + invokeEffectsInDev(fiber, MountLayoutDev, invokeLayoutEffectUnmountInDEV); - case ForwardRef: - candidateType = type.render; - break; - } + if (hasPassiveEffects) { + invokeEffectsInDev(fiber, MountPassiveDev, invokePassiveEffectUnmountInDEV); + } + + invokeEffectsInDev(fiber, MountLayoutDev, invokeLayoutEffectMountInDEV); + + if (hasPassiveEffects) { + invokeEffectsInDev(fiber, MountPassiveDev, invokePassiveEffectMountInDEV); + } - var didMatch = false; + resetCurrentFiber(); +} - if (candidateType !== null) { - if (types.has(candidateType)) { - didMatch = true; - } - } +function invokeEffectsInDev(firstChild, fiberFlags, invokeEffectFn) { + var current = firstChild; + var subtreeRoot = null; - if (didMatch) { - // We have a match. This only drills down to the closest host components. - // There's no need to search deeper because for the purpose of giving - // visual feedback, "flashing" outermost parent rectangles is sufficient. - findHostInstancesForFiberShallowly(fiber, hostInstances); + while (current != null) { + var primarySubtreeFlag = current.subtreeFlags & fiberFlags; + + if ( + current !== subtreeRoot && + current.child != null && + primarySubtreeFlag !== NoFlags$1 + ) { + current = current.child; } else { - // If there's no match, maybe there will be one further down in the child tree. - if (child !== null) { - findHostInstancesForMatchingFibersRecursively( - child, - types, - hostInstances - ); + if ((current.flags & fiberFlags) !== NoFlags$1) { + invokeEffectFn(current); } - } - if (sibling !== null) { - findHostInstancesForMatchingFibersRecursively( - sibling, - types, - hostInstances - ); + if (current.sibling !== null) { + current = current.sibling; + } else { + current = subtreeRoot = current.return; + } } } } -function findHostInstancesForFiberShallowly(fiber, hostInstances) { +var didWarnStateUpdateForNotYetMountedComponent = null; +function warnAboutUpdateOnNotYetMountedFiberInDEV(fiber) { { - var foundHostInstances = findChildHostInstancesForFiberShallowly( - fiber, - hostInstances - ); + if ((executionContext & RenderContext) !== NoContext) { + // We let the other warning about render phase updates deal with this one. + return; + } - if (foundHostInstances) { + if (!(fiber.mode & ConcurrentMode)) { return; - } // If we didn't find any host children, fallback to closest host parent. + } - var node = fiber; + var tag = fiber.tag; - while (true) { - switch (node.tag) { - case HostSingleton: - case HostComponent: - hostInstances.add(node.stateNode); - return; + if ( + tag !== IndeterminateComponent && + tag !== HostRoot && + tag !== ClassComponent && + tag !== FunctionComponent && + tag !== ForwardRef && + tag !== MemoComponent && + tag !== SimpleMemoComponent + ) { + // Only warn for user-defined components, not internal ones like Suspense. + return; + } // We show the whole stack but dedupe on the top component's name because + // the problematic code almost always lies inside that component. - case HostPortal: - hostInstances.add(node.stateNode.containerInfo); - return; + var componentName = getComponentNameFromFiber(fiber) || "ReactComponent"; - case HostRoot: - hostInstances.add(node.stateNode.containerInfo); - return; - } + if (didWarnStateUpdateForNotYetMountedComponent !== null) { + if (didWarnStateUpdateForNotYetMountedComponent.has(componentName)) { + return; + } // $FlowFixMe[incompatible-use] found when upgrading Flow - if (node.return === null) { - throw new Error("Expected to reach root first."); - } + didWarnStateUpdateForNotYetMountedComponent.add(componentName); + } else { + didWarnStateUpdateForNotYetMountedComponent = new Set([componentName]); + } - node = node.return; + var previousFiber = current; + + try { + setCurrentFiber(fiber); + + error( + "Can't perform a React state update on a component that hasn't mounted yet. " + + "This indicates that you have a side-effect in your render function that " + + "asynchronously later calls tries to update the component. Move this work to " + + "useEffect instead." + ); + } finally { + if (previousFiber) { + setCurrentFiber(fiber); + } else { + resetCurrentFiber(); + } } } } +var beginWork; -function findChildHostInstancesForFiberShallowly(fiber, hostInstances) { - { - var node = fiber; - var foundHostInstances = false; +{ + var dummyFiber = null; - while (true) { - if (node.tag === HostComponent || node.tag === HostHoistable || false) { - // We got a match. - foundHostInstances = true; - hostInstances.add(node.stateNode); // There may still be more, so keep searching. - } else if (node.child !== null) { - node.child.return = node; - node = node.child; - continue; - } + beginWork = function (current, unitOfWork, lanes) { + // If a component throws an error, we replay it again in a synchronously + // dispatched event, so that the debugger will treat it as an uncaught + // error See ReactErrorUtils for more information. + // Before entering the begin phase, copy the work-in-progress onto a dummy + // fiber. If beginWork throws, we'll use this to reset the state. + var originalWorkInProgressCopy = assignFiberPropertiesInDEV( + dummyFiber, + unitOfWork + ); - if (node === fiber) { - return foundHostInstances; - } + try { + return beginWork$1(current, unitOfWork, lanes); + } catch (originalError) { + if ( + didSuspendOrErrorWhileHydratingDEV() || + originalError === SuspenseException || + originalError === SelectiveHydrationException || + (originalError !== null && + typeof originalError === "object" && + typeof originalError.then === "function") + ) { + // Don't replay promises. + // Don't replay errors if we are hydrating and have already suspended or handled an error + throw originalError; + } // Don't reset current debug fiber, since we're about to work on the + // same fiber again. + // Unwind the failed stack frame - while (node.sibling === null) { - if (node.return === null || node.return === fiber) { - return foundHostInstances; - } + resetSuspendedWorkLoopOnUnwind(); + unwindInterruptedWork(current, unitOfWork); // Restore the original properties of the fiber. - node = node.return; - } + assignFiberPropertiesInDEV(unitOfWork, originalWorkInProgressCopy); - node.sibling.return = node.return; - node = node.sibling; - } - } + if (unitOfWork.mode & ProfileMode) { + // Reset the profiler timer. + startProfilerTimer(unitOfWork); + } // Run beginWork again. - return false; + invokeGuardedCallback( + null, + beginWork$1, + null, + current, + unitOfWork, + lanes + ); + + if (hasCaughtError()) { + var replayError = clearCaughtError(); + + if ( + typeof replayError === "object" && + replayError !== null && + replayError._suppressLogging && + typeof originalError === "object" && + originalError !== null && + !originalError._suppressLogging + ) { + // If suppressed, let the flag carry over to the original error which is the one we'll rethrow. + originalError._suppressLogging = true; + } + } // We always throw the original error in case the second render pass is not idempotent. + // This can happen if a memoized function or CommonJS module doesn't throw after first invocation. + + throw originalError; + } + }; } -var hasBadMapPolyfill; +var didWarnAboutUpdateInRender = false; +var didWarnAboutUpdateInRenderForAnotherComponent; { - hasBadMapPolyfill = false; + didWarnAboutUpdateInRenderForAnotherComponent = new Set(); +} - try { - var nonExtensibleObject = Object.preventExtensions({}); - /* eslint-disable no-new */ +function warnAboutRenderPhaseUpdatesInDEV(fiber) { + { + if (isRendering) { + switch (fiber.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: { + var renderingComponentName = + (workInProgress && getComponentNameFromFiber(workInProgress)) || + "Unknown"; // Dedupe by the rendering component because it's the one that needs to be fixed. - new Map([[nonExtensibleObject, null]]); - new Set([nonExtensibleObject]); - /* eslint-enable no-new */ - } catch (e) { - // TODO: Consider warning about bad polyfills - hasBadMapPolyfill = true; - } -} + var dedupeKey = renderingComponentName; -function FiberNode(tag, pendingProps, key, mode) { - // Instance - this.tag = tag; - this.key = key; - this.elementType = null; - this.type = null; - this.stateNode = null; // Fiber + if (!didWarnAboutUpdateInRenderForAnotherComponent.has(dedupeKey)) { + didWarnAboutUpdateInRenderForAnotherComponent.add(dedupeKey); + var setStateComponentName = + getComponentNameFromFiber(fiber) || "Unknown"; + + error( + "Cannot update a component (`%s`) while rendering a " + + "different component (`%s`). To locate the bad setState() call inside `%s`, " + + "follow the stack trace as described in https://reactjs.org/link/setstate-in-render", + setStateComponentName, + renderingComponentName, + renderingComponentName + ); + } - this.return = null; - this.child = null; - this.sibling = null; - this.index = 0; - this.ref = null; - this.refCleanup = null; - this.pendingProps = pendingProps; - this.memoizedProps = null; - this.updateQueue = null; - this.memoizedState = null; - this.dependencies = null; - this.mode = mode; // Effects + break; + } - this.flags = NoFlags$1; - this.subtreeFlags = NoFlags$1; - this.deletions = null; - this.lanes = NoLanes; - this.childLanes = NoLanes; - this.alternate = null; + case ClassComponent: { + if (!didWarnAboutUpdateInRender) { + error( + "Cannot update during an existing state transition (such as " + + "within `render`). Render methods should be a pure " + + "function of props and state." + ); - { - // Note: The following is done to avoid a v8 performance cliff. - // - // Initializing the fields below to smis and later updating them with - // double values will cause Fibers to end up having separate shapes. - // This behavior/bug has something to do with Object.preventExtension(). - // Fortunately this only impacts DEV builds. - // Unfortunately it makes React unusably slow for some applications. - // To work around this, initialize the fields below with doubles. - // - // Learn more about this here: - // https://github.com/facebook/react/issues/14365 - // https://bugs.chromium.org/p/v8/issues/detail?id=8538 - this.actualDuration = Number.NaN; - this.actualStartTime = Number.NaN; - this.selfBaseDuration = Number.NaN; - this.treeBaseDuration = Number.NaN; // It's okay to replace the initial doubles with smis after initialization. - // This won't trigger the performance cliff mentioned above, - // and it simplifies other profiler code (including DevTools). + didWarnAboutUpdateInRender = true; + } - this.actualDuration = 0; - this.actualStartTime = -1; - this.selfBaseDuration = 0; - this.treeBaseDuration = 0; + break; + } + } + } } +} +function restorePendingUpdaters(root, lanes) { { - // This isn't directly used but is handy for debugging internals: - this._debugSource = null; - this._debugOwner = null; - this._debugNeedsRemount = false; - this._debugHookTypes = null; - - if (!hasBadMapPolyfill && typeof Object.preventExtensions === "function") { - Object.preventExtensions(this); + if (isDevToolsPresent) { + var memoizedUpdaters = root.memoizedUpdaters; + memoizedUpdaters.forEach(function (schedulingFiber) { + addFiberToLanesMap(root, schedulingFiber, lanes); + }); // This function intentionally does not clear memoized updaters. + // Those may still be relevant to the current commit + // and a future one (e.g. Suspense). } } -} // This is a constructor function, rather than a POJO constructor, still -// please ensure we do the following: -// 1) Nobody should add any instance methods on this. Instance methods can be -// more difficult to predict when they get optimized and they are almost -// never inlined properly in static compilers. -// 2) Nobody should rely on `instanceof Fiber` for type testing. We should -// always know when it is a fiber. -// 3) We might want to experiment with using numeric keys since they are easier -// to optimize in a non-JIT environment. -// 4) We can easily go from a constructor to a createFiber object literal if that -// is faster. -// 5) It should be easy to port this to a C struct and keep a C implementation -// compatible. - -function createFiber(tag, pendingProps, key, mode) { - // $FlowFixMe: the shapes are exact here but Flow doesn't like constructors - return new FiberNode(tag, pendingProps, key, mode); } +var fakeActCallbackNode = {}; // $FlowFixMe[missing-local-annot] -function shouldConstruct(Component) { - var prototype = Component.prototype; - return !!(prototype && prototype.isReactComponent); -} +function scheduleCallback(priorityLevel, callback) { + { + // If we're currently inside an `act` scope, bypass Scheduler and push to + // the `act` queue instead. + var actQueue = ReactCurrentActQueue.current; -function isSimpleFunctionComponent(type) { - return ( - typeof type === "function" && - !shouldConstruct(type) && - type.defaultProps === undefined - ); + if (actQueue !== null) { + actQueue.push(callback); + return fakeActCallbackNode; + } else { + return scheduleCallback$1(priorityLevel, callback); + } + } } -function resolveLazyComponentTag(Component) { - if (typeof Component === "function") { - return shouldConstruct(Component) ? ClassComponent : FunctionComponent; - } else if (Component !== undefined && Component !== null) { - var $$typeof = Component.$$typeof; - if ($$typeof === REACT_FORWARD_REF_TYPE) { - return ForwardRef; - } +function cancelCallback(callbackNode) { + if (callbackNode === fakeActCallbackNode) { + return; + } // In production, always call Scheduler. This function will be stripped out. - if ($$typeof === REACT_MEMO_TYPE) { - return MemoComponent; - } - } + return cancelCallback$1(callbackNode); +} - return IndeterminateComponent; -} // This is used to create an alternate fiber to do work on. +function shouldForceFlushFallbacksInDEV() { + // Never force flush in production. This function should get stripped out. + return ReactCurrentActQueue.current !== null; +} -function createWorkInProgress(current, pendingProps) { - var workInProgress = current.alternate; +function warnIfUpdatesNotWrappedWithActDEV(fiber) { + { + if (fiber.mode & ConcurrentMode) { + if (!isConcurrentActEnvironment()) { + // Not in an act environment. No need to warn. + return; + } + } else { + // Legacy mode has additional cases where we suppress a warning. + if (!isLegacyActEnvironment()) { + // Not in an act environment. No need to warn. + return; + } - if (workInProgress === null) { - // We use a double buffering pooling technique because we know that we'll - // only ever need at most two versions of a tree. We pool the "other" unused - // node that we're free to reuse. This is lazily created to avoid allocating - // extra objects for things that are never updated. It also allow us to - // reclaim the extra memory if needed. - workInProgress = createFiber( - current.tag, - pendingProps, - current.key, - current.mode - ); - workInProgress.elementType = current.elementType; - workInProgress.type = current.type; - workInProgress.stateNode = current.stateNode; + if (executionContext !== NoContext) { + // Legacy mode doesn't warn if the update is batched, i.e. + // batchedUpdates or flushSync. + return; + } - { - // DEV-only fields - workInProgress._debugSource = current._debugSource; - workInProgress._debugOwner = current._debugOwner; - workInProgress._debugHookTypes = current._debugHookTypes; + if ( + fiber.tag !== FunctionComponent && + fiber.tag !== ForwardRef && + fiber.tag !== SimpleMemoComponent + ) { + // For backwards compatibility with pre-hooks code, legacy mode only + // warns for updates that originate from a hook. + return; + } } - workInProgress.alternate = current; - current.alternate = workInProgress; - } else { - workInProgress.pendingProps = pendingProps; // Needed because Blocks store data on type. - - workInProgress.type = current.type; // We already have an alternate. - // Reset the effect tag. + if (ReactCurrentActQueue.current === null) { + var previousFiber = current; - workInProgress.flags = NoFlags$1; // The effects are no longer valid. + try { + setCurrentFiber(fiber); - workInProgress.subtreeFlags = NoFlags$1; - workInProgress.deletions = null; + error( + "An update to %s inside a test was not wrapped in act(...).\n\n" + + "When testing, code that causes React state updates should be " + + "wrapped into act(...):\n\n" + + "act(() => {\n" + + " /* fire events that update state */\n" + + "});\n" + + "/* assert on the output */\n\n" + + "This ensures that you're testing the behavior the user would see " + + "in the browser." + + " Learn more at https://reactjs.org/link/wrap-tests-with-act", + getComponentNameFromFiber(fiber) + ); + } finally { + if (previousFiber) { + setCurrentFiber(fiber); + } else { + resetCurrentFiber(); + } + } + } + } +} - { - // We intentionally reset, rather than copy, actualDuration & actualStartTime. - // This prevents time from endlessly accumulating in new commits. - // This has the downside of resetting values for different priority renders, - // But works for yielding (the common case) and should support resuming. - workInProgress.actualDuration = 0; - workInProgress.actualStartTime = -1; +function warnIfSuspenseResolutionNotWrappedWithActDEV(root) { + { + if ( + root.tag !== LegacyRoot && + isConcurrentActEnvironment() && + ReactCurrentActQueue.current === null + ) { + error( + "A suspended resource finished loading inside a test, but the event " + + "was not wrapped in act(...).\n\n" + + "When testing, code that resolves suspended data should be wrapped " + + "into act(...):\n\n" + + "act(() => {\n" + + " /* finish loading suspended data */\n" + + "});\n" + + "/* assert on the output */\n\n" + + "This ensures that you're testing the behavior the user would see " + + "in the browser." + + " Learn more at https://reactjs.org/link/wrap-tests-with-act" + ); } - } // Reset all effects except static ones. - // Static effects are not specific to a render. - - workInProgress.flags = current.flags & StaticMask; - workInProgress.childLanes = current.childLanes; - workInProgress.lanes = current.lanes; - workInProgress.child = current.child; - workInProgress.memoizedProps = current.memoizedProps; - workInProgress.memoizedState = current.memoizedState; - workInProgress.updateQueue = current.updateQueue; // Clone the dependencies object. This is mutated during the render phase, so - // it cannot be shared with the current fiber. + } +} - var currentDependencies = current.dependencies; - workInProgress.dependencies = - currentDependencies === null - ? null - : { - lanes: currentDependencies.lanes, - firstContext: currentDependencies.firstContext - }; // These will be overridden during the parent's reconciliation +function setIsRunningInsertionEffect(isRunning) { + { + isRunningInsertionEffect = isRunning; + } +} - workInProgress.sibling = current.sibling; - workInProgress.index = current.index; - workInProgress.ref = current.ref; - workInProgress.refCleanup = current.refCleanup; +/* eslint-disable react-internal/prod-error-codes */ +// Used by React Refresh runtime through DevTools Global Hook. +var resolveFamily = null; +var failedBoundaries = null; +var setRefreshHandler = function (handler) { { - workInProgress.selfBaseDuration = current.selfBaseDuration; - workInProgress.treeBaseDuration = current.treeBaseDuration; + resolveFamily = handler; } - +}; +function resolveFunctionForHotReloading(type) { { - workInProgress._debugNeedsRemount = current._debugNeedsRemount; + if (resolveFamily === null) { + // Hot reloading is disabled. + return type; + } - switch (workInProgress.tag) { - case IndeterminateComponent: - case FunctionComponent: - case SimpleMemoComponent: - workInProgress.type = resolveFunctionForHotReloading(current.type); - break; + var family = resolveFamily(type); - case ClassComponent: - workInProgress.type = resolveClassForHotReloading(current.type); - break; + if (family === undefined) { + return type; + } // Use the latest known implementation. - case ForwardRef: - workInProgress.type = resolveForwardRefForHotReloading(current.type); - break; - } + return family.current; } +} +function resolveClassForHotReloading(type) { + // No implementation differences. + return resolveFunctionForHotReloading(type); +} +function resolveForwardRefForHotReloading(type) { + { + if (resolveFamily === null) { + // Hot reloading is disabled. + return type; + } - return workInProgress; -} // Used to reuse a Fiber for a second pass. - -function resetWorkInProgress(workInProgress, renderLanes) { - // This resets the Fiber to what createFiber or createWorkInProgress would - // have set the values to before during the first pass. Ideally this wouldn't - // be necessary but unfortunately many code paths reads from the workInProgress - // when they should be reading from current and writing to workInProgress. - // We assume pendingProps, index, key, ref, return are still untouched to - // avoid doing another reconciliation. - // Reset the effect flags but keep any Placement tags, since that's something - // that child fiber is setting, not the reconciliation. - workInProgress.flags &= StaticMask | Placement; // The effects are no longer valid. + var family = resolveFamily(type); - var current = workInProgress.alternate; + if (family === undefined) { + // Check if we're dealing with a real forwardRef. Don't want to crash early. + if ( + type !== null && + type !== undefined && + typeof type.render === "function" + ) { + // ForwardRef is special because its resolved .type is an object, + // but it's possible that we only have its inner render function in the map. + // If that inner render function is different, we'll build a new forwardRef type. + var currentRender = resolveFunctionForHotReloading(type.render); - if (current === null) { - // Reset to createFiber's initial values. - workInProgress.childLanes = NoLanes; - workInProgress.lanes = renderLanes; - workInProgress.child = null; - workInProgress.subtreeFlags = NoFlags$1; - workInProgress.memoizedProps = null; - workInProgress.memoizedState = null; - workInProgress.updateQueue = null; - workInProgress.dependencies = null; - workInProgress.stateNode = null; + if (type.render !== currentRender) { + var syntheticType = { + $$typeof: REACT_FORWARD_REF_TYPE, + render: currentRender + }; - { - // Note: We don't reset the actualTime counts. It's useful to accumulate - // actual time across multiple render passes. - workInProgress.selfBaseDuration = 0; - workInProgress.treeBaseDuration = 0; - } - } else { - // Reset to the cloned values that createWorkInProgress would've. - workInProgress.childLanes = current.childLanes; - workInProgress.lanes = current.lanes; - workInProgress.child = current.child; - workInProgress.subtreeFlags = NoFlags$1; - workInProgress.deletions = null; - workInProgress.memoizedProps = current.memoizedProps; - workInProgress.memoizedState = current.memoizedState; - workInProgress.updateQueue = current.updateQueue; // Needed because Blocks store data on type. + if (type.displayName !== undefined) { + syntheticType.displayName = type.displayName; + } - workInProgress.type = current.type; // Clone the dependencies object. This is mutated during the render phase, so - // it cannot be shared with the current fiber. + return syntheticType; + } + } - var currentDependencies = current.dependencies; - workInProgress.dependencies = - currentDependencies === null - ? null - : { - lanes: currentDependencies.lanes, - firstContext: currentDependencies.firstContext - }; + return type; + } // Use the latest known implementation. - { - // Note: We don't reset the actualTime counts. It's useful to accumulate - // actual time across multiple render passes. - workInProgress.selfBaseDuration = current.selfBaseDuration; - workInProgress.treeBaseDuration = current.treeBaseDuration; - } + return family.current; } - - return workInProgress; } -function createHostRootFiber( - tag, - isStrictMode, - concurrentUpdatesByDefaultOverride -) { - var mode; - - if (tag === ConcurrentRoot) { - mode = ConcurrentMode; - - if (isStrictMode === true || createRootStrictEffectsByDefault) { - mode |= StrictLegacyMode | StrictEffectsMode; +function isCompatibleFamilyForHotReloading(fiber, element) { + { + if (resolveFamily === null) { + // Hot reloading is disabled. + return false; } - if ( - // Only for internal experiments. - concurrentUpdatesByDefaultOverride - ) { - mode |= ConcurrentUpdatesByDefaultMode; - } - } else { - mode = NoMode; - } + var prevType = fiber.elementType; + var nextType = element.type; // If we got here, we know types aren't === equal. - if (isDevToolsPresent) { - // Always collect profile timings when DevTools are present. - // This enables DevTools to start capturing timing at any point– - // Without some nodes in the tree having empty base times. - mode |= ProfileMode; - } + var needsCompareFamilies = false; + var $$typeofNextType = + typeof nextType === "object" && nextType !== null + ? nextType.$$typeof + : null; - return createFiber(HostRoot, null, null, mode); -} -function createFiberFromTypeAndProps( - type, // React$ElementType - key, - pendingProps, - owner, - mode, - lanes -) { - var fiberTag = IndeterminateComponent; // The resolved type is set if we know what the final type will be. I.e. it's not lazy. + switch (fiber.tag) { + case ClassComponent: { + if (typeof nextType === "function") { + needsCompareFamilies = true; + } - var resolvedType = type; + break; + } - if (typeof type === "function") { - if (shouldConstruct(type)) { - fiberTag = ClassComponent; + case FunctionComponent: { + if (typeof nextType === "function") { + needsCompareFamilies = true; + } else if ($$typeofNextType === REACT_LAZY_TYPE) { + // We don't know the inner type yet. + // We're going to assume that the lazy inner type is stable, + // and so it is sufficient to avoid reconciling it away. + // We're not going to unwrap or actually use the new lazy type. + needsCompareFamilies = true; + } - { - resolvedType = resolveClassForHotReloading(resolvedType); - } - } else { - { - resolvedType = resolveFunctionForHotReloading(resolvedType); + break; } - } - } else if (typeof type === "string") { - { - fiberTag = HostComponent; - } - } else { - getTag: switch (type) { - case REACT_FRAGMENT_TYPE: - return createFiberFromFragment(pendingProps.children, mode, lanes, key); - - case REACT_STRICT_MODE_TYPE: - fiberTag = Mode; - mode |= StrictLegacyMode; - if ((mode & ConcurrentMode) !== NoMode) { - // Strict effects should never run on legacy roots - mode |= StrictEffectsMode; + case ForwardRef: { + if ($$typeofNextType === REACT_FORWARD_REF_TYPE) { + needsCompareFamilies = true; + } else if ($$typeofNextType === REACT_LAZY_TYPE) { + needsCompareFamilies = true; } break; + } - case REACT_PROFILER_TYPE: - return createFiberFromProfiler(pendingProps, mode, lanes, key); + case MemoComponent: + case SimpleMemoComponent: { + if ($$typeofNextType === REACT_MEMO_TYPE) { + // TODO: if it was but can no longer be simple, + // we shouldn't set this. + needsCompareFamilies = true; + } else if ($$typeofNextType === REACT_LAZY_TYPE) { + needsCompareFamilies = true; + } - case REACT_SUSPENSE_TYPE: - return createFiberFromSuspense(pendingProps, mode, lanes, key); + break; + } - case REACT_SUSPENSE_LIST_TYPE: - return createFiberFromSuspenseList(pendingProps, mode, lanes, key); + default: + return false; + } // Check if both types have a family and it's the same one. - case REACT_OFFSCREEN_TYPE: - return createFiberFromOffscreen(pendingProps, mode, lanes, key); + if (needsCompareFamilies) { + // Note: memo() and forwardRef() we'll compare outer rather than inner type. + // This means both of them need to be registered to preserve state. + // If we unwrapped and compared the inner types for wrappers instead, + // then we would risk falsely saying two separate memo(Foo) + // calls are equivalent because they wrap the same Foo function. + var prevFamily = resolveFamily(prevType); // $FlowFixMe[not-a-function] found when upgrading Flow - case REACT_LEGACY_HIDDEN_TYPE: { - return createFiberFromLegacyHidden(pendingProps, mode, lanes, key); + if (prevFamily !== undefined && prevFamily === resolveFamily(nextType)) { + return true; } + } - // eslint-disable-next-line no-fallthrough + return false; + } +} +function markFailedErrorBoundaryForHotReloading(fiber) { + { + if (resolveFamily === null) { + // Hot reloading is disabled. + return; + } - case REACT_SCOPE_TYPE: + if (typeof WeakSet !== "function") { + return; + } - // eslint-disable-next-line no-fallthrough + if (failedBoundaries === null) { + failedBoundaries = new WeakSet(); + } - case REACT_CACHE_TYPE: + failedBoundaries.add(fiber); + } +} +var scheduleRefresh = function (root, update) { + { + if (resolveFamily === null) { + // Hot reloading is disabled. + return; + } - // eslint-disable-next-line no-fallthrough + var staleFamilies = update.staleFamilies, + updatedFamilies = update.updatedFamilies; + flushPassiveEffects(); + flushSync(function () { + scheduleFibersWithFamiliesRecursively( + root.current, + updatedFamilies, + staleFamilies + ); + }); + } +}; +var scheduleRoot = function (root, element) { + { + if (root.context !== emptyContextObject) { + // Super edge case: root has a legacy _renderSubtree context + // but we don't know the parentComponent so we can't pass it. + // Just ignore. We'll delete this with _renderSubtree code path later. + return; + } - case REACT_TRACING_MARKER_TYPE: + flushPassiveEffects(); + flushSync(function () { + updateContainer(element, root, null, null); + }); + } +}; - // eslint-disable-next-line no-fallthrough +function scheduleFibersWithFamiliesRecursively( + fiber, + updatedFamilies, + staleFamilies +) { + { + var alternate = fiber.alternate, + child = fiber.child, + sibling = fiber.sibling, + tag = fiber.tag, + type = fiber.type; + var candidateType = null; - case REACT_DEBUG_TRACING_MODE_TYPE: + switch (tag) { + case FunctionComponent: + case SimpleMemoComponent: + case ClassComponent: + candidateType = type; + break; - // eslint-disable-next-line no-fallthrough + case ForwardRef: + candidateType = type.render; + break; + } - default: { - if (typeof type === "object" && type !== null) { - switch (type.$$typeof) { - case REACT_PROVIDER_TYPE: - fiberTag = ContextProvider; - break getTag; + if (resolveFamily === null) { + throw new Error("Expected resolveFamily to be set during hot reload."); + } - case REACT_CONTEXT_TYPE: - // This is a consumer - fiberTag = ContextConsumer; - break getTag; + var needsRender = false; + var needsRemount = false; - case REACT_FORWARD_REF_TYPE: - fiberTag = ForwardRef; + if (candidateType !== null) { + var family = resolveFamily(candidateType); - { - resolvedType = resolveForwardRefForHotReloading(resolvedType); - } + if (family !== undefined) { + if (staleFamilies.has(family)) { + needsRemount = true; + } else if (updatedFamilies.has(family)) { + if (tag === ClassComponent) { + needsRemount = true; + } else { + needsRender = true; + } + } + } + } - break getTag; + if (failedBoundaries !== null) { + if ( + failedBoundaries.has(fiber) || // $FlowFixMe[incompatible-use] found when upgrading Flow + (alternate !== null && failedBoundaries.has(alternate)) + ) { + needsRemount = true; + } + } - case REACT_MEMO_TYPE: - fiberTag = MemoComponent; - break getTag; + if (needsRemount) { + fiber._debugNeedsRemount = true; + } - case REACT_LAZY_TYPE: - fiberTag = LazyComponent; - resolvedType = null; - break getTag; - } - } + if (needsRemount || needsRender) { + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - var info = ""; + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); + } + } - { - if ( - type === undefined || - (typeof type === "object" && - type !== null && - Object.keys(type).length === 0) - ) { - info += - " You likely forgot to export your component from the file " + - "it's defined in, or you might have mixed up default and " + - "named imports."; - } + if (child !== null && !needsRemount) { + scheduleFibersWithFamiliesRecursively( + child, + updatedFamilies, + staleFamilies + ); + } - var ownerName = owner ? getComponentNameFromFiber(owner) : null; + if (sibling !== null) { + scheduleFibersWithFamiliesRecursively( + sibling, + updatedFamilies, + staleFamilies + ); + } + } +} - if (ownerName) { - info += "\n\nCheck the render method of `" + ownerName + "`."; - } - } +var findHostInstancesForRefresh = function (root, families) { + { + var hostInstances = new Set(); + var types = new Set( + families.map(function (family) { + return family.current; + }) + ); + findHostInstancesForMatchingFibersRecursively( + root.current, + types, + hostInstances + ); + return hostInstances; + } +}; + +function findHostInstancesForMatchingFibersRecursively( + fiber, + types, + hostInstances +) { + { + var child = fiber.child, + sibling = fiber.sibling, + tag = fiber.tag, + type = fiber.type; + var candidateType = null; + + switch (tag) { + case FunctionComponent: + case SimpleMemoComponent: + case ClassComponent: + candidateType = type; + break; + + case ForwardRef: + candidateType = type.render; + break; + } + + var didMatch = false; - throw new Error( - "Element type is invalid: expected a string (for built-in " + - "components) or a class/function (for composite components) " + - ("but got: " + (type == null ? type : typeof type) + "." + info) - ); + if (candidateType !== null) { + if (types.has(candidateType)) { + didMatch = true; } } - } - var fiber = createFiber(fiberTag, pendingProps, key, mode); - fiber.elementType = type; - fiber.type = resolvedType; - fiber.lanes = lanes; + if (didMatch) { + // We have a match. This only drills down to the closest host components. + // There's no need to search deeper because for the purpose of giving + // visual feedback, "flashing" outermost parent rectangles is sufficient. + findHostInstancesForFiberShallowly(fiber, hostInstances); + } else { + // If there's no match, maybe there will be one further down in the child tree. + if (child !== null) { + findHostInstancesForMatchingFibersRecursively( + child, + types, + hostInstances + ); + } + } - { - fiber._debugOwner = owner; + if (sibling !== null) { + findHostInstancesForMatchingFibersRecursively( + sibling, + types, + hostInstances + ); + } } - - return fiber; } -function createFiberFromElement(element, mode, lanes) { - var owner = null; +function findHostInstancesForFiberShallowly(fiber, hostInstances) { { - owner = element._owner; - } + var foundHostInstances = findChildHostInstancesForFiberShallowly( + fiber, + hostInstances + ); - var type = element.type; - var key = element.key; - var pendingProps = element.props; - var fiber = createFiberFromTypeAndProps( - type, - key, - pendingProps, - owner, - mode, - lanes - ); + if (foundHostInstances) { + return; + } // If we didn't find any host children, fallback to closest host parent. - { - fiber._debugSource = element._source; - fiber._debugOwner = element._owner; - } + var node = fiber; - return fiber; -} -function createFiberFromFragment(elements, mode, lanes, key) { - var fiber = createFiber(Fragment, elements, key, mode); - fiber.lanes = lanes; - return fiber; -} + while (true) { + switch (node.tag) { + case HostSingleton: + case HostComponent: + hostInstances.add(node.stateNode); + return; -function createFiberFromProfiler(pendingProps, mode, lanes, key) { - { - if (typeof pendingProps.id !== "string") { - error( - 'Profiler must specify an "id" of type `string` as a prop. Received the type `%s` instead.', - typeof pendingProps.id - ); + case HostPortal: + hostInstances.add(node.stateNode.containerInfo); + return; + + case HostRoot: + hostInstances.add(node.stateNode.containerInfo); + return; + } + + if (node.return === null) { + throw new Error("Expected to reach root first."); + } + + node = node.return; } } +} - var fiber = createFiber(Profiler, pendingProps, key, mode | ProfileMode); - fiber.elementType = REACT_PROFILER_TYPE; - fiber.lanes = lanes; - +function findChildHostInstancesForFiberShallowly(fiber, hostInstances) { { - fiber.stateNode = { - effectDuration: 0, - passiveEffectDuration: 0 - }; - } + var node = fiber; + var foundHostInstances = false; - return fiber; -} + while (true) { + if (node.tag === HostComponent || node.tag === HostHoistable || false) { + // We got a match. + foundHostInstances = true; + hostInstances.add(node.stateNode); // There may still be more, so keep searching. + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } -function createFiberFromSuspense(pendingProps, mode, lanes, key) { - var fiber = createFiber(SuspenseComponent, pendingProps, key, mode); - fiber.elementType = REACT_SUSPENSE_TYPE; - fiber.lanes = lanes; - return fiber; -} -function createFiberFromSuspenseList(pendingProps, mode, lanes, key) { - var fiber = createFiber(SuspenseListComponent, pendingProps, key, mode); - fiber.elementType = REACT_SUSPENSE_LIST_TYPE; - fiber.lanes = lanes; - return fiber; -} -function createFiberFromOffscreen(pendingProps, mode, lanes, key) { - var fiber = createFiber(OffscreenComponent, pendingProps, key, mode); - fiber.elementType = REACT_OFFSCREEN_TYPE; - fiber.lanes = lanes; - var primaryChildInstance = { - _visibility: OffscreenVisible, - _pendingVisibility: OffscreenVisible, - _pendingMarkers: null, - _retryCache: null, - _transitions: null, - _current: null, - detach: function () { - return detachOffscreenInstance(primaryChildInstance); - }, - attach: function () { - return attachOffscreenInstance(primaryChildInstance); - } - }; - fiber.stateNode = primaryChildInstance; - return fiber; -} -function createFiberFromLegacyHidden(pendingProps, mode, lanes, key) { - var fiber = createFiber(LegacyHiddenComponent, pendingProps, key, mode); - fiber.elementType = REACT_LEGACY_HIDDEN_TYPE; - fiber.lanes = lanes; // Adding a stateNode for legacy hidden because it's currently using - // the offscreen implementation, which depends on a state node + if (node === fiber) { + return foundHostInstances; + } - var instance = { - _visibility: OffscreenVisible, - _pendingVisibility: OffscreenVisible, - _pendingMarkers: null, - _transitions: null, - _retryCache: null, - _current: null, - detach: function () { - return detachOffscreenInstance(instance); - }, - attach: function () { - return attachOffscreenInstance(instance); + while (node.sibling === null) { + if (node.return === null || node.return === fiber) { + return foundHostInstances; + } + + node = node.return; + } + + node.sibling.return = node.return; + node = node.sibling; } - }; - fiber.stateNode = instance; - return fiber; -} -function createFiberFromText(content, mode, lanes) { - var fiber = createFiber(HostText, content, null, mode); - fiber.lanes = lanes; - return fiber; + } + + return false; } -function createFiberFromPortal(portal, mode, lanes) { - var pendingProps = portal.children !== null ? portal.children : []; - var fiber = createFiber(HostPortal, pendingProps, portal.key, mode); - fiber.lanes = lanes; - fiber.stateNode = { - containerInfo: portal.containerInfo, - pendingChildren: null, - // Used by persistent updates - implementation: portal.implementation - }; - return fiber; -} // Used for stashing WIP properties to replay failed work in DEV. -function assignFiberPropertiesInDEV(target, source) { - if (target === null) { - // This Fiber's initial properties will always be overwritten. - // We only use a Fiber to ensure the same hidden class so DEV isn't slow. - target = createFiber(IndeterminateComponent, null, null, NoMode); - } // This is intentionally written as a list of all properties. - // We tried to use Object.assign() instead but this is called in - // the hottest path, and Object.assign() was too slow: - // https://github.com/facebook/react/issues/12502 - // This code is DEV-only so size is not a concern. +var hasBadMapPolyfill; - target.tag = source.tag; - target.key = source.key; - target.elementType = source.elementType; - target.type = source.type; - target.stateNode = source.stateNode; - target.return = source.return; - target.child = source.child; - target.sibling = source.sibling; - target.index = source.index; - target.ref = source.ref; - target.refCleanup = source.refCleanup; - target.pendingProps = source.pendingProps; - target.memoizedProps = source.memoizedProps; - target.updateQueue = source.updateQueue; - target.memoizedState = source.memoizedState; - target.dependencies = source.dependencies; - target.mode = source.mode; - target.flags = source.flags; - target.subtreeFlags = source.subtreeFlags; - target.deletions = source.deletions; - target.lanes = source.lanes; - target.childLanes = source.childLanes; - target.alternate = source.alternate; +{ + hasBadMapPolyfill = false; - { - target.actualDuration = source.actualDuration; - target.actualStartTime = source.actualStartTime; - target.selfBaseDuration = source.selfBaseDuration; - target.treeBaseDuration = source.treeBaseDuration; - } + try { + var nonExtensibleObject = Object.preventExtensions({}); + /* eslint-disable no-new */ - target._debugSource = source._debugSource; - target._debugOwner = source._debugOwner; - target._debugNeedsRemount = source._debugNeedsRemount; - target._debugHookTypes = source._debugHookTypes; - return target; + new Map([[nonExtensibleObject, null]]); + new Set([nonExtensibleObject]); + /* eslint-enable no-new */ + } catch (e) { + // TODO: Consider warning about bad polyfills + hasBadMapPolyfill = true; + } } -function FiberRootNode( - containerInfo, // $FlowFixMe[missing-local-annot] - tag, - hydrate, - identifierPrefix, - onRecoverableError -) { +function FiberNode(tag, pendingProps, key, mode) { + // Instance this.tag = tag; - this.containerInfo = containerInfo; - this.pendingChildren = null; - this.current = null; - this.pingCache = null; - this.finishedWork = null; - this.timeoutHandle = noTimeout; - this.cancelPendingCommit = null; - this.context = null; - this.pendingContext = null; - this.callbackNode = null; - this.callbackPriority = NoLane; - this.eventTimes = createLaneMap(NoLanes); - this.expirationTimes = createLaneMap(NoTimestamp); - this.pendingLanes = NoLanes; - this.suspendedLanes = NoLanes; - this.pingedLanes = NoLanes; - this.expiredLanes = NoLanes; - this.mutableReadLanes = NoLanes; - this.finishedLanes = NoLanes; - this.errorRecoveryDisabledLanes = NoLanes; - this.entangledLanes = NoLanes; - this.entanglements = createLaneMap(NoLanes); - this.hiddenUpdates = createLaneMap(null); - this.identifierPrefix = identifierPrefix; - this.onRecoverableError = onRecoverableError; + this.key = key; + this.elementType = null; + this.type = null; + this.stateNode = null; // Fiber - this.incompleteTransitions = new Map(); + this.return = null; + this.child = null; + this.sibling = null; + this.index = 0; + this.ref = null; + this.refCleanup = null; + this.pendingProps = pendingProps; + this.memoizedProps = null; + this.updateQueue = null; + this.memoizedState = null; + this.dependencies = null; + this.mode = mode; // Effects - { - this.effectDuration = 0; - this.passiveEffectDuration = 0; - } + this.flags = NoFlags$1; + this.subtreeFlags = NoFlags$1; + this.deletions = null; + this.lanes = NoLanes; + this.childLanes = NoLanes; + this.alternate = null; { - this.memoizedUpdaters = new Set(); - var pendingUpdatersLaneMap = (this.pendingUpdatersLaneMap = []); + // Note: The following is done to avoid a v8 performance cliff. + // + // Initializing the fields below to smis and later updating them with + // double values will cause Fibers to end up having separate shapes. + // This behavior/bug has something to do with Object.preventExtension(). + // Fortunately this only impacts DEV builds. + // Unfortunately it makes React unusably slow for some applications. + // To work around this, initialize the fields below with doubles. + // + // Learn more about this here: + // https://github.com/facebook/react/issues/14365 + // https://bugs.chromium.org/p/v8/issues/detail?id=8538 + this.actualDuration = Number.NaN; + this.actualStartTime = Number.NaN; + this.selfBaseDuration = Number.NaN; + this.treeBaseDuration = Number.NaN; // It's okay to replace the initial doubles with smis after initialization. + // This won't trigger the performance cliff mentioned above, + // and it simplifies other profiler code (including DevTools). - for (var _i = 0; _i < TotalLanes; _i++) { - pendingUpdatersLaneMap.push(new Set()); - } + this.actualDuration = 0; + this.actualStartTime = -1; + this.selfBaseDuration = 0; + this.treeBaseDuration = 0; } { - switch (tag) { - case ConcurrentRoot: - this._debugRootType = hydrate ? "hydrateRoot()" : "createRoot()"; - break; + // This isn't directly used but is handy for debugging internals: + this._debugSource = null; + this._debugOwner = null; + this._debugNeedsRemount = false; + this._debugHookTypes = null; - case LegacyRoot: - this._debugRootType = hydrate ? "hydrate()" : "render()"; - break; + if (!hasBadMapPolyfill && typeof Object.preventExtensions === "function") { + Object.preventExtensions(this); } } +} // This is a constructor function, rather than a POJO constructor, still +// please ensure we do the following: +// 1) Nobody should add any instance methods on this. Instance methods can be +// more difficult to predict when they get optimized and they are almost +// never inlined properly in static compilers. +// 2) Nobody should rely on `instanceof Fiber` for type testing. We should +// always know when it is a fiber. +// 3) We might want to experiment with using numeric keys since they are easier +// to optimize in a non-JIT environment. +// 4) We can easily go from a constructor to a createFiber object literal if that +// is faster. +// 5) It should be easy to port this to a C struct and keep a C implementation +// compatible. + +function createFiber(tag, pendingProps, key, mode) { + // $FlowFixMe: the shapes are exact here but Flow doesn't like constructors + return new FiberNode(tag, pendingProps, key, mode); } -function createFiberRoot( - containerInfo, - tag, - hydrate, - initialChildren, - hydrationCallbacks, - isStrictMode, - concurrentUpdatesByDefaultOverride, // TODO: We have several of these arguments that are conceptually part of the - // host config, but because they are passed in at runtime, we have to thread - // them through the root constructor. Perhaps we should put them all into a - // single type, like a DynamicHostConfig that is defined by the renderer. - identifierPrefix, - onRecoverableError, - transitionCallbacks -) { - // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions - var root = new FiberRootNode( - containerInfo, - tag, - hydrate, - identifierPrefix, - onRecoverableError - ); - // stateNode is any. +function shouldConstruct(Component) { + var prototype = Component.prototype; + return !!(prototype && prototype.isReactComponent); +} - var uninitializedFiber = createHostRootFiber( - tag, - isStrictMode, - concurrentUpdatesByDefaultOverride +function isSimpleFunctionComponent(type) { + return ( + typeof type === "function" && + !shouldConstruct(type) && + type.defaultProps === undefined ); - root.current = uninitializedFiber; - uninitializedFiber.stateNode = root; +} +function resolveLazyComponentTag(Component) { + if (typeof Component === "function") { + return shouldConstruct(Component) ? ClassComponent : FunctionComponent; + } else if (Component !== undefined && Component !== null) { + var $$typeof = Component.$$typeof; - { - var _initialState = { - element: initialChildren, - isDehydrated: hydrate, - cache: null // not enabled yet - }; - uninitializedFiber.memoizedState = _initialState; + if ($$typeof === REACT_FORWARD_REF_TYPE) { + return ForwardRef; + } + + if ($$typeof === REACT_MEMO_TYPE) { + return MemoComponent; + } } - initializeUpdateQueue(uninitializedFiber); - return root; -} + return IndeterminateComponent; +} // This is used to create an alternate fiber to do work on. -var ReactVersion = "18.3.0-next-f77099b6f-20230322"; +function createWorkInProgress(current, pendingProps) { + var workInProgress = current.alternate; -function createPortal$1( - children, - containerInfo, // TODO: figure out the API for cross-renderer implementation. - implementation -) { - var key = - arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; + if (workInProgress === null) { + // We use a double buffering pooling technique because we know that we'll + // only ever need at most two versions of a tree. We pool the "other" unused + // node that we're free to reuse. This is lazily created to avoid allocating + // extra objects for things that are never updated. It also allow us to + // reclaim the extra memory if needed. + workInProgress = createFiber( + current.tag, + pendingProps, + current.key, + current.mode + ); + workInProgress.elementType = current.elementType; + workInProgress.type = current.type; + workInProgress.stateNode = current.stateNode; - { - checkKeyStringCoercion(key); - } + { + // DEV-only fields + workInProgress._debugSource = current._debugSource; + workInProgress._debugOwner = current._debugOwner; + workInProgress._debugHookTypes = current._debugHookTypes; + } - return { - // This tag allow us to uniquely identify this as a React Portal - $$typeof: REACT_PORTAL_TYPE, - key: key == null ? null : "" + key, - children: children, - containerInfo: containerInfo, - implementation: implementation - }; -} + workInProgress.alternate = current; + current.alternate = workInProgress; + } else { + workInProgress.pendingProps = pendingProps; // Needed because Blocks store data on type. + + workInProgress.type = current.type; // We already have an alternate. + // Reset the effect tag. + + workInProgress.flags = NoFlags$1; // The effects are no longer valid. + + workInProgress.subtreeFlags = NoFlags$1; + workInProgress.deletions = null; + + { + // We intentionally reset, rather than copy, actualDuration & actualStartTime. + // This prevents time from endlessly accumulating in new commits. + // This has the downside of resetting values for different priority renders, + // But works for yielding (the common case) and should support resuming. + workInProgress.actualDuration = 0; + workInProgress.actualStartTime = -1; + } + } // Reset all effects except static ones. + // Static effects are not specific to a render. -// Might add PROFILE later. + workInProgress.flags = current.flags & StaticMask; + workInProgress.childLanes = current.childLanes; + workInProgress.lanes = current.lanes; + workInProgress.child = current.child; + workInProgress.memoizedProps = current.memoizedProps; + workInProgress.memoizedState = current.memoizedState; + workInProgress.updateQueue = current.updateQueue; // Clone the dependencies object. This is mutated during the render phase, so + // it cannot be shared with the current fiber. -var didWarnAboutNestedUpdates; -var didWarnAboutFindNodeInStrictMode; + var currentDependencies = current.dependencies; + workInProgress.dependencies = + currentDependencies === null + ? null + : { + lanes: currentDependencies.lanes, + firstContext: currentDependencies.firstContext + }; // These will be overridden during the parent's reconciliation -{ - didWarnAboutNestedUpdates = false; - didWarnAboutFindNodeInStrictMode = {}; -} + workInProgress.sibling = current.sibling; + workInProgress.index = current.index; + workInProgress.ref = current.ref; + workInProgress.refCleanup = current.refCleanup; -function getContextForSubtree(parentComponent) { - if (!parentComponent) { - return emptyContextObject; + { + workInProgress.selfBaseDuration = current.selfBaseDuration; + workInProgress.treeBaseDuration = current.treeBaseDuration; } - var fiber = get(parentComponent); - var parentContext = findCurrentUnmaskedContext(fiber); + { + workInProgress._debugNeedsRemount = current._debugNeedsRemount; - if (fiber.tag === ClassComponent) { - var Component = fiber.type; + switch (workInProgress.tag) { + case IndeterminateComponent: + case FunctionComponent: + case SimpleMemoComponent: + workInProgress.type = resolveFunctionForHotReloading(current.type); + break; - if (isContextProvider(Component)) { - return processChildContext(fiber, Component, parentContext); + case ClassComponent: + workInProgress.type = resolveClassForHotReloading(current.type); + break; + + case ForwardRef: + workInProgress.type = resolveForwardRefForHotReloading(current.type); + break; } } - return parentContext; -} + return workInProgress; +} // Used to reuse a Fiber for a second pass. -function findHostInstanceWithWarning(component, methodName) { - { - var fiber = get(component); +function resetWorkInProgress(workInProgress, renderLanes) { + // This resets the Fiber to what createFiber or createWorkInProgress would + // have set the values to before during the first pass. Ideally this wouldn't + // be necessary but unfortunately many code paths reads from the workInProgress + // when they should be reading from current and writing to workInProgress. + // We assume pendingProps, index, key, ref, return are still untouched to + // avoid doing another reconciliation. + // Reset the effect flags but keep any Placement tags, since that's something + // that child fiber is setting, not the reconciliation. + workInProgress.flags &= StaticMask | Placement; // The effects are no longer valid. - if (fiber === undefined) { - if (typeof component.render === "function") { - throw new Error("Unable to find node on an unmounted component."); - } else { - var keys = Object.keys(component).join(","); - throw new Error( - "Argument appears to not be a ReactComponent. Keys: " + keys - ); - } - } + var current = workInProgress.alternate; - var hostFiber = findCurrentHostFiber(fiber); + if (current === null) { + // Reset to createFiber's initial values. + workInProgress.childLanes = NoLanes; + workInProgress.lanes = renderLanes; + workInProgress.child = null; + workInProgress.subtreeFlags = NoFlags$1; + workInProgress.memoizedProps = null; + workInProgress.memoizedState = null; + workInProgress.updateQueue = null; + workInProgress.dependencies = null; + workInProgress.stateNode = null; - if (hostFiber === null) { - return null; + { + // Note: We don't reset the actualTime counts. It's useful to accumulate + // actual time across multiple render passes. + workInProgress.selfBaseDuration = 0; + workInProgress.treeBaseDuration = 0; } + } else { + // Reset to the cloned values that createWorkInProgress would've. + workInProgress.childLanes = current.childLanes; + workInProgress.lanes = current.lanes; + workInProgress.child = current.child; + workInProgress.subtreeFlags = NoFlags$1; + workInProgress.deletions = null; + workInProgress.memoizedProps = current.memoizedProps; + workInProgress.memoizedState = current.memoizedState; + workInProgress.updateQueue = current.updateQueue; // Needed because Blocks store data on type. - if (hostFiber.mode & StrictLegacyMode) { - var componentName = getComponentNameFromFiber(fiber) || "Component"; - - if (!didWarnAboutFindNodeInStrictMode[componentName]) { - didWarnAboutFindNodeInStrictMode[componentName] = true; - var previousFiber = current; + workInProgress.type = current.type; // Clone the dependencies object. This is mutated during the render phase, so + // it cannot be shared with the current fiber. - try { - setCurrentFiber(hostFiber); + var currentDependencies = current.dependencies; + workInProgress.dependencies = + currentDependencies === null + ? null + : { + lanes: currentDependencies.lanes, + firstContext: currentDependencies.firstContext + }; - if (fiber.mode & StrictLegacyMode) { - error( - "%s is deprecated in StrictMode. " + - "%s was passed an instance of %s which is inside StrictMode. " + - "Instead, add a ref directly to the element you want to reference. " + - "Learn more about using refs safely here: " + - "https://reactjs.org/link/strict-mode-find-node", - methodName, - methodName, - componentName - ); - } else { - error( - "%s is deprecated in StrictMode. " + - "%s was passed an instance of %s which renders StrictMode children. " + - "Instead, add a ref directly to the element you want to reference. " + - "Learn more about using refs safely here: " + - "https://reactjs.org/link/strict-mode-find-node", - methodName, - methodName, - componentName - ); - } - } finally { - // Ideally this should reset to previous but this shouldn't be called in - // render and there's another warning for that anyway. - if (previousFiber) { - setCurrentFiber(previousFiber); - } else { - resetCurrentFiber(); - } - } - } + { + // Note: We don't reset the actualTime counts. It's useful to accumulate + // actual time across multiple render passes. + workInProgress.selfBaseDuration = current.selfBaseDuration; + workInProgress.treeBaseDuration = current.treeBaseDuration; } - - return getPublicInstance(hostFiber.stateNode); } -} -function createContainer( - containerInfo, + return workInProgress; +} +function createHostRootFiber( tag, - hydrationCallbacks, isStrictMode, - concurrentUpdatesByDefaultOverride, - identifierPrefix, - onRecoverableError, - transitionCallbacks + concurrentUpdatesByDefaultOverride ) { - var hydrate = false; - var initialChildren = null; - return createFiberRoot( - containerInfo, - tag, - hydrate, - initialChildren, - hydrationCallbacks, - isStrictMode, - concurrentUpdatesByDefaultOverride, - identifierPrefix, - onRecoverableError - ); -} -function updateContainer(element, container, parentComponent, callback) { - { - onScheduleRoot(container, element); - } - - var current$1 = container.current; - var lane = requestUpdateLane(current$1); + var mode; - { - markRenderScheduled(lane); - } + if (tag === ConcurrentRoot) { + mode = ConcurrentMode; - var context = getContextForSubtree(parentComponent); + if (isStrictMode === true || createRootStrictEffectsByDefault) { + mode |= StrictLegacyMode | StrictEffectsMode; + } - if (container.context === null) { - container.context = context; + if ( + // Only for internal experiments. + concurrentUpdatesByDefaultOverride + ) { + mode |= ConcurrentUpdatesByDefaultMode; + } } else { - container.pendingContext = context; + mode = NoMode; } - { - if (isRendering && current !== null && !didWarnAboutNestedUpdates) { - didWarnAboutNestedUpdates = true; - - error( - "Render methods should be a pure function of props and state; " + - "triggering nested component updates from render is not allowed. " + - "If necessary, trigger nested updates in componentDidUpdate.\n\n" + - "Check the render method of %s.", - getComponentNameFromFiber(current) || "Unknown" - ); - } + if (isDevToolsPresent) { + // Always collect profile timings when DevTools are present. + // This enables DevTools to start capturing timing at any point– + // Without some nodes in the tree having empty base times. + mode |= ProfileMode; } - var update = createUpdate(lane); // Caution: React DevTools currently depends on this property - // being called "element". + return createFiber(HostRoot, null, null, mode); +} +function createFiberFromTypeAndProps( + type, // React$ElementType + key, + pendingProps, + owner, + mode, + lanes +) { + var fiberTag = IndeterminateComponent; // The resolved type is set if we know what the final type will be. I.e. it's not lazy. + + var resolvedType = type; - update.payload = { - element: element - }; - callback = callback === undefined ? null : callback; + if (typeof type === "function") { + if (shouldConstruct(type)) { + fiberTag = ClassComponent; - if (callback !== null) { - { - if (typeof callback !== "function") { - error( - "render(...): Expected the last optional `callback` argument to be a " + - "function. Instead received: %s.", - callback - ); + { + resolvedType = resolveClassForHotReloading(resolvedType); + } + } else { + { + resolvedType = resolveFunctionForHotReloading(resolvedType); } } + } else if (typeof type === "string") { + { + fiberTag = HostComponent; + } + } else { + getTag: switch (type) { + case REACT_FRAGMENT_TYPE: + return createFiberFromFragment(pendingProps.children, mode, lanes, key); - update.callback = callback; - } + case REACT_STRICT_MODE_TYPE: + fiberTag = Mode; + mode |= StrictLegacyMode; - var root = enqueueUpdate(current$1, update, lane); + if ((mode & ConcurrentMode) !== NoMode) { + // Strict effects should never run on legacy roots + mode |= StrictEffectsMode; + } - if (root !== null) { - var eventTime = requestEventTime(); - scheduleUpdateOnFiber(root, current$1, lane, eventTime); - entangleTransitions(root, current$1, lane); - } + break; - return lane; -} -function getPublicRootInstance(container) { - var containerFiber = container.current; + case REACT_PROFILER_TYPE: + return createFiberFromProfiler(pendingProps, mode, lanes, key); - if (!containerFiber.child) { - return null; - } + case REACT_SUSPENSE_TYPE: + return createFiberFromSuspense(pendingProps, mode, lanes, key); - switch (containerFiber.child.tag) { - case HostSingleton: - case HostComponent: - return getPublicInstance(containerFiber.child.stateNode); + case REACT_SUSPENSE_LIST_TYPE: + return createFiberFromSuspenseList(pendingProps, mode, lanes, key); - default: - return containerFiber.child.stateNode; - } -} + case REACT_OFFSCREEN_TYPE: + return createFiberFromOffscreen(pendingProps, mode, lanes, key); -var shouldErrorImpl = function (fiber) { - return null; -}; + case REACT_LEGACY_HIDDEN_TYPE: { + return createFiberFromLegacyHidden(pendingProps, mode, lanes, key); + } -function shouldError(fiber) { - return shouldErrorImpl(fiber); -} + // eslint-disable-next-line no-fallthrough -var shouldSuspendImpl = function (fiber) { - return false; -}; + case REACT_SCOPE_TYPE: -function shouldSuspend(fiber) { - return shouldSuspendImpl(fiber); -} -var overrideHookState = null; -var overrideHookStateDeletePath = null; -var overrideHookStateRenamePath = null; -var overrideProps = null; -var overridePropsDeletePath = null; -var overridePropsRenamePath = null; -var scheduleUpdate = null; -var setErrorHandler = null; -var setSuspenseHandler = null; + // eslint-disable-next-line no-fallthrough -{ - var copyWithDeleteImpl = function (obj, path, index) { - var key = path[index]; - var updated = isArray(obj) ? obj.slice() : assign({}, obj); + case REACT_CACHE_TYPE: - if (index + 1 === path.length) { - if (isArray(updated)) { - updated.splice(key, 1); - } else { - delete updated[key]; - } + // eslint-disable-next-line no-fallthrough - return updated; - } // $FlowFixMe number or string is fine here + case REACT_TRACING_MARKER_TYPE: - updated[key] = copyWithDeleteImpl(obj[key], path, index + 1); - return updated; - }; + // eslint-disable-next-line no-fallthrough - var copyWithDelete = function (obj, path) { - return copyWithDeleteImpl(obj, path, 0); - }; + case REACT_DEBUG_TRACING_MODE_TYPE: - var copyWithRenameImpl = function (obj, oldPath, newPath, index) { - var oldKey = oldPath[index]; - var updated = isArray(obj) ? obj.slice() : assign({}, obj); + // eslint-disable-next-line no-fallthrough - if (index + 1 === oldPath.length) { - var newKey = newPath[index]; // $FlowFixMe number or string is fine here + default: { + if (typeof type === "object" && type !== null) { + switch (type.$$typeof) { + case REACT_PROVIDER_TYPE: + fiberTag = ContextProvider; + break getTag; - updated[newKey] = updated[oldKey]; + case REACT_CONTEXT_TYPE: + // This is a consumer + fiberTag = ContextConsumer; + break getTag; - if (isArray(updated)) { - updated.splice(oldKey, 1); - } else { - delete updated[oldKey]; - } - } else { - // $FlowFixMe number or string is fine here - updated[oldKey] = copyWithRenameImpl( - // $FlowFixMe number or string is fine here - obj[oldKey], - oldPath, - newPath, - index + 1 - ); - } + case REACT_FORWARD_REF_TYPE: + fiberTag = ForwardRef; - return updated; - }; + { + resolvedType = resolveForwardRefForHotReloading(resolvedType); + } - var copyWithRename = function (obj, oldPath, newPath) { - if (oldPath.length !== newPath.length) { - warn("copyWithRename() expects paths of the same length"); + break getTag; - return; - } else { - for (var i = 0; i < newPath.length - 1; i++) { - if (oldPath[i] !== newPath[i]) { - warn( - "copyWithRename() expects paths to be the same except for the deepest key" - ); + case REACT_MEMO_TYPE: + fiberTag = MemoComponent; + break getTag; - return; + case REACT_LAZY_TYPE: + fiberTag = LazyComponent; + resolvedType = null; + break getTag; + } } - } - } - - return copyWithRenameImpl(obj, oldPath, newPath, 0); - }; - - var copyWithSetImpl = function (obj, path, index, value) { - if (index >= path.length) { - return value; - } - var key = path[index]; - var updated = isArray(obj) ? obj.slice() : assign({}, obj); // $FlowFixMe number or string is fine here + var info = ""; - updated[key] = copyWithSetImpl(obj[key], path, index + 1, value); - return updated; - }; + { + if ( + type === undefined || + (typeof type === "object" && + type !== null && + Object.keys(type).length === 0) + ) { + info += + " You likely forgot to export your component from the file " + + "it's defined in, or you might have mixed up default and " + + "named imports."; + } - var copyWithSet = function (obj, path, value) { - return copyWithSetImpl(obj, path, 0, value); - }; + var ownerName = owner ? getComponentNameFromFiber(owner) : null; - var findHook = function (fiber, id) { - // For now, the "id" of stateful hooks is just the stateful hook index. - // This may change in the future with e.g. nested hooks. - var currentHook = fiber.memoizedState; + if (ownerName) { + info += "\n\nCheck the render method of `" + ownerName + "`."; + } + } - while (currentHook !== null && id > 0) { - currentHook = currentHook.next; - id--; + throw new Error( + "Element type is invalid: expected a string (for built-in " + + "components) or a class/function (for composite components) " + + ("but got: " + (type == null ? type : typeof type) + "." + info) + ); + } } + } - return currentHook; - }; // Support DevTools editable values for useState and useReducer. - - overrideHookState = function (fiber, id, path, value) { - var hook = findHook(fiber, id); + var fiber = createFiber(fiberTag, pendingProps, key, mode); + fiber.elementType = type; + fiber.type = resolvedType; + fiber.lanes = lanes; - if (hook !== null) { - var newState = copyWithSet(hook.memoizedState, path, value); - hook.memoizedState = newState; - hook.baseState = newState; // We aren't actually adding an update to the queue, - // because there is no update we can add for useReducer hooks that won't trigger an error. - // (There's no appropriate action type for DevTools overrides.) - // As a result though, React will see the scheduled update as a noop and bailout. - // Shallow cloning props works as a workaround for now to bypass the bailout check. + { + fiber._debugOwner = owner; + } - fiber.memoizedProps = assign({}, fiber.memoizedProps); - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + return fiber; +} +function createFiberFromElement(element, mode, lanes) { + var owner = null; - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); - } - } - }; + { + owner = element._owner; + } - overrideHookStateDeletePath = function (fiber, id, path) { - var hook = findHook(fiber, id); + var type = element.type; + var key = element.key; + var pendingProps = element.props; + var fiber = createFiberFromTypeAndProps( + type, + key, + pendingProps, + owner, + mode, + lanes + ); - if (hook !== null) { - var newState = copyWithDelete(hook.memoizedState, path); - hook.memoizedState = newState; - hook.baseState = newState; // We aren't actually adding an update to the queue, - // because there is no update we can add for useReducer hooks that won't trigger an error. - // (There's no appropriate action type for DevTools overrides.) - // As a result though, React will see the scheduled update as a noop and bailout. - // Shallow cloning props works as a workaround for now to bypass the bailout check. + { + fiber._debugSource = element._source; + fiber._debugOwner = element._owner; + } - fiber.memoizedProps = assign({}, fiber.memoizedProps); - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + return fiber; +} +function createFiberFromFragment(elements, mode, lanes, key) { + var fiber = createFiber(Fragment, elements, key, mode); + fiber.lanes = lanes; + return fiber; +} - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); - } +function createFiberFromProfiler(pendingProps, mode, lanes, key) { + { + if (typeof pendingProps.id !== "string") { + error( + 'Profiler must specify an "id" of type `string` as a prop. Received the type `%s` instead.', + typeof pendingProps.id + ); } - }; + } - overrideHookStateRenamePath = function (fiber, id, oldPath, newPath) { - var hook = findHook(fiber, id); + var fiber = createFiber(Profiler, pendingProps, key, mode | ProfileMode); + fiber.elementType = REACT_PROFILER_TYPE; + fiber.lanes = lanes; - if (hook !== null) { - var newState = copyWithRename(hook.memoizedState, oldPath, newPath); - hook.memoizedState = newState; - hook.baseState = newState; // We aren't actually adding an update to the queue, - // because there is no update we can add for useReducer hooks that won't trigger an error. - // (There's no appropriate action type for DevTools overrides.) - // As a result though, React will see the scheduled update as a noop and bailout. - // Shallow cloning props works as a workaround for now to bypass the bailout check. + { + fiber.stateNode = { + effectDuration: 0, + passiveEffectDuration: 0 + }; + } - fiber.memoizedProps = assign({}, fiber.memoizedProps); - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + return fiber; +} - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); - } +function createFiberFromSuspense(pendingProps, mode, lanes, key) { + var fiber = createFiber(SuspenseComponent, pendingProps, key, mode); + fiber.elementType = REACT_SUSPENSE_TYPE; + fiber.lanes = lanes; + return fiber; +} +function createFiberFromSuspenseList(pendingProps, mode, lanes, key) { + var fiber = createFiber(SuspenseListComponent, pendingProps, key, mode); + fiber.elementType = REACT_SUSPENSE_LIST_TYPE; + fiber.lanes = lanes; + return fiber; +} +function createFiberFromOffscreen(pendingProps, mode, lanes, key) { + var fiber = createFiber(OffscreenComponent, pendingProps, key, mode); + fiber.elementType = REACT_OFFSCREEN_TYPE; + fiber.lanes = lanes; + var primaryChildInstance = { + _visibility: OffscreenVisible, + _pendingVisibility: OffscreenVisible, + _pendingMarkers: null, + _retryCache: null, + _transitions: null, + _current: null, + detach: function () { + return detachOffscreenInstance(primaryChildInstance); + }, + attach: function () { + return attachOffscreenInstance(primaryChildInstance); } - }; // Support DevTools props for function components, forwardRef, memo, host components, etc. - - overrideProps = function (fiber, path, value) { - fiber.pendingProps = copyWithSet(fiber.memoizedProps, path, value); + }; + fiber.stateNode = primaryChildInstance; + return fiber; +} +function createFiberFromLegacyHidden(pendingProps, mode, lanes, key) { + var fiber = createFiber(LegacyHiddenComponent, pendingProps, key, mode); + fiber.elementType = REACT_LEGACY_HIDDEN_TYPE; + fiber.lanes = lanes; // Adding a stateNode for legacy hidden because it's currently using + // the offscreen implementation, which depends on a state node - if (fiber.alternate) { - fiber.alternate.pendingProps = fiber.pendingProps; + var instance = { + _visibility: OffscreenVisible, + _pendingVisibility: OffscreenVisible, + _pendingMarkers: null, + _transitions: null, + _retryCache: null, + _current: null, + detach: function () { + return detachOffscreenInstance(instance); + }, + attach: function () { + return attachOffscreenInstance(instance); } + }; + fiber.stateNode = instance; + return fiber; +} +function createFiberFromText(content, mode, lanes) { + var fiber = createFiber(HostText, content, null, mode); + fiber.lanes = lanes; + return fiber; +} +function createFiberFromPortal(portal, mode, lanes) { + var pendingProps = portal.children !== null ? portal.children : []; + var fiber = createFiber(HostPortal, pendingProps, portal.key, mode); + fiber.lanes = lanes; + fiber.stateNode = { + containerInfo: portal.containerInfo, + pendingChildren: null, + // Used by persistent updates + implementation: portal.implementation + }; + return fiber; +} // Used for stashing WIP properties to replay failed work in DEV. - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); +function assignFiberPropertiesInDEV(target, source) { + if (target === null) { + // This Fiber's initial properties will always be overwritten. + // We only use a Fiber to ensure the same hidden class so DEV isn't slow. + target = createFiber(IndeterminateComponent, null, null, NoMode); + } // This is intentionally written as a list of all properties. + // We tried to use Object.assign() instead but this is called in + // the hottest path, and Object.assign() was too slow: + // https://github.com/facebook/react/issues/12502 + // This code is DEV-only so size is not a concern. - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); - } - }; + target.tag = source.tag; + target.key = source.key; + target.elementType = source.elementType; + target.type = source.type; + target.stateNode = source.stateNode; + target.return = source.return; + target.child = source.child; + target.sibling = source.sibling; + target.index = source.index; + target.ref = source.ref; + target.refCleanup = source.refCleanup; + target.pendingProps = source.pendingProps; + target.memoizedProps = source.memoizedProps; + target.updateQueue = source.updateQueue; + target.memoizedState = source.memoizedState; + target.dependencies = source.dependencies; + target.mode = source.mode; + target.flags = source.flags; + target.subtreeFlags = source.subtreeFlags; + target.deletions = source.deletions; + target.lanes = source.lanes; + target.childLanes = source.childLanes; + target.alternate = source.alternate; - overridePropsDeletePath = function (fiber, path) { - fiber.pendingProps = copyWithDelete(fiber.memoizedProps, path); + { + target.actualDuration = source.actualDuration; + target.actualStartTime = source.actualStartTime; + target.selfBaseDuration = source.selfBaseDuration; + target.treeBaseDuration = source.treeBaseDuration; + } - if (fiber.alternate) { - fiber.alternate.pendingProps = fiber.pendingProps; - } + target._debugSource = source._debugSource; + target._debugOwner = source._debugOwner; + target._debugNeedsRemount = source._debugNeedsRemount; + target._debugHookTypes = source._debugHookTypes; + return target; +} - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); +function FiberRootNode( + containerInfo, // $FlowFixMe[missing-local-annot] + tag, + hydrate, + identifierPrefix, + onRecoverableError +) { + this.tag = tag; + this.containerInfo = containerInfo; + this.pendingChildren = null; + this.current = null; + this.pingCache = null; + this.finishedWork = null; + this.timeoutHandle = noTimeout; + this.cancelPendingCommit = null; + this.context = null; + this.pendingContext = null; + this.callbackNode = null; + this.callbackPriority = NoLane; + this.eventTimes = createLaneMap(NoLanes); + this.expirationTimes = createLaneMap(NoTimestamp); + this.pendingLanes = NoLanes; + this.suspendedLanes = NoLanes; + this.pingedLanes = NoLanes; + this.expiredLanes = NoLanes; + this.mutableReadLanes = NoLanes; + this.finishedLanes = NoLanes; + this.errorRecoveryDisabledLanes = NoLanes; + this.entangledLanes = NoLanes; + this.entanglements = createLaneMap(NoLanes); + this.hiddenUpdates = createLaneMap(null); + this.identifierPrefix = identifierPrefix; + this.onRecoverableError = onRecoverableError; - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); - } - }; + this.incompleteTransitions = new Map(); - overridePropsRenamePath = function (fiber, oldPath, newPath) { - fiber.pendingProps = copyWithRename(fiber.memoizedProps, oldPath, newPath); + { + this.effectDuration = 0; + this.passiveEffectDuration = 0; + } - if (fiber.alternate) { - fiber.alternate.pendingProps = fiber.pendingProps; + { + this.memoizedUpdaters = new Set(); + var pendingUpdatersLaneMap = (this.pendingUpdatersLaneMap = []); + + for (var _i = 0; _i < TotalLanes; _i++) { + pendingUpdatersLaneMap.push(new Set()); } + } - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + { + switch (tag) { + case ConcurrentRoot: + this._debugRootType = hydrate ? "hydrateRoot()" : "createRoot()"; + break; - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); + case LegacyRoot: + this._debugRootType = hydrate ? "hydrate()" : "render()"; + break; } - }; + } +} - scheduleUpdate = function (fiber) { - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); +function createFiberRoot( + containerInfo, + tag, + hydrate, + initialChildren, + hydrationCallbacks, + isStrictMode, + concurrentUpdatesByDefaultOverride, // TODO: We have several of these arguments that are conceptually part of the + // host config, but because they are passed in at runtime, we have to thread + // them through the root constructor. Perhaps we should put them all into a + // single type, like a DynamicHostConfig that is defined by the renderer. + identifierPrefix, + onRecoverableError, + transitionCallbacks +) { + // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions + var root = new FiberRootNode( + containerInfo, + tag, + hydrate, + identifierPrefix, + onRecoverableError + ); + // stateNode is any. - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); - } - }; + var uninitializedFiber = createHostRootFiber( + tag, + isStrictMode, + concurrentUpdatesByDefaultOverride + ); + root.current = uninitializedFiber; + uninitializedFiber.stateNode = root; - setErrorHandler = function (newShouldErrorImpl) { - shouldErrorImpl = newShouldErrorImpl; - }; + { + var _initialState = { + element: initialChildren, + isDehydrated: hydrate, + cache: null // not enabled yet + }; + uninitializedFiber.memoizedState = _initialState; + } - setSuspenseHandler = function (newShouldSuspendImpl) { - shouldSuspendImpl = newShouldSuspendImpl; - }; + initializeUpdateQueue(uninitializedFiber); + return root; } -function findHostInstanceByFiber(fiber) { - var hostFiber = findCurrentHostFiber(fiber); +var ReactVersion = "18.3.0-next-9c54b29b4-20230322"; - if (hostFiber === null) { - return null; +function createPortal$1( + children, + containerInfo, // TODO: figure out the API for cross-renderer implementation. + implementation +) { + var key = + arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; + + { + checkKeyStringCoercion(key); } - return hostFiber.stateNode; + return { + // This tag allow us to uniquely identify this as a React Portal + $$typeof: REACT_PORTAL_TYPE, + key: key == null ? null : "" + key, + children: children, + containerInfo: containerInfo, + implementation: implementation + }; } -function emptyFindFiberByHostInstance(instance) { - return null; -} +// Might add PROFILE later. -function getCurrentFiberForDevTools() { - return current; -} +var didWarnAboutNestedUpdates; +var didWarnAboutFindNodeInStrictMode; -function injectIntoDevTools(devToolsConfig) { - var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; - var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher; - return injectInternals({ - bundleType: devToolsConfig.bundleType, - version: devToolsConfig.version, - rendererPackageName: devToolsConfig.rendererPackageName, - rendererConfig: devToolsConfig.rendererConfig, - overrideHookState: overrideHookState, - overrideHookStateDeletePath: overrideHookStateDeletePath, - overrideHookStateRenamePath: overrideHookStateRenamePath, - overrideProps: overrideProps, - overridePropsDeletePath: overridePropsDeletePath, - overridePropsRenamePath: overridePropsRenamePath, - setErrorHandler: setErrorHandler, - setSuspenseHandler: setSuspenseHandler, - scheduleUpdate: scheduleUpdate, - currentDispatcherRef: ReactCurrentDispatcher, - findHostInstanceByFiber: findHostInstanceByFiber, - findFiberByHostInstance: - findFiberByHostInstance || emptyFindFiberByHostInstance, - // React Refresh - findHostInstancesForRefresh: findHostInstancesForRefresh, - scheduleRefresh: scheduleRefresh, - scheduleRoot: scheduleRoot, - setRefreshHandler: setRefreshHandler, - // Enables DevTools to append owner stacks to error messages in DEV mode. - getCurrentFiber: getCurrentFiberForDevTools, - // Enables DevTools to detect reconciler version rather than renderer version - // which may not match for third party renderers. - reconcilerVersion: ReactVersion - }); +{ + didWarnAboutNestedUpdates = false; + didWarnAboutFindNodeInStrictMode = {}; } -/** - * IMPORTANT: This module is used in Paper and Fabric. It needs to be defined - * outside of `ReactFabricPublicInstance` because that module requires - * `nativeFabricUIManager` to be defined in the global scope (which does not - * happen in Paper). - */ +function getContextForSubtree(parentComponent) { + if (!parentComponent) { + return emptyContextObject; + } -function getNativeTagFromPublicInstance(publicInstance) { - return publicInstance.__nativeTag; -} -function getNodeFromPublicInstance(publicInstance) { - if (publicInstance.__internalInstanceHandle == null) { - return null; + var fiber = get(parentComponent); + var parentContext = findCurrentUnmaskedContext(fiber); + + if (fiber.tag === ClassComponent) { + var Component = fiber.type; + + if (isContextProvider(Component)) { + return processChildContext(fiber, Component, parentContext); + } } - return getNodeFromInternalInstanceHandle( - publicInstance.__internalInstanceHandle - ); + return parentContext; } -var ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner; -function findHostInstance_DEPRECATED(componentOrHandle) { +function findHostInstanceWithWarning(component, methodName) { { - var owner = ReactCurrentOwner.current; + var fiber = get(component); - if (owner !== null && owner.stateNode !== null) { - if (!owner.stateNode._warnedAboutRefsInRender) { - error( - "%s is accessing findNodeHandle inside its render(). " + - "render() should be a pure function of props and state. It should " + - "never access something that requires stale data from the previous " + - "render, such as refs. Move this logic to componentDidMount and " + - "componentDidUpdate instead.", - getComponentNameFromType(owner.type) || "A component" + if (fiber === undefined) { + if (typeof component.render === "function") { + throw new Error("Unable to find node on an unmounted component."); + } else { + var keys = Object.keys(component).join(","); + throw new Error( + "Argument appears to not be a ReactComponent. Keys: " + keys ); } - - owner.stateNode._warnedAboutRefsInRender = true; } - } - - if (componentOrHandle == null) { - return null; - } // For compatibility with Fabric instances - if ( - componentOrHandle.canonical && - componentOrHandle.canonical.publicInstance - ) { - // $FlowExpectedError[incompatible-return] Can't refine componentOrHandle as a Fabric instance - return componentOrHandle.canonical.publicInstance; - } // For compatibility with legacy renderer instances + var hostFiber = findCurrentHostFiber(fiber); - if (componentOrHandle._nativeTag) { - // $FlowFixMe[incompatible-exact] Necessary when running Flow on Fabric - // $FlowFixMe[incompatible-return] - return componentOrHandle; - } + if (hostFiber === null) { + return null; + } - var hostInstance; + if (hostFiber.mode & StrictLegacyMode) { + var componentName = getComponentNameFromFiber(fiber) || "Component"; - { - hostInstance = findHostInstanceWithWarning( - componentOrHandle, - "findHostInstance_DEPRECATED" - ); - } // findHostInstance handles legacy vs. Fabric differences correctly - // $FlowFixMe[incompatible-exact] we need to fix the definition of `HostComponent` to use NativeMethods as an interface, not as a type. + if (!didWarnAboutFindNodeInStrictMode[componentName]) { + didWarnAboutFindNodeInStrictMode[componentName] = true; + var previousFiber = current; - return hostInstance; -} -function findNodeHandle(componentOrHandle) { - { - var owner = ReactCurrentOwner.current; + try { + setCurrentFiber(hostFiber); - if (owner !== null && owner.stateNode !== null) { - if (!owner.stateNode._warnedAboutRefsInRender) { - error( - "%s is accessing findNodeHandle inside its render(). " + - "render() should be a pure function of props and state. It should " + - "never access something that requires stale data from the previous " + - "render, such as refs. Move this logic to componentDidMount and " + - "componentDidUpdate instead.", - getComponentNameFromType(owner.type) || "A component" - ); + if (fiber.mode & StrictLegacyMode) { + error( + "%s is deprecated in StrictMode. " + + "%s was passed an instance of %s which is inside StrictMode. " + + "Instead, add a ref directly to the element you want to reference. " + + "Learn more about using refs safely here: " + + "https://reactjs.org/link/strict-mode-find-node", + methodName, + methodName, + componentName + ); + } else { + error( + "%s is deprecated in StrictMode. " + + "%s was passed an instance of %s which renders StrictMode children. " + + "Instead, add a ref directly to the element you want to reference. " + + "Learn more about using refs safely here: " + + "https://reactjs.org/link/strict-mode-find-node", + methodName, + methodName, + componentName + ); + } + } finally { + // Ideally this should reset to previous but this shouldn't be called in + // render and there's another warning for that anyway. + if (previousFiber) { + setCurrentFiber(previousFiber); + } else { + resetCurrentFiber(); + } + } } - - owner.stateNode._warnedAboutRefsInRender = true; } - } - if (componentOrHandle == null) { - return null; + return getPublicInstance(hostFiber.stateNode); } +} - if (typeof componentOrHandle === "number") { - // Already a node handle - return componentOrHandle; - } // For compatibility with legacy renderer instances - - if (componentOrHandle._nativeTag) { - return componentOrHandle._nativeTag; - } // For compatibility with Fabric instances - - if ( - componentOrHandle.canonical != null && - componentOrHandle.canonical.nativeTag != null - ) { - return componentOrHandle.canonical.nativeTag; - } // For compatibility with Fabric public instances - - var nativeTag = getNativeTagFromPublicInstance(componentOrHandle); - - if (nativeTag) { - return nativeTag; +function createContainer( + containerInfo, + tag, + hydrationCallbacks, + isStrictMode, + concurrentUpdatesByDefaultOverride, + identifierPrefix, + onRecoverableError, + transitionCallbacks +) { + var hydrate = false; + var initialChildren = null; + return createFiberRoot( + containerInfo, + tag, + hydrate, + initialChildren, + hydrationCallbacks, + isStrictMode, + concurrentUpdatesByDefaultOverride, + identifierPrefix, + onRecoverableError + ); +} +function updateContainer(element, container, parentComponent, callback) { + { + onScheduleRoot(container, element); } - var hostInstance; + var current$1 = container.current; + var lane = requestUpdateLane(current$1); { - hostInstance = findHostInstanceWithWarning( - componentOrHandle, - "findNodeHandle" - ); + markRenderScheduled(lane); } - if (hostInstance == null) { - return hostInstance; - } // $FlowFixMe[prop-missing] For compatibility with legacy renderer instances + var context = getContextForSubtree(parentComponent); - if (hostInstance._nativeTag != null) { - // $FlowFixMe[incompatible-return] - return hostInstance._nativeTag; - } // $FlowFixMe[incompatible-call] Necessary when running Flow on the legacy renderer + if (container.context === null) { + container.context = context; + } else { + container.pendingContext = context; + } - return getNativeTagFromPublicInstance(hostInstance); -} -function dispatchCommand(handle, command, args) { - var nativeTag = - handle._nativeTag != null - ? handle._nativeTag - : getNativeTagFromPublicInstance(handle); + { + if (isRendering && current !== null && !didWarnAboutNestedUpdates) { + didWarnAboutNestedUpdates = true; - if (nativeTag == null) { - { error( - "dispatchCommand was called with a ref that isn't a " + - "native component. Use React.forwardRef to get access to the underlying native component" + "Render methods should be a pure function of props and state; " + + "triggering nested component updates from render is not allowed. " + + "If necessary, trigger nested updates in componentDidUpdate.\n\n" + + "Check the render method of %s.", + getComponentNameFromFiber(current) || "Unknown" ); } - - return; } - var node = getNodeFromPublicInstance(handle); + var update = createUpdate(lane); // Caution: React DevTools currently depends on this property + // being called "element". - if (node != null) { - nativeFabricUIManager.dispatchCommand(node, command, args); - } else { - ReactNativePrivateInterface.UIManager.dispatchViewManagerCommand( - nativeTag, - command, - args - ); - } -} -function sendAccessibilityEvent(handle, eventType) { - var nativeTag = - handle._nativeTag != null - ? handle._nativeTag - : getNativeTagFromPublicInstance(handle); + update.payload = { + element: element + }; + callback = callback === undefined ? null : callback; - if (nativeTag == null) { + if (callback !== null) { { - error( - "sendAccessibilityEvent was called with a ref that isn't a " + - "native component. Use React.forwardRef to get access to the underlying native component" - ); + if (typeof callback !== "function") { + error( + "render(...): Expected the last optional `callback` argument to be a " + + "function. Instead received: %s.", + callback + ); + } } - return; + update.callback = callback; } - var node = getNodeFromPublicInstance(handle); + var root = enqueueUpdate(current$1, update, lane); - if (node != null) { - nativeFabricUIManager.sendAccessibilityEvent(node, eventType); - } else { - ReactNativePrivateInterface.legacySendAccessibilityEvent( - nativeTag, - eventType - ); + if (root !== null) { + var eventTime = requestEventTime(); + scheduleUpdateOnFiber(root, current$1, lane, eventTime); + entangleTransitions(root, current$1, lane); } -} -function getNodeFromInternalInstanceHandle(internalInstanceHandle) { - return ( - // $FlowExpectedError[incompatible-return] internalInstanceHandle is opaque but we need to make an exception here. - internalInstanceHandle && // $FlowExpectedError[incompatible-return] - internalInstanceHandle.stateNode && // $FlowExpectedError[incompatible-use] - internalInstanceHandle.stateNode.node - ); -} -var _nativeFabricUIManage$1 = nativeFabricUIManager, - fabricMeasure = _nativeFabricUIManage$1.measure, - fabricMeasureInWindow = _nativeFabricUIManage$1.measureInWindow, - fabricMeasureLayout = _nativeFabricUIManage$1.measureLayout, - _setNativeProps = _nativeFabricUIManage$1.setNativeProps, - fabricGetBoundingClientRect = _nativeFabricUIManage$1.getBoundingClientRect; - -var noop = function () {}; -/** - * This is used for refs on host components. - */ + return lane; +} +function getPublicRootInstance(container) { + var containerFiber = container.current; -var ReactFabricHostComponent = /*#__PURE__*/ (function () { - // These need to be accessible from `ReactFabricPublicInstanceUtils`. - function ReactFabricHostComponent(tag, viewConfig, internalInstanceHandle) { - this.__nativeTag = void 0; - this.__internalInstanceHandle = void 0; - this._viewConfig = void 0; - this.__nativeTag = tag; - this._viewConfig = viewConfig; - this.__internalInstanceHandle = internalInstanceHandle; + if (!containerFiber.child) { + return null; } - var _proto = ReactFabricHostComponent.prototype; + switch (containerFiber.child.tag) { + case HostSingleton: + case HostComponent: + return getPublicInstance(containerFiber.child.stateNode); - _proto.blur = function blur() { - ReactNativePrivateInterface.TextInputState.blurTextInput(this); - }; + default: + return containerFiber.child.stateNode; + } +} - _proto.focus = function focus() { - ReactNativePrivateInterface.TextInputState.focusTextInput(this); - }; +var shouldErrorImpl = function (fiber) { + return null; +}; - _proto.measure = function measure(callback) { - var node = getNodeFromInternalInstanceHandle(this.__internalInstanceHandle); +function shouldError(fiber) { + return shouldErrorImpl(fiber); +} - if (node != null) { - fabricMeasure(node, callback); - } - }; +var shouldSuspendImpl = function (fiber) { + return false; +}; - _proto.measureInWindow = function measureInWindow(callback) { - var node = getNodeFromInternalInstanceHandle(this.__internalInstanceHandle); +function shouldSuspend(fiber) { + return shouldSuspendImpl(fiber); +} +var overrideHookState = null; +var overrideHookStateDeletePath = null; +var overrideHookStateRenamePath = null; +var overrideProps = null; +var overridePropsDeletePath = null; +var overridePropsRenamePath = null; +var scheduleUpdate = null; +var setErrorHandler = null; +var setSuspenseHandler = null; - if (node != null) { - fabricMeasureInWindow(node, callback); - } - }; +{ + var copyWithDeleteImpl = function (obj, path, index) { + var key = path[index]; + var updated = isArray(obj) ? obj.slice() : assign({}, obj); - _proto.measureLayout = function measureLayout( - relativeToNativeNode, - onSuccess, - onFail - /* currently unused */ - ) { - if ( - typeof relativeToNativeNode === "number" || - !(relativeToNativeNode instanceof ReactFabricHostComponent) - ) { - { - error( - "Warning: ref.measureLayout must be called with a ref to a native component." - ); + if (index + 1 === path.length) { + if (isArray(updated)) { + updated.splice(key, 1); + } else { + delete updated[key]; } - return; - } - - var toStateNode = getNodeFromInternalInstanceHandle( - this.__internalInstanceHandle - ); - var fromStateNode = getNodeFromInternalInstanceHandle( - relativeToNativeNode.__internalInstanceHandle - ); + return updated; + } // $FlowFixMe number or string is fine here - if (toStateNode != null && fromStateNode != null) { - fabricMeasureLayout( - toStateNode, - fromStateNode, - onFail != null ? onFail : noop, - onSuccess != null ? onSuccess : noop - ); - } + updated[key] = copyWithDeleteImpl(obj[key], path, index + 1); + return updated; }; - _proto.unstable_getBoundingClientRect = - function unstable_getBoundingClientRect() { - var node = getNodeFromInternalInstanceHandle( - this.__internalInstanceHandle - ); + var copyWithDelete = function (obj, path) { + return copyWithDeleteImpl(obj, path, 0); + }; - if (node != null) { - var rect = fabricGetBoundingClientRect(node); + var copyWithRenameImpl = function (obj, oldPath, newPath, index) { + var oldKey = oldPath[index]; + var updated = isArray(obj) ? obj.slice() : assign({}, obj); - if (rect) { - return new DOMRect(rect[0], rect[1], rect[2], rect[3]); - } - } // Empty rect if any of the above failed + if (index + 1 === oldPath.length) { + var newKey = newPath[index]; // $FlowFixMe number or string is fine here - return new DOMRect(0, 0, 0, 0); - }; + updated[newKey] = updated[oldKey]; - _proto.setNativeProps = function setNativeProps(nativeProps) { - { - warnForStyleProps(nativeProps, this._viewConfig.validAttributes); + if (isArray(updated)) { + updated.splice(oldKey, 1); + } else { + delete updated[oldKey]; + } + } else { + // $FlowFixMe number or string is fine here + updated[oldKey] = copyWithRenameImpl( + // $FlowFixMe number or string is fine here + obj[oldKey], + oldPath, + newPath, + index + 1 + ); } - var updatePayload = create(nativeProps, this._viewConfig.validAttributes); - var node = getNodeFromInternalInstanceHandle(this.__internalInstanceHandle); - - if (node != null && updatePayload != null) { - _setNativeProps(node, updatePayload); - } + return updated; }; - return ReactFabricHostComponent; -})(); -function createPublicInstance(tag, viewConfig, internalInstanceHandle) { - return new ReactFabricHostComponent(tag, viewConfig, internalInstanceHandle); -} - -// Used as a way to call batchedUpdates when we don't have a reference to -// the renderer. Such as when we're dispatching events or if third party -// libraries need to call batchedUpdates. Eventually, this API will go away when -// everything is batched by default. We'll then have a similar API to opt-out of -// scheduled work and instead do synchronous work. -// Defaults -var batchedUpdatesImpl = function (fn, bookkeeping) { - return fn(bookkeeping); -}; - -var isInsideEventHandler = false; -function batchedUpdates(fn, bookkeeping) { - if (isInsideEventHandler) { - // If we are currently inside another batch, we need to wait until it - // fully completes before restoring state. - return fn(bookkeeping); - } + var copyWithRename = function (obj, oldPath, newPath) { + if (oldPath.length !== newPath.length) { + warn("copyWithRename() expects paths of the same length"); - isInsideEventHandler = true; + return; + } else { + for (var i = 0; i < newPath.length - 1; i++) { + if (oldPath[i] !== newPath[i]) { + warn( + "copyWithRename() expects paths to be the same except for the deepest key" + ); - try { - return batchedUpdatesImpl(fn, bookkeeping); - } finally { - isInsideEventHandler = false; - } -} -function setBatchingImplementation(_batchedUpdatesImpl, _discreteUpdatesImpl) { - batchedUpdatesImpl = _batchedUpdatesImpl; -} + return; + } + } + } -/** - * Internal queue of events that have accumulated their dispatches and are - * waiting to have their dispatches executed. - */ + return copyWithRenameImpl(obj, oldPath, newPath, 0); + }; -var eventQueue = null; -/** - * Dispatches an event and releases it back into the pool, unless persistent. - * - * @param {?object} event Synthetic event to be dispatched. - * @private - */ + var copyWithSetImpl = function (obj, path, index, value) { + if (index >= path.length) { + return value; + } -function executeDispatchesAndRelease(event) { - if (event) { - executeDispatchesInOrder(event); + var key = path[index]; + var updated = isArray(obj) ? obj.slice() : assign({}, obj); // $FlowFixMe number or string is fine here - if (!event.isPersistent()) { - event.constructor.release(event); - } - } -} // $FlowFixMe[missing-local-annot] + updated[key] = copyWithSetImpl(obj[key], path, index + 1, value); + return updated; + }; -function executeDispatchesAndReleaseTopLevel(e) { - return executeDispatchesAndRelease(e); -} + var copyWithSet = function (obj, path, value) { + return copyWithSetImpl(obj, path, 0, value); + }; -function runEventsInBatch(events) { - if (events !== null) { - eventQueue = accumulateInto(eventQueue, events); - } // Set `eventQueue` to null before processing it so that we can tell if more - // events get enqueued while processing. + var findHook = function (fiber, id) { + // For now, the "id" of stateful hooks is just the stateful hook index. + // This may change in the future with e.g. nested hooks. + var currentHook = fiber.memoizedState; - var processingEventQueue = eventQueue; - eventQueue = null; + while (currentHook !== null && id > 0) { + currentHook = currentHook.next; + id--; + } - if (!processingEventQueue) { - return; - } + return currentHook; + }; // Support DevTools editable values for useState and useReducer. - forEachAccumulated(processingEventQueue, executeDispatchesAndReleaseTopLevel); + overrideHookState = function (fiber, id, path, value) { + var hook = findHook(fiber, id); - if (eventQueue) { - throw new Error( - "processEventQueue(): Additional events were enqueued while processing " + - "an event queue. Support for this has not yet been implemented." - ); - } // This would be a good time to rethrow if any of the event handlers threw. + if (hook !== null) { + var newState = copyWithSet(hook.memoizedState, path, value); + hook.memoizedState = newState; + hook.baseState = newState; // We aren't actually adding an update to the queue, + // because there is no update we can add for useReducer hooks that won't trigger an error. + // (There's no appropriate action type for DevTools overrides.) + // As a result though, React will see the scheduled update as a noop and bailout. + // Shallow cloning props works as a workaround for now to bypass the bailout check. - rethrowCaughtError(); -} + fiber.memoizedProps = assign({}, fiber.memoizedProps); + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); -/** - * Allows registered plugins an opportunity to extract events from top-level - * native browser events. - * - * @return {*} An accumulation of synthetic events. - * @internal - */ + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); + } + } + }; -function extractPluginEvents( - topLevelType, - targetInst, - nativeEvent, - nativeEventTarget -) { - var events = null; - var legacyPlugins = plugins; + overrideHookStateDeletePath = function (fiber, id, path) { + var hook = findHook(fiber, id); - for (var i = 0; i < legacyPlugins.length; i++) { - // Not every plugin in the ordering may be loaded at runtime. - var possiblePlugin = legacyPlugins[i]; + if (hook !== null) { + var newState = copyWithDelete(hook.memoizedState, path); + hook.memoizedState = newState; + hook.baseState = newState; // We aren't actually adding an update to the queue, + // because there is no update we can add for useReducer hooks that won't trigger an error. + // (There's no appropriate action type for DevTools overrides.) + // As a result though, React will see the scheduled update as a noop and bailout. + // Shallow cloning props works as a workaround for now to bypass the bailout check. - if (possiblePlugin) { - var extractedEvents = possiblePlugin.extractEvents( - topLevelType, - targetInst, - nativeEvent, - nativeEventTarget - ); + fiber.memoizedProps = assign({}, fiber.memoizedProps); + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - if (extractedEvents) { - events = accumulateInto(events, extractedEvents); + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); } } - } - - return events; -} + }; -function runExtractedPluginEventsInBatch( - topLevelType, - targetInst, - nativeEvent, - nativeEventTarget -) { - var events = extractPluginEvents( - topLevelType, - targetInst, - nativeEvent, - nativeEventTarget - ); - runEventsInBatch(events); -} + overrideHookStateRenamePath = function (fiber, id, oldPath, newPath) { + var hook = findHook(fiber, id); -function dispatchEvent(target, topLevelType, nativeEvent) { - var targetFiber = target; - var eventTarget = null; + if (hook !== null) { + var newState = copyWithRename(hook.memoizedState, oldPath, newPath); + hook.memoizedState = newState; + hook.baseState = newState; // We aren't actually adding an update to the queue, + // because there is no update we can add for useReducer hooks that won't trigger an error. + // (There's no appropriate action type for DevTools overrides.) + // As a result though, React will see the scheduled update as a noop and bailout. + // Shallow cloning props works as a workaround for now to bypass the bailout check. - if (targetFiber != null) { - var stateNode = targetFiber.stateNode; // Guard against Fiber being unmounted + fiber.memoizedProps = assign({}, fiber.memoizedProps); + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - if (stateNode != null) { - // $FlowExpectedError[incompatible-cast] public instances in Fabric do not implement `EventTarget` yet. - eventTarget = getPublicInstance(stateNode); + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); + } } - } + }; // Support DevTools props for function components, forwardRef, memo, host components, etc. - batchedUpdates(function () { - // Emit event to the RawEventEmitter. This is an unused-by-default EventEmitter - // that can be used to instrument event performance monitoring (primarily - could be useful - // for other things too). - // - // NOTE: this merely emits events into the EventEmitter below. - // If *you* do not add listeners to the `RawEventEmitter`, - // then all of these emitted events will just blackhole and are no-ops. - // It is available (although not officially supported... yet) if you want to collect - // perf data on event latency in your application, and could also be useful for debugging - // low-level events issues. - // - // If you do not have any event perf monitoring and are extremely concerned about event perf, - // it is safe to disable these "emit" statements; it will prevent checking the size of - // an empty array twice and prevent two no-ops. Practically the overhead is so low that - // we don't think it's worth thinking about in prod; your perf issues probably lie elsewhere. - // - // We emit two events here: one for listeners to this specific event, - // and one for the catchall listener '*', for any listeners that want - // to be notified for all events. - // Note that extracted events are *not* emitted, - // only events that have a 1:1 mapping with a native event, at least for now. - var event = { - eventName: topLevelType, - nativeEvent: nativeEvent - }; // $FlowFixMe[class-object-subtyping] found when upgrading Flow + overrideProps = function (fiber, path, value) { + fiber.pendingProps = copyWithSet(fiber.memoizedProps, path, value); - ReactNativePrivateInterface.RawEventEmitter.emit(topLevelType, event); // $FlowFixMe[class-object-subtyping] found when upgrading Flow + if (fiber.alternate) { + fiber.alternate.pendingProps = fiber.pendingProps; + } - ReactNativePrivateInterface.RawEventEmitter.emit("*", event); // Heritage plugin event system + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - runExtractedPluginEventsInBatch( - topLevelType, - targetFiber, - nativeEvent, - eventTarget - ); - }); // React Native doesn't use ReactControlledComponent but if it did, here's - // where it would do it. -} + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); + } + }; -// Renderers that don't support mutation -// can re-export everything from this module. -function shim$1() { - throw new Error( - "The current renderer does not support mutation. " + - "This error is likely caused by a bug in React. " + - "Please file an issue." - ); -} // Mutation (when unsupported) -var commitMount = shim$1; + overridePropsDeletePath = function (fiber, path) { + fiber.pendingProps = copyWithDelete(fiber.memoizedProps, path); -// Renderers that don't support hydration -// can re-export everything from this module. -function shim() { - throw new Error( - "The current renderer does not support hydration. " + - "This error is likely caused by a bug in React. " + - "Please file an issue." - ); -} // Hydration (when unsupported) -var isSuspenseInstancePending = shim; -var isSuspenseInstanceFallback = shim; -var getSuspenseInstanceFallbackErrorDetails = shim; -var registerSuspenseInstanceRetry = shim; -var errorHydratingContainer = shim; + if (fiber.alternate) { + fiber.alternate.pendingProps = fiber.pendingProps; + } -var _nativeFabricUIManage = nativeFabricUIManager, - createNode = _nativeFabricUIManage.createNode, - cloneNode = _nativeFabricUIManage.cloneNode, - cloneNodeWithNewChildren = _nativeFabricUIManage.cloneNodeWithNewChildren, - cloneNodeWithNewChildrenAndProps = - _nativeFabricUIManage.cloneNodeWithNewChildrenAndProps, - cloneNodeWithNewProps = _nativeFabricUIManage.cloneNodeWithNewProps, - createChildNodeSet = _nativeFabricUIManage.createChildSet, - appendChildNode = _nativeFabricUIManage.appendChild, - appendChildNodeToSet = _nativeFabricUIManage.appendChildToSet, - completeRoot = _nativeFabricUIManage.completeRoot, - registerEventHandler = _nativeFabricUIManage.registerEventHandler, - FabricDefaultPriority = _nativeFabricUIManage.unstable_DefaultEventPriority, - FabricDiscretePriority = _nativeFabricUIManage.unstable_DiscreteEventPriority, - fabricGetCurrentEventPriority = - _nativeFabricUIManage.unstable_getCurrentEventPriority; -var getViewConfigForType = - ReactNativePrivateInterface.ReactNativeViewConfigRegistry.get; // Counter for uniquely identifying views. -// % 10 === 1 means it is a rootTag. -// % 2 === 0 means it is a Fabric tag. -// This means that they never overlap. + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); -var nextReactTag = 2; // TODO: Remove this conditional once all changes have propagated. + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); + } + }; -if (registerEventHandler) { - /** - * Register the event emitter with the native bridge - */ - registerEventHandler(dispatchEvent); -} -function appendInitialChild(parentInstance, child) { - appendChildNode(parentInstance.node, child.node); -} -function createInstance( - type, - props, - rootContainerInstance, - hostContext, - internalInstanceHandle -) { - var tag = nextReactTag; - nextReactTag += 2; - var viewConfig = getViewConfigForType(type); + overridePropsRenamePath = function (fiber, oldPath, newPath) { + fiber.pendingProps = copyWithRename(fiber.memoizedProps, oldPath, newPath); - { - for (var key in viewConfig.validAttributes) { - if (props.hasOwnProperty(key)) { - ReactNativePrivateInterface.deepFreezeAndThrowOnMutationInDev( - props[key] - ); - } + if (fiber.alternate) { + fiber.alternate.pendingProps = fiber.pendingProps; } - } - var updatePayload = create(props, viewConfig.validAttributes); - var node = createNode( - tag, // reactTag - viewConfig.uiViewClassName, // viewName - rootContainerInstance, // rootTag - updatePayload, // props - internalInstanceHandle // internalInstanceHandle - ); - var component = createPublicInstance(tag, viewConfig, internalInstanceHandle); - return { - node: node, - canonical: { - nativeTag: tag, - viewConfig: viewConfig, - currentProps: props, - internalInstanceHandle: internalInstanceHandle, - publicInstance: component + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); } }; -} -function createTextInstance( - text, - rootContainerInstance, - hostContext, - internalInstanceHandle -) { - { - if (!hostContext.isInAParentText) { - error("Text strings must be rendered within a component."); + + scheduleUpdate = function (fiber) { + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); } - } + }; - var tag = nextReactTag; - nextReactTag += 2; - var node = createNode( - tag, // reactTag - "RCTRawText", // viewName - rootContainerInstance, // rootTag - { - text: text - }, // props - internalInstanceHandle // instance handle - ); - return { - node: node + setErrorHandler = function (newShouldErrorImpl) { + shouldErrorImpl = newShouldErrorImpl; }; -} -function getRootHostContext(rootContainerInstance) { - return { - isInAParentText: false + + setSuspenseHandler = function (newShouldSuspendImpl) { + shouldSuspendImpl = newShouldSuspendImpl; }; } -function getChildHostContext(parentHostContext, type) { - var prevIsInAParentText = parentHostContext.isInAParentText; - var isInAParentText = - type === "AndroidTextInput" || // Android - type === "RCTMultilineTextInputView" || // iOS - type === "RCTSinglelineTextInputView" || // iOS - type === "RCTText" || - type === "RCTVirtualText"; // TODO: If this is an offscreen host container, we should reuse the - // parent context. - if (prevIsInAParentText !== isInAParentText) { - return { - isInAParentText: isInAParentText - }; - } else { - return parentHostContext; - } -} -function getPublicInstance(instance) { - if (instance.canonical != null && instance.canonical.publicInstance != null) { - return instance.canonical.publicInstance; - } // For compatibility with the legacy renderer, in case it's used with Fabric - // in the same app. - // $FlowExpectedError[prop-missing] +function findHostInstanceByFiber(fiber) { + var hostFiber = findCurrentHostFiber(fiber); - if (instance._nativeTag != null) { - // $FlowExpectedError[incompatible-return] - return instance; + if (hostFiber === null) { + return null; } + return hostFiber.stateNode; +} + +function emptyFindFiberByHostInstance(instance) { return null; } -function getPublicInstanceFromInternalInstanceHandle(internalInstanceHandle) { - var instance = internalInstanceHandle.stateNode; - return getPublicInstance(instance); + +function getCurrentFiberForDevTools() { + return current; } -function prepareUpdate(instance, type, oldProps, newProps, hostContext) { - var viewConfig = instance.canonical.viewConfig; - var updatePayload = diff(oldProps, newProps, viewConfig.validAttributes); // TODO: If the event handlers have changed, we need to update the current props - // in the commit phase but there is no host config hook to do it yet. - // So instead we hack it by updating it in the render phase. - instance.canonical.currentProps = newProps; - return updatePayload; +function injectIntoDevTools(devToolsConfig) { + var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; + var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher; + return injectInternals({ + bundleType: devToolsConfig.bundleType, + version: devToolsConfig.version, + rendererPackageName: devToolsConfig.rendererPackageName, + rendererConfig: devToolsConfig.rendererConfig, + overrideHookState: overrideHookState, + overrideHookStateDeletePath: overrideHookStateDeletePath, + overrideHookStateRenamePath: overrideHookStateRenamePath, + overrideProps: overrideProps, + overridePropsDeletePath: overridePropsDeletePath, + overridePropsRenamePath: overridePropsRenamePath, + setErrorHandler: setErrorHandler, + setSuspenseHandler: setSuspenseHandler, + scheduleUpdate: scheduleUpdate, + currentDispatcherRef: ReactCurrentDispatcher, + findHostInstanceByFiber: findHostInstanceByFiber, + findFiberByHostInstance: + findFiberByHostInstance || emptyFindFiberByHostInstance, + // React Refresh + findHostInstancesForRefresh: findHostInstancesForRefresh, + scheduleRefresh: scheduleRefresh, + scheduleRoot: scheduleRoot, + setRefreshHandler: setRefreshHandler, + // Enables DevTools to append owner stacks to error messages in DEV mode. + getCurrentFiber: getCurrentFiberForDevTools, + // Enables DevTools to detect reconciler version rather than renderer version + // which may not match for third party renderers. + reconcilerVersion: ReactVersion + }); } -function shouldSetTextContent(type, props) { - // TODO (bvaughn) Revisit this decision. - // Always returning false simplifies the createInstance() implementation, - // But creates an additional child Fiber for raw text children. - // No additional native views are created though. - // It's not clear to me which is better so I'm deferring for now. - // More context @ github.com/facebook/react/pull/8560#discussion_r92111303 - return false; + +var instanceCache = new Map(); + +function getInstanceFromTag(tag) { + return instanceCache.get(tag) || null; } -function getCurrentEventPriority() { - var currentEventPriority = fabricGetCurrentEventPriority - ? fabricGetCurrentEventPriority() - : null; - if (currentEventPriority != null) { - switch (currentEventPriority) { - case FabricDiscretePriority: - return DiscreteEventPriority; +var ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner; +function findHostInstance_DEPRECATED(componentOrHandle) { + { + var owner = ReactCurrentOwner.current; + + if (owner !== null && owner.stateNode !== null) { + if (!owner.stateNode._warnedAboutRefsInRender) { + error( + "%s is accessing findNodeHandle inside its render(). " + + "render() should be a pure function of props and state. It should " + + "never access something that requires stale data from the previous " + + "render, such as refs. Move this logic to componentDidMount and " + + "componentDidUpdate instead.", + getComponentNameFromType(owner.type) || "A component" + ); + } - case FabricDefaultPriority: - default: - return DefaultEventPriority; + owner.stateNode._warnedAboutRefsInRender = true; } } - return DefaultEventPriority; -} // The Fabric renderer is secondary to the existing React Native renderer. - -var isPrimaryRenderer = false; // The Fabric renderer shouldn't trigger missing act() warnings + if (componentOrHandle == null) { + return null; + } // For compatibility with Fabric instances -var warnsIfNotActing = false; -var scheduleTimeout = setTimeout; -var cancelTimeout = clearTimeout; -var noTimeout = -1; // ------------------- -function cloneInstance( - instance, - updatePayload, - type, - oldProps, - newProps, - internalInstanceHandle, - keepChildren, - recyclableInstance -) { - var node = instance.node; - var clone; + if ( + componentOrHandle.canonical && + componentOrHandle.canonical.publicInstance + ) { + // $FlowExpectedError[incompatible-return] Can't refine componentOrHandle as a Fabric instance + return componentOrHandle.canonical.publicInstance; + } // For compatibility with legacy renderer instances - if (keepChildren) { - if (updatePayload !== null) { - clone = cloneNodeWithNewProps(node, updatePayload); - } else { - clone = cloneNode(node); - } - } else { - if (updatePayload !== null) { - clone = cloneNodeWithNewChildrenAndProps(node, updatePayload); - } else { - clone = cloneNodeWithNewChildren(node); - } + if (componentOrHandle._nativeTag) { + // $FlowFixMe[incompatible-exact] Necessary when running Flow on Fabric + // $FlowFixMe[incompatible-return] + return componentOrHandle; } - return { - node: clone, - canonical: instance.canonical - }; + var hostInstance; + + { + hostInstance = findHostInstanceWithWarning( + componentOrHandle, + "findHostInstance_DEPRECATED" + ); + } // findHostInstance handles legacy vs. Fabric differences correctly + // $FlowFixMe[incompatible-exact] we need to fix the definition of `HostComponent` to use NativeMethods as an interface, not as a type. + // $FlowFixMe[incompatible-return] + + return hostInstance; } -function cloneHiddenInstance(instance, type, props, internalInstanceHandle) { - var viewConfig = instance.canonical.viewConfig; - var node = instance.node; - var updatePayload = create( - { - style: { - display: "none" +function findNodeHandle(componentOrHandle) { + { + var owner = ReactCurrentOwner.current; + + if (owner !== null && owner.stateNode !== null) { + if (!owner.stateNode._warnedAboutRefsInRender) { + error( + "%s is accessing findNodeHandle inside its render(). " + + "render() should be a pure function of props and state. It should " + + "never access something that requires stale data from the previous " + + "render, such as refs. Move this logic to componentDidMount and " + + "componentDidUpdate instead.", + getComponentNameFromType(owner.type) || "A component" + ); } - }, - viewConfig.validAttributes - ); - return { - node: cloneNodeWithNewProps(node, updatePayload), - canonical: instance.canonical - }; -} -function cloneHiddenTextInstance(instance, text, internalInstanceHandle) { - throw new Error("Not yet implemented."); -} -function createContainerChildSet(container) { - return createChildNodeSet(container); -} -function appendChildToContainerChildSet(childSet, child) { - appendChildNodeToSet(childSet, child.node); -} -function finalizeContainerChildren(container, newChildren) { - completeRoot(container, newChildren); -} -function replaceContainerChildren(container, newChildren) {} -function preloadInstance(type, props) { - return true; -} -function waitForCommitToBeReady() { - return null; -} -// This is ok in DOM because they types are interchangeable, but in React Native -// they aren't. + owner.stateNode._warnedAboutRefsInRender = true; + } + } -function getInstanceFromNode(node) { - var instance = node; // In React Native, node is never a text instance + if (componentOrHandle == null) { + return null; + } + + if (typeof componentOrHandle === "number") { + // Already a node handle + return componentOrHandle; + } // For compatibility with legacy renderer instances + + if (componentOrHandle._nativeTag) { + return componentOrHandle._nativeTag; + } // For compatibility with Fabric instances if ( - instance.canonical != null && - instance.canonical.internalInstanceHandle != null + componentOrHandle.canonical != null && + componentOrHandle.canonical.nativeTag != null ) { - return instance.canonical.internalInstanceHandle; - } // $FlowFixMe[incompatible-return] DevTools incorrectly passes a fiber in React Native. + return componentOrHandle.canonical.nativeTag; + } // For compatibility with Fabric public instances - return node; -} + var nativeTag = + ReactNativePrivateInterface.getNativeTagFromPublicInstance( + componentOrHandle + ); -function getNodeFromInstance(fiber) { - var publicInstance = getPublicInstance(fiber.stateNode); + if (nativeTag) { + return nativeTag; + } - if (publicInstance == null) { - throw new Error("Could not find host instance from fiber"); + var hostInstance; + + { + hostInstance = findHostInstanceWithWarning( + componentOrHandle, + "findNodeHandle" + ); } - return publicInstance; -} + if (hostInstance == null) { + return hostInstance; + } // $FlowFixMe[incompatible-type] For compatibility with legacy renderer instances -function getFiberCurrentPropsFromNode(instance) { - return instance.canonical.currentProps; + if (hostInstance._nativeTag != null) { + return hostInstance._nativeTag; + } // $FlowFixMe[incompatible-call] Necessary when running Flow on the legacy renderer + + return ReactNativePrivateInterface.getNativeTagFromPublicInstance( + hostInstance + ); } +function dispatchCommand(handle, command, args) { + var nativeTag = + handle._nativeTag != null + ? handle._nativeTag + : ReactNativePrivateInterface.getNativeTagFromPublicInstance(handle); -var ReactFabricGlobalResponderHandler = { - onChange: function (from, to, blockNativeResponder) { - if (from && from.stateNode) { - // equivalent to clearJSResponder - nativeFabricUIManager.setIsJSResponder( - from.stateNode.node, - false, - blockNativeResponder || false + if (nativeTag == null) { + { + error( + "dispatchCommand was called with a ref that isn't a " + + "native component. Use React.forwardRef to get access to the underlying native component" ); } - if (to && to.stateNode) { - // equivalent to setJSResponder - nativeFabricUIManager.setIsJSResponder( - to.stateNode.node, - true, - blockNativeResponder || false + return; + } + + var node = ReactNativePrivateInterface.getNodeFromPublicInstance(handle); + + if (node != null) { + nativeFabricUIManager.dispatchCommand(node, command, args); + } else { + ReactNativePrivateInterface.UIManager.dispatchViewManagerCommand( + nativeTag, + command, + args + ); + } +} +function sendAccessibilityEvent(handle, eventType) { + var nativeTag = + handle._nativeTag != null + ? handle._nativeTag + : ReactNativePrivateInterface.getNativeTagFromPublicInstance(handle); + + if (nativeTag == null) { + { + error( + "sendAccessibilityEvent was called with a ref that isn't a " + + "native component. Use React.forwardRef to get access to the underlying native component" ); } - } -}; -setComponentTree( - getFiberCurrentPropsFromNode, - getInstanceFromNode, - getNodeFromInstance -); -ResponderEventPlugin.injection.injectGlobalResponderHandler( - ReactFabricGlobalResponderHandler -); + return; + } -var instanceCache = new Map(); + var node = ReactNativePrivateInterface.getNodeFromPublicInstance(handle); -function getInstanceFromTag(tag) { - return instanceCache.get(tag) || null; + if (node != null) { + nativeFabricUIManager.sendAccessibilityEvent(node, eventType); + } else { + ReactNativePrivateInterface.legacySendAccessibilityEvent( + nativeTag, + eventType + ); + } +} +function getNodeFromInternalInstanceHandle(internalInstanceHandle) { + return ( + // $FlowExpectedError[incompatible-return] internalInstanceHandle is opaque but we need to make an exception here. + internalInstanceHandle && // $FlowExpectedError[incompatible-return] + internalInstanceHandle.stateNode && // $FlowExpectedError[incompatible-use] + internalInstanceHandle.stateNode.node + ); } var emptyObject = {}; @@ -27953,7 +27799,8 @@ function getInspectorDataForViewAtPoint( ) { { var closestInstance = null; - var fabricNode = getNodeFromPublicInstance(inspectedView); + var fabricNode = + ReactNativePrivateInterface.getNodeFromPublicInstance(inspectedView); if (fabricNode) { // For Fabric we can look up the instance handle directly and measure it. @@ -28093,7 +27940,7 @@ function createPortal(children, containerTag) { return createPortal$1(children, containerTag, null, key); } -setBatchingImplementation(batchedUpdates$1); +setBatchingImplementation(batchedUpdates); var roots = new Map(); injectIntoDevTools({ // $FlowExpectedError[incompatible-call] The type of `Instance` in `getClosestInstanceFromNode` does not match in Fabric and the legacy renderer, so it fails to typecheck here. diff --git a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-prod.fb.js b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-prod.fb.js index 1ba3ea558599a..9670256197d8f 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-prod.fb.js +++ b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-prod.fb.js @@ -1235,10 +1235,434 @@ function diffProperties(updatePayload, prevProps, nextProps, validAttributes) { ))))); return updatePayload; } -var ReactSharedInternals = +function batchedUpdatesImpl(fn, bookkeeping) { + return fn(bookkeeping); +} +var isInsideEventHandler = !1; +function batchedUpdates$1(fn, bookkeeping) { + if (isInsideEventHandler) return fn(bookkeeping); + isInsideEventHandler = !0; + try { + return batchedUpdatesImpl(fn, bookkeeping); + } finally { + isInsideEventHandler = !1; + } +} +var eventQueue = null; +function executeDispatchesAndReleaseTopLevel(e) { + if (e) { + var dispatchListeners = e._dispatchListeners, + dispatchInstances = e._dispatchInstances; + if (isArrayImpl(dispatchListeners)) + for ( + var i = 0; + i < dispatchListeners.length && !e.isPropagationStopped(); + i++ + ) + executeDispatch(e, dispatchListeners[i], dispatchInstances[i]); + else + dispatchListeners && + executeDispatch(e, dispatchListeners, dispatchInstances); + e._dispatchListeners = null; + e._dispatchInstances = null; + e.isPersistent() || e.constructor.release(e); + } +} +function dispatchEvent(target, topLevelType, nativeEvent) { + var eventTarget = null; + if (null != target) { + var stateNode = target.stateNode; + null != stateNode && (eventTarget = getPublicInstance(stateNode)); + } + batchedUpdates$1(function () { + var event = { eventName: topLevelType, nativeEvent: nativeEvent }; + ReactNativePrivateInterface.RawEventEmitter.emit(topLevelType, event); + ReactNativePrivateInterface.RawEventEmitter.emit("*", event); + event = eventTarget; + for ( + var events = null, legacyPlugins = plugins, i = 0; + i < legacyPlugins.length; + i++ + ) { + var possiblePlugin = legacyPlugins[i]; + possiblePlugin && + (possiblePlugin = possiblePlugin.extractEvents( + topLevelType, + target, + nativeEvent, + event + )) && + (events = accumulateInto(events, possiblePlugin)); + } + event = events; + null !== event && (eventQueue = accumulateInto(eventQueue, event)); + event = eventQueue; + eventQueue = null; + if (event) { + forEachAccumulated(event, executeDispatchesAndReleaseTopLevel); + if (eventQueue) + throw Error( + "processEventQueue(): Additional events were enqueued while processing an event queue. Support for this has not yet been implemented." + ); + if (hasRethrowError) + throw ( + ((event = rethrowError), + (hasRethrowError = !1), + (rethrowError = null), + event) + ); + } + }); +} +var enableUseRefAccessWarning = dynamicFlags.enableUseRefAccessWarning, + scheduleCallback$1 = Scheduler.unstable_scheduleCallback, + cancelCallback$1 = Scheduler.unstable_cancelCallback, + shouldYield = Scheduler.unstable_shouldYield, + requestPaint = Scheduler.unstable_requestPaint, + now = Scheduler.unstable_now, + ImmediatePriority = Scheduler.unstable_ImmediatePriority, + UserBlockingPriority = Scheduler.unstable_UserBlockingPriority, + NormalPriority = Scheduler.unstable_NormalPriority, + IdlePriority = Scheduler.unstable_IdlePriority, + ReactSharedInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, - enableUseRefAccessWarning = dynamicFlags.enableUseRefAccessWarning, - REACT_ELEMENT_TYPE = Symbol.for("react.element"), + rendererID = null, + injectedHook = null; +function onCommitRoot(root) { + if (injectedHook && "function" === typeof injectedHook.onCommitFiberRoot) + try { + injectedHook.onCommitFiberRoot( + rendererID, + root, + void 0, + 128 === (root.current.flags & 128) + ); + } catch (err) {} +} +var clz32 = Math.clz32 ? Math.clz32 : clz32Fallback, + log = Math.log, + LN2 = Math.LN2; +function clz32Fallback(x) { + x >>>= 0; + return 0 === x ? 32 : (31 - ((log(x) / LN2) | 0)) | 0; +} +var nextTransitionLane = 128, + nextRetryLane = 8388608; +function getHighestPriorityLanes(lanes) { + switch (lanes & -lanes) { + case 1: + return 1; + case 2: + return 2; + case 4: + return 4; + case 8: + return 8; + case 16: + return 16; + case 32: + return 32; + case 64: + return 64; + case 128: + case 256: + case 512: + case 1024: + case 2048: + case 4096: + case 8192: + case 16384: + case 32768: + case 65536: + case 131072: + case 262144: + case 524288: + case 1048576: + case 2097152: + case 4194304: + return lanes & 8388480; + case 8388608: + case 16777216: + case 33554432: + case 67108864: + return lanes & 125829120; + case 134217728: + return 134217728; + case 268435456: + return 268435456; + case 536870912: + return 536870912; + case 1073741824: + return 1073741824; + default: + return lanes; + } +} +function getNextLanes(root, wipLanes) { + var pendingLanes = root.pendingLanes; + if (0 === pendingLanes) return 0; + var nextLanes = 0, + suspendedLanes = root.suspendedLanes, + pingedLanes = root.pingedLanes, + nonIdlePendingLanes = pendingLanes & 268435455; + if (0 !== nonIdlePendingLanes) { + var nonIdleUnblockedLanes = nonIdlePendingLanes & ~suspendedLanes; + 0 !== nonIdleUnblockedLanes + ? (nextLanes = getHighestPriorityLanes(nonIdleUnblockedLanes)) + : ((pingedLanes &= nonIdlePendingLanes), + 0 !== pingedLanes && + (nextLanes = getHighestPriorityLanes(pingedLanes))); + } else + (nonIdlePendingLanes = pendingLanes & ~suspendedLanes), + 0 !== nonIdlePendingLanes + ? (nextLanes = getHighestPriorityLanes(nonIdlePendingLanes)) + : 0 !== pingedLanes && + (nextLanes = getHighestPriorityLanes(pingedLanes)); + if (0 === nextLanes) return 0; + if ( + 0 !== wipLanes && + wipLanes !== nextLanes && + 0 === (wipLanes & suspendedLanes) && + ((suspendedLanes = nextLanes & -nextLanes), + (pingedLanes = wipLanes & -wipLanes), + suspendedLanes >= pingedLanes || + (32 === suspendedLanes && 0 !== (pingedLanes & 8388480))) + ) + return wipLanes; + 0 === (root.current.mode & 32) && + 0 !== (nextLanes & 8) && + (nextLanes |= pendingLanes & 32); + wipLanes = root.entangledLanes; + if (0 !== wipLanes) + for (root = root.entanglements, wipLanes &= nextLanes; 0 < wipLanes; ) + (pendingLanes = 31 - clz32(wipLanes)), + (suspendedLanes = 1 << pendingLanes), + (nextLanes |= root[pendingLanes]), + (wipLanes &= ~suspendedLanes); + return nextLanes; +} +function computeExpirationTime(lane, currentTime) { + switch (lane) { + case 1: + case 2: + case 4: + case 8: + return currentTime + 250; + case 16: + case 32: + case 64: + case 128: + case 256: + case 512: + case 1024: + case 2048: + case 4096: + case 8192: + case 16384: + case 32768: + case 65536: + case 131072: + case 262144: + case 524288: + case 1048576: + case 2097152: + case 4194304: + return currentTime + 5e3; + case 8388608: + case 16777216: + case 33554432: + case 67108864: + return -1; + case 134217728: + case 268435456: + case 536870912: + case 1073741824: + return -1; + default: + return -1; + } +} +function getLanesToRetrySynchronouslyOnError(root, originallyAttemptedLanes) { + if (root.errorRecoveryDisabledLanes & originallyAttemptedLanes) return 0; + root = root.pendingLanes & -1073741825; + return 0 !== root ? root : root & 1073741824 ? 1073741824 : 0; +} +function includesBlockingLane(root, lanes) { + return 0 !== (root.current.mode & 32) ? !1 : 0 !== (lanes & 60); +} +function claimNextTransitionLane() { + var lane = nextTransitionLane; + nextTransitionLane <<= 1; + 0 === (nextTransitionLane & 8388480) && (nextTransitionLane = 128); + return lane; +} +function claimNextRetryLane() { + var lane = nextRetryLane; + nextRetryLane <<= 1; + 0 === (nextRetryLane & 125829120) && (nextRetryLane = 8388608); + return lane; +} +function createLaneMap(initial) { + for (var laneMap = [], i = 0; 31 > i; i++) laneMap.push(initial); + return laneMap; +} +function markRootUpdated(root, updateLane, eventTime) { + root.pendingLanes |= updateLane; + 536870912 !== updateLane && + ((root.suspendedLanes = 0), (root.pingedLanes = 0)); + root = root.eventTimes; + updateLane = 31 - clz32(updateLane); + root[updateLane] = eventTime; +} +function markRootFinished(root, remainingLanes) { + var noLongerPendingLanes = root.pendingLanes & ~remainingLanes; + root.pendingLanes = remainingLanes; + root.suspendedLanes = 0; + root.pingedLanes = 0; + root.expiredLanes &= remainingLanes; + root.mutableReadLanes &= remainingLanes; + root.entangledLanes &= remainingLanes; + root.errorRecoveryDisabledLanes &= remainingLanes; + remainingLanes = root.entanglements; + var eventTimes = root.eventTimes, + expirationTimes = root.expirationTimes; + for (root = root.hiddenUpdates; 0 < noLongerPendingLanes; ) { + var index$6 = 31 - clz32(noLongerPendingLanes), + lane = 1 << index$6; + remainingLanes[index$6] = 0; + eventTimes[index$6] = -1; + expirationTimes[index$6] = -1; + var hiddenUpdatesForLane = root[index$6]; + if (null !== hiddenUpdatesForLane) + for ( + root[index$6] = null, index$6 = 0; + index$6 < hiddenUpdatesForLane.length; + index$6++ + ) { + var update = hiddenUpdatesForLane[index$6]; + null !== update && (update.lane &= -1073741825); + } + noLongerPendingLanes &= ~lane; + } +} +function markRootEntangled(root, entangledLanes) { + var rootEntangledLanes = (root.entangledLanes |= entangledLanes); + for (root = root.entanglements; rootEntangledLanes; ) { + var index$7 = 31 - clz32(rootEntangledLanes), + lane = 1 << index$7; + (lane & entangledLanes) | (root[index$7] & entangledLanes) && + (root[index$7] |= entangledLanes); + rootEntangledLanes &= ~lane; + } +} +var currentUpdatePriority = 0; +function lanesToEventPriority(lanes) { + lanes &= -lanes; + return 2 < lanes + ? 8 < lanes + ? 0 !== (lanes & 268435455) + ? 32 + : 536870912 + : 8 + : 2; +} +function shim() { + throw Error( + "The current renderer does not support hydration. This error is likely caused by a bug in React. Please file an issue." + ); +} +var _nativeFabricUIManage = nativeFabricUIManager, + createNode = _nativeFabricUIManage.createNode, + cloneNode = _nativeFabricUIManage.cloneNode, + cloneNodeWithNewChildren = _nativeFabricUIManage.cloneNodeWithNewChildren, + cloneNodeWithNewChildrenAndProps = + _nativeFabricUIManage.cloneNodeWithNewChildrenAndProps, + cloneNodeWithNewProps = _nativeFabricUIManage.cloneNodeWithNewProps, + createChildNodeSet = _nativeFabricUIManage.createChildSet, + appendChildNode = _nativeFabricUIManage.appendChild, + appendChildNodeToSet = _nativeFabricUIManage.appendChildToSet, + completeRoot = _nativeFabricUIManage.completeRoot, + registerEventHandler = _nativeFabricUIManage.registerEventHandler, + FabricDiscretePriority = _nativeFabricUIManage.unstable_DiscreteEventPriority, + fabricGetCurrentEventPriority = + _nativeFabricUIManage.unstable_getCurrentEventPriority, + getViewConfigForType = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.get, + nextReactTag = 2; +registerEventHandler && registerEventHandler(dispatchEvent); +function createTextInstance( + text, + rootContainerInstance, + hostContext, + internalInstanceHandle +) { + hostContext = nextReactTag; + nextReactTag += 2; + return { + node: createNode( + hostContext, + "RCTRawText", + rootContainerInstance, + { text: text }, + internalInstanceHandle + ) + }; +} +function getPublicInstance(instance) { + return null != instance.canonical && null != instance.canonical.publicInstance + ? instance.canonical.publicInstance + : null != instance._nativeTag + ? instance + : null; +} +var scheduleTimeout = setTimeout, + cancelTimeout = clearTimeout; +function cloneHiddenInstance(instance) { + var node = instance.node; + var JSCompiler_inline_result = diffProperties( + null, + emptyObject$1, + { style: { display: "none" } }, + instance.canonical.viewConfig.validAttributes + ); + return { + node: cloneNodeWithNewProps(node, JSCompiler_inline_result), + canonical: instance.canonical + }; +} +function getInstanceFromNode(node) { + return null != node.canonical && null != node.canonical.internalInstanceHandle + ? node.canonical.internalInstanceHandle + : node; +} +getFiberCurrentPropsFromNode$1 = function (instance) { + return instance.canonical.currentProps; +}; +getInstanceFromNode$1 = getInstanceFromNode; +getNodeFromInstance$1 = function (fiber) { + fiber = getPublicInstance(fiber.stateNode); + if (null == fiber) throw Error("Could not find host instance from fiber"); + return fiber; +}; +ResponderEventPlugin.injection.injectGlobalResponderHandler({ + onChange: function (from, to, blockNativeResponder) { + from && + from.stateNode && + nativeFabricUIManager.setIsJSResponder( + from.stateNode.node, + !1, + blockNativeResponder || !1 + ); + to && + to.stateNode && + nativeFabricUIManager.setIsJSResponder( + to.stateNode.node, + !0, + blockNativeResponder || !1 + ); + } +}); +var REACT_ELEMENT_TYPE = Symbol.for("react.element"), REACT_PORTAL_TYPE = Symbol.for("react.portal"), REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"), REACT_STRICT_MODE_TYPE = Symbol.for("react.strict_mode"), @@ -1429,422 +1853,173 @@ function findCurrentFiberUsingSlowPath(fiber) { } if (a.return !== b.return) (a = parentA), (b = parentB); else { - for (var didFindChild = !1, child$2 = parentA.child; child$2; ) { - if (child$2 === a) { + for (var didFindChild = !1, child$8 = parentA.child; child$8; ) { + if (child$8 === a) { didFindChild = !0; a = parentA; b = parentB; - break; - } - if (child$2 === b) { - didFindChild = !0; - b = parentA; - a = parentB; - break; - } - child$2 = child$2.sibling; - } - if (!didFindChild) { - for (child$2 = parentB.child; child$2; ) { - if (child$2 === a) { - didFindChild = !0; - a = parentB; - b = parentA; - break; - } - if (child$2 === b) { - didFindChild = !0; - b = parentB; - a = parentA; - break; - } - child$2 = child$2.sibling; - } - if (!didFindChild) - throw Error( - "Child was not found in either parent set. This indicates a bug in React related to the return pointer. Please file an issue." - ); - } - } - if (a.alternate !== b) - throw Error( - "Return fibers should always be each others' alternates. This error is likely caused by a bug in React. Please file an issue." - ); - } - if (3 !== a.tag) - throw Error("Unable to find node on an unmounted component."); - return a.stateNode.current === a ? fiber : alternate; -} -function findCurrentHostFiber(parent) { - parent = findCurrentFiberUsingSlowPath(parent); - return null !== parent ? findCurrentHostFiberImpl(parent) : null; -} -function findCurrentHostFiberImpl(node) { - var tag = node.tag; - if (5 === tag || 26 === tag || 27 === tag || 6 === tag) return node; - for (node = node.child; null !== node; ) { - tag = findCurrentHostFiberImpl(node); - if (null !== tag) return tag; - node = node.sibling; - } - return null; -} -function describeComponentFrame(name, source, ownerName) { - source = ""; - ownerName && (source = " (created by " + ownerName + ")"); - return "\n in " + (name || "Unknown") + source; -} -function describeFunctionComponentFrame(fn, source) { - return fn - ? describeComponentFrame(fn.displayName || fn.name || null, source, null) - : ""; -} -var hasOwnProperty = Object.prototype.hasOwnProperty, - valueStack = [], - index = -1; -function createCursor(defaultValue) { - return { current: defaultValue }; -} -function pop(cursor) { - 0 > index || - ((cursor.current = valueStack[index]), (valueStack[index] = null), index--); -} -function push(cursor, value) { - index++; - valueStack[index] = cursor.current; - cursor.current = value; -} -var emptyContextObject = {}, - contextStackCursor$1 = createCursor(emptyContextObject), - didPerformWorkStackCursor = createCursor(!1), - previousContext = emptyContextObject; -function getMaskedContext(workInProgress, unmaskedContext) { - var contextTypes = workInProgress.type.contextTypes; - if (!contextTypes) return emptyContextObject; - var instance = workInProgress.stateNode; - if ( - instance && - instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext - ) - return instance.__reactInternalMemoizedMaskedChildContext; - var context = {}, - key; - for (key in contextTypes) context[key] = unmaskedContext[key]; - instance && - ((workInProgress = workInProgress.stateNode), - (workInProgress.__reactInternalMemoizedUnmaskedChildContext = - unmaskedContext), - (workInProgress.__reactInternalMemoizedMaskedChildContext = context)); - return context; -} -function isContextProvider(type) { - type = type.childContextTypes; - return null !== type && void 0 !== type; -} -function popContext() { - pop(didPerformWorkStackCursor); - pop(contextStackCursor$1); -} -function pushTopLevelContextObject(fiber, context, didChange) { - if (contextStackCursor$1.current !== emptyContextObject) - throw Error( - "Unexpected context found on stack. This error is likely caused by a bug in React. Please file an issue." - ); - push(contextStackCursor$1, context); - push(didPerformWorkStackCursor, didChange); -} -function processChildContext(fiber, type, parentContext) { - var instance = fiber.stateNode; - type = type.childContextTypes; - if ("function" !== typeof instance.getChildContext) return parentContext; - instance = instance.getChildContext(); - for (var contextKey in instance) - if (!(contextKey in type)) - throw Error( - (getComponentNameFromFiber(fiber) || "Unknown") + - '.getChildContext(): key "' + - contextKey + - '" is not defined in childContextTypes.' - ); - return assign({}, parentContext, instance); -} -function pushContextProvider(workInProgress) { - workInProgress = - ((workInProgress = workInProgress.stateNode) && - workInProgress.__reactInternalMemoizedMergedChildContext) || - emptyContextObject; - previousContext = contextStackCursor$1.current; - push(contextStackCursor$1, workInProgress); - push(didPerformWorkStackCursor, didPerformWorkStackCursor.current); - return !0; -} -function invalidateContextProvider(workInProgress, type, didChange) { - var instance = workInProgress.stateNode; - if (!instance) - throw Error( - "Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue." - ); - didChange - ? ((workInProgress = processChildContext( - workInProgress, - type, - previousContext - )), - (instance.__reactInternalMemoizedMergedChildContext = workInProgress), - pop(didPerformWorkStackCursor), - pop(contextStackCursor$1), - push(contextStackCursor$1, workInProgress)) - : pop(didPerformWorkStackCursor); - push(didPerformWorkStackCursor, didChange); -} -var clz32 = Math.clz32 ? Math.clz32 : clz32Fallback, - log = Math.log, - LN2 = Math.LN2; -function clz32Fallback(x) { - x >>>= 0; - return 0 === x ? 32 : (31 - ((log(x) / LN2) | 0)) | 0; -} -var nextTransitionLane = 128, - nextRetryLane = 8388608; -function getHighestPriorityLanes(lanes) { - switch (lanes & -lanes) { - case 1: - return 1; - case 2: - return 2; - case 4: - return 4; - case 8: - return 8; - case 16: - return 16; - case 32: - return 32; - case 64: - return 64; - case 128: - case 256: - case 512: - case 1024: - case 2048: - case 4096: - case 8192: - case 16384: - case 32768: - case 65536: - case 131072: - case 262144: - case 524288: - case 1048576: - case 2097152: - case 4194304: - return lanes & 8388480; - case 8388608: - case 16777216: - case 33554432: - case 67108864: - return lanes & 125829120; - case 134217728: - return 134217728; - case 268435456: - return 268435456; - case 536870912: - return 536870912; - case 1073741824: - return 1073741824; - default: - return lanes; + break; + } + if (child$8 === b) { + didFindChild = !0; + b = parentA; + a = parentB; + break; + } + child$8 = child$8.sibling; + } + if (!didFindChild) { + for (child$8 = parentB.child; child$8; ) { + if (child$8 === a) { + didFindChild = !0; + a = parentB; + b = parentA; + break; + } + if (child$8 === b) { + didFindChild = !0; + b = parentB; + a = parentA; + break; + } + child$8 = child$8.sibling; + } + if (!didFindChild) + throw Error( + "Child was not found in either parent set. This indicates a bug in React related to the return pointer. Please file an issue." + ); + } + } + if (a.alternate !== b) + throw Error( + "Return fibers should always be each others' alternates. This error is likely caused by a bug in React. Please file an issue." + ); } + if (3 !== a.tag) + throw Error("Unable to find node on an unmounted component."); + return a.stateNode.current === a ? fiber : alternate; } -function getNextLanes(root, wipLanes) { - var pendingLanes = root.pendingLanes; - if (0 === pendingLanes) return 0; - var nextLanes = 0, - suspendedLanes = root.suspendedLanes, - pingedLanes = root.pingedLanes, - nonIdlePendingLanes = pendingLanes & 268435455; - if (0 !== nonIdlePendingLanes) { - var nonIdleUnblockedLanes = nonIdlePendingLanes & ~suspendedLanes; - 0 !== nonIdleUnblockedLanes - ? (nextLanes = getHighestPriorityLanes(nonIdleUnblockedLanes)) - : ((pingedLanes &= nonIdlePendingLanes), - 0 !== pingedLanes && - (nextLanes = getHighestPriorityLanes(pingedLanes))); - } else - (nonIdlePendingLanes = pendingLanes & ~suspendedLanes), - 0 !== nonIdlePendingLanes - ? (nextLanes = getHighestPriorityLanes(nonIdlePendingLanes)) - : 0 !== pingedLanes && - (nextLanes = getHighestPriorityLanes(pingedLanes)); - if (0 === nextLanes) return 0; - if ( - 0 !== wipLanes && - wipLanes !== nextLanes && - 0 === (wipLanes & suspendedLanes) && - ((suspendedLanes = nextLanes & -nextLanes), - (pingedLanes = wipLanes & -wipLanes), - suspendedLanes >= pingedLanes || - (32 === suspendedLanes && 0 !== (pingedLanes & 8388480))) - ) - return wipLanes; - 0 === (root.current.mode & 32) && - 0 !== (nextLanes & 8) && - (nextLanes |= pendingLanes & 32); - wipLanes = root.entangledLanes; - if (0 !== wipLanes) - for (root = root.entanglements, wipLanes &= nextLanes; 0 < wipLanes; ) - (pendingLanes = 31 - clz32(wipLanes)), - (suspendedLanes = 1 << pendingLanes), - (nextLanes |= root[pendingLanes]), - (wipLanes &= ~suspendedLanes); - return nextLanes; +function findCurrentHostFiber(parent) { + parent = findCurrentFiberUsingSlowPath(parent); + return null !== parent ? findCurrentHostFiberImpl(parent) : null; } -function computeExpirationTime(lane, currentTime) { - switch (lane) { - case 1: - case 2: - case 4: - case 8: - return currentTime + 250; - case 16: - case 32: - case 64: - case 128: - case 256: - case 512: - case 1024: - case 2048: - case 4096: - case 8192: - case 16384: - case 32768: - case 65536: - case 131072: - case 262144: - case 524288: - case 1048576: - case 2097152: - case 4194304: - return currentTime + 5e3; - case 8388608: - case 16777216: - case 33554432: - case 67108864: - return -1; - case 134217728: - case 268435456: - case 536870912: - case 1073741824: - return -1; - default: - return -1; +function findCurrentHostFiberImpl(node) { + var tag = node.tag; + if (5 === tag || 26 === tag || 27 === tag || 6 === tag) return node; + for (node = node.child; null !== node; ) { + tag = findCurrentHostFiberImpl(node); + if (null !== tag) return tag; + node = node.sibling; } + return null; } -function getLanesToRetrySynchronouslyOnError(root, originallyAttemptedLanes) { - if (root.errorRecoveryDisabledLanes & originallyAttemptedLanes) return 0; - root = root.pendingLanes & -1073741825; - return 0 !== root ? root : root & 1073741824 ? 1073741824 : 0; -} -function includesBlockingLane(root, lanes) { - return 0 !== (root.current.mode & 32) ? !1 : 0 !== (lanes & 60); +function describeComponentFrame(name, source, ownerName) { + source = ""; + ownerName && (source = " (created by " + ownerName + ")"); + return "\n in " + (name || "Unknown") + source; } -function claimNextTransitionLane() { - var lane = nextTransitionLane; - nextTransitionLane <<= 1; - 0 === (nextTransitionLane & 8388480) && (nextTransitionLane = 128); - return lane; +function describeFunctionComponentFrame(fn, source) { + return fn + ? describeComponentFrame(fn.displayName || fn.name || null, source, null) + : ""; } -function claimNextRetryLane() { - var lane = nextRetryLane; - nextRetryLane <<= 1; - 0 === (nextRetryLane & 125829120) && (nextRetryLane = 8388608); - return lane; +var hasOwnProperty = Object.prototype.hasOwnProperty, + valueStack = [], + index = -1; +function createCursor(defaultValue) { + return { current: defaultValue }; } -function createLaneMap(initial) { - for (var laneMap = [], i = 0; 31 > i; i++) laneMap.push(initial); - return laneMap; +function pop(cursor) { + 0 > index || + ((cursor.current = valueStack[index]), (valueStack[index] = null), index--); } -function markRootUpdated(root, updateLane, eventTime) { - root.pendingLanes |= updateLane; - 536870912 !== updateLane && - ((root.suspendedLanes = 0), (root.pingedLanes = 0)); - root = root.eventTimes; - updateLane = 31 - clz32(updateLane); - root[updateLane] = eventTime; +function push(cursor, value) { + index++; + valueStack[index] = cursor.current; + cursor.current = value; } -function markRootFinished(root, remainingLanes) { - var noLongerPendingLanes = root.pendingLanes & ~remainingLanes; - root.pendingLanes = remainingLanes; - root.suspendedLanes = 0; - root.pingedLanes = 0; - root.expiredLanes &= remainingLanes; - root.mutableReadLanes &= remainingLanes; - root.entangledLanes &= remainingLanes; - root.errorRecoveryDisabledLanes &= remainingLanes; - remainingLanes = root.entanglements; - var eventTimes = root.eventTimes, - expirationTimes = root.expirationTimes; - for (root = root.hiddenUpdates; 0 < noLongerPendingLanes; ) { - var index$7 = 31 - clz32(noLongerPendingLanes), - lane = 1 << index$7; - remainingLanes[index$7] = 0; - eventTimes[index$7] = -1; - expirationTimes[index$7] = -1; - var hiddenUpdatesForLane = root[index$7]; - if (null !== hiddenUpdatesForLane) - for ( - root[index$7] = null, index$7 = 0; - index$7 < hiddenUpdatesForLane.length; - index$7++ - ) { - var update = hiddenUpdatesForLane[index$7]; - null !== update && (update.lane &= -1073741825); - } - noLongerPendingLanes &= ~lane; - } +var emptyContextObject = {}, + contextStackCursor$1 = createCursor(emptyContextObject), + didPerformWorkStackCursor = createCursor(!1), + previousContext = emptyContextObject; +function getMaskedContext(workInProgress, unmaskedContext) { + var contextTypes = workInProgress.type.contextTypes; + if (!contextTypes) return emptyContextObject; + var instance = workInProgress.stateNode; + if ( + instance && + instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext + ) + return instance.__reactInternalMemoizedMaskedChildContext; + var context = {}, + key; + for (key in contextTypes) context[key] = unmaskedContext[key]; + instance && + ((workInProgress = workInProgress.stateNode), + (workInProgress.__reactInternalMemoizedUnmaskedChildContext = + unmaskedContext), + (workInProgress.__reactInternalMemoizedMaskedChildContext = context)); + return context; } -function markRootEntangled(root, entangledLanes) { - var rootEntangledLanes = (root.entangledLanes |= entangledLanes); - for (root = root.entanglements; rootEntangledLanes; ) { - var index$8 = 31 - clz32(rootEntangledLanes), - lane = 1 << index$8; - (lane & entangledLanes) | (root[index$8] & entangledLanes) && - (root[index$8] |= entangledLanes); - rootEntangledLanes &= ~lane; - } +function isContextProvider(type) { + type = type.childContextTypes; + return null !== type && void 0 !== type; } -var currentUpdatePriority = 0; -function lanesToEventPriority(lanes) { - lanes &= -lanes; - return 2 < lanes - ? 8 < lanes - ? 0 !== (lanes & 268435455) - ? 32 - : 536870912 - : 8 - : 2; +function popContext() { + pop(didPerformWorkStackCursor); + pop(contextStackCursor$1); } -var scheduleCallback$1 = Scheduler.unstable_scheduleCallback, - cancelCallback$1 = Scheduler.unstable_cancelCallback, - shouldYield = Scheduler.unstable_shouldYield, - requestPaint = Scheduler.unstable_requestPaint, - now = Scheduler.unstable_now, - ImmediatePriority = Scheduler.unstable_ImmediatePriority, - UserBlockingPriority = Scheduler.unstable_UserBlockingPriority, - NormalPriority = Scheduler.unstable_NormalPriority, - IdlePriority = Scheduler.unstable_IdlePriority, - rendererID = null, - injectedHook = null; -function onCommitRoot(root) { - if (injectedHook && "function" === typeof injectedHook.onCommitFiberRoot) - try { - injectedHook.onCommitFiberRoot( - rendererID, - root, - void 0, - 128 === (root.current.flags & 128) +function pushTopLevelContextObject(fiber, context, didChange) { + if (contextStackCursor$1.current !== emptyContextObject) + throw Error( + "Unexpected context found on stack. This error is likely caused by a bug in React. Please file an issue." + ); + push(contextStackCursor$1, context); + push(didPerformWorkStackCursor, didChange); +} +function processChildContext(fiber, type, parentContext) { + var instance = fiber.stateNode; + type = type.childContextTypes; + if ("function" !== typeof instance.getChildContext) return parentContext; + instance = instance.getChildContext(); + for (var contextKey in instance) + if (!(contextKey in type)) + throw Error( + (getComponentNameFromFiber(fiber) || "Unknown") + + '.getChildContext(): key "' + + contextKey + + '" is not defined in childContextTypes.' ); - } catch (err) {} + return assign({}, parentContext, instance); +} +function pushContextProvider(workInProgress) { + workInProgress = + ((workInProgress = workInProgress.stateNode) && + workInProgress.__reactInternalMemoizedMergedChildContext) || + emptyContextObject; + previousContext = contextStackCursor$1.current; + push(contextStackCursor$1, workInProgress); + push(didPerformWorkStackCursor, didPerformWorkStackCursor.current); + return !0; +} +function invalidateContextProvider(workInProgress, type, didChange) { + var instance = workInProgress.stateNode; + if (!instance) + throw Error( + "Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue." + ); + didChange + ? ((workInProgress = processChildContext( + workInProgress, + type, + previousContext + )), + (instance.__reactInternalMemoizedMergedChildContext = workInProgress), + pop(didPerformWorkStackCursor), + pop(contextStackCursor$1), + push(contextStackCursor$1, workInProgress)) + : pop(didPerformWorkStackCursor); + push(didPerformWorkStackCursor, didChange); } function is(x, y) { return (x === y && (0 !== x || 1 / x === 1 / y)) || (x !== x && y !== y); @@ -2303,12 +2478,12 @@ function isThenableResolved(thenable) { thenable = thenable.status; return "fulfilled" === thenable || "rejected" === thenable; } -function noop$1() {} +function noop() {} function trackUsedThenable(thenableState, thenable, index) { index = thenableState[index]; void 0 === index ? thenableState.push(thenable) - : index !== thenable && (thenable.then(noop$1, noop$1), (thenable = index)); + : index !== thenable && (thenable.then(noop, noop), (thenable = index)); switch (thenable.status) { case "fulfilled": return thenable.value; @@ -2316,7 +2491,7 @@ function trackUsedThenable(thenableState, thenable, index) { throw thenable.reason; default: "string" === typeof thenable.status - ? thenable.then(noop$1, noop$1) + ? thenable.then(noop, noop) : ((thenableState = thenable), (thenableState.status = "pending"), thenableState.then( @@ -5771,7 +5946,7 @@ function completeWork(current, workInProgress, renderLanes) { recyclableInstance, workInProgress ); - recyclableInstance = new ReactFabricHostComponent( + recyclableInstance = ReactNativePrivateInterface.createPublicInstance( current, renderLanes, workInProgress @@ -7215,12 +7390,12 @@ function ensureRootIsScheduled(root, currentTime) { 0 < lanes; ) { - var index$5 = 31 - clz32(lanes), - lane = 1 << index$5, - expirationTime = expirationTimes[index$5]; + var index$4 = 31 - clz32(lanes), + lane = 1 << index$4, + expirationTime = expirationTimes[index$4]; if (-1 === expirationTime) { if (0 === (lane & suspendedLanes) || 0 !== (lane & pingedLanes)) - expirationTimes[index$5] = computeExpirationTime(lane, currentTime); + expirationTimes[index$4] = computeExpirationTime(lane, currentTime); } else expirationTime <= currentTime && (root.expiredLanes |= lane); lanes &= ~lane; } @@ -7392,10 +7567,10 @@ function performConcurrentWorkOnRoot(root, didTimeout) { exitStatus = lanes; errorRetryLanes = root.eventTimes; for (errorRetryLanes$98 = -1; 0 < exitStatus; ) { - var index$4 = 31 - clz32(exitStatus), - lane = 1 << index$4; - index$4 = errorRetryLanes[index$4]; - index$4 > errorRetryLanes$98 && (errorRetryLanes$98 = index$4); + var index$3 = 31 - clz32(exitStatus), + lane = 1 << index$3; + index$3 = errorRetryLanes[index$3]; + index$3 > errorRetryLanes$98 && (errorRetryLanes$98 = index$3); exitStatus &= ~lane; } exitStatus = errorRetryLanes$98; @@ -7521,9 +7696,9 @@ function markRootSuspended(root, suspendedLanes) { root.suspendedLanes |= suspendedLanes; root.pingedLanes &= ~suspendedLanes; for (root = root.expirationTimes; 0 < suspendedLanes; ) { - var index$6 = 31 - clz32(suspendedLanes), - lane = 1 << index$6; - root[index$6] = -1; + var index$5 = 31 - clz32(suspendedLanes), + lane = 1 << index$5; + root[index$5] = -1; suspendedLanes &= ~lane; } } @@ -9173,264 +9348,20 @@ function findNodeHandle(componentOrHandle) { null != componentOrHandle.canonical.nativeTag ) return componentOrHandle.canonical.nativeTag; - var nativeTag = componentOrHandle.__nativeTag; + var nativeTag = + ReactNativePrivateInterface.getNativeTagFromPublicInstance( + componentOrHandle + ); if (nativeTag) return nativeTag; componentOrHandle = findHostInstance(componentOrHandle); return null == componentOrHandle ? componentOrHandle : null != componentOrHandle._nativeTag ? componentOrHandle._nativeTag - : componentOrHandle.__nativeTag; -} -function getNodeFromInternalInstanceHandle(internalInstanceHandle) { - return ( - internalInstanceHandle && - internalInstanceHandle.stateNode && - internalInstanceHandle.stateNode.node - ); -} -var _nativeFabricUIManage$1 = nativeFabricUIManager, - fabricMeasure = _nativeFabricUIManage$1.measure, - fabricMeasureInWindow = _nativeFabricUIManage$1.measureInWindow, - fabricMeasureLayout = _nativeFabricUIManage$1.measureLayout, - _setNativeProps = _nativeFabricUIManage$1.setNativeProps, - fabricGetBoundingClientRect = _nativeFabricUIManage$1.getBoundingClientRect; -function noop() {} -var ReactFabricHostComponent = (function () { - function ReactFabricHostComponent(tag, viewConfig, internalInstanceHandle) { - this.__nativeTag = tag; - this._viewConfig = viewConfig; - this.__internalInstanceHandle = internalInstanceHandle; - } - var _proto = ReactFabricHostComponent.prototype; - _proto.blur = function () { - ReactNativePrivateInterface.TextInputState.blurTextInput(this); - }; - _proto.focus = function () { - ReactNativePrivateInterface.TextInputState.focusTextInput(this); - }; - _proto.measure = function (callback) { - var node = getNodeFromInternalInstanceHandle(this.__internalInstanceHandle); - null != node && fabricMeasure(node, callback); - }; - _proto.measureInWindow = function (callback) { - var node = getNodeFromInternalInstanceHandle(this.__internalInstanceHandle); - null != node && fabricMeasureInWindow(node, callback); - }; - _proto.measureLayout = function (relativeToNativeNode, onSuccess, onFail) { - if ( - "number" !== typeof relativeToNativeNode && - relativeToNativeNode instanceof ReactFabricHostComponent - ) { - var toStateNode = getNodeFromInternalInstanceHandle( - this.__internalInstanceHandle - ); - relativeToNativeNode = getNodeFromInternalInstanceHandle( - relativeToNativeNode.__internalInstanceHandle + : ReactNativePrivateInterface.getNativeTagFromPublicInstance( + componentOrHandle ); - null != toStateNode && - null != relativeToNativeNode && - fabricMeasureLayout( - toStateNode, - relativeToNativeNode, - null != onFail ? onFail : noop, - null != onSuccess ? onSuccess : noop - ); - } - }; - _proto.unstable_getBoundingClientRect = function () { - var node = getNodeFromInternalInstanceHandle(this.__internalInstanceHandle); - return null != node && (node = fabricGetBoundingClientRect(node)) - ? new DOMRect(node[0], node[1], node[2], node[3]) - : new DOMRect(0, 0, 0, 0); - }; - _proto.setNativeProps = function (nativeProps) { - nativeProps = diffProperties( - null, - emptyObject$1, - nativeProps, - this._viewConfig.validAttributes - ); - var node = getNodeFromInternalInstanceHandle(this.__internalInstanceHandle); - null != node && null != nativeProps && _setNativeProps(node, nativeProps); - }; - return ReactFabricHostComponent; -})(); -function batchedUpdatesImpl(fn, bookkeeping) { - return fn(bookkeeping); -} -var isInsideEventHandler = !1; -function batchedUpdates(fn, bookkeeping) { - if (isInsideEventHandler) return fn(bookkeeping); - isInsideEventHandler = !0; - try { - return batchedUpdatesImpl(fn, bookkeeping); - } finally { - isInsideEventHandler = !1; - } -} -var eventQueue = null; -function executeDispatchesAndReleaseTopLevel(e) { - if (e) { - var dispatchListeners = e._dispatchListeners, - dispatchInstances = e._dispatchInstances; - if (isArrayImpl(dispatchListeners)) - for ( - var i = 0; - i < dispatchListeners.length && !e.isPropagationStopped(); - i++ - ) - executeDispatch(e, dispatchListeners[i], dispatchInstances[i]); - else - dispatchListeners && - executeDispatch(e, dispatchListeners, dispatchInstances); - e._dispatchListeners = null; - e._dispatchInstances = null; - e.isPersistent() || e.constructor.release(e); - } -} -function dispatchEvent(target, topLevelType, nativeEvent) { - var eventTarget = null; - if (null != target) { - var stateNode = target.stateNode; - null != stateNode && (eventTarget = getPublicInstance(stateNode)); - } - batchedUpdates(function () { - var event = { eventName: topLevelType, nativeEvent: nativeEvent }; - ReactNativePrivateInterface.RawEventEmitter.emit(topLevelType, event); - ReactNativePrivateInterface.RawEventEmitter.emit("*", event); - event = eventTarget; - for ( - var events = null, legacyPlugins = plugins, i = 0; - i < legacyPlugins.length; - i++ - ) { - var possiblePlugin = legacyPlugins[i]; - possiblePlugin && - (possiblePlugin = possiblePlugin.extractEvents( - topLevelType, - target, - nativeEvent, - event - )) && - (events = accumulateInto(events, possiblePlugin)); - } - event = events; - null !== event && (eventQueue = accumulateInto(eventQueue, event)); - event = eventQueue; - eventQueue = null; - if (event) { - forEachAccumulated(event, executeDispatchesAndReleaseTopLevel); - if (eventQueue) - throw Error( - "processEventQueue(): Additional events were enqueued while processing an event queue. Support for this has not yet been implemented." - ); - if (hasRethrowError) - throw ( - ((event = rethrowError), - (hasRethrowError = !1), - (rethrowError = null), - event) - ); - } - }); -} -function shim() { - throw Error( - "The current renderer does not support hydration. This error is likely caused by a bug in React. Please file an issue." - ); -} -var _nativeFabricUIManage = nativeFabricUIManager, - createNode = _nativeFabricUIManage.createNode, - cloneNode = _nativeFabricUIManage.cloneNode, - cloneNodeWithNewChildren = _nativeFabricUIManage.cloneNodeWithNewChildren, - cloneNodeWithNewChildrenAndProps = - _nativeFabricUIManage.cloneNodeWithNewChildrenAndProps, - cloneNodeWithNewProps = _nativeFabricUIManage.cloneNodeWithNewProps, - createChildNodeSet = _nativeFabricUIManage.createChildSet, - appendChildNode = _nativeFabricUIManage.appendChild, - appendChildNodeToSet = _nativeFabricUIManage.appendChildToSet, - completeRoot = _nativeFabricUIManage.completeRoot, - registerEventHandler = _nativeFabricUIManage.registerEventHandler, - FabricDiscretePriority = _nativeFabricUIManage.unstable_DiscreteEventPriority, - fabricGetCurrentEventPriority = - _nativeFabricUIManage.unstable_getCurrentEventPriority, - getViewConfigForType = - ReactNativePrivateInterface.ReactNativeViewConfigRegistry.get, - nextReactTag = 2; -registerEventHandler && registerEventHandler(dispatchEvent); -function createTextInstance( - text, - rootContainerInstance, - hostContext, - internalInstanceHandle -) { - hostContext = nextReactTag; - nextReactTag += 2; - return { - node: createNode( - hostContext, - "RCTRawText", - rootContainerInstance, - { text: text }, - internalInstanceHandle - ) - }; -} -function getPublicInstance(instance) { - return null != instance.canonical && null != instance.canonical.publicInstance - ? instance.canonical.publicInstance - : null != instance._nativeTag - ? instance - : null; -} -var scheduleTimeout = setTimeout, - cancelTimeout = clearTimeout; -function cloneHiddenInstance(instance) { - var node = instance.node; - var JSCompiler_inline_result = diffProperties( - null, - emptyObject$1, - { style: { display: "none" } }, - instance.canonical.viewConfig.validAttributes - ); - return { - node: cloneNodeWithNewProps(node, JSCompiler_inline_result), - canonical: instance.canonical - }; } -function getInstanceFromNode(node) { - return null != node.canonical && null != node.canonical.internalInstanceHandle - ? node.canonical.internalInstanceHandle - : node; -} -getFiberCurrentPropsFromNode$1 = function (instance) { - return instance.canonical.currentProps; -}; -getInstanceFromNode$1 = getInstanceFromNode; -getNodeFromInstance$1 = function (fiber) { - fiber = getPublicInstance(fiber.stateNode); - if (null == fiber) throw Error("Could not find host instance from fiber"); - return fiber; -}; -ResponderEventPlugin.injection.injectGlobalResponderHandler({ - onChange: function (from, to, blockNativeResponder) { - from && - from.stateNode && - nativeFabricUIManager.setIsJSResponder( - from.stateNode.node, - !1, - blockNativeResponder || !1 - ); - to && - to.stateNode && - nativeFabricUIManager.setIsJSResponder( - to.stateNode.node, - !0, - blockNativeResponder || !1 - ); - } -}); var emptyObject = {}; function createHierarchy(fiberHierarchy) { return fiberHierarchy.map(function (fiber$jscomp$0) { @@ -9506,7 +9437,7 @@ var roots = new Map(), devToolsConfig$jscomp$inline_1049 = { findFiberByHostInstance: getInstanceFromNode, bundleType: 0, - version: "18.3.0-next-f77099b6f-20230322", + version: "18.3.0-next-9c54b29b4-20230322", rendererPackageName: "react-native-renderer", rendererConfig: { getInspectorDataForViewTag: function () { @@ -9548,7 +9479,7 @@ var internals$jscomp$inline_1292 = { scheduleRoot: null, setRefreshHandler: null, getCurrentFiber: null, - reconcilerVersion: "18.3.0-next-f77099b6f-20230322" + reconcilerVersion: "18.3.0-next-9c54b29b4-20230322" }; if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) { var hook$jscomp$inline_1293 = __REACT_DEVTOOLS_GLOBAL_HOOK__; @@ -9573,12 +9504,11 @@ exports.createPortal = function (children, containerTag) { }; exports.dispatchCommand = function (handle, command, args) { var nativeTag = - null != handle._nativeTag ? handle._nativeTag : handle.__nativeTag; + null != handle._nativeTag + ? handle._nativeTag + : ReactNativePrivateInterface.getNativeTagFromPublicInstance(handle); null != nativeTag && - ((handle = - null == handle.__internalInstanceHandle - ? null - : getNodeFromInternalInstanceHandle(handle.__internalInstanceHandle)), + ((handle = ReactNativePrivateInterface.getNodeFromPublicInstance(handle)), null != handle ? nativeFabricUIManager.dispatchCommand(handle, command, args) : ReactNativePrivateInterface.UIManager.dispatchViewManagerCommand( @@ -9630,7 +9560,13 @@ exports.getInspectorDataForInstance = function (closestInstance) { source: source }; }; -exports.getNodeFromInternalInstanceHandle = getNodeFromInternalInstanceHandle; +exports.getNodeFromInternalInstanceHandle = function (internalInstanceHandle) { + return ( + internalInstanceHandle && + internalInstanceHandle.stateNode && + internalInstanceHandle.stateNode.node + ); +}; exports.getPublicInstanceFromInternalInstanceHandle = function ( internalInstanceHandle ) { @@ -9669,12 +9605,11 @@ exports.render = function (element, containerTag, callback, concurrentRoot) { }; exports.sendAccessibilityEvent = function (handle, eventType) { var nativeTag = - null != handle._nativeTag ? handle._nativeTag : handle.__nativeTag; + null != handle._nativeTag + ? handle._nativeTag + : ReactNativePrivateInterface.getNativeTagFromPublicInstance(handle); null != nativeTag && - ((handle = - null == handle.__internalInstanceHandle - ? null - : getNodeFromInternalInstanceHandle(handle.__internalInstanceHandle)), + ((handle = ReactNativePrivateInterface.getNodeFromPublicInstance(handle)), null != handle ? nativeFabricUIManager.sendAccessibilityEvent(handle, eventType) : ReactNativePrivateInterface.legacySendAccessibilityEvent( diff --git a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-profiling.fb.js b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-profiling.fb.js index 6984e329349e7..326678752733a 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-profiling.fb.js +++ b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-profiling.fb.js @@ -24,9 +24,9 @@ if ( "use strict"; require("react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore"); var ReactNativePrivateInterface = require("react-native/Libraries/ReactPrivate/ReactNativePrivateInterface"), - React = require("react"), dynamicFlags = require("ReactNativeInternalFeatureFlags"), - Scheduler = require("scheduler"); + Scheduler = require("scheduler"), + React = require("react"); function invokeGuardedCallbackImpl(name, func, context) { var funcArgs = Array.prototype.slice.call(arguments, 3); try { @@ -1246,367 +1246,181 @@ function diffProperties(updatePayload, prevProps, nextProps, validAttributes) { ))))); return updatePayload; } -var ReactSharedInternals = - React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, - enableUseRefAccessWarning = dynamicFlags.enableUseRefAccessWarning, - REACT_ELEMENT_TYPE = Symbol.for("react.element"), - REACT_PORTAL_TYPE = Symbol.for("react.portal"), - REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"), - REACT_STRICT_MODE_TYPE = Symbol.for("react.strict_mode"), - REACT_PROFILER_TYPE = Symbol.for("react.profiler"), - REACT_PROVIDER_TYPE = Symbol.for("react.provider"), - REACT_CONTEXT_TYPE = Symbol.for("react.context"), - REACT_SERVER_CONTEXT_TYPE = Symbol.for("react.server_context"), - REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"), - REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"), - REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"), - REACT_MEMO_TYPE = Symbol.for("react.memo"), - REACT_LAZY_TYPE = Symbol.for("react.lazy"); -Symbol.for("react.scope"); -Symbol.for("react.debug_trace_mode"); -var REACT_OFFSCREEN_TYPE = Symbol.for("react.offscreen"), - REACT_LEGACY_HIDDEN_TYPE = Symbol.for("react.legacy_hidden"); -Symbol.for("react.cache"); -Symbol.for("react.tracing_marker"); -var REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED = Symbol.for( - "react.default_value" - ), - REACT_MEMO_CACHE_SENTINEL = Symbol.for("react.memo_cache_sentinel"), - MAYBE_ITERATOR_SYMBOL = Symbol.iterator; -function getIteratorFn(maybeIterable) { - if (null === maybeIterable || "object" !== typeof maybeIterable) return null; - maybeIterable = - (MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL]) || - maybeIterable["@@iterator"]; - return "function" === typeof maybeIterable ? maybeIterable : null; -} -function getComponentNameFromType(type) { - if (null == type) return null; - if ("function" === typeof type) return type.displayName || type.name || null; - if ("string" === typeof type) return type; - switch (type) { - case REACT_FRAGMENT_TYPE: - return "Fragment"; - case REACT_PORTAL_TYPE: - return "Portal"; - case REACT_PROFILER_TYPE: - return "Profiler"; - case REACT_STRICT_MODE_TYPE: - return "StrictMode"; - case REACT_SUSPENSE_TYPE: - return "Suspense"; - case REACT_SUSPENSE_LIST_TYPE: - return "SuspenseList"; - } - if ("object" === typeof type) - switch (type.$$typeof) { - case REACT_CONTEXT_TYPE: - return (type.displayName || "Context") + ".Consumer"; - case REACT_PROVIDER_TYPE: - return (type._context.displayName || "Context") + ".Provider"; - case REACT_FORWARD_REF_TYPE: - var innerType = type.render; - type = type.displayName; - type || - ((type = innerType.displayName || innerType.name || ""), - (type = "" !== type ? "ForwardRef(" + type + ")" : "ForwardRef")); - return type; - case REACT_MEMO_TYPE: - return ( - (innerType = type.displayName || null), - null !== innerType - ? innerType - : getComponentNameFromType(type.type) || "Memo" - ); - case REACT_LAZY_TYPE: - innerType = type._payload; - type = type._init; - try { - return getComponentNameFromType(type(innerType)); - } catch (x) { - break; - } - case REACT_SERVER_CONTEXT_TYPE: - return (type.displayName || type._globalName) + ".Provider"; - } - return null; +function batchedUpdatesImpl(fn, bookkeeping) { + return fn(bookkeeping); } -function getComponentNameFromFiber(fiber) { - var type = fiber.type; - switch (fiber.tag) { - case 24: - return "Cache"; - case 9: - return (type.displayName || "Context") + ".Consumer"; - case 10: - return (type._context.displayName || "Context") + ".Provider"; - case 18: - return "DehydratedFragment"; - case 11: - return ( - (fiber = type.render), - (fiber = fiber.displayName || fiber.name || ""), - type.displayName || - ("" !== fiber ? "ForwardRef(" + fiber + ")" : "ForwardRef") - ); - case 7: - return "Fragment"; - case 26: - case 27: - case 5: - return type; - case 4: - return "Portal"; - case 3: - return "Root"; - case 6: - return "Text"; - case 16: - return getComponentNameFromType(type); - case 8: - return type === REACT_STRICT_MODE_TYPE ? "StrictMode" : "Mode"; - case 22: - return "Offscreen"; - case 12: - return "Profiler"; - case 21: - return "Scope"; - case 13: - return "Suspense"; - case 19: - return "SuspenseList"; - case 25: - return "TracingMarker"; - case 1: - case 0: - case 17: - case 2: - case 14: - case 15: - if ("function" === typeof type) - return type.displayName || type.name || null; - if ("string" === typeof type) return type; - break; - case 23: - return "LegacyHidden"; +var isInsideEventHandler = !1; +function batchedUpdates$1(fn, bookkeeping) { + if (isInsideEventHandler) return fn(bookkeeping); + isInsideEventHandler = !0; + try { + return batchedUpdatesImpl(fn, bookkeeping); + } finally { + isInsideEventHandler = !1; } - return null; } -function getNearestMountedFiber(fiber) { - var node = fiber, - nearestMounted = fiber; - if (fiber.alternate) for (; node.return; ) node = node.return; - else { - fiber = node; - do - (node = fiber), - 0 !== (node.flags & 4098) && (nearestMounted = node.return), - (fiber = node.return); - while (fiber); +var eventQueue = null; +function executeDispatchesAndReleaseTopLevel(e) { + if (e) { + var dispatchListeners = e._dispatchListeners, + dispatchInstances = e._dispatchInstances; + if (isArrayImpl(dispatchListeners)) + for ( + var i = 0; + i < dispatchListeners.length && !e.isPropagationStopped(); + i++ + ) + executeDispatch(e, dispatchListeners[i], dispatchInstances[i]); + else + dispatchListeners && + executeDispatch(e, dispatchListeners, dispatchInstances); + e._dispatchListeners = null; + e._dispatchInstances = null; + e.isPersistent() || e.constructor.release(e); } - return 3 === node.tag ? nearestMounted : null; -} -function assertIsMounted(fiber) { - if (getNearestMountedFiber(fiber) !== fiber) - throw Error("Unable to find node on an unmounted component."); } -function findCurrentFiberUsingSlowPath(fiber) { - var alternate = fiber.alternate; - if (!alternate) { - alternate = getNearestMountedFiber(fiber); - if (null === alternate) - throw Error("Unable to find node on an unmounted component."); - return alternate !== fiber ? null : fiber; +function dispatchEvent(target, topLevelType, nativeEvent) { + var eventTarget = null; + if (null != target) { + var stateNode = target.stateNode; + null != stateNode && (eventTarget = getPublicInstance(stateNode)); } - for (var a = fiber, b = alternate; ; ) { - var parentA = a.return; - if (null === parentA) break; - var parentB = parentA.alternate; - if (null === parentB) { - b = parentA.return; - if (null !== b) { - a = b; - continue; - } - break; + batchedUpdates$1(function () { + var event = { eventName: topLevelType, nativeEvent: nativeEvent }; + ReactNativePrivateInterface.RawEventEmitter.emit(topLevelType, event); + ReactNativePrivateInterface.RawEventEmitter.emit("*", event); + event = eventTarget; + for ( + var events = null, legacyPlugins = plugins, i = 0; + i < legacyPlugins.length; + i++ + ) { + var possiblePlugin = legacyPlugins[i]; + possiblePlugin && + (possiblePlugin = possiblePlugin.extractEvents( + topLevelType, + target, + nativeEvent, + event + )) && + (events = accumulateInto(events, possiblePlugin)); } - if (parentA.child === parentB.child) { - for (parentB = parentA.child; parentB; ) { - if (parentB === a) return assertIsMounted(parentA), fiber; - if (parentB === b) return assertIsMounted(parentA), alternate; - parentB = parentB.sibling; - } - throw Error("Unable to find node on an unmounted component."); + event = events; + null !== event && (eventQueue = accumulateInto(eventQueue, event)); + event = eventQueue; + eventQueue = null; + if (event) { + forEachAccumulated(event, executeDispatchesAndReleaseTopLevel); + if (eventQueue) + throw Error( + "processEventQueue(): Additional events were enqueued while processing an event queue. Support for this has not yet been implemented." + ); + if (hasRethrowError) + throw ( + ((event = rethrowError), + (hasRethrowError = !1), + (rethrowError = null), + event) + ); } - if (a.return !== b.return) (a = parentA), (b = parentB); - else { - for (var didFindChild = !1, child$2 = parentA.child; child$2; ) { - if (child$2 === a) { - didFindChild = !0; - a = parentA; - b = parentB; - break; - } - if (child$2 === b) { - didFindChild = !0; - b = parentA; - a = parentB; + }); +} +var enableUseRefAccessWarning = dynamicFlags.enableUseRefAccessWarning, + scheduleCallback$1 = Scheduler.unstable_scheduleCallback, + cancelCallback$1 = Scheduler.unstable_cancelCallback, + shouldYield = Scheduler.unstable_shouldYield, + requestPaint = Scheduler.unstable_requestPaint, + now$1 = Scheduler.unstable_now, + ImmediatePriority = Scheduler.unstable_ImmediatePriority, + UserBlockingPriority = Scheduler.unstable_UserBlockingPriority, + NormalPriority = Scheduler.unstable_NormalPriority, + IdlePriority = Scheduler.unstable_IdlePriority, + ReactSharedInternals = + React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, + rendererID = null, + injectedHook = null, + injectedProfilingHooks = null, + isDevToolsPresent = "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__; +function onCommitRoot(root, eventPriority) { + if (injectedHook && "function" === typeof injectedHook.onCommitFiberRoot) + try { + var didError = 128 === (root.current.flags & 128); + switch (eventPriority) { + case 2: + var schedulerPriority = ImmediatePriority; break; - } - child$2 = child$2.sibling; - } - if (!didFindChild) { - for (child$2 = parentB.child; child$2; ) { - if (child$2 === a) { - didFindChild = !0; - a = parentB; - b = parentA; - break; - } - if (child$2 === b) { - didFindChild = !0; - b = parentB; - a = parentA; - break; - } - child$2 = child$2.sibling; - } - if (!didFindChild) - throw Error( - "Child was not found in either parent set. This indicates a bug in React related to the return pointer. Please file an issue." - ); + case 8: + schedulerPriority = UserBlockingPriority; + break; + case 32: + schedulerPriority = NormalPriority; + break; + case 536870912: + schedulerPriority = IdlePriority; + break; + default: + schedulerPriority = NormalPriority; } - } - if (a.alternate !== b) - throw Error( - "Return fibers should always be each others' alternates. This error is likely caused by a bug in React. Please file an issue." + injectedHook.onCommitFiberRoot( + rendererID, + root, + schedulerPriority, + didError ); - } - if (3 !== a.tag) - throw Error("Unable to find node on an unmounted component."); - return a.stateNode.current === a ? fiber : alternate; + } catch (err) {} } -function findCurrentHostFiber(parent) { - parent = findCurrentFiberUsingSlowPath(parent); - return null !== parent ? findCurrentHostFiberImpl(parent) : null; +function injectProfilingHooks(profilingHooks) { + injectedProfilingHooks = profilingHooks; } -function findCurrentHostFiberImpl(node) { - var tag = node.tag; - if (5 === tag || 26 === tag || 27 === tag || 6 === tag) return node; - for (node = node.child; null !== node; ) { - tag = findCurrentHostFiberImpl(node); - if (null !== tag) return tag; - node = node.sibling; +function getLaneLabelMap() { + for (var map = new Map(), lane = 1, index$2 = 0; 31 > index$2; index$2++) { + var label = getLabelForLane(lane); + map.set(lane, label); + lane *= 2; } - return null; -} -function describeComponentFrame(name, source, ownerName) { - source = ""; - ownerName && (source = " (created by " + ownerName + ")"); - return "\n in " + (name || "Unknown") + source; -} -function describeFunctionComponentFrame(fn, source) { - return fn - ? describeComponentFrame(fn.displayName || fn.name || null, source, null) - : ""; -} -var hasOwnProperty = Object.prototype.hasOwnProperty, - valueStack = [], - index = -1; -function createCursor(defaultValue) { - return { current: defaultValue }; -} -function pop(cursor) { - 0 > index || - ((cursor.current = valueStack[index]), (valueStack[index] = null), index--); + return map; } -function push(cursor, value) { - index++; - valueStack[index] = cursor.current; - cursor.current = value; +function markCommitStopped() { + null !== injectedProfilingHooks && + "function" === typeof injectedProfilingHooks.markCommitStopped && + injectedProfilingHooks.markCommitStopped(); } -var emptyContextObject = {}, - contextStackCursor$1 = createCursor(emptyContextObject), - didPerformWorkStackCursor = createCursor(!1), - previousContext = emptyContextObject; -function getMaskedContext(workInProgress, unmaskedContext) { - var contextTypes = workInProgress.type.contextTypes; - if (!contextTypes) return emptyContextObject; - var instance = workInProgress.stateNode; - if ( - instance && - instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext - ) - return instance.__reactInternalMemoizedMaskedChildContext; - var context = {}, - key; - for (key in contextTypes) context[key] = unmaskedContext[key]; - instance && - ((workInProgress = workInProgress.stateNode), - (workInProgress.__reactInternalMemoizedUnmaskedChildContext = - unmaskedContext), - (workInProgress.__reactInternalMemoizedMaskedChildContext = context)); - return context; +function markComponentRenderStarted(fiber) { + null !== injectedProfilingHooks && + "function" === typeof injectedProfilingHooks.markComponentRenderStarted && + injectedProfilingHooks.markComponentRenderStarted(fiber); } -function isContextProvider(type) { - type = type.childContextTypes; - return null !== type && void 0 !== type; +function markComponentRenderStopped() { + null !== injectedProfilingHooks && + "function" === typeof injectedProfilingHooks.markComponentRenderStopped && + injectedProfilingHooks.markComponentRenderStopped(); } -function popContext() { - pop(didPerformWorkStackCursor); - pop(contextStackCursor$1); +function markComponentLayoutEffectUnmountStarted(fiber) { + null !== injectedProfilingHooks && + "function" === + typeof injectedProfilingHooks.markComponentLayoutEffectUnmountStarted && + injectedProfilingHooks.markComponentLayoutEffectUnmountStarted(fiber); } -function pushTopLevelContextObject(fiber, context, didChange) { - if (contextStackCursor$1.current !== emptyContextObject) - throw Error( - "Unexpected context found on stack. This error is likely caused by a bug in React. Please file an issue." - ); - push(contextStackCursor$1, context); - push(didPerformWorkStackCursor, didChange); +function markComponentLayoutEffectUnmountStopped() { + null !== injectedProfilingHooks && + "function" === + typeof injectedProfilingHooks.markComponentLayoutEffectUnmountStopped && + injectedProfilingHooks.markComponentLayoutEffectUnmountStopped(); } -function processChildContext(fiber, type, parentContext) { - var instance = fiber.stateNode; - type = type.childContextTypes; - if ("function" !== typeof instance.getChildContext) return parentContext; - instance = instance.getChildContext(); - for (var contextKey in instance) - if (!(contextKey in type)) - throw Error( - (getComponentNameFromFiber(fiber) || "Unknown") + - '.getChildContext(): key "' + - contextKey + - '" is not defined in childContextTypes.' - ); - return assign({}, parentContext, instance); +function markRenderStarted(lanes) { + null !== injectedProfilingHooks && + "function" === typeof injectedProfilingHooks.markRenderStarted && + injectedProfilingHooks.markRenderStarted(lanes); } -function pushContextProvider(workInProgress) { - workInProgress = - ((workInProgress = workInProgress.stateNode) && - workInProgress.__reactInternalMemoizedMergedChildContext) || - emptyContextObject; - previousContext = contextStackCursor$1.current; - push(contextStackCursor$1, workInProgress); - push(didPerformWorkStackCursor, didPerformWorkStackCursor.current); - return !0; +function markRenderStopped() { + null !== injectedProfilingHooks && + "function" === typeof injectedProfilingHooks.markRenderStopped && + injectedProfilingHooks.markRenderStopped(); } -function invalidateContextProvider(workInProgress, type, didChange) { - var instance = workInProgress.stateNode; - if (!instance) - throw Error( - "Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue." - ); - didChange - ? ((workInProgress = processChildContext( - workInProgress, - type, - previousContext - )), - (instance.__reactInternalMemoizedMergedChildContext = workInProgress), - pop(didPerformWorkStackCursor), - pop(contextStackCursor$1), - push(contextStackCursor$1, workInProgress)) - : pop(didPerformWorkStackCursor); - push(didPerformWorkStackCursor, didChange); +function markStateUpdateScheduled(fiber, lane) { + null !== injectedProfilingHooks && + "function" === typeof injectedProfilingHooks.markStateUpdateScheduled && + injectedProfilingHooks.markStateUpdateScheduled(fiber, lane); } var clz32 = Math.clz32 ? Math.clz32 : clz32Fallback, log = Math.log, @@ -1829,150 +1643,511 @@ function markRootFinished(root, remainingLanes) { noLongerPendingLanes &= ~lane; } } -function markRootEntangled(root, entangledLanes) { - var rootEntangledLanes = (root.entangledLanes |= entangledLanes); - for (root = root.entanglements; rootEntangledLanes; ) { - var index$8 = 31 - clz32(rootEntangledLanes), - lane = 1 << index$8; - (lane & entangledLanes) | (root[index$8] & entangledLanes) && - (root[index$8] |= entangledLanes); - rootEntangledLanes &= ~lane; - } +function markRootEntangled(root, entangledLanes) { + var rootEntangledLanes = (root.entangledLanes |= entangledLanes); + for (root = root.entanglements; rootEntangledLanes; ) { + var index$8 = 31 - clz32(rootEntangledLanes), + lane = 1 << index$8; + (lane & entangledLanes) | (root[index$8] & entangledLanes) && + (root[index$8] |= entangledLanes); + rootEntangledLanes &= ~lane; + } +} +function addFiberToLanesMap(root, fiber, lanes) { + if (isDevToolsPresent) + for (root = root.pendingUpdatersLaneMap; 0 < lanes; ) { + var index$9 = 31 - clz32(lanes), + lane = 1 << index$9; + root[index$9].add(fiber); + lanes &= ~lane; + } +} +function movePendingFibersToMemoized(root, lanes) { + if (isDevToolsPresent) + for ( + var pendingUpdatersLaneMap = root.pendingUpdatersLaneMap, + memoizedUpdaters = root.memoizedUpdaters; + 0 < lanes; + + ) { + var index$10 = 31 - clz32(lanes); + root = 1 << index$10; + index$10 = pendingUpdatersLaneMap[index$10]; + 0 < index$10.size && + (index$10.forEach(function (fiber) { + var alternate = fiber.alternate; + (null !== alternate && memoizedUpdaters.has(alternate)) || + memoizedUpdaters.add(fiber); + }), + index$10.clear()); + lanes &= ~root; + } +} +var currentUpdatePriority = 0; +function lanesToEventPriority(lanes) { + lanes &= -lanes; + return 2 < lanes + ? 8 < lanes + ? 0 !== (lanes & 268435455) + ? 32 + : 536870912 + : 8 + : 2; +} +function shim() { + throw Error( + "The current renderer does not support hydration. This error is likely caused by a bug in React. Please file an issue." + ); +} +var _nativeFabricUIManage = nativeFabricUIManager, + createNode = _nativeFabricUIManage.createNode, + cloneNode = _nativeFabricUIManage.cloneNode, + cloneNodeWithNewChildren = _nativeFabricUIManage.cloneNodeWithNewChildren, + cloneNodeWithNewChildrenAndProps = + _nativeFabricUIManage.cloneNodeWithNewChildrenAndProps, + cloneNodeWithNewProps = _nativeFabricUIManage.cloneNodeWithNewProps, + createChildNodeSet = _nativeFabricUIManage.createChildSet, + appendChildNode = _nativeFabricUIManage.appendChild, + appendChildNodeToSet = _nativeFabricUIManage.appendChildToSet, + completeRoot = _nativeFabricUIManage.completeRoot, + registerEventHandler = _nativeFabricUIManage.registerEventHandler, + FabricDiscretePriority = _nativeFabricUIManage.unstable_DiscreteEventPriority, + fabricGetCurrentEventPriority = + _nativeFabricUIManage.unstable_getCurrentEventPriority, + getViewConfigForType = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.get, + nextReactTag = 2; +registerEventHandler && registerEventHandler(dispatchEvent); +function createTextInstance( + text, + rootContainerInstance, + hostContext, + internalInstanceHandle +) { + hostContext = nextReactTag; + nextReactTag += 2; + return { + node: createNode( + hostContext, + "RCTRawText", + rootContainerInstance, + { text: text }, + internalInstanceHandle + ) + }; +} +function getPublicInstance(instance) { + return null != instance.canonical && null != instance.canonical.publicInstance + ? instance.canonical.publicInstance + : null != instance._nativeTag + ? instance + : null; +} +var scheduleTimeout = setTimeout, + cancelTimeout = clearTimeout; +function cloneHiddenInstance(instance) { + var node = instance.node; + var JSCompiler_inline_result = diffProperties( + null, + emptyObject$1, + { style: { display: "none" } }, + instance.canonical.viewConfig.validAttributes + ); + return { + node: cloneNodeWithNewProps(node, JSCompiler_inline_result), + canonical: instance.canonical + }; +} +function getInstanceFromNode(node) { + return null != node.canonical && null != node.canonical.internalInstanceHandle + ? node.canonical.internalInstanceHandle + : node; +} +getFiberCurrentPropsFromNode$1 = function (instance) { + return instance.canonical.currentProps; +}; +getInstanceFromNode$1 = getInstanceFromNode; +getNodeFromInstance$1 = function (fiber) { + fiber = getPublicInstance(fiber.stateNode); + if (null == fiber) throw Error("Could not find host instance from fiber"); + return fiber; +}; +ResponderEventPlugin.injection.injectGlobalResponderHandler({ + onChange: function (from, to, blockNativeResponder) { + from && + from.stateNode && + nativeFabricUIManager.setIsJSResponder( + from.stateNode.node, + !1, + blockNativeResponder || !1 + ); + to && + to.stateNode && + nativeFabricUIManager.setIsJSResponder( + to.stateNode.node, + !0, + blockNativeResponder || !1 + ); + } +}); +var REACT_ELEMENT_TYPE = Symbol.for("react.element"), + REACT_PORTAL_TYPE = Symbol.for("react.portal"), + REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"), + REACT_STRICT_MODE_TYPE = Symbol.for("react.strict_mode"), + REACT_PROFILER_TYPE = Symbol.for("react.profiler"), + REACT_PROVIDER_TYPE = Symbol.for("react.provider"), + REACT_CONTEXT_TYPE = Symbol.for("react.context"), + REACT_SERVER_CONTEXT_TYPE = Symbol.for("react.server_context"), + REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"), + REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"), + REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"), + REACT_MEMO_TYPE = Symbol.for("react.memo"), + REACT_LAZY_TYPE = Symbol.for("react.lazy"); +Symbol.for("react.scope"); +Symbol.for("react.debug_trace_mode"); +var REACT_OFFSCREEN_TYPE = Symbol.for("react.offscreen"), + REACT_LEGACY_HIDDEN_TYPE = Symbol.for("react.legacy_hidden"); +Symbol.for("react.cache"); +Symbol.for("react.tracing_marker"); +var REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED = Symbol.for( + "react.default_value" + ), + REACT_MEMO_CACHE_SENTINEL = Symbol.for("react.memo_cache_sentinel"), + MAYBE_ITERATOR_SYMBOL = Symbol.iterator; +function getIteratorFn(maybeIterable) { + if (null === maybeIterable || "object" !== typeof maybeIterable) return null; + maybeIterable = + (MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL]) || + maybeIterable["@@iterator"]; + return "function" === typeof maybeIterable ? maybeIterable : null; +} +function getComponentNameFromType(type) { + if (null == type) return null; + if ("function" === typeof type) return type.displayName || type.name || null; + if ("string" === typeof type) return type; + switch (type) { + case REACT_FRAGMENT_TYPE: + return "Fragment"; + case REACT_PORTAL_TYPE: + return "Portal"; + case REACT_PROFILER_TYPE: + return "Profiler"; + case REACT_STRICT_MODE_TYPE: + return "StrictMode"; + case REACT_SUSPENSE_TYPE: + return "Suspense"; + case REACT_SUSPENSE_LIST_TYPE: + return "SuspenseList"; + } + if ("object" === typeof type) + switch (type.$$typeof) { + case REACT_CONTEXT_TYPE: + return (type.displayName || "Context") + ".Consumer"; + case REACT_PROVIDER_TYPE: + return (type._context.displayName || "Context") + ".Provider"; + case REACT_FORWARD_REF_TYPE: + var innerType = type.render; + type = type.displayName; + type || + ((type = innerType.displayName || innerType.name || ""), + (type = "" !== type ? "ForwardRef(" + type + ")" : "ForwardRef")); + return type; + case REACT_MEMO_TYPE: + return ( + (innerType = type.displayName || null), + null !== innerType + ? innerType + : getComponentNameFromType(type.type) || "Memo" + ); + case REACT_LAZY_TYPE: + innerType = type._payload; + type = type._init; + try { + return getComponentNameFromType(type(innerType)); + } catch (x) { + break; + } + case REACT_SERVER_CONTEXT_TYPE: + return (type.displayName || type._globalName) + ".Provider"; + } + return null; +} +function getComponentNameFromFiber(fiber) { + var type = fiber.type; + switch (fiber.tag) { + case 24: + return "Cache"; + case 9: + return (type.displayName || "Context") + ".Consumer"; + case 10: + return (type._context.displayName || "Context") + ".Provider"; + case 18: + return "DehydratedFragment"; + case 11: + return ( + (fiber = type.render), + (fiber = fiber.displayName || fiber.name || ""), + type.displayName || + ("" !== fiber ? "ForwardRef(" + fiber + ")" : "ForwardRef") + ); + case 7: + return "Fragment"; + case 26: + case 27: + case 5: + return type; + case 4: + return "Portal"; + case 3: + return "Root"; + case 6: + return "Text"; + case 16: + return getComponentNameFromType(type); + case 8: + return type === REACT_STRICT_MODE_TYPE ? "StrictMode" : "Mode"; + case 22: + return "Offscreen"; + case 12: + return "Profiler"; + case 21: + return "Scope"; + case 13: + return "Suspense"; + case 19: + return "SuspenseList"; + case 25: + return "TracingMarker"; + case 1: + case 0: + case 17: + case 2: + case 14: + case 15: + if ("function" === typeof type) + return type.displayName || type.name || null; + if ("string" === typeof type) return type; + break; + case 23: + return "LegacyHidden"; + } + return null; +} +function getNearestMountedFiber(fiber) { + var node = fiber, + nearestMounted = fiber; + if (fiber.alternate) for (; node.return; ) node = node.return; + else { + fiber = node; + do + (node = fiber), + 0 !== (node.flags & 4098) && (nearestMounted = node.return), + (fiber = node.return); + while (fiber); + } + return 3 === node.tag ? nearestMounted : null; +} +function assertIsMounted(fiber) { + if (getNearestMountedFiber(fiber) !== fiber) + throw Error("Unable to find node on an unmounted component."); } -function addFiberToLanesMap(root, fiber, lanes) { - if (isDevToolsPresent) - for (root = root.pendingUpdatersLaneMap; 0 < lanes; ) { - var index$9 = 31 - clz32(lanes), - lane = 1 << index$9; - root[index$9].add(fiber); - lanes &= ~lane; +function findCurrentFiberUsingSlowPath(fiber) { + var alternate = fiber.alternate; + if (!alternate) { + alternate = getNearestMountedFiber(fiber); + if (null === alternate) + throw Error("Unable to find node on an unmounted component."); + return alternate !== fiber ? null : fiber; + } + for (var a = fiber, b = alternate; ; ) { + var parentA = a.return; + if (null === parentA) break; + var parentB = parentA.alternate; + if (null === parentB) { + b = parentA.return; + if (null !== b) { + a = b; + continue; + } + break; } -} -function movePendingFibersToMemoized(root, lanes) { - if (isDevToolsPresent) - for ( - var pendingUpdatersLaneMap = root.pendingUpdatersLaneMap, - memoizedUpdaters = root.memoizedUpdaters; - 0 < lanes; - - ) { - var index$10 = 31 - clz32(lanes); - root = 1 << index$10; - index$10 = pendingUpdatersLaneMap[index$10]; - 0 < index$10.size && - (index$10.forEach(function (fiber) { - var alternate = fiber.alternate; - (null !== alternate && memoizedUpdaters.has(alternate)) || - memoizedUpdaters.add(fiber); - }), - index$10.clear()); - lanes &= ~root; + if (parentA.child === parentB.child) { + for (parentB = parentA.child; parentB; ) { + if (parentB === a) return assertIsMounted(parentA), fiber; + if (parentB === b) return assertIsMounted(parentA), alternate; + parentB = parentB.sibling; + } + throw Error("Unable to find node on an unmounted component."); } -} -var currentUpdatePriority = 0; -function lanesToEventPriority(lanes) { - lanes &= -lanes; - return 2 < lanes - ? 8 < lanes - ? 0 !== (lanes & 268435455) - ? 32 - : 536870912 - : 8 - : 2; -} -var scheduleCallback$1 = Scheduler.unstable_scheduleCallback, - cancelCallback$1 = Scheduler.unstable_cancelCallback, - shouldYield = Scheduler.unstable_shouldYield, - requestPaint = Scheduler.unstable_requestPaint, - now$1 = Scheduler.unstable_now, - ImmediatePriority = Scheduler.unstable_ImmediatePriority, - UserBlockingPriority = Scheduler.unstable_UserBlockingPriority, - NormalPriority = Scheduler.unstable_NormalPriority, - IdlePriority = Scheduler.unstable_IdlePriority, - rendererID = null, - injectedHook = null, - injectedProfilingHooks = null, - isDevToolsPresent = "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__; -function onCommitRoot(root, eventPriority) { - if (injectedHook && "function" === typeof injectedHook.onCommitFiberRoot) - try { - var didError = 128 === (root.current.flags & 128); - switch (eventPriority) { - case 2: - var schedulerPriority = ImmediatePriority; - break; - case 8: - schedulerPriority = UserBlockingPriority; - break; - case 32: - schedulerPriority = NormalPriority; + if (a.return !== b.return) (a = parentA), (b = parentB); + else { + for (var didFindChild = !1, child$11 = parentA.child; child$11; ) { + if (child$11 === a) { + didFindChild = !0; + a = parentA; + b = parentB; break; - case 536870912: - schedulerPriority = IdlePriority; + } + if (child$11 === b) { + didFindChild = !0; + b = parentA; + a = parentB; break; - default: - schedulerPriority = NormalPriority; + } + child$11 = child$11.sibling; } - injectedHook.onCommitFiberRoot( - rendererID, - root, - schedulerPriority, - didError + if (!didFindChild) { + for (child$11 = parentB.child; child$11; ) { + if (child$11 === a) { + didFindChild = !0; + a = parentB; + b = parentA; + break; + } + if (child$11 === b) { + didFindChild = !0; + b = parentB; + a = parentA; + break; + } + child$11 = child$11.sibling; + } + if (!didFindChild) + throw Error( + "Child was not found in either parent set. This indicates a bug in React related to the return pointer. Please file an issue." + ); + } + } + if (a.alternate !== b) + throw Error( + "Return fibers should always be each others' alternates. This error is likely caused by a bug in React. Please file an issue." ); - } catch (err) {} + } + if (3 !== a.tag) + throw Error("Unable to find node on an unmounted component."); + return a.stateNode.current === a ? fiber : alternate; } -function injectProfilingHooks(profilingHooks) { - injectedProfilingHooks = profilingHooks; +function findCurrentHostFiber(parent) { + parent = findCurrentFiberUsingSlowPath(parent); + return null !== parent ? findCurrentHostFiberImpl(parent) : null; } -function getLaneLabelMap() { - for (var map = new Map(), lane = 1, index$11 = 0; 31 > index$11; index$11++) { - var label = getLabelForLane(lane); - map.set(lane, label); - lane *= 2; +function findCurrentHostFiberImpl(node) { + var tag = node.tag; + if (5 === tag || 26 === tag || 27 === tag || 6 === tag) return node; + for (node = node.child; null !== node; ) { + tag = findCurrentHostFiberImpl(node); + if (null !== tag) return tag; + node = node.sibling; } - return map; + return null; } -function markCommitStopped() { - null !== injectedProfilingHooks && - "function" === typeof injectedProfilingHooks.markCommitStopped && - injectedProfilingHooks.markCommitStopped(); +function describeComponentFrame(name, source, ownerName) { + source = ""; + ownerName && (source = " (created by " + ownerName + ")"); + return "\n in " + (name || "Unknown") + source; } -function markComponentRenderStarted(fiber) { - null !== injectedProfilingHooks && - "function" === typeof injectedProfilingHooks.markComponentRenderStarted && - injectedProfilingHooks.markComponentRenderStarted(fiber); +function describeFunctionComponentFrame(fn, source) { + return fn + ? describeComponentFrame(fn.displayName || fn.name || null, source, null) + : ""; } -function markComponentRenderStopped() { - null !== injectedProfilingHooks && - "function" === typeof injectedProfilingHooks.markComponentRenderStopped && - injectedProfilingHooks.markComponentRenderStopped(); +var hasOwnProperty = Object.prototype.hasOwnProperty, + valueStack = [], + index = -1; +function createCursor(defaultValue) { + return { current: defaultValue }; } -function markComponentLayoutEffectUnmountStarted(fiber) { - null !== injectedProfilingHooks && - "function" === - typeof injectedProfilingHooks.markComponentLayoutEffectUnmountStarted && - injectedProfilingHooks.markComponentLayoutEffectUnmountStarted(fiber); +function pop(cursor) { + 0 > index || + ((cursor.current = valueStack[index]), (valueStack[index] = null), index--); } -function markComponentLayoutEffectUnmountStopped() { - null !== injectedProfilingHooks && - "function" === - typeof injectedProfilingHooks.markComponentLayoutEffectUnmountStopped && - injectedProfilingHooks.markComponentLayoutEffectUnmountStopped(); +function push(cursor, value) { + index++; + valueStack[index] = cursor.current; + cursor.current = value; } -function markRenderStarted(lanes) { - null !== injectedProfilingHooks && - "function" === typeof injectedProfilingHooks.markRenderStarted && - injectedProfilingHooks.markRenderStarted(lanes); +var emptyContextObject = {}, + contextStackCursor$1 = createCursor(emptyContextObject), + didPerformWorkStackCursor = createCursor(!1), + previousContext = emptyContextObject; +function getMaskedContext(workInProgress, unmaskedContext) { + var contextTypes = workInProgress.type.contextTypes; + if (!contextTypes) return emptyContextObject; + var instance = workInProgress.stateNode; + if ( + instance && + instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext + ) + return instance.__reactInternalMemoizedMaskedChildContext; + var context = {}, + key; + for (key in contextTypes) context[key] = unmaskedContext[key]; + instance && + ((workInProgress = workInProgress.stateNode), + (workInProgress.__reactInternalMemoizedUnmaskedChildContext = + unmaskedContext), + (workInProgress.__reactInternalMemoizedMaskedChildContext = context)); + return context; +} +function isContextProvider(type) { + type = type.childContextTypes; + return null !== type && void 0 !== type; +} +function popContext() { + pop(didPerformWorkStackCursor); + pop(contextStackCursor$1); +} +function pushTopLevelContextObject(fiber, context, didChange) { + if (contextStackCursor$1.current !== emptyContextObject) + throw Error( + "Unexpected context found on stack. This error is likely caused by a bug in React. Please file an issue." + ); + push(contextStackCursor$1, context); + push(didPerformWorkStackCursor, didChange); } -function markRenderStopped() { - null !== injectedProfilingHooks && - "function" === typeof injectedProfilingHooks.markRenderStopped && - injectedProfilingHooks.markRenderStopped(); +function processChildContext(fiber, type, parentContext) { + var instance = fiber.stateNode; + type = type.childContextTypes; + if ("function" !== typeof instance.getChildContext) return parentContext; + instance = instance.getChildContext(); + for (var contextKey in instance) + if (!(contextKey in type)) + throw Error( + (getComponentNameFromFiber(fiber) || "Unknown") + + '.getChildContext(): key "' + + contextKey + + '" is not defined in childContextTypes.' + ); + return assign({}, parentContext, instance); } -function markStateUpdateScheduled(fiber, lane) { - null !== injectedProfilingHooks && - "function" === typeof injectedProfilingHooks.markStateUpdateScheduled && - injectedProfilingHooks.markStateUpdateScheduled(fiber, lane); +function pushContextProvider(workInProgress) { + workInProgress = + ((workInProgress = workInProgress.stateNode) && + workInProgress.__reactInternalMemoizedMergedChildContext) || + emptyContextObject; + previousContext = contextStackCursor$1.current; + push(contextStackCursor$1, workInProgress); + push(didPerformWorkStackCursor, didPerformWorkStackCursor.current); + return !0; +} +function invalidateContextProvider(workInProgress, type, didChange) { + var instance = workInProgress.stateNode; + if (!instance) + throw Error( + "Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue." + ); + didChange + ? ((workInProgress = processChildContext( + workInProgress, + type, + previousContext + )), + (instance.__reactInternalMemoizedMergedChildContext = workInProgress), + pop(didPerformWorkStackCursor), + pop(contextStackCursor$1), + push(contextStackCursor$1, workInProgress)) + : pop(didPerformWorkStackCursor); + push(didPerformWorkStackCursor, didChange); } function is(x, y) { return (x === y && (0 !== x || 1 / x === 1 / y)) || (x !== x && y !== y); @@ -2431,12 +2606,12 @@ function isThenableResolved(thenable) { thenable = thenable.status; return "fulfilled" === thenable || "rejected" === thenable; } -function noop$1() {} +function noop() {} function trackUsedThenable(thenableState, thenable, index) { index = thenableState[index]; void 0 === index ? thenableState.push(thenable) - : index !== thenable && (thenable.then(noop$1, noop$1), (thenable = index)); + : index !== thenable && (thenable.then(noop, noop), (thenable = index)); switch (thenable.status) { case "fulfilled": return thenable.value; @@ -2444,7 +2619,7 @@ function trackUsedThenable(thenableState, thenable, index) { throw thenable.reason; default: "string" === typeof thenable.status - ? thenable.then(noop$1, noop$1) + ? thenable.then(noop, noop) : ((thenableState = thenable), (thenableState.status = "pending"), thenableState.then( @@ -6035,7 +6210,7 @@ function completeWork(current, workInProgress, renderLanes) { recyclableInstance, workInProgress ); - recyclableInstance = new ReactFabricHostComponent( + recyclableInstance = ReactNativePrivateInterface.createPublicInstance( current, renderLanes, workInProgress @@ -9881,264 +10056,20 @@ function findNodeHandle(componentOrHandle) { null != componentOrHandle.canonical.nativeTag ) return componentOrHandle.canonical.nativeTag; - var nativeTag = componentOrHandle.__nativeTag; + var nativeTag = + ReactNativePrivateInterface.getNativeTagFromPublicInstance( + componentOrHandle + ); if (nativeTag) return nativeTag; componentOrHandle = findHostInstance(componentOrHandle); return null == componentOrHandle ? componentOrHandle : null != componentOrHandle._nativeTag ? componentOrHandle._nativeTag - : componentOrHandle.__nativeTag; -} -function getNodeFromInternalInstanceHandle(internalInstanceHandle) { - return ( - internalInstanceHandle && - internalInstanceHandle.stateNode && - internalInstanceHandle.stateNode.node - ); -} -var _nativeFabricUIManage$1 = nativeFabricUIManager, - fabricMeasure = _nativeFabricUIManage$1.measure, - fabricMeasureInWindow = _nativeFabricUIManage$1.measureInWindow, - fabricMeasureLayout = _nativeFabricUIManage$1.measureLayout, - _setNativeProps = _nativeFabricUIManage$1.setNativeProps, - fabricGetBoundingClientRect = _nativeFabricUIManage$1.getBoundingClientRect; -function noop() {} -var ReactFabricHostComponent = (function () { - function ReactFabricHostComponent(tag, viewConfig, internalInstanceHandle) { - this.__nativeTag = tag; - this._viewConfig = viewConfig; - this.__internalInstanceHandle = internalInstanceHandle; - } - var _proto = ReactFabricHostComponent.prototype; - _proto.blur = function () { - ReactNativePrivateInterface.TextInputState.blurTextInput(this); - }; - _proto.focus = function () { - ReactNativePrivateInterface.TextInputState.focusTextInput(this); - }; - _proto.measure = function (callback) { - var node = getNodeFromInternalInstanceHandle(this.__internalInstanceHandle); - null != node && fabricMeasure(node, callback); - }; - _proto.measureInWindow = function (callback) { - var node = getNodeFromInternalInstanceHandle(this.__internalInstanceHandle); - null != node && fabricMeasureInWindow(node, callback); - }; - _proto.measureLayout = function (relativeToNativeNode, onSuccess, onFail) { - if ( - "number" !== typeof relativeToNativeNode && - relativeToNativeNode instanceof ReactFabricHostComponent - ) { - var toStateNode = getNodeFromInternalInstanceHandle( - this.__internalInstanceHandle - ); - relativeToNativeNode = getNodeFromInternalInstanceHandle( - relativeToNativeNode.__internalInstanceHandle + : ReactNativePrivateInterface.getNativeTagFromPublicInstance( + componentOrHandle ); - null != toStateNode && - null != relativeToNativeNode && - fabricMeasureLayout( - toStateNode, - relativeToNativeNode, - null != onFail ? onFail : noop, - null != onSuccess ? onSuccess : noop - ); - } - }; - _proto.unstable_getBoundingClientRect = function () { - var node = getNodeFromInternalInstanceHandle(this.__internalInstanceHandle); - return null != node && (node = fabricGetBoundingClientRect(node)) - ? new DOMRect(node[0], node[1], node[2], node[3]) - : new DOMRect(0, 0, 0, 0); - }; - _proto.setNativeProps = function (nativeProps) { - nativeProps = diffProperties( - null, - emptyObject$1, - nativeProps, - this._viewConfig.validAttributes - ); - var node = getNodeFromInternalInstanceHandle(this.__internalInstanceHandle); - null != node && null != nativeProps && _setNativeProps(node, nativeProps); - }; - return ReactFabricHostComponent; -})(); -function batchedUpdatesImpl(fn, bookkeeping) { - return fn(bookkeeping); -} -var isInsideEventHandler = !1; -function batchedUpdates(fn, bookkeeping) { - if (isInsideEventHandler) return fn(bookkeeping); - isInsideEventHandler = !0; - try { - return batchedUpdatesImpl(fn, bookkeeping); - } finally { - isInsideEventHandler = !1; - } -} -var eventQueue = null; -function executeDispatchesAndReleaseTopLevel(e) { - if (e) { - var dispatchListeners = e._dispatchListeners, - dispatchInstances = e._dispatchInstances; - if (isArrayImpl(dispatchListeners)) - for ( - var i = 0; - i < dispatchListeners.length && !e.isPropagationStopped(); - i++ - ) - executeDispatch(e, dispatchListeners[i], dispatchInstances[i]); - else - dispatchListeners && - executeDispatch(e, dispatchListeners, dispatchInstances); - e._dispatchListeners = null; - e._dispatchInstances = null; - e.isPersistent() || e.constructor.release(e); - } -} -function dispatchEvent(target, topLevelType, nativeEvent) { - var eventTarget = null; - if (null != target) { - var stateNode = target.stateNode; - null != stateNode && (eventTarget = getPublicInstance(stateNode)); - } - batchedUpdates(function () { - var event = { eventName: topLevelType, nativeEvent: nativeEvent }; - ReactNativePrivateInterface.RawEventEmitter.emit(topLevelType, event); - ReactNativePrivateInterface.RawEventEmitter.emit("*", event); - event = eventTarget; - for ( - var events = null, legacyPlugins = plugins, i = 0; - i < legacyPlugins.length; - i++ - ) { - var possiblePlugin = legacyPlugins[i]; - possiblePlugin && - (possiblePlugin = possiblePlugin.extractEvents( - topLevelType, - target, - nativeEvent, - event - )) && - (events = accumulateInto(events, possiblePlugin)); - } - event = events; - null !== event && (eventQueue = accumulateInto(eventQueue, event)); - event = eventQueue; - eventQueue = null; - if (event) { - forEachAccumulated(event, executeDispatchesAndReleaseTopLevel); - if (eventQueue) - throw Error( - "processEventQueue(): Additional events were enqueued while processing an event queue. Support for this has not yet been implemented." - ); - if (hasRethrowError) - throw ( - ((event = rethrowError), - (hasRethrowError = !1), - (rethrowError = null), - event) - ); - } - }); -} -function shim() { - throw Error( - "The current renderer does not support hydration. This error is likely caused by a bug in React. Please file an issue." - ); -} -var _nativeFabricUIManage = nativeFabricUIManager, - createNode = _nativeFabricUIManage.createNode, - cloneNode = _nativeFabricUIManage.cloneNode, - cloneNodeWithNewChildren = _nativeFabricUIManage.cloneNodeWithNewChildren, - cloneNodeWithNewChildrenAndProps = - _nativeFabricUIManage.cloneNodeWithNewChildrenAndProps, - cloneNodeWithNewProps = _nativeFabricUIManage.cloneNodeWithNewProps, - createChildNodeSet = _nativeFabricUIManage.createChildSet, - appendChildNode = _nativeFabricUIManage.appendChild, - appendChildNodeToSet = _nativeFabricUIManage.appendChildToSet, - completeRoot = _nativeFabricUIManage.completeRoot, - registerEventHandler = _nativeFabricUIManage.registerEventHandler, - FabricDiscretePriority = _nativeFabricUIManage.unstable_DiscreteEventPriority, - fabricGetCurrentEventPriority = - _nativeFabricUIManage.unstable_getCurrentEventPriority, - getViewConfigForType = - ReactNativePrivateInterface.ReactNativeViewConfigRegistry.get, - nextReactTag = 2; -registerEventHandler && registerEventHandler(dispatchEvent); -function createTextInstance( - text, - rootContainerInstance, - hostContext, - internalInstanceHandle -) { - hostContext = nextReactTag; - nextReactTag += 2; - return { - node: createNode( - hostContext, - "RCTRawText", - rootContainerInstance, - { text: text }, - internalInstanceHandle - ) - }; -} -function getPublicInstance(instance) { - return null != instance.canonical && null != instance.canonical.publicInstance - ? instance.canonical.publicInstance - : null != instance._nativeTag - ? instance - : null; -} -var scheduleTimeout = setTimeout, - cancelTimeout = clearTimeout; -function cloneHiddenInstance(instance) { - var node = instance.node; - var JSCompiler_inline_result = diffProperties( - null, - emptyObject$1, - { style: { display: "none" } }, - instance.canonical.viewConfig.validAttributes - ); - return { - node: cloneNodeWithNewProps(node, JSCompiler_inline_result), - canonical: instance.canonical - }; } -function getInstanceFromNode(node) { - return null != node.canonical && null != node.canonical.internalInstanceHandle - ? node.canonical.internalInstanceHandle - : node; -} -getFiberCurrentPropsFromNode$1 = function (instance) { - return instance.canonical.currentProps; -}; -getInstanceFromNode$1 = getInstanceFromNode; -getNodeFromInstance$1 = function (fiber) { - fiber = getPublicInstance(fiber.stateNode); - if (null == fiber) throw Error("Could not find host instance from fiber"); - return fiber; -}; -ResponderEventPlugin.injection.injectGlobalResponderHandler({ - onChange: function (from, to, blockNativeResponder) { - from && - from.stateNode && - nativeFabricUIManager.setIsJSResponder( - from.stateNode.node, - !1, - blockNativeResponder || !1 - ); - to && - to.stateNode && - nativeFabricUIManager.setIsJSResponder( - to.stateNode.node, - !0, - blockNativeResponder || !1 - ); - } -}); var emptyObject = {}; function createHierarchy(fiberHierarchy) { return fiberHierarchy.map(function (fiber$jscomp$0) { @@ -10214,7 +10145,7 @@ var roots = new Map(), devToolsConfig$jscomp$inline_1128 = { findFiberByHostInstance: getInstanceFromNode, bundleType: 0, - version: "18.3.0-next-f77099b6f-20230322", + version: "18.3.0-next-9c54b29b4-20230322", rendererPackageName: "react-native-renderer", rendererConfig: { getInspectorDataForViewTag: function () { @@ -10269,7 +10200,7 @@ var roots = new Map(), scheduleRoot: null, setRefreshHandler: null, getCurrentFiber: null, - reconcilerVersion: "18.3.0-next-f77099b6f-20230322" + reconcilerVersion: "18.3.0-next-9c54b29b4-20230322" }); exports.createPortal = function (children, containerTag) { return createPortal$1( @@ -10281,12 +10212,11 @@ exports.createPortal = function (children, containerTag) { }; exports.dispatchCommand = function (handle, command, args) { var nativeTag = - null != handle._nativeTag ? handle._nativeTag : handle.__nativeTag; + null != handle._nativeTag + ? handle._nativeTag + : ReactNativePrivateInterface.getNativeTagFromPublicInstance(handle); null != nativeTag && - ((handle = - null == handle.__internalInstanceHandle - ? null - : getNodeFromInternalInstanceHandle(handle.__internalInstanceHandle)), + ((handle = ReactNativePrivateInterface.getNodeFromPublicInstance(handle)), null != handle ? nativeFabricUIManager.dispatchCommand(handle, command, args) : ReactNativePrivateInterface.UIManager.dispatchViewManagerCommand( @@ -10338,7 +10268,13 @@ exports.getInspectorDataForInstance = function (closestInstance) { source: source }; }; -exports.getNodeFromInternalInstanceHandle = getNodeFromInternalInstanceHandle; +exports.getNodeFromInternalInstanceHandle = function (internalInstanceHandle) { + return ( + internalInstanceHandle && + internalInstanceHandle.stateNode && + internalInstanceHandle.stateNode.node + ); +}; exports.getPublicInstanceFromInternalInstanceHandle = function ( internalInstanceHandle ) { @@ -10379,12 +10315,11 @@ exports.render = function (element, containerTag, callback, concurrentRoot) { }; exports.sendAccessibilityEvent = function (handle, eventType) { var nativeTag = - null != handle._nativeTag ? handle._nativeTag : handle.__nativeTag; + null != handle._nativeTag + ? handle._nativeTag + : ReactNativePrivateInterface.getNativeTagFromPublicInstance(handle); null != nativeTag && - ((handle = - null == handle.__internalInstanceHandle - ? null - : getNodeFromInternalInstanceHandle(handle.__internalInstanceHandle)), + ((handle = ReactNativePrivateInterface.getNodeFromPublicInstance(handle)), null != handle ? nativeFabricUIManager.sendAccessibilityEvent(handle, eventType) : ReactNativePrivateInterface.legacySendAccessibilityEvent( diff --git a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js index c4548765d03ba..9212a39c8a686 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js +++ b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js @@ -27454,7 +27454,7 @@ function createFiberRoot( return root; } -var ReactVersion = "18.3.0-next-f77099b6f-20230322"; +var ReactVersion = "18.3.0-next-9c54b29b4-20230322"; function createPortal$1( children, @@ -28031,6 +28031,7 @@ function findHostInstance_DEPRECATED(componentOrHandle) { ); } // findHostInstance handles legacy vs. Fabric differences correctly // $FlowFixMe[incompatible-exact] we need to fix the definition of `HostComponent` to use NativeMethods as an interface, not as a type. + // $FlowFixMe[incompatible-return] return hostInstance; } @@ -28074,7 +28075,10 @@ function findNodeHandle(componentOrHandle) { return componentOrHandle.canonical.nativeTag; } // For compatibility with Fabric public instances - var nativeTag = getNativeTagFromPublicInstance(componentOrHandle); + var nativeTag = + ReactNativePrivateInterface.getNativeTagFromPublicInstance( + componentOrHandle + ); if (nativeTag) { return nativeTag; @@ -28091,20 +28095,21 @@ function findNodeHandle(componentOrHandle) { if (hostInstance == null) { return hostInstance; - } // $FlowFixMe[prop-missing] For compatibility with legacy renderer instances + } // $FlowFixMe[incompatible-type] For compatibility with legacy renderer instances if (hostInstance._nativeTag != null) { - // $FlowFixMe[incompatible-return] return hostInstance._nativeTag; } // $FlowFixMe[incompatible-call] Necessary when running Flow on the legacy renderer - return getNativeTagFromPublicInstance(hostInstance); + return ReactNativePrivateInterface.getNativeTagFromPublicInstance( + hostInstance + ); } function dispatchCommand(handle, command, args) { var nativeTag = handle._nativeTag != null ? handle._nativeTag - : getNativeTagFromPublicInstance(handle); + : ReactNativePrivateInterface.getNativeTagFromPublicInstance(handle); if (nativeTag == null) { { @@ -28117,7 +28122,7 @@ function dispatchCommand(handle, command, args) { return; } - var node = getNodeFromPublicInstance(handle); + var node = ReactNativePrivateInterface.getNodeFromPublicInstance(handle); if (node != null) { nativeFabricUIManager.dispatchCommand(node, command, args); @@ -28133,7 +28138,7 @@ function sendAccessibilityEvent(handle, eventType) { var nativeTag = handle._nativeTag != null ? handle._nativeTag - : getNativeTagFromPublicInstance(handle); + : ReactNativePrivateInterface.getNativeTagFromPublicInstance(handle); if (nativeTag == null) { { @@ -28146,7 +28151,7 @@ function sendAccessibilityEvent(handle, eventType) { return; } - var node = getNodeFromPublicInstance(handle); + var node = ReactNativePrivateInterface.getNodeFromPublicInstance(handle); if (node != null) { nativeFabricUIManager.sendAccessibilityEvent(node, eventType); @@ -28166,26 +28171,6 @@ function getNodeFromInternalInstanceHandle(internalInstanceHandle) { ); } -/** - * IMPORTANT: This module is used in Paper and Fabric. It needs to be defined - * outside of `ReactFabricPublicInstance` because that module requires - * `nativeFabricUIManager` to be defined in the global scope (which does not - * happen in Paper). - */ - -function getNativeTagFromPublicInstance(publicInstance) { - return publicInstance.__nativeTag; -} -function getNodeFromPublicInstance(publicInstance) { - if (publicInstance.__internalInstanceHandle == null) { - return null; - } - - return getNodeFromInternalInstanceHandle( - publicInstance.__internalInstanceHandle - ); -} - var emptyObject = {}; { @@ -28348,7 +28333,8 @@ function getInspectorDataForViewAtPoint( ) { { var closestInstance = null; - var fabricNode = getNodeFromPublicInstance(inspectedView); + var fabricNode = + ReactNativePrivateInterface.getNodeFromPublicInstance(inspectedView); if (fabricNode) { // For Fabric we can look up the instance handle directly and measure it. diff --git a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-prod.fb.js b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-prod.fb.js index fe60e0cfaf143..005930a268fe9 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-prod.fb.js +++ b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-prod.fb.js @@ -940,7 +940,7 @@ eventPluginOrder = Array.prototype.slice.call([ "ReactNativeBridgeEventPlugin" ]); recomputePluginOrdering(); -var injectedNamesToPlugins$jscomp$inline_248 = { +var injectedNamesToPlugins$jscomp$inline_247 = { ResponderEventPlugin: ResponderEventPlugin, ReactNativeBridgeEventPlugin: { eventTypes: {}, @@ -986,32 +986,32 @@ var injectedNamesToPlugins$jscomp$inline_248 = { } } }, - isOrderingDirty$jscomp$inline_249 = !1, - pluginName$jscomp$inline_250; -for (pluginName$jscomp$inline_250 in injectedNamesToPlugins$jscomp$inline_248) + isOrderingDirty$jscomp$inline_248 = !1, + pluginName$jscomp$inline_249; +for (pluginName$jscomp$inline_249 in injectedNamesToPlugins$jscomp$inline_247) if ( - injectedNamesToPlugins$jscomp$inline_248.hasOwnProperty( - pluginName$jscomp$inline_250 + injectedNamesToPlugins$jscomp$inline_247.hasOwnProperty( + pluginName$jscomp$inline_249 ) ) { - var pluginModule$jscomp$inline_251 = - injectedNamesToPlugins$jscomp$inline_248[pluginName$jscomp$inline_250]; + var pluginModule$jscomp$inline_250 = + injectedNamesToPlugins$jscomp$inline_247[pluginName$jscomp$inline_249]; if ( - !namesToPlugins.hasOwnProperty(pluginName$jscomp$inline_250) || - namesToPlugins[pluginName$jscomp$inline_250] !== - pluginModule$jscomp$inline_251 + !namesToPlugins.hasOwnProperty(pluginName$jscomp$inline_249) || + namesToPlugins[pluginName$jscomp$inline_249] !== + pluginModule$jscomp$inline_250 ) { - if (namesToPlugins[pluginName$jscomp$inline_250]) + if (namesToPlugins[pluginName$jscomp$inline_249]) throw Error( "EventPluginRegistry: Cannot inject two different event plugins using the same name, `" + - (pluginName$jscomp$inline_250 + "`.") + (pluginName$jscomp$inline_249 + "`.") ); - namesToPlugins[pluginName$jscomp$inline_250] = - pluginModule$jscomp$inline_251; - isOrderingDirty$jscomp$inline_249 = !0; + namesToPlugins[pluginName$jscomp$inline_249] = + pluginModule$jscomp$inline_250; + isOrderingDirty$jscomp$inline_248 = !0; } } -isOrderingDirty$jscomp$inline_249 && recomputePluginOrdering(); +isOrderingDirty$jscomp$inline_248 && recomputePluginOrdering(); var instanceCache = new Map(), instanceProps = new Map(); function getInstanceFromTag(tag) { @@ -9597,21 +9597,19 @@ function findNodeHandle(componentOrHandle) { null != componentOrHandle.canonical.nativeTag ) return componentOrHandle.canonical.nativeTag; - var nativeTag = componentOrHandle.__nativeTag; + var nativeTag = + ReactNativePrivateInterface.getNativeTagFromPublicInstance( + componentOrHandle + ); if (nativeTag) return nativeTag; componentOrHandle = findHostInstance(componentOrHandle); return null == componentOrHandle ? componentOrHandle : null != componentOrHandle._nativeTag ? componentOrHandle._nativeTag - : componentOrHandle.__nativeTag; -} -function getNodeFromPublicInstance(publicInstance) { - return null == publicInstance.__internalInstanceHandle - ? null - : (publicInstance = publicInstance.__internalInstanceHandle) && - publicInstance.stateNode && - publicInstance.stateNode.node; + : ReactNativePrivateInterface.getNativeTagFromPublicInstance( + componentOrHandle + ); } var emptyObject = {}; function createHierarchy(fiberHierarchy) { @@ -9692,10 +9690,10 @@ batchedUpdatesImpl = function (fn, a) { } }; var roots = new Map(), - devToolsConfig$jscomp$inline_1111 = { + devToolsConfig$jscomp$inline_1108 = { findFiberByHostInstance: getInstanceFromTag, bundleType: 0, - version: "18.3.0-next-f77099b6f-20230322", + version: "18.3.0-next-9c54b29b4-20230322", rendererPackageName: "react-native-renderer", rendererConfig: { getInspectorDataForViewTag: function () { @@ -9710,11 +9708,11 @@ var roots = new Map(), }.bind(null, findNodeHandle) } }; -var internals$jscomp$inline_1361 = { - bundleType: devToolsConfig$jscomp$inline_1111.bundleType, - version: devToolsConfig$jscomp$inline_1111.version, - rendererPackageName: devToolsConfig$jscomp$inline_1111.rendererPackageName, - rendererConfig: devToolsConfig$jscomp$inline_1111.rendererConfig, +var internals$jscomp$inline_1358 = { + bundleType: devToolsConfig$jscomp$inline_1108.bundleType, + version: devToolsConfig$jscomp$inline_1108.version, + rendererPackageName: devToolsConfig$jscomp$inline_1108.rendererPackageName, + rendererConfig: devToolsConfig$jscomp$inline_1108.rendererConfig, overrideHookState: null, overrideHookStateDeletePath: null, overrideHookStateRenamePath: null, @@ -9730,26 +9728,26 @@ var internals$jscomp$inline_1361 = { return null === fiber ? null : fiber.stateNode; }, findFiberByHostInstance: - devToolsConfig$jscomp$inline_1111.findFiberByHostInstance || + devToolsConfig$jscomp$inline_1108.findFiberByHostInstance || emptyFindFiberByHostInstance, findHostInstancesForRefresh: null, scheduleRefresh: null, scheduleRoot: null, setRefreshHandler: null, getCurrentFiber: null, - reconcilerVersion: "18.3.0-next-f77099b6f-20230322" + reconcilerVersion: "18.3.0-next-9c54b29b4-20230322" }; if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) { - var hook$jscomp$inline_1362 = __REACT_DEVTOOLS_GLOBAL_HOOK__; + var hook$jscomp$inline_1359 = __REACT_DEVTOOLS_GLOBAL_HOOK__; if ( - !hook$jscomp$inline_1362.isDisabled && - hook$jscomp$inline_1362.supportsFiber + !hook$jscomp$inline_1359.isDisabled && + hook$jscomp$inline_1359.supportsFiber ) try { - (rendererID = hook$jscomp$inline_1362.inject( - internals$jscomp$inline_1361 + (rendererID = hook$jscomp$inline_1359.inject( + internals$jscomp$inline_1358 )), - (injectedHook = hook$jscomp$inline_1362); + (injectedHook = hook$jscomp$inline_1359); } catch (err) {} } exports.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = { @@ -9769,9 +9767,11 @@ exports.createPortal = function (children, containerTag) { }; exports.dispatchCommand = function (handle, command, args) { var nativeTag = - null != handle._nativeTag ? handle._nativeTag : handle.__nativeTag; + null != handle._nativeTag + ? handle._nativeTag + : ReactNativePrivateInterface.getNativeTagFromPublicInstance(handle); null != nativeTag && - ((handle = getNodeFromPublicInstance(handle)), + ((handle = ReactNativePrivateInterface.getNodeFromPublicInstance(handle)), null != handle ? nativeFabricUIManager.dispatchCommand(handle, command, args) : ReactNativePrivateInterface.UIManager.dispatchViewManagerCommand( @@ -9853,9 +9853,11 @@ exports.render = function (element, containerTag, callback) { }; exports.sendAccessibilityEvent = function (handle, eventType) { var nativeTag = - null != handle._nativeTag ? handle._nativeTag : handle.__nativeTag; + null != handle._nativeTag + ? handle._nativeTag + : ReactNativePrivateInterface.getNativeTagFromPublicInstance(handle); null != nativeTag && - ((handle = getNodeFromPublicInstance(handle)), + ((handle = ReactNativePrivateInterface.getNodeFromPublicInstance(handle)), null != handle ? nativeFabricUIManager.sendAccessibilityEvent(handle, eventType) : ReactNativePrivateInterface.legacySendAccessibilityEvent( diff --git a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.fb.js b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.fb.js index c64af1ced68cd..afc2bc3c3b13c 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.fb.js +++ b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.fb.js @@ -951,7 +951,7 @@ eventPluginOrder = Array.prototype.slice.call([ "ReactNativeBridgeEventPlugin" ]); recomputePluginOrdering(); -var injectedNamesToPlugins$jscomp$inline_264 = { +var injectedNamesToPlugins$jscomp$inline_263 = { ResponderEventPlugin: ResponderEventPlugin, ReactNativeBridgeEventPlugin: { eventTypes: {}, @@ -997,32 +997,32 @@ var injectedNamesToPlugins$jscomp$inline_264 = { } } }, - isOrderingDirty$jscomp$inline_265 = !1, - pluginName$jscomp$inline_266; -for (pluginName$jscomp$inline_266 in injectedNamesToPlugins$jscomp$inline_264) + isOrderingDirty$jscomp$inline_264 = !1, + pluginName$jscomp$inline_265; +for (pluginName$jscomp$inline_265 in injectedNamesToPlugins$jscomp$inline_263) if ( - injectedNamesToPlugins$jscomp$inline_264.hasOwnProperty( - pluginName$jscomp$inline_266 + injectedNamesToPlugins$jscomp$inline_263.hasOwnProperty( + pluginName$jscomp$inline_265 ) ) { - var pluginModule$jscomp$inline_267 = - injectedNamesToPlugins$jscomp$inline_264[pluginName$jscomp$inline_266]; + var pluginModule$jscomp$inline_266 = + injectedNamesToPlugins$jscomp$inline_263[pluginName$jscomp$inline_265]; if ( - !namesToPlugins.hasOwnProperty(pluginName$jscomp$inline_266) || - namesToPlugins[pluginName$jscomp$inline_266] !== - pluginModule$jscomp$inline_267 + !namesToPlugins.hasOwnProperty(pluginName$jscomp$inline_265) || + namesToPlugins[pluginName$jscomp$inline_265] !== + pluginModule$jscomp$inline_266 ) { - if (namesToPlugins[pluginName$jscomp$inline_266]) + if (namesToPlugins[pluginName$jscomp$inline_265]) throw Error( "EventPluginRegistry: Cannot inject two different event plugins using the same name, `" + - (pluginName$jscomp$inline_266 + "`.") + (pluginName$jscomp$inline_265 + "`.") ); - namesToPlugins[pluginName$jscomp$inline_266] = - pluginModule$jscomp$inline_267; - isOrderingDirty$jscomp$inline_265 = !0; + namesToPlugins[pluginName$jscomp$inline_265] = + pluginModule$jscomp$inline_266; + isOrderingDirty$jscomp$inline_264 = !0; } } -isOrderingDirty$jscomp$inline_265 && recomputePluginOrdering(); +isOrderingDirty$jscomp$inline_264 && recomputePluginOrdering(); var instanceCache = new Map(), instanceProps = new Map(); function getInstanceFromTag(tag) { @@ -10305,21 +10305,19 @@ function findNodeHandle(componentOrHandle) { null != componentOrHandle.canonical.nativeTag ) return componentOrHandle.canonical.nativeTag; - var nativeTag = componentOrHandle.__nativeTag; + var nativeTag = + ReactNativePrivateInterface.getNativeTagFromPublicInstance( + componentOrHandle + ); if (nativeTag) return nativeTag; componentOrHandle = findHostInstance(componentOrHandle); return null == componentOrHandle ? componentOrHandle : null != componentOrHandle._nativeTag ? componentOrHandle._nativeTag - : componentOrHandle.__nativeTag; -} -function getNodeFromPublicInstance(publicInstance) { - return null == publicInstance.__internalInstanceHandle - ? null - : (publicInstance = publicInstance.__internalInstanceHandle) && - publicInstance.stateNode && - publicInstance.stateNode.node; + : ReactNativePrivateInterface.getNativeTagFromPublicInstance( + componentOrHandle + ); } var emptyObject = {}; function createHierarchy(fiberHierarchy) { @@ -10400,10 +10398,10 @@ batchedUpdatesImpl = function (fn, a) { } }; var roots = new Map(), - devToolsConfig$jscomp$inline_1190 = { + devToolsConfig$jscomp$inline_1187 = { findFiberByHostInstance: getInstanceFromTag, bundleType: 0, - version: "18.3.0-next-f77099b6f-20230322", + version: "18.3.0-next-9c54b29b4-20230322", rendererPackageName: "react-native-renderer", rendererConfig: { getInspectorDataForViewTag: function () { @@ -10432,10 +10430,10 @@ var roots = new Map(), } catch (err) {} return hook.checkDCE ? !0 : !1; })({ - bundleType: devToolsConfig$jscomp$inline_1190.bundleType, - version: devToolsConfig$jscomp$inline_1190.version, - rendererPackageName: devToolsConfig$jscomp$inline_1190.rendererPackageName, - rendererConfig: devToolsConfig$jscomp$inline_1190.rendererConfig, + bundleType: devToolsConfig$jscomp$inline_1187.bundleType, + version: devToolsConfig$jscomp$inline_1187.version, + rendererPackageName: devToolsConfig$jscomp$inline_1187.rendererPackageName, + rendererConfig: devToolsConfig$jscomp$inline_1187.rendererConfig, overrideHookState: null, overrideHookStateDeletePath: null, overrideHookStateRenamePath: null, @@ -10451,14 +10449,14 @@ var roots = new Map(), return null === fiber ? null : fiber.stateNode; }, findFiberByHostInstance: - devToolsConfig$jscomp$inline_1190.findFiberByHostInstance || + devToolsConfig$jscomp$inline_1187.findFiberByHostInstance || emptyFindFiberByHostInstance, findHostInstancesForRefresh: null, scheduleRefresh: null, scheduleRoot: null, setRefreshHandler: null, getCurrentFiber: null, - reconcilerVersion: "18.3.0-next-f77099b6f-20230322" + reconcilerVersion: "18.3.0-next-9c54b29b4-20230322" }); exports.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = { computeComponentStackForErrorReporting: function (reactTag) { @@ -10477,9 +10475,11 @@ exports.createPortal = function (children, containerTag) { }; exports.dispatchCommand = function (handle, command, args) { var nativeTag = - null != handle._nativeTag ? handle._nativeTag : handle.__nativeTag; + null != handle._nativeTag + ? handle._nativeTag + : ReactNativePrivateInterface.getNativeTagFromPublicInstance(handle); null != nativeTag && - ((handle = getNodeFromPublicInstance(handle)), + ((handle = ReactNativePrivateInterface.getNodeFromPublicInstance(handle)), null != handle ? nativeFabricUIManager.dispatchCommand(handle, command, args) : ReactNativePrivateInterface.UIManager.dispatchViewManagerCommand( @@ -10568,9 +10568,11 @@ exports.render = function (element, containerTag, callback) { }; exports.sendAccessibilityEvent = function (handle, eventType) { var nativeTag = - null != handle._nativeTag ? handle._nativeTag : handle.__nativeTag; + null != handle._nativeTag + ? handle._nativeTag + : ReactNativePrivateInterface.getNativeTagFromPublicInstance(handle); null != nativeTag && - ((handle = getNodeFromPublicInstance(handle)), + ((handle = ReactNativePrivateInterface.getNodeFromPublicInstance(handle)), null != handle ? nativeFabricUIManager.sendAccessibilityEvent(handle, eventType) : ReactNativePrivateInterface.legacySendAccessibilityEvent(