diff --git a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-is/cjs/ReactIs-dev.js b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-is/cjs/ReactIs-dev.js index 8ab25aaee0d27..fa2bc4db06197 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-is/cjs/ReactIs-dev.js +++ b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-is/cjs/ReactIs-dev.js @@ -7,232 +7,207 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<> + * @generated SignedSource<<4b798dcd431887c30b264d36a3b13441>> */ -"use strict"; +'use strict'; if (__DEV__) { - (function () { - "use strict"; - - var dynamicFlagsUntyped = require("ReactNativeInternalFeatureFlags"); - - // 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"); // TODO: Delete with enableRenderableContext - - var REACT_CONSUMER_TYPE = Symbol.for("react.consumer"); - var REACT_CONTEXT_TYPE = Symbol.for("react.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_OFFSCREEN_TYPE = Symbol.for("react.offscreen"); - - // Re-export dynamic flags from the internal module. - var dynamicFlags = dynamicFlagsUntyped; // We destructure each value before re-exporting to avoid a dynamic look-up on - // the exports object every time a flag is read. - - var enableRenderableContext = dynamicFlags.enableRenderableContext; - // The rest of the flags are static for better dead code elimination. - var enableDebugTracing = false; - var enableScopeAPI = false; - var enableLegacyHidden = false; - var enableTransitionTracing = false; - - var REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference"); - function isValidElementType(type) { - if (typeof type === "string" || typeof type === "function") { - return true; - } // Note: typeof might be other than 'symbol' or 'number' (e.g. if it's a polyfill). - - if ( - type === REACT_FRAGMENT_TYPE || - type === REACT_PROFILER_TYPE || - enableDebugTracing || - type === REACT_STRICT_MODE_TYPE || - type === REACT_SUSPENSE_TYPE || - type === REACT_SUSPENSE_LIST_TYPE || - enableLegacyHidden || - type === REACT_OFFSCREEN_TYPE || - enableScopeAPI || - enableTransitionTracing - ) { - return true; - } - - if (typeof type === "object" && type !== null) { - if ( - type.$$typeof === REACT_LAZY_TYPE || - type.$$typeof === REACT_MEMO_TYPE || - type.$$typeof === REACT_CONTEXT_TYPE || - (!enableRenderableContext && type.$$typeof === REACT_PROVIDER_TYPE) || - (enableRenderableContext && type.$$typeof === REACT_CONSUMER_TYPE) || - type.$$typeof === REACT_FORWARD_REF_TYPE || // This needs to include all possible module reference object - // types supported by any Flight configuration anywhere since - // we don't know which Flight build this will end up being used - // with. - type.$$typeof === REACT_CLIENT_REFERENCE || - type.getModuleId !== undefined - ) { - return true; - } - } - - return false; + (function() { +'use strict'; + +var dynamicFlagsUntyped = require('ReactNativeInternalFeatureFlags'); + +// 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'); // TODO: Delete with enableRenderableContext + +var REACT_CONSUMER_TYPE = Symbol.for('react.consumer'); +var REACT_CONTEXT_TYPE = Symbol.for('react.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_OFFSCREEN_TYPE = Symbol.for('react.offscreen'); + +// Re-export dynamic flags from the internal module. +var dynamicFlags = dynamicFlagsUntyped; // We destructure each value before re-exporting to avoid a dynamic look-up on +// the exports object every time a flag is read. + +var enableRenderableContext = dynamicFlags.enableRenderableContext; + // The rest of the flags are static for better dead code elimination. +var enableDebugTracing = false; +var enableScopeAPI = false; +var enableLegacyHidden = false; +var enableTransitionTracing = false; + +var REACT_CLIENT_REFERENCE = Symbol.for('react.client.reference'); +function isValidElementType(type) { + if (typeof type === 'string' || typeof type === 'function') { + return true; + } // Note: typeof might be other than 'symbol' or 'number' (e.g. if it's a polyfill). + + + if (type === REACT_FRAGMENT_TYPE || type === REACT_PROFILER_TYPE || enableDebugTracing || type === REACT_STRICT_MODE_TYPE || type === REACT_SUSPENSE_TYPE || type === REACT_SUSPENSE_LIST_TYPE || enableLegacyHidden || type === REACT_OFFSCREEN_TYPE || enableScopeAPI || enableTransitionTracing ) { + return true; + } + + if (typeof type === 'object' && type !== null) { + if (type.$$typeof === REACT_LAZY_TYPE || type.$$typeof === REACT_MEMO_TYPE || type.$$typeof === REACT_CONTEXT_TYPE || !enableRenderableContext && type.$$typeof === REACT_PROVIDER_TYPE || enableRenderableContext && type.$$typeof === REACT_CONSUMER_TYPE || type.$$typeof === REACT_FORWARD_REF_TYPE || // This needs to include all possible module reference object + // types supported by any Flight configuration anywhere since + // we don't know which Flight build this will end up being used + // with. + type.$$typeof === REACT_CLIENT_REFERENCE || type.getModuleId !== undefined) { + return true; } + } - function typeOf(object) { - if (typeof object === "object" && object !== null) { - var $$typeof = object.$$typeof; - - switch ($$typeof) { - case REACT_ELEMENT_TYPE: - var type = object.type; - - switch (type) { - case REACT_FRAGMENT_TYPE: - case REACT_PROFILER_TYPE: - case REACT_STRICT_MODE_TYPE: - case REACT_SUSPENSE_TYPE: - case REACT_SUSPENSE_LIST_TYPE: - return type; - - default: - var $$typeofType = type && type.$$typeof; - - switch ($$typeofType) { - case REACT_CONTEXT_TYPE: - case REACT_FORWARD_REF_TYPE: - case REACT_LAZY_TYPE: - case REACT_MEMO_TYPE: - return $$typeofType; + return false; +} - case REACT_CONSUMER_TYPE: - if (enableRenderableContext) { - return $$typeofType; - } +function typeOf(object) { + if (typeof object === 'object' && object !== null) { + var $$typeof = object.$$typeof; + + switch ($$typeof) { + case REACT_ELEMENT_TYPE: + var type = object.type; + + switch (type) { + case REACT_FRAGMENT_TYPE: + case REACT_PROFILER_TYPE: + case REACT_STRICT_MODE_TYPE: + case REACT_SUSPENSE_TYPE: + case REACT_SUSPENSE_LIST_TYPE: + return type; + + default: + var $$typeofType = type && type.$$typeof; + + switch ($$typeofType) { + case REACT_CONTEXT_TYPE: + case REACT_FORWARD_REF_TYPE: + case REACT_LAZY_TYPE: + case REACT_MEMO_TYPE: + return $$typeofType; + + case REACT_CONSUMER_TYPE: + if (enableRenderableContext) { + return $$typeofType; + } - // Fall through + // Fall through - case REACT_PROVIDER_TYPE: - if (!enableRenderableContext) { - return $$typeofType; - } + case REACT_PROVIDER_TYPE: + if (!enableRenderableContext) { + return $$typeofType; + } - // Fall through + // Fall through - default: - return $$typeof; - } + default: + return $$typeof; } - case REACT_PORTAL_TYPE: - return $$typeof; } - } - return undefined; - } - var ContextConsumer = enableRenderableContext - ? REACT_CONSUMER_TYPE - : REACT_CONTEXT_TYPE; - var ContextProvider = enableRenderableContext - ? REACT_CONTEXT_TYPE - : REACT_PROVIDER_TYPE; - var Element = REACT_ELEMENT_TYPE; - var ForwardRef = REACT_FORWARD_REF_TYPE; - var Fragment = REACT_FRAGMENT_TYPE; - var Lazy = REACT_LAZY_TYPE; - var Memo = REACT_MEMO_TYPE; - var Portal = REACT_PORTAL_TYPE; - var Profiler = REACT_PROFILER_TYPE; - var StrictMode = REACT_STRICT_MODE_TYPE; - var Suspense = REACT_SUSPENSE_TYPE; - var SuspenseList = REACT_SUSPENSE_LIST_TYPE; - function isContextConsumer(object) { - if (enableRenderableContext) { - return typeOf(object) === REACT_CONSUMER_TYPE; - } else { - return typeOf(object) === REACT_CONTEXT_TYPE; - } - } - function isContextProvider(object) { - if (enableRenderableContext) { - return typeOf(object) === REACT_CONTEXT_TYPE; - } else { - return typeOf(object) === REACT_PROVIDER_TYPE; - } - } - function isElement(object) { - return ( - typeof object === "object" && - object !== null && - object.$$typeof === REACT_ELEMENT_TYPE - ); - } - function isForwardRef(object) { - return typeOf(object) === REACT_FORWARD_REF_TYPE; - } - function isFragment(object) { - return typeOf(object) === REACT_FRAGMENT_TYPE; - } - function isLazy(object) { - return typeOf(object) === REACT_LAZY_TYPE; - } - function isMemo(object) { - return typeOf(object) === REACT_MEMO_TYPE; - } - function isPortal(object) { - return typeOf(object) === REACT_PORTAL_TYPE; - } - function isProfiler(object) { - return typeOf(object) === REACT_PROFILER_TYPE; - } - function isStrictMode(object) { - return typeOf(object) === REACT_STRICT_MODE_TYPE; - } - function isSuspense(object) { - return typeOf(object) === REACT_SUSPENSE_TYPE; - } - function isSuspenseList(object) { - return typeOf(object) === REACT_SUSPENSE_LIST_TYPE; + case REACT_PORTAL_TYPE: + return $$typeof; } + } + + return undefined; +} +var ContextConsumer = enableRenderableContext ? REACT_CONSUMER_TYPE : REACT_CONTEXT_TYPE; +var ContextProvider = enableRenderableContext ? REACT_CONTEXT_TYPE : REACT_PROVIDER_TYPE; +var Element = REACT_ELEMENT_TYPE; +var ForwardRef = REACT_FORWARD_REF_TYPE; +var Fragment = REACT_FRAGMENT_TYPE; +var Lazy = REACT_LAZY_TYPE; +var Memo = REACT_MEMO_TYPE; +var Portal = REACT_PORTAL_TYPE; +var Profiler = REACT_PROFILER_TYPE; +var StrictMode = REACT_STRICT_MODE_TYPE; +var Suspense = REACT_SUSPENSE_TYPE; +var SuspenseList = REACT_SUSPENSE_LIST_TYPE; +function isContextConsumer(object) { + if (enableRenderableContext) { + return typeOf(object) === REACT_CONSUMER_TYPE; + } else { + return typeOf(object) === REACT_CONTEXT_TYPE; + } +} +function isContextProvider(object) { + if (enableRenderableContext) { + return typeOf(object) === REACT_CONTEXT_TYPE; + } else { + return typeOf(object) === REACT_PROVIDER_TYPE; + } +} +function isElement(object) { + return typeof object === 'object' && object !== null && object.$$typeof === REACT_ELEMENT_TYPE; +} +function isForwardRef(object) { + return typeOf(object) === REACT_FORWARD_REF_TYPE; +} +function isFragment(object) { + return typeOf(object) === REACT_FRAGMENT_TYPE; +} +function isLazy(object) { + return typeOf(object) === REACT_LAZY_TYPE; +} +function isMemo(object) { + return typeOf(object) === REACT_MEMO_TYPE; +} +function isPortal(object) { + return typeOf(object) === REACT_PORTAL_TYPE; +} +function isProfiler(object) { + return typeOf(object) === REACT_PROFILER_TYPE; +} +function isStrictMode(object) { + return typeOf(object) === REACT_STRICT_MODE_TYPE; +} +function isSuspense(object) { + return typeOf(object) === REACT_SUSPENSE_TYPE; +} +function isSuspenseList(object) { + return typeOf(object) === REACT_SUSPENSE_LIST_TYPE; +} - exports.ContextConsumer = ContextConsumer; - exports.ContextProvider = ContextProvider; - exports.Element = Element; - exports.ForwardRef = ForwardRef; - exports.Fragment = Fragment; - exports.Lazy = Lazy; - exports.Memo = Memo; - exports.Portal = Portal; - exports.Profiler = Profiler; - exports.StrictMode = StrictMode; - exports.Suspense = Suspense; - exports.SuspenseList = SuspenseList; - exports.isContextConsumer = isContextConsumer; - exports.isContextProvider = isContextProvider; - exports.isElement = isElement; - exports.isForwardRef = isForwardRef; - exports.isFragment = isFragment; - exports.isLazy = isLazy; - exports.isMemo = isMemo; - exports.isPortal = isPortal; - exports.isProfiler = isProfiler; - exports.isStrictMode = isStrictMode; - exports.isSuspense = isSuspense; - exports.isSuspenseList = isSuspenseList; - exports.isValidElementType = isValidElementType; - exports.typeOf = typeOf; +exports.ContextConsumer = ContextConsumer; +exports.ContextProvider = ContextProvider; +exports.Element = Element; +exports.ForwardRef = ForwardRef; +exports.Fragment = Fragment; +exports.Lazy = Lazy; +exports.Memo = Memo; +exports.Portal = Portal; +exports.Profiler = Profiler; +exports.StrictMode = StrictMode; +exports.Suspense = Suspense; +exports.SuspenseList = SuspenseList; +exports.isContextConsumer = isContextConsumer; +exports.isContextProvider = isContextProvider; +exports.isElement = isElement; +exports.isForwardRef = isForwardRef; +exports.isFragment = isFragment; +exports.isLazy = isLazy; +exports.isMemo = isMemo; +exports.isPortal = isPortal; +exports.isProfiler = isProfiler; +exports.isStrictMode = isStrictMode; +exports.isSuspense = isSuspense; +exports.isSuspenseList = isSuspenseList; +exports.isValidElementType = isValidElementType; +exports.typeOf = typeOf; })(); } 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 e23f78a77de97..3d412c54b2090 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 @@ -7,8777 +7,7735 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<> + * @generated SignedSource<> */ -"use strict"; +'use strict'; if (__DEV__) { - (function () { - "use strict"; + (function() { +'use strict'; - var React = require("react"); - var Scheduler = require("scheduler/unstable_mock"); - var Scheduler$1 = require("scheduler"); +var React = require('react'); +var Scheduler = require('scheduler/unstable_mock'); +var Scheduler$1 = require('scheduler'); - var ReactSharedInternals = - React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE; +var ReactSharedInternals = React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE; - // by calls to these methods by a Babel plugin. - // - // In PROD (or in packages without access to React internals), - // they are left as they are instead. - - function warn(format) { - { - { - for ( - var _len = arguments.length, - args = new Array(_len > 1 ? _len - 1 : 0), - _key = 1; - _key < _len; - _key++ - ) { - args[_key - 1] = arguments[_key]; - } +// by calls to these methods by a Babel plugin. +// +// In PROD (or in packages without access to React internals), +// they are left as they are instead. - printWarning("warn", format, args); - } +function warn(format) { + { + { + for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; } - } - function error(format) { - { - { - for ( - var _len2 = arguments.length, - args = new Array(_len2 > 1 ? _len2 - 1 : 0), - _key2 = 1; - _key2 < _len2; - _key2++ - ) { - args[_key2 - 1] = arguments[_key2]; - } - printWarning("error", format, args); - } - } + printWarning('warn', format, args); } - - function printWarning(level, format, args) { - // When changing this logic, you might want to also - // update consoleWithStackDev.www.js as well. - { - var stack = ReactSharedInternals.getStackAddendum(); - - if (stack !== "") { - format += "%s"; - args = args.concat([stack]); - } // eslint-disable-next-line react-internal/safe-string-coercion - - var argsWithFormat = args.map(function (item) { - return String(item); - }); // Careful: RN currently depends on this prefix - - argsWithFormat.unshift("Warning: " + format); // We intentionally don't use spread (or .apply) directly because it - // breaks IE9: https://github.com/facebook/react/issues/13610 - // eslint-disable-next-line react-internal/no-production-logging - - Function.prototype.apply.call(console[level], console, argsWithFormat); - } - } - - function _defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || false; - descriptor.configurable = true; - if ("value" in descriptor) descriptor.writable = true; - Object.defineProperty(target, descriptor.key, descriptor); - } - } - - function _createClass(Constructor, protoProps, staticProps) { - if (protoProps) _defineProperties(Constructor.prototype, protoProps); - if (staticProps) _defineProperties(Constructor, staticProps); - return Constructor; - } - - function _objectWithoutPropertiesLoose(source, excluded) { - if (source == null) return {}; - var target = {}; - var sourceKeys = Object.keys(source); - var key, i; - - for (i = 0; i < sourceKeys.length; i++) { - key = sourceKeys[i]; - if (excluded.indexOf(key) >= 0) continue; - target[key] = source[key]; - } - - return target; - } - - var assign = Object.assign; - - var LegacyRoot = 0; - var ConcurrentRoot = 1; - - /** - * `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; - } - - var debugRenderPhaseSideEffectsForStrictMode = false; - var enableSchedulingProfiler = true; - var enableProfilerTimer = true; - var enableProfilerCommitHooks = true; - var enableProfilerNestedUpdatePhase = true; - var syncLaneExpirationMs = 250; - var transitionLaneExpirationMs = 5000; - var enableLazyContextPropagation = false; - var enableLegacyHidden = false; - var enableAsyncActions = true; - var disableLegacyMode = false; - - var FunctionComponent = 0; - var ClassComponent = 1; - var HostRoot = 3; // Root of a host tree. Could be nested inside another node. - - var HostPortal = 4; // A subtree. Could be an entry point to a different renderer. - - var HostComponent = 5; - var HostText = 6; - var Fragment = 7; - var Mode = 8; - var ContextConsumer = 9; - var ContextProvider = 10; - var ForwardRef = 11; - var Profiler = 12; - var SuspenseComponent = 13; - var MemoComponent = 14; - var SimpleMemoComponent = 15; - var LazyComponent = 16; - var IncompleteClassComponent = 17; - var DehydratedFragment = 18; - var SuspenseListComponent = 19; - var ScopeComponent = 21; - var OffscreenComponent = 22; - var LegacyHiddenComponent = 23; - var CacheComponent = 24; - var TracingMarkerComponent = 25; - var HostHoistable = 26; - var HostSingleton = 27; - var IncompleteFunctionComponent = 28; - - // 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"); // TODO: Delete with enableRenderableContext - - var REACT_CONSUMER_TYPE = Symbol.for("react.consumer"); - var REACT_CONTEXT_TYPE = Symbol.for("react.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_TRACING_MARKER_TYPE = Symbol.for("react.tracing_marker"); - 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 error(format) { + { + { + for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { + args[_key2 - 1] = arguments[_key2]; } - var maybeIterator = - (MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL]) || - maybeIterable[FAUX_ITERATOR_SYMBOL]; + printWarning('error', format, args); + } + } +} - if (typeof maybeIterator === "function") { - return maybeIterator; - } +function printWarning(level, format, args) { + // When changing this logic, you might want to also + // update consoleWithStackDev.www.js as well. + { + var stack = ReactSharedInternals.getStackAddendum(); - return null; - } + if (stack !== '') { + format += '%s'; + args = args.concat([stack]); + } // eslint-disable-next-line react-internal/safe-string-coercion - function getWrappedName$1(outerType, innerType, wrapperName) { - var displayName = outerType.displayName; - if (displayName) { - return displayName; - } + var argsWithFormat = args.map(function (item) { + return String(item); + }); // Careful: RN currently depends on this prefix - var functionName = innerType.displayName || innerType.name || ""; - return functionName !== "" - ? wrapperName + "(" + functionName + ")" - : wrapperName; - } // Keep in sync with react-reconciler/getComponentNameFromFiber + argsWithFormat.unshift('Warning: ' + format); // We intentionally don't use spread (or .apply) directly because it + // breaks IE9: https://github.com/facebook/react/issues/13610 + // eslint-disable-next-line react-internal/no-production-logging - function getContextName$1(type) { - return type.displayName || "Context"; - } + Function.prototype.apply.call(console[level], console, argsWithFormat); + } +} - var REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference"); // Note that the reconciler package should generally prefer to use getComponentNameFromFiber() instead. +function _defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } +} - function getComponentNameFromType(type) { - if (type == null) { - // Host root, text node or just invalid type. - return null; - } +function _createClass(Constructor, protoProps, staticProps) { + if (protoProps) _defineProperties(Constructor.prototype, protoProps); + if (staticProps) _defineProperties(Constructor, staticProps); + return Constructor; +} - if (typeof type === "function") { - if (type.$$typeof === REACT_CLIENT_REFERENCE) { - // TODO: Create a convention for naming client references with debug info. - return null; - } +function _objectWithoutPropertiesLoose(source, excluded) { + if (source == null) return {}; + var target = {}; + var sourceKeys = Object.keys(source); + var key, i; - return type.displayName || type.name || null; - } + for (i = 0; i < sourceKeys.length; i++) { + key = sourceKeys[i]; + if (excluded.indexOf(key) >= 0) continue; + target[key] = source[key]; + } - if (typeof type === "string") { - return type; - } + return target; +} - switch (type) { - case REACT_FRAGMENT_TYPE: - return "Fragment"; +var assign = Object.assign; - case REACT_PORTAL_TYPE: - return "Portal"; +var LegacyRoot = 0; +var ConcurrentRoot = 1; - case REACT_PROFILER_TYPE: - return "Profiler"; +/** + * `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; +} - case REACT_STRICT_MODE_TYPE: - return "StrictMode"; +var debugRenderPhaseSideEffectsForStrictMode = false; +var enableSchedulingProfiler = true; +var enableProfilerTimer = true; +var enableProfilerCommitHooks = true; +var enableProfilerNestedUpdatePhase = true; +var syncLaneExpirationMs = 250; +var transitionLaneExpirationMs = 5000; +var enableLazyContextPropagation = false; +var enableLegacyHidden = false; +var enableAsyncActions = true; +var disableLegacyMode = false; + +var FunctionComponent = 0; +var ClassComponent = 1; +var HostRoot = 3; // Root of a host tree. Could be nested inside another node. + +var HostPortal = 4; // A subtree. Could be an entry point to a different renderer. + +var HostComponent = 5; +var HostText = 6; +var Fragment = 7; +var Mode = 8; +var ContextConsumer = 9; +var ContextProvider = 10; +var ForwardRef = 11; +var Profiler = 12; +var SuspenseComponent = 13; +var MemoComponent = 14; +var SimpleMemoComponent = 15; +var LazyComponent = 16; +var IncompleteClassComponent = 17; +var DehydratedFragment = 18; +var SuspenseListComponent = 19; +var ScopeComponent = 21; +var OffscreenComponent = 22; +var LegacyHiddenComponent = 23; +var CacheComponent = 24; +var TracingMarkerComponent = 25; +var HostHoistable = 26; +var HostSingleton = 27; +var IncompleteFunctionComponent = 28; + +// 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'); // TODO: Delete with enableRenderableContext + +var REACT_CONSUMER_TYPE = Symbol.for('react.consumer'); +var REACT_CONTEXT_TYPE = Symbol.for('react.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_TRACING_MARKER_TYPE = Symbol.for('react.tracing_marker'); +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 maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]; + + if (typeof maybeIterator === 'function') { + return maybeIterator; + } + + return null; +} - case REACT_SUSPENSE_TYPE: - return "Suspense"; +function getWrappedName$1(outerType, innerType, wrapperName) { + var displayName = outerType.displayName; - case REACT_SUSPENSE_LIST_TYPE: - return "SuspenseList"; - } + if (displayName) { + return displayName; + } - if (typeof type === "object") { - { - if (typeof type.tag === "number") { - error( - "Received an unexpected object in getComponentNameFromType(). " + - "This is likely a bug in React. Please file an issue." - ); - } - } + var functionName = innerType.displayName || innerType.name || ''; + return functionName !== '' ? wrapperName + "(" + functionName + ")" : wrapperName; +} // Keep in sync with react-reconciler/getComponentNameFromFiber - switch (type.$$typeof) { - case REACT_PROVIDER_TYPE: { - var provider = type; - return getContextName$1(provider._context) + ".Provider"; - } - case REACT_CONTEXT_TYPE: - var context = type; +function getContextName$1(type) { + return type.displayName || 'Context'; +} - { - return getContextName$1(context) + ".Consumer"; - } +var REACT_CLIENT_REFERENCE = Symbol.for('react.client.reference'); // Note that the reconciler package should generally prefer to use getComponentNameFromFiber() instead. - case REACT_CONSUMER_TYPE: { - return null; - } +function getComponentNameFromType(type) { + if (type == null) { + // Host root, text node or just invalid type. + return null; + } - case REACT_FORWARD_REF_TYPE: - return getWrappedName$1(type, type.render, "ForwardRef"); + if (typeof type === 'function') { + if (type.$$typeof === REACT_CLIENT_REFERENCE) { + // TODO: Create a convention for naming client references with debug info. + return null; + } - case REACT_MEMO_TYPE: - var outerName = type.displayName || null; + return type.displayName || type.name || null; + } - if (outerName !== null) { - return outerName; - } + if (typeof type === 'string') { + return type; + } - return getComponentNameFromType(type.type) || "Memo"; + switch (type) { + case REACT_FRAGMENT_TYPE: + return 'Fragment'; - case REACT_LAZY_TYPE: { - var lazyComponent = type; - var payload = lazyComponent._payload; - var init = lazyComponent._init; + case REACT_PORTAL_TYPE: + return 'Portal'; - try { - return getComponentNameFromType(init(payload)); - } catch (x) { - return null; - } - } - } - } + case REACT_PROFILER_TYPE: + return 'Profiler'; - return null; - } + case REACT_STRICT_MODE_TYPE: + return 'StrictMode'; - function getWrappedName(outerType, innerType, wrapperName) { - var functionName = innerType.displayName || innerType.name || ""; - return ( - outerType.displayName || - (functionName !== "" - ? wrapperName + "(" + functionName + ")" - : wrapperName) - ); - } // Keep in sync with shared/getComponentNameFromType + case REACT_SUSPENSE_TYPE: + return 'Suspense'; - function getContextName(type) { - return type.displayName || "Context"; - } + case REACT_SUSPENSE_LIST_TYPE: + return 'SuspenseList'; - function getComponentNameFromOwner(owner) { - if (typeof owner.tag === "number") { - return getComponentNameFromFiber(owner); - } + } - if (typeof owner.name === "string") { - return owner.name; + if (typeof type === 'object') { + { + if (typeof type.tag === 'number') { + error('Received an unexpected object in getComponentNameFromType(). ' + 'This is likely a bug in React. Please file an issue.'); } - - return null; } - 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: { + switch (type.$$typeof) { + case REACT_PROVIDER_TYPE: + { var provider = type; - return getContextName(provider._context) + ".Provider"; + return getContextName$1(provider._context) + '.Provider'; } - case DehydratedFragment: - return "DehydratedFragment"; + case REACT_CONTEXT_TYPE: + var context = type; - case ForwardRef: - return getWrappedName(type, type.render, "ForwardRef"); + { + return getContextName$1(context) + '.Consumer'; + } - case Fragment: - return "Fragment"; + case REACT_CONSUMER_TYPE: + { + return null; + } - case HostHoistable: - case HostSingleton: - case HostComponent: - // Host component type is the display name (e.g. "div", "View") - return type; + case REACT_FORWARD_REF_TYPE: + return getWrappedName$1(type, type.render, 'ForwardRef'); - case HostPortal: - return "Portal"; + case REACT_MEMO_TYPE: + var outerName = type.displayName || null; - case HostRoot: - return "Root"; + if (outerName !== null) { + return outerName; + } - case HostText: - return "Text"; + return getComponentNameFromType(type.type) || 'Memo'; - case LazyComponent: - // Name comes from the type in this case; we don't have a tag. - return getComponentNameFromType(type); + case REACT_LAZY_TYPE: + { + var lazyComponent = type; + var payload = lazyComponent._payload; + var init = lazyComponent._init; - case Mode: - if (type === REACT_STRICT_MODE_TYPE) { - // Don't be less specific than shared/getComponentNameFromType - return "StrictMode"; + try { + return getComponentNameFromType(init(payload)); + } catch (x) { + return null; } + } + } + } - return "Mode"; - - case OffscreenComponent: - return "Offscreen"; - - case Profiler: - return "Profiler"; + return null; +} - case ScopeComponent: - return "Scope"; +function getWrappedName(outerType, innerType, wrapperName) { + var functionName = innerType.displayName || innerType.name || ''; + return outerType.displayName || (functionName !== '' ? wrapperName + "(" + functionName + ")" : wrapperName); +} // Keep in sync with shared/getComponentNameFromType - case SuspenseComponent: - return "Suspense"; - case SuspenseListComponent: - return "SuspenseList"; +function getContextName(type) { + return type.displayName || 'Context'; +} - case TracingMarkerComponent: - return "TracingMarker"; - // The display name for these tags come from the user-provided type: +function getComponentNameFromOwner(owner) { + if (typeof owner.tag === 'number') { + return getComponentNameFromFiber(owner); + } - case IncompleteClassComponent: - case IncompleteFunctionComponent: + if (typeof owner.name === 'string') { + return owner.name; + } - // Fallthrough + return null; +} +function getComponentNameFromFiber(fiber) { + var tag = fiber.tag, + type = fiber.type; - case ClassComponent: - case FunctionComponent: - case MemoComponent: - case SimpleMemoComponent: - if (typeof type === "function") { - return type.displayName || type.name || null; - } + switch (tag) { + case CacheComponent: + return 'Cache'; - if (typeof type === "string") { - return type; - } + case ContextConsumer: + { + var context = type; + return getContextName(context) + '.Consumer'; + } - break; + case ContextProvider: + { + var provider = type; + return getContextName(provider._context) + '.Provider'; } - return null; - } + case DehydratedFragment: + return 'DehydratedFragment'; - var NoFlags$1 = - /* */ - 0; - var PerformedWork = - /* */ - 1; - var Placement = - /* */ - 2; - var DidCapture = - /* */ - 128; - var Hydrating = - /* */ - 4096; // You can change the rest (and add more). - - var Update = - /* */ - 4; - /* Skipped value: 0b0000000000000000000000001000; */ - - var ChildDeletion = - /* */ - 16; - var ContentReset = - /* */ - 32; - var Callback = - /* */ - 64; - /* Used by DidCapture: 0b0000000000000000000010000000; */ - - var ForceClientRender = - /* */ - 256; - var Ref = - /* */ - 512; - var Snapshot = - /* */ - 1024; - var Passive$1 = - /* */ - 2048; - /* Used by Hydrating: 0b0000000000000001000000000000; */ - - var Visibility = - /* */ - 8192; - var StoreConsistency = - /* */ - 16384; // It's OK to reuse these bits because these flags are mutually exclusive for - // different fiber types. We should really be doing this for as many flags as - // possible, because we're about to run out of bits. - - var ScheduleRetry = StoreConsistency; - var ShouldSuspendCommit = Visibility; - var DidDefer = ContentReset; - var FormReset = Snapshot; - var LifecycleEffectMask = - Passive$1 | Update | Callback | Ref | Snapshot | StoreConsistency; // Union of all commit flags (flags with the lifetime of a particular commit) - - var HostEffectMask = - /* */ - 32767; // These are not really side effects, but we still reuse this field. - - var Incomplete = - /* */ - 32768; - var ShouldCapture = - /* */ - 65536; - var ForceUpdateForLegacySuspense = - /* */ - 131072; - var Forked = - /* */ - 1048576; // Static tags describe aspects of a fiber that are not specific to a render, - // e.g. a fiber uses a passive effect (even if there are no updates on this particular render). - // This enables us to defer more work in the unmount case, - // since we can defer traversing the tree during layout to look for Passive effects, - // and instead rely on the static flag as a signal that there may be cleanup work. - - var RefStatic = - /* */ - 2097152; - var LayoutStatic = - /* */ - 4194304; - var PassiveStatic = - /* */ - 8388608; - var MaySuspendCommit = - /* */ - 16777216; // Flag used to identify newly inserted fibers. It isn't reset after commit unlike `Placement`. - - var PlacementDEV = - /* */ - 33554432; - var MountLayoutDev = - /* */ - 67108864; - var MountPassiveDev = - /* */ - 134217728; // Groups of flags that are used in the commit phase to skip over trees that - // don't contain effects, by checking subtreeFlags. - - var BeforeMutationMask = // TODO: Remove Update flag from before mutation phase by re-landing Visibility - // flag logic (see #20043) - Update | Snapshot | 0; - var MutationMask = - Placement | - Update | - ChildDeletion | - ContentReset | - Ref | - Hydrating | - Visibility | - FormReset; - var LayoutMask = Update | Callback | Ref | Visibility; // TODO: Split into PassiveMountMask and PassiveUnmountMask - - var PassiveMask = Passive$1 | Visibility | ChildDeletion; // Union of tags that don't get reset on clones. - // This allows certain concepts to persist without recalculating them, - // e.g. whether a subtree contains passive effects or portals. - - var StaticMask = - LayoutStatic | PassiveStatic | RefStatic | MaySuspendCommit; - - function getNearestMountedFiber(fiber) { - var node = fiber; - var nearestMounted = fiber; - - 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; + case ForwardRef: + return getWrappedName(type, type.render, 'ForwardRef'); - do { - node = nextNode; + case Fragment: + return 'Fragment'; - 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 + case HostHoistable: + case HostSingleton: + case HostComponent: + // Host component type is the display name (e.g. "div", "View") + return type; - nextNode = node.return; - } while (nextNode); - } else { - while (node.return) { - node = node.return; - } - } + case HostPortal: + return 'Portal'; - 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. + case HostRoot: + return 'Root'; - return null; - } - function isFiberMounted(fiber) { - return getNearestMountedFiber(fiber) === fiber; - } - function isMounted(component) { - { - var owner = ReactSharedInternals.owner; - - if (owner !== null && owner.tag === ClassComponent) { - var ownerFiber = owner; - var instance = ownerFiber.stateNode; - - 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" - ); - } + case HostText: + return 'Text'; - instance._warnedAboutRefsInRender = true; - } + 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'; } - var fiber = get(component); + return 'Mode'; - if (!fiber) { - return false; - } + case OffscreenComponent: + return 'Offscreen'; - return getNearestMountedFiber(fiber) === fiber; - } + case Profiler: + return 'Profiler'; - function assertIsMounted(fiber) { - if (getNearestMountedFiber(fiber) !== fiber) { - throw new Error("Unable to find node on an unmounted component."); - } - } + case ScopeComponent: + return 'Scope'; - function findCurrentFiberUsingSlowPath(fiber) { - var alternate = fiber.alternate; + case SuspenseComponent: + return 'Suspense'; - if (!alternate) { - // If there is no alternate, then we only need to check if it is mounted. - var nearestMounted = getNearestMountedFiber(fiber); + case SuspenseListComponent: + return 'SuspenseList'; - if (nearestMounted === null) { - throw new Error("Unable to find node on an unmounted component."); - } + case TracingMarkerComponent: + return 'TracingMarker'; + // The display name for these tags come from the user-provided type: - if (nearestMounted !== fiber) { - return null; - } + case IncompleteClassComponent: + case IncompleteFunctionComponent: - 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. + // Fallthrough - var a = fiber; - var b = alternate; + case ClassComponent: + case FunctionComponent: + case MemoComponent: + case SimpleMemoComponent: + if (typeof type === 'function') { + return type.displayName || type.name || null; + } - while (true) { - var parentA = a.return; + if (typeof type === 'string') { + return type; + } - if (parentA === null) { - // We're at the root. - break; - } + break; - 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; + return null; +} - if (nextParent !== null) { - a = b = nextParent; - continue; - } // If there's no parent, we're at the root. +var NoFlags$1 = +/* */ +0; +var PerformedWork = +/* */ +1; +var Placement = +/* */ +2; +var DidCapture = +/* */ +128; +var Hydrating = +/* */ +4096; // You can change the rest (and add more). + +var Update = +/* */ +4; +/* Skipped value: 0b0000000000000000000000001000; */ + +var ChildDeletion = +/* */ +16; +var ContentReset = +/* */ +32; +var Callback = +/* */ +64; +/* Used by DidCapture: 0b0000000000000000000010000000; */ + +var ForceClientRender = +/* */ +256; +var Ref = +/* */ +512; +var Snapshot = +/* */ +1024; +var Passive$1 = +/* */ +2048; +/* Used by Hydrating: 0b0000000000000001000000000000; */ + +var Visibility = +/* */ +8192; +var StoreConsistency = +/* */ +16384; // It's OK to reuse these bits because these flags are mutually exclusive for +// different fiber types. We should really be doing this for as many flags as +// possible, because we're about to run out of bits. + +var ScheduleRetry = StoreConsistency; +var ShouldSuspendCommit = Visibility; +var DidDefer = ContentReset; +var FormReset = Snapshot; +var LifecycleEffectMask = Passive$1 | Update | Callback | Ref | Snapshot | StoreConsistency; // Union of all commit flags (flags with the lifetime of a particular commit) + +var HostEffectMask = +/* */ +32767; // These are not really side effects, but we still reuse this field. + +var Incomplete = +/* */ +32768; +var ShouldCapture = +/* */ +65536; +var ForceUpdateForLegacySuspense = +/* */ +131072; +var Forked = +/* */ +1048576; // Static tags describe aspects of a fiber that are not specific to a render, +// e.g. a fiber uses a passive effect (even if there are no updates on this particular render). +// This enables us to defer more work in the unmount case, +// since we can defer traversing the tree during layout to look for Passive effects, +// and instead rely on the static flag as a signal that there may be cleanup work. + +var RefStatic = +/* */ +2097152; +var LayoutStatic = +/* */ +4194304; +var PassiveStatic = +/* */ +8388608; +var MaySuspendCommit = +/* */ +16777216; // Flag used to identify newly inserted fibers. It isn't reset after commit unlike `Placement`. + +var PlacementDEV = +/* */ +33554432; +var MountLayoutDev = +/* */ +67108864; +var MountPassiveDev = +/* */ +134217728; // Groups of flags that are used in the commit phase to skip over trees that +// don't contain effects, by checking subtreeFlags. + +var BeforeMutationMask = // TODO: Remove Update flag from before mutation phase by re-landing Visibility +// flag logic (see #20043) +Update | Snapshot | (0); +var MutationMask = Placement | Update | ChildDeletion | ContentReset | Ref | Hydrating | Visibility | FormReset; +var LayoutMask = Update | Callback | Ref | Visibility; // TODO: Split into PassiveMountMask and PassiveUnmountMask + +var PassiveMask = Passive$1 | Visibility | ChildDeletion; // Union of tags that don't get reset on clones. +// This allows certain concepts to persist without recalculating them, +// e.g. whether a subtree contains passive effects or portals. + +var StaticMask = LayoutStatic | PassiveStatic | RefStatic | MaySuspendCommit; + +function getNearestMountedFiber(fiber) { + var node = fiber; + var nearestMounted = fiber; + + 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; + + do { + node = nextNode; + + 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; + } + } + + 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. + + + return null; +} +function isFiberMounted(fiber) { + return getNearestMountedFiber(fiber) === fiber; +} +function isMounted(component) { + { + var owner = ReactSharedInternals.owner; - 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 (owner !== null && owner.tag === ClassComponent) { + var ownerFiber = owner; + var instance = ownerFiber.stateNode; - if (child === b) { - // We've determined that B is the current branch. - assertIsMounted(parentA); - return alternate; - } + 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'); + } - 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. + instance._warnedAboutRefsInRender = true; + } + } - throw new Error("Unable to find node on an unmounted component."); - } + var fiber = get(component); - 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 (!fiber) { + return false; + } - if (_child === b) { - didFindChild = true; - b = parentA; - a = parentB; - break; - } + return getNearestMountedFiber(fiber) === fiber; +} - _child = _child.sibling; - } +function assertIsMounted(fiber) { + if (getNearestMountedFiber(fiber) !== fiber) { + throw new Error('Unable to find node on an unmounted component.'); + } +} - if (!didFindChild) { - // Search parent B's child set - _child = parentB.child; +function findCurrentFiberUsingSlowPath(fiber) { + var alternate = fiber.alternate; - while (_child) { - if (_child === a) { - didFindChild = true; - a = parentB; - b = parentA; - break; - } + if (!alternate) { + // If there is no alternate, then we only need to check if it is mounted. + var nearestMounted = getNearestMountedFiber(fiber); - if (_child === b) { - didFindChild = true; - b = parentB; - a = parentA; - break; - } + if (nearestMounted === null) { + throw new Error('Unable to find node on an unmounted component.'); + } - _child = _child.sibling; - } + if (nearestMounted !== fiber) { + return null; + } - 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." - ); - } - } - } + 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. - 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. - if (a.tag !== HostRoot) { - throw new Error("Unable to find node on an unmounted component."); - } + var a = fiber; + var b = alternate; - if (a.stateNode.current === a) { - // We've determined that A is the current branch. - return fiber; - } // Otherwise B has to be current branch. + while (true) { + var parentA = a.return; - return alternate; - } - function findCurrentHostFiber(parent) { - var currentParent = findCurrentFiberUsingSlowPath(parent); - return currentParent !== null - ? findCurrentHostFiberImpl(currentParent) - : null; + if (parentA === null) { + // We're at the root. + break; } - function findCurrentHostFiberImpl(node) { - // Next we'll drill down this component to find the first HostComponent/Text. - var tag = node.tag; + var parentB = parentA.alternate; - if ( - tag === HostComponent || - tag === HostHoistable || - tag === HostSingleton || - tag === HostText - ) { - return node; - } + 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; - var child = node.child; + if (nextParent !== null) { + a = b = nextParent; + continue; + } // If there's no parent, we're at the root. - while (child !== null) { - var match = findCurrentHostFiberImpl(child); - if (match !== null) { - return match; + 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 (child === b) { + // We've determined that B is the current branch. + assertIsMounted(parentA); + return alternate; } 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. - return null; + + throw new Error('Unable to find node on an unmounted component.'); } - var isArrayImpl = Array.isArray; // eslint-disable-next-line no-redeclare - - function isArray(a) { - return isArrayImpl(a); - } - - // This module only exists as an ESM wrapper around the external CommonJS - var scheduleCallback$3 = Scheduler$1.unstable_scheduleCallback; - var cancelCallback$1 = Scheduler$1.unstable_cancelCallback; - var shouldYield = Scheduler$1.unstable_shouldYield; - var requestPaint = Scheduler$1.unstable_requestPaint; - var now$1 = Scheduler$1.unstable_now; - var ImmediatePriority = Scheduler$1.unstable_ImmediatePriority; - var UserBlockingPriority = Scheduler$1.unstable_UserBlockingPriority; - var NormalPriority$1 = Scheduler$1.unstable_NormalPriority; - var IdlePriority = Scheduler$1.unstable_IdlePriority; // this doesn't actually exist on the scheduler, but it *does* - - // 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[cannot-write] 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 */ - } + 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; - disabledDepth++; - } - } - function reenableLogs() { - { - disabledDepth--; - - if (disabledDepth === 0) { - /* eslint-disable react-internal/no-production-logging */ - var props = { - configurable: true, - enumerable: true, - writable: true - }; // $FlowFixMe[cannot-write] 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 */ + while (_child) { + if (_child === a) { + didFindChild = true; + a = parentA; + b = parentB; + break; } - if (disabledDepth < 0) { - error( - "disabledDepth fell below zero. " + - "This is a bug in React. Please file an issue." - ); + if (_child === b) { + didFindChild = true; + b = parentA; + a = parentB; + break; } - } - } - 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; + _child = _child.sibling; } - var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__; - - 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; - } + if (!didFindChild) { + // Search parent B's child set + _child = parentB.child; - 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://react.dev/link/react-devtools" - ); - } // DevTools exists, even though it doesn't support Fiber. + while (_child) { + if (_child === a) { + didFindChild = true; + a = parentB; + b = parentA; + break; + } - return true; - } + if (_child === b) { + didFindChild = true; + b = parentB; + a = parentA; + break; + } - 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 - }); + _child = _child.sibling; } - 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); + 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 (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; - error("React instrumentation encountered an error: %s", err); - } - } - } - } + 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 onCommitRoot(root, eventPriority) { - if ( - injectedHook && - typeof injectedHook.onCommitFiberRoot === "function" - ) { - try { - var didError = (root.current.flags & DidCapture) === DidCapture; + } // If the root is not a host container, we're in a disconnected tree. I.e. + // unmounted. - if (enableProfilerTimer) { - var schedulerPriority; - switch (eventPriority) { - case DiscreteEventPriority: - schedulerPriority = ImmediatePriority; - break; + if (a.tag !== HostRoot) { + throw new Error('Unable to find node on an unmounted component.'); + } - case ContinuousEventPriority: - schedulerPriority = UserBlockingPriority; - break; + if (a.stateNode.current === a) { + // We've determined that A is the current branch. + return fiber; + } // Otherwise B has to be current branch. - case DefaultEventPriority: - schedulerPriority = NormalPriority$1; - break; - case IdleEventPriority: - schedulerPriority = IdlePriority; - break; + return alternate; +} +function findCurrentHostFiber(parent) { + var currentParent = findCurrentFiberUsingSlowPath(parent); + return currentParent !== null ? findCurrentHostFiberImpl(currentParent) : null; +} - default: - schedulerPriority = NormalPriority$1; - break; - } +function findCurrentHostFiberImpl(node) { + // Next we'll drill down this component to find the first HostComponent/Text. + var tag = node.tag; - injectedHook.onCommitFiberRoot( - rendererID, - root, - schedulerPriority, - didError - ); - } - } catch (err) { - { - if (!hasLoggedError) { - hasLoggedError = true; + if (tag === HostComponent || tag === HostHoistable || tag === HostSingleton || tag === HostText) { + return node; + } - error("React instrumentation encountered an error: %s", err); - } - } - } - } - } - function onPostCommitRoot(root) { - if ( - injectedHook && - typeof injectedHook.onPostCommitFiberRoot === "function" - ) { - try { - injectedHook.onPostCommitFiberRoot(rendererID, root); - } catch (err) { - { - if (!hasLoggedError) { - hasLoggedError = true; + var child = node.child; - error("React instrumentation encountered an error: %s", err); - } - } - } - } + while (child !== null) { + var match = findCurrentHostFiberImpl(child); + + if (match !== null) { + return match; } - function onCommitUnmount(fiber) { - if ( - injectedHook && - typeof injectedHook.onCommitFiberUnmount === "function" - ) { - try { - injectedHook.onCommitFiberUnmount(rendererID, fiber); - } catch (err) { - { - if (!hasLoggedError) { - hasLoggedError = true; - error("React instrumentation encountered an error: %s", err); - } - } - } - } + child = child.sibling; + } + + return null; +} + +var isArrayImpl = Array.isArray; // eslint-disable-next-line no-redeclare + +function isArray(a) { + return isArrayImpl(a); +} + +// This module only exists as an ESM wrapper around the external CommonJS +var scheduleCallback$3 = Scheduler$1.unstable_scheduleCallback; +var cancelCallback$1 = Scheduler$1.unstable_cancelCallback; +var shouldYield = Scheduler$1.unstable_shouldYield; +var requestPaint = Scheduler$1.unstable_requestPaint; +var now$1 = Scheduler$1.unstable_now; +var ImmediatePriority = Scheduler$1.unstable_ImmediatePriority; +var UserBlockingPriority = Scheduler$1.unstable_UserBlockingPriority; +var NormalPriority$1 = Scheduler$1.unstable_NormalPriority; +var IdlePriority = Scheduler$1.unstable_IdlePriority; // this doesn't actually exist on the scheduler, but it *does* + +// 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[cannot-write] 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 */ + } + + disabledDepth++; + } +} +function reenableLogs() { + { + disabledDepth--; + + if (disabledDepth === 0) { + /* eslint-disable react-internal/no-production-logging */ + var props = { + configurable: true, + enumerable: true, + writable: true + }; // $FlowFixMe[cannot-write] 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 */ } - function setIsStrictModeForDevtools(newIsStrictMode) { - { - if (newIsStrictMode) { - disableLogs(); - } else { - reenableLogs(); - } - } - } // Profiler API hooks - function injectProfilingHooks(profilingHooks) { - injectedProfilingHooks = profilingHooks; + if (disabledDepth < 0) { + error('disabledDepth fell below zero. ' + 'This is a bug in React. Please file an issue.'); } + } +} - function getLaneLabelMap() { - { - var map = new Map(); - var lane = 1; +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; + } + + var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__; + + 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; + } + + 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://react.dev/link/react-devtools'); + } // DevTools exists, even though it doesn't support Fiber. - for (var index = 0; index < TotalLanes; index++) { - var label = getLabelForLane(lane); - map.set(lane, label); - lane *= 2; - } - return map; - } + return true; + } + + 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 + }); } - function markCommitStarted(lanes) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markCommitStarted === "function" - ) { - injectedProfilingHooks.markCommitStarted(lanes); - } - } + 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); } - function markCommitStopped() { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markCommitStopped === "function" - ) { - injectedProfilingHooks.markCommitStopped(); + } + + 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; + + error('React instrumentation encountered an error: %s', err); } } } - function markComponentRenderStarted(fiber) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentRenderStarted === - "function" - ) { - injectedProfilingHooks.markComponentRenderStarted(fiber); + } +} +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; + + case ContinuousEventPriority: + schedulerPriority = UserBlockingPriority; + break; + + case DefaultEventPriority: + schedulerPriority = NormalPriority$1; + break; + + case IdleEventPriority: + schedulerPriority = IdlePriority; + break; + + default: + schedulerPriority = NormalPriority$1; + break; } + + injectedHook.onCommitFiberRoot(rendererID, root, schedulerPriority, didError); } - } - function markComponentRenderStopped() { + } catch (err) { { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentRenderStopped === - "function" - ) { - injectedProfilingHooks.markComponentRenderStopped(); + if (!hasLoggedError) { + hasLoggedError = true; + + error('React instrumentation encountered an error: %s', err); } } } - function markComponentPassiveEffectMountStarted(fiber) { + } +} +function onPostCommitRoot(root) { + if (injectedHook && typeof injectedHook.onPostCommitFiberRoot === 'function') { + try { + injectedHook.onPostCommitFiberRoot(rendererID, root); + } catch (err) { { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentPassiveEffectMountStarted === - "function" - ) { - injectedProfilingHooks.markComponentPassiveEffectMountStarted(fiber); + if (!hasLoggedError) { + hasLoggedError = true; + + error('React instrumentation encountered an error: %s', err); } } } - function markComponentPassiveEffectMountStopped() { + } +} +function onCommitUnmount(fiber) { + if (injectedHook && typeof injectedHook.onCommitFiberUnmount === 'function') { + try { + injectedHook.onCommitFiberUnmount(rendererID, fiber); + } catch (err) { { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentPassiveEffectMountStopped === - "function" - ) { - injectedProfilingHooks.markComponentPassiveEffectMountStopped(); + if (!hasLoggedError) { + hasLoggedError = true; + + error('React instrumentation encountered an error: %s', err); } } } - function markComponentPassiveEffectUnmountStarted(fiber) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentPassiveEffectUnmountStarted === - "function" - ) { - injectedProfilingHooks.markComponentPassiveEffectUnmountStarted( - fiber - ); - } - } + } +} +function setIsStrictModeForDevtools(newIsStrictMode) { + { + if (newIsStrictMode) { + disableLogs(); + } else { + reenableLogs(); + } + } +} // Profiler API hooks + +function injectProfilingHooks(profilingHooks) { + injectedProfilingHooks = profilingHooks; +} + +function getLaneLabelMap() { + { + var map = new Map(); + var lane = 1; + + for (var index = 0; index < TotalLanes; index++) { + var label = getLabelForLane(lane); + map.set(lane, label); + lane *= 2; } - function markComponentPassiveEffectUnmountStopped() { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentPassiveEffectUnmountStopped === - "function" - ) { - injectedProfilingHooks.markComponentPassiveEffectUnmountStopped(); - } - } + + return map; + } +} + +function markCommitStarted(lanes) { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markCommitStarted === 'function') { + injectedProfilingHooks.markCommitStarted(lanes); } - function markComponentLayoutEffectMountStarted(fiber) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentLayoutEffectMountStarted === - "function" - ) { - injectedProfilingHooks.markComponentLayoutEffectMountStarted(fiber); - } - } + } +} +function markCommitStopped() { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markCommitStopped === 'function') { + injectedProfilingHooks.markCommitStopped(); } - function markComponentLayoutEffectMountStopped() { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentLayoutEffectMountStopped === - "function" - ) { - injectedProfilingHooks.markComponentLayoutEffectMountStopped(); - } - } + } +} +function markComponentRenderStarted(fiber) { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentRenderStarted === 'function') { + injectedProfilingHooks.markComponentRenderStarted(fiber); } - function markComponentLayoutEffectUnmountStarted(fiber) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentLayoutEffectUnmountStarted === - "function" - ) { - injectedProfilingHooks.markComponentLayoutEffectUnmountStarted(fiber); - } - } + } +} +function markComponentRenderStopped() { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentRenderStopped === 'function') { + injectedProfilingHooks.markComponentRenderStopped(); } - function markComponentLayoutEffectUnmountStopped() { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentLayoutEffectUnmountStopped === - "function" - ) { - injectedProfilingHooks.markComponentLayoutEffectUnmountStopped(); - } - } + } +} +function markComponentPassiveEffectMountStarted(fiber) { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentPassiveEffectMountStarted === 'function') { + injectedProfilingHooks.markComponentPassiveEffectMountStarted(fiber); } - function markComponentErrored(fiber, thrownValue, lanes) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentErrored === "function" - ) { - injectedProfilingHooks.markComponentErrored( - fiber, - thrownValue, - lanes - ); - } - } + } +} +function markComponentPassiveEffectMountStopped() { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentPassiveEffectMountStopped === 'function') { + injectedProfilingHooks.markComponentPassiveEffectMountStopped(); } - function markComponentSuspended(fiber, wakeable, lanes) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentSuspended === "function" - ) { - injectedProfilingHooks.markComponentSuspended(fiber, wakeable, lanes); - } - } + } +} +function markComponentPassiveEffectUnmountStarted(fiber) { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentPassiveEffectUnmountStarted === 'function') { + injectedProfilingHooks.markComponentPassiveEffectUnmountStarted(fiber); } - function markLayoutEffectsStarted(lanes) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markLayoutEffectsStarted === "function" - ) { - injectedProfilingHooks.markLayoutEffectsStarted(lanes); - } - } + } +} +function markComponentPassiveEffectUnmountStopped() { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentPassiveEffectUnmountStopped === 'function') { + injectedProfilingHooks.markComponentPassiveEffectUnmountStopped(); } - function markLayoutEffectsStopped() { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markLayoutEffectsStopped === "function" - ) { - injectedProfilingHooks.markLayoutEffectsStopped(); - } - } + } +} +function markComponentLayoutEffectMountStarted(fiber) { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentLayoutEffectMountStarted === 'function') { + injectedProfilingHooks.markComponentLayoutEffectMountStarted(fiber); } - function markPassiveEffectsStarted(lanes) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markPassiveEffectsStarted === "function" - ) { - injectedProfilingHooks.markPassiveEffectsStarted(lanes); - } - } + } +} +function markComponentLayoutEffectMountStopped() { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentLayoutEffectMountStopped === 'function') { + injectedProfilingHooks.markComponentLayoutEffectMountStopped(); } - function markPassiveEffectsStopped() { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markPassiveEffectsStopped === "function" - ) { - injectedProfilingHooks.markPassiveEffectsStopped(); - } - } + } +} +function markComponentLayoutEffectUnmountStarted(fiber) { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentLayoutEffectUnmountStarted === 'function') { + injectedProfilingHooks.markComponentLayoutEffectUnmountStarted(fiber); } - function markRenderStarted(lanes) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markRenderStarted === "function" - ) { - injectedProfilingHooks.markRenderStarted(lanes); - } - } + } +} +function markComponentLayoutEffectUnmountStopped() { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentLayoutEffectUnmountStopped === 'function') { + injectedProfilingHooks.markComponentLayoutEffectUnmountStopped(); } - function markRenderYielded() { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markRenderYielded === "function" - ) { - injectedProfilingHooks.markRenderYielded(); - } - } + } +} +function markComponentErrored(fiber, thrownValue, lanes) { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentErrored === 'function') { + injectedProfilingHooks.markComponentErrored(fiber, thrownValue, lanes); } - function markRenderStopped() { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markRenderStopped === "function" - ) { - injectedProfilingHooks.markRenderStopped(); - } - } + } +} +function markComponentSuspended(fiber, wakeable, lanes) { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentSuspended === 'function') { + injectedProfilingHooks.markComponentSuspended(fiber, wakeable, lanes); } - function markRenderScheduled(lane) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markRenderScheduled === "function" - ) { - injectedProfilingHooks.markRenderScheduled(lane); - } - } + } +} +function markLayoutEffectsStarted(lanes) { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markLayoutEffectsStarted === 'function') { + injectedProfilingHooks.markLayoutEffectsStarted(lanes); } - function markForceUpdateScheduled(fiber, lane) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markForceUpdateScheduled === "function" - ) { - injectedProfilingHooks.markForceUpdateScheduled(fiber, lane); - } - } + } +} +function markLayoutEffectsStopped() { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markLayoutEffectsStopped === 'function') { + injectedProfilingHooks.markLayoutEffectsStopped(); } - function markStateUpdateScheduled(fiber, lane) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markStateUpdateScheduled === "function" - ) { - injectedProfilingHooks.markStateUpdateScheduled(fiber, lane); - } - } + } +} +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(); + } + } +} +function markRenderScheduled(lane) { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markRenderScheduled === 'function') { + injectedProfilingHooks.markRenderScheduled(lane); + } + } +} +function markForceUpdateScheduled(fiber, lane) { + { + 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); + } + } +} - 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; - var NoStrictPassiveEffectsMode = - /* */ - 64; - - // 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. - - var TotalLanes = 31; - var NoLanes = - /* */ - 0; - var NoLane = - /* */ - 0; - var SyncHydrationLane = - /* */ - 1; - var SyncLane = - /* */ - 2; - var SyncLaneIndex = 1; - var InputContinuousHydrationLane = - /* */ - 4; - var InputContinuousLane = - /* */ - 8; - var DefaultHydrationLane = - /* */ - 16; - var DefaultLane = - /* */ - 32; - var SyncUpdateLanes = SyncLane | InputContinuousLane | DefaultLane; - var TransitionHydrationLane = - /* */ - 64; - var TransitionLanes = - /* */ - 4194176; - var TransitionLane1 = - /* */ - 128; - var TransitionLane2 = - /* */ - 256; - var TransitionLane3 = - /* */ - 512; - var TransitionLane4 = - /* */ - 1024; - var TransitionLane5 = - /* */ - 2048; - var TransitionLane6 = - /* */ - 4096; - var TransitionLane7 = - /* */ - 8192; - var TransitionLane8 = - /* */ - 16384; - var TransitionLane9 = - /* */ - 32768; - var TransitionLane10 = - /* */ - 65536; - var TransitionLane11 = - /* */ - 131072; - var TransitionLane12 = - /* */ - 262144; - var TransitionLane13 = - /* */ - 524288; - var TransitionLane14 = - /* */ - 1048576; - var TransitionLane15 = - /* */ - 2097152; - var RetryLanes = - /* */ - 62914560; - var RetryLane1 = - /* */ - 4194304; - var RetryLane2 = - /* */ - 8388608; - var RetryLane3 = - /* */ - 16777216; - var RetryLane4 = - /* */ - 33554432; - var SomeRetryLane = RetryLane1; - var SelectiveHydrationLane = - /* */ - 67108864; - var NonIdleLanes = - /* */ - 134217727; - var IdleHydrationLane = - /* */ - 134217728; - var IdleLane = - /* */ - 268435456; - var OffscreenLane = - /* */ - 536870912; - var DeferredLane = - /* */ - 1073741824; // Any lane that might schedule an update. This is used to detect infinite - // update loops, so it doesn't include hydration lanes or retries. - - var UpdateLanes = - SyncLane | InputContinuousLane | DefaultLane | TransitionLanes; // This function is used for the experimental timeline (react-devtools-timeline) - // It should be kept in sync with the Lanes values above. - - function getLabelForLane(lane) { - { - if (lane & SyncHydrationLane) { - return "SyncHydrationLane"; - } - - if (lane & SyncLane) { - return "Sync"; - } - - if (lane & InputContinuousHydrationLane) { - return "InputContinuousHydration"; - } - - if (lane & InputContinuousLane) { - return "InputContinuous"; - } +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; +var NoStrictPassiveEffectsMode = +/* */ +64; + +// 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 (lane & DefaultHydrationLane) { - return "DefaultHydration"; - } +// If those values are changed that package should be rebuilt and redeployed. + +var TotalLanes = 31; +var NoLanes = +/* */ +0; +var NoLane = +/* */ +0; +var SyncHydrationLane = +/* */ +1; +var SyncLane = +/* */ +2; +var SyncLaneIndex = 1; +var InputContinuousHydrationLane = +/* */ +4; +var InputContinuousLane = +/* */ +8; +var DefaultHydrationLane = +/* */ +16; +var DefaultLane = +/* */ +32; +var SyncUpdateLanes = SyncLane | InputContinuousLane | DefaultLane ; +var TransitionHydrationLane = +/* */ +64; +var TransitionLanes = +/* */ +4194176; +var TransitionLane1 = +/* */ +128; +var TransitionLane2 = +/* */ +256; +var TransitionLane3 = +/* */ +512; +var TransitionLane4 = +/* */ +1024; +var TransitionLane5 = +/* */ +2048; +var TransitionLane6 = +/* */ +4096; +var TransitionLane7 = +/* */ +8192; +var TransitionLane8 = +/* */ +16384; +var TransitionLane9 = +/* */ +32768; +var TransitionLane10 = +/* */ +65536; +var TransitionLane11 = +/* */ +131072; +var TransitionLane12 = +/* */ +262144; +var TransitionLane13 = +/* */ +524288; +var TransitionLane14 = +/* */ +1048576; +var TransitionLane15 = +/* */ +2097152; +var RetryLanes = +/* */ +62914560; +var RetryLane1 = +/* */ +4194304; +var RetryLane2 = +/* */ +8388608; +var RetryLane3 = +/* */ +16777216; +var RetryLane4 = +/* */ +33554432; +var SomeRetryLane = RetryLane1; +var SelectiveHydrationLane = +/* */ +67108864; +var NonIdleLanes = +/* */ +134217727; +var IdleHydrationLane = +/* */ +134217728; +var IdleLane = +/* */ +268435456; +var OffscreenLane = +/* */ +536870912; +var DeferredLane = +/* */ +1073741824; // Any lane that might schedule an update. This is used to detect infinite +// update loops, so it doesn't include hydration lanes or retries. + +var UpdateLanes = SyncLane | InputContinuousLane | DefaultLane | TransitionLanes; // This function is used for the experimental timeline (react-devtools-timeline) +// It should be kept in sync with the Lanes values above. + +function getLabelForLane(lane) { + { + if (lane & SyncHydrationLane) { + return 'SyncHydrationLane'; + } + + if (lane & SyncLane) { + return 'Sync'; + } + + if (lane & InputContinuousHydrationLane) { + return 'InputContinuousHydration'; + } + + if (lane & InputContinuousLane) { + return 'InputContinuous'; + } + + if (lane & DefaultHydrationLane) { + return 'DefaultHydration'; + } + + if (lane & DefaultLane) { + return 'Default'; + } + + if (lane & TransitionHydrationLane) { + return 'TransitionHydration'; + } + + if (lane & TransitionLanes) { + return 'Transition'; + } + + if (lane & RetryLanes) { + return 'Retry'; + } + + if (lane & SelectiveHydrationLane) { + return 'SelectiveHydration'; + } - if (lane & DefaultLane) { - return "Default"; - } + if (lane & IdleHydrationLane) { + return 'IdleHydration'; + } - if (lane & TransitionHydrationLane) { - return "TransitionHydration"; - } + if (lane & IdleLane) { + return 'Idle'; + } - if (lane & TransitionLanes) { - return "Transition"; - } + if (lane & OffscreenLane) { + return 'Offscreen'; + } - if (lane & RetryLanes) { - return "Retry"; - } + if (lane & DeferredLane) { + return 'Deferred'; + } + } +} +var NoTimestamp = -1; +var nextTransitionLane = TransitionLane1; +var nextRetryLane = RetryLane1; - if (lane & SelectiveHydrationLane) { - return "SelectiveHydration"; - } +function getHighestPriorityLanes(lanes) { + { + var pendingSyncLanes = lanes & SyncUpdateLanes; - if (lane & IdleHydrationLane) { - return "IdleHydration"; - } + if (pendingSyncLanes !== 0) { + return pendingSyncLanes; + } + } - if (lane & IdleLane) { - return "Idle"; - } + switch (getHighestPriorityLane(lanes)) { + case SyncHydrationLane: + return SyncHydrationLane; - if (lane & OffscreenLane) { - return "Offscreen"; - } + case SyncLane: + return SyncLane; - if (lane & DeferredLane) { - return "Deferred"; - } - } - } - var NoTimestamp = -1; - var nextTransitionLane = TransitionLane1; - var nextRetryLane = RetryLane1; + case InputContinuousHydrationLane: + return InputContinuousHydrationLane; + + case InputContinuousLane: + return InputContinuousLane; + + case DefaultHydrationLane: + return DefaultHydrationLane; + + case DefaultLane: + return DefaultLane; + + case TransitionHydrationLane: + return TransitionHydrationLane; + + case TransitionLane1: + case TransitionLane2: + case TransitionLane3: + case TransitionLane4: + case TransitionLane5: + case TransitionLane6: + case TransitionLane7: + case TransitionLane8: + case TransitionLane9: + case TransitionLane10: + case TransitionLane11: + case TransitionLane12: + case TransitionLane13: + case TransitionLane14: + case TransitionLane15: + return lanes & TransitionLanes; + + case RetryLane1: + case RetryLane2: + case RetryLane3: + case RetryLane4: + return lanes & RetryLanes; + + case SelectiveHydrationLane: + return SelectiveHydrationLane; + + case IdleHydrationLane: + return IdleHydrationLane; + + case IdleLane: + return IdleLane; + + case OffscreenLane: + return OffscreenLane; + + case DeferredLane: + // This shouldn't be reachable because deferred work is always entangled + // with something else. + return NoLanes; - function getHighestPriorityLanes(lanes) { + default: { - var pendingSyncLanes = lanes & SyncUpdateLanes; + error('Should have found matching lanes. This is a bug in React.'); + } // This shouldn't be reachable, but as a fallback, return the entire bitmask. - if (pendingSyncLanes !== 0) { - return pendingSyncLanes; - } - } - switch (getHighestPriorityLane(lanes)) { - case SyncHydrationLane: - return SyncHydrationLane; + return lanes; + } +} - case SyncLane: - return SyncLane; +function getNextLanes(root, wipLanes) { + // Early bailout if there's no pending work left. + var pendingLanes = root.pendingLanes; - case InputContinuousHydrationLane: - return InputContinuousHydrationLane; + if (pendingLanes === NoLanes) { + return NoLanes; + } - case InputContinuousLane: - return InputContinuousLane; + var nextLanes = NoLanes; + var suspendedLanes = root.suspendedLanes; + var pingedLanes = root.pingedLanes; // Do not work on any idle work until all the non-idle work has finished, + // even if the work is suspended. - case DefaultHydrationLane: - return DefaultHydrationLane; + var nonIdlePendingLanes = pendingLanes & NonIdleLanes; - case DefaultLane: - return DefaultLane; + if (nonIdlePendingLanes !== NoLanes) { + var nonIdleUnblockedLanes = nonIdlePendingLanes & ~suspendedLanes; - case TransitionHydrationLane: - return TransitionHydrationLane; + if (nonIdleUnblockedLanes !== NoLanes) { + nextLanes = getHighestPriorityLanes(nonIdleUnblockedLanes); + } else { + var nonIdlePingedLanes = nonIdlePendingLanes & pingedLanes; - case TransitionLane1: - case TransitionLane2: - case TransitionLane3: - case TransitionLane4: - case TransitionLane5: - case TransitionLane6: - case TransitionLane7: - case TransitionLane8: - case TransitionLane9: - case TransitionLane10: - case TransitionLane11: - case TransitionLane12: - case TransitionLane13: - case TransitionLane14: - case TransitionLane15: - return lanes & TransitionLanes; + if (nonIdlePingedLanes !== NoLanes) { + nextLanes = getHighestPriorityLanes(nonIdlePingedLanes); + } + } + } else { + // The only remaining work is Idle. + var unblockedLanes = pendingLanes & ~suspendedLanes; - case RetryLane1: - case RetryLane2: - case RetryLane3: - case RetryLane4: - return lanes & RetryLanes; + if (unblockedLanes !== NoLanes) { + nextLanes = getHighestPriorityLanes(unblockedLanes); + } else { + if (pingedLanes !== NoLanes) { + nextLanes = getHighestPriorityLanes(pingedLanes); + } + } + } - case SelectiveHydrationLane: - return SelectiveHydrationLane; + if (nextLanes === NoLanes) { + // This should only be reachable if we're suspended + // TODO: Consider warning in this path if a fallback timer is not scheduled. + return NoLanes; + } // If we're already in the middle of a render, switching lanes will interrupt + // it and we'll lose our progress. We should only do this if the new lanes are + // higher priority. - case IdleHydrationLane: - return IdleHydrationLane; - case IdleLane: - return IdleLane; + if (wipLanes !== NoLanes && wipLanes !== nextLanes && // If we already suspended with a delay, then interrupting is fine. Don't + // bother waiting until the root is complete. + (wipLanes & suspendedLanes) === NoLanes) { + var nextLane = getHighestPriorityLane(nextLanes); + var wipLane = getHighestPriorityLane(wipLanes); - case OffscreenLane: - return OffscreenLane; + if ( // Tests whether the next lane is equal or lower priority than the wip + // one. This works because the bits decrease in priority as you go left. + nextLane >= wipLane || // Default priority updates should not interrupt transition updates. The + // only difference between default updates and transition updates is that + // default updates do not support refresh transitions. + nextLane === DefaultLane && (wipLane & TransitionLanes) !== NoLanes) { + // Keep working on the existing in-progress tree. Do not interrupt. + return wipLanes; + } + } - case DeferredLane: - // This shouldn't be reachable because deferred work is always entangled - // with something else. - return NoLanes; + return nextLanes; +} +function getEntangledLanes(root, renderLanes) { + var entangledLanes = renderLanes; + + if ((root.current.mode & ConcurrentUpdatesByDefaultMode) !== NoMode) ; else if ((entangledLanes & InputContinuousLane) !== NoLanes) { + // When updates are sync by default, we entangle continuous priority updates + // and default updates, so they render in the same batch. The only reason + // they use separate lanes is because continuous updates should interrupt + // transitions, but default updates should not. + entangledLanes |= entangledLanes & DefaultLane; + } // Check for entangled lanes and add them to the batch. + // + // A lane is said to be entangled with another when it's not allowed to render + // in a batch that does not also include the other lane. Typically we do this + // when multiple updates have the same source, and we only want to respond to + // the most recent event from that source. + // + // Note that we apply entanglements *after* checking for partial work above. + // This means that if a lane is entangled during an interleaved event while + // it's already rendering, we won't interrupt it. This is intentional, since + // entanglement is usually "best effort": we'll try our best to render the + // lanes in the same batch, but it's not worth throwing out partially + // completed work in order to do it. + // TODO: Reconsider this. The counter-argument is that the partial work + // represents an intermediate state, which we don't want to show to the user. + // And by spending extra time finishing it, we're increasing the amount of + // time it takes to show the final state, which is what they are actually + // waiting for. + // + // For those exceptions where entanglement is semantically important, + // we should ensure that there is no partial work at the + // time we apply the entanglement. + + + var allEntangledLanes = root.entangledLanes; + + if (allEntangledLanes !== NoLanes) { + var entanglements = root.entanglements; + var lanes = entangledLanes & allEntangledLanes; + + while (lanes > 0) { + var index = pickArbitraryLaneIndex(lanes); + var lane = 1 << index; + entangledLanes |= entanglements[index]; + lanes &= ~lane; + } + } + + return entangledLanes; +} - default: - { - error("Should have found matching lanes. This is a bug in React."); - } // This shouldn't be reachable, but as a fallback, return the entire bitmask. +function computeExpirationTime(lane, currentTime) { + switch (lane) { + case SyncHydrationLane: + case SyncLane: + case InputContinuousHydrationLane: + case InputContinuousLane: + // User interactions should expire slightly more quickly. + // + // NOTE: This is set to the corresponding constant as in Scheduler.js. + // When we made it larger, a product metric in www regressed, suggesting + // there's a user interaction that's being starved by a series of + // synchronous updates. If that theory is correct, the proper solution is + // to fix the starvation. However, this scenario supports the idea that + // expiration times are an important safeguard when starvation + // does happen. + return currentTime + syncLaneExpirationMs; + + case DefaultHydrationLane: + case DefaultLane: + case TransitionHydrationLane: + case TransitionLane1: + case TransitionLane2: + case TransitionLane3: + case TransitionLane4: + case TransitionLane5: + case TransitionLane6: + case TransitionLane7: + case TransitionLane8: + case TransitionLane9: + case TransitionLane10: + case TransitionLane11: + case TransitionLane12: + case TransitionLane13: + case TransitionLane14: + case TransitionLane15: + return currentTime + transitionLaneExpirationMs; + + case RetryLane1: + case RetryLane2: + case RetryLane3: + case RetryLane4: + // TODO: Retries should be allowed to expire if they are CPU bound for + // too long, but when I made this change it caused a spike in browser + // crashes. There must be some other underlying bug; not super urgent but + // ideally should figure out why and fix it. Unfortunately we don't have + // a repro for the crashes, only detected via production metrics. + return NoTimestamp; + + case SelectiveHydrationLane: + case IdleHydrationLane: + case IdleLane: + case OffscreenLane: + case DeferredLane: + // Anything idle priority or lower should never expire. + return NoTimestamp; + + default: + { + error('Should have found matching lanes. This is a bug in React.'); + } + + return NoTimestamp; + } +} - return lanes; - } - } +function markStarvedLanesAsExpired(root, currentTime) { + // TODO: This gets called every time we yield. We can optimize by storing + // the earliest expiration time on the root. Then use that to quickly bail out + // of this function. + var pendingLanes = root.pendingLanes; + var suspendedLanes = root.suspendedLanes; + var pingedLanes = root.pingedLanes; + var expirationTimes = root.expirationTimes; // Iterate through the pending lanes and check if we've reached their + // expiration time. If so, we'll assume the update is being starved and mark + // it as expired to force it to finish. + // TODO: We should be able to replace this with upgradePendingLanesToSync + // + // We exclude retry lanes because those must always be time sliced, in order + // to unwrap uncached promises. + // TODO: Write a test for this + + var lanes = pendingLanes & ~RetryLanes; + + while (lanes > 0) { + var index = pickArbitraryLaneIndex(lanes); + var lane = 1 << index; + var expirationTime = expirationTimes[index]; + + if (expirationTime === NoTimestamp) { + // Found a pending lane with no expiration time. If it's not suspended, or + // if it's pinged, assume it's CPU-bound. Compute a new expiration time + // using the current time. + if ((lane & suspendedLanes) === NoLanes || (lane & pingedLanes) !== NoLanes) { + // Assumes timestamps are monotonically increasing. + expirationTimes[index] = computeExpirationTime(lane, currentTime); + } + } else if (expirationTime <= currentTime) { + // This lane expired + root.expiredLanes |= lane; + } + + lanes &= ~lane; + } +} // This returns the highest priority pending lanes regardless of whether they +function getLanesToRetrySynchronouslyOnError(root, originallyAttemptedLanes) { + if (root.errorRecoveryDisabledLanes & originallyAttemptedLanes) { + // The error recovery mechanism is disabled until these lanes are cleared. + return NoLanes; + } + + var everythingButOffscreen = root.pendingLanes & ~OffscreenLane; + + if (everythingButOffscreen !== NoLanes) { + return everythingButOffscreen; + } + + if (everythingButOffscreen & OffscreenLane) { + return OffscreenLane; + } + + return NoLanes; +} +function includesSyncLane(lanes) { + return (lanes & (SyncLane | SyncHydrationLane)) !== NoLanes; +} +function includesNonIdleWork(lanes) { + return (lanes & NonIdleLanes) !== NoLanes; +} +function includesOnlyRetries(lanes) { + return (lanes & RetryLanes) === lanes; +} +function includesOnlyNonUrgentLanes(lanes) { + // TODO: Should hydration lanes be included here? This function is only + // used in `updateDeferredValueImpl`. + var UrgentLanes = SyncLane | InputContinuousLane | DefaultLane; + return (lanes & UrgentLanes) === NoLanes; +} +function includesOnlyTransitions(lanes) { + return (lanes & TransitionLanes) === lanes; +} +function includesBlockingLane(root, lanes) { + if ((root.current.mode & ConcurrentUpdatesByDefaultMode) !== NoMode) { + // Concurrent updates by default always use time slicing. + return false; + } + + var SyncDefaultLanes = InputContinuousHydrationLane | InputContinuousLane | DefaultHydrationLane | DefaultLane; + return (lanes & SyncDefaultLanes) !== NoLanes; +} +function includesExpiredLane(root, lanes) { + // This is a separate check from includesBlockingLane because a lane can + // expire after a render has already started. + return (lanes & root.expiredLanes) !== NoLanes; +} +function isTransitionLane(lane) { + return (lane & TransitionLanes) !== NoLanes; +} +function claimNextTransitionLane() { + // Cycle through the lanes, assigning each new transition to the next lane. + // In most cases, this means every transition gets its own lane, until we + // run out of lanes and cycle back to the beginning. + var lane = nextTransitionLane; + nextTransitionLane <<= 1; + + if ((nextTransitionLane & TransitionLanes) === NoLanes) { + nextTransitionLane = TransitionLane1; + } + + return lane; +} +function claimNextRetryLane() { + var lane = nextRetryLane; + nextRetryLane <<= 1; - function getNextLanes(root, wipLanes) { - // Early bailout if there's no pending work left. - var pendingLanes = root.pendingLanes; + if ((nextRetryLane & RetryLanes) === NoLanes) { + nextRetryLane = RetryLane1; + } - if (pendingLanes === NoLanes) { - return NoLanes; - } + return lane; +} +function getHighestPriorityLane(lanes) { + return lanes & -lanes; +} +function pickArbitraryLane(lanes) { + // This wrapper function gets inlined. Only exists so to communicate that it + // doesn't matter which bit is selected; you can pick any bit without + // affecting the algorithms where its used. Here I'm using + // getHighestPriorityLane because it requires the fewest operations. + return getHighestPriorityLane(lanes); +} - var nextLanes = NoLanes; - var suspendedLanes = root.suspendedLanes; - var pingedLanes = root.pingedLanes; // Do not work on any idle work until all the non-idle work has finished, - // even if the work is suspended. +function pickArbitraryLaneIndex(lanes) { + return 31 - clz32(lanes); +} - var nonIdlePendingLanes = pendingLanes & NonIdleLanes; +function laneToIndex(lane) { + return pickArbitraryLaneIndex(lane); +} - if (nonIdlePendingLanes !== NoLanes) { - var nonIdleUnblockedLanes = nonIdlePendingLanes & ~suspendedLanes; +function includesSomeLane(a, b) { + return (a & b) !== NoLanes; +} +function isSubsetOfLanes(set, subset) { + return (set & subset) === subset; +} +function mergeLanes(a, b) { + return a | b; +} +function removeLanes(set, subset) { + return set & ~subset; +} +function intersectLanes(a, b) { + return a & b; +} // Seems redundant, but it changes the type from a single lane (used for +// updates) to a group of lanes (used for flushing work). - if (nonIdleUnblockedLanes !== NoLanes) { - nextLanes = getHighestPriorityLanes(nonIdleUnblockedLanes); - } else { - var nonIdlePingedLanes = nonIdlePendingLanes & pingedLanes; +function laneToLanes(lane) { + return lane; +} +function createLaneMap(initial) { + // Intentionally pushing one by one. + // https://v8.dev/blog/elements-kinds#avoid-creating-holes + var laneMap = []; - if (nonIdlePingedLanes !== NoLanes) { - nextLanes = getHighestPriorityLanes(nonIdlePingedLanes); - } - } - } else { - // The only remaining work is Idle. - var unblockedLanes = pendingLanes & ~suspendedLanes; + for (var i = 0; i < TotalLanes; i++) { + laneMap.push(initial); + } - if (unblockedLanes !== NoLanes) { - nextLanes = getHighestPriorityLanes(unblockedLanes); - } else { - if (pingedLanes !== NoLanes) { - nextLanes = getHighestPriorityLanes(pingedLanes); - } - } - } + return laneMap; +} +function markRootUpdated$1(root, updateLane) { + root.pendingLanes |= updateLane; // If there are any suspended transitions, it's possible this new update + // could unblock them. Clear the suspended lanes so that we can try rendering + // them again. + // + // TODO: We really only need to unsuspend only lanes that are in the + // `subtreeLanes` of the updated fiber, or the update lanes of the return + // path. This would exclude suspended updates in an unrelated sibling tree, + // since there's no way for this update to unblock it. + // + // We don't do this if the incoming update is idle, because we never process + // idle updates until after all the regular updates have finished; there's no + // way it could unblock a transition. + + if (updateLane !== IdleLane) { + root.suspendedLanes = NoLanes; + root.pingedLanes = NoLanes; + } +} +function markRootSuspended$1(root, suspendedLanes, spawnedLane) { + root.suspendedLanes |= suspendedLanes; + root.pingedLanes &= ~suspendedLanes; // The suspended lanes are no longer CPU-bound. Clear their expiration times. + + var expirationTimes = root.expirationTimes; + var lanes = suspendedLanes; + + while (lanes > 0) { + var index = pickArbitraryLaneIndex(lanes); + var lane = 1 << index; + expirationTimes[index] = NoTimestamp; + lanes &= ~lane; + } + + if (spawnedLane !== NoLane) { + markSpawnedDeferredLane(root, spawnedLane, suspendedLanes); + } +} +function markRootPinged$1(root, pingedLanes) { + root.pingedLanes |= root.suspendedLanes & pingedLanes; +} +function markRootFinished(root, remainingLanes, spawnedLane) { + var noLongerPendingLanes = root.pendingLanes & ~remainingLanes; + root.pendingLanes = remainingLanes; // Let's try everything again - if (nextLanes === NoLanes) { - // This should only be reachable if we're suspended - // TODO: Consider warning in this path if a fallback timer is not scheduled. - return NoLanes; - } // If we're already in the middle of a render, switching lanes will interrupt - // it and we'll lose our progress. We should only do this if the new lanes are - // higher priority. - - if ( - wipLanes !== NoLanes && - wipLanes !== nextLanes && // If we already suspended with a delay, then interrupting is fine. Don't - // bother waiting until the root is complete. - (wipLanes & suspendedLanes) === NoLanes - ) { - var nextLane = getHighestPriorityLane(nextLanes); - var wipLane = getHighestPriorityLane(wipLanes); - - if ( - // Tests whether the next lane is equal or lower priority than the wip - // one. This works because the bits decrease in priority as you go left. - nextLane >= wipLane || // Default priority updates should not interrupt transition updates. The - // only difference between default updates and transition updates is that - // default updates do not support refresh transitions. - (nextLane === DefaultLane && (wipLane & TransitionLanes) !== NoLanes) - ) { - // Keep working on the existing in-progress tree. Do not interrupt. - return wipLanes; - } - } + root.suspendedLanes = NoLanes; + root.pingedLanes = NoLanes; + root.expiredLanes &= remainingLanes; + root.entangledLanes &= remainingLanes; + root.errorRecoveryDisabledLanes &= remainingLanes; + root.shellSuspendCounter = 0; + var entanglements = root.entanglements; + var expirationTimes = root.expirationTimes; + var hiddenUpdates = root.hiddenUpdates; // Clear the lanes that no longer have pending work - return nextLanes; - } - function getEntangledLanes(root, renderLanes) { - var entangledLanes = renderLanes; + var lanes = noLongerPendingLanes; - if ((root.current.mode & ConcurrentUpdatesByDefaultMode) !== NoMode); - else if ((entangledLanes & InputContinuousLane) !== NoLanes) { - // When updates are sync by default, we entangle continuous priority updates - // and default updates, so they render in the same batch. The only reason - // they use separate lanes is because continuous updates should interrupt - // transitions, but default updates should not. - entangledLanes |= entangledLanes & DefaultLane; - } // Check for entangled lanes and add them to the batch. - // - // A lane is said to be entangled with another when it's not allowed to render - // in a batch that does not also include the other lane. Typically we do this - // when multiple updates have the same source, and we only want to respond to - // the most recent event from that source. - // - // Note that we apply entanglements *after* checking for partial work above. - // This means that if a lane is entangled during an interleaved event while - // it's already rendering, we won't interrupt it. This is intentional, since - // entanglement is usually "best effort": we'll try our best to render the - // lanes in the same batch, but it's not worth throwing out partially - // completed work in order to do it. - // TODO: Reconsider this. The counter-argument is that the partial work - // represents an intermediate state, which we don't want to show to the user. - // And by spending extra time finishing it, we're increasing the amount of - // time it takes to show the final state, which is what they are actually - // waiting for. - // - // For those exceptions where entanglement is semantically important, - // we should ensure that there is no partial work at the - // time we apply the entanglement. + while (lanes > 0) { + var index = pickArbitraryLaneIndex(lanes); + var lane = 1 << index; + entanglements[index] = NoLanes; + expirationTimes[index] = NoTimestamp; + var hiddenUpdatesForLane = hiddenUpdates[index]; - var allEntangledLanes = root.entangledLanes; + if (hiddenUpdatesForLane !== null) { + hiddenUpdates[index] = null; // "Hidden" updates are updates that were made to a hidden component. They + // have special logic associated with them because they may be entangled + // with updates that occur outside that tree. But once the outer tree + // commits, they behave like regular updates. - if (allEntangledLanes !== NoLanes) { - var entanglements = root.entanglements; - var lanes = entangledLanes & allEntangledLanes; + for (var i = 0; i < hiddenUpdatesForLane.length; i++) { + var update = hiddenUpdatesForLane[i]; - while (lanes > 0) { - var index = pickArbitraryLaneIndex(lanes); - var lane = 1 << index; - entangledLanes |= entanglements[index]; - lanes &= ~lane; + if (update !== null) { + update.lane &= ~OffscreenLane; } } - - return entangledLanes; } - function computeExpirationTime(lane, currentTime) { - switch (lane) { - case SyncHydrationLane: - case SyncLane: - case InputContinuousHydrationLane: - case InputContinuousLane: - // User interactions should expire slightly more quickly. - // - // NOTE: This is set to the corresponding constant as in Scheduler.js. - // When we made it larger, a product metric in www regressed, suggesting - // there's a user interaction that's being starved by a series of - // synchronous updates. If that theory is correct, the proper solution is - // to fix the starvation. However, this scenario supports the idea that - // expiration times are an important safeguard when starvation - // does happen. - return currentTime + syncLaneExpirationMs; - - case DefaultHydrationLane: - case DefaultLane: - case TransitionHydrationLane: - case TransitionLane1: - case TransitionLane2: - case TransitionLane3: - case TransitionLane4: - case TransitionLane5: - case TransitionLane6: - case TransitionLane7: - case TransitionLane8: - case TransitionLane9: - case TransitionLane10: - case TransitionLane11: - case TransitionLane12: - case TransitionLane13: - case TransitionLane14: - case TransitionLane15: - return currentTime + transitionLaneExpirationMs; - - case RetryLane1: - case RetryLane2: - case RetryLane3: - case RetryLane4: - // TODO: Retries should be allowed to expire if they are CPU bound for - // too long, but when I made this change it caused a spike in browser - // crashes. There must be some other underlying bug; not super urgent but - // ideally should figure out why and fix it. Unfortunately we don't have - // a repro for the crashes, only detected via production metrics. - return NoTimestamp; - - case SelectiveHydrationLane: - case IdleHydrationLane: - case IdleLane: - case OffscreenLane: - case DeferredLane: - // Anything idle priority or lower should never expire. - return NoTimestamp; - - default: - { - error("Should have found matching lanes. This is a bug in React."); - } + lanes &= ~lane; + } - return NoTimestamp; - } - } + if (spawnedLane !== NoLane) { + markSpawnedDeferredLane(root, spawnedLane, // This render finished successfully without suspending, so we don't need + // to entangle the spawned task with the parent task. + NoLanes); + } +} - function markStarvedLanesAsExpired(root, currentTime) { - // TODO: This gets called every time we yield. We can optimize by storing - // the earliest expiration time on the root. Then use that to quickly bail out - // of this function. - var pendingLanes = root.pendingLanes; - var suspendedLanes = root.suspendedLanes; - var pingedLanes = root.pingedLanes; - var expirationTimes = root.expirationTimes; // Iterate through the pending lanes and check if we've reached their - // expiration time. If so, we'll assume the update is being starved and mark - // it as expired to force it to finish. - // TODO: We should be able to replace this with upgradePendingLanesToSync - // - // We exclude retry lanes because those must always be time sliced, in order - // to unwrap uncached promises. - // TODO: Write a test for this - - var lanes = pendingLanes & ~RetryLanes; - - while (lanes > 0) { - var index = pickArbitraryLaneIndex(lanes); - var lane = 1 << index; - var expirationTime = expirationTimes[index]; - - if (expirationTime === NoTimestamp) { - // Found a pending lane with no expiration time. If it's not suspended, or - // if it's pinged, assume it's CPU-bound. Compute a new expiration time - // using the current time. - if ( - (lane & suspendedLanes) === NoLanes || - (lane & pingedLanes) !== NoLanes - ) { - // Assumes timestamps are monotonically increasing. - expirationTimes[index] = computeExpirationTime(lane, currentTime); - } - } else if (expirationTime <= currentTime) { - // This lane expired - root.expiredLanes |= lane; - } +function markSpawnedDeferredLane(root, spawnedLane, entangledLanes) { + // This render spawned a deferred task. Mark it as pending. + root.pendingLanes |= spawnedLane; + root.suspendedLanes &= ~spawnedLane; // Entangle the spawned lane with the DeferredLane bit so that we know it + // was the result of another render. This lets us avoid a useDeferredValue + // waterfall — only the first level will defer. + + var spawnedLaneIndex = laneToIndex(spawnedLane); + root.entangledLanes |= spawnedLane; + root.entanglements[spawnedLaneIndex] |= DeferredLane | // If the parent render task suspended, we must also entangle those lanes + // with the spawned task, so that the deferred task includes all the same + // updates that the parent task did. We can exclude any lane that is not + // used for updates (e.g. Offscreen). + entangledLanes & UpdateLanes; +} - lanes &= ~lane; - } - } // This returns the highest priority pending lanes regardless of whether they - function getLanesToRetrySynchronouslyOnError( - root, - originallyAttemptedLanes - ) { - if (root.errorRecoveryDisabledLanes & originallyAttemptedLanes) { - // The error recovery mechanism is disabled until these lanes are cleared. - return NoLanes; - } +function markRootEntangled(root, entangledLanes) { + // In addition to entangling each of the given lanes with each other, we also + // have to consider _transitive_ entanglements. For each lane that is already + // entangled with *any* of the given lanes, that lane is now transitively + // entangled with *all* the given lanes. + // + // Translated: If C is entangled with A, then entangling A with B also + // entangles C with B. + // + // If this is hard to grasp, it might help to intentionally break this + // function and look at the tests that fail in ReactTransition-test.js. Try + // commenting out one of the conditions below. + var rootEntangledLanes = root.entangledLanes |= entangledLanes; + var entanglements = root.entanglements; + var lanes = rootEntangledLanes; + + while (lanes) { + var index = pickArbitraryLaneIndex(lanes); + var lane = 1 << index; + + if ( // Is this one of the newly entangled lanes? + lane & entangledLanes | // Is this lane transitively entangled with the newly entangled lanes? + entanglements[index] & entangledLanes) { + entanglements[index] |= entangledLanes; + } + + lanes &= ~lane; + } +} +function upgradePendingLaneToSync(root, lane) { + // Since we're upgrading the priority of the given lane, there is now pending + // sync work. + root.pendingLanes |= SyncLane; // Entangle the sync lane with the lane we're upgrading. This means SyncLane + // will not be allowed to finish without also finishing the given lane. + + root.entangledLanes |= SyncLane; + root.entanglements[SyncLaneIndex] |= lane; +} +function markHiddenUpdate(root, update, lane) { + var index = laneToIndex(lane); + var hiddenUpdates = root.hiddenUpdates; + var hiddenUpdatesForLane = hiddenUpdates[index]; + + if (hiddenUpdatesForLane === null) { + hiddenUpdates[index] = [update]; + } else { + hiddenUpdatesForLane.push(update); + } + + update.lane = lane | OffscreenLane; +} +function getBumpedLaneForHydration(root, renderLanes) { + var renderLane = getHighestPriorityLane(renderLanes); + var lane; + + if ((renderLane & SyncUpdateLanes) !== NoLane) { + lane = SyncHydrationLane; + } else { + switch (renderLane) { + case SyncLane: + lane = SyncHydrationLane; + break; + + case InputContinuousLane: + lane = InputContinuousHydrationLane; + break; + + case DefaultLane: + lane = DefaultHydrationLane; + break; + + case TransitionLane1: + case TransitionLane2: + case TransitionLane3: + case TransitionLane4: + case TransitionLane5: + case TransitionLane6: + case TransitionLane7: + case TransitionLane8: + case TransitionLane9: + case TransitionLane10: + case TransitionLane11: + case TransitionLane12: + case TransitionLane13: + case TransitionLane14: + case TransitionLane15: + case RetryLane1: + case RetryLane2: + case RetryLane3: + case RetryLane4: + lane = TransitionHydrationLane; + break; + + case IdleLane: + lane = IdleHydrationLane; + break; + + default: + // Everything else is already either a hydration lane, or shouldn't + // be retried at a hydration lane. + lane = NoLane; + break; + } + } // Check if the lane we chose is suspended. If so, that indicates that we + // already attempted and failed to hydrate at that level. Also check if we're + // already rendering that lane, which is rare but could happen. + + + if ((lane & (root.suspendedLanes | renderLanes)) !== NoLane) { + // Give up trying to hydrate and fall back to client render. + return NoLane; + } + + return lane; +} +function getTransitionsForLanes(root, lanes) { + { + return null; + } +} - var everythingButOffscreen = root.pendingLanes & ~OffscreenLane; +var NoEventPriority = NoLane; +var DiscreteEventPriority = SyncLane; +var ContinuousEventPriority = InputContinuousLane; +var DefaultEventPriority = DefaultLane; +var IdleEventPriority = IdleLane; +function higherEventPriority(a, b) { + return a !== 0 && a < b ? a : b; +} +function lowerEventPriority(a, b) { + return a === 0 || a > b ? a : b; +} +function isHigherEventPriority(a, b) { + return a !== 0 && a < b; +} +function eventPriorityToLane(updatePriority) { + return updatePriority; +} +function lanesToEventPriority(lanes) { + var lane = getHighestPriorityLane(lanes); - if (everythingButOffscreen !== NoLanes) { - return everythingButOffscreen; - } + if (!isHigherEventPriority(DiscreteEventPriority, lane)) { + return DiscreteEventPriority; + } - if (everythingButOffscreen & OffscreenLane) { - return OffscreenLane; - } + if (!isHigherEventPriority(ContinuousEventPriority, lane)) { + return ContinuousEventPriority; + } - return NoLanes; - } - function includesSyncLane(lanes) { - return (lanes & (SyncLane | SyncHydrationLane)) !== NoLanes; - } - function includesNonIdleWork(lanes) { - return (lanes & NonIdleLanes) !== NoLanes; - } - function includesOnlyRetries(lanes) { - return (lanes & RetryLanes) === lanes; - } - function includesOnlyNonUrgentLanes(lanes) { - // TODO: Should hydration lanes be included here? This function is only - // used in `updateDeferredValueImpl`. - var UrgentLanes = SyncLane | InputContinuousLane | DefaultLane; - return (lanes & UrgentLanes) === NoLanes; - } - function includesOnlyTransitions(lanes) { - return (lanes & TransitionLanes) === lanes; - } - function includesBlockingLane(root, lanes) { - if ((root.current.mode & ConcurrentUpdatesByDefaultMode) !== NoMode) { - // Concurrent updates by default always use time slicing. - return false; - } + if (includesNonIdleWork(lane)) { + return DefaultEventPriority; + } - var SyncDefaultLanes = - InputContinuousHydrationLane | - InputContinuousLane | - DefaultHydrationLane | - DefaultLane; - return (lanes & SyncDefaultLanes) !== NoLanes; - } - function includesExpiredLane(root, lanes) { - // This is a separate check from includesBlockingLane because a lane can - // expire after a render has already started. - return (lanes & root.expiredLanes) !== NoLanes; - } - function isTransitionLane(lane) { - return (lane & TransitionLanes) !== NoLanes; - } - function claimNextTransitionLane() { - // Cycle through the lanes, assigning each new transition to the next lane. - // In most cases, this means every transition gets its own lane, until we - // run out of lanes and cycle back to the beginning. - var lane = nextTransitionLane; - nextTransitionLane <<= 1; + return IdleEventPriority; +} - if ((nextTransitionLane & TransitionLanes) === NoLanes) { - nextTransitionLane = TransitionLane1; - } +// Renderers that don't support hydration +// can re-export everything from this module. +function shim$1() { + 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 supportsHydration = false; +var isSuspenseInstancePending = shim$1; +var isSuspenseInstanceFallback = shim$1; +var getSuspenseInstanceFallbackErrorDetails = shim$1; +var registerSuspenseInstanceRetry = shim$1; +var clearSuspenseBoundary = shim$1; +var clearSuspenseBoundaryFromContainer = shim$1; + +// Renderers that don't support hydration +// can re-export everything from this module. +function shim() { + throw new Error('The current renderer does not support Resources. ' + 'This error is likely caused by a bug in React. ' + 'Please file an issue.'); +} // Resources (when unsupported) +var suspendResource = shim; + +var NO_CONTEXT = {}; +var nodeToInstanceMap = new WeakMap(); + +{ + Object.freeze(NO_CONTEXT); +} - return lane; - } - function claimNextRetryLane() { - var lane = nextRetryLane; - nextRetryLane <<= 1; +function getPublicInstance(inst) { + switch (inst.tag) { + case 'INSTANCE': + var createNodeMock = inst.rootContainerInstance.createNodeMock; + var mockNode = createNodeMock({ + type: inst.type, + props: inst.props + }); - if ((nextRetryLane & RetryLanes) === NoLanes) { - nextRetryLane = RetryLane1; + if (typeof mockNode === 'object' && mockNode !== null) { + nodeToInstanceMap.set(mockNode, inst); } - return lane; - } - function getHighestPriorityLane(lanes) { - return lanes & -lanes; - } - function pickArbitraryLane(lanes) { - // This wrapper function gets inlined. Only exists so to communicate that it - // doesn't matter which bit is selected; you can pick any bit without - // affecting the algorithms where its used. Here I'm using - // getHighestPriorityLane because it requires the fewest operations. - return getHighestPriorityLane(lanes); - } - - function pickArbitraryLaneIndex(lanes) { - return 31 - clz32(lanes); - } - - function laneToIndex(lane) { - return pickArbitraryLaneIndex(lane); - } + return mockNode; - function includesSomeLane(a, b) { - return (a & b) !== NoLanes; - } - function isSubsetOfLanes(set, subset) { - return (set & subset) === subset; - } - function mergeLanes(a, b) { - return a | b; - } - function removeLanes(set, subset) { - return set & ~subset; + default: + return inst; + } +} +function appendChild(parentInstance, child) { + { + if (!isArray(parentInstance.children)) { + error('An invalid container has been provided. ' + 'This may indicate that another renderer is being used in addition to the test renderer. ' + '(For example, ReactDOM.createPortal inside of a ReactTestRenderer tree.) ' + 'This is not supported.'); } - function intersectLanes(a, b) { - return a & b; - } // Seems redundant, but it changes the type from a single lane (used for - // updates) to a group of lanes (used for flushing work). + } - function laneToLanes(lane) { - return lane; - } - function createLaneMap(initial) { - // Intentionally pushing one by one. - // https://v8.dev/blog/elements-kinds#avoid-creating-holes - var laneMap = []; + var index = parentInstance.children.indexOf(child); - for (var i = 0; i < TotalLanes; i++) { - laneMap.push(initial); - } + if (index !== -1) { + parentInstance.children.splice(index, 1); + } - return laneMap; - } - function markRootUpdated$1(root, updateLane) { - root.pendingLanes |= updateLane; // If there are any suspended transitions, it's possible this new update - // could unblock them. Clear the suspended lanes so that we can try rendering - // them again. - // - // TODO: We really only need to unsuspend only lanes that are in the - // `subtreeLanes` of the updated fiber, or the update lanes of the return - // path. This would exclude suspended updates in an unrelated sibling tree, - // since there's no way for this update to unblock it. - // - // We don't do this if the incoming update is idle, because we never process - // idle updates until after all the regular updates have finished; there's no - // way it could unblock a transition. + parentInstance.children.push(child); +} +function insertBefore(parentInstance, child, beforeChild) { + var index = parentInstance.children.indexOf(child); - if (updateLane !== IdleLane) { - root.suspendedLanes = NoLanes; - root.pingedLanes = NoLanes; - } - } - function markRootSuspended$1(root, suspendedLanes, spawnedLane) { - root.suspendedLanes |= suspendedLanes; - root.pingedLanes &= ~suspendedLanes; // The suspended lanes are no longer CPU-bound. Clear their expiration times. + if (index !== -1) { + parentInstance.children.splice(index, 1); + } - var expirationTimes = root.expirationTimes; - var lanes = suspendedLanes; + var beforeIndex = parentInstance.children.indexOf(beforeChild); + parentInstance.children.splice(beforeIndex, 0, child); +} +function removeChild(parentInstance, child) { + var index = parentInstance.children.indexOf(child); + parentInstance.children.splice(index, 1); +} +function clearContainer(container) { + container.children.splice(0); +} +function getRootHostContext(rootContainerInstance) { + return NO_CONTEXT; +} +function getChildHostContext(parentHostContext, type) { + return NO_CONTEXT; +} +function createInstance(type, props, rootContainerInstance, hostContext, internalInstanceHandle) { + return { + type: type, + props: props, + isHidden: false, + children: [], + internalInstanceHandle: internalInstanceHandle, + rootContainerInstance: rootContainerInstance, + tag: 'INSTANCE' + }; +} +function appendInitialChild(parentInstance, child) { + var index = parentInstance.children.indexOf(child); - while (lanes > 0) { - var index = pickArbitraryLaneIndex(lanes); - var lane = 1 << index; - expirationTimes[index] = NoTimestamp; - lanes &= ~lane; - } + if (index !== -1) { + parentInstance.children.splice(index, 1); + } - if (spawnedLane !== NoLane) { - markSpawnedDeferredLane(root, spawnedLane, suspendedLanes); - } - } - function markRootPinged$1(root, pingedLanes) { - root.pingedLanes |= root.suspendedLanes & pingedLanes; - } - function markRootFinished(root, remainingLanes, spawnedLane) { - var noLongerPendingLanes = root.pendingLanes & ~remainingLanes; - root.pendingLanes = remainingLanes; // Let's try everything again + parentInstance.children.push(child); +} +function shouldSetTextContent(type, props) { + return false; +} +function createTextInstance(text, rootContainerInstance, hostContext, internalInstanceHandle) { + return { + text: text, + isHidden: false, + tag: 'TEXT' + }; +} +var currentUpdatePriority = NoEventPriority; +function setCurrentUpdatePriority(newPriority) { + currentUpdatePriority = newPriority; +} +function getCurrentUpdatePriority() { + return currentUpdatePriority; +} +function resolveUpdatePriority() { + if (currentUpdatePriority !== NoEventPriority) { + return currentUpdatePriority; + } - root.suspendedLanes = NoLanes; - root.pingedLanes = NoLanes; - root.expiredLanes &= remainingLanes; - root.entangledLanes &= remainingLanes; - root.errorRecoveryDisabledLanes &= remainingLanes; - root.shellSuspendCounter = 0; - var entanglements = root.entanglements; - var expirationTimes = root.expirationTimes; - var hiddenUpdates = root.hiddenUpdates; // Clear the lanes that no longer have pending work + return DefaultEventPriority; +} +function shouldAttemptEagerTransition() { + return false; +} +var scheduleTimeout = setTimeout; +var cancelTimeout = clearTimeout; +var noTimeout = -1; // ------------------- +function commitUpdate(instance, updatePayload, type, oldProps, newProps, internalInstanceHandle) { + instance.type = type; + instance.props = newProps; +} +function commitMount(instance, type, newProps, internalInstanceHandle) {// noop +} +function commitTextUpdate(textInstance, oldText, newText) { + textInstance.text = newText; +} +function resetTextContent(testElement) {// noop +} +var appendChildToContainer = appendChild; +var insertInContainerBefore = insertBefore; +var removeChildFromContainer = removeChild; +function hideInstance(instance) { + instance.isHidden = true; +} +function hideTextInstance(textInstance) { + textInstance.isHidden = true; +} +function unhideInstance(instance, props) { + instance.isHidden = false; +} +function unhideTextInstance(textInstance, text) { + textInstance.isHidden = false; +} +function preloadInstance(type, props) { + // Return true to indicate it's already loaded + return true; +} +function waitForCommitToBeReady() { + return null; +} +var NotPendingTransition = null; - var lanes = noLongerPendingLanes; +var valueStack = []; +var fiberStack; - while (lanes > 0) { - var index = pickArbitraryLaneIndex(lanes); - var lane = 1 << index; - entanglements[index] = NoLanes; - expirationTimes[index] = NoTimestamp; - var hiddenUpdatesForLane = hiddenUpdates[index]; +{ + fiberStack = []; +} - if (hiddenUpdatesForLane !== null) { - hiddenUpdates[index] = null; // "Hidden" updates are updates that were made to a hidden component. They - // have special logic associated with them because they may be entangled - // with updates that occur outside that tree. But once the outer tree - // commits, they behave like regular updates. +var index = -1; - for (var i = 0; i < hiddenUpdatesForLane.length; i++) { - var update = hiddenUpdatesForLane[i]; +function createCursor(defaultValue) { + return { + current: defaultValue + }; +} - if (update !== null) { - update.lane &= ~OffscreenLane; - } - } - } +function pop(cursor, fiber) { + if (index < 0) { + { + error('Unexpected pop.'); + } - lanes &= ~lane; - } + return; + } - if (spawnedLane !== NoLane) { - markSpawnedDeferredLane( - root, - spawnedLane, // This render finished successfully without suspending, so we don't need - // to entangle the spawned task with the parent task. - NoLanes - ); - } + { + if (fiber !== fiberStack[index]) { + error('Unexpected Fiber popped.'); } + } - function markSpawnedDeferredLane(root, spawnedLane, entangledLanes) { - // This render spawned a deferred task. Mark it as pending. - root.pendingLanes |= spawnedLane; - root.suspendedLanes &= ~spawnedLane; // Entangle the spawned lane with the DeferredLane bit so that we know it - // was the result of another render. This lets us avoid a useDeferredValue - // waterfall — only the first level will defer. + cursor.current = valueStack[index]; + valueStack[index] = null; - var spawnedLaneIndex = laneToIndex(spawnedLane); - root.entangledLanes |= spawnedLane; - root.entanglements[spawnedLaneIndex] |= - DeferredLane | // If the parent render task suspended, we must also entangle those lanes - // with the spawned task, so that the deferred task includes all the same - // updates that the parent task did. We can exclude any lane that is not - // used for updates (e.g. Offscreen). - (entangledLanes & UpdateLanes); - } + { + fiberStack[index] = null; + } - function markRootEntangled(root, entangledLanes) { - // In addition to entangling each of the given lanes with each other, we also - // have to consider _transitive_ entanglements. For each lane that is already - // entangled with *any* of the given lanes, that lane is now transitively - // entangled with *all* the given lanes. - // - // Translated: If C is entangled with A, then entangling A with B also - // entangles C with B. - // - // If this is hard to grasp, it might help to intentionally break this - // function and look at the tests that fail in ReactTransition-test.js. Try - // commenting out one of the conditions below. - var rootEntangledLanes = (root.entangledLanes |= entangledLanes); - var entanglements = root.entanglements; - var lanes = rootEntangledLanes; - - while (lanes) { - var index = pickArbitraryLaneIndex(lanes); - var lane = 1 << index; - - if ( - // Is this one of the newly entangled lanes? - (lane & entangledLanes) | // Is this lane transitively entangled with the newly entangled lanes? - (entanglements[index] & entangledLanes) - ) { - entanglements[index] |= entangledLanes; - } + index--; +} - lanes &= ~lane; - } - } - function upgradePendingLaneToSync(root, lane) { - // Since we're upgrading the priority of the given lane, there is now pending - // sync work. - root.pendingLanes |= SyncLane; // Entangle the sync lane with the lane we're upgrading. This means SyncLane - // will not be allowed to finish without also finishing the given lane. +function push(cursor, value, fiber) { + index++; + valueStack[index] = cursor.current; - root.entangledLanes |= SyncLane; - root.entanglements[SyncLaneIndex] |= lane; - } - function markHiddenUpdate(root, update, lane) { - var index = laneToIndex(lane); - var hiddenUpdates = root.hiddenUpdates; - var hiddenUpdatesForLane = hiddenUpdates[index]; + { + fiberStack[index] = fiber; + } - if (hiddenUpdatesForLane === null) { - hiddenUpdates[index] = [update]; - } else { - hiddenUpdatesForLane.push(update); - } + cursor.current = value; +} - update.lane = lane | OffscreenLane; - } - function getBumpedLaneForHydration(root, renderLanes) { - var renderLane = getHighestPriorityLane(renderLanes); - var lane; +var warnedAboutMissingGetChildContext; - if ((renderLane & SyncUpdateLanes) !== NoLane) { - lane = SyncHydrationLane; - } else { - switch (renderLane) { - case SyncLane: - lane = SyncHydrationLane; - break; +{ + warnedAboutMissingGetChildContext = {}; +} - case InputContinuousLane: - lane = InputContinuousHydrationLane; - break; +var emptyContextObject = {}; - case DefaultLane: - lane = DefaultHydrationLane; - break; +{ + Object.freeze(emptyContextObject); +} // A cursor to the current merged context object on the stack. - case TransitionLane1: - case TransitionLane2: - case TransitionLane3: - case TransitionLane4: - case TransitionLane5: - case TransitionLane6: - case TransitionLane7: - case TransitionLane8: - case TransitionLane9: - case TransitionLane10: - case TransitionLane11: - case TransitionLane12: - case TransitionLane13: - case TransitionLane14: - case TransitionLane15: - case RetryLane1: - case RetryLane2: - case RetryLane3: - case RetryLane4: - lane = TransitionHydrationLane; - break; - case IdleLane: - lane = IdleHydrationLane; - break; +var contextStackCursor$1 = createCursor(emptyContextObject); // A cursor to a boolean indicating whether the context has changed. - default: - // Everything else is already either a hydration lane, or shouldn't - // be retried at a hydration lane. - lane = NoLane; - break; - } - } // Check if the lane we chose is suspended. If so, that indicates that we - // already attempted and failed to hydrate at that level. Also check if we're - // already rendering that lane, which is rare but could happen. +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. - if ((lane & (root.suspendedLanes | renderLanes)) !== NoLane) { - // Give up trying to hydrate and fall back to client render. - return NoLane; - } +var previousContext = emptyContextObject; - return lane; - } - function getTransitionsForLanes(root, lanes) { - { - return null; - } +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; } - var NoEventPriority = NoLane; - var DiscreteEventPriority = SyncLane; - var ContinuousEventPriority = InputContinuousLane; - var DefaultEventPriority = DefaultLane; - var IdleEventPriority = IdleLane; - function higherEventPriority(a, b) { - return a !== 0 && a < b ? a : b; - } - function lowerEventPriority(a, b) { - return a === 0 || a > b ? a : b; - } - function isHigherEventPriority(a, b) { - return a !== 0 && a < b; - } - function eventPriorityToLane(updatePriority) { - return updatePriority; - } - function lanesToEventPriority(lanes) { - var lane = getHighestPriorityLane(lanes); + return contextStackCursor$1.current; + } +} - if (!isHigherEventPriority(DiscreteEventPriority, lane)) { - return DiscreteEventPriority; - } +function cacheContext(workInProgress, unmaskedContext, maskedContext) { + { + var instance = workInProgress.stateNode; + instance.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext; + instance.__reactInternalMemoizedMaskedChildContext = maskedContext; + } +} - if (!isHigherEventPriority(ContinuousEventPriority, lane)) { - return ContinuousEventPriority; - } +function getMaskedContext(workInProgress, unmaskedContext) { + { + var type = workInProgress.type; + var contextTypes = type.contextTypes; - if (includesNonIdleWork(lane)) { - return DefaultEventPriority; - } + 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. - return IdleEventPriority; - } - // Renderers that don't support hydration - // can re-export everything from this module. - function shim$1() { - 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 instance = workInProgress.stateNode; - var supportsHydration = false; - var isSuspenseInstancePending = shim$1; - var isSuspenseInstanceFallback = shim$1; - var getSuspenseInstanceFallbackErrorDetails = shim$1; - var registerSuspenseInstanceRetry = shim$1; - var clearSuspenseBoundary = shim$1; - var clearSuspenseBoundaryFromContainer = shim$1; + if (instance && instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext) { + return instance.__reactInternalMemoizedMaskedChildContext; + } - // Renderers that don't support hydration - // can re-export everything from this module. - function shim() { - throw new Error( - "The current renderer does not support Resources. " + - "This error is likely caused by a bug in React. " + - "Please file an issue." - ); - } // Resources (when unsupported) - var suspendResource = shim; + var context = {}; - var NO_CONTEXT = {}; - var nodeToInstanceMap = new WeakMap(); + for (var key in contextTypes) { + context[key] = unmaskedContext[key]; + } // 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. - { - Object.freeze(NO_CONTEXT); + + if (instance) { + cacheContext(workInProgress, unmaskedContext, context); } - function getPublicInstance(inst) { - switch (inst.tag) { - case "INSTANCE": - var createNodeMock = inst.rootContainerInstance.createNodeMock; - var mockNode = createNodeMock({ - type: inst.type, - props: inst.props - }); + return context; + } +} - if (typeof mockNode === "object" && mockNode !== null) { - nodeToInstanceMap.set(mockNode, inst); - } +function hasContextChanged() { + { + return didPerformWorkStackCursor.current; + } +} + +function isContextProvider(type) { + { + var childContextTypes = type.childContextTypes; + return childContextTypes !== null && childContextTypes !== undefined; + } +} - return mockNode; +function popContext(fiber) { + { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor$1, fiber); + } +} - default: - return inst; - } +function popTopLevelContextObject(fiber) { + { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor$1, fiber); + } +} + +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.'); } - function appendChild(parentInstance, child) { - { - if (!isArray(parentInstance.children)) { - error( - "An invalid container has been provided. " + - "This may indicate that another renderer is being used in addition to the test renderer. " + - "(For example, ReactDOM.createPortal inside of a ReactTestRenderer tree.) " + - "This is not supported." - ); - } - } - var index = parentInstance.children.indexOf(child); + push(contextStackCursor$1, context, fiber); + push(didPerformWorkStackCursor, didChange, fiber); + } +} - if (index !== -1) { - parentInstance.children.splice(index, 1); - } +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. - parentInstance.children.push(child); - } - function insertBefore(parentInstance, child, beforeChild) { - var index = parentInstance.children.indexOf(child); + if (typeof instance.getChildContext !== 'function') { + { + var componentName = getComponentNameFromFiber(fiber) || 'Unknown'; - if (index !== -1) { - parentInstance.children.splice(index, 1); + if (!warnedAboutMissingGetChildContext[componentName]) { + warnedAboutMissingGetChildContext[componentName] = true; + + 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 beforeIndex = parentInstance.children.indexOf(beforeChild); - parentInstance.children.splice(beforeIndex, 0, child); - } - function removeChild(parentInstance, child) { - var index = parentInstance.children.indexOf(child); - parentInstance.children.splice(index, 1); - } - function clearContainer(container) { - container.children.splice(0); - } - function getRootHostContext(rootContainerInstance) { - return NO_CONTEXT; - } - function getChildHostContext(parentHostContext, type) { - return NO_CONTEXT; - } - function createInstance( - type, - props, - rootContainerInstance, - hostContext, - internalInstanceHandle - ) { - return { - type: type, - props: props, - isHidden: false, - children: [], - internalInstanceHandle: internalInstanceHandle, - rootContainerInstance: rootContainerInstance, - tag: "INSTANCE" - }; + return parentContext; } - function appendInitialChild(parentInstance, child) { - var index = parentInstance.children.indexOf(child); - if (index !== -1) { - parentInstance.children.splice(index, 1); - } + var childContext = instance.getChildContext(); - parentInstance.children.push(child); - } - function shouldSetTextContent(type, props) { - return false; - } - function createTextInstance( - text, - rootContainerInstance, - hostContext, - internalInstanceHandle - ) { - return { - text: text, - isHidden: false, - tag: "TEXT" - }; - } - var currentUpdatePriority = NoEventPriority; - function setCurrentUpdatePriority(newPriority) { - currentUpdatePriority = newPriority; - } - function getCurrentUpdatePriority() { - return currentUpdatePriority; - } - function resolveUpdatePriority() { - if (currentUpdatePriority !== NoEventPriority) { - return currentUpdatePriority; + for (var contextKey in childContext) { + if (!(contextKey in childContextTypes)) { + throw new Error((getComponentNameFromFiber(fiber) || 'Unknown') + ".getChildContext(): key \"" + contextKey + "\" is not defined in childContextTypes."); } - - return DefaultEventPriority; - } - function shouldAttemptEagerTransition() { - return false; - } - var scheduleTimeout = setTimeout; - var cancelTimeout = clearTimeout; - var noTimeout = -1; // ------------------- - function commitUpdate( - instance, - updatePayload, - type, - oldProps, - newProps, - internalInstanceHandle - ) { - instance.type = type; - instance.props = newProps; - } - function commitMount(instance, type, newProps, internalInstanceHandle) { - // noop - } - function commitTextUpdate(textInstance, oldText, newText) { - textInstance.text = newText; - } - function resetTextContent(testElement) { - // noop - } - var appendChildToContainer = appendChild; - var insertInContainerBefore = insertBefore; - var removeChildFromContainer = removeChild; - function hideInstance(instance) { - instance.isHidden = true; - } - function hideTextInstance(textInstance) { - textInstance.isHidden = true; - } - function unhideInstance(instance, props) { - instance.isHidden = false; - } - function unhideTextInstance(textInstance, text) { - textInstance.isHidden = false; - } - function preloadInstance(type, props) { - // Return true to indicate it's already loaded - return true; } - function waitForCommitToBeReady() { - return null; - } - var NotPendingTransition = null; - var valueStack = []; - var fiberStack; + return assign({}, parentContext, childContext); + } +} - { - fiberStack = []; - } +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 index = -1; + 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. - function createCursor(defaultValue) { - return { - current: defaultValue - }; - } + previousContext = contextStackCursor$1.current; + push(contextStackCursor$1, memoizedMergedChildContext, workInProgress); + push(didPerformWorkStackCursor, didPerformWorkStackCursor.current, workInProgress); + return true; + } +} - function pop(cursor, fiber) { - if (index < 0) { - { - error("Unexpected pop."); - } +function invalidateContextProvider(workInProgress, type, didChange) { + { + var instance = workInProgress.stateNode; - return; - } + 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 (fiber !== fiberStack[index]) { - error("Unexpected Fiber popped."); - } - } + 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. - cursor.current = valueStack[index]; - valueStack[index] = null; + pop(didPerformWorkStackCursor, workInProgress); + pop(contextStackCursor$1, workInProgress); // Now push the new context and mark that it has changed. - { - fiberStack[index] = null; - } + push(contextStackCursor$1, mergedContext, workInProgress); + push(didPerformWorkStackCursor, didChange, workInProgress); + } else { + pop(didPerformWorkStackCursor, workInProgress); + push(didPerformWorkStackCursor, didChange, workInProgress); + } + } +} - index--; +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.'); } - function push(cursor, value, fiber) { - index++; - valueStack[index] = cursor.current; + var node = fiber; - { - fiberStack[index] = fiber; - } + do { + switch (node.tag) { + case HostRoot: + return node.stateNode.context; - cursor.current = value; - } + case ClassComponent: + { + var Component = node.type; - var warnedAboutMissingGetChildContext; + if (isContextProvider(Component)) { + return node.stateNode.__reactInternalMemoizedMergedChildContext; + } - { - warnedAboutMissingGetChildContext = {}; - } + break; + } + } // $FlowFixMe[incompatible-type] we bail out when we get a null - var emptyContextObject = {}; - { - Object.freeze(emptyContextObject); - } // A cursor to the current merged context object on the stack. + node = node.return; + } while (node !== null); - var contextStackCursor$1 = createCursor(emptyContextObject); // A cursor to a boolean indicating whether the context has changed. + throw new Error('Found unexpected detached subtree parent. ' + 'This error is likely caused by a bug in React. Please file an issue.'); + } +} - 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. +// 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 previousContext = emptyContextObject; +/** + * 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 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; - } +var objectIs = // $FlowFixMe[method-unbinding] +typeof Object.is === 'function' ? Object.is : is; - return contextStackCursor$1.current; - } - } +function describeBuiltInComponentFrame(name) { + { + return describeComponentFrame(name); + } +} +function describeDebugInfoFrame(name, env) { + return describeBuiltInComponentFrame(name + (env ? ' (' + env + ')' : '')); +} - function cacheContext(workInProgress, unmaskedContext, maskedContext) { - { - var instance = workInProgress.stateNode; - instance.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext; - instance.__reactInternalMemoizedMaskedChildContext = maskedContext; - } - } +{ + var PossiblyWeakMap$1 = typeof WeakMap === 'function' ? WeakMap : Map; + new PossiblyWeakMap$1(); +} - function getMaskedContext(workInProgress, unmaskedContext) { - { - var type = workInProgress.type; - var contextTypes = type.contextTypes; +function describeComponentFrame(name) { + return '\n in ' + (name || 'Unknown'); +} - 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. +function describeClassComponentFrame(ctor) { + { + return describeFunctionComponentFrame(ctor); + } +} +function describeFunctionComponentFrame(fn) { + { + if (!fn) { + return ''; + } - var instance = workInProgress.stateNode; + var name = fn.displayName || fn.name || null; + return describeComponentFrame(name); + } +} - if ( - instance && - instance.__reactInternalMemoizedUnmaskedChildContext === - unmaskedContext - ) { - return instance.__reactInternalMemoizedMaskedChildContext; - } +function describeFiber(fiber) { + switch (fiber.tag) { + case HostHoistable: + case HostSingleton: + case HostComponent: + return describeBuiltInComponentFrame(fiber.type); - var context = {}; + case LazyComponent: + return describeBuiltInComponentFrame('Lazy'); - for (var key in contextTypes) { - context[key] = unmaskedContext[key]; - } // 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. + case SuspenseComponent: + return describeBuiltInComponentFrame('Suspense'); - if (instance) { - cacheContext(workInProgress, unmaskedContext, context); - } + case SuspenseListComponent: + return describeBuiltInComponentFrame('SuspenseList'); - return context; - } - } + case FunctionComponent: + case SimpleMemoComponent: + return describeFunctionComponentFrame(fiber.type); - function hasContextChanged() { - { - return didPerformWorkStackCursor.current; - } - } + case ForwardRef: + return describeFunctionComponentFrame(fiber.type.render); - function isContextProvider(type) { - { - var childContextTypes = type.childContextTypes; - return childContextTypes !== null && childContextTypes !== undefined; - } - } + case ClassComponent: + return describeClassComponentFrame(fiber.type); - function popContext(fiber) { - { - pop(didPerformWorkStackCursor, fiber); - pop(contextStackCursor$1, fiber); - } - } + default: + return ''; + } +} - function popTopLevelContextObject(fiber) { - { - pop(didPerformWorkStackCursor, fiber); - pop(contextStackCursor$1, fiber); - } - } +function getStackByFiberInDevAndProd(workInProgress) { + try { + var info = ''; + var node = workInProgress; - 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." - ); - } + do { + info += describeFiber(node); - push(contextStackCursor$1, context, fiber); - push(didPerformWorkStackCursor, didChange, fiber); - } - } + if (true) { + // Add any Server Component stack frames in reverse order. + var debugInfo = node._debugInfo; - 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 (debugInfo) { + for (var i = debugInfo.length - 1; i >= 0; i--) { + var entry = debugInfo[i]; - if (typeof instance.getChildContext !== "function") { - { - var componentName = getComponentNameFromFiber(fiber) || "Unknown"; - - if (!warnedAboutMissingGetChildContext[componentName]) { - warnedAboutMissingGetChildContext[componentName] = true; - - 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 - ); + if (typeof entry.name === 'string') { + info += describeDebugInfoFrame(entry.name, entry.env); } } - - return parentContext; } + } // $FlowFixMe[incompatible-type] we bail out when we get a null - var childContext = instance.getChildContext(); - for (var contextKey in childContext) { - if (!(contextKey in childContextTypes)) { - throw new Error( - (getComponentNameFromFiber(fiber) || "Unknown") + - '.getChildContext(): key "' + - contextKey + - '" is not defined in childContextTypes.' - ); - } - } + node = node.return; + } while (node); - return assign({}, parentContext, childContext); - } - } + return info; + } catch (x) { + return '\nError generating stack: ' + x.message + '\n' + x.stack; + } +} - 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); - } - } - } +var CapturedStacks = new WeakMap(); +function createCapturedValueAtFiber(value, source) { + // If the value is an error, call this function immediately after it is thrown + // so the stack is accurate. + var stack; + + if (typeof value === 'object' && value !== null) { + var capturedStack = CapturedStacks.get(value); + + if (typeof capturedStack === 'string') { + stack = capturedStack; + } else { + stack = getStackByFiberInDevAndProd(source); + CapturedStacks.set(value, stack); + } + } else { + stack = getStackByFiberInDevAndProd(source); + } + + return { + value: value, + source: source, + stack: stack + }; +} +function createCapturedValueFromError(value, stack) { + if (typeof stack === 'string') { + CapturedStacks.set(value, stack); + } + + return { + value: value, + source: null, + stack: stack + }; +} - 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 contextStackCursor = createCursor(null); +var contextFiberStackCursor = createCursor(null); +var rootInstanceStackCursor = createCursor(null); // Represents the nearest host transition provider (in React DOM, a
) +// NOTE: Since forms cannot be nested, and this feature is only implemented by +// React DOM, we don't technically need this to be a stack. It could be a single +// module variable instead. + +var hostTransitionProviderCursor = createCursor(null); // TODO: This should initialize to NotPendingTransition, a constant +// imported from the fiber config. However, because of a cycle in the module +// graph, that value isn't defined during this module's initialization. I can't +// think of a way to work around this without moving that value out of the +// fiber config. For now, the "no provider" case is handled when reading, +// inside useHostTransitionStatus. + +var HostTransitionContext = { + $$typeof: REACT_CONTEXT_TYPE, + Provider: null, + Consumer: null, + _currentValue: null, + _currentValue2: null, + _threadCount: 0 +}; + +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 c; +} - var node = fiber; +function getRootHostContainer() { + var rootInstance = requiredContext(rootInstanceStackCursor.current); + return rootInstance; +} - do { - switch (node.tag) { - case HostRoot: - return node.stateNode.context; +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 ClassComponent: { - var Component = node.type; + 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 (isContextProvider(Component)) { - return node.stateNode.__reactInternalMemoizedMergedChildContext; - } + push(contextStackCursor, null, fiber); + var nextRootContext = getRootHostContext(); // Now that we know this function doesn't throw, replace it. - break; - } - } // $FlowFixMe[incompatible-type] we bail out when we get a null + pop(contextStackCursor, fiber); + push(contextStackCursor, nextRootContext, fiber); +} - node = node.return; - } while (node !== null); +function popHostContainer(fiber) { + pop(contextStackCursor, fiber); + pop(contextFiberStackCursor, fiber); + pop(rootInstanceStackCursor, fiber); +} - throw new Error( - "Found unexpected detached subtree parent. " + - "This error is likely caused by a bug in React. Please file an issue." - ); - } - } +function getHostContext() { + var context = requiredContext(contextStackCursor.current); + return context; +} - // 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 pushHostContext(fiber) { + { + var stateHook = fiber.memoizedState; - /** - * 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 - ); + if (stateHook !== null) { + // Only provide context if this fiber has been upgraded by a host + // transition. We use the same optimization for regular host context below. + push(hostTransitionProviderCursor, fiber, fiber); } + } - var objectIs = typeof Object.is === "function" ? Object.is : is; // $FlowFixMe[method-unbinding] + var context = requiredContext(contextStackCursor.current); + var nextContext = getChildHostContext(); // Don't push this Fiber's context unless it's unique. - function describeBuiltInComponentFrame(name) { - { - return describeComponentFrame(name); - } - } - function describeDebugInfoFrame(name, env) { - return describeBuiltInComponentFrame( - name + (env ? " (" + env + ")" : "") - ); - } + if (context !== nextContext) { + // 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); + } +} - { - var PossiblyWeakMap$1 = typeof WeakMap === "function" ? WeakMap : Map; - new PossiblyWeakMap$1(); - } +function popHostContext(fiber) { + if (contextFiberStackCursor.current === fiber) { + // Do not pop unless this Fiber provided the current context. + // pushHostContext() only pushes Fibers that provide unique contexts. + pop(contextStackCursor, fiber); + pop(contextFiberStackCursor, fiber); + } - function describeComponentFrame(name) { - return "\n in " + (name || "Unknown"); - } + { + if (hostTransitionProviderCursor.current === fiber) { + // Do not pop unless this Fiber provided the current context. This is mostly + // a performance optimization, but conveniently it also prevents a potential + // data race where a host provider is upgraded (i.e. memoizedState becomes + // non-null) during a concurrent event. This is a bit of a flaw in the way + // we upgrade host components, but because we're accounting for it here, it + // should be fine. + pop(hostTransitionProviderCursor, fiber); // When popping the transition provider, we reset the context value back + // to `null`. We can do this because you're not allowd to nest forms. If + // we allowed for multiple nested host transition providers, then we'd + // need to reset this to the parent provider's status. - function describeClassComponentFrame(ctor) { - { - return describeFunctionComponentFrame(ctor); - } - } - function describeFunctionComponentFrame(fn) { { - if (!fn) { - return ""; - } - - var name = fn.displayName || fn.name || null; - return describeComponentFrame(name); + HostTransitionContext._currentValue2 = null; } } + } +} - function describeFiber(fiber) { - switch (fiber.tag) { - case HostHoistable: - case HostSingleton: - case HostComponent: - return describeBuiltInComponentFrame(fiber.type); - - case LazyComponent: - return describeBuiltInComponentFrame("Lazy"); - - case SuspenseComponent: - return describeBuiltInComponentFrame("Suspense"); +var maxRowLength = 120; +var idealDepth = 15; - case SuspenseListComponent: - return describeBuiltInComponentFrame("SuspenseList"); +function findNotableNode(node, indent) { + if (node.serverProps === undefined && node.serverTail.length === 0 && node.children.length === 1 && node.distanceFromLeaf > 3 && node.distanceFromLeaf > idealDepth - indent) { + // This is not an interesting node for contextual purposes so we can skip it. + var child = node.children[0]; + return findNotableNode(child, indent); + } - case FunctionComponent: - case SimpleMemoComponent: - return describeFunctionComponentFrame(fiber.type); + return node; +} - case ForwardRef: - return describeFunctionComponentFrame(fiber.type.render); +function indentation(indent) { + return ' ' + ' '.repeat(indent); +} - case ClassComponent: - return describeClassComponentFrame(fiber.type); +function added(indent) { + return '+ ' + ' '.repeat(indent); +} - default: - return ""; - } - } +function removed(indent) { + return '- ' + ' '.repeat(indent); +} - function getStackByFiberInDevAndProd(workInProgress) { - try { - var info = ""; - var node = workInProgress; +function describeFiberType(fiber) { + switch (fiber.tag) { + case HostHoistable: + case HostSingleton: + case HostComponent: + return fiber.type; - do { - info += describeFiber(node); + case LazyComponent: + return 'Lazy'; - if (true) { - // Add any Server Component stack frames in reverse order. - var debugInfo = node._debugInfo; + case SuspenseComponent: + return 'Suspense'; - if (debugInfo) { - for (var i = debugInfo.length - 1; i >= 0; i--) { - var entry = debugInfo[i]; + case SuspenseListComponent: + return 'SuspenseList'; - if (typeof entry.name === "string") { - info += describeDebugInfoFrame(entry.name, entry.env); - } - } - } - } // $FlowFixMe[incompatible-type] we bail out when we get a null + case FunctionComponent: + case SimpleMemoComponent: + var fn = fiber.type; + return fn.displayName || fn.name || null; - node = node.return; - } while (node); + case ForwardRef: + var render = fiber.type.render; + return render.displayName || render.name || null; - return info; - } catch (x) { - return "\nError generating stack: " + x.message + "\n" + x.stack; - } - } + case ClassComponent: + var ctr = fiber.type; + return ctr.displayName || ctr.name || null; - var CapturedStacks = new WeakMap(); - function createCapturedValueAtFiber(value, source) { - // If the value is an error, call this function immediately after it is thrown - // so the stack is accurate. - var stack; + default: + // Skip + return null; + } +} - if (typeof value === "object" && value !== null) { - var capturedStack = CapturedStacks.get(value); +var needsEscaping = /["'&<>\n\t]/; - if (typeof capturedStack === "string") { - stack = capturedStack; - } else { - stack = getStackByFiberInDevAndProd(source); - CapturedStacks.set(value, stack); - } - } else { - stack = getStackByFiberInDevAndProd(source); - } +function describeTextNode(content, maxLength) { + if (needsEscaping.test(content)) { + var encoded = JSON.stringify(content); - return { - value: value, - source: source, - stack: stack - }; - } - function createCapturedValueFromError(value, stack) { - if (typeof stack === "string") { - CapturedStacks.set(value, stack); + if (encoded.length > maxLength - 2) { + if (maxLength < 8) { + return '{"..."}'; } - return { - value: value, - source: null, - stack: stack - }; + return '{' + encoded.slice(0, maxLength - 7) + '..."}'; } - var contextStackCursor = createCursor(null); - var contextFiberStackCursor = createCursor(null); - var rootInstanceStackCursor = createCursor(null); // Represents the nearest host transition provider (in React DOM, a ) - // NOTE: Since forms cannot be nested, and this feature is only implemented by - // React DOM, we don't technically need this to be a stack. It could be a single - // module variable instead. - - var hostTransitionProviderCursor = createCursor(null); // TODO: This should initialize to NotPendingTransition, a constant - // imported from the fiber config. However, because of a cycle in the module - // graph, that value isn't defined during this module's initialization. I can't - // think of a way to work around this without moving that value out of the - // fiber config. For now, the "no provider" case is handled when reading, - // inside useHostTransitionStatus. - - var HostTransitionContext = { - $$typeof: REACT_CONTEXT_TYPE, - Provider: null, - Consumer: null, - _currentValue: null, - _currentValue2: null, - _threadCount: 0 - }; - - 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 '{' + encoded + '}'; + } else { + if (content.length > maxLength) { + if (maxLength < 5) { + return '{"..."}'; } - return c; - } - - function getRootHostContainer() { - var rootInstance = requiredContext(rootInstanceStackCursor.current); - return rootInstance; + return content.slice(0, maxLength - 3) + '...'; } - 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. + return content; + } +} - 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. +function describeTextDiff(clientText, serverProps, indent) { + var maxLength = maxRowLength - indent * 2; - push(contextStackCursor, null, fiber); - var nextRootContext = getRootHostContext(); // Now that we know this function doesn't throw, replace it. + if (serverProps === null) { + return added(indent) + describeTextNode(clientText, maxLength) + '\n'; + } else if (typeof serverProps === 'string') { + var serverText = serverProps; + var firstDiff = 0; - pop(contextStackCursor, fiber); - push(contextStackCursor, nextRootContext, fiber); + for (; firstDiff < serverText.length && firstDiff < clientText.length; firstDiff++) { + if (serverText.charCodeAt(firstDiff) !== clientText.charCodeAt(firstDiff)) { + break; + } } - function popHostContainer(fiber) { - pop(contextStackCursor, fiber); - pop(contextFiberStackCursor, fiber); - pop(rootInstanceStackCursor, fiber); + if (firstDiff > maxLength - 8 && firstDiff > 10) { + // The first difference between the two strings would be cut off, so cut off in + // the beginning instead. + clientText = '...' + clientText.slice(firstDiff - 8); + serverText = '...' + serverText.slice(firstDiff - 8); } - function getHostContext() { - var context = requiredContext(contextStackCursor.current); - return context; - } + return added(indent) + describeTextNode(clientText, maxLength) + '\n' + removed(indent) + describeTextNode(serverText, maxLength) + '\n'; + } else { + return indentation(indent) + describeTextNode(clientText, maxLength) + '\n'; + } +} - function pushHostContext(fiber) { - { - var stateHook = fiber.memoizedState; +function objectName(object) { + // $FlowFixMe[method-unbinding] + var name = Object.prototype.toString.call(object); + return name.replace(/^\[object (.*)\]$/, function (m, p0) { + return p0; + }); +} - if (stateHook !== null) { - // Only provide context if this fiber has been upgraded by a host - // transition. We use the same optimization for regular host context below. - push(hostTransitionProviderCursor, fiber, fiber); - } - } +function describeValue(value, maxLength) { + switch (typeof value) { + case 'string': + { + var encoded = JSON.stringify(value); - var context = requiredContext(contextStackCursor.current); - var nextContext = getChildHostContext(); // Don't push this Fiber's context unless it's unique. + if (encoded.length > maxLength) { + if (maxLength < 5) { + return '"..."'; + } - if (context !== nextContext) { - // 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); - } - } + return encoded.slice(0, maxLength - 4) + '..."'; + } - function popHostContext(fiber) { - if (contextFiberStackCursor.current === fiber) { - // Do not pop unless this Fiber provided the current context. - // pushHostContext() only pushes Fibers that provide unique contexts. - pop(contextStackCursor, fiber); - pop(contextFiberStackCursor, fiber); + return encoded; } + case 'object': { - if (hostTransitionProviderCursor.current === fiber) { - // Do not pop unless this Fiber provided the current context. This is mostly - // a performance optimization, but conveniently it also prevents a potential - // data race where a host provider is upgraded (i.e. memoizedState becomes - // non-null) during a concurrent event. This is a bit of a flaw in the way - // we upgrade host components, but because we're accounting for it here, it - // should be fine. - pop(hostTransitionProviderCursor, fiber); // When popping the transition provider, we reset the context value back - // to `null`. We can do this because you're not allowd to nest forms. If - // we allowed for multiple nested host transition providers, then we'd - // need to reset this to the parent provider's status. + if (value === null) { + return 'null'; + } - { - HostTransitionContext._currentValue2 = null; - } + if (isArray(value)) { + return '[...]'; } - } - } - var maxRowLength = 120; - var idealDepth = 15; + if (value.$$typeof === REACT_ELEMENT_TYPE) { + var type = getComponentNameFromType(value.type); + return type ? '<' + type + '>' : '<...>'; + } - function findNotableNode(node, indent) { - if ( - node.serverProps === undefined && - node.serverTail.length === 0 && - node.children.length === 1 && - node.distanceFromLeaf > 3 && - node.distanceFromLeaf > idealDepth - indent - ) { - // This is not an interesting node for contextual purposes so we can skip it. - var child = node.children[0]; - return findNotableNode(child, indent); - } + var name = objectName(value); - return node; - } + if (name === 'Object') { + var properties = ''; + maxLength -= 2; - function indentation(indent) { - return " " + " ".repeat(indent); - } + for (var propName in value) { + if (!value.hasOwnProperty(propName)) { + continue; + } - function added(indent) { - return "+ " + " ".repeat(indent); - } + var jsonPropName = JSON.stringify(propName); - function removed(indent) { - return "- " + " ".repeat(indent); - } + if (jsonPropName !== '"' + propName + '"') { + propName = jsonPropName; + } - function describeFiberType(fiber) { - switch (fiber.tag) { - case HostHoistable: - case HostSingleton: - case HostComponent: - return fiber.type; + maxLength -= propName.length - 2; + var propValue = describeValue(value[propName], maxLength < 15 ? maxLength : 15); + maxLength -= propValue.length; - case LazyComponent: - return "Lazy"; + if (maxLength < 0) { + properties += properties === '' ? '...' : ', ...'; + break; + } - case SuspenseComponent: - return "Suspense"; + properties += (properties === '' ? '' : ',') + propName + ':' + propValue; + } - case SuspenseListComponent: - return "SuspenseList"; + return '{' + properties + '}'; + } - case FunctionComponent: - case SimpleMemoComponent: - var fn = fiber.type; - return fn.displayName || fn.name || null; + return name; + } - case ForwardRef: - var render = fiber.type.render; - return render.displayName || render.name || null; + case 'function': + { + var _name = value.displayName || value.name; - case ClassComponent: - var ctr = fiber.type; - return ctr.displayName || ctr.name || null; + return _name ? 'function ' + _name : 'function'; + } - default: - // Skip - return null; + default: + // eslint-disable-next-line react-internal/safe-string-coercion + return String(value); + } +} + +function describePropValue(value, maxLength) { + if (typeof value === 'string' && !needsEscaping.test(value)) { + if (value.length > maxLength - 2) { + if (maxLength < 5) { + return '"..."'; } + + return '"' + value.slice(0, maxLength - 5) + '..."'; } - var needsEscaping = /["'&<>\n\t]/; + return '"' + value + '"'; + } - function describeTextNode(content, maxLength) { - if (needsEscaping.test(content)) { - var encoded = JSON.stringify(content); + return '{' + describeValue(value, maxLength - 2) + '}'; +} - if (encoded.length > maxLength - 2) { - if (maxLength < 8) { - return '{"..."}'; - } +function describeCollapsedElement(type, props, indent) { + // This function tries to fit the props into a single line for non-essential elements. + // We also ignore children because we're not going deeper. + var maxLength = maxRowLength - indent * 2 - type.length - 2; + var content = ''; - return "{" + encoded.slice(0, maxLength - 7) + '..."}'; - } + for (var propName in props) { + if (!props.hasOwnProperty(propName)) { + continue; + } - return "{" + encoded + "}"; - } else { - if (content.length > maxLength) { - if (maxLength < 5) { - return '{"..."}'; - } + if (propName === 'children') { + // Ignored. + continue; + } - return content.slice(0, maxLength - 3) + "..."; - } + var propValue = describePropValue(props[propName], 15); + maxLength -= propName.length + propValue.length + 2; - return content; - } + if (maxLength < 0) { + content += ' ...'; + break; } - function describeTextDiff(clientText, serverProps, indent) { - var maxLength = maxRowLength - indent * 2; + content += ' ' + propName + '=' + propValue; + } - if (serverProps === null) { - return added(indent) + describeTextNode(clientText, maxLength) + "\n"; - } else if (typeof serverProps === "string") { - var serverText = serverProps; - var firstDiff = 0; + return indentation(indent) + '<' + type + content + '>\n'; +} - for ( - ; - firstDiff < serverText.length && firstDiff < clientText.length; - firstDiff++ - ) { - if ( - serverText.charCodeAt(firstDiff) !== - clientText.charCodeAt(firstDiff) - ) { - break; - } - } +function describeExpandedElement(type, props, rowPrefix) { + // This function tries to fit the props into a single line for non-essential elements. + // We also ignore children because we're not going deeper. + var remainingRowLength = maxRowLength - rowPrefix.length - type.length; // We add the properties to a set so we can choose later whether we'll put it on one + // line or multiple lines. - if (firstDiff > maxLength - 8 && firstDiff > 10) { - // The first difference between the two strings would be cut off, so cut off in - // the beginning instead. - clientText = "..." + clientText.slice(firstDiff - 8); - serverText = "..." + serverText.slice(firstDiff - 8); - } + var properties = []; - return ( - added(indent) + - describeTextNode(clientText, maxLength) + - "\n" + - removed(indent) + - describeTextNode(serverText, maxLength) + - "\n" - ); - } else { - return ( - indentation(indent) + describeTextNode(clientText, maxLength) + "\n" - ); - } + for (var propName in props) { + if (!props.hasOwnProperty(propName)) { + continue; } - function objectName(object) { - // $FlowFixMe[method-unbinding] - var name = Object.prototype.toString.call(object); - return name.replace(/^\[object (.*)\]$/, function (m, p0) { - return p0; - }); + if (propName === 'children') { + // Ignored. + continue; } - function describeValue(value, maxLength) { - switch (typeof value) { - case "string": { - var encoded = JSON.stringify(value); + var maxLength = maxRowLength - rowPrefix.length - propName.length - 1; + var propValue = describePropValue(props[propName], maxLength); + remainingRowLength -= propName.length + propValue.length + 2; + properties.push(propName + '=' + propValue); + } - if (encoded.length > maxLength) { - if (maxLength < 5) { - return '"..."'; - } + if (properties.length === 0) { + return rowPrefix + '<' + type + '>\n'; + } else if (remainingRowLength > 0) { + // We can fit all on one row. + return rowPrefix + '<' + type + ' ' + properties.join(' ') + '>\n'; + } else { + // Split into one row per property: + return rowPrefix + '<' + type + '\n' + rowPrefix + ' ' + properties.join('\n' + rowPrefix + ' ') + '\n' + rowPrefix + '>\n'; + } +} - return encoded.slice(0, maxLength - 4) + '..."'; - } +function describePropertiesDiff(clientObject, serverObject, indent) { + var properties = ''; + var remainingServerProperties = assign({}, serverObject); - return encoded; - } + for (var propName in clientObject) { + if (!clientObject.hasOwnProperty(propName)) { + continue; + } - case "object": { - if (value === null) { - return "null"; - } + delete remainingServerProperties[propName]; + var maxLength = maxRowLength - indent * 2 - propName.length - 2; + var clientValue = clientObject[propName]; + var clientPropValue = describeValue(clientValue, maxLength); - if (isArray(value)) { - return "[...]"; - } + if (serverObject.hasOwnProperty(propName)) { + var serverValue = serverObject[propName]; + var serverPropValue = describeValue(serverValue, maxLength); + properties += added(indent) + propName + ': ' + clientPropValue + '\n'; + properties += removed(indent) + propName + ': ' + serverPropValue + '\n'; + } else { + properties += added(indent) + propName + ': ' + clientPropValue + '\n'; + } + } - if (value.$$typeof === REACT_ELEMENT_TYPE) { - var type = getComponentNameFromType(value.type); - return type ? "<" + type + ">" : "<...>"; - } + for (var _propName in remainingServerProperties) { + if (!remainingServerProperties.hasOwnProperty(_propName)) { + continue; + } - var name = objectName(value); + var _maxLength = maxRowLength - indent * 2 - _propName.length - 2; - if (name === "Object") { - var properties = ""; - maxLength -= 2; + var _serverValue = remainingServerProperties[_propName]; - for (var propName in value) { - if (!value.hasOwnProperty(propName)) { - continue; - } + var _serverPropValue = describeValue(_serverValue, _maxLength); - var jsonPropName = JSON.stringify(propName); + properties += removed(indent) + _propName + ': ' + _serverPropValue + '\n'; + } - if (jsonPropName !== '"' + propName + '"') { - propName = jsonPropName; - } + return properties; +} - maxLength -= propName.length - 2; - var propValue = describeValue( - value[propName], - maxLength < 15 ? maxLength : 15 - ); - maxLength -= propValue.length; +function describeElementDiff(type, clientProps, serverProps, indent) { + var content = ''; // Maps any previously unmatched lower case server prop name to its full prop name - if (maxLength < 0) { - properties += properties === "" ? "..." : ", ..."; - break; - } + var serverPropNames = new Map(); - properties += - (properties === "" ? "" : ",") + propName + ":" + propValue; - } + for (var propName in serverProps) { + if (!serverProps.hasOwnProperty(propName)) { + continue; + } - return "{" + properties + "}"; - } + serverPropNames.set(propName.toLowerCase(), propName); + } - return name; - } + if (serverPropNames.size === 1 && serverPropNames.has('children')) { + content += describeExpandedElement(type, clientProps, indentation(indent)); + } else { + for (var _propName2 in clientProps) { + if (!clientProps.hasOwnProperty(_propName2)) { + continue; + } - case "function": { - var _name = value.displayName || value.name; + if (_propName2 === 'children') { + // Handled below. + continue; + } - return _name ? "function " + _name : "function"; - } + var maxLength = maxRowLength - (indent + 1) * 2 - _propName2.length - 1; + var serverPropName = serverPropNames.get(_propName2.toLowerCase()); - default: - // eslint-disable-next-line react-internal/safe-string-coercion - return String(value); - } - } + if (serverPropName !== undefined) { + serverPropNames.delete(_propName2.toLowerCase()); // There's a diff here. - function describePropValue(value, maxLength) { - if (typeof value === "string" && !needsEscaping.test(value)) { - if (value.length > maxLength - 2) { - if (maxLength < 5) { - return '"..."'; - } + var clientValue = clientProps[_propName2]; + var serverValue = serverProps[serverPropName]; + var clientPropValue = describePropValue(clientValue, maxLength); + var serverPropValue = describePropValue(serverValue, maxLength); - return '"' + value.slice(0, maxLength - 5) + '..."'; + if (typeof clientValue === 'object' && clientValue !== null && typeof serverValue === 'object' && serverValue !== null && objectName(clientValue) === 'Object' && objectName(serverValue) === 'Object' && ( // Only do the diff if the object has a lot of keys or was shortened. + Object.keys(clientValue).length > 2 || Object.keys(serverValue).length > 2 || clientPropValue.indexOf('...') > -1 || serverPropValue.indexOf('...') > -1)) { + // We're comparing two plain objects. We can diff the nested objects instead. + content += indentation(indent + 1) + _propName2 + '={{\n' + describePropertiesDiff(clientValue, serverValue, indent + 2) + indentation(indent + 1) + '}}\n'; + } else { + content += added(indent + 1) + _propName2 + '=' + clientPropValue + '\n'; + content += removed(indent + 1) + _propName2 + '=' + serverPropValue + '\n'; } + } else { + // Considered equal. + content += indentation(indent + 1) + _propName2 + '=' + describePropValue(clientProps[_propName2], maxLength) + '\n'; + } + } - return '"' + value + '"'; + serverPropNames.forEach(function (propName) { + if (propName === 'children') { + // Handled below. + return; } - return "{" + describeValue(value, maxLength - 2) + "}"; + var maxLength = maxRowLength - (indent + 1) * 2 - propName.length - 1; + content += removed(indent + 1) + propName + '=' + describePropValue(serverProps[propName], maxLength) + '\n'; + }); + + if (content === '') { + // No properties + content = indentation(indent) + '<' + type + '>\n'; + } else { + // Had properties + content = indentation(indent) + '<' + type + '\n' + content + indentation(indent) + '>\n'; } + } - function describeCollapsedElement(type, props, indent) { - // This function tries to fit the props into a single line for non-essential elements. - // We also ignore children because we're not going deeper. - var maxLength = maxRowLength - indent * 2 - type.length - 2; - var content = ""; + var serverChildren = serverProps.children; + var clientChildren = clientProps.children; - for (var propName in props) { - if (!props.hasOwnProperty(propName)) { - continue; - } + if (typeof serverChildren === 'string' || typeof serverChildren === 'number' || typeof serverChildren === 'bigint') { + // There's a diff of the children. + // $FlowFixMe[unsafe-addition] + var serverText = '' + serverChildren; + var clientText = ''; - if (propName === "children") { - // Ignored. - continue; - } + if (typeof clientChildren === 'string' || typeof clientChildren === 'number' || typeof clientChildren === 'bigint') { + // $FlowFixMe[unsafe-addition] + clientText = '' + clientChildren; + } - var propValue = describePropValue(props[propName], 15); - maxLength -= propName.length + propValue.length + 2; + content += describeTextDiff(clientText, serverText, indent + 1); + } else if (typeof clientChildren === 'string' || typeof clientChildren === 'number' || typeof clientChildren === 'bigint') { + // The client has children but it's not considered a difference from the server. + // $FlowFixMe[unsafe-addition] + content += describeTextDiff('' + clientChildren, undefined, indent + 1); + } - if (maxLength < 0) { - content += " ..."; - break; - } + return content; +} - content += " " + propName + "=" + propValue; - } +function describeSiblingFiber(fiber, indent) { + var type = describeFiberType(fiber); - return indentation(indent) + "<" + type + content + ">\n"; + if (type === null) { + // Skip this type of fiber. We currently treat this as a fragment + // so it's just part of the parent's children. + var flatContent = ''; + var childFiber = fiber.child; + + while (childFiber) { + flatContent += describeSiblingFiber(childFiber, indent); + childFiber = childFiber.sibling; } - function describeExpandedElement(type, props, rowPrefix) { - // This function tries to fit the props into a single line for non-essential elements. - // We also ignore children because we're not going deeper. - var remainingRowLength = maxRowLength - rowPrefix.length - type.length; // We add the properties to a set so we can choose later whether we'll put it on one - // line or multiple lines. + return flatContent; + } - var properties = []; + return indentation(indent) + '<' + type + '>' + '\n'; +} - for (var propName in props) { - if (!props.hasOwnProperty(propName)) { - continue; - } +function describeNode(node, indent) { + var skipToNode = findNotableNode(node, indent); - if (propName === "children") { - // Ignored. - continue; - } + if (skipToNode !== node && (node.children.length !== 1 || node.children[0] !== skipToNode)) { + return indentation(indent) + '...\n' + describeNode(skipToNode, indent + 1); + } // Prefix with any server components for context - var maxLength = maxRowLength - rowPrefix.length - propName.length - 1; - var propValue = describePropValue(props[propName], maxLength); - remainingRowLength -= propName.length + propValue.length + 2; - properties.push(propName + "=" + propValue); - } - if (properties.length === 0) { - return rowPrefix + "<" + type + ">\n"; - } else if (remainingRowLength > 0) { - // We can fit all on one row. - return rowPrefix + "<" + type + " " + properties.join(" ") + ">\n"; - } else { - // Split into one row per property: - return ( - rowPrefix + - "<" + - type + - "\n" + - rowPrefix + - " " + - properties.join("\n" + rowPrefix + " ") + - "\n" + - rowPrefix + - ">\n" - ); - } - } - - function describePropertiesDiff(clientObject, serverObject, indent) { - var properties = ""; - var remainingServerProperties = assign({}, serverObject); - - for (var propName in clientObject) { - if (!clientObject.hasOwnProperty(propName)) { - continue; - } + var parentContent = ''; + var debugInfo = node.fiber._debugInfo; - delete remainingServerProperties[propName]; - var maxLength = maxRowLength - indent * 2 - propName.length - 2; - var clientValue = clientObject[propName]; - var clientPropValue = describeValue(clientValue, maxLength); - - if (serverObject.hasOwnProperty(propName)) { - var serverValue = serverObject[propName]; - var serverPropValue = describeValue(serverValue, maxLength); - properties += - added(indent) + propName + ": " + clientPropValue + "\n"; - properties += - removed(indent) + propName + ": " + serverPropValue + "\n"; - } else { - properties += - added(indent) + propName + ": " + clientPropValue + "\n"; - } + if (debugInfo) { + for (var i = 0; i < debugInfo.length; i++) { + var serverComponentName = debugInfo[i].name; + + if (typeof serverComponentName === 'string') { + parentContent += indentation(indent) + '<' + serverComponentName + '>' + '\n'; + indent++; } + } + } // Self - for (var _propName in remainingServerProperties) { - if (!remainingServerProperties.hasOwnProperty(_propName)) { - continue; - } - var _maxLength = maxRowLength - indent * 2 - _propName.length - 2; + var selfContent = ''; // We use the pending props since we might be generating a diff before the complete phase + // when something throws. - var _serverValue = remainingServerProperties[_propName]; + var clientProps = node.fiber.pendingProps; - var _serverPropValue = describeValue(_serverValue, _maxLength); + if (node.fiber.tag === HostText) { + // Text Node + selfContent = describeTextDiff(clientProps, node.serverProps, indent); + } else { + var type = describeFiberType(node.fiber); - properties += - removed(indent) + _propName + ": " + _serverPropValue + "\n"; + if (type !== null) { + // Element Node + if (node.serverProps === undefined) { + // Just a reference node for context. + selfContent = describeCollapsedElement(type, clientProps, indent); + indent++; + } else if (node.serverProps === null) { + selfContent = describeExpandedElement(type, clientProps, added(indent)); // If this was an insertion we won't step down further. Any tail + // are considered siblings so we don't indent. + // TODO: Model this a little better. + } else if (typeof node.serverProps === 'string') { + { + error('Should not have matched a non HostText fiber to a Text node. This is a bug in React.'); + } + } else { + selfContent = describeElementDiff(type, clientProps, node.serverProps, indent); + indent++; } - - return properties; } + } // Compute children - function describeElementDiff(type, clientProps, serverProps, indent) { - var content = ""; // Maps any previously unmatched lower case server prop name to its full prop name - var serverPropNames = new Map(); + var childContent = ''; + var childFiber = node.fiber.child; + var diffIdx = 0; - for (var propName in serverProps) { - if (!serverProps.hasOwnProperty(propName)) { - continue; - } + while (childFiber && diffIdx < node.children.length) { + var childNode = node.children[diffIdx]; - serverPropNames.set(propName.toLowerCase(), propName); - } + if (childNode.fiber === childFiber) { + // This was a match in the diff. + childContent += describeNode(childNode, indent); + diffIdx++; + } else { + // This is an unrelated previous sibling. + childContent += describeSiblingFiber(childFiber, indent); + } - if (serverPropNames.size === 1 && serverPropNames.has("children")) { - content += describeExpandedElement( - type, - clientProps, - indentation(indent) - ); - } else { - for (var _propName2 in clientProps) { - if (!clientProps.hasOwnProperty(_propName2)) { - continue; - } + childFiber = childFiber.sibling; + } - if (_propName2 === "children") { - // Handled below. - continue; - } + if (childFiber && node.children.length > 0) { + // If we had any further siblings after the last mismatch, we can't be sure if it's + // actually a valid match since it might not have found a match. So we exclude next + // siblings to avoid confusion. + childContent += indentation(indent) + '...' + '\n'; + } // Deleted tail nodes - var maxLength = - maxRowLength - (indent + 1) * 2 - _propName2.length - 1; - var serverPropName = serverPropNames.get(_propName2.toLowerCase()); - - if (serverPropName !== undefined) { - serverPropNames.delete(_propName2.toLowerCase()); // There's a diff here. - - var clientValue = clientProps[_propName2]; - var serverValue = serverProps[serverPropName]; - var clientPropValue = describePropValue(clientValue, maxLength); - var serverPropValue = describePropValue(serverValue, maxLength); - - if ( - typeof clientValue === "object" && - clientValue !== null && - typeof serverValue === "object" && - serverValue !== null && - objectName(clientValue) === "Object" && - objectName(serverValue) === "Object" && // Only do the diff if the object has a lot of keys or was shortened. - (Object.keys(clientValue).length > 2 || - Object.keys(serverValue).length > 2 || - clientPropValue.indexOf("...") > -1 || - serverPropValue.indexOf("...") > -1) - ) { - // We're comparing two plain objects. We can diff the nested objects instead. - content += - indentation(indent + 1) + - _propName2 + - "={{\n" + - describePropertiesDiff(clientValue, serverValue, indent + 2) + - indentation(indent + 1) + - "}}\n"; - } else { - content += - added(indent + 1) + _propName2 + "=" + clientPropValue + "\n"; - content += - removed(indent + 1) + _propName2 + "=" + serverPropValue + "\n"; - } - } else { - // Considered equal. - content += - indentation(indent + 1) + - _propName2 + - "=" + - describePropValue(clientProps[_propName2], maxLength) + - "\n"; - } - } - serverPropNames.forEach(function (propName) { - if (propName === "children") { - // Handled below. - return; - } + var serverTail = node.serverTail; - var maxLength = maxRowLength - (indent + 1) * 2 - propName.length - 1; - content += - removed(indent + 1) + - propName + - "=" + - describePropValue(serverProps[propName], maxLength) + - "\n"; - }); + for (var _i = 0; _i < serverTail.length; _i++) { + var tailNode = serverTail[_i]; - if (content === "") { - // No properties - content = indentation(indent) + "<" + type + ">\n"; - } else { - // Had properties - content = - indentation(indent) + - "<" + - type + - "\n" + - content + - indentation(indent) + - ">\n"; - } - } + if (typeof tailNode === 'string') { + // Removed text node + childContent += removed(indent) + describeTextNode(tailNode, maxRowLength - indent * 2) + '\n'; + } else { + // Removed element + childContent += describeExpandedElement(tailNode.type, tailNode.props, removed(indent)); + } + } - var serverChildren = serverProps.children; - var clientChildren = clientProps.children; - - if ( - typeof serverChildren === "string" || - typeof serverChildren === "number" || - typeof serverChildren === "bigint" - ) { - // There's a diff of the children. - // $FlowFixMe[unsafe-addition] - var serverText = "" + serverChildren; - var clientText = ""; - - if ( - typeof clientChildren === "string" || - typeof clientChildren === "number" || - typeof clientChildren === "bigint" - ) { - // $FlowFixMe[unsafe-addition] - clientText = "" + clientChildren; - } + return parentContent + selfContent + childContent; +} - content += describeTextDiff(clientText, serverText, indent + 1); - } else if ( - typeof clientChildren === "string" || - typeof clientChildren === "number" || - typeof clientChildren === "bigint" - ) { - // The client has children but it's not considered a difference from the server. - // $FlowFixMe[unsafe-addition] - content += describeTextDiff("" + clientChildren, undefined, indent + 1); - } +function describeDiff(rootNode) { + try { + return '\n\n' + describeNode(rootNode, 0); + } catch (x) { + return ''; + } +} - return content; - } +var isHydrating = false; // This flag allows for warning supression when we expect there to be mismatches - function describeSiblingFiber(fiber, indent) { - var type = describeFiberType(fiber); +var hydrationDiffRootDEV = null; // Hydration errors that were thrown inside this boundary - if (type === null) { - // Skip this type of fiber. We currently treat this as a fragment - // so it's just part of the parent's children. - var flatContent = ""; - var childFiber = fiber.child; +var hydrationErrors = null; - while (childFiber) { - flatContent += describeSiblingFiber(childFiber, indent); - childFiber = childFiber.sibling; - } +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.'); + } +} - return flatContent; - } +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.'); + } +} - return indentation(indent) + "<" + type + ">" + "\n"; - } +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.'); + } +} - function describeNode(node, indent) { - var skipToNode = findNotableNode(node, indent); +function popHydrationState(fiber) { + { + return false; + } +} - if ( - skipToNode !== node && - (node.children.length !== 1 || node.children[0] !== skipToNode) - ) { - return ( - indentation(indent) + "...\n" + describeNode(skipToNode, indent + 1) - ); - } // Prefix with any server components for context +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; + } +} - var parentContent = ""; - var debugInfo = node.fiber._debugInfo; +function getIsHydrating() { + return isHydrating; +} - if (debugInfo) { - for (var i = 0; i < debugInfo.length; i++) { - var serverComponentName = debugInfo[i].name; +function queueHydrationError(error) { + if (hydrationErrors === null) { + hydrationErrors = [error]; + } else { + hydrationErrors.push(error); + } +} +function emitPendingHydrationWarnings() { + { + // If we haven't yet thrown any hydration errors by the time we reach the end we've successfully + // hydrated, however, we might still have DEV-only mismatches that we log now. + var diffRoot = hydrationDiffRootDEV; - if (typeof serverComponentName === "string") { - parentContent += - indentation(indent) + "<" + serverComponentName + ">" + "\n"; - indent++; - } - } - } // Self + if (diffRoot !== null) { + hydrationDiffRootDEV = null; + var diff = describeDiff(diffRoot); - var selfContent = ""; // We use the pending props since we might be generating a diff before the complete phase - // when something throws. + error("A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. " + 'This can happen if a SSR-ed Client Component used:\n' + '\n' + "- A server/client branch `if (typeof window !== 'undefined')`.\n" + "- Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.\n" + "- Date formatting in a user's locale which doesn't match the server.\n" + '- External changing data without sending a snapshot of it along with the HTML.\n' + '- Invalid HTML tag nesting.\n' + '\n' + 'It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.\n' + '\n' + '%s%s', 'https://react.dev/link/hydration-mismatch', diff); + } + } +} - var clientProps = node.fiber.pendingProps; +// 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 concurrentQueues = []; +var concurrentQueuesIndex = 0; +var concurrentlyUpdatedLanes = NoLanes; +function finishQueueingConcurrentUpdates() { + var endIndex = concurrentQueuesIndex; + concurrentQueuesIndex = 0; + concurrentlyUpdatedLanes = NoLanes; + var i = 0; + + 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 (node.fiber.tag === HostText) { - // Text Node - selfContent = describeTextDiff(clientProps, node.serverProps, indent); - } else { - var type = describeFiberType(node.fiber); - - if (type !== null) { - // Element Node - if (node.serverProps === undefined) { - // Just a reference node for context. - selfContent = describeCollapsedElement(type, clientProps, indent); - indent++; - } else if (node.serverProps === null) { - selfContent = describeExpandedElement( - type, - clientProps, - added(indent) - ); // If this was an insertion we won't step down further. Any tail - // are considered siblings so we don't indent. - // TODO: Model this a little better. - } else if (typeof node.serverProps === "string") { - { - error( - "Should not have matched a non HostText fiber to a Text node. This is a bug in React." - ); - } - } else { - selfContent = describeElementDiff( - type, - clientProps, - node.serverProps, - indent - ); - indent++; - } - } - } // Compute children + if (pending === null) { + // This is the first update. Create a circular list. + update.next = update; + } else { + update.next = pending.next; + pending.next = update; + } + + queue.pending = update; + } - var childContent = ""; - var childFiber = node.fiber.child; - var diffIdx = 0; + if (lane !== NoLane) { + markUpdateLaneFromFiberToRoot(fiber, update, lane); + } + } +} +function getConcurrentlyUpdatedLanes() { + return concurrentlyUpdatedLanes; +} - while (childFiber && diffIdx < node.children.length) { - var childNode = node.children[diffIdx]; +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. + + fiber.lanes = mergeLanes(fiber.lanes, lane); + var alternate = fiber.alternate; + + if (alternate !== null) { + alternate.lanes = mergeLanes(alternate.lanes, lane); + } +} - if (childNode.fiber === childFiber) { - // This was a match in the diff. - childContent += describeNode(childNode, indent); - diffIdx++; - } else { - // This is an unrelated previous sibling. - childContent += describeSiblingFiber(childFiber, indent); - } +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; + + 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. + +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; +} - childFiber = childFiber.sibling; - } +function markUpdateLaneFromFiberToRoot(sourceFiber, update, lane) { + // Update the source fiber's lanes + sourceFiber.lanes = mergeLanes(sourceFiber.lanes, lane); + var alternate = sourceFiber.alternate; - if (childFiber && node.children.length > 0) { - // If we had any further siblings after the last mismatch, we can't be sure if it's - // actually a valid match since it might not have found a match. So we exclude next - // siblings to avoid confusion. - childContent += indentation(indent) + "..." + "\n"; - } // Deleted tail nodes + if (alternate !== null) { + alternate.lanes = mergeLanes(alternate.lanes, lane); + } // Walk the parent path to the root and update the child lanes. - var serverTail = node.serverTail; - for (var _i = 0; _i < serverTail.length; _i++) { - var tailNode = serverTail[_i]; + var isHidden = false; + var parent = sourceFiber.return; + var node = sourceFiber; - if (typeof tailNode === "string") { - // Removed text node - childContent += - removed(indent) + - describeTextNode(tailNode, maxRowLength - indent * 2) + - "\n"; - } else { - // Removed element - childContent += describeExpandedElement( - tailNode.type, - tailNode.props, - removed(indent) - ); - } - } + while (parent !== null) { + parent.childLanes = mergeLanes(parent.childLanes, lane); + alternate = parent.alternate; - return parentContent + selfContent + childContent; + if (alternate !== null) { + alternate.childLanes = mergeLanes(alternate.childLanes, lane); } - function describeDiff(rootNode) { - try { - return "\n\n" + describeNode(rootNode, 0); - } catch (x) { - return ""; + 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 (offscreenInstance !== null && !(offscreenInstance._visibility & OffscreenVisible)) { + isHidden = true; } } - var isHydrating = false; // This flag allows for warning supression when we expect there to be mismatches + node = parent; + parent = parent.return; + } - var hydrationDiffRootDEV = null; // Hydration errors that were thrown inside this boundary + if (isHidden && update !== null && node.tag === HostRoot) { + var root = node.stateNode; + markHiddenUpdate(root, update, lane); + } +} - var hydrationErrors = null; +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. + + detectUpdateOnUnmountedFiber(sourceFiber, sourceFiber); + var node = sourceFiber; + var parent = node.return; + + while (parent !== null) { + detectUpdateOnUnmountedFiber(sourceFiber, node); + node = parent; + parent = node.return; + } + + return node.tag === HostRoot ? node.stateNode : null; +} - 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." - ); - } - } +function detectUpdateOnUnmountedFiber(sourceFiber, parent) { + { + var alternate = parent.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 (alternate === null && (parent.flags & (Placement | Hydrating)) !== NoFlags$1) { + warnAboutUpdateOnNotYetMountedFiberInDEV(sourceFiber); } + } +} - 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." - ); - } - } +// there's only a single root, but we do support multi root apps, hence this +// extra complexity. But this module is optimized for the single root case. + +var firstScheduledRoot = null; +var lastScheduledRoot = null; // Used to prevent redundant mircotasks from being scheduled. + +var didScheduleMicrotask = false; // `act` "microtasks" are scheduled on the `act` queue instead of an actual +// microtask, so we have to dedupe those separately. This wouldn't be an issue +// if we required all `act` calls to be awaited, which we might in the future. + +var didScheduleMicrotask_act = false; // Used to quickly bail out of flushSync if there's no sync work to do. + +var mightHavePendingSyncWork = false; +var isFlushingWork = false; +var currentEventTransitionLane = NoLane; +function ensureRootIsScheduled(root) { + // This function is called whenever a root receives an update. It does two + // things 1) it ensures the root is in the root schedule, and 2) it ensures + // there's a pending microtask to process the root schedule. + // + // Most of the actual scheduling logic does not happen until + // `scheduleTaskForRootDuringMicrotask` runs. + // Add the root to the schedule + if (root === lastScheduledRoot || root.next !== null) ; else { + if (lastScheduledRoot === null) { + firstScheduledRoot = lastScheduledRoot = root; + } else { + lastScheduledRoot.next = root; + lastScheduledRoot = root; + } + } // Any time a root received an update, we set this to true until the next time + // we process the schedule. If it's false, then we can quickly exit flushSync + // without consulting the schedule. + + + mightHavePendingSyncWork = true; // At the end of the current event, go through each of the roots and ensure + // there's a task scheduled for each one at the correct priority. + + if (ReactSharedInternals.actQueue !== null) { + // We're inside an `act` scope. + if (!didScheduleMicrotask_act) { + didScheduleMicrotask_act = true; + scheduleImmediateTask(processRootScheduleInMicrotask); + } + } else { + if (!didScheduleMicrotask) { + didScheduleMicrotask = true; + scheduleImmediateTask(processRootScheduleInMicrotask); + } + } + + { + // While this flag is disabled, we schedule the render task immediately + // instead of waiting a microtask. + // TODO: We need to land enableDeferRootSchedulingToMicrotask ASAP to + // unblock additional features we have planned. + scheduleTaskForRootDuringMicrotask(root, now$1()); + } + + if (ReactSharedInternals.isBatchingLegacy && root.tag === LegacyRoot) { + // Special `act` case: Record whenever a legacy update is scheduled. + ReactSharedInternals.didScheduleLegacyUpdate = true; + } +} +function flushSyncWorkOnAllRoots() { + // This is allowed to be called synchronously, but the caller should check + // the execution context first. + flushSyncWorkAcrossRoots_impl(false); +} +function flushSyncWorkOnLegacyRootsOnly() { + // This is allowed to be called synchronously, but the caller should check + // the execution context first. + { + flushSyncWorkAcrossRoots_impl(true); + } +} - function popHydrationState(fiber) { - { - return false; - } - } +function flushSyncWorkAcrossRoots_impl(onlyLegacy) { + if (isFlushingWork) { + // Prevent reentrancy. + // TODO: Is this overly defensive? The callers must check the execution + // context first regardless. + return; + } - 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 (!mightHavePendingSyncWork) { + // Fast path. There's no sync work to do. + return; + } // There may or may not be synchronous work scheduled. Let's check. - function getIsHydrating() { - return isHydrating; - } - function queueHydrationError(error) { - if (hydrationErrors === null) { - hydrationErrors = [error]; - } else { - hydrationErrors.push(error); - } - } - function emitPendingHydrationWarnings() { - { - // If we haven't yet thrown any hydration errors by the time we reach the end we've successfully - // hydrated, however, we might still have DEV-only mismatches that we log now. - var diffRoot = hydrationDiffRootDEV; - - if (diffRoot !== null) { - hydrationDiffRootDEV = null; - var diff = describeDiff(diffRoot); - - error( - "A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. " + - "This can happen if a SSR-ed Client Component used:\n" + - "\n" + - "- A server/client branch `if (typeof window !== 'undefined')`.\n" + - "- Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.\n" + - "- Date formatting in a user's locale which doesn't match the server.\n" + - "- External changing data without sending a snapshot of it along with the HTML.\n" + - "- Invalid HTML tag nesting.\n" + - "\n" + - "It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.\n" + - "\n" + - "%s%s", - "https://react.dev/link/hydration-mismatch", - diff - ); - } - } - } + var didPerformSomeWork; + isFlushingWork = true; - // 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 concurrentQueues = []; - var concurrentQueuesIndex = 0; - var concurrentlyUpdatedLanes = NoLanes; - function finishQueueingConcurrentUpdates() { - var endIndex = concurrentQueuesIndex; - concurrentQueuesIndex = 0; - concurrentlyUpdatedLanes = NoLanes; - var i = 0; - - 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; - } + do { + didPerformSomeWork = false; + var root = firstScheduledRoot; - queue.pending = update; - } + while (root !== null) { + if (onlyLegacy && (root.tag !== LegacyRoot)) ; else { + var workInProgressRoot = getWorkInProgressRoot(); + var workInProgressRootRenderLanes = getWorkInProgressRootRenderLanes(); + var nextLanes = getNextLanes(root, root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes); - if (lane !== NoLane) { - markUpdateLaneFromFiberToRoot(fiber, update, lane); + if (includesSyncLane(nextLanes)) { + // This root has pending sync work. Flush it now. + didPerformSomeWork = true; + performSyncWorkOnRoot(root, nextLanes); } } - } - function getConcurrentlyUpdatedLanes() { - return concurrentlyUpdatedLanes; - } - - 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. - fiber.lanes = mergeLanes(fiber.lanes, lane); - var alternate = fiber.alternate; + root = root.next; + } + } while (didPerformSomeWork); - if (alternate !== null) { - alternate.lanes = mergeLanes(alternate.lanes, lane); - } - } - - 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. + isFlushingWork = false; +} - var isConcurrentlyRendering = getWorkInProgressRoot() !== null; +function processRootScheduleInMicrotask() { + // This function is always called inside a microtask. It should never be + // called synchronously. + didScheduleMicrotask = false; - 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. + { + didScheduleMicrotask_act = false; + } // We'll recompute this as we iterate through all the roots and schedule them. - 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; + mightHavePendingSyncWork = false; + var currentTime = now$1(); + var prev = null; + var root = firstScheduledRoot; - if (alternate !== null) { - alternate.lanes = mergeLanes(alternate.lanes, lane); - } // Walk the parent path to the root and update the child lanes. + while (root !== null) { + var next = root.next; - var isHidden = false; - var parent = sourceFiber.return; - var node = sourceFiber; + if (currentEventTransitionLane !== NoLane && shouldAttemptEagerTransition()) { + // A transition was scheduled during an event, but we're going to try to + // render it synchronously anyway. We do this during a popstate event to + // preserve the scroll position of the previous page. + upgradePendingLaneToSync(root, currentEventTransitionLane); + } - while (parent !== null) { - parent.childLanes = mergeLanes(parent.childLanes, lane); - alternate = parent.alternate; + var nextLanes = scheduleTaskForRootDuringMicrotask(root, currentTime); - if (alternate !== null) { - alternate.childLanes = mergeLanes(alternate.childLanes, lane); - } + if (nextLanes === NoLane) { + // This root has no more pending work. Remove it from the schedule. To + // guard against subtle reentrancy bugs, this microtask is the only place + // we do this — you can add roots to the schedule whenever, but you can + // only remove them here. + // Null this out so we know it's been removed from the schedule. + root.next = 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; - - if ( - offscreenInstance !== null && - !(offscreenInstance._visibility & OffscreenVisible) - ) { - isHidden = true; - } - } + if (prev === null) { + // This is the new head of the list + firstScheduledRoot = next; + } else { + prev.next = next; + } - node = parent; - parent = parent.return; + if (next === null) { + // This is the new tail of the list + lastScheduledRoot = prev; } + } else { + // This root still has work. Keep it in the list. + prev = root; - if (isHidden && update !== null && node.tag === HostRoot) { - var root = node.stateNode; - markHiddenUpdate(root, update, lane); + if (includesSyncLane(nextLanes)) { + mightHavePendingSyncWork = true; } } - 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. + root = next; + } - detectUpdateOnUnmountedFiber(sourceFiber, sourceFiber); - var node = sourceFiber; - var parent = node.return; + currentEventTransitionLane = NoLane; // At the end of the microtask, flush any pending synchronous work. This has + // to come at the end, because it does actual rendering work that might throw. - while (parent !== null) { - detectUpdateOnUnmountedFiber(sourceFiber, node); - node = parent; - parent = node.return; - } + flushSyncWorkOnAllRoots(); +} - return node.tag === HostRoot ? node.stateNode : null; - } +function scheduleTaskForRootDuringMicrotask(root, currentTime) { + // This function is always called inside a microtask, or at the very end of a + // rendering task right before we yield to the main thread. It should never be + // called synchronously. + // + // TODO: Unless enableDeferRootSchedulingToMicrotask is off. We need to land + // that ASAP to unblock additional features we have planned. + // + // This function also never performs React work synchronously; it should + // only schedule work to be performed later, in a separate task or microtask. + // Check if any lanes are being starved by other work. If so, mark them as + // expired so we know to work on those next. + markStarvedLanesAsExpired(root, currentTime); // Determine the next lanes to work on, and their priority. + + var workInProgressRoot = getWorkInProgressRoot(); + var workInProgressRootRenderLanes = getWorkInProgressRootRenderLanes(); + var nextLanes = getNextLanes(root, root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes); + var existingCallbackNode = root.callbackNode; + + if ( // Check if there's nothing to work on + nextLanes === NoLanes || // 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. + // + // Suspended render phase + root === workInProgressRoot && isWorkLoopSuspendedOnData() || // Suspended commit phase + root.cancelPendingCommit !== null) { + // Fast path: There's nothing to work on. + if (existingCallbackNode !== null) { + cancelCallback(existingCallbackNode); + } + + root.callbackNode = null; + root.callbackPriority = NoLane; + return NoLane; + } // Schedule a new callback in the host environment. + + + if (includesSyncLane(nextLanes)) { + // Synchronous work is always flushed at the end of the microtask, so we + // don't need to schedule an additional task. + if (existingCallbackNode !== null) { + cancelCallback(existingCallbackNode); + } + + root.callbackPriority = SyncLane; + root.callbackNode = null; + return SyncLane; + } else { + // We use the highest priority lane to represent the priority of the callback. + var existingCallbackPriority = root.callbackPriority; + var newCallbackPriority = getHighestPriorityLane(nextLanes); + + if (newCallbackPriority === existingCallbackPriority && // Special case related to `act`. If the currently scheduled task is a + // Scheduler task, rather than an `act` task, cancel it and re-schedule + // on the `act` queue. + !(ReactSharedInternals.actQueue !== null && existingCallbackNode !== fakeActCallbackNode$1)) { + // The priority hasn't changed. We can reuse the existing task. + return newCallbackPriority; + } else { + // Cancel the existing callback. We'll schedule a new one below. + cancelCallback(existingCallbackNode); + } + + var schedulerPriorityLevel; + + switch (lanesToEventPriority(nextLanes)) { + case DiscreteEventPriority: + schedulerPriorityLevel = ImmediatePriority; + break; + + case ContinuousEventPriority: + schedulerPriorityLevel = UserBlockingPriority; + break; + + case DefaultEventPriority: + schedulerPriorityLevel = NormalPriority$1; + break; + + case IdleEventPriority: + schedulerPriorityLevel = IdlePriority; + break; + + default: + schedulerPriorityLevel = NormalPriority$1; + break; + } + + var newCallbackNode = scheduleCallback$2(schedulerPriorityLevel, performConcurrentWorkOnRoot.bind(null, root)); + root.callbackPriority = newCallbackPriority; + root.callbackNode = newCallbackNode; + return newCallbackPriority; + } +} - function detectUpdateOnUnmountedFiber(sourceFiber, parent) { - { - var alternate = parent.alternate; +function getContinuationForRoot(root, originalCallbackNode) { + // This is called at the end of `performConcurrentWorkOnRoot` to determine + // if we need to schedule a continuation task. + // + // Usually `scheduleTaskForRootDuringMicrotask` only runs inside a microtask; + // however, since most of the logic for determining if we need a continuation + // versus a new task is the same, we cheat a bit and call it here. This is + // only safe to do because we know we're at the end of the browser task. + // So although it's not an actual microtask, it might as well be. + scheduleTaskForRootDuringMicrotask(root, now$1()); + + 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); + } + + return null; +} +var fakeActCallbackNode$1 = {}; + +function scheduleCallback$2(priorityLevel, callback) { + if (ReactSharedInternals.actQueue !== null) { + // Special case: We're inside an `act` scope (a testing utility). + // Instead of scheduling work in the host environment, add it to a + // fake internal queue that's managed by the `act` implementation. + ReactSharedInternals.actQueue.push(callback); + return fakeActCallbackNode$1; + } else { + return scheduleCallback$3(priorityLevel, callback); + } +} - if ( - alternate === null && - (parent.flags & (Placement | Hydrating)) !== NoFlags$1 - ) { - warnAboutUpdateOnNotYetMountedFiberInDEV(sourceFiber); - } - } - } +function cancelCallback(callbackNode) { + if (callbackNode === fakeActCallbackNode$1) ; else if (callbackNode !== null) { + cancelCallback$1(callbackNode); + } +} - // there's only a single root, but we do support multi root apps, hence this - // extra complexity. But this module is optimized for the single root case. +function scheduleImmediateTask(cb) { + if (ReactSharedInternals.actQueue !== null) { + // Special case: Inside an `act` scope, we push microtasks to the fake `act` + // callback queue. This is because we currently support calling `act` + // without awaiting the result. The plan is to deprecate that, and require + // that you always await the result so that the microtasks have a chance to + // run. But it hasn't happened yet. + ReactSharedInternals.actQueue.push(function () { + cb(); + return null; + }); + } // TODO: Can we land supportsMicrotasks? Which environments don't support it? + // Alternatively, can we move this check to the host config? - var firstScheduledRoot = null; - var lastScheduledRoot = null; // Used to prevent redundant mircotasks from being scheduled. - var didScheduleMicrotask = false; // `act` "microtasks" are scheduled on the `act` queue instead of an actual - // microtask, so we have to dedupe those separately. This wouldn't be an issue - // if we required all `act` calls to be awaited, which we might in the future. + { + // If microtasks are not supported, use Scheduler. + scheduleCallback$3(ImmediatePriority, cb); + } +} - var didScheduleMicrotask_act = false; // Used to quickly bail out of flushSync if there's no sync work to do. +function requestTransitionLane( // This argument isn't used, it's only here to encourage the caller to +// check that it's inside a transition before calling this function. +// TODO: Make this non-nullable. Requires a tweak to useOptimistic. +transition) { + // 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(); + } + + return currentEventTransitionLane; +} - var mightHavePendingSyncWork = false; - var isFlushingWork = false; - var currentEventTransitionLane = NoLane; - function ensureRootIsScheduled(root) { - // This function is called whenever a root receives an update. It does two - // things 1) it ensures the root is in the root schedule, and 2) it ensures - // there's a pending microtask to process the root schedule. - // - // Most of the actual scheduling logic does not happen until - // `scheduleTaskForRootDuringMicrotask` runs. - // Add the root to the schedule - if (root === lastScheduledRoot || root.next !== null); - else { - if (lastScheduledRoot === null) { - firstScheduledRoot = lastScheduledRoot = root; - } else { - lastScheduledRoot.next = root; - lastScheduledRoot = root; - } - } // Any time a root received an update, we set this to true until the next time - // we process the schedule. If it's false, then we can quickly exit flushSync - // without consulting the schedule. - - mightHavePendingSyncWork = true; // At the end of the current event, go through each of the roots and ensure - // there's a task scheduled for each one at the correct priority. - - if (ReactSharedInternals.actQueue !== null) { - // We're inside an `act` scope. - if (!didScheduleMicrotask_act) { - didScheduleMicrotask_act = true; - scheduleImmediateTask(processRootScheduleInMicrotask); - } - } else { - if (!didScheduleMicrotask) { - didScheduleMicrotask = true; - scheduleImmediateTask(processRootScheduleInMicrotask); - } +// transition updates that occur while the async action is still in progress +// are treated as part of the action. +// +// The ideal behavior would be to treat each async function as an independent +// action. However, without a mechanism like AsyncContext, we can't tell which +// action an update corresponds to. So instead, we entangle them all into one. +// The listeners to notify once the entangled scope completes. + +var currentEntangledListeners = null; // The number of pending async actions in the entangled scope. + +var currentEntangledPendingCount = 0; // The transition lane shared by all updates in the entangled scope. + +var currentEntangledLane = NoLane; // A thenable that resolves when the entangled scope completes. It does not +// resolve to a particular value because it's only used for suspending the UI +// until the async action scope has completed. + +var currentEntangledActionThenable = null; +function entangleAsyncAction(transition, thenable) { + // `thenable` is the return value of the async action scope function. Create + // a combined thenable that resolves once every entangled scope function + // has finished. + if (currentEntangledListeners === null) { + // There's no outer async action scope. Create a new one. + var entangledListeners = currentEntangledListeners = []; + currentEntangledPendingCount = 0; + currentEntangledLane = requestTransitionLane(); + var entangledThenable = { + status: 'pending', + value: undefined, + then: function (resolve) { + entangledListeners.push(resolve); } + }; + currentEntangledActionThenable = entangledThenable; + } - { - // While this flag is disabled, we schedule the render task immediately - // instead of waiting a microtask. - // TODO: We need to land enableDeferRootSchedulingToMicrotask ASAP to - // unblock additional features we have planned. - scheduleTaskForRootDuringMicrotask(root, now$1()); - } + currentEntangledPendingCount++; + thenable.then(pingEngtangledActionScope, pingEngtangledActionScope); + return thenable; +} - if (ReactSharedInternals.isBatchingLegacy && root.tag === LegacyRoot) { - // Special `act` case: Record whenever a legacy update is scheduled. - ReactSharedInternals.didScheduleLegacyUpdate = true; - } - } - function flushSyncWorkOnAllRoots() { - // This is allowed to be called synchronously, but the caller should check - // the execution context first. - flushSyncWorkAcrossRoots_impl(false); - } - function flushSyncWorkOnLegacyRootsOnly() { - // This is allowed to be called synchronously, but the caller should check - // the execution context first. - { - flushSyncWorkAcrossRoots_impl(true); - } +function pingEngtangledActionScope() { + if (currentEntangledListeners !== null && --currentEntangledPendingCount === 0) { + // All the actions have finished. Close the entangled async action scope + // and notify all the listeners. + if (currentEntangledActionThenable !== null) { + var fulfilledThenable = currentEntangledActionThenable; + fulfilledThenable.status = 'fulfilled'; } - function flushSyncWorkAcrossRoots_impl(onlyLegacy) { - if (isFlushingWork) { - // Prevent reentrancy. - // TODO: Is this overly defensive? The callers must check the execution - // context first regardless. - return; - } - - if (!mightHavePendingSyncWork) { - // Fast path. There's no sync work to do. - return; - } // There may or may not be synchronous work scheduled. Let's check. - - var didPerformSomeWork; - isFlushingWork = true; - - do { - didPerformSomeWork = false; - var root = firstScheduledRoot; - - while (root !== null) { - if (onlyLegacy && root.tag !== LegacyRoot); - else { - var workInProgressRoot = getWorkInProgressRoot(); - var workInProgressRootRenderLanes = - getWorkInProgressRootRenderLanes(); - var nextLanes = getNextLanes( - root, - root === workInProgressRoot - ? workInProgressRootRenderLanes - : NoLanes - ); + var listeners = currentEntangledListeners; + currentEntangledListeners = null; + currentEntangledLane = NoLane; + currentEntangledActionThenable = null; - if (includesSyncLane(nextLanes)) { - // This root has pending sync work. Flush it now. - didPerformSomeWork = true; - performSyncWorkOnRoot(root, nextLanes); - } - } + for (var i = 0; i < listeners.length; i++) { + var listener = listeners[i]; + listener(); + } + } +} - root = root.next; - } - } while (didPerformSomeWork); +function chainThenableValue(thenable, result) { + // Equivalent to: Promise.resolve(thenable).then(() => result), except we can + // cheat a bit since we know that that this thenable is only ever consumed + // by React. + // + // We don't technically require promise support on the client yet, hence this + // extra code. + var listeners = []; + var thenableWithOverride = { + status: 'pending', + value: null, + reason: null, + then: function (resolve) { + listeners.push(resolve); + } + }; + thenable.then(function (value) { + var fulfilledThenable = thenableWithOverride; + fulfilledThenable.status = 'fulfilled'; + fulfilledThenable.value = result; + + for (var i = 0; i < listeners.length; i++) { + var listener = listeners[i]; + listener(result); + } + }, function (error) { + var rejectedThenable = thenableWithOverride; + rejectedThenable.status = 'rejected'; + rejectedThenable.reason = error; + + for (var i = 0; i < listeners.length; i++) { + var listener = listeners[i]; // This is a perf hack where we call the `onFulfill` ping function + // instead of `onReject`, because we know that React is the only + // consumer of these promises, and it passes the same listener to both. + // We also know that it will read the error directly off the + // `.reason` field. + + listener(undefined); + } + }); + return thenableWithOverride; +} +function peekEntangledActionLane() { + return currentEntangledLane; +} +function peekEntangledActionThenable() { + return currentEntangledActionThenable; +} - isFlushingWork = false; - } +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`. - function processRootScheduleInMicrotask() { - // This function is always called inside a microtask. It should never be - // called synchronously. - didScheduleMicrotask = false; +var hasForceUpdate = false; +var didWarnUpdateInsideUpdate; +var currentlyProcessingQueue; - { - didScheduleMicrotask_act = false; - } // We'll recompute this as we iterate through all the roots and schedule them. - - mightHavePendingSyncWork = false; - var currentTime = now$1(); - var prev = null; - var root = firstScheduledRoot; - - while (root !== null) { - var next = root.next; - - if ( - currentEventTransitionLane !== NoLane && - shouldAttemptEagerTransition() - ) { - // A transition was scheduled during an event, but we're going to try to - // render it synchronously anyway. We do this during a popstate event to - // preserve the scroll position of the previous page. - upgradePendingLaneToSync(root, currentEventTransitionLane); - } +{ + didWarnUpdateInsideUpdate = false; + currentlyProcessingQueue = null; +} - var nextLanes = scheduleTaskForRootDuringMicrotask(root, currentTime); +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 (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; - if (nextLanes === NoLane) { - // This root has no more pending work. Remove it from the schedule. To - // guard against subtle reentrancy bugs, this microtask is the only place - // we do this — you can add roots to the schedule whenever, but you can - // only remove them here. - // Null this out so we know it's been removed from the schedule. - root.next = null; + if (updateQueue === null) { + // Only occurs if the fiber has been unmounted. + return null; + } - if (prev === null) { - // This is the new head of the list - firstScheduledRoot = next; - } else { - prev.next = next; - } + var sharedQueue = updateQueue.shared; - if (next === null) { - // This is the new tail of the list - lastScheduledRoot = prev; - } - } else { - // This root still has work. Keep it in the list. - prev = root; + { + if (currentlyProcessingQueue === sharedQueue && !didWarnUpdateInsideUpdate) { + var componentName = getComponentNameFromFiber(fiber); - if (includesSyncLane(nextLanes)) { - mightHavePendingSyncWork = true; - } - } + 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); - root = next; - } + didWarnUpdateInsideUpdate = true; + } + } - currentEventTransitionLane = NoLane; // At the end of the microtask, flush any pending synchronous work. This has - // to come at the end, because it does actual rendering work that might throw. + 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; - flushSyncWorkOnAllRoots(); + if (pending === null) { + // This is the first update. Create a circular list. + update.next = update; + } else { + update.next = pending.next; + pending.next = update; } - function scheduleTaskForRootDuringMicrotask(root, currentTime) { - // This function is always called inside a microtask, or at the very end of a - // rendering task right before we yield to the main thread. It should never be - // called synchronously. - // - // TODO: Unless enableDeferRootSchedulingToMicrotask is off. We need to land - // that ASAP to unblock additional features we have planned. - // - // This function also never performs React work synchronously; it should - // only schedule work to be performed later, in a separate task or microtask. - // Check if any lanes are being starved by other work. If so, mark them as - // expired so we know to work on those next. - markStarvedLanesAsExpired(root, currentTime); // Determine the next lanes to work on, and their priority. - - var workInProgressRoot = getWorkInProgressRoot(); - var workInProgressRootRenderLanes = getWorkInProgressRootRenderLanes(); - var nextLanes = getNextLanes( - root, - root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes - ); - var existingCallbackNode = root.callbackNode; - - if ( - // Check if there's nothing to work on - nextLanes === NoLanes || // 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. - // - // Suspended render phase - (root === workInProgressRoot && isWorkLoopSuspendedOnData()) || // Suspended commit phase - root.cancelPendingCommit !== null - ) { - // Fast path: There's nothing to work on. - if (existingCallbackNode !== null) { - cancelCallback(existingCallbackNode); - } + 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). - root.callbackNode = null; - root.callbackPriority = NoLane; - return NoLane; - } // Schedule a new callback in the host environment. + return unsafe_markUpdateLaneFromFiberToRoot(fiber, lane); + } else { + return enqueueConcurrentClassUpdate(fiber, sharedQueue, update, lane); + } +} +function entangleTransitions(root, fiber, lane) { + var updateQueue = fiber.updateQueue; - if (includesSyncLane(nextLanes)) { - // Synchronous work is always flushed at the end of the microtask, so we - // don't need to schedule an additional task. - if (existingCallbackNode !== null) { - cancelCallback(existingCallbackNode); - } + if (updateQueue === null) { + // Only occurs if the fiber has been unmounted. + return; + } - root.callbackPriority = SyncLane; - root.callbackNode = null; - return SyncLane; - } else { - // We use the highest priority lane to represent the priority of the callback. - var existingCallbackPriority = root.callbackPriority; - var newCallbackPriority = getHighestPriorityLane(nextLanes); - - if ( - newCallbackPriority === existingCallbackPriority && // Special case related to `act`. If the currently scheduled task is a - // Scheduler task, rather than an `act` task, cancel it and re-schedule - // on the `act` queue. - !( - ReactSharedInternals.actQueue !== null && - existingCallbackNode !== fakeActCallbackNode$1 - ) - ) { - // The priority hasn't changed. We can reuse the existing task. - return newCallbackPriority; - } else { - // Cancel the existing callback. We'll schedule a new one below. - cancelCallback(existingCallbackNode); - } + var sharedQueue = updateQueue.shared; - var schedulerPriorityLevel; + 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. - switch (lanesToEventPriority(nextLanes)) { - case DiscreteEventPriority: - schedulerPriorityLevel = ImmediatePriority; - break; + queueLanes = intersectLanes(queueLanes, root.pendingLanes); // Entangle the new transition lane with the other transition lanes. - case ContinuousEventPriority: - schedulerPriorityLevel = UserBlockingPriority; - break; + 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. - case DefaultEventPriority: - schedulerPriorityLevel = NormalPriority$1; - break; + 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 current = workInProgress.alternate; + + if (current !== null) { + var currentQueue = current.updateQueue; + + 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; - case IdleEventPriority: - schedulerPriorityLevel = IdlePriority; - break; + if (firstBaseUpdate !== null) { + // Loop through the updates and clone them. + var update = firstBaseUpdate; - default: - schedulerPriorityLevel = NormalPriority$1; - break; - } + 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 newCallbackNode = scheduleCallback$2( - schedulerPriorityLevel, - performConcurrentWorkOnRoot.bind(null, root) - ); - root.callbackPriority = newCallbackPriority; - root.callbackNode = newCallbackNode; - return newCallbackPriority; - } - } + if (newLast === null) { + newFirst = newLast = clone; + } else { + newLast.next = clone; + newLast = clone; + } // $FlowFixMe[incompatible-type] we bail out when we get a null - function getContinuationForRoot(root, originalCallbackNode) { - // This is called at the end of `performConcurrentWorkOnRoot` to determine - // if we need to schedule a continuation task. - // - // Usually `scheduleTaskForRootDuringMicrotask` only runs inside a microtask; - // however, since most of the logic for determining if we need a continuation - // versus a new task is the same, we cheat a bit and call it here. This is - // only safe to do because we know we're at the end of the browser task. - // So although it's not an actual microtask, it might as well be. - scheduleTaskForRootDuringMicrotask(root, now$1()); - 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); - } + update = update.next; + } while (update !== null); // Append the captured update the end of the cloned list. - return null; - } - var fakeActCallbackNode$1 = {}; - function scheduleCallback$2(priorityLevel, callback) { - if (ReactSharedInternals.actQueue !== null) { - // Special case: We're inside an `act` scope (a testing utility). - // Instead of scheduling work in the host environment, add it to a - // fake internal queue that's managed by the `act` implementation. - ReactSharedInternals.actQueue.push(callback); - return fakeActCallbackNode$1; + if (newLast === null) { + newFirst = newLast = capturedUpdate; + } else { + newLast.next = capturedUpdate; + newLast = capturedUpdate; + } } else { - return scheduleCallback$3(priorityLevel, callback); + // There are no base updates. + newFirst = newLast = capturedUpdate; } - } - function cancelCallback(callbackNode) { - if (callbackNode === fakeActCallbackNode$1); - else if (callbackNode !== null) { - cancelCallback$1(callbackNode); - } + 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. - function scheduleImmediateTask(cb) { - if (ReactSharedInternals.actQueue !== null) { - // Special case: Inside an `act` scope, we push microtasks to the fake `act` - // callback queue. This is because we currently support calling `act` - // without awaiting the result. The plan is to deprecate that, and require - // that you always await the result so that the microtasks have a chance to - // run. But it hasn't happened yet. - ReactSharedInternals.actQueue.push(function () { - cb(); - return null; - }); - } // TODO: Can we land supportsMicrotasks? Which environments don't support it? - // Alternatively, can we move this check to the host config? - - { - // If microtasks are not supported, use Scheduler. - scheduleCallback$3(ImmediatePriority, cb); - } - } - function requestTransitionLane( // This argument isn't used, it's only here to encourage the caller to - // check that it's inside a transition before calling this function. - // TODO: Make this non-nullable. Requires a tweak to useOptimistic. - transition - ) { - // 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(); - } + var lastBaseUpdate = queue.lastBaseUpdate; - return currentEventTransitionLane; - } + if (lastBaseUpdate === null) { + queue.firstBaseUpdate = capturedUpdate; + } else { + lastBaseUpdate.next = capturedUpdate; + } - // transition updates that occur while the async action is still in progress - // are treated as part of the action. - // - // The ideal behavior would be to treat each async function as an independent - // action. However, without a mechanism like AsyncContext, we can't tell which - // action an update corresponds to. So instead, we entangle them all into one. - // The listeners to notify once the entangled scope completes. - - var currentEntangledListeners = null; // The number of pending async actions in the entangled scope. - - var currentEntangledPendingCount = 0; // The transition lane shared by all updates in the entangled scope. - - var currentEntangledLane = NoLane; // A thenable that resolves when the entangled scope completes. It does not - // resolve to a particular value because it's only used for suspending the UI - // until the async action scope has completed. - - var currentEntangledActionThenable = null; - function entangleAsyncAction(transition, thenable) { - // `thenable` is the return value of the async action scope function. Create - // a combined thenable that resolves once every entangled scope function - // has finished. - if (currentEntangledListeners === null) { - // There's no outer async action scope. Create a new one. - var entangledListeners = (currentEntangledListeners = []); - currentEntangledPendingCount = 0; - currentEntangledLane = requestTransitionLane(); - var entangledThenable = { - status: "pending", - value: undefined, - then: function (resolve) { - entangledListeners.push(resolve); - } - }; - currentEntangledActionThenable = entangledThenable; - } + queue.lastBaseUpdate = capturedUpdate; +} - currentEntangledPendingCount++; - thenable.then(pingEngtangledActionScope, pingEngtangledActionScope); - return thenable; - } +function getStateFromUpdate(workInProgress, queue, update, prevState, nextProps, instance) { + switch (update.tag) { + case ReplaceState: + { + var payload = update.payload; - function pingEngtangledActionScope() { - if ( - currentEntangledListeners !== null && - --currentEntangledPendingCount === 0 - ) { - // All the actions have finished. Close the entangled async action scope - // and notify all the listeners. - if (currentEntangledActionThenable !== null) { - var fulfilledThenable = currentEntangledActionThenable; - fulfilledThenable.status = "fulfilled"; - } + if (typeof payload === 'function') { + // Updater function + { + enterDisallowedContextReadInDEV(); + } - var listeners = currentEntangledListeners; - currentEntangledListeners = null; - currentEntangledLane = NoLane; - currentEntangledActionThenable = null; + var nextState = payload.call(instance, prevState, nextProps); - for (var i = 0; i < listeners.length; i++) { - var listener = listeners[i]; - listener(); - } - } - } + { - function chainThenableValue(thenable, result) { - // Equivalent to: Promise.resolve(thenable).then(() => result), except we can - // cheat a bit since we know that that this thenable is only ever consumed - // by React. - // - // We don't technically require promise support on the client yet, hence this - // extra code. - var listeners = []; - var thenableWithOverride = { - status: "pending", - value: null, - reason: null, - then: function (resolve) { - listeners.push(resolve); - } - }; - thenable.then( - function (value) { - var fulfilledThenable = thenableWithOverride; - fulfilledThenable.status = "fulfilled"; - fulfilledThenable.value = result; - - for (var i = 0; i < listeners.length; i++) { - var listener = listeners[i]; - listener(result); + exitDisallowedContextReadInDEV(); } - }, - function (error) { - var rejectedThenable = thenableWithOverride; - rejectedThenable.status = "rejected"; - rejectedThenable.reason = error; - - for (var i = 0; i < listeners.length; i++) { - var listener = listeners[i]; // This is a perf hack where we call the `onFulfill` ping function - // instead of `onReject`, because we know that React is the only - // consumer of these promises, and it passes the same listener to both. - // We also know that it will read the error directly off the - // `.reason` field. - - listener(undefined); - } - } - ); - return thenableWithOverride; - } - function peekEntangledActionLane() { - return currentEntangledLane; - } - function peekEntangledActionThenable() { - return currentEntangledActionThenable; - } - - 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 hasForceUpdate = false; - var didWarnUpdateInsideUpdate; - var currentlyProcessingQueue; + return nextState; + } // State object - { - didWarnUpdateInsideUpdate = false; - currentlyProcessingQueue = null; - } - - 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 (queue === currentQueue) { - var clone = { - baseState: currentQueue.baseState, - firstBaseUpdate: currentQueue.firstBaseUpdate, - lastBaseUpdate: currentQueue.lastBaseUpdate, - shared: currentQueue.shared, - callbacks: null - }; - workInProgress.updateQueue = clone; + return payload; } - } - 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; + case CaptureUpdate: + { + workInProgress.flags = workInProgress.flags & ~ShouldCapture | DidCapture; } + // Intentional fallthrough - var sharedQueue = updateQueue.shared; - + case UpdateState: { - if ( - currentlyProcessingQueue === sharedQueue && - !didWarnUpdateInsideUpdate - ) { - var componentName = getComponentNameFromFiber(fiber); - - 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 - ); - - didWarnUpdateInsideUpdate = true; - } - } + var _payload = update.payload; + var partialState; - 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; + if (typeof _payload === 'function') { + // Updater function + { + enterDisallowedContextReadInDEV(); + } + + partialState = _payload.call(instance, prevState, nextProps); + + { - if (pending === null) { - // This is the first update. Create a circular list. - update.next = update; + exitDisallowedContextReadInDEV(); + } } else { - update.next = pending.next; - pending.next = update; + // Partial state object + partialState = _payload; } - 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). + if (partialState === null || partialState === undefined) { + // Null and undefined are treated as no-ops. + return prevState; + } // Merge the partial state and the previous state. - return unsafe_markUpdateLaneFromFiberToRoot(fiber, lane); - } else { - return enqueueConcurrentClassUpdate(fiber, sharedQueue, update, lane); + + return assign({}, prevState, partialState); } - } - function entangleTransitions(root, fiber, lane) { - var updateQueue = fiber.updateQueue; - if (updateQueue === null) { - // Only occurs if the fiber has been unmounted. - return; + case ForceUpdate: + { + hasForceUpdate = true; + return prevState; } + } - var sharedQueue = updateQueue.shared; + return prevState; +} - 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. +var didReadFromEntangledAsyncAction = false; // Each call to processUpdateQueue should be accompanied by a call to this. It's +// only in a separate function because in updateHostRoot, it must happen after +// all the context stacks have been pushed to, to prevent a stack mismatch. A +// bit unfortunate. + +function suspendIfUpdateReadFromEntangledAsyncAction() { + // Check if this update is part of a pending async action. If so, we'll + // need to suspend until the action has finished, so that it's batched + // together with future updates in the same action. + // TODO: Once we support hooks inside useMemo (or an equivalent + // memoization boundary like Forget), hoist this logic so that it only + // suspends if the memo boundary produces a new value. + if (didReadFromEntangledAsyncAction) { + var entangledActionThenable = peekEntangledActionThenable(); + + if (entangledActionThenable !== null) { + // TODO: Instead of the throwing the thenable directly, throw a + // special object like `use` does so we can detect if it's captured + // by userspace. + throw entangledActionThenable; + } + } +} +function processUpdateQueue(workInProgress, props, instance, renderLanes) { + didReadFromEntangledAsyncAction = false; // This is always non-null on a ClassComponent or HostRoot - queueLanes = intersectLanes(queueLanes, root.pendingLanes); // Entangle the new transition lane with the other transition lanes. + var queue = workInProgress.updateQueue; + hasForceUpdate = false; - 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. + { + currentlyProcessingQueue = queue.shared; + } - 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 firstBaseUpdate = queue.firstBaseUpdate; + var lastBaseUpdate = queue.lastBaseUpdate; // Check if there are pending updates. If so, transfer them to the base queue. - var current = workInProgress.alternate; + var pendingQueue = queue.shared.pending; - if (current !== null) { - var currentQueue = current.updateQueue; - - 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; - - if (firstBaseUpdate !== null) { - // Loop through the updates and clone them. - var update = firstBaseUpdate; - - 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 - }; + 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. - if (newLast === null) { - newFirst = newLast = clone; - } else { - newLast.next = clone; - newLast = clone; - } // $FlowFixMe[incompatible-type] we bail out when we get a null + var lastPendingUpdate = pendingQueue; + var firstPendingUpdate = lastPendingUpdate.next; + lastPendingUpdate.next = null; // Append pending updates to base queue - update = update.next; - } while (update !== null); // Append the captured update the end of the cloned list. + if (lastBaseUpdate === null) { + firstBaseUpdate = firstPendingUpdate; + } else { + lastBaseUpdate.next = firstPendingUpdate; + } - if (newLast === null) { - newFirst = newLast = capturedUpdate; - } else { - newLast.next = capturedUpdate; - newLast = capturedUpdate; - } - } else { - // There are no base updates. - newFirst = newLast = capturedUpdate; - } + 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 - 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. + var current = workInProgress.alternate; - var lastBaseUpdate = queue.lastBaseUpdate; + if (current !== null) { + // This is always non-null on a ClassComponent or HostRoot + var currentQueue = current.updateQueue; + var currentLastBaseUpdate = currentQueue.lastBaseUpdate; - if (lastBaseUpdate === null) { - queue.firstBaseUpdate = capturedUpdate; - } else { - lastBaseUpdate.next = capturedUpdate; - } + if (currentLastBaseUpdate !== lastBaseUpdate) { + if (currentLastBaseUpdate === null) { + currentQueue.firstBaseUpdate = firstPendingUpdate; + } else { + currentLastBaseUpdate.next = firstPendingUpdate; + } - queue.lastBaseUpdate = capturedUpdate; + currentQueue.lastBaseUpdate = lastPendingUpdate; + } } + } // These values may change as we process the queue. - function getStateFromUpdate( - workInProgress, - queue, - update, - prevState, - nextProps, - instance - ) { - switch (update.tag) { - case ReplaceState: { - var payload = update.payload; - if (typeof payload === "function") { - // Updater function - { - enterDisallowedContextReadInDEV(); - } + 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 nextState = payload.call(instance, prevState, nextProps); + var newLanes = NoLanes; + var newBaseState = null; + var newFirstBaseUpdate = null; + var newLastBaseUpdate = null; + var update = firstBaseUpdate; - { - exitDisallowedContextReadInDEV(); - } + 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. - return nextState; - } // State object + var shouldSkipUpdate = isHiddenUpdate ? !isSubsetOfLanes(getWorkInProgressRootRenderLanes(), updateLane) : !isSubsetOfLanes(renderLanes, updateLane); - return payload; - } + 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 + }; - case CaptureUpdate: { - workInProgress.flags = - (workInProgress.flags & ~ShouldCapture) | DidCapture; - } - // Intentional fallthrough + if (newLastBaseUpdate === null) { + newFirstBaseUpdate = newLastBaseUpdate = clone; + newBaseState = newState; + } else { + newLastBaseUpdate = newLastBaseUpdate.next = clone; + } // Update the remaining priority in the queue. - case UpdateState: { - var _payload = update.payload; - var partialState; - if (typeof _payload === "function") { - // Updater function - { - enterDisallowedContextReadInDEV(); - } + newLanes = mergeLanes(newLanes, updateLane); + } else { + // This update does have sufficient priority. + // Check if this update is part of a pending async action. If so, + // we'll need to suspend until the action has finished, so that it's + // batched together with future updates in the same action. + if (updateLane !== NoLane && updateLane === peekEntangledActionLane()) { + didReadFromEntangledAsyncAction = true; + } + + 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. - partialState = _payload.call(instance, prevState, nextProps); - { - exitDisallowedContextReadInDEV(); - } - } else { - // Partial state object - partialState = _payload; + newState = getStateFromUpdate(workInProgress, queue, update, newState, props, instance); + var callback = update.callback; + + if (callback !== null) { + workInProgress.flags |= Callback; + + if (isHiddenUpdate) { + workInProgress.flags |= Visibility; } - if (partialState === null || partialState === undefined) { - // Null and undefined are treated as no-ops. - return prevState; - } // Merge the partial state and the previous state. + var callbacks = queue.callbacks; - return assign({}, prevState, partialState); + if (callbacks === null) { + queue.callbacks = [callback]; + } else { + callbacks.push(callback); + } } + } // $FlowFixMe[incompatible-type] we bail out when we get a null - case ForceUpdate: { - hasForceUpdate = true; - return prevState; - } - } - return prevState; - } + update = update.next; - var didReadFromEntangledAsyncAction = false; // Each call to processUpdateQueue should be accompanied by a call to this. It's - // only in a separate function because in updateHostRoot, it must happen after - // all the context stacks have been pushed to, to prevent a stack mismatch. A - // bit unfortunate. + if (update === null) { + pendingQueue = queue.shared.pending; - function suspendIfUpdateReadFromEntangledAsyncAction() { - // Check if this update is part of a pending async action. If so, we'll - // need to suspend until the action has finished, so that it's batched - // together with future updates in the same action. - // TODO: Once we support hooks inside useMemo (or an equivalent - // memoization boundary like Forget), hoist this logic so that it only - // suspends if the memo boundary produces a new value. - if (didReadFromEntangledAsyncAction) { - var entangledActionThenable = peekEntangledActionThenable(); + 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 (entangledActionThenable !== null) { - // TODO: Instead of the throwing the thenable directly, throw a - // special object like `use` does so we can detect if it's captured - // by userspace. - throw entangledActionThenable; + var _firstPendingUpdate = _lastPendingUpdate.next; + _lastPendingUpdate.next = null; + update = _firstPendingUpdate; + queue.lastBaseUpdate = _lastPendingUpdate; + queue.shared.pending = null; } } - } - function processUpdateQueue(workInProgress, props, instance, renderLanes) { - didReadFromEntangledAsyncAction = false; // This is always non-null on a ClassComponent or HostRoot - - var queue = workInProgress.updateQueue; - hasForceUpdate = false; - - { - currentlyProcessingQueue = queue.shared; - } - - var firstBaseUpdate = queue.firstBaseUpdate; - var lastBaseUpdate = queue.lastBaseUpdate; // Check if there are pending updates. If so, transfer them to the base queue. + } while (true); - var pendingQueue = queue.shared.pending; + if (newLastBaseUpdate === null) { + newBaseState = newState; + } - 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. + queue.baseState = newBaseState; + queue.firstBaseUpdate = newFirstBaseUpdate; + queue.lastBaseUpdate = newLastBaseUpdate; - var lastPendingUpdate = pendingQueue; - var firstPendingUpdate = lastPendingUpdate.next; - lastPendingUpdate.next = null; // Append pending updates to base queue + 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 (lastBaseUpdate === null) { - firstBaseUpdate = firstPendingUpdate; - } else { - lastBaseUpdate.next = firstPendingUpdate; - } - 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 + markSkippedUpdateLanes(newLanes); + workInProgress.lanes = newLanes; + workInProgress.memoizedState = newState; + } - var current = workInProgress.alternate; + { + currentlyProcessingQueue = null; + } +} - if (current !== null) { - // This is always non-null on a ClassComponent or HostRoot - var currentQueue = current.updateQueue; - var currentLastBaseUpdate = currentQueue.lastBaseUpdate; +function callCallback(callback, context) { + if (typeof callback !== 'function') { + throw new Error('Invalid argument passed as callback. Expected a function. Instead ' + ("received: " + callback)); + } - if (currentLastBaseUpdate !== lastBaseUpdate) { - if (currentLastBaseUpdate === null) { - currentQueue.firstBaseUpdate = firstPendingUpdate; - } else { - currentLastBaseUpdate.next = firstPendingUpdate; - } + callback.call(context); +} - currentQueue.lastBaseUpdate = lastPendingUpdate; - } - } - } // These values may change as we process the queue. +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; - 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 newLanes = NoLanes; - var newBaseState = null; - var newFirstBaseUpdate = null; - var newLastBaseUpdate = null; - var update = firstBaseUpdate; + if (newHiddenCallbacks !== null) { + var existingHiddenCallbacks = updateQueue.shared.hiddenCallbacks; - 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); - - 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 - }; + 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; - if (newLastBaseUpdate === null) { - newFirstBaseUpdate = newLastBaseUpdate = clone; - newBaseState = newState; - } else { - newLastBaseUpdate = newLastBaseUpdate.next = clone; - } // Update the remaining priority in the queue. + if (hiddenCallbacks !== null) { + updateQueue.shared.hiddenCallbacks = null; - newLanes = mergeLanes(newLanes, updateLane); - } else { - // This update does have sufficient priority. - // Check if this update is part of a pending async action. If so, - // we'll need to suspend until the action has finished, so that it's - // batched together with future updates in the same action. - if ( - updateLane !== NoLane && - updateLane === peekEntangledActionLane() - ) { - didReadFromEntangledAsyncAction = true; - } + for (var i = 0; i < hiddenCallbacks.length; i++) { + var callback = hiddenCallbacks[i]; + callCallback(callback, context); + } + } +} +function commitCallbacks(updateQueue, context) { + var callbacks = updateQueue.callbacks; - 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. - - newState = getStateFromUpdate( - workInProgress, - queue, - update, - newState, - props, - instance - ); - var callback = update.callback; + if (callbacks !== null) { + updateQueue.callbacks = null; - if (callback !== null) { - workInProgress.flags |= Callback; + for (var i = 0; i < callbacks.length; i++) { + var callback = callbacks[i]; + callCallback(callback, context); + } + } +} - if (isHiddenUpdate) { - workInProgress.flags |= Visibility; - } +// $FlowFixMe[method-unbinding] +var hasOwnProperty = Object.prototype.hasOwnProperty; - var callbacks = queue.callbacks; +/** + * 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. + */ - if (callbacks === null) { - queue.callbacks = [callback]; - } else { - callbacks.push(callback); - } - } - } // $FlowFixMe[incompatible-type] we bail out when we get a null +function shallowEqual(objA, objB) { + if (objectIs(objA, objB)) { + return true; + } - update = update.next; + if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) { + return false; + } - if (update === null) { - pendingQueue = queue.shared.pending; + var keysA = Object.keys(objA); + var keysB = Object.keys(objB); - 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. - - var _firstPendingUpdate = _lastPendingUpdate.next; - _lastPendingUpdate.next = null; - update = _firstPendingUpdate; - queue.lastBaseUpdate = _lastPendingUpdate; - queue.shared.pending = null; - } - } - } while (true); + if (keysA.length !== keysB.length) { + return false; + } // Test for A's keys different from B. - if (newLastBaseUpdate === null) { - newBaseState = newState; - } - queue.baseState = newBaseState; - queue.firstBaseUpdate = newFirstBaseUpdate; - queue.lastBaseUpdate = newLastBaseUpdate; + for (var i = 0; i < keysA.length; i++) { + var currentKey = keysA[i]; - 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 (!hasOwnProperty.call(objB, currentKey) || // $FlowFixMe[incompatible-use] lost refinement of `objB` + !objectIs(objA[currentKey], objB[currentKey])) { + return false; + } + } - markSkippedUpdateLanes(newLanes); - workInProgress.lanes = newLanes; - workInProgress.memoizedState = newState; - } + return true; +} - { - currentlyProcessingQueue = null; - } +var current = null; +var isRendering = false; +function getCurrentFiberOwnerNameInDevOrNull() { + { + if (current === null) { + return null; } - function callCallback(callback, context) { - if (typeof callback !== "function") { - throw new Error( - "Invalid argument passed as callback. Expected a function. Instead " + - ("received: " + callback) - ); - } + var owner = current._debugOwner; - callback.call(context); + if (owner != null) { + return getComponentNameFromOwner(owner); } + } - 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; + return null; +} - if (newHiddenCallbacks !== null) { - var existingHiddenCallbacks = updateQueue.shared.hiddenCallbacks; +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. - 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; - if (hiddenCallbacks !== null) { - updateQueue.shared.hiddenCallbacks = null; + return getStackByFiberInDevAndProd(current); + } +} - for (var i = 0; i < hiddenCallbacks.length; i++) { - var callback = hiddenCallbacks[i]; - callCallback(callback, context); - } - } - } - function commitCallbacks(updateQueue, context) { - var callbacks = updateQueue.callbacks; +function resetCurrentFiber() { + { + ReactSharedInternals.getCurrentStack = null; + current = null; + isRendering = false; + } +} +function setCurrentFiber(fiber) { + { + ReactSharedInternals.getCurrentStack = fiber === null ? null : getCurrentFiberStackInDev; + current = fiber; + isRendering = false; + } +} +function getCurrentFiber() { + { + return current; + } +} +function setIsRendering(rendering) { + { + isRendering = rendering; + } +} - if (callbacks !== null) { - updateQueue.callbacks = null; +var ReactStrictModeWarnings = { + recordUnsafeLifecycleWarnings: function (fiber, instance) {}, + flushPendingUnsafeLifecycleWarnings: function () {}, + recordLegacyContextWarning: function (fiber, instance) {}, + flushLegacyContextWarning: function () {}, + discardPendingWarnings: function () {} +}; - for (var i = 0; i < callbacks.length; i++) { - var callback = callbacks[i]; - callCallback(callback, context); - } +{ + var findStrictRoot = function (fiber) { + var maybeStrictRoot = null; + var node = fiber; + + while (node !== null) { + if (node.mode & StrictLegacyMode) { + maybeStrictRoot = node; } + + node = node.return; } - // $FlowFixMe[method-unbinding] - var hasOwnProperty = Object.prototype.hasOwnProperty; + return maybeStrictRoot; + }; - /** - * 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. - */ + var setToSortedString = function (set) { + var array = []; + set.forEach(function (value) { + array.push(value); + }); + return array.sort().join(', '); + }; - function shallowEqual(objA, objB) { - if (objectIs(objA, objB)) { - return true; - } + var pendingComponentWillMountWarnings = []; + var pendingUNSAFE_ComponentWillMountWarnings = []; + var pendingComponentWillReceivePropsWarnings = []; + var pendingUNSAFE_ComponentWillReceivePropsWarnings = []; + var pendingComponentWillUpdateWarnings = []; + var pendingUNSAFE_ComponentWillUpdateWarnings = []; // Tracks components we have already warned about. - if ( - typeof objA !== "object" || - objA === null || - typeof objB !== "object" || - objB === null - ) { - return false; - } + var didWarnAboutUnsafeLifecycles = new Set(); - var keysA = Object.keys(objA); - var keysB = Object.keys(objB); + ReactStrictModeWarnings.recordUnsafeLifecycleWarnings = function (fiber, instance) { + // Dedupe strategy: Warn once per component. + if (didWarnAboutUnsafeLifecycles.has(fiber.type)) { + return; + } - if (keysA.length !== keysB.length) { - return false; - } // Test for A's keys different from B. + if (typeof instance.componentWillMount === 'function' && // Don't warn about react-lifecycles-compat polyfilled components. + instance.componentWillMount.__suppressDeprecationWarning !== true) { + pendingComponentWillMountWarnings.push(fiber); + } - for (var i = 0; i < keysA.length; i++) { - var currentKey = keysA[i]; + if (fiber.mode & StrictLegacyMode && typeof instance.UNSAFE_componentWillMount === 'function') { + pendingUNSAFE_ComponentWillMountWarnings.push(fiber); + } - if ( - !hasOwnProperty.call(objB, currentKey) || // $FlowFixMe[incompatible-use] lost refinement of `objB` - !objectIs(objA[currentKey], objB[currentKey]) - ) { - return false; - } - } + if (typeof instance.componentWillReceiveProps === 'function' && instance.componentWillReceiveProps.__suppressDeprecationWarning !== true) { + pendingComponentWillReceivePropsWarnings.push(fiber); + } - return true; + if (fiber.mode & StrictLegacyMode && typeof instance.UNSAFE_componentWillReceiveProps === 'function') { + pendingUNSAFE_ComponentWillReceivePropsWarnings.push(fiber); } - var current = null; - var isRendering = false; - function getCurrentFiberOwnerNameInDevOrNull() { - { - if (current === null) { - return null; - } + if (typeof instance.componentWillUpdate === 'function' && instance.componentWillUpdate.__suppressDeprecationWarning !== true) { + pendingComponentWillUpdateWarnings.push(fiber); + } - var owner = current._debugOwner; + if (fiber.mode & StrictLegacyMode && typeof instance.UNSAFE_componentWillUpdate === 'function') { + pendingUNSAFE_ComponentWillUpdateWarnings.push(fiber); + } + }; - if (owner != null) { - return getComponentNameFromOwner(owner); - } - } + ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = function () { + // We do an initial pass to gather component names + var componentWillMountUniqueNames = new Set(); - return null; + if (pendingComponentWillMountWarnings.length > 0) { + pendingComponentWillMountWarnings.forEach(function (fiber) { + componentWillMountUniqueNames.add(getComponentNameFromFiber(fiber) || 'Component'); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingComponentWillMountWarnings = []; } - 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. + var UNSAFE_componentWillMountUniqueNames = new Set(); - return getStackByFiberInDevAndProd(current); - } + if (pendingUNSAFE_ComponentWillMountWarnings.length > 0) { + pendingUNSAFE_ComponentWillMountWarnings.forEach(function (fiber) { + UNSAFE_componentWillMountUniqueNames.add(getComponentNameFromFiber(fiber) || 'Component'); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingUNSAFE_ComponentWillMountWarnings = []; } - function resetCurrentFiber() { - { - ReactSharedInternals.getCurrentStack = null; - current = null; - isRendering = false; - } - } - function setCurrentFiber(fiber) { - { - ReactSharedInternals.getCurrentStack = - fiber === null ? null : getCurrentFiberStackInDev; - current = fiber; - isRendering = false; - } - } - function getCurrentFiber() { - { - return current; - } - } - function setIsRendering(rendering) { - { - isRendering = rendering; - } + var componentWillReceivePropsUniqueNames = new Set(); + + if (pendingComponentWillReceivePropsWarnings.length > 0) { + pendingComponentWillReceivePropsWarnings.forEach(function (fiber) { + componentWillReceivePropsUniqueNames.add(getComponentNameFromFiber(fiber) || 'Component'); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingComponentWillReceivePropsWarnings = []; } - var ReactStrictModeWarnings = { - recordUnsafeLifecycleWarnings: function (fiber, instance) {}, - flushPendingUnsafeLifecycleWarnings: function () {}, - recordLegacyContextWarning: function (fiber, instance) {}, - flushLegacyContextWarning: function () {}, - discardPendingWarnings: function () {} - }; + var UNSAFE_componentWillReceivePropsUniqueNames = new Set(); - { - var findStrictRoot = function (fiber) { - var maybeStrictRoot = null; - var node = fiber; + if (pendingUNSAFE_ComponentWillReceivePropsWarnings.length > 0) { + pendingUNSAFE_ComponentWillReceivePropsWarnings.forEach(function (fiber) { + UNSAFE_componentWillReceivePropsUniqueNames.add(getComponentNameFromFiber(fiber) || 'Component'); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingUNSAFE_ComponentWillReceivePropsWarnings = []; + } - while (node !== null) { - if (node.mode & StrictLegacyMode) { - maybeStrictRoot = node; - } + var componentWillUpdateUniqueNames = new Set(); - node = node.return; - } + if (pendingComponentWillUpdateWarnings.length > 0) { + pendingComponentWillUpdateWarnings.forEach(function (fiber) { + componentWillUpdateUniqueNames.add(getComponentNameFromFiber(fiber) || 'Component'); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingComponentWillUpdateWarnings = []; + } - return maybeStrictRoot; - }; + var UNSAFE_componentWillUpdateUniqueNames = new Set(); - var setToSortedString = function (set) { - var array = []; - set.forEach(function (value) { - array.push(value); - }); - return array.sort().join(", "); - }; + 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 pendingComponentWillMountWarnings = []; - var pendingUNSAFE_ComponentWillMountWarnings = []; - var pendingComponentWillReceivePropsWarnings = []; - var pendingUNSAFE_ComponentWillReceivePropsWarnings = []; - var pendingComponentWillUpdateWarnings = []; - var pendingUNSAFE_ComponentWillUpdateWarnings = []; // Tracks components we have already warned about. - - var didWarnAboutUnsafeLifecycles = new Set(); - - ReactStrictModeWarnings.recordUnsafeLifecycleWarnings = function ( - fiber, - instance - ) { - // Dedupe strategy: Warn once per component. - if (didWarnAboutUnsafeLifecycles.has(fiber.type)) { - return; - } - if ( - typeof instance.componentWillMount === "function" && // Don't warn about react-lifecycles-compat polyfilled components. - instance.componentWillMount.__suppressDeprecationWarning !== true - ) { - pendingComponentWillMountWarnings.push(fiber); - } + if (UNSAFE_componentWillMountUniqueNames.size > 0) { + var sortedNames = setToSortedString(UNSAFE_componentWillMountUniqueNames); - if ( - fiber.mode & StrictLegacyMode && - typeof instance.UNSAFE_componentWillMount === "function" - ) { - pendingUNSAFE_ComponentWillMountWarnings.push(fiber); - } + error('Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code. ' + 'See https://react.dev/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 ( - typeof instance.componentWillReceiveProps === "function" && - instance.componentWillReceiveProps.__suppressDeprecationWarning !== - true - ) { - pendingComponentWillReceivePropsWarnings.push(fiber); - } + if (UNSAFE_componentWillReceivePropsUniqueNames.size > 0) { + var _sortedNames = setToSortedString(UNSAFE_componentWillReceivePropsUniqueNames); - if ( - fiber.mode & StrictLegacyMode && - typeof instance.UNSAFE_componentWillReceiveProps === "function" - ) { - pendingUNSAFE_ComponentWillReceivePropsWarnings.push(fiber); - } + error('Using UNSAFE_componentWillReceiveProps in strict mode is not recommended ' + 'and may indicate bugs in your code. ' + 'See https://react.dev/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://react.dev/link/derived-state\n' + '\nPlease update the following components: %s', _sortedNames); + } - if ( - typeof instance.componentWillUpdate === "function" && - instance.componentWillUpdate.__suppressDeprecationWarning !== true - ) { - pendingComponentWillUpdateWarnings.push(fiber); - } + if (UNSAFE_componentWillUpdateUniqueNames.size > 0) { + var _sortedNames2 = setToSortedString(UNSAFE_componentWillUpdateUniqueNames); - if ( - fiber.mode & StrictLegacyMode && - typeof instance.UNSAFE_componentWillUpdate === "function" - ) { - pendingUNSAFE_ComponentWillUpdateWarnings.push(fiber); - } - }; + error('Using UNSAFE_componentWillUpdate in strict mode is not recommended ' + 'and may indicate bugs in your code. ' + 'See https://react.dev/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); + } - ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = - function () { - // We do an initial pass to gather component names - var componentWillMountUniqueNames = new Set(); - - if (pendingComponentWillMountWarnings.length > 0) { - pendingComponentWillMountWarnings.forEach(function (fiber) { - componentWillMountUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingComponentWillMountWarnings = []; - } + if (componentWillMountUniqueNames.size > 0) { + var _sortedNames3 = setToSortedString(componentWillMountUniqueNames); - var UNSAFE_componentWillMountUniqueNames = new Set(); + warn('componentWillMount has been renamed, and is not recommended for use. ' + 'See https://react.dev/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); + } - if (pendingUNSAFE_ComponentWillMountWarnings.length > 0) { - pendingUNSAFE_ComponentWillMountWarnings.forEach(function (fiber) { - UNSAFE_componentWillMountUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingUNSAFE_ComponentWillMountWarnings = []; - } + if (componentWillReceivePropsUniqueNames.size > 0) { + var _sortedNames4 = setToSortedString(componentWillReceivePropsUniqueNames); - var componentWillReceivePropsUniqueNames = new Set(); + warn('componentWillReceiveProps has been renamed, and is not recommended for use. ' + 'See https://react.dev/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://react.dev/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 (pendingComponentWillReceivePropsWarnings.length > 0) { - pendingComponentWillReceivePropsWarnings.forEach(function (fiber) { - componentWillReceivePropsUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingComponentWillReceivePropsWarnings = []; - } + if (componentWillUpdateUniqueNames.size > 0) { + var _sortedNames5 = setToSortedString(componentWillUpdateUniqueNames); - var UNSAFE_componentWillReceivePropsUniqueNames = new Set(); + warn('componentWillUpdate has been renamed, and is not recommended for use. ' + 'See https://react.dev/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 (pendingUNSAFE_ComponentWillReceivePropsWarnings.length > 0) { - pendingUNSAFE_ComponentWillReceivePropsWarnings.forEach( - function (fiber) { - UNSAFE_componentWillReceivePropsUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - } - ); - pendingUNSAFE_ComponentWillReceivePropsWarnings = []; - } + var pendingLegacyContextWarning = new Map(); // Tracks components we have already warned about. - var componentWillUpdateUniqueNames = new Set(); + var didWarnAboutLegacyContext = new Set(); - if (pendingComponentWillUpdateWarnings.length > 0) { - pendingComponentWillUpdateWarnings.forEach(function (fiber) { - componentWillUpdateUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingComponentWillUpdateWarnings = []; - } + ReactStrictModeWarnings.recordLegacyContextWarning = function (fiber, instance) { + var strictRoot = findStrictRoot(fiber); - var UNSAFE_componentWillUpdateUniqueNames = new Set(); - - 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 (UNSAFE_componentWillMountUniqueNames.size > 0) { - var sortedNames = setToSortedString( - UNSAFE_componentWillMountUniqueNames - ); + 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.'); - error( - "Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code. " + - "See https://react.dev/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 - ); - } + return; + } // Dedup strategy: Warn once per component. - if (UNSAFE_componentWillReceivePropsUniqueNames.size > 0) { - var _sortedNames = setToSortedString( - UNSAFE_componentWillReceivePropsUniqueNames - ); - error( - "Using UNSAFE_componentWillReceiveProps in strict mode is not recommended " + - "and may indicate bugs in your code. " + - "See https://react.dev/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://react.dev/link/derived-state\n" + - "\nPlease update the following components: %s", - _sortedNames - ); - } + if (didWarnAboutLegacyContext.has(fiber.type)) { + return; + } - if (UNSAFE_componentWillUpdateUniqueNames.size > 0) { - var _sortedNames2 = setToSortedString( - UNSAFE_componentWillUpdateUniqueNames - ); + var warningsForRoot = pendingLegacyContextWarning.get(strictRoot); - error( - "Using UNSAFE_componentWillUpdate in strict mode is not recommended " + - "and may indicate bugs in your code. " + - "See https://react.dev/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 - ); - } + if (fiber.type.contextTypes != null || fiber.type.childContextTypes != null || instance !== null && typeof instance.getChildContext === 'function') { + if (warningsForRoot === undefined) { + warningsForRoot = []; + pendingLegacyContextWarning.set(strictRoot, warningsForRoot); + } - if (componentWillMountUniqueNames.size > 0) { - var _sortedNames3 = setToSortedString( - componentWillMountUniqueNames - ); + warningsForRoot.push(fiber); + } + }; - warn( - "componentWillMount has been renamed, and is not recommended for use. " + - "See https://react.dev/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 - ); - } + ReactStrictModeWarnings.flushLegacyContextWarning = function () { + pendingLegacyContextWarning.forEach(function (fiberArray, strictRoot) { + if (fiberArray.length === 0) { + return; + } - if (componentWillReceivePropsUniqueNames.size > 0) { - var _sortedNames4 = setToSortedString( - componentWillReceivePropsUniqueNames - ); + 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); - warn( - "componentWillReceiveProps has been renamed, and is not recommended for use. " + - "See https://react.dev/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://react.dev/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 - ); - } + try { + setCurrentFiber(firstFiber); - if (componentWillUpdateUniqueNames.size > 0) { - var _sortedNames5 = setToSortedString( - componentWillUpdateUniqueNames - ); + 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://react.dev/link/legacy-context', sortedNames); + } finally { + resetCurrentFiber(); + } + }); + }; + + ReactStrictModeWarnings.discardPendingWarnings = function () { + pendingComponentWillMountWarnings = []; + pendingUNSAFE_ComponentWillMountWarnings = []; + pendingComponentWillReceivePropsWarnings = []; + pendingUNSAFE_ComponentWillReceivePropsWarnings = []; + pendingComponentWillUpdateWarnings = []; + pendingUNSAFE_ComponentWillUpdateWarnings = []; + pendingLegacyContextWarning = new Map(); + }; +} - warn( - "componentWillUpdate has been renamed, and is not recommended for use. " + - "See https://react.dev/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 - ); - } - }; +function getThenablesFromState(state) { + { + var devState = state; + return devState.thenables; + } +} // 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. - var pendingLegacyContextWarning = new Map(); // Tracks components we have already warned about. - var didWarnAboutLegacyContext = new Set(); +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. - ReactStrictModeWarnings.recordLegacyContextWarning = function ( - fiber, - instance - ) { - var strictRoot = findStrictRoot(fiber); +var noopSuspenseyCommitThenable = { + then: function () { + { + error('Internal React error: A listener was unexpectedly attached to a ' + '"noop" thenable. This is a bug in React. Please file an issue.'); + } + } +}; +function createThenableState() { + // The ThenableState is created the first time a component suspends. If it + // suspends again, we'll reuse the same state. + { + return { + didWarnAboutUncachedPromise: false, + thenables: [] + }; + } +} +function isThenableResolved(thenable) { + var status = thenable.status; + return status === 'fulfilled' || status === 'rejected'; +} - 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." - ); +function noop() {} - return; - } // Dedup strategy: Warn once per component. +function trackUsedThenable(thenableState, thenable, index) { + if (ReactSharedInternals.actQueue !== null) { + ReactSharedInternals.didUsePromise = true; + } - if (didWarnAboutLegacyContext.has(fiber.type)) { - return; - } + var trackedThenables = getThenablesFromState(thenableState); + var previous = trackedThenables[index]; - var warningsForRoot = pendingLegacyContextWarning.get(strictRoot); + if (previous === undefined) { + trackedThenables.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. + { + var thenableStateDev = thenableState; - if ( - fiber.type.contextTypes != null || - fiber.type.childContextTypes != null || - (instance !== null && typeof instance.getChildContext === "function") - ) { - if (warningsForRoot === undefined) { - warningsForRoot = []; - pendingLegacyContextWarning.set(strictRoot, warningsForRoot); - } + if (!thenableStateDev.didWarnAboutUncachedPromise) { + // We should only warn the first time an uncached thenable is + // discovered per component, because if there are multiple, the + // subsequent ones are likely derived from the first. + // + // We track this on the thenableState instead of deduping using the + // component name like we usually do, because in the case of a + // promise-as-React-node, the owner component is likely different from + // the parent that's currently being reconciled. We'd have to track + // the owner using state, which we're trying to move away from. Though + // since this is dev-only, maybe that'd be OK. + // + // However, another benefit of doing it this way is we might + // eventually have a thenableState per memo/Forget boundary instead + // of per component, so this would allow us to have more + // granular warnings. + thenableStateDev.didWarnAboutUncachedPromise = true; // TODO: This warning should link to a corresponding docs page. - warningsForRoot.push(fiber); + error('A component was suspended by an uncached promise. Creating ' + 'promises inside a Client Component or hook is not yet ' + 'supported, except via a Suspense-compatible library or framework.'); } - }; + } // Avoid an unhandled rejection errors for the Promises that we'll + // intentionally ignore. - ReactStrictModeWarnings.flushLegacyContextWarning = function () { - pendingLegacyContextWarning.forEach(function (fiberArray, strictRoot) { - if (fiberArray.length === 0) { - return; - } - - 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); - - try { - setCurrentFiber(firstFiber); - - 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://react.dev/link/legacy-context", - sortedNames - ); - } finally { - resetCurrentFiber(); - } - }); - }; - ReactStrictModeWarnings.discardPendingWarnings = function () { - pendingComponentWillMountWarnings = []; - pendingUNSAFE_ComponentWillMountWarnings = []; - pendingComponentWillReceivePropsWarnings = []; - pendingUNSAFE_ComponentWillReceivePropsWarnings = []; - pendingComponentWillUpdateWarnings = []; - pendingUNSAFE_ComponentWillUpdateWarnings = []; - pendingLegacyContextWarning = new Map(); - }; + thenable.then(noop, noop); + thenable = previous; } + } // 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. - function getThenablesFromState(state) { - { - var devState = state; - return devState.thenables; - } - } // 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. - - 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 noopSuspenseyCommitThenable = { - then: function () { - { - error( - "Internal React error: A listener was unexpectedly attached to a " + - '"noop" thenable. This is a bug in React. Please file an issue.' - ); - } - } - }; - function createThenableState() { - // The ThenableState is created the first time a component suspends. If it - // suspends again, we'll reuse the same state. + + switch (thenable.status) { + case 'fulfilled': { - return { - didWarnAboutUncachedPromise: false, - thenables: [] - }; + var fulfilledValue = thenable.value; + return fulfilledValue; } - } - function isThenableResolved(thenable) { - var status = thenable.status; - return status === "fulfilled" || status === "rejected"; - } - - function noop() {} - function trackUsedThenable(thenableState, thenable, index) { - if (ReactSharedInternals.actQueue !== null) { - ReactSharedInternals.didUsePromise = true; + case 'rejected': + { + var rejectedError = thenable.reason; + checkIfUseWrappedInAsyncCatch(rejectedError); + throw rejectedError; } - var trackedThenables = getThenablesFromState(thenableState); - var previous = trackedThenables[index]; - - if (previous === undefined) { - trackedThenables.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. - { - var thenableStateDev = thenableState; - - if (!thenableStateDev.didWarnAboutUncachedPromise) { - // We should only warn the first time an uncached thenable is - // discovered per component, because if there are multiple, the - // subsequent ones are likely derived from the first. - // - // We track this on the thenableState instead of deduping using the - // component name like we usually do, because in the case of a - // promise-as-React-node, the owner component is likely different from - // the parent that's currently being reconciled. We'd have to track - // the owner using state, which we're trying to move away from. Though - // since this is dev-only, maybe that'd be OK. - // - // However, another benefit of doing it this way is we might - // eventually have a thenableState per memo/Forget boundary instead - // of per component, so this would allow us to have more - // granular warnings. - thenableStateDev.didWarnAboutUncachedPromise = true; // TODO: This warning should link to a corresponding docs page. - - error( - "A component was suspended by an uncached promise. Creating " + - "promises inside a Client Component or hook is not yet " + - "supported, except via a Suspense-compatible library or framework." - ); - } - } // Avoid an unhandled rejection errors for the Promises that we'll - // intentionally ignore. - + 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); - thenable = previous; - } - } // 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; - } + } else { + // This is an uncached thenable that we haven't seen before. + // Detect infinite ping loops caused by uncached promises. + var root = getWorkInProgressRoot(); - case "rejected": { - var rejectedError = thenable.reason; - checkIfUseWrappedInAsyncCatch(rejectedError); - throw rejectedError; - } + if (root !== null && root.shellSuspendCounter > 100) { + // This root has suspended repeatedly in the shell without making any + // progress (i.e. committing something). This is highly suggestive of + // an infinite ping loop, often caused by an accidental Async Client + // Component. + // + // During a transition, we can suspend the work loop until the promise + // to resolve, but this is a sync render, so that's not an option. We + // also can't show a fallback, because none was provided. So our last + // resort is to throw an error. + // + // TODO: Remove this error in a future release. Other ways of handling + // this case include forcing a concurrent render, or putting the whole + // root into offscreen mode. + throw new Error('async/await is not yet supported in Client Components, only ' + 'Server Components. This error is often caused by accidentally ' + "adding `'use client'` to a module that was originally written " + 'for the server.'); + } - 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 { - // This is an uncached thenable that we haven't seen before. - // Detect infinite ping loops caused by uncached promises. - var root = getWorkInProgressRoot(); - - if (root !== null && root.shellSuspendCounter > 100) { - // This root has suspended repeatedly in the shell without making any - // progress (i.e. committing something). This is highly suggestive of - // an infinite ping loop, often caused by an accidental Async Client - // Component. - // - // During a transition, we can suspend the work loop until the promise - // to resolve, but this is a sync render, so that's not an option. We - // also can't show a fallback, because none was provided. So our last - // resort is to throw an error. - // - // TODO: Remove this error in a future release. Other ways of handling - // this case include forcing a concurrent render, or putting the whole - // root into offscreen mode. - throw new Error( - "async/await is not yet supported in Client Components, only " + - "Server Components. This error is often caused by accidentally " + - "adding `'use client'` to a module that was originally written " + - "for the server." - ); + 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. - 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. - switch (thenable.status) { - case "fulfilled": { + switch (thenable.status) { + case 'fulfilled': + { var fulfilledThenable = thenable; return fulfilledThenable.value; } - case "rejected": { + case 'rejected': + { var rejectedThenable = thenable; var _rejectedError = rejectedThenable.reason; checkIfUseWrappedInAsyncCatch(_rejectedError); throw _rejectedError; } - } // 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. + } // 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. - suspendedThenable = thenable; - { - needsToResetSuspendedThenableDEV = true; - } + suspendedThenable = thenable; - throw SuspenseException; + { + needsToResetSuspendedThenableDEV = true; } + + throw SuspenseException; } + } +} +// 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.'); + } + + 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; } - // 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 false; +} +function checkIfUseWrappedInAsyncCatch(rejectedReason) { + // This check runs in prod, too, because it prevents a more confusing + // downstream error, where SuspenseException is caught by a promise and + // thrown asynchronously. + // TODO: Another way to prevent SuspenseException from leaking into an async + // execution context is to check the dispatcher every time `use` is called, + // or some equivalent. That might be preferable for other reasons, too, since + // it matches how we prevent similar mistakes for other hooks. + if (rejectedReason === SuspenseException) { + throw new Error('Hooks are not supported inside an async component. This ' + "error is often caused by accidentally adding `'use client'` " + 'to a module that was originally written for the server.'); + } +} - var thenable = suspendedThenable; - suspendedThenable = null; +var thenableState$1 = null; +var thenableIndexCounter$1 = 0; + +function mergeDebugInfo(outer, inner) { + + if (inner == null) { + return outer; + } else if (outer === null) { + return inner; + } else { + // If we have two debugInfo, we need to create a new one. This makes the array no longer + // live so we'll miss any future updates if we received more so ideally we should always + // do this after both have fully resolved/unsuspended. + return outer.concat(inner); + } +} - { - needsToResetSuspendedThenableDEV = false; - } +var didWarnAboutMaps; +var didWarnAboutGenerators; +var ownerHasKeyUseWarning; +var ownerHasFunctionTypeWarning; +var ownerHasSymbolTypeWarning; - 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 warnForMissingKey = function (child, returnFiber) {}; - return false; +{ + didWarnAboutMaps = false; + didWarnAboutGenerators = false; + /** + * 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 = {}; + ownerHasSymbolTypeWarning = {}; + + warnForMissingKey = function (child, returnFiber) { + if (child === null || typeof child !== 'object') { + return; } - function checkIfUseWrappedInAsyncCatch(rejectedReason) { - // This check runs in prod, too, because it prevents a more confusing - // downstream error, where SuspenseException is caught by a promise and - // thrown asynchronously. - // TODO: Another way to prevent SuspenseException from leaking into an async - // execution context is to check the dispatcher every time `use` is called, - // or some equivalent. That might be preferable for other reasons, too, since - // it matches how we prevent similar mistakes for other hooks. - if (rejectedReason === SuspenseException) { - throw new Error( - "Hooks are not supported inside an async component. This " + - "error is often caused by accidentally adding `'use client'` " + - "to a module that was originally written for the server." - ); - } - } - - var thenableState$1 = null; - var thenableIndexCounter$1 = 0; - - function mergeDebugInfo(outer, inner) { - if (inner == null) { - return outer; - } else if (outer === null) { - return inner; - } else { - // If we have two debugInfo, we need to create a new one. This makes the array no longer - // live so we'll miss any future updates if we received more so ideally we should always - // do this after both have fully resolved/unsuspended. - return outer.concat(inner); - } + + if (!child._store || child._store.validated || child.key != null) { + return; } - var didWarnAboutMaps; - var didWarnAboutGenerators; - var ownerHasKeyUseWarning; - var ownerHasFunctionTypeWarning; - var ownerHasSymbolTypeWarning; + 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[cannot-write] unable to narrow type from mixed to writable object - var warnForMissingKey = function (child, returnFiber) {}; - { - didWarnAboutMaps = false; - didWarnAboutGenerators = false; - /** - * 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 = {}; - ownerHasSymbolTypeWarning = {}; - - warnForMissingKey = function (child, returnFiber) { - if (child === null || typeof child !== "object") { - return; - } + child._store.validated = true; + var componentName = getComponentNameFromFiber(returnFiber) || 'Component'; - if (!child._store || child._store.validated || child.key != null) { - return; - } + if (ownerHasKeyUseWarning[componentName]) { + return; + } - 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[cannot-write] unable to narrow type from mixed to writable object + ownerHasKeyUseWarning[componentName] = true; - child._store.validated = true; - var componentName = - getComponentNameFromFiber(returnFiber) || "Component"; + error('Each child in a list should have a unique ' + '"key" prop. See https://react.dev/link/warning-keys for ' + 'more information.'); + }; +} - if (ownerHasKeyUseWarning[componentName]) { - return; - } +function unwrapThenable(thenable) { + var index = thenableIndexCounter$1; + thenableIndexCounter$1 += 1; - ownerHasKeyUseWarning[componentName] = true; + if (thenableState$1 === null) { + thenableState$1 = createThenableState(); + } - error( - "Each child in a list should have a unique " + - '"key" prop. See https://react.dev/link/warning-keys for ' + - "more information." - ); - }; - } + return trackUsedThenable(thenableState$1, thenable, index); +} - function unwrapThenable(thenable) { - var index = thenableIndexCounter$1; - thenableIndexCounter$1 += 1; +function coerceRef(returnFiber, current, workInProgress, element) { + var ref; - if (thenableState$1 === null) { - thenableState$1 = createThenableState(); - } + { + // Old behavior. + ref = element.ref; + } // TODO: If enableRefAsProp is on, we shouldn't use the `ref` field. We + // should always read the ref from the prop. - return trackUsedThenable(thenableState$1, thenable, index); - } - function coerceRef(returnFiber, current, workInProgress, element) { - var ref; + workInProgress.ref = ref; +} - { - // Old behavior. - ref = element.ref; - } // TODO: If enableRefAsProp is on, we shouldn't use the `ref` field. We - // should always read the ref from the prop. +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.'); +} - workInProgress.ref = ref; - } +function warnOnFunctionType(returnFiber, invalidChild) { + { + var parentName = getComponentNameFromFiber(returnFiber) || 'Component'; - 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." - ); + if (ownerHasFunctionTypeWarning[parentName]) { + return; } - function warnOnFunctionType(returnFiber, invalidChild) { - { - var parentName = getComponentNameFromFiber(returnFiber) || "Component"; - - if (ownerHasFunctionTypeWarning[parentName]) { - return; - } + ownerHasFunctionTypeWarning[parentName] = true; + var name = invalidChild.displayName || invalidChild.name || 'Component'; - ownerHasFunctionTypeWarning[parentName] = true; - var name = invalidChild.displayName || invalidChild.name || "Component"; - - if (returnFiber.tag === HostRoot) { - error( - "Functions are not valid as a React child. This may happen if " + - "you return %s instead of <%s /> from render. " + - "Or maybe you meant to call this function rather than return it.\n" + - " root.render(%s)", - name, - name, - name - ); - } else { - error( - "Functions are not valid as a React child. This may happen if " + - "you return %s instead of <%s /> from render. " + - "Or maybe you meant to call this function rather than return it.\n" + - " <%s>{%s}", - name, - name, - parentName, - name, - parentName - ); - } - } + if (returnFiber.tag === HostRoot) { + error('Functions are not valid as a React child. This may happen if ' + 'you return %s instead of <%s /> from render. ' + 'Or maybe you meant to call this function rather than return it.\n' + ' root.render(%s)', name, name, name); + } else { + error('Functions are not valid as a React child. This may happen if ' + 'you return %s instead of <%s /> from render. ' + 'Or maybe you meant to call this function rather than return it.\n' + ' <%s>{%s}', name, name, parentName, name, parentName); } + } +} - function warnOnSymbolType(returnFiber, invalidChild) { - { - var parentName = getComponentNameFromFiber(returnFiber) || "Component"; +function warnOnSymbolType(returnFiber, invalidChild) { + { + var parentName = getComponentNameFromFiber(returnFiber) || 'Component'; - if (ownerHasSymbolTypeWarning[parentName]) { - return; - } + if (ownerHasSymbolTypeWarning[parentName]) { + return; + } - ownerHasSymbolTypeWarning[parentName] = true; // eslint-disable-next-line react-internal/safe-string-coercion + ownerHasSymbolTypeWarning[parentName] = true; // eslint-disable-next-line react-internal/safe-string-coercion - var name = String(invalidChild); + var name = String(invalidChild); - if (returnFiber.tag === HostRoot) { - error( - "Symbols are not valid as a React child.\n" + " root.render(%s)", - name - ); - } else { - error( - "Symbols are not valid as a React child.\n" + " <%s>%s", - parentName, - name, - parentName - ); - } - } + if (returnFiber.tag === HostRoot) { + error('Symbols are not valid as a React child.\n' + ' root.render(%s)', name); + } else { + error('Symbols are not valid as a React child.\n' + ' <%s>%s', parentName, name, parentName); } + } +} - 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. +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. - function createChildReconciler(shouldTrackSideEffects) { - function deleteChild(returnFiber, childToDelete) { - if (!shouldTrackSideEffects) { - // Noop. - return; - } - var deletions = returnFiber.deletions; +function createChildReconciler(shouldTrackSideEffects) { + function deleteChild(returnFiber, childToDelete) { + if (!shouldTrackSideEffects) { + // Noop. + return; + } - if (deletions === null) { - returnFiber.deletions = [childToDelete]; - returnFiber.flags |= ChildDeletion; - } else { - deletions.push(childToDelete); - } - } + var deletions = returnFiber.deletions; - 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 (deletions === null) { + returnFiber.deletions = [childToDelete]; + returnFiber.flags |= ChildDeletion; + } else { + deletions.push(childToDelete); + } + } - var childToDelete = currentFirstChild; + 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. - while (childToDelete !== null) { - deleteChild(returnFiber, childToDelete); - childToDelete = childToDelete.sibling; - } - return null; - } + var childToDelete = currentFirstChild; - function mapRemainingChildren(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; + while (childToDelete !== null) { + deleteChild(returnFiber, childToDelete); + childToDelete = childToDelete.sibling; + } - while (existingChild !== null) { - if (existingChild.key !== null) { - existingChildren.set(existingChild.key, existingChild); - } else { - existingChildren.set(existingChild.index, existingChild); - } + return null; + } - existingChild = existingChild.sibling; - } + function mapRemainingChildren(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; - return existingChildren; + while (existingChild !== null) { + if (existingChild.key !== null) { + existingChildren.set(existingChild.key, existingChild); + } else { + existingChildren.set(existingChild.index, existingChild); } - 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; - } + existingChild = existingChild.sibling; + } - function placeChild(newFiber, lastPlacedIndex, newIndex) { - newFiber.index = newIndex; + return existingChildren; + } - 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; - } + 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; + } - var current = newFiber.alternate; + function placeChild(newFiber, lastPlacedIndex, newIndex) { + newFiber.index = newIndex; - if (current !== null) { - var oldIndex = current.index; + 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 (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; - } - } + var current = newFiber.alternate; - 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; - } + if (current !== null) { + var oldIndex = current.index; - return newFiber; - } - - function updateTextNode( - returnFiber, - current, - textContent, - lanes, - debugInfo - ) { - if (current === null || current.tag !== HostText) { - // Insert - var created = createFiberFromText( - textContent, - returnFiber.mode, - lanes - ); - created.return = returnFiber; + 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; + } + } - { - created._debugInfo = debugInfo; - } + 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; + } - return created; - } else { - // Update - var existing = useFiber(current, textContent); - existing.return = returnFiber; + return newFiber; + } - { - existing._debugInfo = debugInfo; - } + function updateTextNode(returnFiber, current, textContent, lanes, debugInfo) { + if (current === null || current.tag !== HostText) { + // Insert + var created = createFiberFromText(textContent, returnFiber.mode, lanes); + created.return = returnFiber; - return existing; - } + { + created._debugInfo = debugInfo; } - function updateElement(returnFiber, current, element, lanes, debugInfo) { - var elementType = element.type; + return created; + } else { + // Update + var existing = useFiber(current, textContent); + existing.return = returnFiber; - if (elementType === REACT_FRAGMENT_TYPE) { - return updateFragment( - returnFiber, - current, - element.props.children, - lanes, - element.key, - debugInfo - ); - } + { + existing._debugInfo = debugInfo; + } - 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); - coerceRef(returnFiber, current, existing, element); - existing.return = returnFiber; + return existing; + } + } - { - existing._debugOwner = element._owner; - existing._debugInfo = debugInfo; - } + function updateElement(returnFiber, current, element, lanes, debugInfo) { + var elementType = element.type; - return existing; - } - } // Insert + if (elementType === REACT_FRAGMENT_TYPE) { + return updateFragment(returnFiber, current, element.props.children, lanes, element.key, debugInfo); + } - var created = createFiberFromElement(element, returnFiber.mode, lanes); - coerceRef(returnFiber, current, created, element); - created.return = returnFiber; + 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); + coerceRef(returnFiber, current, existing, element); + existing.return = returnFiber; { - created._debugInfo = debugInfo; + existing._debugOwner = element._owner; + existing._debugInfo = debugInfo; } - return created; + return existing; } + } // Insert - function updatePortal(returnFiber, current, portal, lanes, debugInfo) { - 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; - { - created._debugInfo = debugInfo; - } + var created = createFiberFromElement(element, returnFiber.mode, lanes); + coerceRef(returnFiber, current, created, element); + created.return = returnFiber; - return created; - } else { - // Update - var existing = useFiber(current, portal.children || []); - existing.return = returnFiber; + { + created._debugInfo = debugInfo; + } - { - existing._debugInfo = debugInfo; - } + return created; + } - return existing; - } + function updatePortal(returnFiber, current, portal, lanes, debugInfo) { + 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; + + { + created._debugInfo = debugInfo; } - function updateFragment( - returnFiber, - current, - fragment, - lanes, - key, - debugInfo - ) { - 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, portal.children || []); + existing.return = returnFiber; - { - created._debugInfo = debugInfo; - } + { + existing._debugInfo = debugInfo; + } - return created; - } else { - // Update - var existing = useFiber(current, fragment); - existing.return = returnFiber; + return existing; + } + } - { - existing._debugInfo = debugInfo; - } + function updateFragment(returnFiber, current, fragment, lanes, key, debugInfo) { + if (current === null || current.tag !== Fragment) { + // Insert + var created = createFiberFromFragment(fragment, returnFiber.mode, lanes, key); + created.return = returnFiber; - return existing; - } + { + created._debugInfo = debugInfo; } - function createChild(returnFiber, newChild, lanes, debugInfo) { - if ( - (typeof newChild === "string" && newChild !== "") || - typeof newChild === "number" || - typeof newChild === "bigint" - ) { - // 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( - // $FlowFixMe[unsafe-addition] Flow doesn't want us to use `+` operator with string and bigint - "" + newChild, - returnFiber.mode, - lanes - ); - created.return = returnFiber; - - { - created._debugInfo = debugInfo; - } - - return created; - } + return created; + } else { + // Update + var existing = useFiber(current, fragment); + existing.return = returnFiber; - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: { - var _created = createFiberFromElement( - newChild, - returnFiber.mode, - lanes - ); + { + existing._debugInfo = debugInfo; + } - coerceRef(returnFiber, null, _created, newChild); - _created.return = returnFiber; + return existing; + } + } - { - _created._debugInfo = mergeDebugInfo( - debugInfo, - newChild._debugInfo - ); - } + function createChild(returnFiber, newChild, lanes, debugInfo) { + if (typeof newChild === 'string' && newChild !== '' || typeof newChild === 'number' || typeof newChild === 'bigint') { + // 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( // $FlowFixMe[unsafe-addition] Flow doesn't want us to use `+` operator with string and bigint + '' + newChild, returnFiber.mode, lanes); + created.return = returnFiber; - return _created; - } + { + created._debugInfo = debugInfo; + } - case REACT_PORTAL_TYPE: { - var _created2 = createFiberFromPortal( - newChild, - returnFiber.mode, - lanes - ); + return created; + } - _created2.return = returnFiber; + if (typeof newChild === 'object' && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + { + var _created = createFiberFromElement(newChild, returnFiber.mode, lanes); - { - _created2._debugInfo = debugInfo; - } + coerceRef(returnFiber, null, _created, newChild); + _created.return = returnFiber; - return _created2; + { + _created._debugInfo = mergeDebugInfo(debugInfo, newChild._debugInfo); } - case REACT_LAZY_TYPE: { - var payload = newChild._payload; - var init = newChild._init; - return createChild( - returnFiber, - init(payload), - lanes, - mergeDebugInfo(debugInfo, newChild._debugInfo) // call merge after init - ); - } + return _created; } - if (isArray(newChild) || getIteratorFn(newChild)) { - var _created3 = createFiberFromFragment( - newChild, - returnFiber.mode, - lanes, - null - ); + case REACT_PORTAL_TYPE: + { + var _created2 = createFiberFromPortal(newChild, returnFiber.mode, lanes); - _created3.return = returnFiber; + _created2.return = returnFiber; { - _created3._debugInfo = mergeDebugInfo( - debugInfo, - newChild._debugInfo - ); + _created2._debugInfo = debugInfo; } - return _created3; - } // Usable node types - // - // Unwrap the inner value and recursively call this function again. - - if (typeof newChild.then === "function") { - var thenable = newChild; - return createChild( - returnFiber, - unwrapThenable(thenable), - lanes, - mergeDebugInfo(debugInfo, newChild._debugInfo) - ); + return _created2; } - if (newChild.$$typeof === REACT_CONTEXT_TYPE) { - var context = newChild; - return createChild( - returnFiber, - readContextDuringReconciliation(returnFiber, context, lanes), - lanes, - debugInfo + case REACT_LAZY_TYPE: + { + var payload = newChild._payload; + var init = newChild._init; + return createChild(returnFiber, init(payload), lanes, mergeDebugInfo(debugInfo, newChild._debugInfo) // call merge after init ); } + } - throwOnInvalidObjectType(returnFiber, newChild); - } + if (isArray(newChild) || getIteratorFn(newChild)) { + var _created3 = createFiberFromFragment(newChild, returnFiber.mode, lanes, null); - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber, newChild); - } + _created3.return = returnFiber; - if (typeof newChild === "symbol") { - warnOnSymbolType(returnFiber, newChild); - } + { + _created3._debugInfo = mergeDebugInfo(debugInfo, newChild._debugInfo); } - return null; + return _created3; + } // Usable node types + // + // Unwrap the inner value and recursively call this function again. + + + if (typeof newChild.then === 'function') { + var thenable = newChild; + return createChild(returnFiber, unwrapThenable(thenable), lanes, mergeDebugInfo(debugInfo, newChild._debugInfo)); } - function updateSlot(returnFiber, oldFiber, newChild, lanes, debugInfo) { - // Update the fiber if the keys match, otherwise return null. - var key = oldFiber !== null ? oldFiber.key : null; + if (newChild.$$typeof === REACT_CONTEXT_TYPE) { + var context = newChild; + return createChild(returnFiber, readContextDuringReconciliation(returnFiber, context, lanes), lanes, debugInfo); + } - if ( - (typeof newChild === "string" && newChild !== "") || - typeof newChild === "number" || - typeof newChild === "bigint" - ) { - // 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; - } + throwOnInvalidObjectType(returnFiber, newChild); + } - return updateTextNode( - returnFiber, - oldFiber, // $FlowFixMe[unsafe-addition] Flow doesn't want us to use `+` operator with string and bigint - "" + newChild, - lanes, - debugInfo - ); - } + { + if (typeof newChild === 'function') { + warnOnFunctionType(returnFiber, newChild); + } - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: { - if (newChild.key === key) { - return updateElement( - returnFiber, - oldFiber, - newChild, - lanes, - mergeDebugInfo(debugInfo, newChild._debugInfo) - ); - } else { - return null; - } - } + if (typeof newChild === 'symbol') { + warnOnSymbolType(returnFiber, newChild); + } + } - case REACT_PORTAL_TYPE: { - if (newChild.key === key) { - return updatePortal( - returnFiber, - oldFiber, - newChild, - lanes, - debugInfo - ); - } else { - return null; - } - } + return null; + } - case REACT_LAZY_TYPE: { - var payload = newChild._payload; - var init = newChild._init; - return updateSlot( - returnFiber, - oldFiber, - init(payload), - lanes, - mergeDebugInfo(debugInfo, newChild._debugInfo) - ); - } - } + function updateSlot(returnFiber, oldFiber, newChild, lanes, debugInfo) { + // Update the fiber if the keys match, otherwise return null. + var key = oldFiber !== null ? oldFiber.key : null; - if (isArray(newChild) || getIteratorFn(newChild)) { - if (key !== null) { + if (typeof newChild === 'string' && newChild !== '' || typeof newChild === 'number' || typeof newChild === 'bigint') { + // 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; + } + + return updateTextNode(returnFiber, oldFiber, // $FlowFixMe[unsafe-addition] Flow doesn't want us to use `+` operator with string and bigint + '' + newChild, lanes, debugInfo); + } + + if (typeof newChild === 'object' && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + { + if (newChild.key === key) { + return updateElement(returnFiber, oldFiber, newChild, lanes, mergeDebugInfo(debugInfo, newChild._debugInfo)); + } else { return null; } + } - return updateFragment( - returnFiber, - oldFiber, - newChild, - lanes, - null, - mergeDebugInfo(debugInfo, newChild._debugInfo) - ); - } // 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, - debugInfo - ); + case REACT_PORTAL_TYPE: + { + if (newChild.key === key) { + return updatePortal(returnFiber, oldFiber, newChild, lanes, debugInfo); + } else { + return null; + } } - if (newChild.$$typeof === REACT_CONTEXT_TYPE) { - var context = newChild; - return updateSlot( - returnFiber, - oldFiber, - readContextDuringReconciliation(returnFiber, context, lanes), - lanes, - debugInfo - ); + case REACT_LAZY_TYPE: + { + var payload = newChild._payload; + var init = newChild._init; + return updateSlot(returnFiber, oldFiber, init(payload), lanes, mergeDebugInfo(debugInfo, newChild._debugInfo)); } + } - throwOnInvalidObjectType(returnFiber, newChild); + if (isArray(newChild) || getIteratorFn(newChild)) { + if (key !== null) { + return null; } - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber, newChild); - } + return updateFragment(returnFiber, oldFiber, newChild, lanes, null, mergeDebugInfo(debugInfo, newChild._debugInfo)); + } // Usable node types + // + // Unwrap the inner value and recursively call this function again. - if (typeof newChild === "symbol") { - warnOnSymbolType(returnFiber, newChild); - } - } - return null; + if (typeof newChild.then === 'function') { + var thenable = newChild; + return updateSlot(returnFiber, oldFiber, unwrapThenable(thenable), lanes, debugInfo); } - function updateFromMap( - existingChildren, - returnFiber, - newIdx, - newChild, - lanes, - debugInfo - ) { - if ( - (typeof newChild === "string" && newChild !== "") || - typeof newChild === "number" || - typeof newChild === "bigint" - ) { - // 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, // $FlowFixMe[unsafe-addition] Flow doesn't want us to use `+` operator with string and bigint - "" + newChild, - lanes, - debugInfo - ); - } - - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: { - var _matchedFiber = - existingChildren.get( - newChild.key === null ? newIdx : newChild.key - ) || null; - - return updateElement( - returnFiber, - _matchedFiber, - newChild, - lanes, - mergeDebugInfo(debugInfo, newChild._debugInfo) - ); - } + if (newChild.$$typeof === REACT_CONTEXT_TYPE) { + var context = newChild; + return updateSlot(returnFiber, oldFiber, readContextDuringReconciliation(returnFiber, context, lanes), lanes, debugInfo); + } - case REACT_PORTAL_TYPE: { - var _matchedFiber2 = - existingChildren.get( - newChild.key === null ? newIdx : newChild.key - ) || null; - - return updatePortal( - returnFiber, - _matchedFiber2, - newChild, - lanes, - debugInfo - ); - } + throwOnInvalidObjectType(returnFiber, newChild); + } - case REACT_LAZY_TYPE: - var payload = newChild._payload; - var init = newChild._init; - return updateFromMap( - existingChildren, - returnFiber, - newIdx, - init(payload), - lanes, - mergeDebugInfo(debugInfo, newChild._debugInfo) - ); - } + { + if (typeof newChild === 'function') { + warnOnFunctionType(returnFiber, newChild); + } - if (isArray(newChild) || getIteratorFn(newChild)) { - var _matchedFiber3 = existingChildren.get(newIdx) || null; + if (typeof newChild === 'symbol') { + warnOnSymbolType(returnFiber, newChild); + } + } - return updateFragment( - returnFiber, - _matchedFiber3, - newChild, - lanes, - null, - mergeDebugInfo(debugInfo, newChild._debugInfo) - ); - } // Usable node types - // - // Unwrap the inner value and recursively call this function again. - - if (typeof newChild.then === "function") { - var thenable = newChild; - return updateFromMap( - existingChildren, - returnFiber, - newIdx, - unwrapThenable(thenable), - lanes, - debugInfo - ); - } + return null; + } - if (newChild.$$typeof === REACT_CONTEXT_TYPE) { - var context = newChild; - return updateFromMap( - existingChildren, - returnFiber, - newIdx, - readContextDuringReconciliation(returnFiber, context, lanes), - lanes, - debugInfo - ); - } + function updateFromMap(existingChildren, returnFiber, newIdx, newChild, lanes, debugInfo) { + if (typeof newChild === 'string' && newChild !== '' || typeof newChild === 'number' || typeof newChild === 'bigint') { + // 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, // $FlowFixMe[unsafe-addition] Flow doesn't want us to use `+` operator with string and bigint + '' + newChild, lanes, debugInfo); + } - throwOnInvalidObjectType(returnFiber, newChild); - } + 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 (typeof newChild === "function") { - warnOnFunctionType(returnFiber, newChild); + return updateElement(returnFiber, _matchedFiber, newChild, lanes, mergeDebugInfo(debugInfo, newChild._debugInfo)); } - if (typeof newChild === "symbol") { - warnOnSymbolType(returnFiber, newChild); + case REACT_PORTAL_TYPE: + { + var _matchedFiber2 = existingChildren.get(newChild.key === null ? newIdx : newChild.key) || null; + + return updatePortal(returnFiber, _matchedFiber2, newChild, lanes, debugInfo); } - } - return null; + case REACT_LAZY_TYPE: + var payload = newChild._payload; + var init = newChild._init; + return updateFromMap(existingChildren, returnFiber, newIdx, init(payload), lanes, mergeDebugInfo(debugInfo, newChild._debugInfo)); } - /** - * Warns if there is a duplicate or missing key - */ - function warnOnInvalidKey(child, knownKeys, returnFiber) { - { - if (typeof child !== "object" || child === null) { - return knownKeys; - } + if (isArray(newChild) || getIteratorFn(newChild)) { + var _matchedFiber3 = existingChildren.get(newIdx) || null; - switch (child.$$typeof) { - case REACT_ELEMENT_TYPE: - case REACT_PORTAL_TYPE: - warnForMissingKey(child, returnFiber); - var key = child.key; + return updateFragment(returnFiber, _matchedFiber3, newChild, lanes, null, mergeDebugInfo(debugInfo, newChild._debugInfo)); + } // Usable node types + // + // Unwrap the inner value and recursively call this function again. - if (typeof key !== "string") { - break; - } - if (knownKeys === null) { - knownKeys = new Set(); - knownKeys.add(key); - break; - } + if (typeof newChild.then === 'function') { + var thenable = newChild; + return updateFromMap(existingChildren, returnFiber, newIdx, unwrapThenable(thenable), lanes, debugInfo); + } - if (!knownKeys.has(key)) { - knownKeys.add(key); - break; - } + if (newChild.$$typeof === REACT_CONTEXT_TYPE) { + var context = newChild; + return updateFromMap(existingChildren, returnFiber, newIdx, readContextDuringReconciliation(returnFiber, context, lanes), lanes, debugInfo); + } - 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 - ); + throwOnInvalidObjectType(returnFiber, newChild); + } - break; + { + if (typeof newChild === 'function') { + warnOnFunctionType(returnFiber, newChild); + } - case REACT_LAZY_TYPE: - var payload = child._payload; - var init = child._init; - warnOnInvalidKey(init(payload), knownKeys, returnFiber); - break; - } - } + if (typeof newChild === 'symbol') { + warnOnSymbolType(returnFiber, newChild); + } + } + return null; + } + /** + * Warns if there is a duplicate or missing key + */ + + + function warnOnInvalidKey(child, knownKeys, returnFiber) { + { + if (typeof child !== 'object' || child === null) { return knownKeys; } - function reconcileChildrenArray( - returnFiber, - currentFirstChild, - newChildren, - lanes, - debugInfo - ) { - // 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; + switch (child.$$typeof) { + case REACT_ELEMENT_TYPE: + case REACT_PORTAL_TYPE: + warnForMissingKey(child, returnFiber); + var key = child.key; - for (var i = 0; i < newChildren.length; i++) { - var child = newChildren[i]; - knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber); + if (typeof key !== 'string') { + break; } - } - 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 (knownKeys === null) { + knownKeys = new Set(); + knownKeys.add(key); + break; } - var newFiber = updateSlot( - returnFiber, - oldFiber, - newChildren[newIdx], - lanes, - debugInfo - ); - - 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 (!knownKeys.has(key)) { + knownKeys.add(key); 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); - } - } + 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); - lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); + break; - 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; - } + case REACT_LAZY_TYPE: + var payload = child._payload; + var init = child._init; + warnOnInvalidKey(init(payload), knownKeys, returnFiber); + break; + } + } - previousNewFiber = newFiber; - oldFiber = nextOldFiber; - } + return knownKeys; + } + + function reconcileChildrenArray(returnFiber, currentFirstChild, newChildren, lanes, debugInfo) { + // 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; + + for (var i = 0; i < newChildren.length; i++) { + var child = newChildren[i]; + knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber); + } + } - if (newIdx === newChildren.length) { - // We've reached the end of the new children. We can delete the rest. - deleteRemainingChildren(returnFiber, oldFiber); + var resultingFirstChild = null; + var previousNewFiber = null; + var oldFiber = currentFirstChild; + var lastPlacedIndex = 0; + var newIdx = 0; + var nextOldFiber = null; - return resultingFirstChild; - } + for (; oldFiber !== null && newIdx < newChildren.length; newIdx++) { + if (oldFiber.index > newIdx) { + nextOldFiber = oldFiber; + oldFiber = null; + } else { + nextOldFiber = oldFiber.sibling; + } - 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, - debugInfo - ); + var newFiber = updateSlot(returnFiber, oldFiber, newChildren[newIdx], lanes, debugInfo); - if (_newFiber === null) { - continue; - } + 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; + } - lastPlacedIndex = placeChild(_newFiber, lastPlacedIndex, newIdx); + break; + } - if (previousNewFiber === null) { - // TODO: Move out of the loop. This only happens for the first run. - resultingFirstChild = _newFiber; - } else { - previousNewFiber.sibling = _newFiber; - } + 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); + } + } - previousNewFiber = _newFiber; - } + lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); - return resultingFirstChild; - } // Add all children to a key map for quick lookups. - - var existingChildren = mapRemainingChildren(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, - debugInfo - ); - - 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 - ); - } - } + 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; + } - lastPlacedIndex = placeChild(_newFiber2, lastPlacedIndex, newIdx); + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } - if (previousNewFiber === null) { - resultingFirstChild = _newFiber2; - } else { - previousNewFiber.sibling = _newFiber2; - } + if (newIdx === newChildren.length) { + // We've reached the end of the new children. We can delete the rest. + deleteRemainingChildren(returnFiber, oldFiber); - previousNewFiber = _newFiber2; - } - } + return resultingFirstChild; + } - 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); - }); - } + 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, debugInfo); - return resultingFirstChild; - } - - function reconcileChildrenIterator( - returnFiber, - currentFirstChild, - newChildrenIterable, - lanes, - debugInfo - ) { - // This is the same implementation as reconcileChildrenArray(), - // but using the iterator instead. - var iteratorFn = getIteratorFn(newChildrenIterable); - - 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." - ); + if (_newFiber === null) { + continue; } - { - // We don't support rendering Generators because it's a mutation. - // See https://github.com/facebook/react/issues/12995 - if ( - typeof Symbol === "function" && // $FlowFixMe[prop-missing] 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." - ); - } + lastPlacedIndex = placeChild(_newFiber, lastPlacedIndex, newIdx); - didWarnAboutGenerators = true; - } // Warn about using Maps as children + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = _newFiber; + } else { + previousNewFiber.sibling = _newFiber; + } - if (newChildrenIterable.entries === iteratorFn) { - if (!didWarnAboutMaps) { - error( - "Using Maps as children is not supported. " + - "Use an array of keyed ReactElements instead." - ); - } + previousNewFiber = _newFiber; + } - didWarnAboutMaps = true; - } // First, validate keys. - // We'll get a different iterator later for the main pass. + return resultingFirstChild; + } // Add all children to a key map for quick lookups. - var _newChildren = iteratorFn.call(newChildrenIterable); - if (_newChildren) { - var knownKeys = null; + var existingChildren = mapRemainingChildren(oldFiber); // Keep scanning and use the map to restore deleted items as moves. - var _step = _newChildren.next(); + for (; newIdx < newChildren.length; newIdx++) { + var _newFiber2 = updateFromMap(existingChildren, returnFiber, newIdx, newChildren[newIdx], lanes, debugInfo); - for (; !_step.done; _step = _newChildren.next()) { - var child = _step.value; - knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber); - } + 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); } } - var newChildren = iteratorFn.call(newChildrenIterable); + lastPlacedIndex = placeChild(_newFiber2, lastPlacedIndex, newIdx); - if (newChildren == null) { - throw new Error("An iterable object provided no iterator."); + if (previousNewFiber === null) { + resultingFirstChild = _newFiber2; + } else { + previousNewFiber.sibling = _newFiber2; } - var resultingFirstChild = null; - var previousNewFiber = null; - var oldFiber = currentFirstChild; - var lastPlacedIndex = 0; - var newIdx = 0; - var nextOldFiber = null; - var step = newChildren.next(); - - for ( - ; - oldFiber !== null && !step.done; - newIdx++, step = newChildren.next() - ) { - if (oldFiber.index > newIdx) { - nextOldFiber = oldFiber; - oldFiber = null; - } else { - nextOldFiber = oldFiber.sibling; - } - - var newFiber = updateSlot( - returnFiber, - oldFiber, - step.value, - lanes, - debugInfo - ); - - 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; - } + previousNewFiber = _newFiber2; + } + } - break; - } + 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); + }); + } - 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); - } - } + return resultingFirstChild; + } - lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); + function reconcileChildrenIterator(returnFiber, currentFirstChild, newChildrenIterable, lanes, debugInfo) { + // This is the same implementation as reconcileChildrenArray(), + // but using the iterator instead. + var iteratorFn = getIteratorFn(newChildrenIterable); - 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 (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.'); + } - previousNewFiber = newFiber; - oldFiber = nextOldFiber; + { + // We don't support rendering Generators because it's a mutation. + // See https://github.com/facebook/react/issues/12995 + if (typeof Symbol === 'function' && // $FlowFixMe[prop-missing] 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.'); } - if (step.done) { - // We've reached the end of the new children. We can delete the rest. - deleteRemainingChildren(returnFiber, oldFiber); + didWarnAboutGenerators = true; + } // Warn about using Maps as children + - return resultingFirstChild; + if (newChildrenIterable.entries === iteratorFn) { + if (!didWarnAboutMaps) { + error('Using Maps as children is not supported. ' + 'Use an array of keyed ReactElements instead.'); } - 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, - debugInfo - ); + didWarnAboutMaps = true; + } // First, validate keys. + // We'll get a different iterator later for the main pass. - if (_newFiber3 === null) { - continue; - } - lastPlacedIndex = placeChild(_newFiber3, lastPlacedIndex, newIdx); + var _newChildren = iteratorFn.call(newChildrenIterable); - if (previousNewFiber === null) { - // TODO: Move out of the loop. This only happens for the first run. - resultingFirstChild = _newFiber3; - } else { - previousNewFiber.sibling = _newFiber3; - } + if (_newChildren) { + var knownKeys = null; - previousNewFiber = _newFiber3; - } + var _step = _newChildren.next(); - return resultingFirstChild; - } // Add all children to a key map for quick lookups. - - var existingChildren = mapRemainingChildren(oldFiber); // Keep scanning and use the map to restore deleted items as moves. - - for (; !step.done; newIdx++, step = newChildren.next()) { - var _newFiber4 = updateFromMap( - existingChildren, - returnFiber, - newIdx, - step.value, - lanes, - debugInfo - ); - - 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 - ); - } - } + for (; !_step.done; _step = _newChildren.next()) { + var child = _step.value; + knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber); + } + } + } - lastPlacedIndex = placeChild(_newFiber4, lastPlacedIndex, newIdx); + var newChildren = iteratorFn.call(newChildrenIterable); - if (previousNewFiber === null) { - resultingFirstChild = _newFiber4; - } else { - previousNewFiber.sibling = _newFiber4; - } + if (newChildren == null) { + throw new Error('An iterable object provided no iterator.'); + } - previousNewFiber = _newFiber4; - } + var resultingFirstChild = null; + var previousNewFiber = null; + var oldFiber = currentFirstChild; + var lastPlacedIndex = 0; + var newIdx = 0; + var nextOldFiber = null; + var step = newChildren.next(); + + for (; oldFiber !== null && !step.done; newIdx++, step = newChildren.next()) { + if (oldFiber.index > newIdx) { + nextOldFiber = oldFiber; + oldFiber = null; + } else { + nextOldFiber = oldFiber.sibling; + } + + var newFiber = updateSlot(returnFiber, oldFiber, step.value, lanes, debugInfo); + + 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 (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); - }); + 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); } + } - return resultingFirstChild; - } - - 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; - } - - function reconcileSingleElement( - returnFiber, - currentFirstChild, - element, - lanes, - debugInfo - ) { - var key = element.key; - var child = currentFirstChild; - - 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 (elementType === REACT_FRAGMENT_TYPE) { - if (child.tag === Fragment) { - deleteRemainingChildren(returnFiber, child.sibling); - var existing = useFiber(child, element.props.children); - existing.return = returnFiber; + lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); - { - existing._debugOwner = element._owner; - existing._debugInfo = debugInfo; - } + 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; + } - 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); + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } - var _existing = useFiber(child, element.props); + if (step.done) { + // We've reached the end of the new children. We can delete the rest. + deleteRemainingChildren(returnFiber, oldFiber); - coerceRef(returnFiber, child, _existing, element); - _existing.return = returnFiber; + return resultingFirstChild; + } - { - _existing._debugOwner = element._owner; - _existing._debugInfo = debugInfo; - } + 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, debugInfo); - return _existing; - } - } // Didn't match. + if (_newFiber3 === null) { + continue; + } - deleteRemainingChildren(returnFiber, child); - break; - } else { - deleteChild(returnFiber, child); - } + lastPlacedIndex = placeChild(_newFiber3, lastPlacedIndex, newIdx); - child = child.sibling; + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = _newFiber3; + } else { + previousNewFiber.sibling = _newFiber3; } - if (element.type === REACT_FRAGMENT_TYPE) { - var created = createFiberFromFragment( - element.props.children, - returnFiber.mode, - lanes, - element.key - ); - created.return = returnFiber; + previousNewFiber = _newFiber3; + } - { - created._debugInfo = debugInfo; - } + return resultingFirstChild; + } // Add all children to a key map for quick lookups. - return created; - } else { - var _created4 = createFiberFromElement( - element, - returnFiber.mode, - lanes - ); - coerceRef(returnFiber, currentFirstChild, _created4, element); - _created4.return = returnFiber; + var existingChildren = mapRemainingChildren(oldFiber); // Keep scanning and use the map to restore deleted items as moves. - { - _created4._debugInfo = debugInfo; - } + for (; !step.done; newIdx++, step = newChildren.next()) { + var _newFiber4 = updateFromMap(existingChildren, returnFiber, newIdx, step.value, lanes, debugInfo); - return _created4; + 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); + } } - } - function reconcileSinglePortal( - returnFiber, - currentFirstChild, - portal, - lanes, - debugInfo - ) { - var key = portal.key; - var child = currentFirstChild; - - 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); - } + lastPlacedIndex = placeChild(_newFiber4, lastPlacedIndex, newIdx); - child = child.sibling; + if (previousNewFiber === null) { + resultingFirstChild = _newFiber4; + } else { + previousNewFiber.sibling = _newFiber4; } - 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 reconcileChildFibersImpl( - returnFiber, - currentFirstChild, - newChild, - lanes, - debugInfo - ) { - // This function is only recursive for Usables/Lazy and not nested arrays. - // That's so that using a Lazy wrapper is unobservable to the Fragment - // convention. - // 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. - // We don't use recursion here because a fragment inside a fragment - // is no longer considered "top level" for these purposes. - var isUnkeyedTopLevelFragment = - typeof newChild === "object" && - newChild !== null && - newChild.type === REACT_FRAGMENT_TYPE && - newChild.key === null; - - if (isUnkeyedTopLevelFragment) { - newChild = newChild.props.children; - } // Handle object types - - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: - return placeSingleChild( - reconcileSingleElement( - returnFiber, - currentFirstChild, - newChild, - lanes, - mergeDebugInfo(debugInfo, newChild._debugInfo) - ) - ); - - case REACT_PORTAL_TYPE: - return placeSingleChild( - reconcileSinglePortal( - returnFiber, - currentFirstChild, - newChild, - lanes - ) - ); - - case REACT_LAZY_TYPE: - var payload = newChild._payload; - var init = newChild._init; - return reconcileChildFibersImpl( - returnFiber, - currentFirstChild, - init(payload), - lanes, - mergeDebugInfo(debugInfo, newChild._debugInfo) - ); - } - - if (isArray(newChild)) { - return reconcileChildrenArray( - returnFiber, - currentFirstChild, - newChild, - lanes, - mergeDebugInfo(debugInfo, newChild._debugInfo) - ); - } + previousNewFiber = _newFiber4; + } + } - if (getIteratorFn(newChild)) { - return reconcileChildrenIterator( - returnFiber, - currentFirstChild, - newChild, - lanes, - mergeDebugInfo(debugInfo, newChild._debugInfo) - ); - } // 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 (typeof newChild.then === "function") { - var thenable = newChild; - return reconcileChildFibersImpl( - returnFiber, - currentFirstChild, - unwrapThenable(thenable), - lanes, - mergeDebugInfo(debugInfo, thenable._debugInfo) - ); - } + 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); + }); + } - if (newChild.$$typeof === REACT_CONTEXT_TYPE) { - var context = newChild; - return reconcileChildFibersImpl( - returnFiber, - currentFirstChild, - readContextDuringReconciliation(returnFiber, context, lanes), - lanes, - debugInfo - ); - } + return resultingFirstChild; + } + + 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; + } + + function reconcileSingleElement(returnFiber, currentFirstChild, element, lanes, debugInfo) { + var key = element.key; + var child = currentFirstChild; + + 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; - throwOnInvalidObjectType(returnFiber, newChild); - } + if (elementType === REACT_FRAGMENT_TYPE) { + if (child.tag === Fragment) { + deleteRemainingChildren(returnFiber, child.sibling); + var existing = useFiber(child, element.props.children); + existing.return = returnFiber; - if ( - (typeof newChild === "string" && newChild !== "") || - typeof newChild === "number" || - typeof newChild === "bigint" - ) { - return placeSingleChild( - reconcileSingleTextNode( - returnFiber, - currentFirstChild, // $FlowFixMe[unsafe-addition] Flow doesn't want us to use `+` operator with string and bigint - "" + newChild, - lanes - ) - ); - } + { + existing._debugOwner = element._owner; + existing._debugInfo = debugInfo; + } - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber, newChild); + 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 (typeof newChild === "symbol") { - warnOnSymbolType(returnFiber, newChild); - } - } // Remaining cases are all treated as empty. + var _existing = useFiber(child, element.props); - return deleteRemainingChildren(returnFiber, currentFirstChild); - } + coerceRef(returnFiber, child, _existing, element); + _existing.return = returnFiber; - 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, - null // debugInfo - ); - thenableState$1 = null; // Don't bother to reset `thenableIndexCounter` to 0 because it always gets - // set at the beginning. + { + _existing._debugOwner = element._owner; + _existing._debugInfo = debugInfo; + } - return firstChildFiber; - } + return _existing; + } + } // Didn't match. - return reconcileChildFibers; - } - 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."); + deleteRemainingChildren(returnFiber, child); + break; + } else { + deleteChild(returnFiber, child); } - if (workInProgress.child === null) { - return; - } + child = child.sibling; + } - var currentChild = workInProgress.child; - var newChild = createWorkInProgress( - currentChild, - currentChild.pendingProps - ); - workInProgress.child = newChild; - newChild.return = workInProgress; + if (element.type === REACT_FRAGMENT_TYPE) { + var created = createFiberFromFragment(element.props.children, returnFiber.mode, lanes, element.key); + created.return = returnFiber; - while (currentChild.sibling !== null) { - currentChild = currentChild.sibling; - newChild = newChild.sibling = createWorkInProgress( - currentChild, - currentChild.pendingProps - ); - newChild.return = workInProgress; + { + created._debugInfo = debugInfo; } - newChild.sibling = null; - } // Reset a workInProgress child set to prepare it for a second pass. + return created; + } else { + var _created4 = createFiberFromElement(element, returnFiber.mode, lanes); - function resetChildFibers(workInProgress, lanes) { - var child = workInProgress.child; + coerceRef(returnFiber, currentFirstChild, _created4, element); + _created4.return = returnFiber; - while (child !== null) { - resetWorkInProgress(child, lanes); - child = child.sibling; + { + _created4._debugInfo = debugInfo; } - } - // TODO: This isn't being used yet, but it's intended to replace the - // InvisibleParentContext that is currently managed by SuspenseContext. + return _created4; + } + } - var currentTreeHiddenStackCursor = createCursor(null); - var prevEntangledRenderLanesCursor = createCursor(NoLanes); - function pushHiddenContext(fiber, context) { - var prevEntangledRenderLanes = getEntangledRenderLanes(); - push(prevEntangledRenderLanesCursor, prevEntangledRenderLanes, 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 reconcileSinglePortal(returnFiber, currentFirstChild, portal, lanes, debugInfo) { + var key = portal.key; + var child = currentFirstChild; - setEntangledRenderLanes( - mergeLanes(prevEntangledRenderLanes, 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(prevEntangledRenderLanesCursor, getEntangledRenderLanes(), fiber); - push( - currentTreeHiddenStackCursor, - currentTreeHiddenStackCursor.current, - fiber - ); - } - function popHiddenContext(fiber) { - // Restore the previous render lanes from the stack - setEntangledRenderLanes(prevEntangledRenderLanesCursor.current); - pop(currentTreeHiddenStackCursor, fiber); - pop(prevEntangledRenderLanesCursor, fiber); - } - function isCurrentTreeHidden() { - return currentTreeHiddenStackCursor.current !== null; - } - - // suspends, i.e. it's the nearest `catch` block on the stack. - - 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; + 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 { - var prevState = current.memoizedState; - - if (prevState !== null) { - // This boundary is showing a fallback in the current UI. - shellBoundary = handler; - } + deleteRemainingChildren(returnFiber, child); + break; } + } else { + deleteChild(returnFiber, child); } + + child = child.sibling; } - 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; + 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. - 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; - } - } - } - } else { - // This is a LegacyHidden component. - reuseSuspenseHandlerOnStack(fiber); + function reconcileChildFibersImpl(returnFiber, currentFirstChild, newChild, lanes, debugInfo) { + // This function is only recursive for Usables/Lazy and not nested arrays. + // That's so that using a Lazy wrapper is unobservable to the Fragment + // convention. + // 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. + // We don't use recursion here because a fragment inside a fragment + // is no longer considered "top level" for these purposes. + var isUnkeyedTopLevelFragment = typeof newChild === 'object' && newChild !== null && newChild.type === REACT_FRAGMENT_TYPE && newChild.key === null; + + if (isUnkeyedTopLevelFragment) { + newChild = newChild.props.children; + } // Handle object types + + + if (typeof newChild === 'object' && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return placeSingleChild(reconcileSingleElement(returnFiber, currentFirstChild, newChild, lanes, mergeDebugInfo(debugInfo, newChild._debugInfo))); + + case REACT_PORTAL_TYPE: + return placeSingleChild(reconcileSinglePortal(returnFiber, currentFirstChild, newChild, lanes)); + + case REACT_LAZY_TYPE: + var payload = newChild._payload; + var init = newChild._init; + return reconcileChildFibersImpl(returnFiber, currentFirstChild, init(payload), lanes, mergeDebugInfo(debugInfo, newChild._debugInfo)); } - } - 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; + if (isArray(newChild)) { + return reconcileChildrenArray(returnFiber, currentFirstChild, newChild, lanes, mergeDebugInfo(debugInfo, newChild._debugInfo)); } - popSuspenseListContext(fiber); - } // SuspenseList context - // TODO: Move to a separate module? We may change the SuspenseList - // implementation to hide/show in the commit phase, anyway. + if (getIteratorFn(newChild)) { + return reconcileChildrenIterator(returnFiber, currentFirstChild, newChild, lanes, mergeDebugInfo(debugInfo, newChild._debugInfo)); + } // 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. + - 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. + if (typeof newChild.then === 'function') { + var thenable = newChild; + return reconcileChildFibersImpl(returnFiber, currentFirstChild, unwrapThenable(thenable), lanes, mergeDebugInfo(debugInfo, thenable._debugInfo)); + } - 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); + if (newChild.$$typeof === REACT_CONTEXT_TYPE) { + var context = newChild; + return reconcileChildFibersImpl(returnFiber, currentFirstChild, readContextDuringReconciliation(returnFiber, context, lanes), lanes, debugInfo); + } + + throwOnInvalidObjectType(returnFiber, newChild); } - function popSuspenseListContext(fiber) { - pop(suspenseStackCursor, fiber); + + if (typeof newChild === 'string' && newChild !== '' || typeof newChild === 'number' || typeof newChild === 'bigint') { + return placeSingleChild(reconcileSingleTextNode(returnFiber, currentFirstChild, // $FlowFixMe[unsafe-addition] Flow doesn't want us to use `+` operator with string and bigint + '' + newChild, lanes)); } - // 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. + { + if (typeof newChild === 'function') { + warnOnFunctionType(returnFiber, newChild); + } - function findFirstSuspended(row) { - var node = row; + if (typeof newChild === 'symbol') { + warnOnSymbolType(returnFiber, newChild); + } + } // Remaining cases are all treated as empty. - while (node !== null) { - if (node.tag === SuspenseComponent) { - var state = node.memoizedState; - if (state !== null) { - var dehydrated = state.dehydrated; + return deleteRemainingChildren(returnFiber, currentFirstChild); + } - if ( - dehydrated === null || - isSuspenseInstancePending() || - isSuspenseInstanceFallback() - ) { - return node; - } - } - } 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; - } - } else if (node.child !== null) { - node.child.return = node; - node = node.child; - continue; - } + 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, null // debugInfo + ); + thenableState$1 = null; // Don't bother to reset `thenableIndexCounter` to 0 because it always gets + // set at the beginning. - if (node === row) { - return null; - } + return firstChildFiber; + } - while (node.sibling === null) { - if (node.return === null || node.return === row) { - return null; - } + return reconcileChildFibers; +} - node = node.return; - } +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 (workInProgress.child === null) { + return; + } + + var currentChild = workInProgress.child; + var newChild = createWorkInProgress(currentChild, currentChild.pendingProps); + workInProgress.child = newChild; + newChild.return = workInProgress; + + while (currentChild.sibling !== null) { + currentChild = currentChild.sibling; + newChild = newChild.sibling = createWorkInProgress(currentChild, currentChild.pendingProps); + newChild.return = workInProgress; + } + + newChild.sibling = null; +} // Reset a workInProgress child set to prepare it for a second pass. + +function resetChildFibers(workInProgress, lanes) { + var child = workInProgress.child; + + while (child !== null) { + resetWorkInProgress(child, lanes); + child = child.sibling; + } +} - node.sibling.return = node.return; - node = node.sibling; - } +// TODO: This isn't being used yet, but it's intended to replace the +// InvisibleParentContext that is currently managed by SuspenseContext. - return null; - } +var currentTreeHiddenStackCursor = createCursor(null); +var prevEntangledRenderLanesCursor = createCursor(NoLanes); +function pushHiddenContext(fiber, context) { + var prevEntangledRenderLanes = getEntangledRenderLanes(); + push(prevEntangledRenderLanesCursor, prevEntangledRenderLanes, 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. + + setEntangledRenderLanes(mergeLanes(prevEntangledRenderLanes, 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(prevEntangledRenderLanesCursor, getEntangledRenderLanes(), fiber); + push(currentTreeHiddenStackCursor, currentTreeHiddenStackCursor.current, fiber); +} +function popHiddenContext(fiber) { + // Restore the previous render lanes from the stack + setEntangledRenderLanes(prevEntangledRenderLanesCursor.current); + pop(currentTreeHiddenStackCursor, fiber); + pop(prevEntangledRenderLanesCursor, fiber); +} +function isCurrentTreeHidden() { + return currentTreeHiddenStackCursor.current !== null; +} - var NoFlags = - /* */ - 0; // Represents whether effect should fire. +// suspends, i.e. it's the nearest `catch` block on the stack. + +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. - var HasEffect = - /* */ - 1; // Represents the phase in which the effect (not the clean-up) fires. + 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. - var Insertion = - /* */ - 2; - var Layout = - /* */ - 4; - var Passive = - /* */ - 8; - var didWarnAboutMismatchedHooksForComponent; - var didWarnUncachedGetSnapshot; - var didWarnAboutUseWrappedInTryCatch; - var didWarnAboutAsyncClientComponent; - var didWarnAboutUseFormState; + push(suspenseHandlerStackCursor, handler, handler); - { - didWarnAboutMismatchedHooksForComponent = new Set(); - didWarnAboutUseWrappedInTryCatch = new Set(); - didWarnAboutAsyncClientComponent = new Set(); - didWarnAboutUseFormState = new Set(); - } // The effect "instance" is a shared object that remains the same for the entire - // lifetime of an effect. In Rust terms, a RefCell. We use it to store the - // "destroy" function that is returned from an effect, because that is stateful. - // The field is `undefined` if the effect is unmounted, or if the effect ran - // but is not stateful. We don't explicitly track whether the effect is mounted - // or unmounted because that can be inferred by the hiddenness of the fiber in - // the tree, i.e. whether there is a hidden Offscreen fiber above it. - // - // It's unfortunate that this is stored on a separate object, because it adds - // more memory per effect instance, but it's conceptually sound. I think there's - // likely a better data structure we could use for effects; perhaps just one - // array of effect instances per fiber. But I think this is OK for now despite - // the additional memory and we can follow up with performance - // optimizations later. - // These are set right before calling the component. - - var renderLanes = 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`. - - var didScheduleRenderPhaseUpdateDuringThisPass = false; - var shouldDoubleInvokeUserFnsInHooksDEV = false; // Counts the number of useId hooks in this component. - - 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. - - var globalClientIdCounter = 0; - var RE_RENDER_LIMIT = 25; // In DEV, this is the name of the currently executing primitive hook - - 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. - - 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 (shellBoundary === null) { + if (current === null || isCurrentTreeHidden()) { + // This boundary is not visible in the current UI. + shellBoundary = handler; + } else { + var prevState = current.memoizedState; - if (hookTypesDev === null) { - hookTypesDev = [hookName]; - } else { - hookTypesDev.push(hookName); - } + 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 (shellBoundary !== null) ; else { + var current = fiber.alternate; - function updateHookTypesDev() { - { - var hookName = currentHookNameInDev; - - if (hookTypesDev !== null) { - hookTypesUpdateIndexDev++; + if (current !== null) { + var prevState = current.memoizedState; - if (hookTypesDev[hookTypesUpdateIndexDev] !== hookName) { - warnOnHookMismatchInDev(hookName); - } + 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; } } } + } 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. + +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 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); +} - 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 - ); - } - } - } +// 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 warnOnHookMismatchInDev(currentHookName) { - { - var componentName = getComponentNameFromFiber( - currentlyRenderingFiber$1 - ); - - if (!didWarnAboutMismatchedHooksForComponent.has(componentName)) { - didWarnAboutMismatchedHooksForComponent.add(componentName); - - if (hookTypesDev !== null) { - var table = ""; - var secondColumnStart = 30; - - 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 - - while (row.length < secondColumnStart) { - row += " "; - } +function findFirstSuspended(row) { + var node = row; - row += newHookName + "\n"; - table += row; - } + while (node !== null) { + if (node.tag === SuspenseComponent) { + var state = node.memoizedState; - 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://react.dev/link/rules-of-hooks\n\n" + - " Previous render Next render\n" + - " ------------------------------------------------------\n" + - "%s" + - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - componentName, - table - ); - } - } - } - } + if (state !== null) { + var dehydrated = state.dehydrated; - function warnOnUseFormStateInDev() { - { - var componentName = getComponentNameFromFiber( - currentlyRenderingFiber$1 - ); - - if (!didWarnAboutUseFormState.has(componentName)) { - didWarnAboutUseFormState.add(componentName); - - error( - "ReactDOM.useFormState has been renamed to React.useActionState. " + - "Please update %s to use React.useActionState.", - componentName - ); + if (dehydrated === null || isSuspenseInstancePending() || isSuspenseInstanceFallback()) { + return node; } } - } + } 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; - function warnIfAsyncClientComponent(Component) { - { - // This dev-only check only works for detecting native async functions, - // not transpiled ones. There's also a prod check that we use to prevent - // async client components from crashing the app; the prod one works even - // for transpiled async functions. Neither mechanism is completely - // bulletproof but together they cover the most common cases. - var isAsyncFunction = // $FlowIgnore[method-unbinding] - Object.prototype.toString.call(Component) === - "[object AsyncFunction]"; - - if (isAsyncFunction) { - // Encountered an async Client Component. This is not yet supported. - var componentName = getComponentNameFromFiber( - currentlyRenderingFiber$1 - ); - - if (!didWarnAboutAsyncClientComponent.has(componentName)) { - didWarnAboutAsyncClientComponent.add(componentName); - - error( - "async/await is not yet supported in Client Components, only " + - "Server Components. This error is often caused by accidentally " + - "adding `'use client'` to a module that was originally written " + - "for the server." - ); - } - } + if (didSuspend) { + return node; } + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; } - 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://react.dev/link/invalid-hook-call for tips about how to debug and fix this problem." - ); + if (node === row) { + return null; } - function areHookInputsEqual(nextDeps, prevDeps) { - { - if (ignorePreviousDependencies) { - // Only true when this component is being hot reloaded. - return false; - } + while (node.sibling === null) { + if (node.return === null || node.return === row) { + return null; } - if (prevDeps === null) { - { - 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 - ); - } + node = node.return; + } - return false; - } + node.sibling.return = node.return; + node = node.sibling; + } - { - // 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 + return 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; - } +var NoFlags = +/* */ +0; // Represents whether effect should fire. + +var HasEffect = +/* */ +1; // Represents the phase in which the effect (not the clean-up) fires. + +var Insertion = +/* */ +2; +var Layout = +/* */ +4; +var Passive = +/* */ +8; + +var didWarnAboutMismatchedHooksForComponent; +var didWarnUncachedGetSnapshot; +var didWarnAboutUseWrappedInTryCatch; +var didWarnAboutAsyncClientComponent; +var didWarnAboutUseFormState; + +{ + didWarnAboutMismatchedHooksForComponent = new Set(); + didWarnAboutUseWrappedInTryCatch = new Set(); + didWarnAboutAsyncClientComponent = new Set(); + didWarnAboutUseFormState = new Set(); +} // The effect "instance" is a shared object that remains the same for the entire +// lifetime of an effect. In Rust terms, a RefCell. We use it to store the +// "destroy" function that is returned from an effect, because that is stateful. +// The field is `undefined` if the effect is unmounted, or if the effect ran +// but is not stateful. We don't explicitly track whether the effect is mounted +// or unmounted because that can be inferred by the hiddenness of the fiber in +// the tree, i.e. whether there is a hidden Offscreen fiber above it. +// +// It's unfortunate that this is stored on a separate object, because it adds +// more memory per effect instance, but it's conceptually sound. I think there's +// likely a better data structure we could use for effects; perhaps just one +// array of effect instances per fiber. But I think this is OK for now despite +// the additional memory and we can follow up with performance +// optimizations later. +// These are set right before calling the component. + + +var renderLanes = 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`. + +var didScheduleRenderPhaseUpdateDuringThisPass = false; +var shouldDoubleInvokeUserFnsInHooksDEV = false; // Counts the number of useId hooks in this component. + +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. + +var globalClientIdCounter = 0; +var RE_RENDER_LIMIT = 25; // In DEV, this is the name of the currently executing primitive hook + +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. + +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 { + hookTypesDev.push(hookName); + } + } +} - return false; +function updateHookTypesDev() { + { + var hookName = currentHookNameInDev; + + if (hookTypesDev !== null) { + hookTypesUpdateIndexDev++; + + if (hookTypesDev[hookTypesUpdateIndexDev] !== hookName) { + warnOnHookMismatchInDev(hookName); } + } + } +} - return true; +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 renderWithHooks( - current, - workInProgress, - Component, - props, - secondArg, - nextRenderLanes - ) { - renderLanes = nextRenderLanes; - currentlyRenderingFiber$1 = workInProgress; +function warnOnHookMismatchInDev(currentHookName) { + { + var componentName = getComponentNameFromFiber(currentlyRenderingFiber$1); - { - hookTypesDev = current !== null ? current._debugHookTypes : null; - hookTypesUpdateIndexDev = -1; // Used for hot reloading: + if (!didWarnAboutMismatchedHooksForComponent.has(componentName)) { + didWarnAboutMismatchedHooksForComponent.add(componentName); - ignorePreviousDependencies = - current !== null && current.type !== workInProgress.type; - warnIfAsyncClientComponent(Component); - } + if (hookTypesDev !== null) { + var table = ''; + var secondColumnStart = 30; - 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. + 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 (current !== null && current.memoizedState !== null) { - ReactSharedInternals.H = 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. - ReactSharedInternals.H = HooksDispatcherOnMountWithHookTypesInDEV; - } else { - ReactSharedInternals.H = 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. + while (row.length < secondColumnStart) { + row += ' '; + } - var shouldDoubleRenderDEV = debugRenderPhaseSideEffectsForStrictMode; - shouldDoubleInvokeUserFnsInHooksDEV = shouldDoubleRenderDEV; - var children = Component(props, secondArg); - shouldDoubleInvokeUserFnsInHooksDEV = false; // Check if there was a render phase update + row += newHookName + '\n'; + table += row; + } - if (didScheduleRenderPhaseUpdateDuringThisPass) { - // Keep rendering until the component stabilizes (there are no more render - // phase updates). - children = renderWithHooksAgain( - workInProgress, - Component, - props, - secondArg - ); + 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://react.dev/link/rules-of-hooks\n\n' + ' Previous render Next render\n' + ' ------------------------------------------------------\n' + '%s' + ' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n', componentName, table); } - - finishRenderingHooks(current, workInProgress); - return children; } + } +} - function finishRenderingHooks(current, workInProgress, Component) { - { - workInProgress._debugHookTypes = hookTypesDev; - } // 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. +function warnOnUseFormStateInDev() { + { + var componentName = getComponentNameFromFiber(currentlyRenderingFiber$1); - ReactSharedInternals.H = ContextOnlyDispatcher; // 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. + if (!didWarnAboutUseFormState.has(componentName)) { + didWarnAboutUseFormState.add(componentName); - var didRenderTooFewHooks = - currentHook !== null && currentHook.next !== null; - renderLanes = NoLanes; - currentlyRenderingFiber$1 = null; - currentHook = null; - workInProgressHook = null; + error('ReactDOM.useFormState has been renamed to React.useActionState. ' + 'Please update %s to use React.useActionState.', componentName); + } + } +} - { - 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( - "Internal React error: Expected static flag was missing. Please " + - "notify the React team." - ); - } - } +function warnIfAsyncClientComponent(Component) { + { + // This dev-only check only works for detecting native async functions, + // not transpiled ones. There's also a prod check that we use to prevent + // async client components from crashing the app; the prod one works even + // for transpiled async functions. Neither mechanism is completely + // bulletproof but together they cover the most common cases. + var isAsyncFunction = // $FlowIgnore[method-unbinding] + Object.prototype.toString.call(Component) === '[object AsyncFunction]'; - didScheduleRenderPhaseUpdate = false; // This is reset by checkDidRenderIdHook - // localIdCounter = 0; + if (isAsyncFunction) { + // Encountered an async Client Component. This is not yet supported. + var componentName = getComponentNameFromFiber(currentlyRenderingFiber$1); - thenableIndexCounter = 0; - thenableState = null; + if (!didWarnAboutAsyncClientComponent.has(componentName)) { + didWarnAboutAsyncClientComponent.add(componentName); - if (didRenderTooFewHooks) { - throw new Error( - "Rendered fewer hooks than expected. This may be caused by an accidental " + - "early return statement." - ); + error('async/await is not yet supported in Client Components, only ' + 'Server Components. This error is often caused by accidentally ' + "adding `'use client'` to a module that was originally written " + 'for the server.'); } + } + } +} - { - if (checkIfUseWrappedInTryCatch()) { - var componentName = - getComponentNameFromFiber(workInProgress) || "Unknown"; - - if ( - !didWarnAboutUseWrappedInTryCatch.has(componentName) && // This warning also fires if you suspend with `use` inside an - // async component. Since we warn for that above, we'll silence this - // second warning by checking here. - !didWarnAboutAsyncClientComponent.has(componentName) - ) { - didWarnAboutUseWrappedInTryCatch.add(componentName); - - 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." - ); - } - } - } +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://react.dev/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; } + } - 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 (prevDeps === null) { + { + 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); + } - ignorePreviousDependencies = - current !== null && current.type !== workInProgress.type; - } + return false; + } - var children = renderWithHooksAgain( - workInProgress, - Component, - props, - secondArg - ); - finishRenderingHooks(current, workInProgress); - return children; + { + // 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 - 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. - currentlyRenderingFiber$1 = workInProgress; - 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; - } + 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; + } - thenableIndexCounter = 0; - didScheduleRenderPhaseUpdateDuringThisPass = false; + return false; + } - if (numberOfReRenders >= RE_RENDER_LIMIT) { - throw new Error( - "Too many re-renders. React limits the number of renders to prevent " + - "an infinite loop." - ); - } + return true; +} - numberOfReRenders += 1; +function renderWithHooks(current, workInProgress, Component, props, secondArg, nextRenderLanes) { + renderLanes = nextRenderLanes; + currentlyRenderingFiber$1 = workInProgress; + + { + hookTypesDev = current !== null ? current._debugHookTypes : null; + hookTypesUpdateIndexDev = -1; // Used for hot reloading: + + ignorePreviousDependencies = current !== null && current.type !== workInProgress.type; + warnIfAsyncClientComponent(Component); + } + + 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 (current !== null && current.memoizedState !== null) { + ReactSharedInternals.H = 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. + ReactSharedInternals.H = HooksDispatcherOnMountWithHookTypesInDEV; + } else { + ReactSharedInternals.H = 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. + + + var shouldDoubleRenderDEV = debugRenderPhaseSideEffectsForStrictMode ; + shouldDoubleInvokeUserFnsInHooksDEV = shouldDoubleRenderDEV; + var children = Component(props, secondArg); + shouldDoubleInvokeUserFnsInHooksDEV = false; // Check if there was a render phase update + + if (didScheduleRenderPhaseUpdateDuringThisPass) { + // Keep rendering until the component stabilizes (there are no more render + // phase updates). + children = renderWithHooksAgain(workInProgress, Component, props, secondArg); + } + + finishRenderingHooks(current, workInProgress); + return children; +} - { - // 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 finishRenderingHooks(current, workInProgress, Component) { + { + workInProgress._debugHookTypes = hookTypesDev; + } // 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. - currentHook = null; - workInProgressHook = null; - workInProgress.updateQueue = null; - { - // Also validate hook order for cascading updates. - hookTypesUpdateIndexDev = -1; - } + ReactSharedInternals.H = ContextOnlyDispatcher; // 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. - ReactSharedInternals.H = HooksDispatcherOnRerenderInDEV; - children = Component(props, secondArg); - } while (didScheduleRenderPhaseUpdateDuringThisPass); + var didRenderTooFewHooks = currentHook !== null && currentHook.next !== null; + renderLanes = NoLanes; + currentlyRenderingFiber$1 = null; + currentHook = null; + workInProgressHook = null; - return children; - } + { + 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. - function renderTransitionAwareHostComponentWithHooks( - current, - workInProgress, - lanes - ) { - return renderWithHooks( - current, - workInProgress, - TransitionAwareHostComponent, - null, - null, - lanes - ); + 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.'); } - function TransitionAwareHostComponent() { - var dispatcher = ReactSharedInternals.H; + } - var _dispatcher$useState = dispatcher.useState(), - maybeThenable = _dispatcher$useState[0]; + didScheduleRenderPhaseUpdate = false; // This is reset by checkDidRenderIdHook + // localIdCounter = 0; - var nextState; + thenableIndexCounter = 0; + thenableState = null; - if (typeof maybeThenable.then === "function") { - var thenable = maybeThenable; - nextState = useThenable(thenable); - } else { - var status = maybeThenable; - nextState = status; - } // The "reset state" is an object. If it changes, that means something - // requested that we reset the form. + if (didRenderTooFewHooks) { + throw new Error('Rendered fewer hooks than expected. This may be caused by an accidental ' + 'early return statement.'); + } - var _dispatcher$useState2 = dispatcher.useState(), - nextResetState = _dispatcher$useState2[0]; + { + if (checkIfUseWrappedInTryCatch()) { + var componentName = getComponentNameFromFiber(workInProgress) || 'Unknown'; - var prevResetState = - currentHook !== null ? currentHook.memoizedState : null; + if (!didWarnAboutUseWrappedInTryCatch.has(componentName) && // This warning also fires if you suspend with `use` inside an + // async component. Since we warn for that above, we'll silence this + // second warning by checking here. + !didWarnAboutAsyncClientComponent.has(componentName)) { + didWarnAboutUseWrappedInTryCatch.add(componentName); - if (prevResetState !== nextResetState) { - // Schedule a form reset - currentlyRenderingFiber$1.flags |= FormReset; + 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.'); } - - return nextState; } - 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 { - workInProgress.flags &= ~(Passive$1 | Update); - } +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: + + ignorePreviousDependencies = current !== null && current.type !== workInProgress.type; + } + + var children = renderWithHooksAgain(workInProgress, Component, props, secondArg); + finishRenderingHooks(current, workInProgress); + return children; +} - current.lanes = removeLanes(current.lanes, lanes); +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. + currentlyRenderingFiber$1 = workInProgress; + 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; } - 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. - currentlyRenderingFiber$1 = null; // 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. - - ReactSharedInternals.H = ContextOnlyDispatcher; - } - function resetHooksOnUnwind(workInProgress) { - 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 = workInProgress.memoizedState; - while (hook !== null) { - var queue = hook.queue; + thenableIndexCounter = 0; + didScheduleRenderPhaseUpdateDuringThisPass = false; - if (queue !== null) { - queue.pending = null; - } + if (numberOfReRenders >= RE_RENDER_LIMIT) { + throw new Error('Too many re-renders. React limits the number of renders to prevent ' + 'an infinite loop.'); + } - hook = hook.next; - } + numberOfReRenders += 1; - didScheduleRenderPhaseUpdate = false; - } + { + // 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 - renderLanes = NoLanes; - currentlyRenderingFiber$1 = null; - currentHook = null; - workInProgressHook = null; - { - hookTypesDev = null; - hookTypesUpdateIndexDev = -1; - currentHookNameInDev = null; - } + currentHook = null; + workInProgressHook = null; + workInProgress.updateQueue = null; - didScheduleRenderPhaseUpdateDuringThisPass = false; - thenableIndexCounter = 0; - thenableState = null; + { + // Also validate hook order for cascading updates. + hookTypesUpdateIndexDev = -1; } - function mountWorkInProgressHook() { - var hook = { - memoizedState: null, - baseState: null, - baseQueue: null, - queue: null, - next: null - }; + ReactSharedInternals.H = HooksDispatcherOnRerenderInDEV ; + children = Component(props, secondArg); + } while (didScheduleRenderPhaseUpdateDuringThisPass); - 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 children; +} - return workInProgressHook; - } +function renderTransitionAwareHostComponentWithHooks(current, workInProgress, lanes) { - 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; + return renderWithHooks(current, workInProgress, TransitionAwareHostComponent, null, null, lanes); +} +function TransitionAwareHostComponent() { - if (currentHook === null) { - var current = currentlyRenderingFiber$1.alternate; + var dispatcher = ReactSharedInternals.H; - if (current !== null) { - nextCurrentHook = current.memoizedState; - } else { - nextCurrentHook = null; - } - } else { - nextCurrentHook = currentHook.next; - } + var _dispatcher$useState = dispatcher.useState(), + maybeThenable = _dispatcher$useState[0]; - var nextWorkInProgressHook; + var nextState; - if (workInProgressHook === null) { - nextWorkInProgressHook = currentlyRenderingFiber$1.memoizedState; - } else { - nextWorkInProgressHook = workInProgressHook.next; - } + if (typeof maybeThenable.then === 'function') { + var thenable = maybeThenable; + nextState = useThenable(thenable); + } else { + var status = maybeThenable; + nextState = status; + } // The "reset state" is an object. If it changes, that means something + // requested that we reset the form. - 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 (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 - }; + var _dispatcher$useState2 = dispatcher.useState(), + nextResetState = _dispatcher$useState2[0]; - 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 prevResetState = currentHook !== null ? currentHook.memoizedState : 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 (prevResetState !== nextResetState) { + // Schedule a form reset + currentlyRenderingFiber$1.flags |= FormReset; + } - var createFunctionComponentUpdateQueue; + return nextState; +} +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). - { - createFunctionComponentUpdateQueue = function () { - return { - lastEffect: null, - events: null, - stores: null, - memoCache: null - }; - }; - } + if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { + workInProgress.flags &= ~(MountPassiveDev | MountLayoutDev | Passive$1 | Update); + } else { + workInProgress.flags &= ~(Passive$1 | Update); + } + + 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. + currentlyRenderingFiber$1 = null; // 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. + + ReactSharedInternals.H = ContextOnlyDispatcher; +} +function resetHooksOnUnwind(workInProgress) { + 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 = workInProgress.memoizedState; - function useThenable(thenable) { - // Track the position of the thenable within this fiber. - var index = thenableIndexCounter; - thenableIndexCounter += 1; + while (hook !== null) { + var queue = hook.queue; - if (thenableState === null) { - thenableState = createThenableState(); + if (queue !== null) { + queue.pending = null; } - var result = trackUsedThenable(thenableState, thenable, index); + hook = hook.next; + } - 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. - { - ReactSharedInternals.H = HooksDispatcherOnMountInDEV; - } - } + didScheduleRenderPhaseUpdate = false; + } + + renderLanes = NoLanes; + currentlyRenderingFiber$1 = null; + currentHook = null; + workInProgressHook = null; + + { + hookTypesDev = null; + hookTypesUpdateIndexDev = -1; + currentHookNameInDev = null; + } + + didScheduleRenderPhaseUpdateDuringThisPass = false; + thenableIndexCounter = 0; + thenableState = null; +} + +function mountWorkInProgressHook() { + var hook = { + memoizedState: null, + baseState: null, + baseQueue: null, + queue: null, + next: null + }; + + 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; +} - return result; +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; + + if (currentHook === null) { + var current = currentlyRenderingFiber$1.alternate; + + if (current !== null) { + nextCurrentHook = current.memoizedState; + } else { + nextCurrentHook = null; + } + } 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 (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.'); + } } - function use(usable) { - if (usable !== null && typeof usable === "object") { - // $FlowFixMe[method-unbinding] - if (typeof usable.then === "function") { - // This is a thenable. - var thenable = usable; - return useThenable(thenable); - } else if (usable.$$typeof === REACT_CONTEXT_TYPE) { - var context = usable; - return readContext(context); - } - } // eslint-disable-next-line react-internal/safe-string-coercion + currentHook = nextCurrentHook; + var newHook = { + memoizedState: currentHook.memoizedState, + baseState: currentHook.baseState, + baseQueue: currentHook.baseQueue, + queue: currentHook.queue, + next: null + }; - throw new Error( - "An unsupported type was passed to use(): " + String(usable) - ); + 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; } + } - function useMemoCache(size) { - var memoCache = null; // Fast-path, load memo cache from wip fiber if already prepared + 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. - var updateQueue = currentlyRenderingFiber$1.updateQueue; - if (updateQueue !== null) { - memoCache = updateQueue.memoCache; - } // Otherwise clone from the current fiber +var createFunctionComponentUpdateQueue; - if (memoCache == null) { - var current = currentlyRenderingFiber$1.alternate; +{ + createFunctionComponentUpdateQueue = function () { + return { + lastEffect: null, + events: null, + stores: null, + memoCache: null + }; + }; +} - if (current !== null) { - var currentUpdateQueue = current.updateQueue; +function useThenable(thenable) { + // Track the position of the thenable within this fiber. + var index = thenableIndexCounter; + thenableIndexCounter += 1; - if (currentUpdateQueue !== null) { - var currentMemoCache = currentUpdateQueue.memoCache; + if (thenableState === null) { + thenableState = createThenableState(); + } - 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 + var result = trackUsedThenable(thenableState, thenable, index); - if (memoCache == null) { - memoCache = { - data: [], - index: 0 - }; - } + 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. + { + ReactSharedInternals.H = HooksDispatcherOnMountInDEV; + } + } - if (updateQueue === null) { - updateQueue = createFunctionComponentUpdateQueue(); - currentlyRenderingFiber$1.updateQueue = updateQueue; - } + return result; +} - updateQueue.memoCache = memoCache; - var data = memoCache.data[memoCache.index]; +function use(usable) { + if (usable !== null && typeof usable === 'object') { + // $FlowFixMe[method-unbinding] + if (typeof usable.then === 'function') { + // This is a thenable. + var thenable = usable; + return useThenable(thenable); + } else if (usable.$$typeof === REACT_CONTEXT_TYPE) { + var context = usable; + return readContext(context); + } + } // eslint-disable-next-line react-internal/safe-string-coercion - if (data === undefined) { - data = memoCache.data[memoCache.index] = new Array(size); - 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 - ); - } - } + throw new Error('An unsupported type was passed to use(): ' + String(usable)); +} - memoCache.index++; - return data; - } +function useMemoCache(size) { + var memoCache = null; // Fast-path, load memo cache from wip fiber if already prepared - function basicStateReducer(state, action) { - // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types - return typeof action === "function" ? action(state) : action; - } + var updateQueue = currentlyRenderingFiber$1.updateQueue; - function mountReducer(reducer, initialArg, init) { - var hook = mountWorkInProgressHook(); - var initialState; + if (updateQueue !== null) { + memoCache = updateQueue.memoCache; + } // Otherwise clone from the current fiber - if (init !== undefined) { - initialState = init(initialArg); - if (shouldDoubleInvokeUserFnsInHooksDEV) { - setIsStrictModeForDevtools(true); - init(initialArg); - setIsStrictModeForDevtools(false); + if (memoCache == null) { + var current = currentlyRenderingFiber$1.alternate; + + if (current !== null) { + var currentUpdateQueue = current.updateQueue; + + if (currentUpdateQueue !== null) { + var currentMemoCache = currentUpdateQueue.memoCache; + + if (currentMemoCache != null) { + memoCache = { + data: currentMemoCache.data.map(function (array) { + return array.slice(); + }), + index: 0 + }; } - } 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]; } + } // Finally fall back to allocating a fresh instance of the cache + + + if (memoCache == null) { + memoCache = { + data: [], + index: 0 + }; + } + + if (updateQueue === null) { + updateQueue = createFunctionComponentUpdateQueue(); + currentlyRenderingFiber$1.updateQueue = updateQueue; + } - function updateReducer(reducer, initialArg, init) { - var hook = updateWorkInProgressHook(); - return updateReducerImpl(hook, currentHook, reducer); + updateQueue.memoCache = memoCache; + var data = memoCache.data[memoCache.index]; + + if (data === undefined) { + data = memoCache.data[memoCache.index] = new Array(size); + + 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); } + } - function updateReducerImpl(hook, current, reducer) { - var queue = hook.queue; + memoCache.index++; + return data; +} - if (queue === null) { - throw new Error( - "Should have a queue. This is likely a bug in React. Please file an issue." - ); - } +function basicStateReducer(state, action) { + // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types + return typeof action === 'function' ? action(state) : action; +} - queue.lastRenderedReducer = reducer; // The last rebase update that is NOT part of the base state. +function mountReducer(reducer, initialArg, init) { + var hook = mountWorkInProgressHook(); + var initialState; + + if (init !== undefined) { + initialState = init(initialArg); + + if (shouldDoubleInvokeUserFnsInHooksDEV) { + setIsStrictModeForDevtools(true); + init(initialArg); + setIsStrictModeForDevtools(false); + } + } 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 baseQueue = hook.baseQueue; // The last pending update that hasn't been processed yet. +function updateReducer(reducer, initialArg, init) { + var hook = updateWorkInProgressHook(); + return updateReducerImpl(hook, currentHook, reducer); +} - var pendingQueue = queue.pending; +function updateReducerImpl(hook, current, reducer) { + var queue = hook.queue; - 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 (queue === null) { + throw new Error('Should have a queue. This is likely a bug in React. Please file an issue.'); + } - { - 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." - ); - } - } + queue.lastRenderedReducer = reducer; // The last rebase update that is NOT part of the base state. - current.baseQueue = baseQueue = pendingQueue; - queue.pending = null; - } + var baseQueue = hook.baseQueue; // The last pending update that hasn't been processed yet. + + var pendingQueue = queue.pending; + + 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.'); + } + } + + current.baseQueue = baseQueue = pendingQueue; + queue.pending = null; + } + + var baseState = hook.baseState; + + if (baseQueue === null) { + // If there are no pending updates, then the memoized state should be the + // same as the base state. Currently these only diverge in the case of + // useOptimistic, because useOptimistic accepts a new baseState on + // every render. + hook.memoizedState = baseState; // We don't need to call markWorkInProgressReceivedUpdate because + // baseState is derived from other reactive values. + } else { + // We have a queue to process. + var first = baseQueue.next; + var newState = baseState; + var newBaseState = null; + var newBaseQueueFirst = null; + var newBaseQueueLast = null; + var update = first; + var didReadFromEntangledAsyncAction = false; + + 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); + + 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, + revertLane: update.revertLane, + 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. - var baseState = hook.baseState; - if (baseQueue === null) { - // If there are no pending updates, then the memoized state should be the - // same as the base state. Currently these only diverge in the case of - // useOptimistic, because useOptimistic accepts a new baseState on - // every render. - hook.memoizedState = baseState; // We don't need to call markWorkInProgressReceivedUpdate because - // baseState is derived from other reactive values. + currentlyRenderingFiber$1.lanes = mergeLanes(currentlyRenderingFiber$1.lanes, updateLane); + markSkippedUpdateLanes(updateLane); } else { - // We have a queue to process. - var first = baseQueue.next; - var newState = baseState; - var newBaseState = null; - var newBaseQueueFirst = null; - var newBaseQueueLast = null; - var update = first; - var didReadFromEntangledAsyncAction = false; + // This update does have sufficient priority. + // Check if this is an optimistic update. + var revertLane = update.revertLane; + + if (revertLane === NoLane) { + // This is not an optimistic update, and we're going to apply it now. + // But, if there were earlier updates that were skipped, we need to + // leave this update in the queue so it can be rebased later. + 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, + revertLane: NoLane, + action: update.action, + hasEagerState: update.hasEagerState, + eagerState: update.eagerState, + next: null + }; + newBaseQueueLast = newBaseQueueLast.next = _clone; + } // Check if this update is part of a pending async action. If so, + // we'll need to suspend until the action has finished, so that it's + // batched together with future updates in the same action. - 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); - - 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, + + if (updateLane === peekEntangledActionLane()) { + didReadFromEntangledAsyncAction = true; + } + } else { + // This is an optimistic update. If the "revert" priority is + // sufficient, don't apply the update. Otherwise, apply the update, + // but leave it in the queue so it can be either reverted or + // rebased in a subsequent render. + if (isSubsetOfLanes(renderLanes, revertLane)) { + // The transition that this optimistic update is associated with + // has finished. Pretend the update doesn't exist by skipping + // over it. + update = update.next; // Check if this update is part of a pending async action. If so, + // we'll need to suspend until the action has finished, so that it's + // batched together with future updates in the same action. + + if (revertLane === peekEntangledActionLane()) { + didReadFromEntangledAsyncAction = true; + } + + continue; + } else { + var _clone2 = { + // Once we commit an optimistic update, we shouldn't uncommit it + // until the transition it is associated with has finished + // (represented by revertLane). Using NoLane here works because 0 + // is a subset of all bitmasks, so this will never be skipped by + // the check above. + lane: NoLane, + // Reuse the same revertLane so we know when the transition + // has finished. revertLane: update.revertLane, action: update.action, hasEagerState: update.hasEagerState, @@ -8786,10831 +7744,8767 @@ if (__DEV__) { }; if (newBaseQueueLast === null) { - newBaseQueueFirst = newBaseQueueLast = clone; + newBaseQueueFirst = newBaseQueueLast = _clone2; newBaseState = newState; } else { - newBaseQueueLast = newBaseQueueLast.next = clone; + newBaseQueueLast = newBaseQueueLast.next = _clone2; } // 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. - // Check if this is an optimistic update. - var revertLane = update.revertLane; - - if (revertLane === NoLane) { - // This is not an optimistic update, and we're going to apply it now. - // But, if there were earlier updates that were skipped, we need to - // leave this update in the queue so it can be rebased later. - 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, - revertLane: NoLane, - action: update.action, - hasEagerState: update.hasEagerState, - eagerState: update.eagerState, - next: null - }; - newBaseQueueLast = newBaseQueueLast.next = _clone; - } // Check if this update is part of a pending async action. If so, - // we'll need to suspend until the action has finished, so that it's - // batched together with future updates in the same action. - - if (updateLane === peekEntangledActionLane()) { - didReadFromEntangledAsyncAction = true; - } - } else { - // This is an optimistic update. If the "revert" priority is - // sufficient, don't apply the update. Otherwise, apply the update, - // but leave it in the queue so it can be either reverted or - // rebased in a subsequent render. - if (isSubsetOfLanes(renderLanes, revertLane)) { - // The transition that this optimistic update is associated with - // has finished. Pretend the update doesn't exist by skipping - // over it. - update = update.next; // Check if this update is part of a pending async action. If so, - // we'll need to suspend until the action has finished, so that it's - // batched together with future updates in the same action. - - if (revertLane === peekEntangledActionLane()) { - didReadFromEntangledAsyncAction = true; - } - - continue; - } else { - var _clone2 = { - // Once we commit an optimistic update, we shouldn't uncommit it - // until the transition it is associated with has finished - // (represented by revertLane). Using NoLane here works because 0 - // is a subset of all bitmasks, so this will never be skipped by - // the check above. - lane: NoLane, - // Reuse the same revertLane so we know when the transition - // has finished. - revertLane: update.revertLane, - action: update.action, - hasEagerState: update.hasEagerState, - eagerState: update.eagerState, - next: null - }; - - if (newBaseQueueLast === null) { - newBaseQueueFirst = newBaseQueueLast = _clone2; - newBaseState = newState; - } else { - newBaseQueueLast = newBaseQueueLast.next = _clone2; - } // 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, - revertLane - ); - markSkippedUpdateLanes(revertLane); - } - } // Process this update. - var action = update.action; + currentlyRenderingFiber$1.lanes = mergeLanes(currentlyRenderingFiber$1.lanes, revertLane); + markSkippedUpdateLanes(revertLane); + } + } // Process this update. - 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); - } - } + var action = update.action; - update = update.next; - } while (update !== null && update !== first); + if (shouldDoubleInvokeUserFnsInHooksDEV) { + reducer(newState, action); + } - if (newBaseQueueLast === null) { - newBaseState = newState; + 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 { - 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(); // Check if this update is part of a pending async action. If so, we'll - // need to suspend until the action has finished, so that it's batched - // together with future updates in the same action. - // TODO: Once we support hooks inside useMemo (or an equivalent - // memoization boundary like Forget), hoist this logic so that it only - // suspends if the memo boundary produces a new value. - - if (didReadFromEntangledAsyncAction) { - var entangledActionThenable = peekEntangledActionThenable(); - - if (entangledActionThenable !== null) { - // TODO: Instead of the throwing the thenable directly, throw a - // special object like `use` does so we can detect if it's captured - // by userspace. - throw entangledActionThenable; - } - } + newState = reducer(newState, action); } - - hook.memoizedState = newState; - hook.baseState = newBaseState; - hook.baseQueue = newBaseQueueLast; - queue.lastRenderedState = newState; - } - - 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; - } - - 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." - ); } - 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; + update = update.next; + } while (update !== null && update !== first); - if (lastRenderPhaseUpdate !== null) { - // The queue doesn't persist past this render pass. - queue.pending = null; - var firstRenderPhaseUpdate = lastRenderPhaseUpdate.next; - var update = firstRenderPhaseUpdate; + 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. - 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(); - } + if (!objectIs(newState, hook.memoizedState)) { + markWorkInProgressReceivedUpdate(); // Check if this update is part of a pending async action. If so, we'll + // need to suspend until the action has finished, so that it's batched + // together with future updates in the same action. + // TODO: Once we support hooks inside useMemo (or an equivalent + // memoization boundary like Forget), hoist this logic so that it only + // suspends if the memo boundary produces a new value. - 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 (didReadFromEntangledAsyncAction) { + var entangledActionThenable = peekEntangledActionThenable(); - if (hook.baseQueue === null) { - hook.baseState = newState; + if (entangledActionThenable !== null) { + // TODO: Instead of the throwing the thenable directly, throw a + // special object like `use` does so we can detect if it's captured + // by userspace. + throw entangledActionThenable; } - - queue.lastRenderedState = newState; } - - return [newState, dispatch]; } - function mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) { - var fiber = currentlyRenderingFiber$1; - var hook = mountWorkInProgressHook(); - var nextSnapshot; - - { - nextSnapshot = getSnapshot(); + hook.memoizedState = newState; + hook.baseState = newBaseState; + hook.baseQueue = newBaseQueueLast; + queue.lastRenderedState = newState; + } - { - if (!didWarnUncachedGetSnapshot) { - var cachedSnapshot = getSnapshot(); + 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; + } - if (!objectIs(nextSnapshot, cachedSnapshot)) { - error( - "The result of getSnapshot should be cached to avoid an infinite loop" - ); + var dispatch = queue.dispatch; + return [hook.memoizedState, dispatch]; +} - 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. +function rerenderReducer(reducer, initialArg, init) { + var hook = updateWorkInProgressHook(); + var queue = hook.queue; - var root = getWorkInProgressRoot(); + if (queue === null) { + throw new Error('Should have a queue. This is likely a bug in React. Please file an issue.'); + } - if (root === null) { - throw new Error( - "Expected a work-in-progress root. This is a bug in React. Please file an issue." - ); - } + queue.lastRenderedReducer = reducer; // This is a re-render. Apply the new render phase updates to the previous + // work-in-progress hook. - var rootRenderLanes = getWorkInProgressRootRenderLanes(); + var dispatch = queue.dispatch; + var lastRenderPhaseUpdate = queue.pending; + var newState = hook.memoizedState; - if (!includesBlockingLane(root, rootRenderLanes)) { - 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. - - fiber.flags |= Passive$1; - pushEffect( - HasEffect | Passive, - updateStoreInstance.bind(null, fiber, inst, nextSnapshot, getSnapshot), - createEffectInstance(), - 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; + if (lastRenderPhaseUpdate !== null) { + // The queue doesn't persist past this render pass. + queue.pending = null; + var firstRenderPhaseUpdate = lastRenderPhaseUpdate.next; + var update = firstRenderPhaseUpdate; - { - nextSnapshot = getSnapshot(); + 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 (!didWarnUncachedGetSnapshot) { - var cachedSnapshot = getSnapshot(); - if (!objectIs(nextSnapshot, cachedSnapshot)) { - error( - "The result of getSnapshot should be cached to avoid an infinite loop" - ); + if (!objectIs(newState, hook.memoizedState)) { + markWorkInProgressReceivedUpdate(); + } - didWarnUncachedGetSnapshot = true; - } - } - } - } + 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. - var prevSnapshot = (currentHook || hook).memoizedState; - var snapshotChanged = !objectIs(prevSnapshot, nextSnapshot); + if (hook.baseQueue === null) { + hook.baseState = newState; + } - if (snapshotChanged) { - hook.memoizedState = nextSnapshot; - markWorkInProgressReceivedUpdate(); - } + queue.lastRenderedState = newState; + } - 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. - - if ( - inst.getSnapshot !== getSnapshot || - snapshotChanged || // Check if the subscribe 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 - ), - createEffectInstance(), - 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 root = getWorkInProgressRoot(); - - if (root === null) { - throw new Error( - "Expected a work-in-progress root. This is a bug in React. Please file an issue." - ); - } + return [newState, dispatch]; +} - if (!includesBlockingLane(root, renderLanes)) { - pushStoreConsistencyCheck(fiber, getSnapshot, nextSnapshot); - } - } +function mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) { + var fiber = currentlyRenderingFiber$1; + var hook = mountWorkInProgressHook(); + var nextSnapshot; - return nextSnapshot; - } + { + nextSnapshot = getSnapshot(); - function pushStoreConsistencyCheck(fiber, getSnapshot, renderedSnapshot) { - fiber.flags |= StoreConsistency; - var check = { - getSnapshot: getSnapshot, - value: renderedSnapshot - }; - var componentUpdateQueue = currentlyRenderingFiber$1.updateQueue; + { + if (!didWarnUncachedGetSnapshot) { + var cachedSnapshot = getSnapshot(); - if (componentUpdateQueue === null) { - componentUpdateQueue = createFunctionComponentUpdateQueue(); - currentlyRenderingFiber$1.updateQueue = componentUpdateQueue; - componentUpdateQueue.stores = [check]; - } else { - var stores = componentUpdateQueue.stores; + if (!objectIs(nextSnapshot, cachedSnapshot)) { + error('The result of getSnapshot should be cached to avoid an infinite loop'); - if (stores === null) { - componentUpdateQueue.stores = [check]; - } else { - stores.push(check); + 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. - 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. - if (checkIfSnapshotChanged(inst)) { - // Force a re-render. - forceStoreRerender(fiber); - } + 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.'); } - 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. + var rootRenderLanes = getWorkInProgressRootRenderLanes(); - return subscribe(handleStoreChange); + if (!includesBlockingLane(root, rootRenderLanes)) { + 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. - function checkIfSnapshotChanged(inst) { - var latestGetSnapshot = inst.getSnapshot; - var prevValue = inst.value; - try { - var nextValue = latestGetSnapshot(); - return !objectIs(prevValue, nextValue); - } catch (error) { - return true; - } - } + hook.memoizedState = nextSnapshot; + var inst = { + value: nextSnapshot, + getSnapshot: getSnapshot + }; + hook.queue = inst; // Schedule an effect to subscribe to the store. - function forceStoreRerender(fiber) { - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + 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. - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane); - } - } + fiber.flags |= Passive$1; + pushEffect(HasEffect | Passive, updateStoreInstance.bind(null, fiber, inst, nextSnapshot, getSnapshot), createEffectInstance(), null); + return nextSnapshot; +} - function mountStateImpl(initialState) { - var hook = mountWorkInProgressHook(); +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. - if (typeof initialState === "function") { - var initialStateInitializer = initialState; // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types + var nextSnapshot; - initialState = initialStateInitializer(); + { + nextSnapshot = getSnapshot(); - if (shouldDoubleInvokeUserFnsInHooksDEV) { - setIsStrictModeForDevtools(true); // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types + { + if (!didWarnUncachedGetSnapshot) { + var cachedSnapshot = getSnapshot(); + + if (!objectIs(nextSnapshot, cachedSnapshot)) { + error('The result of getSnapshot should be cached to avoid an infinite loop'); - initialStateInitializer(); - setIsStrictModeForDevtools(false); + didWarnUncachedGetSnapshot = true; } } - - hook.memoizedState = hook.baseState = initialState; - var queue = { - pending: null, - lanes: NoLanes, - dispatch: null, - lastRenderedReducer: basicStateReducer, - lastRenderedState: initialState - }; - hook.queue = queue; - return hook; } + } - function mountState(initialState) { - var hook = mountStateImpl(initialState); - var queue = hook.queue; - var dispatch = dispatchSetState.bind( - null, - currentlyRenderingFiber$1, - queue - ); - queue.dispatch = dispatch; - return [hook.memoizedState, dispatch]; - } + var prevSnapshot = (currentHook || hook).memoizedState; + var snapshotChanged = !objectIs(prevSnapshot, nextSnapshot); - function updateState(initialState) { - return updateReducer(basicStateReducer); - } + if (snapshotChanged) { + hook.memoizedState = nextSnapshot; + markWorkInProgressReceivedUpdate(); + } - function rerenderState(initialState) { - return rerenderReducer(basicStateReducer); - } + 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. - function mountOptimistic(passthrough, reducer) { - var hook = mountWorkInProgressHook(); - hook.memoizedState = hook.baseState = passthrough; - var queue = { - pending: null, - lanes: NoLanes, - dispatch: null, - // Optimistic state does not use the eager update optimization. - lastRenderedReducer: null, - lastRenderedState: null - }; - hook.queue = queue; // This is different than the normal setState function. + if (inst.getSnapshot !== getSnapshot || snapshotChanged || // Check if the subscribe 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), createEffectInstance(), 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 root = getWorkInProgressRoot(); - var dispatch = dispatchOptimisticSetState.bind( - null, - currentlyRenderingFiber$1, - true, - queue - ); - queue.dispatch = dispatch; - return [passthrough, dispatch]; + if (root === null) { + throw new Error('Expected a work-in-progress root. This is a bug in React. Please file an issue.'); } - function updateOptimistic(passthrough, reducer) { - var hook = updateWorkInProgressHook(); - return updateOptimisticImpl(hook, currentHook, passthrough, reducer); + if (!includesBlockingLane(root, renderLanes)) { + pushStoreConsistencyCheck(fiber, getSnapshot, nextSnapshot); } + } - function updateOptimisticImpl(hook, current, passthrough, reducer) { - // Optimistic updates are always rebased on top of the latest value passed in - // as an argument. It's called a passthrough because if there are no pending - // updates, it will be returned as-is. - // - // Reset the base state to the passthrough. Future updates will be applied - // on top of this. - hook.baseState = passthrough; // If a reducer is not provided, default to the same one used by useState. + return nextSnapshot; +} - var resolvedReducer = - typeof reducer === "function" ? reducer : basicStateReducer; - return updateReducerImpl(hook, currentHook, resolvedReducer); - } +function pushStoreConsistencyCheck(fiber, getSnapshot, renderedSnapshot) { + fiber.flags |= StoreConsistency; + var check = { + getSnapshot: getSnapshot, + value: renderedSnapshot + }; + var componentUpdateQueue = currentlyRenderingFiber$1.updateQueue; + + if (componentUpdateQueue === null) { + componentUpdateQueue = createFunctionComponentUpdateQueue(); + currentlyRenderingFiber$1.updateQueue = componentUpdateQueue; + componentUpdateQueue.stores = [check]; + } else { + var stores = componentUpdateQueue.stores; + + if (stores === null) { + componentUpdateQueue.stores = [check]; + } else { + stores.push(check); + } + } +} - function rerenderOptimistic(passthrough, reducer) { - // Unlike useState, useOptimistic doesn't support render phase updates. - // Also unlike useState, we need to replay all pending updates again in case - // the passthrough value changed. - // - // So instead of a forked re-render implementation that knows how to handle - // render phase udpates, we can use the same implementation as during a - // regular mount or update. - var hook = updateWorkInProgressHook(); - - if (currentHook !== null) { - // This is an update. Process the update queue. - return updateOptimisticImpl(hook, currentHook, passthrough, reducer); - } // This is a mount. No updates to process. - // Reset the base state to the passthrough. Future updates will be applied - // on top of this. - - hook.baseState = passthrough; - var dispatch = hook.queue.dispatch; - return [passthrough, dispatch]; - } // useActionState actions run sequentially, because each action receives the - // previous state as an argument. We store pending actions on a queue. - - function dispatchActionState( - fiber, - actionQueue, - setPendingState, - setState, - payload - ) { - if (isRenderPhaseUpdate(fiber)) { - throw new Error("Cannot update form state while rendering."); - } - - var last = actionQueue.pending; - - if (last === null) { - // There are no pending actions; this is the first one. We can run - // it immediately. - var newLast = { - payload: payload, - next: null // circular - }; - newLast.next = actionQueue.pending = newLast; - runActionStateAction(actionQueue, setPendingState, setState, payload); - } else { - // There's already an action running. Add to the queue. - var first = last.next; - var _newLast = { - payload: payload, - next: first - }; - actionQueue.pending = last.next = _newLast; - } +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. + + if (checkIfSnapshotChanged(inst)) { + // Force a re-render. + forceStoreRerender(fiber); + } +} + +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 runActionStateAction( - actionQueue, - setPendingState, - setState, - payload - ) { - var action = actionQueue.action; - var prevState = actionQueue.state; // This is a fork of startTransition - var prevTransition = ReactSharedInternals.T; - var currentTransition = { - _callbacks: new Set() - }; - ReactSharedInternals.T = currentTransition; + return subscribe(handleStoreChange); +} - { - ReactSharedInternals.T._updatedFibers = new Set(); - } // Optimistically update the pending state, similar to useTransition. - // This will be reverted automatically when all actions are finished. +function checkIfSnapshotChanged(inst) { + var latestGetSnapshot = inst.getSnapshot; + var prevValue = inst.value; - setPendingState(true); + try { + var nextValue = latestGetSnapshot(); + return !objectIs(prevValue, nextValue); + } catch (error) { + return true; + } +} - try { - var returnValue = action(prevState, payload); - - if ( - returnValue !== null && - typeof returnValue === "object" && // $FlowFixMe[method-unbinding] - typeof returnValue.then === "function" - ) { - var thenable = returnValue; - notifyTransitionCallbacks(currentTransition, thenable); // Attach a listener to read the return state of the action. As soon as - // this resolves, we can run the next action in the sequence. - - thenable.then( - function (nextState) { - actionQueue.state = nextState; - finishRunningActionStateAction( - actionQueue, - setPendingState, - setState - ); - }, - function () { - return finishRunningActionStateAction( - actionQueue, - setPendingState, - setState - ); - } - ); - setState(thenable); - } else { - setState(returnValue); - var nextState = returnValue; - actionQueue.state = nextState; - finishRunningActionStateAction( - actionQueue, - setPendingState, - setState - ); - } - } catch (error) { - // This is a trick to get the `useActionState` hook to rethrow the error. - // When it unwraps the thenable with the `use` algorithm, the error - // will be thrown. - var rejectedThenable = { - then: function () {}, - status: "rejected", - reason: error // $FlowFixMe: Not sure why this doesn't work - }; - setState(rejectedThenable); - finishRunningActionStateAction(actionQueue, setPendingState, setState); - } finally { - ReactSharedInternals.T = prevTransition; +function forceStoreRerender(fiber) { + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - { - if (prevTransition === null && currentTransition._updatedFibers) { - var updatedFibersCount = currentTransition._updatedFibers.size; + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane); + } +} - currentTransition._updatedFibers.clear(); +function mountStateImpl(initialState) { + var hook = mountWorkInProgressHook(); - 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 initialState === 'function') { + var initialStateInitializer = initialState; // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types - function finishRunningActionStateAction( - actionQueue, - setPendingState, - setState - ) { - // The action finished running. Pop it from the queue and run the next pending - // action, if there are any. - var last = actionQueue.pending; + initialState = initialStateInitializer(); - if (last !== null) { - var first = last.next; + if (shouldDoubleInvokeUserFnsInHooksDEV) { + setIsStrictModeForDevtools(true); // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types - if (first === last) { - // This was the last action in the queue. - actionQueue.pending = null; - } else { - // Remove the first node from the circular queue. - var next = first.next; - last.next = next; // Run the next action. - - runActionStateAction( - actionQueue, - setPendingState, - setState, - next.payload - ); - } - } + initialStateInitializer(); + setIsStrictModeForDevtools(false); } + } - function actionStateReducer(oldState, newState) { - return newState; - } + hook.memoizedState = hook.baseState = initialState; + var queue = { + pending: null, + lanes: NoLanes, + dispatch: null, + lastRenderedReducer: basicStateReducer, + lastRenderedState: initialState + }; + hook.queue = queue; + return hook; +} - function mountActionState(action, initialStateProp, permalink) { - var initialState = initialStateProp; - // the `use` algorithm during render. +function mountState(initialState) { + var hook = mountStateImpl(initialState); + var queue = hook.queue; + var dispatch = dispatchSetState.bind(null, currentlyRenderingFiber$1, queue); + queue.dispatch = dispatch; + return [hook.memoizedState, dispatch]; +} - var stateHook = mountWorkInProgressHook(); - stateHook.memoizedState = stateHook.baseState = initialState; // TODO: Typing this "correctly" results in recursion limit errors - // const stateQueue: UpdateQueue, S | Awaited> = { +function updateState(initialState) { + return updateReducer(basicStateReducer); +} - var stateQueue = { - pending: null, - lanes: NoLanes, - dispatch: null, - lastRenderedReducer: actionStateReducer, - lastRenderedState: initialState - }; - stateHook.queue = stateQueue; - var setState = dispatchSetState.bind( - null, - currentlyRenderingFiber$1, - stateQueue - ); - stateQueue.dispatch = setState; // Pending state. This is used to store the pending state of the action. - // Tracked optimistically, like a transition pending state. - - var pendingStateHook = mountStateImpl(false); - var setPendingState = dispatchOptimisticSetState.bind( - null, - currentlyRenderingFiber$1, - false, - pendingStateHook.queue - ); // Action queue hook. This is used to queue pending actions. The queue is - // shared between all instances of the hook. Similar to a regular state queue, - // but different because the actions are run sequentially, and they run in - // an event instead of during render. - - var actionQueueHook = mountWorkInProgressHook(); - var actionQueue = { - state: initialState, - dispatch: null, - // circular - action: action, - pending: null - }; - actionQueueHook.queue = actionQueue; - var dispatch = dispatchActionState.bind( - null, - currentlyRenderingFiber$1, - actionQueue, - setPendingState, - setState - ); - actionQueue.dispatch = dispatch; // Stash the action function on the memoized state of the hook. We'll use this - // to detect when the action function changes so we can update it in - // an effect. - - actionQueueHook.memoizedState = action; - return [initialState, dispatch, false]; - } - - function updateActionState(action, initialState, permalink) { - var stateHook = updateWorkInProgressHook(); - var currentStateHook = currentHook; - return updateActionStateImpl(stateHook, currentStateHook, action); - } - - function updateActionStateImpl( - stateHook, - currentStateHook, - action, - initialState, - permalink - ) { - var _updateReducerImpl = updateReducerImpl( - stateHook, - currentStateHook, - actionStateReducer - ), - actionResult = _updateReducerImpl[0]; - - var _updateState = updateState(), - isPending = _updateState[0]; // This will suspend until the action finishes. - - var state = - typeof actionResult === "object" && - actionResult !== null && // $FlowFixMe[method-unbinding] - typeof actionResult.then === "function" - ? useThenable(actionResult) - : actionResult; - var actionQueueHook = updateWorkInProgressHook(); - var actionQueue = actionQueueHook.queue; - var dispatch = actionQueue.dispatch; // Check if a new action was passed. If so, update it in an effect. - - var prevAction = actionQueueHook.memoizedState; - - if (action !== prevAction) { - currentlyRenderingFiber$1.flags |= Passive$1; - pushEffect( - HasEffect | Passive, - actionStateActionEffect.bind(null, actionQueue, action), - createEffectInstance(), - null - ); - } - - return [state, dispatch, isPending]; - } - - function actionStateActionEffect(actionQueue, action) { - actionQueue.action = action; - } - - function rerenderActionState(action, initialState, permalink) { - // Unlike useState, useActionState doesn't support render phase updates. - // Also unlike useState, we need to replay all pending updates again in case - // the passthrough value changed. - // - // So instead of a forked re-render implementation that knows how to handle - // render phase udpates, we can use the same implementation as during a - // regular mount or update. - var stateHook = updateWorkInProgressHook(); - var currentStateHook = currentHook; +function rerenderState(initialState) { + return rerenderReducer(basicStateReducer); +} - if (currentStateHook !== null) { - // This is an update. Process the update queue. - return updateActionStateImpl(stateHook, currentStateHook, action); - } +function mountOptimistic(passthrough, reducer) { + var hook = mountWorkInProgressHook(); + hook.memoizedState = hook.baseState = passthrough; + var queue = { + pending: null, + lanes: NoLanes, + dispatch: null, + // Optimistic state does not use the eager update optimization. + lastRenderedReducer: null, + lastRenderedState: null + }; + hook.queue = queue; // This is different than the normal setState function. + + var dispatch = dispatchOptimisticSetState.bind(null, currentlyRenderingFiber$1, true, queue); + queue.dispatch = dispatch; + return [passthrough, dispatch]; +} - updateWorkInProgressHook(); // State - // This is a mount. No updates to process. +function updateOptimistic(passthrough, reducer) { + var hook = updateWorkInProgressHook(); + return updateOptimisticImpl(hook, currentHook, passthrough, reducer); +} - var state = stateHook.memoizedState; - var actionQueueHook = updateWorkInProgressHook(); - var actionQueue = actionQueueHook.queue; - var dispatch = actionQueue.dispatch; // This may have changed during the rerender. +function updateOptimisticImpl(hook, current, passthrough, reducer) { + // Optimistic updates are always rebased on top of the latest value passed in + // as an argument. It's called a passthrough because if there are no pending + // updates, it will be returned as-is. + // + // Reset the base state to the passthrough. Future updates will be applied + // on top of this. + hook.baseState = passthrough; // If a reducer is not provided, default to the same one used by useState. + + var resolvedReducer = typeof reducer === 'function' ? reducer : basicStateReducer; + return updateReducerImpl(hook, currentHook, resolvedReducer); +} - actionQueueHook.memoizedState = action; // For mount, pending is always false. +function rerenderOptimistic(passthrough, reducer) { + // Unlike useState, useOptimistic doesn't support render phase updates. + // Also unlike useState, we need to replay all pending updates again in case + // the passthrough value changed. + // + // So instead of a forked re-render implementation that knows how to handle + // render phase udpates, we can use the same implementation as during a + // regular mount or update. + var hook = updateWorkInProgressHook(); + + if (currentHook !== null) { + // This is an update. Process the update queue. + return updateOptimisticImpl(hook, currentHook, passthrough, reducer); + } // This is a mount. No updates to process. + // Reset the base state to the passthrough. Future updates will be applied + // on top of this. + + + hook.baseState = passthrough; + var dispatch = hook.queue.dispatch; + return [passthrough, dispatch]; +} // useActionState actions run sequentially, because each action receives the +// previous state as an argument. We store pending actions on a queue. + + +function dispatchActionState(fiber, actionQueue, setPendingState, setState, payload) { + if (isRenderPhaseUpdate(fiber)) { + throw new Error('Cannot update form state while rendering.'); + } + + var last = actionQueue.pending; + + if (last === null) { + // There are no pending actions; this is the first one. We can run + // it immediately. + var newLast = { + payload: payload, + next: null // circular - return [state, dispatch, false]; - } + }; + newLast.next = actionQueue.pending = newLast; + runActionStateAction(actionQueue, setPendingState, setState, payload); + } else { + // There's already an action running. Add to the queue. + var first = last.next; + var _newLast = { + payload: payload, + next: first + }; + actionQueue.pending = last.next = _newLast; + } +} - function pushEffect(tag, create, inst, deps) { - var effect = { - tag: tag, - create: create, - inst: inst, - deps: deps, - // Circular - next: null - }; - var componentUpdateQueue = currentlyRenderingFiber$1.updateQueue; +function runActionStateAction(actionQueue, setPendingState, setState, payload) { + var action = actionQueue.action; + var prevState = actionQueue.state; // This is a fork of startTransition - if (componentUpdateQueue === null) { - componentUpdateQueue = createFunctionComponentUpdateQueue(); - currentlyRenderingFiber$1.updateQueue = componentUpdateQueue; - componentUpdateQueue.lastEffect = effect.next = effect; - } else { - var lastEffect = componentUpdateQueue.lastEffect; + var prevTransition = ReactSharedInternals.T; + var currentTransition = { + _callbacks: new Set() + }; + ReactSharedInternals.T = currentTransition; - if (lastEffect === null) { - componentUpdateQueue.lastEffect = effect.next = effect; - } else { - var firstEffect = lastEffect.next; - lastEffect.next = effect; - effect.next = firstEffect; - componentUpdateQueue.lastEffect = effect; - } - } + { + ReactSharedInternals.T._updatedFibers = new Set(); + } // Optimistically update the pending state, similar to useTransition. + // This will be reverted automatically when all actions are finished. - return effect; - } - function createEffectInstance() { - return { - destroy: undefined - }; - } + setPendingState(true); - function mountRef(initialValue) { - var hook = mountWorkInProgressHook(); - var ref = { - current: initialValue - }; - hook.memoizedState = ref; - return ref; - } + try { + var returnValue = action(prevState, payload); - function updateRef(initialValue) { - var hook = updateWorkInProgressHook(); - return hook.memoizedState; - } + if (returnValue !== null && typeof returnValue === 'object' && // $FlowFixMe[method-unbinding] + typeof returnValue.then === 'function') { + var thenable = returnValue; + notifyTransitionCallbacks(currentTransition, thenable); // Attach a listener to read the return state of the action. As soon as + // this resolves, we can run the next action in the sequence. - 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, - createEffectInstance(), - nextDeps - ); - } + thenable.then(function (nextState) { + actionQueue.state = nextState; + finishRunningActionStateAction(actionQueue, setPendingState, setState); + }, function () { + return finishRunningActionStateAction(actionQueue, setPendingState, setState); + }); + setState(thenable); + } else { + setState(returnValue); + var nextState = returnValue; + actionQueue.state = nextState; + finishRunningActionStateAction(actionQueue, setPendingState, setState); + } + } catch (error) { + // This is a trick to get the `useActionState` hook to rethrow the error. + // When it unwraps the thenable with the `use` algorithm, the error + // will be thrown. + var rejectedThenable = { + then: function () {}, + status: 'rejected', + reason: error // $FlowFixMe: Not sure why this doesn't work - function updateEffectImpl(fiberFlags, hookFlags, create, deps) { - var hook = updateWorkInProgressHook(); - var nextDeps = deps === undefined ? null : deps; - var effect = hook.memoizedState; - var inst = effect.inst; // currentHook is null on initial mount when rerendering after a render phase - // state update or for strict mode. + }; + setState(rejectedThenable); + finishRunningActionStateAction(actionQueue, setPendingState, setState); + } finally { + ReactSharedInternals.T = prevTransition; - if (currentHook !== null) { - if (nextDeps !== null) { - var prevEffect = currentHook.memoizedState; - var prevDeps = prevEffect.deps; + { + if (prevTransition === null && currentTransition._updatedFibers) { + var updatedFibersCount = currentTransition._updatedFibers.size; - if (areHookInputsEqual(nextDeps, prevDeps)) { - hook.memoizedState = pushEffect(hookFlags, create, inst, nextDeps); - return; - } - } - } + currentTransition._updatedFibers.clear(); - currentlyRenderingFiber$1.flags |= fiberFlags; - hook.memoizedState = pushEffect( - HasEffect | hookFlags, - create, - inst, - nextDeps - ); - } - - function mountEffect(create, deps) { - if ( - (currentlyRenderingFiber$1.mode & StrictEffectsMode) !== NoMode && - (currentlyRenderingFiber$1.mode & NoStrictPassiveEffectsMode) === NoMode - ) { - mountEffectImpl( - MountPassiveDev | Passive$1 | PassiveStatic, - Passive, - create, - deps - ); - } else { - mountEffectImpl(Passive$1 | PassiveStatic, Passive, create, deps); + 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.'); + } } } + } +} - function updateEffect(create, deps) { - updateEffectImpl(Passive$1, Passive, create, deps); - } +function finishRunningActionStateAction(actionQueue, setPendingState, setState) { + // The action finished running. Pop it from the queue and run the next pending + // action, if there are any. + var last = actionQueue.pending; - function mountInsertionEffect(create, deps) { - mountEffectImpl(Update, Insertion, create, deps); - } + if (last !== null) { + var first = last.next; - function updateInsertionEffect(create, deps) { - return updateEffectImpl(Update, Insertion, create, deps); + if (first === last) { + // This was the last action in the queue. + actionQueue.pending = null; + } else { + // Remove the first node from the circular queue. + var next = first.next; + last.next = next; // Run the next action. + + runActionStateAction(actionQueue, setPendingState, setState, next.payload); } + } +} - function mountLayoutEffect(create, deps) { - var fiberFlags = Update | LayoutStatic; +function actionStateReducer(oldState, newState) { + return newState; +} - if ((currentlyRenderingFiber$1.mode & StrictEffectsMode) !== NoMode) { - fiberFlags |= MountLayoutDev; - } +function mountActionState(action, initialStateProp, permalink) { + var initialState = initialStateProp; + // the `use` algorithm during render. + + + var stateHook = mountWorkInProgressHook(); + stateHook.memoizedState = stateHook.baseState = initialState; // TODO: Typing this "correctly" results in recursion limit errors + // const stateQueue: UpdateQueue, S | Awaited> = { + + var stateQueue = { + pending: null, + lanes: NoLanes, + dispatch: null, + lastRenderedReducer: actionStateReducer, + lastRenderedState: initialState + }; + stateHook.queue = stateQueue; + var setState = dispatchSetState.bind(null, currentlyRenderingFiber$1, stateQueue); + stateQueue.dispatch = setState; // Pending state. This is used to store the pending state of the action. + // Tracked optimistically, like a transition pending state. + + var pendingStateHook = mountStateImpl(false); + var setPendingState = dispatchOptimisticSetState.bind(null, currentlyRenderingFiber$1, false, pendingStateHook.queue); // Action queue hook. This is used to queue pending actions. The queue is + // shared between all instances of the hook. Similar to a regular state queue, + // but different because the actions are run sequentially, and they run in + // an event instead of during render. + + var actionQueueHook = mountWorkInProgressHook(); + var actionQueue = { + state: initialState, + dispatch: null, + // circular + action: action, + pending: null + }; + actionQueueHook.queue = actionQueue; + var dispatch = dispatchActionState.bind(null, currentlyRenderingFiber$1, actionQueue, setPendingState, setState); + actionQueue.dispatch = dispatch; // Stash the action function on the memoized state of the hook. We'll use this + // to detect when the action function changes so we can update it in + // an effect. + + actionQueueHook.memoizedState = action; + return [initialState, dispatch, false]; +} - return mountEffectImpl(fiberFlags, Layout, create, deps); - } +function updateActionState(action, initialState, permalink) { + var stateHook = updateWorkInProgressHook(); + var currentStateHook = currentHook; + return updateActionStateImpl(stateHook, currentStateHook, action); +} - function updateLayoutEffect(create, deps) { - return updateEffectImpl(Update, Layout, create, deps); - } +function updateActionStateImpl(stateHook, currentStateHook, action, initialState, permalink) { + var _updateReducerImpl = updateReducerImpl(stateHook, currentStateHook, actionStateReducer), + actionResult = _updateReducerImpl[0]; - 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; + var _updateState = updateState(), + isPending = _updateState[0]; // This will suspend until the action finishes. - { - 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(); + var state = typeof actionResult === 'object' && actionResult !== null && // $FlowFixMe[method-unbinding] + typeof actionResult.then === 'function' ? useThenable(actionResult) : actionResult; + var actionQueueHook = updateWorkInProgressHook(); + var actionQueue = actionQueueHook.queue; + var dispatch = actionQueue.dispatch; // Check if a new action was passed. If so, update it in an effect. - refObject.current = _inst; - return function () { - refObject.current = null; - }; - } - } + var prevAction = actionQueueHook.memoizedState; - 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? + if (action !== prevAction) { + currentlyRenderingFiber$1.flags |= Passive$1; + pushEffect(HasEffect | Passive, actionStateActionEffect.bind(null, actionQueue, action), createEffectInstance(), null); + } - var effectDeps = - deps !== null && deps !== undefined ? deps.concat([ref]) : null; - var fiberFlags = Update | LayoutStatic; + return [state, dispatch, isPending]; +} - if ((currentlyRenderingFiber$1.mode & StrictEffectsMode) !== NoMode) { - fiberFlags |= MountLayoutDev; - } +function actionStateActionEffect(actionQueue, action) { + actionQueue.action = action; +} - mountEffectImpl( - fiberFlags, - Layout, - imperativeHandleEffect.bind(null, create, ref), - effectDeps - ); - } +function rerenderActionState(action, initialState, permalink) { + // Unlike useState, useActionState doesn't support render phase updates. + // Also unlike useState, we need to replay all pending updates again in case + // the passthrough value changed. + // + // So instead of a forked re-render implementation that knows how to handle + // render phase udpates, we can use the same implementation as during a + // regular mount or update. + var stateHook = updateWorkInProgressHook(); + var currentStateHook = currentHook; + + if (currentStateHook !== null) { + // This is an update. Process the update queue. + return updateActionStateImpl(stateHook, currentStateHook, action); + } + + updateWorkInProgressHook(); // State + // This is a mount. No updates to process. + + var state = stateHook.memoizedState; + var actionQueueHook = updateWorkInProgressHook(); + var actionQueue = actionQueueHook.queue; + var dispatch = actionQueue.dispatch; // This may have changed during the rerender. + + actionQueueHook.memoizedState = action; // For mount, pending is always false. + + return [state, dispatch, false]; +} - 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? +function pushEffect(tag, create, inst, deps) { + var effect = { + tag: tag, + create: create, + inst: inst, + 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; +} - var effectDeps = - deps !== null && deps !== undefined ? deps.concat([ref]) : null; - updateEffectImpl( - Update, - Layout, - imperativeHandleEffect.bind(null, create, ref), - effectDeps - ); - } +function createEffectInstance() { + return { + destroy: undefined + }; +} - 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. - } +function mountRef(initialValue) { + var hook = mountWorkInProgressHook(); + var ref = { + current: initialValue + }; + hook.memoizedState = ref; + return ref; +} - var updateDebugValue = mountDebugValue; +function updateRef(initialValue) { + var hook = updateWorkInProgressHook(); + return hook.memoizedState; +} - function mountCallback(callback, deps) { - var hook = mountWorkInProgressHook(); - var nextDeps = deps === undefined ? null : deps; - hook.memoizedState = [callback, nextDeps]; - return callback; - } +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, createEffectInstance(), nextDeps); +} - function updateCallback(callback, deps) { - var hook = updateWorkInProgressHook(); - var nextDeps = deps === undefined ? null : deps; - var prevState = hook.memoizedState; +function updateEffectImpl(fiberFlags, hookFlags, create, deps) { + var hook = updateWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + var effect = hook.memoizedState; + var inst = effect.inst; // currentHook is null on initial mount when rerendering after a render phase + // state update or for strict mode. - if (nextDeps !== null) { - var prevDeps = prevState[1]; + if (currentHook !== null) { + if (nextDeps !== null) { + var prevEffect = currentHook.memoizedState; + var prevDeps = prevEffect.deps; - if (areHookInputsEqual(nextDeps, prevDeps)) { - return prevState[0]; - } + if (areHookInputsEqual(nextDeps, prevDeps)) { + hook.memoizedState = pushEffect(hookFlags, create, inst, nextDeps); + return; } - - hook.memoizedState = [callback, nextDeps]; - return callback; } + } - function mountMemo(nextCreate, deps) { - var hook = mountWorkInProgressHook(); - var nextDeps = deps === undefined ? null : deps; - var nextValue = nextCreate(); + currentlyRenderingFiber$1.flags |= fiberFlags; + hook.memoizedState = pushEffect(HasEffect | hookFlags, create, inst, nextDeps); +} - if (shouldDoubleInvokeUserFnsInHooksDEV) { - setIsStrictModeForDevtools(true); - nextCreate(); - setIsStrictModeForDevtools(false); - } +function mountEffect(create, deps) { + if ((currentlyRenderingFiber$1.mode & StrictEffectsMode) !== NoMode && (currentlyRenderingFiber$1.mode & NoStrictPassiveEffectsMode) === NoMode) { + mountEffectImpl(MountPassiveDev | Passive$1 | PassiveStatic, Passive, create, deps); + } else { + mountEffectImpl(Passive$1 | PassiveStatic, Passive, create, deps); + } +} - hook.memoizedState = [nextValue, nextDeps]; - return nextValue; - } +function updateEffect(create, deps) { + updateEffectImpl(Passive$1, Passive, create, deps); +} - 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 mountInsertionEffect(create, deps) { + mountEffectImpl(Update, Insertion, create, deps); +} - if (nextDeps !== null) { - var prevDeps = prevState[1]; +function updateInsertionEffect(create, deps) { + return updateEffectImpl(Update, Insertion, create, deps); +} - if (areHookInputsEqual(nextDeps, prevDeps)) { - return prevState[0]; - } - } +function mountLayoutEffect(create, deps) { + var fiberFlags = Update | LayoutStatic; - var nextValue = nextCreate(); + if ((currentlyRenderingFiber$1.mode & StrictEffectsMode) !== NoMode) { + fiberFlags |= MountLayoutDev; + } - if (shouldDoubleInvokeUserFnsInHooksDEV) { - setIsStrictModeForDevtools(true); - nextCreate(); - setIsStrictModeForDevtools(false); - } + return mountEffectImpl(fiberFlags, Layout, create, deps); +} - hook.memoizedState = [nextValue, nextDeps]; - return nextValue; - } +function updateLayoutEffect(create, deps) { + return updateEffectImpl(Update, Layout, create, deps); +} - function mountDeferredValue(value, initialValue) { - var hook = mountWorkInProgressHook(); - return mountDeferredValueImpl(hook, value, initialValue); - } +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; - function updateDeferredValue(value, initialValue) { - var hook = updateWorkInProgressHook(); - var resolvedCurrentHook = currentHook; - var prevValue = resolvedCurrentHook.memoizedState; - return updateDeferredValueImpl(hook, prevValue, value, initialValue); + { + 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(', ') + '}'); + } } - function rerenderDeferredValue(value, initialValue) { - var hook = updateWorkInProgressHook(); + var _inst = create(); - if (currentHook === null) { - // This is a rerender during a mount. - return mountDeferredValueImpl(hook, value, initialValue); - } else { - // This is a rerender during an update. - var prevValue = currentHook.memoizedState; - return updateDeferredValueImpl(hook, prevValue, value, initialValue); - } - } - - function mountDeferredValueImpl(hook, value, initialValue) { - if ( - // When `initialValue` is provided, we defer the initial render even if the - // current render is not synchronous. - initialValue !== undefined && // However, to avoid waterfalls, we do not defer if this render - // was itself spawned by an earlier useDeferredValue. Check if DeferredLane - // is part of the render lanes. - !includesSomeLane(renderLanes, DeferredLane) - ) { - // Render with the initial value - hook.memoizedState = initialValue; // Schedule a deferred render to switch to the final value. - - var deferredLane = requestDeferredLane(); - currentlyRenderingFiber$1.lanes = mergeLanes( - currentlyRenderingFiber$1.lanes, - deferredLane - ); - markSkippedUpdateLanes(deferredLane); - return initialValue; - } else { - hook.memoizedState = value; - return value; - } + refObject.current = _inst; + return function () { + refObject.current = null; + }; + } +} + +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? - function updateDeferredValueImpl(hook, prevValue, value, initialValue) { - if (objectIs(value, prevValue)) { - // The incoming value is referentially identical to the currently rendered - // value, so we can bail out quickly. - return value; - } else { - // Received a new value that's different from the current value. - // Check if we're inside a hidden tree - if (isCurrentTreeHidden()) { - // Revealing a prerendered tree is considered the same as mounting new - // one, so we reuse the "mount" path in this case. - var resultValue = mountDeferredValueImpl(hook, value, initialValue); // Unlike during an actual mount, we need to mark this as an update if - // the value changed. - - if (!objectIs(resultValue, prevValue)) { - markWorkInProgressReceivedUpdate(); - } - return resultValue; - } + var effectDeps = deps !== null && deps !== undefined ? deps.concat([ref]) : null; + var fiberFlags = Update | LayoutStatic; - var shouldDeferValue = !includesOnlyNonUrgentLanes(renderLanes); - - if (shouldDeferValue) { - // This is an urgent update. Since the value has changed, keep using the - // previous value and spawn a deferred render to update it later. - // Schedule a deferred render - var deferredLane = requestDeferredLane(); - currentlyRenderingFiber$1.lanes = mergeLanes( - currentlyRenderingFiber$1.lanes, - deferredLane - ); - markSkippedUpdateLanes(deferredLane); // Reuse the previous value. We do not need to mark this as an update, - // because we did not render a new value. - - 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. - // Mark this as an update to prevent the fiber from bailing out. - markWorkInProgressReceivedUpdate(); - hook.memoizedState = value; - return value; - } - } + if ((currentlyRenderingFiber$1.mode & StrictEffectsMode) !== NoMode) { + fiberFlags |= MountLayoutDev; + } + + mountEffectImpl(fiberFlags, Layout, imperativeHandleEffect.bind(null, create, ref), effectDeps); +} + +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? - function startTransition( - fiber, - queue, - pendingState, - finishedState, - callback, - options - ) { - var previousPriority = getCurrentUpdatePriority(); - setCurrentUpdatePriority( - higherEventPriority(previousPriority, ContinuousEventPriority) - ); - var prevTransition = ReactSharedInternals.T; - var currentTransition = { - _callbacks: new Set() - }; - { - // We don't really need to use an optimistic update here, because we - // schedule a second "revert" update below (which we use to suspend the - // transition until the async action scope has finished). But we'll use an - // optimistic update anyway to make it less likely the behavior accidentally - // diverges; for example, both an optimistic update and this one should - // share the same lane. - ReactSharedInternals.T = currentTransition; - dispatchOptimisticSetState(fiber, false, queue, pendingState); - } + var effectDeps = deps !== null && deps !== undefined ? deps.concat([ref]) : null; + updateEffectImpl(Update, Layout, imperativeHandleEffect.bind(null, create, ref), effectDeps); +} - { - currentTransition._updatedFibers = new Set(); - } +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. +} - try { - if (enableAsyncActions) { - var returnValue = callback(); // Check if we're inside an async action scope. If so, we'll entangle - // this new action with the existing scope. - // - // If we're not already inside an async action scope, and this action is - // async, then we'll create a new async scope. - // - // In the async case, the resulting render will suspend until the async - // action scope has finished. - - if ( - returnValue !== null && - typeof returnValue === "object" && - typeof returnValue.then === "function" - ) { - var thenable = returnValue; - notifyTransitionCallbacks(currentTransition, thenable); // Create a thenable that resolves to `finishedState` once the async - // action has completed. - - var thenableForFinishedState = chainThenableValue( - thenable, - finishedState - ); - dispatchSetState(fiber, queue, thenableForFinishedState); - } else { - dispatchSetState(fiber, queue, finishedState); - } - } - } catch (error) { - { - // This is a trick to get the `useTransition` hook to rethrow the error. - // When it unwraps the thenable with the `use` algorithm, the error - // will be thrown. - var rejectedThenable = { - then: function () {}, - status: "rejected", - reason: error - }; - dispatchSetState(fiber, queue, rejectedThenable); - } - } finally { - setCurrentUpdatePriority(previousPriority); - ReactSharedInternals.T = prevTransition; +var updateDebugValue = mountDebugValue; - { - if (prevTransition === null && currentTransition._updatedFibers) { - var updatedFibersCount = currentTransition._updatedFibers.size; +function mountCallback(callback, deps) { + var hook = mountWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + hook.memoizedState = [callback, nextDeps]; + return callback; +} - currentTransition._updatedFibers.clear(); +function updateCallback(callback, deps) { + var hook = updateWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + var prevState = hook.memoizedState; - 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 (nextDeps !== null) { + var prevDeps = prevState[1]; + + if (areHookInputsEqual(nextDeps, prevDeps)) { + return prevState[0]; } + } + + hook.memoizedState = [callback, nextDeps]; + return callback; +} - function mountTransition() { - var stateHook = mountStateImpl(false); // The `start` method never changes. +function mountMemo(nextCreate, deps) { + var hook = mountWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + var nextValue = nextCreate(); - var start = startTransition.bind( - null, - currentlyRenderingFiber$1, - stateHook.queue, - true, - false - ); - var hook = mountWorkInProgressHook(); - hook.memoizedState = start; - return [false, start]; - } + if (shouldDoubleInvokeUserFnsInHooksDEV) { + setIsStrictModeForDevtools(true); + nextCreate(); + setIsStrictModeForDevtools(false); + } - function updateTransition() { - var _updateState2 = updateState(), - booleanOrThenable = _updateState2[0]; + hook.memoizedState = [nextValue, nextDeps]; + return nextValue; +} - var hook = updateWorkInProgressHook(); - var start = hook.memoizedState; - var isPending = - typeof booleanOrThenable === "boolean" - ? booleanOrThenable // This will suspend until the async action scope has finished. - : useThenable(booleanOrThenable); - return [isPending, start]; - } +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 rerenderTransition() { - var _rerenderState = rerenderState(), - booleanOrThenable = _rerenderState[0]; + if (nextDeps !== null) { + var prevDeps = prevState[1]; - var hook = updateWorkInProgressHook(); - var start = hook.memoizedState; - var isPending = - typeof booleanOrThenable === "boolean" - ? booleanOrThenable // This will suspend until the async action scope has finished. - : useThenable(booleanOrThenable); - return [isPending, start]; + if (areHookInputsEqual(nextDeps, prevDeps)) { + return prevState[0]; } + } - function useHostTransitionStatus() { - var status = readContext(HostTransitionContext); - return status !== null ? status : NotPendingTransition; - } + var nextValue = nextCreate(); - 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 (shouldDoubleInvokeUserFnsInHooksDEV) { + setIsStrictModeForDevtools(true); + nextCreate(); + setIsStrictModeForDevtools(false); + } - var identifierPrefix = root.identifierPrefix; - var id; + hook.memoizedState = [nextValue, nextDeps]; + return nextValue; +} - { - // Use a lowercase r prefix for client-generated ids. - var globalClientId = globalClientIdCounter++; - id = ":" + identifierPrefix + "r" + globalClientId.toString(32) + ":"; +function mountDeferredValue(value, initialValue) { + var hook = mountWorkInProgressHook(); + return mountDeferredValueImpl(hook, value, initialValue); +} + +function updateDeferredValue(value, initialValue) { + var hook = updateWorkInProgressHook(); + var resolvedCurrentHook = currentHook; + var prevValue = resolvedCurrentHook.memoizedState; + return updateDeferredValueImpl(hook, prevValue, value, initialValue); +} + +function rerenderDeferredValue(value, initialValue) { + var hook = updateWorkInProgressHook(); + + if (currentHook === null) { + // This is a rerender during a mount. + return mountDeferredValueImpl(hook, value, initialValue); + } else { + // This is a rerender during an update. + var prevValue = currentHook.memoizedState; + return updateDeferredValueImpl(hook, prevValue, value, initialValue); + } +} + +function mountDeferredValueImpl(hook, value, initialValue) { + if (// When `initialValue` is provided, we defer the initial render even if the + // current render is not synchronous. + initialValue !== undefined && // However, to avoid waterfalls, we do not defer if this render + // was itself spawned by an earlier useDeferredValue. Check if DeferredLane + // is part of the render lanes. + !includesSomeLane(renderLanes, DeferredLane)) { + // Render with the initial value + hook.memoizedState = initialValue; // Schedule a deferred render to switch to the final value. + + var deferredLane = requestDeferredLane(); + currentlyRenderingFiber$1.lanes = mergeLanes(currentlyRenderingFiber$1.lanes, deferredLane); + markSkippedUpdateLanes(deferredLane); + return initialValue; + } else { + hook.memoizedState = value; + return value; + } +} + +function updateDeferredValueImpl(hook, prevValue, value, initialValue) { + if (objectIs(value, prevValue)) { + // The incoming value is referentially identical to the currently rendered + // value, so we can bail out quickly. + return value; + } else { + // Received a new value that's different from the current value. + // Check if we're inside a hidden tree + if (isCurrentTreeHidden()) { + // Revealing a prerendered tree is considered the same as mounting new + // one, so we reuse the "mount" path in this case. + var resultValue = mountDeferredValueImpl(hook, value, initialValue); // Unlike during an actual mount, we need to mark this as an update if + // the value changed. + + if (!objectIs(resultValue, prevValue)) { + markWorkInProgressReceivedUpdate(); } - hook.memoizedState = id; - return id; + return resultValue; } - function updateId() { - var hook = updateWorkInProgressHook(); - var id = hook.memoizedState; - return id; + var shouldDeferValue = !includesOnlyNonUrgentLanes(renderLanes); + + if (shouldDeferValue) { + // This is an urgent update. Since the value has changed, keep using the + // previous value and spawn a deferred render to update it later. + // Schedule a deferred render + var deferredLane = requestDeferredLane(); + currentlyRenderingFiber$1.lanes = mergeLanes(currentlyRenderingFiber$1.lanes, deferredLane); + markSkippedUpdateLanes(deferredLane); // Reuse the previous value. We do not need to mark this as an update, + // because we did not render a new value. + + 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. + // Mark this as an update to prevent the fiber from bailing out. + markWorkInProgressReceivedUpdate(); + hook.memoizedState = value; + return value; } + } +} + +function startTransition(fiber, queue, pendingState, finishedState, callback, options) { + var previousPriority = getCurrentUpdatePriority(); + setCurrentUpdatePriority(higherEventPriority(previousPriority, ContinuousEventPriority)); + var prevTransition = ReactSharedInternals.T; + var currentTransition = { + _callbacks: new Set() + }; + + { + // We don't really need to use an optimistic update here, because we + // schedule a second "revert" update below (which we use to suspend the + // transition until the async action scope has finished). But we'll use an + // optimistic update anyway to make it less likely the behavior accidentally + // diverges; for example, both an optimistic update and this one should + // share the same lane. + ReactSharedInternals.T = currentTransition; + dispatchOptimisticSetState(fiber, false, queue, pendingState); + } + + { + currentTransition._updatedFibers = new Set(); + } + + try { + if (enableAsyncActions) { + var returnValue = callback(); // Check if we're inside an async action scope. If so, we'll entangle + // this new action with the existing scope. + // + // If we're not already inside an async action scope, and this action is + // async, then we'll create a new async scope. + // + // In the async case, the resulting render will suspend until the async + // action scope has finished. + + if (returnValue !== null && typeof returnValue === 'object' && typeof returnValue.then === 'function') { + var thenable = returnValue; + notifyTransitionCallbacks(currentTransition, thenable); // Create a thenable that resolves to `finishedState` once the async + // action has completed. - function mountRefresh() { - var hook = mountWorkInProgressHook(); - var refresh = (hook.memoizedState = refreshCache.bind( - null, - currentlyRenderingFiber$1 - )); - return refresh; + var thenableForFinishedState = chainThenableValue(thenable, finishedState); + dispatchSetState(fiber, queue, thenableForFinishedState); + } else { + dispatchSetState(fiber, queue, finishedState); + } + } + } catch (error) { + { + // This is a trick to get the `useTransition` hook to rethrow the error. + // When it unwraps the thenable with the `use` algorithm, the error + // will be thrown. + var rejectedThenable = { + then: function () {}, + status: 'rejected', + reason: error + }; + dispatchSetState(fiber, queue, rejectedThenable); } + } finally { + setCurrentUpdatePriority(previousPriority); + ReactSharedInternals.T = prevTransition; + + { + if (prevTransition === null && currentTransition._updatedFibers) { + var updatedFibersCount = currentTransition._updatedFibers.size; + + currentTransition._updatedFibers.clear(); - function updateRefresh() { - var hook = updateWorkInProgressHook(); - return hook.memoizedState; + 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.'); + } + } } + } +} - function refreshCache(fiber, seedKey, seedValue) { - // TODO: Consider warning if the refresh is at discrete priority, or if we - // otherwise suspect that it wasn't batched properly. +function mountTransition() { + var stateHook = mountStateImpl(false); // The `start` method never changes. - var provider = fiber.return; + var start = startTransition.bind(null, currentlyRenderingFiber$1, stateHook.queue, true, false); + var hook = mountWorkInProgressHook(); + hook.memoizedState = start; + return [false, start]; +} - while (provider !== null) { - switch (provider.tag) { - case CacheComponent: - case HostRoot: { - // Schedule an update on the cache boundary to trigger a refresh. - var lane = requestUpdateLane(provider); - var refreshUpdate = createUpdate(lane); - var root = enqueueUpdate(provider, refreshUpdate, lane); +function updateTransition() { + var _updateState2 = updateState(), + booleanOrThenable = _updateState2[0]; - if (root !== null) { - scheduleUpdateOnFiber(root, provider, lane); - entangleTransitions(root, provider, lane); - } // TODO: If a refresh never commits, the new cache created here must be - // released. A simple case is start refreshing a cache boundary, but then - // unmount that boundary before the refresh completes. + var hook = updateWorkInProgressHook(); + var start = hook.memoizedState; + var isPending = typeof booleanOrThenable === 'boolean' ? booleanOrThenable : // This will suspend until the async action scope has finished. + useThenable(booleanOrThenable); + return [isPending, start]; +} - var seededCache = createCache(); +function rerenderTransition() { + var _rerenderState = rerenderState(), + booleanOrThenable = _rerenderState[0]; - if (seedKey !== null && seedKey !== undefined && root !== null) { - { - { - error( - "The seed argument is not enabled outside experimental channels." - ); - } - } - } + var hook = updateWorkInProgressHook(); + var start = hook.memoizedState; + var isPending = typeof booleanOrThenable === 'boolean' ? booleanOrThenable : // This will suspend until the async action scope has finished. + useThenable(booleanOrThenable); + return [isPending, start]; +} - var payload = { - cache: seededCache - }; - refreshUpdate.payload = payload; - return; - } - } +function useHostTransitionStatus() { - provider = provider.return; - } // TODO: Warn if unmounted? - } + var status = readContext(HostTransitionContext); + return status !== null ? status : NotPendingTransition; +} - 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()." - ); - } - } +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; + + { + // Use a lowercase r prefix for client-generated ids. + var globalClientId = globalClientIdCounter++; + id = ':' + identifierPrefix + 'r' + globalClientId.toString(32) + ':'; + } + + hook.memoizedState = id; + return id; +} - var lane = requestUpdateLane(fiber); - var update = { - lane: lane, - revertLane: NoLane, - action: action, - hasEagerState: false, - eagerState: null, - next: null - }; +function updateId() { + var hook = updateWorkInProgressHook(); + var id = hook.memoizedState; + return id; +} - if (isRenderPhaseUpdate(fiber)) { - enqueueRenderPhaseUpdate(queue, update); - } else { - var root = enqueueConcurrentHookUpdate(fiber, queue, update, lane); +function mountRefresh() { + var hook = mountWorkInProgressHook(); + var refresh = hook.memoizedState = refreshCache.bind(null, currentlyRenderingFiber$1); + return refresh; +} - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, lane); - entangleTransitionUpdate(root, queue, lane); - } - } +function updateRefresh() { + var hook = updateWorkInProgressHook(); + return hook.memoizedState; +} - markUpdateInDevTools(fiber, lane); - } +function refreshCache(fiber, seedKey, seedValue) { + // TODO: Consider warning if the refresh is at discrete priority, or if we + // otherwise suspect that it wasn't batched properly. - 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()." - ); - } - } - var lane = requestUpdateLane(fiber); - var update = { - lane: lane, - revertLane: NoLane, - action: action, - hasEagerState: false, - eagerState: null, - next: null - }; + var provider = fiber.return; - if (isRenderPhaseUpdate(fiber)) { - enqueueRenderPhaseUpdate(queue, update); - } else { - var alternate = fiber.alternate; + while (provider !== null) { + switch (provider.tag) { + case CacheComponent: + case HostRoot: + { + // Schedule an update on the cache boundary to trigger a refresh. + var lane = requestUpdateLane(provider); + var refreshUpdate = createUpdate(lane); + var root = enqueueUpdate(provider, refreshUpdate, lane); - 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; + if (root !== null) { + scheduleUpdateOnFiber(root, provider, lane); + entangleTransitions(root, provider, lane); + } // TODO: If a refresh never commits, the new cache created here must be + // released. A simple case is start refreshing a cache boundary, but then + // unmount that boundary before the refresh completes. - if (lastRenderedReducer !== null) { - var prevDispatcher = null; - { - prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = - InvalidNestedHooksDispatcherOnUpdateInDEV; - } + var seededCache = createCache(); - 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. - - update.hasEagerState = true; - update.eagerState = eagerState; - - 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 { + if (seedKey !== null && seedKey !== undefined && root !== null) { + { { - ReactSharedInternals.H = prevDispatcher; + error('The seed argument is not enabled outside experimental channels.'); } } } + + var payload = { + cache: seededCache + }; + refreshUpdate.payload = payload; + return; } + } - var root = enqueueConcurrentHookUpdate(fiber, queue, update, lane); + provider = provider.return; + } // TODO: Warn if unmounted? - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, lane); - entangleTransitionUpdate(root, queue, lane); - } - } +} - markUpdateInDevTools(fiber, lane); +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().'); } + } - function dispatchOptimisticSetState( - fiber, - throwIfDuringRender, - queue, - action - ) { - var transition = requestCurrentTransition(); + var lane = requestUpdateLane(fiber); + var update = { + lane: lane, + revertLane: NoLane, + action: action, + hasEagerState: false, + eagerState: null, + next: null + }; - { - if (transition === null) { - // An optimistic update occurred, but startTransition is not on the stack. - // There are two likely scenarios. - // One possibility is that the optimistic update is triggered by a regular - // event handler (e.g. `onSubmit`) instead of an action. This is a mistake - // and we will warn. - // The other possibility is the optimistic update is inside an async - // action, but after an `await`. In this case, we can make it "just work" - // by associating the optimistic update with the pending async action. - // Technically it's possible that the optimistic update is unrelated to - // the pending action, but we don't have a way of knowing this for sure - // because browsers currently do not provide a way to track async scope. - // (The AsyncContext proposal, if it lands, will solve this in the - // future.) However, this is no different than the problem of unrelated - // transitions being grouped together — it's not wrong per se, but it's - // not ideal. - // Once AsyncContext starts landing in browsers, we will provide better - // warnings in development for these cases. - if (peekEntangledActionLane() !== NoLane); - else { - // There's no pending async action. The most likely cause is that we're - // inside a regular event handler (e.g. onSubmit) instead of an action. - error( - "An optimistic state update occurred outside a transition or " + - "action. To fix, move the update to an action, or wrap " + - "with startTransition." - ); - } - } - } + if (isRenderPhaseUpdate(fiber)) { + enqueueRenderPhaseUpdate(queue, update); + } else { + var root = enqueueConcurrentHookUpdate(fiber, queue, update, lane); - var update = { - // An optimistic update commits synchronously. - lane: SyncLane, - // After committing, the optimistic update is "reverted" using the same - // lane as the transition it's associated with. - revertLane: requestTransitionLane(), - action: action, - hasEagerState: false, - eagerState: null, - next: null - }; + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, lane); + entangleTransitionUpdate(root, queue, lane); + } + } - if (isRenderPhaseUpdate(fiber)) { - // When calling startTransition during render, this warns instead of - // throwing because throwing would be a breaking change. setOptimisticState - // is a new API so it's OK to throw. - if (throwIfDuringRender) { - throw new Error("Cannot update optimistic state while rendering."); - } else { - // startTransition was called during render. We don't need to do anything - // besides warn here because the render phase update would be overidden by - // the second update, anyway. We can remove this branch and make it throw - // in a future release. - { - error("Cannot call startTransition while rendering."); - } + markUpdateInDevTools(fiber, lane); +} + +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().'); + } + } + + var lane = requestUpdateLane(fiber); + var update = { + lane: lane, + revertLane: NoLane, + action: action, + hasEagerState: false, + eagerState: null, + next: null + }; + + if (isRenderPhaseUpdate(fiber)) { + enqueueRenderPhaseUpdate(queue, update); + } else { + var alternate = fiber.alternate; + + 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; + + if (lastRenderedReducer !== null) { + var prevDispatcher = null; + + { + prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; } - } else { - var root = enqueueConcurrentHookUpdate(fiber, queue, update, SyncLane); - if (root !== null) { - // NOTE: The optimistic update implementation assumes that the transition - // will never be attempted before the optimistic update. This currently - // holds because the optimistic update is always synchronous. If we ever - // change that, we'll need to account for this. - scheduleUpdateOnFiber(root, fiber, SyncLane); // Optimistic updates are always synchronous, so we don't need to call - // entangleTransitionUpdate here. + 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. + + update.hasEagerState = true; + update.eagerState = eagerState; + + 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 { + { + ReactSharedInternals.H = prevDispatcher; + } } } - - markUpdateInDevTools(fiber, SyncLane); } - function isRenderPhaseUpdate(fiber) { - var alternate = fiber.alternate; - return ( - fiber === currentlyRenderingFiber$1 || - (alternate !== null && alternate === currentlyRenderingFiber$1) - ); - } + var root = enqueueConcurrentHookUpdate(fiber, queue, update, lane); - 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 (root !== null) { + scheduleUpdateOnFiber(root, fiber, lane); + entangleTransitionUpdate(root, queue, lane); + } + } - if (pending === null) { - // This is the first update. Create a circular list. - update.next = update; - } else { - update.next = pending.next; - pending.next = update; - } + markUpdateInDevTools(fiber, lane); +} - queue.pending = update; - } // TODO: Move to ReactFiberConcurrentUpdates? +function dispatchOptimisticSetState(fiber, throwIfDuringRender, queue, action) { + var transition = requestCurrentTransition(); + + { + if (transition === null) { + // An optimistic update occurred, but startTransition is not on the stack. + // There are two likely scenarios. + // One possibility is that the optimistic update is triggered by a regular + // event handler (e.g. `onSubmit`) instead of an action. This is a mistake + // and we will warn. + // The other possibility is the optimistic update is inside an async + // action, but after an `await`. In this case, we can make it "just work" + // by associating the optimistic update with the pending async action. + // Technically it's possible that the optimistic update is unrelated to + // the pending action, but we don't have a way of knowing this for sure + // because browsers currently do not provide a way to track async scope. + // (The AsyncContext proposal, if it lands, will solve this in the + // future.) However, this is no different than the problem of unrelated + // transitions being grouped together — it's not wrong per se, but it's + // not ideal. + // Once AsyncContext starts landing in browsers, we will provide better + // warnings in development for these cases. + if (peekEntangledActionLane() !== NoLane) ; else { + // There's no pending async action. The most likely cause is that we're + // inside a regular event handler (e.g. onSubmit) instead of an action. + error('An optimistic state update occurred outside a transition or ' + 'action. To fix, move the update to an action, or wrap ' + 'with startTransition.'); + } + } + } + + var update = { + // An optimistic update commits synchronously. + lane: SyncLane, + // After committing, the optimistic update is "reverted" using the same + // lane as the transition it's associated with. + revertLane: requestTransitionLane(), + action: action, + hasEagerState: false, + eagerState: null, + next: null + }; + + if (isRenderPhaseUpdate(fiber)) { + // When calling startTransition during render, this warns instead of + // throwing because throwing would be a breaking change. setOptimisticState + // is a new API so it's OK to throw. + if (throwIfDuringRender) { + throw new Error('Cannot update optimistic state while rendering.'); + } else { + // startTransition was called during render. We don't need to do anything + // besides warn here because the render phase update would be overidden by + // the second update, anyway. We can remove this branch and make it throw + // in a future release. + { + error('Cannot call startTransition while rendering.'); + } + } + } else { + var root = enqueueConcurrentHookUpdate(fiber, queue, update, SyncLane); + + if (root !== null) { + // NOTE: The optimistic update implementation assumes that the transition + // will never be attempted before the optimistic update. This currently + // holds because the optimistic update is always synchronous. If we ever + // change that, we'll need to account for this. + scheduleUpdateOnFiber(root, fiber, SyncLane); // Optimistic updates are always synchronous, so we don't need to call + // entangleTransitionUpdate here. + } + } + + markUpdateInDevTools(fiber, SyncLane); +} - 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. +function isRenderPhaseUpdate(fiber) { + var alternate = fiber.alternate; + return fiber === currentlyRenderingFiber$1 || alternate !== null && alternate === currentlyRenderingFiber$1; +} - queueLanes = intersectLanes(queueLanes, root.pendingLanes); // Entangle the new transition lane with the other transition lanes. +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 (pending === null) { + // This is the first update. Create a circular list. + update.next = update; + } else { + update.next = pending.next; + pending.next = update; + } + + queue.pending = update; +} // TODO: Move to ReactFiberConcurrentUpdates? + + +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. + + queueLanes = intersectLanes(queueLanes, root.pendingLanes); // Entangle the new transition lane with the other transition lanes. + + 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. + + markRootEntangled(root, newQueueLanes); + } +} - 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. +function markUpdateInDevTools(fiber, lane, action) { - markRootEntangled(root, newQueueLanes); - } - } + { + markStateUpdateScheduled(fiber, lane); + } +} - function markUpdateInDevTools(fiber, lane, action) { - { - markStateUpdateScheduled(fiber, lane); - } - } - - var ContextOnlyDispatcher = { - readContext: readContext, - use: use, - useCallback: throwInvalidHookError, - useContext: throwInvalidHookError, - useEffect: throwInvalidHookError, - useImperativeHandle: throwInvalidHookError, - useLayoutEffect: throwInvalidHookError, - useInsertionEffect: throwInvalidHookError, - useMemo: throwInvalidHookError, - useReducer: throwInvalidHookError, - useRef: throwInvalidHookError, - useState: throwInvalidHookError, - useDebugValue: throwInvalidHookError, - useDeferredValue: throwInvalidHookError, - useTransition: throwInvalidHookError, - useSyncExternalStore: throwInvalidHookError, - useId: throwInvalidHookError - }; +var ContextOnlyDispatcher = { + readContext: readContext, + use: use, + useCallback: throwInvalidHookError, + useContext: throwInvalidHookError, + useEffect: throwInvalidHookError, + useImperativeHandle: throwInvalidHookError, + useLayoutEffect: throwInvalidHookError, + useInsertionEffect: throwInvalidHookError, + useMemo: throwInvalidHookError, + useReducer: throwInvalidHookError, + useRef: throwInvalidHookError, + useState: throwInvalidHookError, + useDebugValue: throwInvalidHookError, + useDeferredValue: throwInvalidHookError, + useTransition: throwInvalidHookError, + useSyncExternalStore: throwInvalidHookError, + useId: throwInvalidHookError +}; + +{ + ContextOnlyDispatcher.useCacheRefresh = throwInvalidHookError; +} - { - ContextOnlyDispatcher.useCacheRefresh = throwInvalidHookError; - } +{ + ContextOnlyDispatcher.useMemoCache = throwInvalidHookError; +} - { - ContextOnlyDispatcher.useMemoCache = throwInvalidHookError; - } +{ + ContextOnlyDispatcher.useHostTransitionStatus = throwInvalidHookError; + ContextOnlyDispatcher.useFormState = throwInvalidHookError; + ContextOnlyDispatcher.useActionState = throwInvalidHookError; +} - { - ContextOnlyDispatcher.useHostTransitionStatus = throwInvalidHookError; - ContextOnlyDispatcher.useFormState = throwInvalidHookError; - ContextOnlyDispatcher.useActionState = throwInvalidHookError; - } +{ + ContextOnlyDispatcher.useOptimistic = throwInvalidHookError; +} - { - ContextOnlyDispatcher.useOptimistic = throwInvalidHookError; - } +var HooksDispatcherOnMountInDEV = null; +var HooksDispatcherOnMountWithHookTypesInDEV = null; +var HooksDispatcherOnUpdateInDEV = null; +var HooksDispatcherOnRerenderInDEV = null; +var InvalidNestedHooksDispatcherOnMountInDEV = null; +var InvalidNestedHooksDispatcherOnUpdateInDEV = null; +var InvalidNestedHooksDispatcherOnRerenderInDEV = null; + +{ + 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().'); + }; + + 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://react.dev/link/rules-of-hooks'); + }; + + HooksDispatcherOnMountInDEV = { + readContext: function (context) { + return readContext(context); + }, + use: use, + 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 = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; - var HooksDispatcherOnMountInDEV = null; - var HooksDispatcherOnMountWithHookTypesInDEV = null; - var HooksDispatcherOnUpdateInDEV = null; - var HooksDispatcherOnRerenderInDEV = null; - var InvalidNestedHooksDispatcherOnMountInDEV = null; - var InvalidNestedHooksDispatcherOnUpdateInDEV = null; - var InvalidNestedHooksDispatcherOnRerenderInDEV = null; + try { + return mountMemo(create, deps); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useReducer: function (reducer, initialArg, init) { + currentHookNameInDev = 'useReducer'; + mountHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; - { - 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()." - ); - }; + try { + return mountReducer(reducer, initialArg, init); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useRef: function (initialValue) { + currentHookNameInDev = 'useRef'; + mountHookTypesDev(); + return mountRef(initialValue); + }, + useState: function (initialState) { + currentHookNameInDev = 'useState'; + mountHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; - 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://react.dev/link/rules-of-hooks" - ); - }; + try { + return mountState(initialState); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useDebugValue: function (value, formatterFn) { + currentHookNameInDev = 'useDebugValue'; + mountHookTypesDev(); + return mountDebugValue(); + }, + useDeferredValue: function (value, initialValue) { + currentHookNameInDev = 'useDeferredValue'; + mountHookTypesDev(); + return mountDeferredValue(value, initialValue); + }, + useTransition: function () { + currentHookNameInDev = 'useTransition'; + mountHookTypesDev(); + return mountTransition(); + }, + useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { + currentHookNameInDev = 'useSyncExternalStore'; + mountHookTypesDev(); + return mountSyncExternalStore(subscribe, getSnapshot); + }, + useId: function () { + currentHookNameInDev = 'useId'; + mountHookTypesDev(); + return mountId(); + } + }; + + { + HooksDispatcherOnMountInDEV.useCacheRefresh = function useCacheRefresh() { + currentHookNameInDev = 'useCacheRefresh'; + mountHookTypesDev(); + return mountRefresh(); + }; + } - HooksDispatcherOnMountInDEV = { - readContext: function (context) { - return readContext(context); - }, - use: use, - 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 = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; + { + HooksDispatcherOnMountInDEV.useMemoCache = useMemoCache; + } - try { - return mountMemo(create, deps); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useReducer: function (reducer, initialArg, init) { - currentHookNameInDev = "useReducer"; - mountHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; + { + HooksDispatcherOnMountInDEV.useHostTransitionStatus = useHostTransitionStatus; - try { - return mountReducer(reducer, initialArg, init); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useRef: function (initialValue) { - currentHookNameInDev = "useRef"; - mountHookTypesDev(); - return mountRef(initialValue); - }, - useState: function (initialState) { - currentHookNameInDev = "useState"; - mountHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; + HooksDispatcherOnMountInDEV.useFormState = function useFormState(action, initialState, permalink) { + currentHookNameInDev = 'useFormState'; + mountHookTypesDev(); + return mountActionState(action, initialState); + }; - try { - return mountState(initialState); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useDebugValue: function (value, formatterFn) { - currentHookNameInDev = "useDebugValue"; - mountHookTypesDev(); - return mountDebugValue(); - }, - useDeferredValue: function (value, initialValue) { - currentHookNameInDev = "useDeferredValue"; - mountHookTypesDev(); - return mountDeferredValue(value, initialValue); - }, - useTransition: function () { - currentHookNameInDev = "useTransition"; - mountHookTypesDev(); - return mountTransition(); - }, - useSyncExternalStore: function ( - subscribe, - getSnapshot, - getServerSnapshot - ) { - currentHookNameInDev = "useSyncExternalStore"; - mountHookTypesDev(); - return mountSyncExternalStore(subscribe, getSnapshot); - }, - useId: function () { - currentHookNameInDev = "useId"; - mountHookTypesDev(); - return mountId(); - } - }; + HooksDispatcherOnMountInDEV.useActionState = function useActionState(action, initialState, permalink) { + currentHookNameInDev = 'useActionState'; + mountHookTypesDev(); + return mountActionState(action, initialState); + }; + } - { - HooksDispatcherOnMountInDEV.useCacheRefresh = - function useCacheRefresh() { - currentHookNameInDev = "useCacheRefresh"; - mountHookTypesDev(); - return mountRefresh(); - }; - } + { + HooksDispatcherOnMountInDEV.useOptimistic = function useOptimistic(passthrough, reducer) { + currentHookNameInDev = 'useOptimistic'; + mountHookTypesDev(); + return mountOptimistic(passthrough); + }; + } + + HooksDispatcherOnMountWithHookTypesInDEV = { + readContext: function (context) { + return readContext(context); + }, + use: use, + 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 = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; - { - HooksDispatcherOnMountInDEV.useMemoCache = useMemoCache; + try { + return mountMemo(create, deps); + } finally { + ReactSharedInternals.H = prevDispatcher; } + }, + useReducer: function (reducer, initialArg, init) { + currentHookNameInDev = 'useReducer'; + updateHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; - { - HooksDispatcherOnMountInDEV.useHostTransitionStatus = - useHostTransitionStatus; - - HooksDispatcherOnMountInDEV.useFormState = function useFormState( - action, - initialState, - permalink - ) { - currentHookNameInDev = "useFormState"; - mountHookTypesDev(); - return mountActionState(action, initialState); - }; + try { + return mountReducer(reducer, initialArg, init); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useRef: function (initialValue) { + currentHookNameInDev = 'useRef'; + updateHookTypesDev(); + return mountRef(initialValue); + }, + useState: function (initialState) { + currentHookNameInDev = 'useState'; + updateHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; - HooksDispatcherOnMountInDEV.useActionState = function useActionState( - action, - initialState, - permalink - ) { - currentHookNameInDev = "useActionState"; - mountHookTypesDev(); - return mountActionState(action, initialState); - }; - } + try { + return mountState(initialState); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useDebugValue: function (value, formatterFn) { + currentHookNameInDev = 'useDebugValue'; + updateHookTypesDev(); + return mountDebugValue(); + }, + useDeferredValue: function (value, initialValue) { + currentHookNameInDev = 'useDeferredValue'; + updateHookTypesDev(); + return mountDeferredValue(value, initialValue); + }, + useTransition: function () { + currentHookNameInDev = 'useTransition'; + updateHookTypesDev(); + return mountTransition(); + }, + useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { + currentHookNameInDev = 'useSyncExternalStore'; + updateHookTypesDev(); + return mountSyncExternalStore(subscribe, getSnapshot); + }, + useId: function () { + currentHookNameInDev = 'useId'; + updateHookTypesDev(); + return mountId(); + } + }; + + { + HooksDispatcherOnMountWithHookTypesInDEV.useCacheRefresh = function useCacheRefresh() { + currentHookNameInDev = 'useCacheRefresh'; + updateHookTypesDev(); + return mountRefresh(); + }; + } - { - HooksDispatcherOnMountInDEV.useOptimistic = function useOptimistic( - passthrough, - reducer - ) { - currentHookNameInDev = "useOptimistic"; - mountHookTypesDev(); - return mountOptimistic(passthrough); - }; - } + { + HooksDispatcherOnMountWithHookTypesInDEV.useMemoCache = useMemoCache; + } - HooksDispatcherOnMountWithHookTypesInDEV = { - readContext: function (context) { - return readContext(context); - }, - use: use, - 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 = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; + { + HooksDispatcherOnMountWithHookTypesInDEV.useHostTransitionStatus = useHostTransitionStatus; - try { - return mountMemo(create, deps); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useReducer: function (reducer, initialArg, init) { - currentHookNameInDev = "useReducer"; - updateHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; + HooksDispatcherOnMountWithHookTypesInDEV.useFormState = function useFormState(action, initialState, permalink) { + currentHookNameInDev = 'useFormState'; + updateHookTypesDev(); + warnOnUseFormStateInDev(); + return mountActionState(action, initialState); + }; - try { - return mountReducer(reducer, initialArg, init); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useRef: function (initialValue) { - currentHookNameInDev = "useRef"; - updateHookTypesDev(); - return mountRef(initialValue); - }, - useState: function (initialState) { - currentHookNameInDev = "useState"; - updateHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; + HooksDispatcherOnMountWithHookTypesInDEV.useActionState = function useActionState(action, initialState, permalink) { + currentHookNameInDev = 'useActionState'; + updateHookTypesDev(); + return mountActionState(action, initialState); + }; + } - try { - return mountState(initialState); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useDebugValue: function (value, formatterFn) { - currentHookNameInDev = "useDebugValue"; - updateHookTypesDev(); - return mountDebugValue(); - }, - useDeferredValue: function (value, initialValue) { - currentHookNameInDev = "useDeferredValue"; - updateHookTypesDev(); - return mountDeferredValue(value, initialValue); - }, - useTransition: function () { - currentHookNameInDev = "useTransition"; - updateHookTypesDev(); - return mountTransition(); - }, - useSyncExternalStore: function ( - subscribe, - getSnapshot, - getServerSnapshot - ) { - currentHookNameInDev = "useSyncExternalStore"; - updateHookTypesDev(); - return mountSyncExternalStore(subscribe, getSnapshot); - }, - useId: function () { - currentHookNameInDev = "useId"; - updateHookTypesDev(); - return mountId(); - } - }; + { + HooksDispatcherOnMountWithHookTypesInDEV.useOptimistic = function useOptimistic(passthrough, reducer) { + currentHookNameInDev = 'useOptimistic'; + updateHookTypesDev(); + return mountOptimistic(passthrough); + }; + } + + HooksDispatcherOnUpdateInDEV = { + readContext: function (context) { + return readContext(context); + }, + use: use, + 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 = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; - { - HooksDispatcherOnMountWithHookTypesInDEV.useCacheRefresh = - function useCacheRefresh() { - currentHookNameInDev = "useCacheRefresh"; - updateHookTypesDev(); - return mountRefresh(); - }; + try { + return updateMemo(create, deps); + } finally { + ReactSharedInternals.H = prevDispatcher; } + }, + useReducer: function (reducer, initialArg, init) { + currentHookNameInDev = 'useReducer'; + updateHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; - { - HooksDispatcherOnMountWithHookTypesInDEV.useMemoCache = useMemoCache; - } + try { + return updateReducer(reducer, initialArg, init); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useRef: function (initialValue) { + currentHookNameInDev = 'useRef'; + updateHookTypesDev(); + return updateRef(); + }, + useState: function (initialState) { + currentHookNameInDev = 'useState'; + updateHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; - { - HooksDispatcherOnMountWithHookTypesInDEV.useHostTransitionStatus = - useHostTransitionStatus; - - HooksDispatcherOnMountWithHookTypesInDEV.useFormState = - function useFormState(action, initialState, permalink) { - currentHookNameInDev = "useFormState"; - updateHookTypesDev(); - warnOnUseFormStateInDev(); - return mountActionState(action, initialState); - }; + try { + return updateState(initialState); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useDebugValue: function (value, formatterFn) { + currentHookNameInDev = 'useDebugValue'; + updateHookTypesDev(); + return updateDebugValue(); + }, + useDeferredValue: function (value, initialValue) { + currentHookNameInDev = 'useDeferredValue'; + updateHookTypesDev(); + return updateDeferredValue(value, initialValue); + }, + useTransition: function () { + currentHookNameInDev = 'useTransition'; + updateHookTypesDev(); + return updateTransition(); + }, + useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { + currentHookNameInDev = 'useSyncExternalStore'; + updateHookTypesDev(); + return updateSyncExternalStore(subscribe, getSnapshot); + }, + useId: function () { + currentHookNameInDev = 'useId'; + updateHookTypesDev(); + return updateId(); + } + }; + + { + HooksDispatcherOnUpdateInDEV.useCacheRefresh = function useCacheRefresh() { + currentHookNameInDev = 'useCacheRefresh'; + updateHookTypesDev(); + return updateRefresh(); + }; + } - HooksDispatcherOnMountWithHookTypesInDEV.useActionState = - function useActionState(action, initialState, permalink) { - currentHookNameInDev = "useActionState"; - updateHookTypesDev(); - return mountActionState(action, initialState); - }; - } + { + HooksDispatcherOnUpdateInDEV.useMemoCache = useMemoCache; + } - { - HooksDispatcherOnMountWithHookTypesInDEV.useOptimistic = - function useOptimistic(passthrough, reducer) { - currentHookNameInDev = "useOptimistic"; - updateHookTypesDev(); - return mountOptimistic(passthrough); - }; + { + HooksDispatcherOnUpdateInDEV.useHostTransitionStatus = useHostTransitionStatus; + + HooksDispatcherOnUpdateInDEV.useFormState = function useFormState(action, initialState, permalink) { + currentHookNameInDev = 'useFormState'; + updateHookTypesDev(); + warnOnUseFormStateInDev(); + return updateActionState(action); + }; + + HooksDispatcherOnUpdateInDEV.useActionState = function useActionState(action, initialState, permalink) { + currentHookNameInDev = 'useActionState'; + updateHookTypesDev(); + return updateActionState(action); + }; + } + + { + HooksDispatcherOnUpdateInDEV.useOptimistic = function useOptimistic(passthrough, reducer) { + currentHookNameInDev = 'useOptimistic'; + updateHookTypesDev(); + return updateOptimistic(passthrough, reducer); + }; + } + + HooksDispatcherOnRerenderInDEV = { + readContext: function (context) { + return readContext(context); + }, + use: use, + 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 = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnRerenderInDEV; + + try { + return updateMemo(create, deps); + } finally { + ReactSharedInternals.H = prevDispatcher; } + }, + useReducer: function (reducer, initialArg, init) { + currentHookNameInDev = 'useReducer'; + updateHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnRerenderInDEV; - HooksDispatcherOnUpdateInDEV = { - readContext: function (context) { - return readContext(context); - }, - use: use, - 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 = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; + try { + return rerenderReducer(reducer, initialArg, init); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useRef: function (initialValue) { + currentHookNameInDev = 'useRef'; + updateHookTypesDev(); + return updateRef(); + }, + useState: function (initialState) { + currentHookNameInDev = 'useState'; + updateHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnRerenderInDEV; - try { - return updateMemo(create, deps); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useReducer: function (reducer, initialArg, init) { - currentHookNameInDev = "useReducer"; - updateHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; + try { + return rerenderState(initialState); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useDebugValue: function (value, formatterFn) { + currentHookNameInDev = 'useDebugValue'; + updateHookTypesDev(); + return updateDebugValue(); + }, + useDeferredValue: function (value, initialValue) { + currentHookNameInDev = 'useDeferredValue'; + updateHookTypesDev(); + return rerenderDeferredValue(value, initialValue); + }, + useTransition: function () { + currentHookNameInDev = 'useTransition'; + updateHookTypesDev(); + return rerenderTransition(); + }, + useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { + currentHookNameInDev = 'useSyncExternalStore'; + updateHookTypesDev(); + return updateSyncExternalStore(subscribe, getSnapshot); + }, + useId: function () { + currentHookNameInDev = 'useId'; + updateHookTypesDev(); + return updateId(); + } + }; + + { + HooksDispatcherOnRerenderInDEV.useCacheRefresh = function useCacheRefresh() { + currentHookNameInDev = 'useCacheRefresh'; + updateHookTypesDev(); + return updateRefresh(); + }; + } - try { - return updateReducer(reducer, initialArg, init); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useRef: function (initialValue) { - currentHookNameInDev = "useRef"; - updateHookTypesDev(); - return updateRef(); - }, - useState: function (initialState) { - currentHookNameInDev = "useState"; - updateHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; + { + HooksDispatcherOnRerenderInDEV.useMemoCache = useMemoCache; + } - try { - return updateState(initialState); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useDebugValue: function (value, formatterFn) { - currentHookNameInDev = "useDebugValue"; - updateHookTypesDev(); - return updateDebugValue(); - }, - useDeferredValue: function (value, initialValue) { - currentHookNameInDev = "useDeferredValue"; - updateHookTypesDev(); - return updateDeferredValue(value, initialValue); - }, - useTransition: function () { - currentHookNameInDev = "useTransition"; - updateHookTypesDev(); - return updateTransition(); - }, - useSyncExternalStore: function ( - subscribe, - getSnapshot, - getServerSnapshot - ) { - currentHookNameInDev = "useSyncExternalStore"; - updateHookTypesDev(); - return updateSyncExternalStore(subscribe, getSnapshot); - }, - useId: function () { - currentHookNameInDev = "useId"; - updateHookTypesDev(); - return updateId(); - } - }; + { + HooksDispatcherOnRerenderInDEV.useHostTransitionStatus = useHostTransitionStatus; - { - HooksDispatcherOnUpdateInDEV.useCacheRefresh = - function useCacheRefresh() { - currentHookNameInDev = "useCacheRefresh"; - updateHookTypesDev(); - return updateRefresh(); - }; + HooksDispatcherOnRerenderInDEV.useFormState = function useFormState(action, initialState, permalink) { + currentHookNameInDev = 'useFormState'; + updateHookTypesDev(); + warnOnUseFormStateInDev(); + return rerenderActionState(action); + }; + + HooksDispatcherOnRerenderInDEV.useActionState = function useActionState(action, initialState, permalink) { + currentHookNameInDev = 'useActionState'; + updateHookTypesDev(); + return rerenderActionState(action); + }; + } + + { + HooksDispatcherOnRerenderInDEV.useOptimistic = function useOptimistic(passthrough, reducer) { + currentHookNameInDev = 'useOptimistic'; + updateHookTypesDev(); + return rerenderOptimistic(passthrough, reducer); + }; + } + + InvalidNestedHooksDispatcherOnMountInDEV = { + readContext: function (context) { + warnInvalidContextAccess(); + return readContext(context); + }, + use: function (usable) { + warnInvalidHookAccess(); + return use(usable); + }, + 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 = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; + + try { + return mountMemo(create, deps); + } finally { + ReactSharedInternals.H = prevDispatcher; } + }, + useReducer: function (reducer, initialArg, init) { + currentHookNameInDev = 'useReducer'; + warnInvalidHookAccess(); + mountHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; - { - HooksDispatcherOnUpdateInDEV.useMemoCache = useMemoCache; + try { + return mountReducer(reducer, initialArg, init); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useRef: function (initialValue) { + currentHookNameInDev = 'useRef'; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountRef(initialValue); + }, + useState: function (initialState) { + currentHookNameInDev = 'useState'; + warnInvalidHookAccess(); + mountHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; + + try { + return mountState(initialState); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useDebugValue: function (value, formatterFn) { + currentHookNameInDev = 'useDebugValue'; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountDebugValue(); + }, + useDeferredValue: function (value, initialValue) { + currentHookNameInDev = 'useDeferredValue'; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountDeferredValue(value, initialValue); + }, + useTransition: function () { + currentHookNameInDev = 'useTransition'; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountTransition(); + }, + useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { + currentHookNameInDev = 'useSyncExternalStore'; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountSyncExternalStore(subscribe, getSnapshot); + }, + useId: function () { + currentHookNameInDev = 'useId'; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountId(); + } + }; + + { + InvalidNestedHooksDispatcherOnMountInDEV.useCacheRefresh = function useCacheRefresh() { + currentHookNameInDev = 'useCacheRefresh'; + mountHookTypesDev(); + return mountRefresh(); + }; + } + + { + InvalidNestedHooksDispatcherOnMountInDEV.useMemoCache = function (size) { + warnInvalidHookAccess(); + return useMemoCache(size); + }; + } + + { + InvalidNestedHooksDispatcherOnMountInDEV.useHostTransitionStatus = useHostTransitionStatus; + + InvalidNestedHooksDispatcherOnMountInDEV.useFormState = function useFormState(action, initialState, permalink) { + currentHookNameInDev = 'useFormState'; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountActionState(action, initialState); + }; + + InvalidNestedHooksDispatcherOnMountInDEV.useActionState = function useActionState(action, initialState, permalink) { + currentHookNameInDev = 'useActionState'; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountActionState(action, initialState); + }; + } + + { + InvalidNestedHooksDispatcherOnMountInDEV.useOptimistic = function useOptimistic(passthrough, reducer) { + currentHookNameInDev = 'useOptimistic'; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountOptimistic(passthrough); + }; + } + + InvalidNestedHooksDispatcherOnUpdateInDEV = { + readContext: function (context) { + warnInvalidContextAccess(); + return readContext(context); + }, + use: function (usable) { + warnInvalidHookAccess(); + return use(usable); + }, + 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 = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; + + try { + return updateMemo(create, deps); + } finally { + ReactSharedInternals.H = prevDispatcher; } + }, + useReducer: function (reducer, initialArg, init) { + currentHookNameInDev = 'useReducer'; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; - { - HooksDispatcherOnUpdateInDEV.useHostTransitionStatus = - useHostTransitionStatus; - - HooksDispatcherOnUpdateInDEV.useFormState = function useFormState( - action, - initialState, - permalink - ) { - currentHookNameInDev = "useFormState"; - updateHookTypesDev(); - warnOnUseFormStateInDev(); - return updateActionState(action); - }; + try { + return updateReducer(reducer, initialArg, init); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useRef: function (initialValue) { + currentHookNameInDev = 'useRef'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateRef(); + }, + useState: function (initialState) { + currentHookNameInDev = 'useState'; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; - HooksDispatcherOnUpdateInDEV.useActionState = function useActionState( - action, - initialState, - permalink - ) { - currentHookNameInDev = "useActionState"; - updateHookTypesDev(); - return updateActionState(action); - }; + try { + return updateState(initialState); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useDebugValue: function (value, formatterFn) { + currentHookNameInDev = 'useDebugValue'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateDebugValue(); + }, + useDeferredValue: function (value, initialValue) { + currentHookNameInDev = 'useDeferredValue'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateDeferredValue(value, initialValue); + }, + useTransition: function () { + currentHookNameInDev = 'useTransition'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateTransition(); + }, + useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { + currentHookNameInDev = 'useSyncExternalStore'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateSyncExternalStore(subscribe, getSnapshot); + }, + useId: function () { + currentHookNameInDev = 'useId'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateId(); + } + }; + + { + InvalidNestedHooksDispatcherOnUpdateInDEV.useCacheRefresh = function useCacheRefresh() { + currentHookNameInDev = 'useCacheRefresh'; + updateHookTypesDev(); + return updateRefresh(); + }; + } + + { + InvalidNestedHooksDispatcherOnUpdateInDEV.useMemoCache = function (size) { + warnInvalidHookAccess(); + return useMemoCache(size); + }; + } + + { + InvalidNestedHooksDispatcherOnUpdateInDEV.useHostTransitionStatus = useHostTransitionStatus; + + InvalidNestedHooksDispatcherOnUpdateInDEV.useFormState = function useFormState(action, initialState, permalink) { + currentHookNameInDev = 'useFormState'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateActionState(action); + }; + + InvalidNestedHooksDispatcherOnUpdateInDEV.useActionState = function useActionState(action, initialState, permalink) { + currentHookNameInDev = 'useActionState'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateActionState(action); + }; + } + + { + InvalidNestedHooksDispatcherOnUpdateInDEV.useOptimistic = function useOptimistic(passthrough, reducer) { + currentHookNameInDev = 'useOptimistic'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateOptimistic(passthrough, reducer); + }; + } + + InvalidNestedHooksDispatcherOnRerenderInDEV = { + readContext: function (context) { + warnInvalidContextAccess(); + return readContext(context); + }, + use: function (usable) { + warnInvalidHookAccess(); + return use(usable); + }, + 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 = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; + + try { + return updateMemo(create, deps); + } finally { + ReactSharedInternals.H = prevDispatcher; } + }, + useReducer: function (reducer, initialArg, init) { + currentHookNameInDev = 'useReducer'; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; - { - HooksDispatcherOnUpdateInDEV.useOptimistic = function useOptimistic( - passthrough, - reducer - ) { - currentHookNameInDev = "useOptimistic"; - updateHookTypesDev(); - return updateOptimistic(passthrough, reducer); - }; + try { + return rerenderReducer(reducer, initialArg, init); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useRef: function (initialValue) { + currentHookNameInDev = 'useRef'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateRef(); + }, + useState: function (initialState) { + currentHookNameInDev = 'useState'; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; + + try { + return rerenderState(initialState); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useDebugValue: function (value, formatterFn) { + currentHookNameInDev = 'useDebugValue'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateDebugValue(); + }, + useDeferredValue: function (value, initialValue) { + currentHookNameInDev = 'useDeferredValue'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return rerenderDeferredValue(value, initialValue); + }, + useTransition: function () { + currentHookNameInDev = 'useTransition'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return rerenderTransition(); + }, + useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { + currentHookNameInDev = 'useSyncExternalStore'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateSyncExternalStore(subscribe, getSnapshot); + }, + useId: function () { + currentHookNameInDev = 'useId'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateId(); + } + }; + + { + InvalidNestedHooksDispatcherOnRerenderInDEV.useCacheRefresh = function useCacheRefresh() { + currentHookNameInDev = 'useCacheRefresh'; + updateHookTypesDev(); + return updateRefresh(); + }; + } + + { + InvalidNestedHooksDispatcherOnRerenderInDEV.useMemoCache = function (size) { + warnInvalidHookAccess(); + return useMemoCache(size); + }; + } + + { + InvalidNestedHooksDispatcherOnRerenderInDEV.useHostTransitionStatus = useHostTransitionStatus; + + InvalidNestedHooksDispatcherOnRerenderInDEV.useFormState = function useFormState(action, initialState, permalink) { + currentHookNameInDev = 'useFormState'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return rerenderActionState(action); + }; + + InvalidNestedHooksDispatcherOnRerenderInDEV.useActionState = function useActionState(action, initialState, permalink) { + currentHookNameInDev = 'useActionState'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return rerenderActionState(action); + }; + } + + { + InvalidNestedHooksDispatcherOnRerenderInDEV.useOptimistic = function useOptimistic(passthrough, reducer) { + currentHookNameInDev = 'useOptimistic'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return rerenderOptimistic(passthrough, reducer); + }; + } +} + +var now = Scheduler$1.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 isCurrentUpdateNested() { + return currentUpdateIsNested; +} + +function markNestedUpdateScheduled() { + { + nestedUpdateScheduled = true; + } +} + +function resetNestedUpdateFlag() { + { + currentUpdateIsNested = false; + nestedUpdateScheduled = false; + } +} + +function syncNestedUpdateFlag() { + { + currentUpdateIsNested = nestedUpdateScheduled; + nestedUpdateScheduled = false; + } +} + +function getCommitTime() { + return commitTime; +} + +function recordCommitTime() { + + commitTime = now(); +} + +function startProfilerTimer(fiber) { + + profilerStartTime = now(); + + if (fiber.actualStartTime < 0) { + fiber.actualStartTime = now(); + } +} + +function stopProfilerTimerIfRunning(fiber) { + + profilerStartTime = -1; +} + +function stopProfilerTimerIfRunningAndRecordDelta(fiber, overrideBaseTime) { + + if (profilerStartTime >= 0) { + var elapsedTime = now() - profilerStartTime; + fiber.actualDuration += elapsedTime; + + if (overrideBaseTime) { + fiber.selfBaseDuration = elapsedTime; + } + + profilerStartTime = -1; + } +} + +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; + + while (parentFiber !== null) { + switch (parentFiber.tag) { + case HostRoot: + var root = parentFiber.stateNode; + root.effectDuration += elapsedTime; + return; + + case Profiler: + var parentStateNode = parentFiber.stateNode; + parentStateNode.effectDuration += elapsedTime; + return; } - HooksDispatcherOnRerenderInDEV = { - readContext: function (context) { - return readContext(context); - }, - use: use, - 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 = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnRerenderInDEV; + parentFiber = parentFiber.return; + } + } +} + +function recordPassiveEffectDuration(fiber) { - try { - return updateMemo(create, deps); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useReducer: function (reducer, initialArg, init) { - currentHookNameInDev = "useReducer"; - updateHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnRerenderInDEV; + 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) - try { - return rerenderReducer(reducer, initialArg, init); - } finally { - ReactSharedInternals.H = prevDispatcher; + var parentFiber = fiber.return; + + while (parentFiber !== null) { + switch (parentFiber.tag) { + case HostRoot: + var root = parentFiber.stateNode; + + if (root !== null) { + root.passiveEffectDuration += elapsedTime; } - }, - useRef: function (initialValue) { - currentHookNameInDev = "useRef"; - updateHookTypesDev(); - return updateRef(); - }, - useState: function (initialState) { - currentHookNameInDev = "useState"; - updateHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnRerenderInDEV; - try { - return rerenderState(initialState); - } finally { - ReactSharedInternals.H = prevDispatcher; + return; + + case Profiler: + var parentStateNode = parentFiber.stateNode; + + 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; } - }, - useDebugValue: function (value, formatterFn) { - currentHookNameInDev = "useDebugValue"; - updateHookTypesDev(); - return updateDebugValue(); - }, - useDeferredValue: function (value, initialValue) { - currentHookNameInDev = "useDeferredValue"; - updateHookTypesDev(); - return rerenderDeferredValue(value, initialValue); - }, - useTransition: function () { - currentHookNameInDev = "useTransition"; - updateHookTypesDev(); - return rerenderTransition(); - }, - useSyncExternalStore: function ( - subscribe, - getSnapshot, - getServerSnapshot - ) { - currentHookNameInDev = "useSyncExternalStore"; - updateHookTypesDev(); - return updateSyncExternalStore(subscribe, getSnapshot); - }, - useId: function () { - currentHookNameInDev = "useId"; - updateHookTypesDev(); - return updateId(); - } - }; - { - HooksDispatcherOnRerenderInDEV.useCacheRefresh = - function useCacheRefresh() { - currentHookNameInDev = "useCacheRefresh"; - updateHookTypesDev(); - return updateRefresh(); - }; + return; } - { - HooksDispatcherOnRerenderInDEV.useMemoCache = useMemoCache; - } + parentFiber = parentFiber.return; + } + } +} - { - HooksDispatcherOnRerenderInDEV.useHostTransitionStatus = - useHostTransitionStatus; - - HooksDispatcherOnRerenderInDEV.useFormState = function useFormState( - action, - initialState, - permalink - ) { - currentHookNameInDev = "useFormState"; - updateHookTypesDev(); - warnOnUseFormStateInDev(); - return rerenderActionState(action); - }; +function startLayoutEffectTimer() { - HooksDispatcherOnRerenderInDEV.useActionState = function useActionState( - action, - initialState, - permalink - ) { - currentHookNameInDev = "useActionState"; - updateHookTypesDev(); - return rerenderActionState(action); - }; - } + layoutEffectStartTime = now(); +} - { - HooksDispatcherOnRerenderInDEV.useOptimistic = function useOptimistic( - passthrough, - reducer - ) { - currentHookNameInDev = "useOptimistic"; - updateHookTypesDev(); - return rerenderOptimistic(passthrough, reducer); - }; - } +function startPassiveEffectTimer() { - InvalidNestedHooksDispatcherOnMountInDEV = { - readContext: function (context) { - warnInvalidContextAccess(); - return readContext(context); - }, - use: function (usable) { - warnInvalidHookAccess(); - return use(usable); - }, - 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 = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; + passiveEffectStartTime = now(); +} - try { - return mountMemo(create, deps); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useReducer: function (reducer, initialArg, init) { - currentHookNameInDev = "useReducer"; - warnInvalidHookAccess(); - mountHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; +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; + + while (child) { + // $FlowFixMe[unsafe-addition] addition with possible null/undefined value + fiber.actualDuration += child.actualDuration; + child = child.sibling; + } +} - try { - return mountReducer(reducer, initialArg, init); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useRef: function (initialValue) { - currentHookNameInDev = "useRef"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountRef(initialValue); - }, - useState: function (initialState) { - currentHookNameInDev = "useState"; - warnInvalidHookAccess(); - mountHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; +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); +} - try { - return mountState(initialState); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useDebugValue: function (value, formatterFn) { - currentHookNameInDev = "useDebugValue"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountDebugValue(); - }, - useDeferredValue: function (value, initialValue) { - currentHookNameInDev = "useDeferredValue"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountDeferredValue(value, initialValue); - }, - useTransition: function () { - currentHookNameInDev = "useTransition"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountTransition(); - }, - useSyncExternalStore: function ( - subscribe, - getSnapshot, - getServerSnapshot - ) { - currentHookNameInDev = "useSyncExternalStore"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountSyncExternalStore(subscribe, getSnapshot); - }, - useId: function () { - currentHookNameInDev = "useId"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountId(); - } - }; +function warnOnInvalidCallback(callback) { + { + if (callback === null || typeof callback === 'function') { + return; + } // eslint-disable-next-line react-internal/safe-string-coercion - { - InvalidNestedHooksDispatcherOnMountInDEV.useCacheRefresh = - function useCacheRefresh() { - currentHookNameInDev = "useCacheRefresh"; - mountHookTypesDev(); - return mountRefresh(); - }; + + var key = String(callback); + + if (!didWarnOnInvalidCallback.has(key)) { + didWarnOnInvalidCallback.add(key); + + error('Expected the last optional `callback` argument to be a ' + 'function. Instead received: %s.', 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); } + } + } +} + +function applyDerivedStateFromProps(workInProgress, ctor, getDerivedStateFromProps, nextProps) { + var prevState = workInProgress.memoizedState; + var partialState = getDerivedStateFromProps(nextProps, prevState); + + { + + 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) { { - InvalidNestedHooksDispatcherOnMountInDEV.useMemoCache = function ( - size - ) { - warnInvalidHookAccess(); - return useMemoCache(size); - }; + warnOnInvalidCallback(callback); } - { - InvalidNestedHooksDispatcherOnMountInDEV.useHostTransitionStatus = - useHostTransitionStatus; - - InvalidNestedHooksDispatcherOnMountInDEV.useFormState = - function useFormState(action, initialState, permalink) { - currentHookNameInDev = "useFormState"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountActionState(action, initialState); - }; + update.callback = callback; + } - InvalidNestedHooksDispatcherOnMountInDEV.useActionState = - function useActionState(action, initialState, permalink) { - currentHookNameInDev = "useActionState"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountActionState(action, initialState); - }; - } + var root = enqueueUpdate(fiber, update, lane); + + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, lane); + entangleTransitions(root, fiber, lane); + } + { + 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; + + if (callback !== undefined && callback !== null) { { - InvalidNestedHooksDispatcherOnMountInDEV.useOptimistic = - function useOptimistic(passthrough, reducer) { - currentHookNameInDev = "useOptimistic"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountOptimistic(passthrough); - }; + warnOnInvalidCallback(callback); } - InvalidNestedHooksDispatcherOnUpdateInDEV = { - readContext: function (context) { - warnInvalidContextAccess(); - return readContext(context); - }, - use: function (usable) { - warnInvalidHookAccess(); - return use(usable); - }, - 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 = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; + update.callback = callback; + } - try { - return updateMemo(create, deps); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useReducer: function (reducer, initialArg, init) { - currentHookNameInDev = "useReducer"; - warnInvalidHookAccess(); - updateHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; + var root = enqueueUpdate(fiber, update, lane); - try { - return updateReducer(reducer, initialArg, init); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useRef: function (initialValue) { - currentHookNameInDev = "useRef"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateRef(); - }, - useState: function (initialState) { - currentHookNameInDev = "useState"; - warnInvalidHookAccess(); - updateHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, lane); + entangleTransitions(root, fiber, lane); + } - try { - return updateState(initialState); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useDebugValue: function (value, formatterFn) { - currentHookNameInDev = "useDebugValue"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateDebugValue(); - }, - useDeferredValue: function (value, initialValue) { - currentHookNameInDev = "useDeferredValue"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateDeferredValue(value, initialValue); - }, - useTransition: function () { - currentHookNameInDev = "useTransition"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateTransition(); - }, - useSyncExternalStore: function ( - subscribe, - getSnapshot, - getServerSnapshot - ) { - currentHookNameInDev = "useSyncExternalStore"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateSyncExternalStore(subscribe, getSnapshot); - }, - useId: function () { - currentHookNameInDev = "useId"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateId(); - } - }; + { + 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 (callback !== undefined && callback !== null) { { - InvalidNestedHooksDispatcherOnUpdateInDEV.useCacheRefresh = - function useCacheRefresh() { - currentHookNameInDev = "useCacheRefresh"; - updateHookTypesDev(); - return updateRefresh(); - }; + warnOnInvalidCallback(callback); } - { - InvalidNestedHooksDispatcherOnUpdateInDEV.useMemoCache = function ( - size - ) { - warnInvalidHookAccess(); - return useMemoCache(size); - }; + update.callback = callback; + } + + var root = enqueueUpdate(fiber, update, lane); + + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, lane); + entangleTransitions(root, fiber, lane); + } + + { + markForceUpdateScheduled(fiber, lane); + } + } +}; + +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 (shouldUpdate === undefined) { + error('%s.shouldComponentUpdate(): Returned undefined instead of a ' + 'boolean value. Make sure to return true or false.', getComponentNameFromType(ctor) || 'Component'); } + } - { - InvalidNestedHooksDispatcherOnUpdateInDEV.useHostTransitionStatus = - useHostTransitionStatus; - - InvalidNestedHooksDispatcherOnUpdateInDEV.useFormState = - function useFormState(action, initialState, permalink) { - currentHookNameInDev = "useFormState"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateActionState(action); - }; + return shouldUpdate; + } - InvalidNestedHooksDispatcherOnUpdateInDEV.useActionState = - function useActionState(action, initialState, permalink) { - currentHookNameInDev = "useActionState"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateActionState(action); - }; - } + if (ctor.prototype && ctor.prototype.isPureReactComponent) { + return !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState); + } - { - InvalidNestedHooksDispatcherOnUpdateInDEV.useOptimistic = - function useOptimistic(passthrough, reducer) { - currentHookNameInDev = "useOptimistic"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateOptimistic(passthrough, reducer); - }; + return true; +} + +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('No `render` method found on the %s ' + 'instance: did you accidentally return an object from the constructor?', name); + } else { + error('No `render` method found on the %s ' + 'instance: you may have forgotten to define `render`.', name); } + } - InvalidNestedHooksDispatcherOnRerenderInDEV = { - readContext: function (context) { - warnInvalidContextAccess(); - return readContext(context); - }, - use: function (usable) { - warnInvalidHookAccess(); - return use(usable); - }, - 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 = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; + 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); + } - try { - return updateMemo(create, deps); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useReducer: function (reducer, initialArg, init) { - currentHookNameInDev = "useReducer"; - warnInvalidHookAccess(); - updateHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; + 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); + } - try { - return rerenderReducer(reducer, initialArg, init); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useRef: function (initialValue) { - currentHookNameInDev = "useRef"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateRef(); - }, - useState: function (initialState) { - currentHookNameInDev = "useState"; - warnInvalidHookAccess(); - updateHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; + if (instance.propTypes) { + error('propTypes was defined as an instance property on %s. Use a static ' + 'property to define propTypes instead.', name); + } - try { - return rerenderState(initialState); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useDebugValue: function (value, formatterFn) { - currentHookNameInDev = "useDebugValue"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateDebugValue(); - }, - useDeferredValue: function (value, initialValue) { - currentHookNameInDev = "useDeferredValue"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return rerenderDeferredValue(value, initialValue); - }, - useTransition: function () { - currentHookNameInDev = "useTransition"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return rerenderTransition(); - }, - useSyncExternalStore: function ( - subscribe, - getSnapshot, - getServerSnapshot - ) { - currentHookNameInDev = "useSyncExternalStore"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateSyncExternalStore(subscribe, getSnapshot); - }, - useId: function () { - currentHookNameInDev = "useId"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateId(); - } - }; + if (instance.contextType) { + error('contextType was defined as an instance property on %s. Use a static ' + 'property to define contextType instead.', name); + } - { - InvalidNestedHooksDispatcherOnRerenderInDEV.useCacheRefresh = - function useCacheRefresh() { - currentHookNameInDev = "useCacheRefresh"; - updateHookTypesDev(); - return updateRefresh(); - }; + { + if (instance.contextTypes) { + error('contextTypes was defined as an instance property on %s. Use a static ' + 'property to define contextTypes instead.', name); } - { - InvalidNestedHooksDispatcherOnRerenderInDEV.useMemoCache = function ( - size - ) { - warnInvalidHookAccess(); - return useMemoCache(size); - }; + if (ctor.contextType && ctor.contextTypes && !didWarnAboutContextTypeAndContextTypes.has(ctor)) { + didWarnAboutContextTypeAndContextTypes.add(ctor); + + error('%s declares both contextTypes and contextType static properties. ' + 'The legacy contextTypes property will be ignored.', name); } + } - { - InvalidNestedHooksDispatcherOnRerenderInDEV.useHostTransitionStatus = - useHostTransitionStatus; - - InvalidNestedHooksDispatcherOnRerenderInDEV.useFormState = - function useFormState(action, initialState, permalink) { - currentHookNameInDev = "useFormState"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return rerenderActionState(action); - }; + 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); + } - InvalidNestedHooksDispatcherOnRerenderInDEV.useActionState = - function useActionState(action, initialState, permalink) { - currentHookNameInDev = "useActionState"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return rerenderActionState(action); - }; - } + 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'); + } - { - InvalidNestedHooksDispatcherOnRerenderInDEV.useOptimistic = - function useOptimistic(passthrough, reducer) { - currentHookNameInDev = "useOptimistic"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return rerenderOptimistic(passthrough, reducer); - }; - } + if (typeof instance.componentDidUnmount === 'function') { + error('%s has a method called ' + 'componentDidUnmount(). But there is no such lifecycle method. ' + 'Did you mean componentWillUnmount()?', name); } - var now = Scheduler$1.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 isCurrentUpdateNested() { - return currentUpdateIsNested; - } - - function markNestedUpdateScheduled() { - { - nestedUpdateScheduled = true; - } + 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 resetNestedUpdateFlag() { - { - currentUpdateIsNested = false; - nestedUpdateScheduled = false; - } + if (typeof instance.componentWillRecieveProps === 'function') { + error('%s has a method called ' + 'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?', name); } - function syncNestedUpdateFlag() { - { - currentUpdateIsNested = nestedUpdateScheduled; - nestedUpdateScheduled = false; - } + if (typeof instance.UNSAFE_componentWillRecieveProps === 'function') { + error('%s has a method called ' + 'UNSAFE_componentWillRecieveProps(). Did you mean UNSAFE_componentWillReceiveProps()?', name); } - function getCommitTime() { - return commitTime; + var hasMutatedProps = instance.props !== newProps; + + if (instance.props !== undefined && hasMutatedProps) { + error('When calling super() in `%s`, make sure to pass ' + "up the same props that your component's constructor was passed.", name); } - function recordCommitTime() { - commitTime = now(); + 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); } - function startProfilerTimer(fiber) { - profilerStartTime = now(); + if (typeof instance.getSnapshotBeforeUpdate === 'function' && typeof instance.componentDidUpdate !== 'function' && !didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.has(ctor)) { + didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.add(ctor); - if (fiber.actualStartTime < 0) { - fiber.actualStartTime = now(); - } + error('%s: getSnapshotBeforeUpdate() should be used with componentDidUpdate(). ' + 'This component defines getSnapshotBeforeUpdate() only.', getComponentNameFromType(ctor)); + } + + 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); + } + + 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 (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); } - function stopProfilerTimerIfRunning(fiber) { - profilerStartTime = -1; + var state = instance.state; + + if (state && (typeof state !== 'object' || isArray(state))) { + error('%s.state: must be set to an object or null', name); } - function stopProfilerTimerIfRunningAndRecordDelta(fiber, overrideBaseTime) { - if (profilerStartTime >= 0) { - var elapsedTime = now() - profilerStartTime; - fiber.actualDuration += elapsedTime; + if (typeof instance.getChildContext === 'function' && typeof ctor.childContextTypes !== 'object') { + error('%s.getChildContext(): childContextTypes must be defined in order to ' + 'use getChildContext().', name); + } + } +} - if (overrideBaseTime) { - fiber.selfBaseDuration = elapsedTime; +function constructClassInstance(workInProgress, ctor, props) { + var isLegacyContextConsumer = false; + var unmaskedContext = emptyContextObject; + var context = emptyContextObject; + var contextType = ctor.contextType; + + { + if ('contextType' in ctor) { + var isValid = // Allow null for conditional declaration + contextType === null || contextType !== undefined && contextType.$$typeof === REACT_CONTEXT_TYPE; + + if (!isValid && !didWarnAboutInvalidateContextType.has(ctor)) { + didWarnAboutInvalidateContextType.add(ctor); + var addendum = ''; + + 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_CONSUMER_TYPE) { + addendum = ' Did you accidentally pass the Context.Consumer instead?'; + } else { + addendum = ' However, it is set to an object with keys {' + Object.keys(contextType).join(', ') + '}.'; } - profilerStartTime = -1; + error('%s defines an invalid contextType. ' + 'contextType should point to the Context object returned by React.createContext().%s', getComponentNameFromType(ctor) || 'Component', addendum); } } + } - 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) + 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 parentFiber = fiber.return; + var instance = new ctor(props, context); // Instantiate twice to help detect side-effects. - while (parentFiber !== null) { - switch (parentFiber.tag) { - case HostRoot: - var root = parentFiber.stateNode; - root.effectDuration += elapsedTime; - return; + var state = workInProgress.memoizedState = instance.state !== null && instance.state !== undefined ? instance.state : null; + instance.updater = classComponentUpdater; + workInProgress.stateNode = instance; // The instance needs access to the fiber so that it can schedule updates - case Profiler: - var parentStateNode = parentFiber.stateNode; - parentStateNode.effectDuration += elapsedTime; - return; - } + set(instance, workInProgress); - parentFiber = parentFiber.return; - } + { + instance._reactInternalInstance = fakeInternalInstance; + } + + { + 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. - 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 parentFiber = fiber.return; + if (typeof ctor.getDerivedStateFromProps === 'function' || typeof instance.getSnapshotBeforeUpdate === 'function') { + var foundWillMountName = null; + var foundWillReceivePropsName = null; + var foundWillUpdateName = null; - while (parentFiber !== null) { - switch (parentFiber.tag) { - case HostRoot: - var root = parentFiber.stateNode; + if (typeof instance.componentWillMount === 'function' && instance.componentWillMount.__suppressDeprecationWarning !== true) { + foundWillMountName = 'componentWillMount'; + } else if (typeof instance.UNSAFE_componentWillMount === 'function') { + foundWillMountName = 'UNSAFE_componentWillMount'; + } - if (root !== null) { - root.passiveEffectDuration += elapsedTime; - } + if (typeof instance.componentWillReceiveProps === 'function' && instance.componentWillReceiveProps.__suppressDeprecationWarning !== true) { + foundWillReceivePropsName = 'componentWillReceiveProps'; + } else if (typeof instance.UNSAFE_componentWillReceiveProps === 'function') { + foundWillReceivePropsName = 'UNSAFE_componentWillReceiveProps'; + } - return; + if (typeof instance.componentWillUpdate === 'function' && instance.componentWillUpdate.__suppressDeprecationWarning !== true) { + foundWillUpdateName = 'componentWillUpdate'; + } else if (typeof instance.UNSAFE_componentWillUpdate === 'function') { + foundWillUpdateName = 'UNSAFE_componentWillUpdate'; + } - case Profiler: - var parentStateNode = parentFiber.stateNode; + if (foundWillMountName !== null || foundWillReceivePropsName !== null || foundWillUpdateName !== null) { + var _componentName = getComponentNameFromType(ctor) || 'Component'; - 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 newApiName = typeof ctor.getDerivedStateFromProps === 'function' ? 'getDerivedStateFromProps()' : 'getSnapshotBeforeUpdate()'; - return; - } + if (!didWarnAboutLegacyLifecyclesAndDerivedState.has(_componentName)) { + didWarnAboutLegacyLifecyclesAndDerivedState.add(_componentName); - parentFiber = parentFiber.return; + 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://react.dev/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. - function startLayoutEffectTimer() { - layoutEffectStartTime = now(); - } - function startPassiveEffectTimer() { - passiveEffectStartTime = now(); - } + if (isLegacyContextConsumer) { + cacheContext(workInProgress, unmaskedContext, context); + } - 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; + return instance; +} - while (child) { - // $FlowFixMe[unsafe-addition] addition with possible null/undefined value - fiber.actualDuration += child.actualDuration; - child = child.sibling; - } - } +function callComponentWillMount(workInProgress, instance) { + var oldState = instance.state; + + if (typeof instance.componentWillMount === 'function') { + instance.componentWillMount(); + } - var fakeInternalInstance = {}; - var didWarnAboutStateAssignmentForComponent; - var didWarnAboutUninitializedState; - var didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate; - var didWarnAboutLegacyLifecyclesAndDerivedState; - var didWarnAboutUndefinedDerivedState; - var didWarnAboutDirectlyAssigningPropsToState; - var didWarnAboutContextTypeAndContextTypes; - var didWarnAboutInvalidateContextType; - var didWarnOnInvalidCallback; + if (typeof instance.UNSAFE_componentWillMount === 'function') { + instance.UNSAFE_componentWillMount(); + } + if (oldState !== instance.state) { { - 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); + error('%s.componentWillMount(): Assigning directly to this.state is ' + "deprecated (except inside a component's " + 'constructor). Use setState instead.', getComponentNameFromFiber(workInProgress) || 'Component'); } - function warnOnInvalidCallback(callback) { - { - if (callback === null || typeof callback === "function") { - return; - } // eslint-disable-next-line react-internal/safe-string-coercion + classComponentUpdater.enqueueReplaceState(instance, instance.state, null); + } +} - var key = String(callback); +function callComponentWillReceiveProps(workInProgress, instance, newProps, nextContext) { + var oldState = instance.state; - if (!didWarnOnInvalidCallback.has(key)) { - didWarnOnInvalidCallback.add(key); + if (typeof instance.componentWillReceiveProps === 'function') { + instance.componentWillReceiveProps(newProps, nextContext); + } - error( - "Expected the last optional `callback` argument to be a " + - "function. Instead received: %s.", - callback - ); - } - } - } + if (typeof instance.UNSAFE_componentWillReceiveProps === 'function') { + instance.UNSAFE_componentWillReceiveProps(newProps, nextContext); + } - function warnOnUndefinedDerivedState(type, partialState) { - { - if (partialState === undefined) { - var componentName = getComponentNameFromType(type) || "Component"; + if (instance.state !== oldState) { + { + var componentName = getComponentNameFromFiber(workInProgress) || 'Component'; - if (!didWarnAboutUndefinedDerivedState.has(componentName)) { - didWarnAboutUndefinedDerivedState.add(componentName); + if (!didWarnAboutStateAssignmentForComponent.has(componentName)) { + didWarnAboutStateAssignmentForComponent.add(componentName); - error( - "%s.getDerivedStateFromProps(): A valid state object (or null) must be returned. " + - "You have returned undefined.", - componentName - ); - } - } + error('%s.componentWillReceiveProps(): Assigning directly to ' + "this.state is deprecated (except inside a component's " + 'constructor). Use setState instead.', componentName); } } - function applyDerivedStateFromProps( - workInProgress, - ctor, - getDerivedStateFromProps, - nextProps - ) { - var prevState = workInProgress.memoizedState; - var partialState = getDerivedStateFromProps(nextProps, prevState); + classComponentUpdater.enqueueReplaceState(instance, instance.state, null); + } +} // Invokes the mount life-cycles on a previously never rendered instance. - { - 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. +function mountClassInstance(workInProgress, ctor, newProps, renderLanes) { + { + checkClassInstance(workInProgress, ctor, newProps); + } - if (workInProgress.lanes === NoLanes) { - // Queue is always non-null for classes - var updateQueue = workInProgress.updateQueue; - updateQueue.baseState = memoizedState; + 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); + } + + { + if (instance.state === newProps) { + var componentName = getComponentNameFromType(ctor) || 'Component'; + + 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 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 (workInProgress.mode & StrictLegacyMode) { + ReactStrictModeWarnings.recordLegacyContextWarning(workInProgress, instance); + } - if (callback !== undefined && callback !== null) { - { - warnOnInvalidCallback(callback); - } + ReactStrictModeWarnings.recordUnsafeLifecycleWarnings(workInProgress, instance); + } - update.callback = callback; - } + instance.state = workInProgress.memoizedState; + var getDerivedStateFromProps = ctor.getDerivedStateFromProps; - var root = enqueueUpdate(fiber, update, lane); + 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 (root !== null) { - scheduleUpdateOnFiber(root, fiber, lane); - entangleTransitions(root, fiber, lane); - } - { - 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; - - if (callback !== undefined && callback !== null) { - { - warnOnInvalidCallback(callback); - } + 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. - update.callback = callback; - } + processUpdateQueue(workInProgress, newProps, instance, renderLanes); + suspendIfUpdateReadFromEntangledAsyncAction(); + instance.state = workInProgress.memoizedState; + } - var root = enqueueUpdate(fiber, update, lane); + if (typeof instance.componentDidMount === 'function') { + workInProgress.flags |= Update | LayoutStatic; + } - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, lane); - entangleTransitions(root, fiber, lane); - } + if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { + workInProgress.flags |= MountLayoutDev; + } +} - { - 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 (callback !== undefined && callback !== null) { - { - warnOnInvalidCallback(callback); - } +function resumeMountClassInstance(workInProgress, ctor, newProps, renderLanes) { + var instance = workInProgress.stateNode; + var unresolvedOldProps = workInProgress.memoizedProps; + var oldProps = resolveClassComponentProps(ctor, unresolvedOldProps, workInProgress.type === workInProgress.elementType); + 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); + } + + var getDerivedStateFromProps = ctor.getDerivedStateFromProps; + var hasNewLifecycles = typeof getDerivedStateFromProps === 'function' || typeof instance.getSnapshotBeforeUpdate === 'function'; // When comparing whether props changed, we should compare using the + // unresolved props object that is stored on the fiber, rather than the + // one that gets assigned to the instance, because that object may have been + // cloned to resolve default props and/or remove `ref`. + + var unresolvedNewProps = workInProgress.pendingProps; + var didReceiveNewProps = unresolvedNewProps !== unresolvedOldProps; // 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 (didReceiveNewProps || oldContext !== nextContext) { + callComponentWillReceiveProps(workInProgress, instance, newProps, nextContext); + } + } + + resetHasForceUpdateBeforeProcessing(); + var oldState = workInProgress.memoizedState; + var newState = instance.state = oldState; + processUpdateQueue(workInProgress, newProps, instance, renderLanes); + suspendIfUpdateReadFromEntangledAsyncAction(); + newState = workInProgress.memoizedState; + + if (!didReceiveNewProps && 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') { + workInProgress.flags |= Update | LayoutStatic; + } + + if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { + workInProgress.flags |= MountLayoutDev; + } + + return false; + } + + if (typeof getDerivedStateFromProps === 'function') { + applyDerivedStateFromProps(workInProgress, ctor, getDerivedStateFromProps, newProps); + newState = workInProgress.memoizedState; + } + + 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(); + } - update.callback = callback; - } + if (typeof instance.UNSAFE_componentWillMount === 'function') { + instance.UNSAFE_componentWillMount(); + } + } - var root = enqueueUpdate(fiber, update, lane); + if (typeof instance.componentDidMount === 'function') { + workInProgress.flags |= Update | LayoutStatic; + } - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, lane); - entangleTransitions(root, fiber, lane); - } + if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { + workInProgress.flags |= MountLayoutDev; + } + } 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') { + workInProgress.flags |= Update | LayoutStatic; + } - { - markForceUpdateScheduled(fiber, lane); - } - } - }; + if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { + workInProgress.flags |= MountLayoutDev; + } // If shouldComponentUpdate returned false, we should still update the + // memoized state to indicate that this work can be reused. - 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 (shouldUpdate === undefined) { - error( - "%s.shouldComponentUpdate(): Returned undefined instead of a " + - "boolean value. Make sure to return true or false.", - getComponentNameFromType(ctor) || "Component" - ); - } - } + workInProgress.memoizedProps = newProps; + workInProgress.memoizedState = newState; + } // Update the existing instance's state, props, and context pointers even + // if shouldComponentUpdate returns false. - return shouldUpdate; - } - if (ctor.prototype && ctor.prototype.isPureReactComponent) { - return ( - !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState) - ); - } + instance.props = newProps; + instance.state = newState; + instance.context = nextContext; + return shouldUpdate; +} // Invokes the update life-cycles and returns false if it shouldn't rerender. - return true; - } - function checkClassInstance(workInProgress, ctor, newProps) { - var instance = workInProgress.stateNode; +function updateClassInstance(current, workInProgress, ctor, newProps, renderLanes) { + var instance = workInProgress.stateNode; + cloneUpdateQueue(current, workInProgress); + var unresolvedOldProps = workInProgress.memoizedProps; + var oldProps = resolveClassComponentProps(ctor, unresolvedOldProps, workInProgress.type === workInProgress.elementType); + instance.props = oldProps; + var unresolvedNewProps = workInProgress.pendingProps; + var oldContext = instance.context; + var contextType = ctor.contextType; + var nextContext = emptyContextObject; - { - var name = getComponentNameFromType(ctor) || "Component"; - var renderPresent = instance.render; - - if (!renderPresent) { - if (ctor.prototype && typeof ctor.prototype.render === "function") { - error( - "No `render` method found on the %s " + - "instance: did you accidentally return an object from the constructor?", - name - ); - } else { - error( - "No `render` method found on the %s " + - "instance: you may have forgotten to define `render`.", - name - ); - } - } + if (typeof contextType === 'object' && contextType !== null) { + nextContext = readContext(contextType); + } else { + var nextUnmaskedContext = getUnmaskedContext(workInProgress, ctor, true); + nextContext = getMaskedContext(workInProgress, nextUnmaskedContext); + } - 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 - ); - } + 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 ( - 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 - ); - } + if (!hasNewLifecycles && (typeof instance.UNSAFE_componentWillReceiveProps === 'function' || typeof instance.componentWillReceiveProps === 'function')) { + if (unresolvedOldProps !== unresolvedNewProps || oldContext !== nextContext) { + callComponentWillReceiveProps(workInProgress, instance, newProps, nextContext); + } + } - if (instance.propTypes) { - error( - "propTypes was defined as an instance property on %s. Use a static " + - "property to define propTypes instead.", - name - ); - } + resetHasForceUpdateBeforeProcessing(); + var oldState = workInProgress.memoizedState; + var newState = instance.state = oldState; + processUpdateQueue(workInProgress, newProps, instance, renderLanes); + suspendIfUpdateReadFromEntangledAsyncAction(); + newState = workInProgress.memoizedState; - if (instance.contextType) { - error( - "contextType was defined as an instance property on %s. Use a static " + - "property to define contextType instead.", - name - ); - } + 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 (instance.contextTypes) { - error( - "contextTypes was defined as an instance property on %s. Use a static " + - "property to define contextTypes instead.", - name - ); - } + if (typeof instance.getSnapshotBeforeUpdate === 'function') { + if (unresolvedOldProps !== current.memoizedProps || oldState !== current.memoizedState) { + workInProgress.flags |= Snapshot; + } + } - if ( - ctor.contextType && - ctor.contextTypes && - !didWarnAboutContextTypeAndContextTypes.has(ctor) - ) { - didWarnAboutContextTypeAndContextTypes.add(ctor); - - error( - "%s declares both contextTypes and contextType static properties. " + - "The legacy contextTypes property will be ignored.", - name - ); - } - } + return false; + } - 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 - ); - } + if (typeof getDerivedStateFromProps === 'function') { + applyDerivedStateFromProps(workInProgress, ctor, getDerivedStateFromProps, newProps); + newState = workInProgress.memoizedState; + } - 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 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 (typeof instance.componentDidUnmount === "function") { - error( - "%s has a method called " + - "componentDidUnmount(). But there is no such lifecycle method. " + - "Did you mean componentWillUnmount()?", - name - ); - } + 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.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 (typeof instance.UNSAFE_componentWillUpdate === 'function') { + instance.UNSAFE_componentWillUpdate(newProps, newState, nextContext); + } + } - if (typeof instance.componentWillRecieveProps === "function") { - error( - "%s has a method called " + - "componentWillRecieveProps(). Did you mean componentWillReceiveProps()?", - name - ); - } + if (typeof instance.componentDidUpdate === 'function') { + workInProgress.flags |= Update; + } - if (typeof instance.UNSAFE_componentWillRecieveProps === "function") { - error( - "%s has a method called " + - "UNSAFE_componentWillRecieveProps(). Did you mean UNSAFE_componentWillReceiveProps()?", - name - ); - } + 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; + } + } - var hasMutatedProps = instance.props !== newProps; + 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 (instance.props !== undefined && hasMutatedProps) { - error( - "When calling super() in `%s`, make sure to pass " + - "up the same props that your component's constructor was passed.", - name - ); - } - 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 - ); - } + workInProgress.memoizedProps = newProps; + workInProgress.memoizedState = newState; + } // Update the existing instance's state, props, and context pointers even + // if shouldComponentUpdate returns false. - if ( - typeof instance.getSnapshotBeforeUpdate === "function" && - typeof instance.componentDidUpdate !== "function" && - !didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.has(ctor) - ) { - didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.add(ctor); - - error( - "%s: getSnapshotBeforeUpdate() should be used with componentDidUpdate(). " + - "This component defines getSnapshotBeforeUpdate() only.", - getComponentNameFromType(ctor) - ); - } - 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 - ); - } + instance.props = newProps; + instance.state = newState; + instance.context = nextContext; + return shouldUpdate; +} - 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 - ); - } +function resolveClassComponentProps(Component, baseProps, // Only resolve default props if this is a lazy component. Otherwise, they +// would have already been resolved by the JSX runtime. +// TODO: We're going to remove default prop resolution from the JSX runtime +// and keep it only for class components. As part of that change, we should +// remove this extra check. +alreadyResolvedDefaultProps) { + var newProps = baseProps; - 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 state = instance.state; + var defaultProps = Component.defaultProps; - if (state && (typeof state !== "object" || isArray(state))) { - error("%s.state: must be set to an object or null", name); - } + if (defaultProps && ( // If disableDefaultPropsExceptForClasses is true, we always resolve + // default props here in the reconciler, rather than in the JSX runtime. + !alreadyResolvedDefaultProps)) { + // We may have already copied the props object above to remove ref. If so, + // we can modify that. Otherwise, copy the props object with Object.assign. + if (newProps === baseProps) { + newProps = assign({}, newProps); + } // Taken from old JSX runtime, where this used to live. - if ( - typeof instance.getChildContext === "function" && - typeof ctor.childContextTypes !== "object" - ) { - error( - "%s.getChildContext(): childContextTypes must be defined in order to " + - "use getChildContext().", - name - ); - } + + for (var _propName in defaultProps) { + if (newProps[_propName] === undefined) { + newProps[_propName] = defaultProps[_propName]; } } + } - function constructClassInstance(workInProgress, ctor, props) { - var isLegacyContextConsumer = false; - var unmaskedContext = emptyContextObject; - var context = emptyContextObject; - var contextType = ctor.contextType; + return newProps; +} - { - if ("contextType" in ctor) { - var isValid = // Allow null for conditional declaration - contextType === null || - (contextType !== undefined && - contextType.$$typeof === REACT_CONTEXT_TYPE); - - if (!isValid && !didWarnAboutInvalidateContextType.has(ctor)) { - didWarnAboutInvalidateContextType.add(ctor); - var addendum = ""; - - 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_CONSUMER_TYPE) { - addendum = - " Did you accidentally pass the Context.Consumer instead?"; - } else { - addendum = - " However, it is set to an object with keys {" + - Object.keys(contextType).join(", ") + - "}."; - } +function resolveDefaultPropsOnNonClassComponent(Component, baseProps) { - error( - "%s defines an invalid contextType. " + - "contextType should point to the Context object returned by React.createContext().%s", - getComponentNameFromType(ctor) || "Component", - addendum - ); - } - } - } + if (Component && Component.defaultProps) { + // Resolve default props. Taken from ReactElement + var props = assign({}, baseProps); + var defaultProps = Component.defaultProps; - 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; + for (var propName in defaultProps) { + if (props[propName] === undefined) { + props[propName] = defaultProps[propName]; } + } + + return props; + } - var instance = new ctor(props, context); // Instantiate twice to help detect side-effects. + return baseProps; +} - var state = (workInProgress.memoizedState = - instance.state !== null && instance.state !== undefined - ? instance.state - : null); - instance.updater = classComponentUpdater; - workInProgress.stateNode = instance; // The instance needs access to the fiber so that it can schedule updates +var reportGlobalError = typeof reportError === 'function' ? // In modern browsers, reportError will dispatch an error event, +// emulating an uncaught JavaScript error. +reportError : function (error) { + if (typeof window === 'object' && typeof window.ErrorEvent === 'function') { + // Browser Polyfill + var message = typeof error === 'object' && error !== null && typeof error.message === 'string' ? // eslint-disable-next-line react-internal/safe-string-coercion + String(error.message) : // eslint-disable-next-line react-internal/safe-string-coercion + String(error); + var event = new window.ErrorEvent('error', { + bubbles: true, + cancelable: true, + message: message, + error: error + }); + var shouldLog = window.dispatchEvent(event); + + if (!shouldLog) { + return; + } + } else if (typeof process === 'object' && // $FlowFixMe[method-unbinding] + typeof process.emit === 'function') { + // Node Polyfill + process.emit('uncaughtException', error); + return; + } // eslint-disable-next-line react-internal/no-production-logging + + + console['error'](error); +}; + +var componentName = null; +var errorBoundaryName = null; +function defaultOnUncaughtError(error, errorInfo) { + // Overriding this can silence these warnings e.g. for tests. + // See https://github.com/facebook/react/pull/13384 + // For uncaught root errors we report them as uncaught to the browser's + // onerror callback. This won't have component stacks and the error addendum. + // So we add those into a separate console.warn. + reportGlobalError(error); + + { + var componentStack = errorInfo.componentStack != null ? errorInfo.componentStack : ''; + var componentNameMessage = componentName ? "An error occurred in the <" + componentName + "> component:" : 'An error occurred in one of your React components:'; + console['warn']('%s\n%s\n\n%s', componentNameMessage, componentStack || '', 'Consider adding an error boundary to your tree to customize error handling behavior.\n' + 'Visit https://react.dev/link/error-boundaries to learn more about error boundaries.'); + } +} +function defaultOnCaughtError(error, errorInfo) { + // Overriding this can silence these warnings e.g. for tests. + // See https://github.com/facebook/react/pull/13384 + // Caught by error boundary + { + var componentStack = errorInfo.componentStack != null ? errorInfo.componentStack : ''; + var componentNameMessage = componentName ? "The above error occurred in the <" + componentName + "> component:" : 'The above error occurred in one of your React components:'; // In development, we provide our own message which includes the component stack + // in addition to the error. + // Don't transform to our wrapper + + console['error']('%o\n\n%s\n%s\n\n%s', error, componentNameMessage, componentStack, "React will try to recreate this component tree from scratch " + ("using the error boundary you provided, " + (errorBoundaryName || 'Anonymous') + ".")); + } +} +function defaultOnRecoverableError(error, errorInfo) { + reportGlobalError(error); +} +function logUncaughtError(root, errorInfo) { + try { + if (true) { + componentName = errorInfo.source ? getComponentNameFromFiber(errorInfo.source) : null; + errorBoundaryName = null; + } - set(instance, workInProgress); + var error = errorInfo.value; - { - instance._reactInternalInstance = fakeInternalInstance; - } + if (true && ReactSharedInternals.actQueue !== null) { + // For uncaught errors inside act, we track them on the act and then + // rethrow them into the test. + ReactSharedInternals.thrownErrors.push(error); + return; + } - { - 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; - - if ( - typeof instance.componentWillMount === "function" && - instance.componentWillMount.__suppressDeprecationWarning !== true - ) { - foundWillMountName = "componentWillMount"; - } else if (typeof instance.UNSAFE_componentWillMount === "function") { - foundWillMountName = "UNSAFE_componentWillMount"; - } + var onUncaughtError = root.onUncaughtError; + onUncaughtError(error, { + componentStack: errorInfo.stack + }); + } 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 logCaughtError(root, boundary, errorInfo) { + try { + if (true) { + componentName = errorInfo.source ? getComponentNameFromFiber(errorInfo.source) : null; + errorBoundaryName = getComponentNameFromFiber(boundary); + } + + var error = errorInfo.value; + var onCaughtError = root.onCaughtError; + onCaughtError(error, { + componentStack: errorInfo.stack, + errorBoundary: boundary.tag === ClassComponent ? boundary.stateNode // This should always be the case as long as we only have class boundaries + : null + }); + } 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; + }); + } +} - if ( - typeof instance.componentWillReceiveProps === "function" && - instance.componentWillReceiveProps.__suppressDeprecationWarning !== - true - ) { - foundWillReceivePropsName = "componentWillReceiveProps"; - } else if ( - typeof instance.UNSAFE_componentWillReceiveProps === "function" - ) { - foundWillReceivePropsName = "UNSAFE_componentWillReceiveProps"; - } +function createRootErrorUpdate(root, errorInfo, lane) { + var update = createUpdate(lane); // Unmount the root by rendering null. - if ( - typeof instance.componentWillUpdate === "function" && - instance.componentWillUpdate.__suppressDeprecationWarning !== true - ) { - foundWillUpdateName = "componentWillUpdate"; - } else if ( - typeof instance.UNSAFE_componentWillUpdate === "function" - ) { - foundWillUpdateName = "UNSAFE_componentWillUpdate"; - } + update.tag = CaptureUpdate; // Caution: React DevTools currently depends on this property + // being called "element". - if ( - foundWillMountName !== null || - foundWillReceivePropsName !== null || - foundWillUpdateName !== null - ) { - var _componentName = getComponentNameFromType(ctor) || "Component"; - - var newApiName = - typeof ctor.getDerivedStateFromProps === "function" - ? "getDerivedStateFromProps()" - : "getSnapshotBeforeUpdate()"; - - if ( - !didWarnAboutLegacyLifecyclesAndDerivedState.has(_componentName) - ) { - didWarnAboutLegacyLifecyclesAndDerivedState.add(_componentName); - - 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://react.dev/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. + update.payload = { + element: null + }; + + update.callback = function () { + logUncaughtError(root, errorInfo); + }; + + return update; +} + +function createClassErrorUpdate(lane) { + var update = createUpdate(lane); + update.tag = CaptureUpdate; + return update; +} + +function initializeClassErrorUpdate(update, root, fiber, errorInfo) { + var getDerivedStateFromError = fiber.type.getDerivedStateFromError; + + if (typeof getDerivedStateFromError === 'function') { + var error$1 = errorInfo.value; + + update.payload = function () { + return getDerivedStateFromError(error$1); + }; - if (isLegacyContextConsumer) { - cacheContext(workInProgress, unmaskedContext, context); + update.callback = function () { + { + markFailedErrorBoundaryForHotReloading(fiber); } - return instance; - } + logCaughtError(root, fiber, errorInfo); + }; + } - function callComponentWillMount(workInProgress, instance) { - var oldState = instance.state; + var inst = fiber.stateNode; - if (typeof instance.componentWillMount === "function") { - instance.componentWillMount(); + if (inst !== null && typeof inst.componentDidCatch === 'function') { + // $FlowFixMe[missing-this-annot] + update.callback = function callback() { + { + markFailedErrorBoundaryForHotReloading(fiber); } - if (typeof instance.UNSAFE_componentWillMount === "function") { - instance.UNSAFE_componentWillMount(); + logCaughtError(root, fiber, errorInfo); + + 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 (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 error$1 = errorInfo.value; + var stack = errorInfo.stack; + this.componentDidCatch(error$1, { + componentStack: stack !== null ? stack : '' + }); - classComponentUpdater.enqueueReplaceState( - instance, - instance.state, - null - ); + { + 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 callComponentWillReceiveProps( - workInProgress, - instance, - newProps, - nextContext - ) { - var oldState = instance.state; +function resetSuspendedComponent(sourceFiber, rootRenderLanes) { + // A legacy mode Suspense quirk, only relevant to hook components. - if (typeof instance.componentWillReceiveProps === "function") { - instance.componentWillReceiveProps(newProps, nextContext); - } - if (typeof instance.UNSAFE_componentWillReceiveProps === "function") { - instance.UNSAFE_componentWillReceiveProps(newProps, nextContext); - } + var tag = sourceFiber.tag; - if (instance.state !== oldState) { - { - var componentName = - getComponentNameFromFiber(workInProgress) || "Component"; + if ((sourceFiber.mode & ConcurrentMode) === NoMode && (tag === FunctionComponent || tag === ForwardRef || tag === SimpleMemoComponent)) { + var currentSource = sourceFiber.alternate; - if (!didWarnAboutStateAssignmentForComponent.has(componentName)) { - didWarnAboutStateAssignmentForComponent.add(componentName); + if (currentSource) { + sourceFiber.updateQueue = currentSource.updateQueue; + sourceFiber.memoizedState = currentSource.memoizedState; + sourceFiber.lanes = currentSource.lanes; + } else { + sourceFiber.updateQueue = null; + sourceFiber.memoizedState = null; + } + } +} - error( - "%s.componentWillReceiveProps(): Assigning directly to " + - "this.state is deprecated (except inside a component's " + - "constructor). Use setState instead.", - componentName - ); - } - } +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; + + 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); + } + } else if (sourceFiber.tag === FunctionComponent) { + var _currentSourceFiber = sourceFiber.alternate; + + if (_currentSourceFiber === null) { + // This is a new mount. Change the tag so it's not mistaken for a + // completed function component. + sourceFiber.tag = IncompleteFunctionComponent; + } + } // The source fiber did not complete. Mark it with Sync priority to + // indicate that it still has pending work. + + + sourceFiber.lanes = mergeLanes(sourceFiber.lanes, SyncLane); + } + + 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. + + + suspenseBoundary.flags |= ShouldCapture; // TODO: I think we can remove this, since we now use `DidCapture` in + // the begin phase to prevent an early bailout. + + suspenseBoundary.lanes = rootRenderLanes; + return suspenseBoundary; +} - classComponentUpdater.enqueueReplaceState( - instance, - instance.state, - null - ); - } - } // Invokes the mount life-cycles on a previously never rendered instance. +function throwException(root, returnFiber, sourceFiber, value, rootRenderLanes) { + // The source fiber did not complete. + sourceFiber.flags |= Incomplete; - function mountClassInstance(workInProgress, ctor, newProps, renderLanes) { - { - checkClassInstance(workInProgress, ctor, newProps); - } + if (value !== null && typeof value === 'object') { - var instance = workInProgress.stateNode; - instance.props = newProps; - instance.state = workInProgress.memoizedState; - instance.refs = {}; - initializeUpdateQueue(workInProgress); - var contextType = ctor.contextType; + if (typeof value.then === 'function') { + // This is a wakeable. The component suspended. + var wakeable = value; + resetSuspendedComponent(sourceFiber); - if (typeof contextType === "object" && contextType !== null) { - instance.context = readContext(contextType); - } else { - var unmaskedContext = getUnmaskedContext(workInProgress, ctor, true); - instance.context = getMaskedContext(workInProgress, unmaskedContext); - } - { - if (instance.state === newProps) { - var componentName = getComponentNameFromType(ctor) || "Component"; + var suspenseBoundary = getSuspenseHandler(); - if (!didWarnAboutDirectlyAssigningPropsToState.has(componentName)) { - didWarnAboutDirectlyAssigningPropsToState.add(componentName); + 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 (current === null) { + renderDidSuspend(); + } + } + } - 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 - ); - } - } + 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. + + var isSuspenseyResource = wakeable === noopSuspenseyCommitThenable; + + if (isSuspenseyResource) { + suspenseBoundary.flags |= ScheduleRetry; + } else { + var retryQueue = suspenseBoundary.updateQueue; - if (workInProgress.mode & StrictLegacyMode) { - ReactStrictModeWarnings.recordLegacyContextWarning( - workInProgress, - instance - ); - } + if (retryQueue === null) { + suspenseBoundary.updateQueue = new Set([wakeable]); + } else { + retryQueue.add(wakeable); + } // We only attach ping listeners in concurrent mode. Legacy + // Suspense always commits fallbacks synchronously, so there are + // no pings. - 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); - suspendIfUpdateReadFromEntangledAsyncAction(); - instance.state = workInProgress.memoizedState; - } - - if (typeof instance.componentDidMount === "function") { - workInProgress.flags |= Update | LayoutStatic; - } - - if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { - workInProgress.flags |= MountLayoutDev; - } - } - - function resumeMountClassInstance( - workInProgress, - ctor, - newProps, - renderLanes - ) { - var instance = workInProgress.stateNode; - var unresolvedOldProps = workInProgress.memoizedProps; - var oldProps = resolveClassComponentProps( - ctor, - unresolvedOldProps, - workInProgress.type === workInProgress.elementType - ); - 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 - ); - } - - var getDerivedStateFromProps = ctor.getDerivedStateFromProps; - var hasNewLifecycles = - typeof getDerivedStateFromProps === "function" || - typeof instance.getSnapshotBeforeUpdate === "function"; // When comparing whether props changed, we should compare using the - // unresolved props object that is stored on the fiber, rather than the - // one that gets assigned to the instance, because that object may have been - // cloned to resolve default props and/or remove `ref`. - - var unresolvedNewProps = workInProgress.pendingProps; - var didReceiveNewProps = unresolvedNewProps !== unresolvedOldProps; // 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 (didReceiveNewProps || oldContext !== nextContext) { - callComponentWillReceiveProps( - workInProgress, - instance, - newProps, - nextContext - ); - } - } - resetHasForceUpdateBeforeProcessing(); - var oldState = workInProgress.memoizedState; - var newState = (instance.state = oldState); - processUpdateQueue(workInProgress, newProps, instance, renderLanes); - suspendIfUpdateReadFromEntangledAsyncAction(); - newState = workInProgress.memoizedState; - - if ( - !didReceiveNewProps && - 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") { - workInProgress.flags |= Update | LayoutStatic; - } + if (suspenseBoundary.mode & ConcurrentMode) { + attachPingListener(root, wakeable, rootRenderLanes); + } + } - if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { - workInProgress.flags |= MountLayoutDev; - } + return false; + } - return false; - } + case OffscreenComponent: + { + if (suspenseBoundary.mode & ConcurrentMode) { + suspenseBoundary.flags |= ShouldCapture; - if (typeof getDerivedStateFromProps === "function") { - applyDerivedStateFromProps( - workInProgress, - ctor, - getDerivedStateFromProps, - newProps - ); - newState = workInProgress.memoizedState; - } - - 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(); - } + var _isSuspenseyResource = wakeable === noopSuspenseyCommitThenable; - if (typeof instance.UNSAFE_componentWillMount === "function") { - instance.UNSAFE_componentWillMount(); - } - } + if (_isSuspenseyResource) { + suspenseBoundary.flags |= ScheduleRetry; + } else { + var offscreenQueue = suspenseBoundary.updateQueue; + + if (offscreenQueue === null) { + var newOffscreenQueue = { + transitions: null, + markerInstances: null, + retryQueue: new Set([wakeable]) + }; + suspenseBoundary.updateQueue = newOffscreenQueue; + } else { + var _retryQueue = offscreenQueue.retryQueue; - if (typeof instance.componentDidMount === "function") { - workInProgress.flags |= Update | LayoutStatic; - } + if (_retryQueue === null) { + offscreenQueue.retryQueue = new Set([wakeable]); + } else { + _retryQueue.add(wakeable); + } + } - if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { - workInProgress.flags |= MountLayoutDev; - } - } 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") { - workInProgress.flags |= Update | LayoutStatic; + attachPingListener(root, wakeable, rootRenderLanes); + } + + return false; + } + } } - if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { - workInProgress.flags |= MountLayoutDev; - } // 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 = resolveClassComponentProps( - ctor, - unresolvedOldProps, - workInProgress.type === workInProgress.elementType - ); - 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); + throw new Error("Unexpected Suspense handler tag (" + suspenseBoundary.tag + "). This " + 'is a bug in React.'); } 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 - ); + // 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 false; + } 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; } } + } + } // This is a regular error, not a Suspense wakeable. - resetHasForceUpdateBeforeProcessing(); - var oldState = workInProgress.memoizedState; - var newState = (instance.state = oldState); - processUpdateQueue(workInProgress, newProps, instance, renderLanes); - suspendIfUpdateReadFromEntangledAsyncAction(); - 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; - } - } + var wrapperError = new Error('There was an error during concurrent rendering but React was able to recover by ' + 'instead synchronously rendering the entire root.', { + cause: value + }); + queueConcurrentError(createCapturedValueAtFiber(wrapperError, sourceFiber)); + renderDidError(); // 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 (typeof instance.getSnapshotBeforeUpdate === "function") { - if ( - unresolvedOldProps !== current.memoizedProps || - oldState !== current.memoizedState - ) { - workInProgress.flags |= Snapshot; - } - } + if (returnFiber === null) { + // There's no return fiber, which means the root errored. This should never + // happen. Return `true` to trigger a fatal error (panic). + return true; + } - return false; - } + var errorInfo = createCapturedValueAtFiber(value, sourceFiber); + var workInProgress = returnFiber; - if (typeof getDerivedStateFromProps === "function") { - applyDerivedStateFromProps( - workInProgress, - ctor, - getDerivedStateFromProps, - newProps - ); - newState = workInProgress.memoizedState; - } - - 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); - } + do { + switch (workInProgress.tag) { + case HostRoot: + { + workInProgress.flags |= ShouldCapture; - if (typeof instance.UNSAFE_componentWillUpdate === "function") { - instance.UNSAFE_componentWillUpdate( - newProps, - newState, - nextContext - ); - } - } + var _lane = pickArbitraryLane(rootRenderLanes); - if (typeof instance.componentDidUpdate === "function") { - workInProgress.flags |= Update; - } + workInProgress.lanes = mergeLanes(workInProgress.lanes, _lane); - 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; - } - } + var _update = createRootErrorUpdate(workInProgress.stateNode, errorInfo, _lane); - 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. - - 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 resolveClassComponentProps( - Component, - baseProps, // Only resolve default props if this is a lazy component. Otherwise, they - // would have already been resolved by the JSX runtime. - // TODO: We're going to remove default prop resolution from the JSX runtime - // and keep it only for class components. As part of that change, we should - // remove this extra check. - alreadyResolvedDefaultProps - ) { - var newProps = baseProps; - - var defaultProps = Component.defaultProps; - - if ( - defaultProps && // If disableDefaultPropsExceptForClasses is true, we always resolve - // default props here in the reconciler, rather than in the JSX runtime. - !alreadyResolvedDefaultProps - ) { - // We may have already copied the props object above to remove ref. If so, - // we can modify that. Otherwise, copy the props object with Object.assign. - if (newProps === baseProps) { - newProps = assign({}, newProps); - } // Taken from old JSX runtime, where this used to live. - - for (var _propName in defaultProps) { - if (newProps[_propName] === undefined) { - newProps[_propName] = defaultProps[_propName]; - } + enqueueCapturedUpdate(workInProgress, _update); + return false; } - } - return newProps; - } + case ClassComponent: + // Capture and retry + var ctor = workInProgress.type; + var instance = workInProgress.stateNode; - function resolveDefaultPropsOnNonClassComponent(Component, baseProps) { - if (Component && Component.defaultProps) { - // Resolve default props. Taken from ReactElement - var props = assign({}, baseProps); - var defaultProps = Component.defaultProps; + if ((workInProgress.flags & DidCapture) === NoFlags$1 && (typeof ctor.getDerivedStateFromError === 'function' || instance !== null && typeof instance.componentDidCatch === 'function' && !isAlreadyFailedLegacyErrorBoundary(instance))) { + workInProgress.flags |= ShouldCapture; - for (var propName in defaultProps) { - if (props[propName] === undefined) { - props[propName] = defaultProps[propName]; - } - } + var _lane2 = pickArbitraryLane(rootRenderLanes); - return props; - } - - return baseProps; - } - - var reportGlobalError = - typeof reportError === "function" // In modern browsers, reportError will dispatch an error event, - ? // emulating an uncaught JavaScript error. - reportError - : function (error) { - if ( - typeof window === "object" && - typeof window.ErrorEvent === "function" - ) { - // Browser Polyfill - var message = - typeof error === "object" && - error !== null && - typeof error.message === "string" // eslint-disable-next-line react-internal/safe-string-coercion - ? String(error.message) // eslint-disable-next-line react-internal/safe-string-coercion - : String(error); - var event = new window.ErrorEvent("error", { - bubbles: true, - cancelable: true, - message: message, - error: error - }); - var shouldLog = window.dispatchEvent(event); - - if (!shouldLog) { - return; - } - } else if ( - typeof process === "object" && // $FlowFixMe[method-unbinding] - typeof process.emit === "function" - ) { - // Node Polyfill - process.emit("uncaughtException", error); - return; - } // eslint-disable-next-line react-internal/no-production-logging - - console["error"](error); - }; + workInProgress.lanes = mergeLanes(workInProgress.lanes, _lane2); // Schedule the error boundary to re-render using updated state - var componentName = null; - var errorBoundaryName = null; - function defaultOnUncaughtError(error, errorInfo) { - // Overriding this can silence these warnings e.g. for tests. - // See https://github.com/facebook/react/pull/13384 - // For uncaught root errors we report them as uncaught to the browser's - // onerror callback. This won't have component stacks and the error addendum. - // So we add those into a separate console.warn. - reportGlobalError(error); + var _update2 = createClassErrorUpdate(_lane2); - { - var componentStack = - errorInfo.componentStack != null ? errorInfo.componentStack : ""; - var componentNameMessage = componentName - ? "An error occurred in the <" + componentName + "> component:" - : "An error occurred in one of your React components:"; - console["warn"]( - "%s\n%s\n\n%s", - componentNameMessage, - componentStack || "", - "Consider adding an error boundary to your tree to customize error handling behavior.\n" + - "Visit https://react.dev/link/error-boundaries to learn more about error boundaries." - ); - } - } - function defaultOnCaughtError(error, errorInfo) { - // Overriding this can silence these warnings e.g. for tests. - // See https://github.com/facebook/react/pull/13384 - // Caught by error boundary - { - var componentStack = - errorInfo.componentStack != null ? errorInfo.componentStack : ""; - var componentNameMessage = componentName - ? "The above error occurred in the <" + componentName + "> component:" - : "The above error occurred in one of your React components:"; // In development, we provide our own message which includes the component stack - // in addition to the error. - // Don't transform to our wrapper - - console["error"]( - "%o\n\n%s\n%s\n\n%s", - error, - componentNameMessage, - componentStack, - "React will try to recreate this component tree from scratch " + - ("using the error boundary you provided, " + - (errorBoundaryName || "Anonymous") + - ".") - ); - } - } - function defaultOnRecoverableError(error, errorInfo) { - reportGlobalError(error); - } - function logUncaughtError(root, errorInfo) { - try { - if (true) { - componentName = errorInfo.source - ? getComponentNameFromFiber(errorInfo.source) - : null; - errorBoundaryName = null; + initializeClassErrorUpdate(_update2, root, workInProgress, errorInfo); + enqueueCapturedUpdate(workInProgress, _update2); + return false; } - var error = errorInfo.value; + break; + } // $FlowFixMe[incompatible-type] we bail out when we get a null - if (true && ReactSharedInternals.actQueue !== null) { - // For uncaught errors inside act, we track them on the act and then - // rethrow them into the test. - ReactSharedInternals.thrownErrors.push(error); - return; - } - var onUncaughtError = root.onUncaughtError; - onUncaughtError(error, { - componentStack: errorInfo.stack - }); - } 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 logCaughtError(root, boundary, errorInfo) { - try { - if (true) { - componentName = errorInfo.source - ? getComponentNameFromFiber(errorInfo.source) - : null; - errorBoundaryName = getComponentNameFromFiber(boundary); - } + workInProgress = workInProgress.return; + } while (workInProgress !== null); - var error = errorInfo.value; - var onCaughtError = root.onCaughtError; - onCaughtError(error, { - componentStack: errorInfo.stack, - errorBoundary: - boundary.tag === ClassComponent - ? boundary.stateNode // This should always be the case as long as we only have class boundaries - : null - }); - } 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; - }); - } - } + return false; +} - function createRootErrorUpdate(root, errorInfo, lane) { - var update = createUpdate(lane); // Unmount the root by rendering null. +// into a dehydrated boundary. + +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 didWarnAboutContextTypeOnFunctionComponent; +var didWarnAboutGetDerivedStateOnFunctionComponent; +var didWarnAboutFunctionRefs; +var didWarnAboutReassigningProps; +var didWarnAboutRevealOrder; +var didWarnAboutTailOptions; +var didWarnAboutDefaultPropsOnFunctionComponent; + +{ + didWarnAboutBadClass = {}; + didWarnAboutContextTypeOnFunctionComponent = {}; + didWarnAboutGetDerivedStateOnFunctionComponent = {}; + didWarnAboutFunctionRefs = {}; + didWarnAboutReassigningProps = false; + didWarnAboutRevealOrder = {}; + didWarnAboutTailOptions = {}; + didWarnAboutDefaultPropsOnFunctionComponent = {}; +} - update.tag = CaptureUpdate; // Caution: React DevTools currently depends on this property - // being called "element". +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); + } +} - update.payload = { - element: null - }; +function forceUnmountCurrentAndReconcile(current, workInProgress, nextChildren, renderLanes) { + // 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); +} - update.callback = function () { - logUncaughtError(root, errorInfo); - }; +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. + var render = Component.render; + var ref = workInProgress.ref; + var propsWithoutRef; - return update; - } + { + propsWithoutRef = nextProps; + } // The rest is a fork of updateFunctionComponent - function createClassErrorUpdate(lane) { - var update = createUpdate(lane); - update.tag = CaptureUpdate; - return update; - } - function initializeClassErrorUpdate(update, root, fiber, errorInfo) { - var getDerivedStateFromError = fiber.type.getDerivedStateFromError; + var nextChildren; + prepareToReadContext(workInProgress, renderLanes); - if (typeof getDerivedStateFromError === "function") { - var error$1 = errorInfo.value; + { + markComponentRenderStarted(workInProgress); + } - update.payload = function () { - return getDerivedStateFromError(error$1); - }; + { + ReactSharedInternals.owner = workInProgress; + setIsRendering(true); + nextChildren = renderWithHooks(current, workInProgress, render, propsWithoutRef, ref, renderLanes); + setIsRendering(false); + } - update.callback = function () { - { - markFailedErrorBoundaryForHotReloading(fiber); - } + { + markComponentRenderStopped(); + } - logCaughtError(root, fiber, errorInfo); - }; - } + if (current !== null && !didReceiveUpdate) { + bailoutHooks(current, workInProgress, renderLanes); + return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); + } - var inst = fiber.stateNode; - if (inst !== null && typeof inst.componentDidCatch === "function") { - // $FlowFixMe[missing-this-annot] - update.callback = function callback() { - { - markFailedErrorBoundaryForHotReloading(fiber); - } + workInProgress.flags |= PerformedWork; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} - logCaughtError(root, fiber, errorInfo); +function updateMemoComponent(current, workInProgress, Component, nextProps, renderLanes) { + if (current === null) { + var type = Component.type; - 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 (isSimpleFunctionComponent(type) && Component.compare === null && ( // SimpleMemoComponent codepath doesn't resolve outer props either. + Component.defaultProps === undefined)) { + var resolvedType = type; - var error$1 = errorInfo.value; - var stack = errorInfo.stack; - this.componentDidCatch(error$1, { - componentStack: stack !== null ? stack : "" - }); + { + 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. - { - 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" - ); - } - } - } - }; + + workInProgress.tag = SimpleMemoComponent; + workInProgress.type = resolvedType; + + { + validateFunctionComponentInDev(workInProgress, type); } - } - function resetSuspendedComponent(sourceFiber, rootRenderLanes) { - // A legacy mode Suspense quirk, only relevant to hook components. + return updateSimpleMemoComponent(current, workInProgress, resolvedType, nextProps, renderLanes); + } - var tag = sourceFiber.tag; + { + { + if (Component.defaultProps !== undefined) { + var componentName = getComponentNameFromType(type) || 'Unknown'; - if ( - (sourceFiber.mode & ConcurrentMode) === NoMode && - (tag === FunctionComponent || - tag === ForwardRef || - tag === SimpleMemoComponent) - ) { - var currentSource = sourceFiber.alternate; + 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 (currentSource) { - sourceFiber.updateQueue = currentSource.updateQueue; - sourceFiber.memoizedState = currentSource.memoizedState; - sourceFiber.lanes = currentSource.lanes; - } else { - sourceFiber.updateQueue = null; - sourceFiber.memoizedState = null; + didWarnAboutDefaultPropsOnFunctionComponent[componentName] = true; + } } } } - 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. + var child = createFiberFromTypeAndProps(Component.type, null, nextProps, workInProgress, workInProgress.mode, renderLanes); + child.ref = workInProgress.ref; + child.return = workInProgress; + workInProgress.child = child; + return child; + } - sourceFiber.flags &= ~(LifecycleEffectMask | Incomplete); + var currentChild = current.child; // This is always exactly one child - if (sourceFiber.tag === ClassComponent) { - var currentSourceFiber = sourceFiber.alternate; + var hasScheduledUpdateOrContext = checkScheduledUpdateOrContext(current, renderLanes); - 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); - } - } else if (sourceFiber.tag === FunctionComponent) { - var _currentSourceFiber = sourceFiber.alternate; + 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 - if (_currentSourceFiber === null) { - // This is a new mount. Change the tag so it's not mistaken for a - // completed function component. - sourceFiber.tag = IncompleteFunctionComponent; - } - } // The source fiber did not complete. Mark it with Sync priority to - // indicate that it still has pending work. + var compare = Component.compare; + compare = compare !== null ? compare : shallowEqual; - sourceFiber.lanes = mergeLanes(sourceFiber.lanes, SyncLane); - } + if (compare(prevProps, nextProps) && current.ref === workInProgress.ref) { + return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); + } + } // React DevTools reads this flag. - 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. + + workInProgress.flags |= PerformedWork; + var newChild = createWorkInProgress(currentChild, nextProps); + newChild.ref = workInProgress.ref; + newChild.return = workInProgress; + workInProgress.child = newChild; + return newChild; +} + +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 (current !== null) { + var prevProps = current.memoizedProps; + + 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. // - // If there's ambiguity due to batching it's resolved in preference of: - // 1) "delayed", 2) "initial render", 3) "retry". + // 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. // - // 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. - - suspenseBoundary.flags |= ShouldCapture; // TODO: I think we can remove this, since we now use `DidCapture` in - // the begin phase to prevent an early bailout. - - suspenseBoundary.lanes = rootRenderLanes; - return suspenseBoundary; - } - - function throwException( - root, - returnFiber, - sourceFiber, - value, - rootRenderLanes - ) { - // The source fiber did not complete. - sourceFiber.flags |= Incomplete; - - if (value !== null && typeof value === "object") { - if (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; - - if (current === null) { - renderDidSuspend(); - } - } - } + // 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; + + 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; + } + } + } - 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. - - var isSuspenseyResource = - wakeable === noopSuspenseyCommitThenable; - - if (isSuspenseyResource) { - suspenseBoundary.flags |= ScheduleRetry; - } else { - var retryQueue = suspenseBoundary.updateQueue; + return updateFunctionComponent(current, workInProgress, Component, nextProps, renderLanes); +} - if (retryQueue === null) { - suspenseBoundary.updateQueue = new Set([wakeable]); - } else { - retryQueue.add(wakeable); - } // We only attach ping listeners in concurrent mode. Legacy - // Suspense always commits fallbacks synchronously, so there are - // no pings. +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(current, workInProgress); - if (suspenseBoundary.mode & ConcurrentMode) { - attachPingListener(root, wakeable, rootRenderLanes); - } - } + if (nextProps.mode === 'hidden' || enableLegacyHidden || nextIsDetached) { + // Rendering a hidden tree. + var didSuspend = (workInProgress.flags & DidCapture) !== NoFlags$1; - return false; - } + 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; - case OffscreenComponent: { - if (suspenseBoundary.mode & ConcurrentMode) { - suspenseBoundary.flags |= ShouldCapture; + 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. - var _isSuspenseyResource = - wakeable === noopSuspenseyCommitThenable; + var currentChildLanes = NoLanes; - if (_isSuspenseyResource) { - suspenseBoundary.flags |= ScheduleRetry; - } else { - var offscreenQueue = suspenseBoundary.updateQueue; - - if (offscreenQueue === null) { - var newOffscreenQueue = { - transitions: null, - markerInstances: null, - retryQueue: new Set([wakeable]) - }; - suspenseBoundary.updateQueue = newOffscreenQueue; - } else { - var _retryQueue = offscreenQueue.retryQueue; + while (currentChild !== null) { + currentChildLanes = mergeLanes(mergeLanes(currentChildLanes, currentChild.lanes), currentChild.childLanes); + currentChild = currentChild.sibling; + } - if (_retryQueue === null) { - offscreenQueue.retryQueue = new Set([wakeable]); - } else { - _retryQueue.add(wakeable); - } - } + var lanesWeJustAttempted = nextBaseLanes; + var remainingChildLanes = removeLanes(currentChildLanes, lanesWeJustAttempted); + workInProgress.childLanes = remainingChildLanes; + } else { + workInProgress.childLanes = NoLanes; + workInProgress.child = null; + } - attachPingListener(root, wakeable, rootRenderLanes); - } + return deferHiddenOffscreenComponent(current, workInProgress, nextBaseLanes); + } - return false; - } - } - } + 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; - throw new Error( - "Unexpected Suspense handler tag (" + - suspenseBoundary.tag + - "). This " + - "is a bug in React." - ); - } 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 false; - } 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; - } - } + { + // push the cache pool even though we're going to bail out + // because otherwise there'd be a context mismatch + if (current !== null) { + pushTransition(workInProgress, null); } - } // This is a regular error, not a Suspense wakeable. + } - var wrapperError = new Error( - "There was an error during concurrent rendering but React was able to recover by " + - "instead synchronously rendering the entire root.", - { - cause: value - } - ); - queueConcurrentError( - createCapturedValueAtFiber(wrapperError, sourceFiber) - ); - renderDidError(); // 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 (returnFiber === null) { - // There's no return fiber, which means the root errored. This should never - // happen. Return `true` to trigger a fatal error (panic). - return true; + 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 _nextBaseLanes = prevState !== null ? mergeLanes(prevState.baseLanes, renderLanes) : renderLanes; + + 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 (current !== null) { + // If the render that spawned this one accessed the cache pool, resume + // using the same cache. Unless the parent changed, since that means + // there was a refresh. + var prevCachePool = prevState !== null ? prevState.cachePool : null; // TODO: Consider if and how Offscreen pre-rendering should + // be attributed to the transition that spawned it + + pushTransition(workInProgress, prevCachePool); + } // Push the lanes that were skipped when we bailed out. + + + if (prevState !== null) { + pushHiddenContext(workInProgress, prevState); + } else { + reuseHiddenContextOnStack(workInProgress); + } + + pushOffscreenSuspenseHandler(workInProgress); + } + } else { + // Rendering a visible tree. + if (prevState !== null) { + // We're going from hidden -> visible. + var _prevCachePool = null; + + { + // If the render that spawned this one accessed the cache pool, resume + // using the same cache. Unless the parent changed, since that means + // there was a refresh. + _prevCachePool = prevState.cachePool; } - var errorInfo = createCapturedValueAtFiber(value, sourceFiber); - var workInProgress = returnFiber; + pushTransition(workInProgress, _prevCachePool); // Push the lanes that were skipped when we bailed out. - do { - switch (workInProgress.tag) { - case HostRoot: { - workInProgress.flags |= ShouldCapture; + pushHiddenContext(workInProgress, prevState); + reuseSuspenseHandlerOnStack(workInProgress); // Since we're not hidden anymore, reset the state + + workInProgress.memoizedState = null; + } else { + // We weren't previously hidden, and we still aren't, so there's nothing + // special to do. Need to push to the stack regardless, though, to avoid + // a push/pop misalignment. + { + // If the render that spawned this one accessed the cache pool, resume + // using the same cache. Unless the parent changed, since that means + // there was a refresh. + if (current !== null) { + pushTransition(workInProgress, null); + } + } // We're about to bail out, but we need to push this to the stack anyway + // to avoid a push/pop misalignment. - var _lane = pickArbitraryLane(rootRenderLanes); - workInProgress.lanes = mergeLanes(workInProgress.lanes, _lane); + reuseHiddenContextOnStack(workInProgress); + reuseSuspenseHandlerOnStack(workInProgress); + } + } - var _update = createRootErrorUpdate( - workInProgress.stateNode, - errorInfo, - _lane - ); + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} - enqueueCapturedUpdate(workInProgress, _update); - return false; - } +function deferHiddenOffscreenComponent(current, workInProgress, nextBaseLanes, renderLanes) { + var nextState = { + baseLanes: nextBaseLanes, + // Save the cache pool so we can resume later. + cachePool: getOffscreenDeferredCache() + }; + workInProgress.memoizedState = nextState; - case ClassComponent: - // Capture and retry - var ctor = workInProgress.type; - var instance = workInProgress.stateNode; - - if ( - (workInProgress.flags & DidCapture) === NoFlags$1 && - (typeof ctor.getDerivedStateFromError === "function" || - (instance !== null && - typeof instance.componentDidCatch === "function" && - !isAlreadyFailedLegacyErrorBoundary(instance))) - ) { - workInProgress.flags |= ShouldCapture; - - var _lane2 = pickArbitraryLane(rootRenderLanes); - - workInProgress.lanes = mergeLanes(workInProgress.lanes, _lane2); // Schedule the error boundary to re-render using updated state - - var _update2 = createClassErrorUpdate(_lane2); - - initializeClassErrorUpdate( - _update2, - root, - workInProgress, - errorInfo - ); - enqueueCapturedUpdate(workInProgress, _update2); - return false; - } + { + // push the cache pool even though we're going to bail out + // because otherwise there'd be a context mismatch + if (current !== null) { + pushTransition(workInProgress, null); + } + } // We're about to bail out, but we need to push this to the stack anyway + // to avoid a push/pop misalignment. - break; - } // $FlowFixMe[incompatible-type] we bail out when we get a null - workInProgress = workInProgress.return; - } while (workInProgress !== null); + reuseHiddenContextOnStack(workInProgress); + pushOffscreenSuspenseHandler(workInProgress); - return false; - } + return null; +} // Note: These happen to have identical begin phases, for now. We shouldn't hold - // into a dehydrated boundary. +function updateCacheComponent(current, workInProgress, 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 didWarnAboutContextTypeOnFunctionComponent; - var didWarnAboutGetDerivedStateOnFunctionComponent; - var didWarnAboutFunctionRefs; - var didWarnAboutReassigningProps; - var didWarnAboutRevealOrder; - var didWarnAboutTailOptions; - var didWarnAboutDefaultPropsOnFunctionComponent; + prepareToReadContext(workInProgress, renderLanes); + var parentCache = readContext(CacheContext); - { - didWarnAboutBadClass = {}; - 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 forceUnmountCurrentAndReconcile( - current, - workInProgress, - nextChildren, - renderLanes - ) { - // 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 - ); - } - - 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. - var render = Component.render; - var ref = workInProgress.ref; - var propsWithoutRef; + if (current === null) { + // Initial mount. Request a fresh cache from the pool. + var freshCache = requestCacheFromPool(renderLanes); + var initialState = { + parent: parentCache, + cache: freshCache + }; + workInProgress.memoizedState = initialState; + initializeUpdateQueue(workInProgress); + pushCacheProvider(workInProgress, freshCache); + } else { + // Check for updates + if (includesSomeLane(current.lanes, renderLanes)) { + cloneUpdateQueue(current, workInProgress); + processUpdateQueue(workInProgress, null, null, renderLanes); + suspendIfUpdateReadFromEntangledAsyncAction(); + } - { - propsWithoutRef = nextProps; - } // The rest is a fork of updateFunctionComponent + var prevState = current.memoizedState; + var nextState = workInProgress.memoizedState; // Compare the new parent cache to the previous to see detect there was + // a refresh. - var nextChildren; - prepareToReadContext(workInProgress, renderLanes); + if (prevState.parent !== parentCache) { + // Refresh in parent. Update the parent. + var derivedState = { + parent: parentCache, + cache: parentCache + }; // Copied from getDerivedStateFromProps implementation. Once the update + // queue is empty, persist the derived state onto the base state. - { - markComponentRenderStarted(workInProgress); - } + workInProgress.memoizedState = derivedState; - { - ReactSharedInternals.owner = workInProgress; - setIsRendering(true); - nextChildren = renderWithHooks( - current, - workInProgress, - render, - propsWithoutRef, - ref, - renderLanes - ); - setIsRendering(false); + if (workInProgress.lanes === NoLanes) { + var updateQueue = workInProgress.updateQueue; + workInProgress.memoizedState = updateQueue.baseState = derivedState; } - { - markComponentRenderStopped(); - } + pushCacheProvider(workInProgress, parentCache); // No need to propagate a context change because the refreshed parent + // already did. + } else { + // The parent didn't refresh. Now check if this cache did. + var nextCache = nextState.cache; + pushCacheProvider(workInProgress, nextCache); - if (current !== null && !didReceiveUpdate) { - bailoutHooks(current, workInProgress, renderLanes); - return bailoutOnAlreadyFinishedWork( - current, - workInProgress, - renderLanes - ); + if (nextCache !== prevState.cache) { + // This cache refreshed. Propagate a context change. + propagateContextChange(workInProgress, CacheContext, renderLanes); } - - workInProgress.flags |= PerformedWork; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; } + } - function updateMemoComponent( - current, - workInProgress, - Component, - nextProps, - renderLanes - ) { - if (current === null) { - var type = Component.type; + var nextChildren = workInProgress.pendingProps.children; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} // This should only be called if the name changes - if ( - isSimpleFunctionComponent(type) && - Component.compare === null && // SimpleMemoComponent codepath doesn't resolve outer props either. - Component.defaultProps === undefined - ) { - var resolvedType = type; +function updateFragment(current, workInProgress, renderLanes) { + var nextChildren = workInProgress.pendingProps; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} - { - 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. +function updateMode(current, workInProgress, renderLanes) { + var nextChildren = workInProgress.pendingProps.children; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} - workInProgress.tag = SimpleMemoComponent; - workInProgress.type = resolvedType; +function updateProfiler(current, workInProgress, renderLanes) { + { + workInProgress.flags |= Update; - { - validateFunctionComponentInDev(workInProgress, type); - } + { + // 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 nextProps = workInProgress.pendingProps; + var nextChildren = nextProps.children; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} - return updateSimpleMemoComponent( - current, - workInProgress, - resolvedType, - nextProps, - renderLanes - ); - } +function markRef(current, workInProgress) { + // TODO: Check props.ref instead of fiber.ref when enableRefAsProp is on. + var ref = workInProgress.ref; - { - { - 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 (ref === null) { + if (current !== null && current.ref !== null) { + // Schedule a Ref effect + workInProgress.flags |= Ref | RefStatic; + } + } else { + if (typeof ref !== 'function' && typeof ref !== 'object') { + throw new Error('Expected ref to be a function, an object returned by React.createRef(), or undefined/null.'); + } - var child = createFiberFromTypeAndProps( - Component.type, - null, - nextProps, - workInProgress, - workInProgress.mode, - renderLanes - ); - child.ref = workInProgress.ref; - child.return = workInProgress; - workInProgress.child = child; - return child; - } - - 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 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 (current === null || current.ref !== ref) { if (current !== null) { - var prevProps = current.memoizedProps; - - 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. - - 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; - } + var oldRef = current.ref; + var newRef = ref; + + if (typeof oldRef === 'function' && typeof newRef === 'function' && typeof oldRef.__stringRef === 'string' && oldRef.__stringRef === newRef.__stringRef && oldRef.__stringRefType === newRef.__stringRefType && oldRef.__stringRefOwner === newRef.__stringRefOwner) { + // Although this is a different callback, it represents the same + // string ref. To avoid breaking old Meta code that relies on string + // refs only being attached once, reuse the old ref. This will + // prevent us from detaching and reattaching the ref on each update. + workInProgress.ref = oldRef; + return; } - } + } // Schedule a Ref effect + - return updateFunctionComponent( - current, - workInProgress, - Component, - nextProps, - renderLanes - ); + workInProgress.flags |= Ref | RefStatic; } + } +} - 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(current, workInProgress); +function mountIncompleteFunctionComponent(_current, workInProgress, Component, nextProps, renderLanes) { + resetSuspendedCurrentOnMountInLegacyMode(_current, workInProgress); + workInProgress.tag = FunctionComponent; + return updateFunctionComponent(null, workInProgress, Component, nextProps, renderLanes); +} - if (nextProps.mode === "hidden" || enableLegacyHidden || nextIsDetached) { - // Rendering a hidden tree. - var didSuspend = (workInProgress.flags & DidCapture) !== NoFlags$1; +function updateFunctionComponent(current, workInProgress, Component, nextProps, renderLanes) { + { + if (Component.prototype && typeof Component.prototype.render === 'function') { + var componentName = getComponentNameFromType(Component) || 'Unknown'; - 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; + 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); - 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. - - var currentChildLanes = NoLanes; - - while (currentChild !== null) { - currentChildLanes = mergeLanes( - mergeLanes(currentChildLanes, currentChild.lanes), - currentChild.childLanes - ); - currentChild = currentChild.sibling; - } + didWarnAboutBadClass[componentName] = true; + } + } - var lanesWeJustAttempted = nextBaseLanes; - var remainingChildLanes = removeLanes( - currentChildLanes, - lanesWeJustAttempted - ); - workInProgress.childLanes = remainingChildLanes; - } else { - workInProgress.childLanes = NoLanes; - workInProgress.child = null; - } + if (workInProgress.mode & StrictLegacyMode) { + ReactStrictModeWarnings.recordLegacyContextWarning(workInProgress, null); + } - return deferHiddenOffscreenComponent( - current, - workInProgress, - nextBaseLanes - ); - } + if (current === null) { + // Some validations were previously done in mountIndeterminateComponent however and are now run + // in updateFuntionComponent but only on mount + validateFunctionComponentInDev(workInProgress, workInProgress.type); + } + } - 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; + var context; - { - // push the cache pool even though we're going to bail out - // because otherwise there'd be a context mismatch - if (current !== null) { - pushTransition(workInProgress, null); - } - } + { + var unmaskedContext = getUnmaskedContext(workInProgress, Component, true); + context = getMaskedContext(workInProgress, unmaskedContext); + } - 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 _nextBaseLanes = - prevState !== null - ? mergeLanes(prevState.baseLanes, renderLanes) - : renderLanes; - - 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; + var nextChildren; + prepareToReadContext(workInProgress, renderLanes); - if (current !== null) { - // If the render that spawned this one accessed the cache pool, resume - // using the same cache. Unless the parent changed, since that means - // there was a refresh. - var prevCachePool = prevState !== null ? prevState.cachePool : null; // TODO: Consider if and how Offscreen pre-rendering should - // be attributed to the transition that spawned it + { + markComponentRenderStarted(workInProgress); + } - pushTransition(workInProgress, prevCachePool); - } // Push the lanes that were skipped when we bailed out. + { + ReactSharedInternals.owner = workInProgress; + setIsRendering(true); + nextChildren = renderWithHooks(current, workInProgress, Component, nextProps, context, renderLanes); + setIsRendering(false); + } - if (prevState !== null) { - pushHiddenContext(workInProgress, prevState); - } else { - reuseHiddenContextOnStack(workInProgress); - } + { + markComponentRenderStopped(); + } - pushOffscreenSuspenseHandler(workInProgress); - } - } else { - // Rendering a visible tree. - if (prevState !== null) { - // We're going from hidden -> visible. - var _prevCachePool = null; + if (current !== null && !didReceiveUpdate) { + bailoutHooks(current, workInProgress, renderLanes); + return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); + } - { - // If the render that spawned this one accessed the cache pool, resume - // using the same cache. Unless the parent changed, since that means - // there was a refresh. - _prevCachePool = prevState.cachePool; - } - pushTransition(workInProgress, _prevCachePool); // Push the lanes that were skipped when we bailed out. + workInProgress.flags |= PerformedWork; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} - pushHiddenContext(workInProgress, prevState); - reuseSuspenseHandlerOnStack(workInProgress); // Since we're not hidden anymore, reset the state +function replayFunctionComponent(current, workInProgress, nextProps, Component, secondArg, renderLanes) { + // 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. + prepareToReadContext(workInProgress, renderLanes); - workInProgress.memoizedState = null; - } else { - // We weren't previously hidden, and we still aren't, so there's nothing - // special to do. Need to push to the stack regardless, though, to avoid - // a push/pop misalignment. - { - // If the render that spawned this one accessed the cache pool, resume - // using the same cache. Unless the parent changed, since that means - // there was a refresh. - if (current !== null) { - pushTransition(workInProgress, null); - } - } // We're about to bail out, but we need to push this to the stack anyway - // to avoid a push/pop misalignment. + { + markComponentRenderStarted(workInProgress); + } - reuseHiddenContextOnStack(workInProgress); - reuseSuspenseHandlerOnStack(workInProgress); - } - } + var nextChildren = replaySuspendedComponentWithHooks(current, workInProgress, Component, nextProps, secondArg); - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; - } + { + markComponentRenderStopped(); + } - function deferHiddenOffscreenComponent( - current, - workInProgress, - nextBaseLanes, - renderLanes - ) { - var nextState = { - baseLanes: nextBaseLanes, - // Save the cache pool so we can resume later. - cachePool: getOffscreenDeferredCache() - }; - workInProgress.memoizedState = nextState; + if (current !== null && !didReceiveUpdate) { + bailoutHooks(current, workInProgress, renderLanes); + return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); + } - { - // push the cache pool even though we're going to bail out - // because otherwise there'd be a context mismatch - if (current !== null) { - pushTransition(workInProgress, null); - } - } // We're about to bail out, but we need to push this to the stack anyway - // to avoid a push/pop misalignment. - reuseHiddenContextOnStack(workInProgress); - pushOffscreenSuspenseHandler(workInProgress); + workInProgress.flags |= PerformedWork; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} - return null; - } // Note: These happen to have identical begin phases, for now. We shouldn't hold +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? - function updateCacheComponent(current, workInProgress, renderLanes) { - prepareToReadContext(workInProgress, renderLanes); - var parentCache = readContext(CacheContext); + var tempInstance = new ctor(workInProgress.memoizedProps, _instance.context); + var state = tempInstance.state; - if (current === null) { - // Initial mount. Request a fresh cache from the pool. - var freshCache = requestCacheFromPool(renderLanes); - var initialState = { - parent: parentCache, - cache: freshCache - }; - workInProgress.memoizedState = initialState; - initializeUpdateQueue(workInProgress); - pushCacheProvider(workInProgress, freshCache); - } else { - // Check for updates - if (includesSomeLane(current.lanes, renderLanes)) { - cloneUpdateQueue(current, workInProgress); - processUpdateQueue(workInProgress, null, null, renderLanes); - suspendIfUpdateReadFromEntangledAsyncAction(); + _instance.updater.enqueueSetState(_instance, state, null); + + break; } - var prevState = current.memoizedState; - var nextState = workInProgress.memoizedState; // Compare the new parent cache to the previous to see detect there was - // a refresh. - - if (prevState.parent !== parentCache) { - // Refresh in parent. Update the parent. - var derivedState = { - parent: parentCache, - cache: parentCache - }; // Copied from getDerivedStateFromProps implementation. Once the update - // queue is empty, persist the derived state onto the base state. - - workInProgress.memoizedState = derivedState; - - if (workInProgress.lanes === NoLanes) { - var updateQueue = workInProgress.updateQueue; - workInProgress.memoizedState = updateQueue.baseState = derivedState; - } + case true: + { + workInProgress.flags |= DidCapture; + workInProgress.flags |= ShouldCapture; // eslint-disable-next-line react-internal/prod-error-codes - pushCacheProvider(workInProgress, parentCache); // No need to propagate a context change because the refreshed parent - // already did. - } else { - // The parent didn't refresh. Now check if this cache did. - var nextCache = nextState.cache; - pushCacheProvider(workInProgress, nextCache); + 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 + + var root = getWorkInProgressRoot(); - if (nextCache !== prevState.cache) { - // This cache refreshed. Propagate a context change. - propagateContextChange(workInProgress, CacheContext, renderLanes); + if (root === null) { + throw new Error('Expected a work-in-progress root. This is a bug in React. Please file an issue.'); } + + var update = createClassErrorUpdate(lane); + initializeClassErrorUpdate(update, root, workInProgress, createCapturedValueAtFiber(error$1, workInProgress)); + enqueueCapturedUpdate(workInProgress, update); + break; } - } + } + } // 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 nextChildren = workInProgress.pendingProps.children; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; - } // This should only be called if the name changes - function updateFragment(current, workInProgress, renderLanes) { - var nextChildren = workInProgress.pendingProps; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; - } + var hasContext; - function updateMode(current, workInProgress, renderLanes) { - var nextChildren = workInProgress.pendingProps.children; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; - } + if (isContextProvider(Component)) { + hasContext = true; + pushContextProvider(workInProgress); + } else { + hasContext = false; + } - function updateProfiler(current, workInProgress, renderLanes) { - { - workInProgress.flags |= Update; + prepareToReadContext(workInProgress, renderLanes); + var instance = workInProgress.stateNode; + var shouldUpdate; - { - // 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 (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); + + { + 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 nextProps = workInProgress.pendingProps; - var nextChildren = nextProps.children; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; + didWarnAboutReassigningProps = true; } + } - function markRef(current, workInProgress) { - // TODO: Check props.ref instead of fiber.ref when enableRefAsProp is on. - var ref = workInProgress.ref; + return nextUnitOfWork; +} - if (ref === null) { - if (current !== null && current.ref !== null) { - // Schedule a Ref effect - workInProgress.flags |= Ref | RefStatic; - } - } else { - if (typeof ref !== "function" && typeof ref !== "object") { - throw new Error( - "Expected ref to be a function, an object returned by React.createRef(), or undefined/null." - ); - } +function finishClassComponent(current, workInProgress, Component, shouldUpdate, hasContext, renderLanes) { + // Refs should update even if shouldComponentUpdate returns false + markRef(current, workInProgress); + var didCaptureError = (workInProgress.flags & DidCapture) !== NoFlags$1; - if (current === null || current.ref !== ref) { - if (current !== null) { - var oldRef = current.ref; - var newRef = ref; - - if ( - typeof oldRef === "function" && - typeof newRef === "function" && - typeof oldRef.__stringRef === "string" && - oldRef.__stringRef === newRef.__stringRef && - oldRef.__stringRefType === newRef.__stringRefType && - oldRef.__stringRefOwner === newRef.__stringRefOwner - ) { - // Although this is a different callback, it represents the same - // string ref. To avoid breaking old Meta code that relies on string - // refs only being attached once, reuse the old ref. This will - // prevent us from detaching and reattaching the ref on each update. - workInProgress.ref = oldRef; - return; - } - } // Schedule a Ref effect + if (!shouldUpdate && !didCaptureError) { + // Context providers should defer to sCU for rendering + if (hasContext) { + invalidateContextProvider(workInProgress, Component, false); + } - workInProgress.flags |= Ref | RefStatic; - } - } + return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); + } + + var instance = workInProgress.stateNode; // Rerender + + { + ReactSharedInternals.owner = workInProgress; + } + + var nextChildren; + + 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; + + { + stopProfilerTimerIfRunning(); + } + } else { + { + markComponentRenderStarted(workInProgress); } - function mountIncompleteFunctionComponent( - _current, - workInProgress, - Component, - nextProps, - renderLanes - ) { - resetSuspendedCurrentOnMountInLegacyMode(_current, workInProgress); - workInProgress.tag = FunctionComponent; - return updateFunctionComponent( - null, - workInProgress, - Component, - nextProps, - renderLanes - ); - } - - function updateFunctionComponent( - current, - workInProgress, - Component, - nextProps, - renderLanes - ) { - { - 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 - ); + { + setIsRendering(true); + nextChildren = instance.render(); - didWarnAboutBadClass[componentName] = true; - } - } + setIsRendering(false); + } - if (workInProgress.mode & StrictLegacyMode) { - ReactStrictModeWarnings.recordLegacyContextWarning( - workInProgress, - null - ); - } + { + markComponentRenderStopped(); + } + } // React DevTools reads this flag. - if (current === null) { - // Some validations were previously done in mountIndeterminateComponent however and are now run - // in updateFuntionComponent but only on mount - validateFunctionComponentInDev(workInProgress, workInProgress.type); - } - } - var context; + workInProgress.flags |= PerformedWork; - { - var unmaskedContext = getUnmaskedContext( - workInProgress, - Component, - true - ); - context = getMaskedContext(workInProgress, unmaskedContext); - } + 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. - var nextChildren; - prepareToReadContext(workInProgress, renderLanes); - { - markComponentRenderStarted(workInProgress); - } + workInProgress.memoizedState = instance.state; // The context might have changed so we need to recalculate it. - { - ReactSharedInternals.owner = workInProgress; - setIsRendering(true); - nextChildren = renderWithHooks( - current, - workInProgress, - Component, - nextProps, - context, - renderLanes - ); - setIsRendering(false); - } + if (hasContext) { + invalidateContextProvider(workInProgress, Component, true); + } - { - markComponentRenderStopped(); - } + return workInProgress.child; +} - if (current !== null && !didReceiveUpdate) { - bailoutHooks(current, workInProgress, renderLanes); - return bailoutOnAlreadyFinishedWork( - current, - workInProgress, - renderLanes - ); - } +function pushHostRootContext(workInProgress) { + var root = workInProgress.stateNode; - workInProgress.flags |= PerformedWork; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; - } + if (root.pendingContext) { + pushTopLevelContextObject(workInProgress, root.pendingContext, root.pendingContext !== root.context); + } else if (root.context) { + // Should always be set + pushTopLevelContextObject(workInProgress, root.context, false); + } - function replayFunctionComponent( - current, - workInProgress, - nextProps, - Component, - secondArg, - renderLanes - ) { - // 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. - prepareToReadContext(workInProgress, renderLanes); + pushHostContainer(workInProgress, root.containerInfo); +} - { - markComponentRenderStarted(workInProgress); - } +function updateHostRoot(current, workInProgress, renderLanes) { + pushHostRootContext(workInProgress); - var nextChildren = replaySuspendedComponentWithHooks( - current, - workInProgress, - Component, - nextProps, - secondArg - ); + if (current === null) { + throw new Error('Should have a current fiber. This is a bug in React.'); + } - { - markComponentRenderStopped(); - } + var nextProps = workInProgress.pendingProps; + var prevState = workInProgress.memoizedState; + var prevChildren = prevState.element; + cloneUpdateQueue(current, workInProgress); + processUpdateQueue(workInProgress, nextProps, null, renderLanes); + var nextState = workInProgress.memoizedState; - if (current !== null && !didReceiveUpdate) { - bailoutHooks(current, workInProgress, renderLanes); - return bailoutOnAlreadyFinishedWork( - current, - workInProgress, - renderLanes - ); - } + { + var nextCache = nextState.cache; + pushCacheProvider(workInProgress, nextCache); - workInProgress.flags |= PerformedWork; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; + if (nextCache !== prevState.cache) { + // The root cache refreshed. + propagateContextChange(workInProgress, CacheContext, renderLanes); } + } // This would ideally go inside processUpdateQueue, but because it suspends, + // it needs to happen after the `pushCacheProvider` call above to avoid a + // context stack mismatch. A bit unfortunate. - 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? - - var tempInstance = new ctor( - workInProgress.memoizedProps, - _instance.context - ); - var state = tempInstance.state; - _instance.updater.enqueueSetState(_instance, state, null); + suspendIfUpdateReadFromEntangledAsyncAction(); // Caution: React DevTools currently depends on this property + // being called "element". - break; - } + var nextChildren = nextState.element; - case true: { - workInProgress.flags |= DidCapture; - workInProgress.flags |= ShouldCapture; // eslint-disable-next-line react-internal/prod-error-codes + { - 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 (nextChildren === prevChildren) { + return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); + } - var root = getWorkInProgressRoot(); + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + } - if (root === null) { - throw new Error( - "Expected a work-in-progress root. This is a bug in React. Please file an issue." - ); - } + return workInProgress.child; +} - var update = createClassErrorUpdate(lane); - initializeClassErrorUpdate( - update, - root, - workInProgress, - createCapturedValueAtFiber(error$1, workInProgress) - ); - enqueueCapturedUpdate(workInProgress, update); - break; - } - } - } // 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 updateHostComponent$1(current, workInProgress, renderLanes) { - var hasContext; + pushHostContext(workInProgress); + var nextProps = workInProgress.pendingProps; + var prevProps = current !== null ? current.memoizedProps : null; + var nextChildren = nextProps.children; - if (isContextProvider(Component)) { - hasContext = true; - pushContextProvider(workInProgress); - } else { - hasContext = false; - } - - 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 (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; + } + + { + var memoizedState = workInProgress.memoizedState; + + if (memoizedState !== null) { + // This fiber has been upgraded to a stateful component. The only way + // happens currently is for form actions. We use hooks to track the + // pending and error state of the form. + // + // Once a fiber is upgraded to be stateful, it remains stateful for the + // rest of its lifetime. + var newState = renderTransitionAwareHostComponentWithHooks(current, workInProgress, renderLanes); // If the transition state changed, propagate the change to all the + // descendents. We use Context as an implementation detail for this. + // + // This is intentionally set here instead of pushHostContext because + // pushHostContext gets called before we process the state hook, to avoid + // a state mismatch in the event that something suspends. + // + // NOTE: This assumes that there cannot be nested transition providers, + // because the only renderer that implements this feature is React DOM, + // and forms cannot be nested. If we did support nested providers, then + // we would need to push a context value even for host fibers that + // haven't been upgraded yet. { - 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" - ); - } + HostTransitionContext._currentValue2 = newState; + } + + { + if (didReceiveUpdate) { + if (current !== null) { + var oldStateHook = current.memoizedState; + var oldState = oldStateHook.memoizedState; // This uses regular equality instead of Object.is because we assume + // that host transition state doesn't include NaN as a valid type. - didWarnAboutReassigningProps = true; + if (oldState !== newState) { + propagateContextChange(workInProgress, HostTransitionContext, renderLanes); + } + } } } - - return nextUnitOfWork; } + } - function finishClassComponent( - current, - workInProgress, - Component, - shouldUpdate, - hasContext, - renderLanes - ) { - // Refs should update even if shouldComponentUpdate returns false - markRef(current, workInProgress); - var didCaptureError = (workInProgress.flags & DidCapture) !== NoFlags$1; + markRef(current, workInProgress); + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} - if (!shouldUpdate && !didCaptureError) { - // Context providers should defer to sCU for rendering - if (hasContext) { - invalidateContextProvider(workInProgress, Component, false); - } +function updateHostText$1(current, workInProgress) { + // immediately after. - return bailoutOnAlreadyFinishedWork( - current, - workInProgress, - renderLanes - ); - } - var instance = workInProgress.stateNode; // Rerender + return null; +} + +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. + + workInProgress.type = Component; + + if (typeof Component === 'function') { + if (isFunctionClassComponent(Component)) { + var resolvedProps = resolveClassComponentProps(Component, props, false); + workInProgress.tag = ClassComponent; { - ReactSharedInternals.owner = workInProgress; + workInProgress.type = Component = resolveClassForHotReloading(Component); } - var nextChildren; + return updateClassComponent(null, workInProgress, Component, resolvedProps, renderLanes); + } else { + var _resolvedProps = resolveDefaultPropsOnNonClassComponent(Component, props); - 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; - - { - stopProfilerTimerIfRunning(); - } - } else { - { - markComponentRenderStarted(workInProgress); - } + workInProgress.tag = FunctionComponent; - { - setIsRendering(true); - nextChildren = instance.render(); + { + validateFunctionComponentInDev(workInProgress, Component); + workInProgress.type = Component = resolveFunctionForHotReloading(Component); + } - setIsRendering(false); - } + return updateFunctionComponent(null, workInProgress, Component, _resolvedProps, renderLanes); + } + } else if (Component !== undefined && Component !== null) { + var $$typeof = Component.$$typeof; - { - markComponentRenderStopped(); - } - } // React DevTools reads this flag. - - workInProgress.flags |= PerformedWork; - - 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. + if ($$typeof === REACT_FORWARD_REF_TYPE) { + var _resolvedProps2 = resolveDefaultPropsOnNonClassComponent(Component, props); - workInProgress.memoizedState = instance.state; // The context might have changed so we need to recalculate it. + workInProgress.tag = ForwardRef; - if (hasContext) { - invalidateContextProvider(workInProgress, Component, true); + { + workInProgress.type = Component = resolveForwardRefForHotReloading(Component); } - return workInProgress.child; - } + return updateForwardRef(null, workInProgress, Component, _resolvedProps2, renderLanes); + } else if ($$typeof === REACT_MEMO_TYPE) { + var _resolvedProps3 = resolveDefaultPropsOnNonClassComponent(Component, props); - function pushHostRootContext(workInProgress) { - var root = workInProgress.stateNode; + workInProgress.tag = MemoComponent; + return updateMemoComponent(null, workInProgress, Component, resolveDefaultPropsOnNonClassComponent(Component.type, _resolvedProps3), // The inner type can have defaults too + renderLanes); + } + } - if (root.pendingContext) { - pushTopLevelContextObject( - workInProgress, - root.pendingContext, - root.pendingContext !== root.context - ); - } else if (root.context) { - // Should always be set - pushTopLevelContextObject(workInProgress, root.context, false); - } + var hint = ''; - pushHostContainer(workInProgress, root.containerInfo); + { + 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. - function updateHostRoot(current, workInProgress, renderLanes) { - pushHostRootContext(workInProgress); - if (current === null) { - throw new Error("Should have a current fiber. This is a bug in React."); - } + 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 nextProps = workInProgress.pendingProps; - var prevState = workInProgress.memoizedState; - var prevChildren = prevState.element; - cloneUpdateQueue(current, workInProgress); - processUpdateQueue(workInProgress, nextProps, null, renderLanes); - var nextState = workInProgress.memoizedState; +function mountIncompleteClassComponent(_current, workInProgress, Component, nextProps, renderLanes) { + resetSuspendedCurrentOnMountInLegacyMode(_current, workInProgress); // Promote the fiber to a class and try rendering again. - { - var nextCache = nextState.cache; - pushCacheProvider(workInProgress, nextCache); + 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 (nextCache !== prevState.cache) { - // The root cache refreshed. - propagateContextChange(workInProgress, CacheContext, renderLanes); - } - } // This would ideally go inside processUpdateQueue, but because it suspends, - // it needs to happen after the `pushCacheProvider` call above to avoid a - // context stack mismatch. A bit unfortunate. + var hasContext; + + if (isContextProvider(Component)) { + hasContext = true; + pushContextProvider(workInProgress); + } else { + hasContext = false; + } + + prepareToReadContext(workInProgress, renderLanes); + constructClassInstance(workInProgress, Component, nextProps); + mountClassInstance(workInProgress, Component, nextProps, renderLanes); + return finishClassComponent(null, workInProgress, Component, true, hasContext, renderLanes); +} + +function validateFunctionComponentInDev(workInProgress, Component) { + { + if (Component) { + if (Component.childContextTypes) { + error('childContextTypes cannot be defined on a function component.\n' + ' %s.childContextTypes = ...', Component.displayName || Component.name || 'Component'); + } + } + + if (workInProgress.ref !== null) { + var info = ''; + var componentName = getComponentNameFromType(Component) || 'Unknown'; + var ownerName = getCurrentFiberOwnerNameInDevOrNull(); - suspendIfUpdateReadFromEntangledAsyncAction(); // Caution: React DevTools currently depends on this property - // being called "element". + if (ownerName) { + info += '\n\nCheck the render method of `' + ownerName + '`.'; + } - var nextChildren = nextState.element; + var warningKey = componentName + '|' + (ownerName || ''); - { - if (nextChildren === prevChildren) { - return bailoutOnAlreadyFinishedWork( - current, - workInProgress, - renderLanes - ); - } + if (!didWarnAboutFunctionRefs[warningKey]) { + didWarnAboutFunctionRefs[warningKey] = true; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); + error('Function components cannot be given refs. ' + 'Attempts to access this ref will fail. ' + 'Did you mean to use React.forwardRef()?%s', info); } - - return workInProgress.child; } - function updateHostComponent$1(current, workInProgress, renderLanes) { - pushHostContext(workInProgress); - var nextProps = workInProgress.pendingProps; - var prevProps = current !== null ? current.memoizedProps : null; - var nextChildren = nextProps.children; + if (Component.defaultProps !== undefined) { + var _componentName = getComponentNameFromType(Component) || 'Unknown'; - 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; - } + 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); - { - var memoizedState = workInProgress.memoizedState; + didWarnAboutDefaultPropsOnFunctionComponent[_componentName] = true; + } + } - if (memoizedState !== null) { - // This fiber has been upgraded to a stateful component. The only way - // happens currently is for form actions. We use hooks to track the - // pending and error state of the form. - // - // Once a fiber is upgraded to be stateful, it remains stateful for the - // rest of its lifetime. - var newState = renderTransitionAwareHostComponentWithHooks( - current, - workInProgress, - renderLanes - ); // If the transition state changed, propagate the change to all the - // descendents. We use Context as an implementation detail for this. - // - // This is intentionally set here instead of pushHostContext because - // pushHostContext gets called before we process the state hook, to avoid - // a state mismatch in the event that something suspends. - // - // NOTE: This assumes that there cannot be nested transition providers, - // because the only renderer that implements this feature is React DOM, - // and forms cannot be nested. If we did support nested providers, then - // we would need to push a context value even for host fibers that - // haven't been upgraded yet. + if (typeof Component.getDerivedStateFromProps === 'function') { + var _componentName2 = getComponentNameFromType(Component) || 'Unknown'; - { - HostTransitionContext._currentValue2 = newState; - } + if (!didWarnAboutGetDerivedStateOnFunctionComponent[_componentName2]) { + error('%s: Function components do not support getDerivedStateFromProps.', _componentName2); - { - if (didReceiveUpdate) { - if (current !== null) { - var oldStateHook = current.memoizedState; - var oldState = oldStateHook.memoizedState; // This uses regular equality instead of Object.is because we assume - // that host transition state doesn't include NaN as a valid type. - - if (oldState !== newState) { - propagateContextChange( - workInProgress, - HostTransitionContext, - renderLanes - ); - } - } - } - } - } + didWarnAboutGetDerivedStateOnFunctionComponent[_componentName2] = true; } - - markRef(current, workInProgress); - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; } - function updateHostText$1(current, workInProgress) { - // immediately after. + if (typeof Component.contextType === 'object' && Component.contextType !== null) { + var _componentName3 = getComponentNameFromType(Component) || 'Unknown'; - return null; + if (!didWarnAboutContextTypeOnFunctionComponent[_componentName3]) { + error('%s: Function components do not support contextType.', _componentName3); + + didWarnAboutContextTypeOnFunctionComponent[_componentName3] = 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. - - workInProgress.type = Component; - - if (typeof Component === "function") { - if (isFunctionClassComponent(Component)) { - var resolvedProps = resolveClassComponentProps( - Component, - props, - false - ); - workInProgress.tag = ClassComponent; +var SUSPENDED_MARKER = { + dehydrated: null, + treeContext: null, + retryLane: NoLane +}; + +function mountSuspenseOffscreenState(renderLanes) { + return { + baseLanes: renderLanes, + cachePool: getSuspendedCache() + }; +} - { - workInProgress.type = Component = - resolveClassForHotReloading(Component); - } +function updateSuspenseOffscreenState(prevOffscreenState, renderLanes) { + var cachePool = null; - return updateClassComponent( - null, - workInProgress, - Component, - resolvedProps, - renderLanes - ); - } else { - var _resolvedProps = resolveDefaultPropsOnNonClassComponent( - Component, - props - ); + { + var prevCachePool = prevOffscreenState.cachePool; - workInProgress.tag = FunctionComponent; + if (prevCachePool !== null) { + var parentCache = CacheContext._currentValue2; - { - validateFunctionComponentInDev(workInProgress, Component); - workInProgress.type = Component = - resolveFunctionForHotReloading(Component); - } + if (prevCachePool.parent !== parentCache) { + // Detected a refresh in the parent. This overrides any previously + // suspended cache. + cachePool = { + parent: parentCache, + pool: parentCache + }; + } else { + // We can reuse the cache from last time. The only thing that would have + // overridden it is a parent refresh, which we checked for above. + cachePool = prevCachePool; + } + } else { + // If there's no previous cache pool, grab the current one. + cachePool = getSuspendedCache(); + } + } + + return { + baseLanes: mergeLanes(prevOffscreenState.baseLanes, renderLanes), + cachePool: cachePool + }; +} // TODO: Probably should inline this back + + +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 (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. - return updateFunctionComponent( - null, - workInProgress, - Component, - _resolvedProps, - renderLanes - ); - } - } else if (Component !== undefined && Component !== null) { - var $$typeof = Component.$$typeof; - if ($$typeof === REACT_FORWARD_REF_TYPE) { - var _resolvedProps2 = resolveDefaultPropsOnNonClassComponent( - Component, - props - ); + var suspenseContext = suspenseStackCursor.current; + return hasSuspenseListContext(suspenseContext, ForceSuspenseFallback); +} - workInProgress.tag = ForwardRef; +function getRemainingWorkInPrimaryTree(current, primaryTreeDidDefer, renderLanes) { + var remainingLanes = current !== null ? removeLanes(current.childLanes, renderLanes) : NoLanes; - { - workInProgress.type = Component = - resolveForwardRefForHotReloading(Component); - } + if (primaryTreeDidDefer) { + // A useDeferredValue hook spawned a deferred task inside the primary tree. + // Ensure that we retry this component at the deferred priority. + // TODO: We could make this a per-subtree value instead of a global one. + // Would need to track it on the context stack somehow, similar to what + // we'd have to do for resumable contexts. + remainingLanes = mergeLanes(remainingLanes, peekDeferredLane()); + } - return updateForwardRef( - null, - workInProgress, - Component, - _resolvedProps2, - renderLanes - ); - } else if ($$typeof === REACT_MEMO_TYPE) { - var _resolvedProps3 = resolveDefaultPropsOnNonClassComponent( - Component, - props - ); - - workInProgress.tag = MemoComponent; - return updateMemoComponent( - null, - workInProgress, - Component, - resolveDefaultPropsOnNonClassComponent( - Component.type, - _resolvedProps3 - ), // The inner type can have defaults too - renderLanes - ); - } - } + return remainingLanes; +} - var hint = ""; +function updateSuspenseComponent(current, workInProgress, renderLanes) { + var nextProps = workInProgress.pendingProps; // This is used by DevTools to force a boundary to suspend. + + { + if (shouldSuspend(workInProgress)) { + workInProgress.flags |= DidCapture; + } + } + + var showFallback = false; + var didSuspend = (workInProgress.flags & DidCapture) !== NoFlags$1; + + if (didSuspend || shouldRemainOnFallback(current)) { + // Something in this boundary's subtree already suspended. Switch to + // rendering the fallback children. + showFallback = true; + workInProgress.flags &= ~DidCapture; + } // Check if the primary children spawned a deferred task (useDeferredValue) + // during the first pass. + + + var didPrimaryChildrenDefer = (workInProgress.flags & DidDefer) !== NoFlags$1; + workInProgress.flags &= ~DidDefer; // 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. + + if (current === null) { + + var nextPrimaryChildren = nextProps.children; + var nextFallbackChildren = nextProps.fallback; + + if (showFallback) { + pushFallbackTreeSuspenseHandler(workInProgress); + var fallbackFragment = mountSuspenseFallbackChildren(workInProgress, nextPrimaryChildren, nextFallbackChildren, renderLanes); + var primaryChildFragment = workInProgress.child; + primaryChildFragment.memoizedState = mountSuspenseOffscreenState(renderLanes); + primaryChildFragment.childLanes = getRemainingWorkInPrimaryTree(current, didPrimaryChildrenDefer, renderLanes); + workInProgress.memoizedState = SUSPENDED_MARKER; + + 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); + + var _fallbackFragment = mountSuspenseFallbackChildren(workInProgress, nextPrimaryChildren, nextFallbackChildren, renderLanes); + + var _primaryChildFragment = workInProgress.child; + _primaryChildFragment.memoizedState = mountSuspenseOffscreenState(renderLanes); + _primaryChildFragment.childLanes = getRemainingWorkInPrimaryTree(current, didPrimaryChildrenDefer, 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 = SomeRetryLane; + return _fallbackFragment; + } else { + pushPrimaryTreeSuspenseHandler(workInProgress); + return mountSuspensePrimaryChildren(workInProgress, nextPrimaryChildren); + } + } else { + // This is an update. + // Special path for hydration + var prevState = current.memoizedState; + + if (prevState !== null) { + var _dehydrated = prevState.dehydrated; + + if (_dehydrated !== null) { + return updateDehydratedSuspenseComponent(current, workInProgress, didSuspend, didPrimaryChildrenDefer, nextProps, _dehydrated, prevState, renderLanes); + } + } + + 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); + + _primaryChildFragment2.childLanes = getRemainingWorkInPrimaryTree(current, didPrimaryChildrenDefer, renderLanes); + workInProgress.memoizedState = SUSPENDED_MARKER; + return fallbackChildFragment; + } else { + pushPrimaryTreeSuspenseHandler(workInProgress); + var _nextPrimaryChildren2 = nextProps.children; - { - 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) - ); - } - - function mountIncompleteClassComponent( - _current, - workInProgress, - Component, - nextProps, - renderLanes - ) { - resetSuspendedCurrentOnMountInLegacyMode(_current, workInProgress); // Promote the fiber to a class and try rendering again. - - 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. - - var hasContext; - - if (isContextProvider(Component)) { - hasContext = true; - pushContextProvider(workInProgress); - } else { - hasContext = false; - } + var _primaryChildFragment3 = updateSuspensePrimaryChildren(current, workInProgress, _nextPrimaryChildren2, renderLanes); - prepareToReadContext(workInProgress, renderLanes); - constructClassInstance(workInProgress, Component, nextProps); - mountClassInstance(workInProgress, Component, nextProps, renderLanes); - return finishClassComponent( - null, - workInProgress, - Component, - true, - hasContext, - renderLanes - ); + workInProgress.memoizedState = null; + return _primaryChildFragment3; } + } +} - function validateFunctionComponentInDev(workInProgress, Component) { - { - if (Component) { - if (Component.childContextTypes) { - error( - "childContextTypes cannot be defined on a function component.\n" + - " %s.childContextTypes = ...", - Component.displayName || Component.name || "Component" - ); - } - } +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 (workInProgress.ref !== null) { - var info = ""; - var componentName = getComponentNameFromType(Component) || "Unknown"; - var ownerName = getCurrentFiberOwnerNameInDevOrNull(); +function mountSuspenseFallbackChildren(workInProgress, primaryChildren, fallbackChildren, 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; + + 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; + } + + 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; +} - if (ownerName) { - info += "\n\nCheck the render method of `" + ownerName + "`."; - } +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); +} - var warningKey = componentName + "|" + (ownerName || ""); +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); +} - if (!didWarnAboutFunctionRefs[warningKey]) { - didWarnAboutFunctionRefs[warningKey] = true; +function updateSuspensePrimaryChildren(current, workInProgress, primaryChildren, renderLanes) { + var currentPrimaryChildFragment = current.child; + var currentFallbackChildFragment = currentPrimaryChildFragment.sibling; + var primaryChildFragment = updateWorkInProgressOffscreenFiber(currentPrimaryChildFragment, { + mode: 'visible', + children: primaryChildren + }); - error( - "Function components cannot be given refs. " + - "Attempts to access this ref will fail. " + - "Did you mean to use React.forwardRef()?%s", - info - ); - } - } + if ((workInProgress.mode & ConcurrentMode) === NoMode) { + primaryChildFragment.lanes = renderLanes; + } - if (Component.defaultProps !== undefined) { - var _componentName = getComponentNameFromType(Component) || "Unknown"; + primaryChildFragment.return = workInProgress; + primaryChildFragment.sibling = null; - 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 (currentFallbackChildFragment !== null) { + // Delete the fallback child fragment + var deletions = workInProgress.deletions; - didWarnAboutDefaultPropsOnFunctionComponent[_componentName] = true; - } - } + if (deletions === null) { + workInProgress.deletions = [currentFallbackChildFragment]; + workInProgress.flags |= ChildDeletion; + } else { + deletions.push(currentFallbackChildFragment); + } + } - if (typeof Component.getDerivedStateFromProps === "function") { - var _componentName2 = - getComponentNameFromType(Component) || "Unknown"; + workInProgress.child = primaryChildFragment; + return primaryChildFragment; +} - if ( - !didWarnAboutGetDerivedStateOnFunctionComponent[_componentName2] - ) { - error( - "%s: Function components do not support getDerivedStateFromProps.", - _componentName2 - ); +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 ( // 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 (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 { + 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.) + + primaryChildFragment.subtreeFlags = currentPrimaryChildFragment.subtreeFlags & StaticMask; + } + + var fallbackChildFragment; + + 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. + + fallbackChildFragment.flags |= Placement; + } + + fallbackChildFragment.return = workInProgress; + primaryChildFragment.return = workInProgress; + primaryChildFragment.sibling = fallbackChildFragment; + workInProgress.child = primaryChildFragment; + return fallbackChildFragment; +} - didWarnAboutGetDerivedStateOnFunctionComponent[_componentName2] = - true; - } - } +function retrySuspenseComponentWithoutHydrating(current, workInProgress, renderLanes) { + // 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. + // 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; +} - if ( - typeof Component.contextType === "object" && - Component.contextType !== null - ) { - var _componentName3 = - getComponentNameFromType(Component) || "Unknown"; - - if (!didWarnAboutContextTypeOnFunctionComponent[_componentName3]) { - error( - "%s: Function components do not support contextType.", - _componentName3 - ); +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; + + 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); + } + + return fallbackChildFragment; +} - didWarnAboutContextTypeOnFunctionComponent[_componentName3] = true; - } - } - } - } +function updateDehydratedSuspenseComponent(current, workInProgress, didSuspend, didPrimaryChildrenDefer, 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 SUSPENDED_MARKER = { - dehydrated: null, - treeContext: null, - retryLane: NoLane - }; + 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; + var message; + var stack = null; + var componentStack = null; - function mountSuspenseOffscreenState(renderLanes) { - return { - baseLanes: renderLanes, - cachePool: getSuspendedCache() - }; - } + { + var _getSuspenseInstanceF = getSuspenseInstanceFallbackErrorDetails(); - function updateSuspenseOffscreenState(prevOffscreenState, renderLanes) { - var cachePool = null; + digest = _getSuspenseInstanceF.digest; + message = _getSuspenseInstanceF.message; + stack = _getSuspenseInstanceF.stack; + componentStack = _getSuspenseInstanceF.componentStack; + } // TODO: Figure out a better signal than encoding a magic digest value. - { - var prevCachePool = prevOffscreenState.cachePool; - if (prevCachePool !== null) { - var parentCache = CacheContext._currentValue2; + { + var error; - if (prevCachePool.parent !== parentCache) { - // Detected a refresh in the parent. This overrides any previously - // suspended cache. - cachePool = { - parent: parentCache, - pool: parentCache - }; - } else { - // We can reuse the cache from last time. The only thing that would have - // overridden it is a parent refresh, which we checked for above. - cachePool = prevCachePool; - } + if (message) { + // eslint-disable-next-line react-internal/prod-error-codes + error = new Error(message); } else { - // If there's no previous cache pool, grab the current one. - cachePool = getSuspendedCache(); - } - } + error = new Error('The server could not finish this Suspense boundary, likely ' + 'due to an error during server rendering. ' + 'Switched to client rendering.'); + } // Replace the stack with the server stack - return { - baseLanes: mergeLanes(prevOffscreenState.baseLanes, renderLanes), - cachePool: cachePool - }; - } // TODO: Probably should inline this back - - 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 (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. + error.stack = stack || ''; + error.digest = digest; + var capturedValue = createCapturedValueFromError(error, componentStack === undefined ? null : componentStack); + queueHydrationError(capturedValue); + } - var suspenseContext = suspenseStackCursor.current; - return hasSuspenseListContext(suspenseContext, ForceSuspenseFallback); + return retrySuspenseComponentWithoutHydrating(current, workInProgress, renderLanes); } + // any context has changed, we need to treat is as if the input might have changed. - function getRemainingWorkInPrimaryTree( - current, - primaryTreeDidDefer, - renderLanes - ) { - var remainingLanes = - current !== null - ? removeLanes(current.childLanes, renderLanes) - : NoLanes; - if (primaryTreeDidDefer) { - // A useDeferredValue hook spawned a deferred task inside the primary tree. - // Ensure that we retry this component at the deferred priority. - // TODO: We could make this a per-subtree value instead of a global one. - // Would need to track it on the context stack somehow, similar to what - // we'd have to do for resumable contexts. - remainingLanes = mergeLanes(remainingLanes, peekDeferredLane()); - } + var hasContextChanged = includesSomeLane(renderLanes, current.childLanes); - return remainingLanes; - } + 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(); - function updateSuspenseComponent(current, workInProgress, renderLanes) { - var nextProps = workInProgress.pendingProps; // This is used by DevTools to force a boundary to suspend. + if (root !== null) { + var attemptHydrationAtLane = getBumpedLaneForHydration(root, renderLanes); + + 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; + enqueueConcurrentRenderForLane(current, attemptHydrationAtLane); + scheduleUpdateOnFiber(root, current, attemptHydrationAtLane); // 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 (shouldSuspend(workInProgress)) { - workInProgress.flags |= DidCapture; + 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. + + + if (isSuspenseInstancePending()) ; else { + renderDidSuspendDelayIfPossible(); + } + + return retrySuspenseComponentWithoutHydrating(current, workInProgress, renderLanes); + } 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. + + workInProgress.child = current.child; // Register a callback to retry this boundary once the server has sent the result. + + 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. + + 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. + // The error should've already been logged in throwException. + pushPrimaryTreeSuspenseHandler(workInProgress); + workInProgress.flags &= ~ForceClientRender; + return retrySuspenseComponentWithoutHydrating(current, workInProgress, renderLanes); + } 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. + + 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); + _primaryChildFragment4.childLanes = getRemainingWorkInPrimaryTree(current, didPrimaryChildrenDefer, renderLanes); + workInProgress.memoizedState = SUSPENDED_MARKER; + return fallbackChildFragment; + } + } +} - var showFallback = false; - var didSuspend = (workInProgress.flags & DidCapture) !== NoFlags$1; +function scheduleSuspenseWorkOnFiber(fiber, renderLanes, propagationRoot) { + fiber.lanes = mergeLanes(fiber.lanes, renderLanes); + var alternate = fiber.alternate; - if (didSuspend || shouldRemainOnFallback(current)) { - // Something in this boundary's subtree already suspended. Switch to - // rendering the fallback children. - showFallback = true; - workInProgress.flags &= ~DidCapture; - } // Check if the primary children spawned a deferred task (useDeferredValue) - // during the first pass. + if (alternate !== null) { + alternate.lanes = mergeLanes(alternate.lanes, renderLanes); + } - var didPrimaryChildrenDefer = - (workInProgress.flags & DidDefer) !== NoFlags$1; - workInProgress.flags &= ~DidDefer; // 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. - - if (current === null) { - var nextPrimaryChildren = nextProps.children; - var nextFallbackChildren = nextProps.fallback; - - if (showFallback) { - pushFallbackTreeSuspenseHandler(workInProgress); - var fallbackFragment = mountSuspenseFallbackChildren( - workInProgress, - nextPrimaryChildren, - nextFallbackChildren, - renderLanes - ); - var primaryChildFragment = workInProgress.child; - primaryChildFragment.memoizedState = - mountSuspenseOffscreenState(renderLanes); - primaryChildFragment.childLanes = getRemainingWorkInPrimaryTree( - current, - didPrimaryChildrenDefer, - renderLanes - ); - workInProgress.memoizedState = SUSPENDED_MARKER; - - 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); - - var _fallbackFragment = mountSuspenseFallbackChildren( - workInProgress, - nextPrimaryChildren, - nextFallbackChildren, - renderLanes - ); - - var _primaryChildFragment = workInProgress.child; - _primaryChildFragment.memoizedState = - mountSuspenseOffscreenState(renderLanes); - _primaryChildFragment.childLanes = getRemainingWorkInPrimaryTree( - current, - didPrimaryChildrenDefer, - 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 = SomeRetryLane; - return _fallbackFragment; - } else { - pushPrimaryTreeSuspenseHandler(workInProgress); - return mountSuspensePrimaryChildren( - workInProgress, - nextPrimaryChildren - ); - } - } else { - // This is an update. - // Special path for hydration - var prevState = current.memoizedState; + scheduleContextWorkOnParentPath(fiber.return, renderLanes, propagationRoot); +} - if (prevState !== null) { - var _dehydrated = prevState.dehydrated; - - if (_dehydrated !== null) { - return updateDehydratedSuspenseComponent( - current, - workInProgress, - didSuspend, - didPrimaryChildrenDefer, - nextProps, - _dehydrated, - prevState, - renderLanes - ); - } - } +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; + + 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 (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); - - _primaryChildFragment2.childLanes = getRemainingWorkInPrimaryTree( - current, - didPrimaryChildrenDefer, - renderLanes - ); - workInProgress.memoizedState = SUSPENDED_MARKER; - return fallbackChildFragment; - } else { - pushPrimaryTreeSuspenseHandler(workInProgress); - var _nextPrimaryChildren2 = nextProps.children; + if (node === workInProgress) { + return; + } // $FlowFixMe[incompatible-use] found when upgrading Flow - var _primaryChildFragment3 = updateSuspensePrimaryChildren( - current, - workInProgress, - _nextPrimaryChildren2, - renderLanes - ); - workInProgress.memoizedState = null; - return _primaryChildFragment3; - } + while (node.sibling === null) { + // $FlowFixMe[incompatible-use] found when upgrading Flow + if (node.return === null || node.return === workInProgress) { + return; } - } - 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; - } + node = node.return; + } // $FlowFixMe[incompatible-use] found when upgrading Flow - function mountSuspenseFallbackChildren( - workInProgress, - primaryChildren, - fallbackChildren, - 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; - - 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; - } - 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; + node.sibling.return = node.return; + node = node.sibling; + } +} + +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. + + if (currentRow !== null && findFirstSuspended(currentRow) === null) { + lastContentRow = row; } - 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 - } - ); + row = row.sibling; + } - if ((workInProgress.mode & ConcurrentMode) === NoMode) { - primaryChildFragment.lanes = renderLanes; - } + return lastContentRow; +} - primaryChildFragment.return = workInProgress; - primaryChildFragment.sibling = null; +function validateRevealOrder(revealOrder) { + { + if (revealOrder !== undefined && revealOrder !== 'forwards' && revealOrder !== 'backwards' && revealOrder !== 'together' && !didWarnAboutRevealOrder[revealOrder]) { + didWarnAboutRevealOrder[revealOrder] = true; - if (currentFallbackChildFragment !== null) { - // Delete the fallback child fragment - var deletions = workInProgress.deletions; + 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()); - if (deletions === null) { - workInProgress.deletions = [currentFallbackChildFragment]; - workInProgress.flags |= ChildDeletion; - } else { - deletions.push(currentFallbackChildFragment); - } - } + break; + } - workInProgress.child = primaryChildFragment; - return primaryChildFragment; - } + 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()); - 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 ( - // 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 (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 { - 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.) + break; + } + + default: + error('"%s" is not a supported revealOrder on . ' + 'Did you mean "together", "forwards" or "backwards"?', revealOrder); - primaryChildFragment.subtreeFlags = - currentPrimaryChildFragment.subtreeFlags & StaticMask; + break; + } + } else { + error('%s is not a supported value for revealOrder on . ' + 'Did you mean "together", "forwards" or "backwards"?', revealOrder); } + } + } +} - var fallbackChildFragment; +function validateTailOptions(tailMode, revealOrder) { + { + if (tailMode !== undefined && !didWarnAboutTailOptions[tailMode]) { + if (tailMode !== 'collapsed' && tailMode !== 'hidden') { + didWarnAboutTailOptions[tailMode] = true; - 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. + 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; - fallbackChildFragment.flags |= Placement; + error(' is only valid if revealOrder is ' + '"forwards" or "backwards". ' + 'Did you mean to specify revealOrder="forwards"?', tailMode); } - - fallbackChildFragment.return = workInProgress; - primaryChildFragment.return = workInProgress; - primaryChildFragment.sibling = fallbackChildFragment; - workInProgress.child = primaryChildFragment; - return fallbackChildFragment; } + } +} - function retrySuspenseComponentWithoutHydrating( - current, - workInProgress, - renderLanes - ) { - // 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. - // This will add the old fiber to the deletion list - reconcileChildFibers(workInProgress, current.child, null, renderLanes); // We're now not suspended nor dehydrated. +function validateSuspenseListNestedChild(childSlot, index) { + { + var isAnArray = isArray(childSlot); + var isIterable = !isAnArray && typeof getIteratorFn(childSlot) === 'function'; - 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. + if (isAnArray || isIterable) { + var type = isAnArray ? 'array' : 'iterable'; - primaryChildFragment.flags |= Placement; - workInProgress.memoizedState = null; - return primaryChildFragment; + error('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; } + } - 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; - - 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); - } + return true; +} - return fallbackChildFragment; - } +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); - function updateDehydratedSuspenseComponent( - current, - workInProgress, - didSuspend, - didPrimaryChildrenDefer, - 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 (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; - var message; - var stack = null; - var componentStack = null; + if (typeof iteratorFn === 'function') { + var childrenIterator = iteratorFn.call(children); - { - var _getSuspenseInstanceF = - getSuspenseInstanceFallbackErrorDetails(); + if (childrenIterator) { + var step = childrenIterator.next(); + var _i = 0; - digest = _getSuspenseInstanceF.digest; - message = _getSuspenseInstanceF.message; - stack = _getSuspenseInstanceF.stack; - componentStack = _getSuspenseInstanceF.componentStack; - } // TODO: Figure out a better signal than encoding a magic digest value. + for (; !step.done; step = childrenIterator.next()) { + if (!validateSuspenseListNestedChild(step.value, _i)) { + return; + } - { - var error; + _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 (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." - ); - } // Replace the stack with the server stack - - error.stack = stack || ""; - error.digest = digest; - var capturedValue = createCapturedValueFromError( - error, - componentStack === undefined ? null : componentStack - ); - queueHydrationError(capturedValue); +function initSuspenseListRenderState(workInProgress, isBackwards, tail, lastContentRow, tailMode) { + var renderState = workInProgress.memoizedState; + + 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. + + +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 (shouldForceFallback) { + suspenseContext = setShallowSuspenseListContext(suspenseContext, ForceSuspenseFallback); + workInProgress.flags |= DidCapture; + } else { + var didSuspendBefore = current !== null && (current.flags & DidCapture) !== NoFlags$1; + + 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); + } + + suspenseContext = setDefaultShallowSuspenseListContext(suspenseContext); + } + + 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; } - return retrySuspenseComponentWithoutHydrating( - current, - workInProgress, - renderLanes - ); + initSuspenseListRenderState(workInProgress, false, // isBackwards + tail, lastContentRow, tailMode); + break; } - // any context has changed, we need to treat is as if the input might have changed. - var hasContextChanged = includesSomeLane( - renderLanes, - current.childLanes - ); - - 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 '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; + + while (row !== null) { + var currentRow = row.alternate; // New rows can't be content rows. + + if (currentRow !== null && findFirstSuspended(currentRow) === null) { + // This is the beginning of the main content. + workInProgress.child = row; + break; + } - if (root !== null) { - var attemptHydrationAtLane = getBumpedLaneForHydration( - root, - renderLanes - ); + var nextRow = row.sibling; + row.sibling = _tail; + _tail = row; + row = nextRow; + } // TODO: If workInProgress.child is null, we can continue on the tail immediately. - 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; - enqueueConcurrentRenderForLane(current, attemptHydrationAtLane); - scheduleUpdateOnFiber(root, current, attemptHydrationAtLane); // 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. - 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. - - if (isSuspenseInstancePending()); - else { - renderDidSuspendDelayIfPossible(); - } + initSuspenseListRenderState(workInProgress, true, // isBackwards + _tail, null, // last + tailMode); + break; + } - return retrySuspenseComponentWithoutHydrating( - current, - workInProgress, - renderLanes - ); - } 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. - - workInProgress.child = current.child; // Register a callback to retry this boundary once the server has sent the result. - - 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. - - primaryChildFragment.flags |= Hydrating; - return primaryChildFragment; + case 'together': + { + initSuspenseListRenderState(workInProgress, false, // isBackwards + null, // tail + null, // last + undefined); + break; } - } 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. - // The error should've already been logged in throwException. - pushPrimaryTreeSuspenseHandler(workInProgress); - workInProgress.flags &= ~ForceClientRender; - return retrySuspenseComponentWithoutHydrating( - current, - workInProgress, - renderLanes - ); - } 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. - 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); - _primaryChildFragment4.childLanes = getRemainingWorkInPrimaryTree( - current, - didPrimaryChildrenDefer, - renderLanes - ); - workInProgress.memoizedState = SUSPENDED_MARKER; - return fallbackChildFragment; + default: + { + // The default reveal order is the same as not having + // a boundary. + workInProgress.memoizedState = null; } - } } + } - function scheduleSuspenseWorkOnFiber(fiber, renderLanes, propagationRoot) { - fiber.lanes = mergeLanes(fiber.lanes, renderLanes); - var alternate = fiber.alternate; + return workInProgress.child; +} - if (alternate !== null) { - alternate.lanes = mergeLanes(alternate.lanes, renderLanes); - } +function updatePortalComponent(current, workInProgress, renderLanes) { + pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); + var nextChildren = workInProgress.pendingProps; + + 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); + } + + return workInProgress.child; +} - scheduleContextWorkOnParentPath( - fiber.return, - renderLanes, - propagationRoot - ); +var hasWarnedAboutUsingNoValuePropOnContextProvider = false; + +function updateContextProvider(current, workInProgress, renderLanes) { + var context; + + { + context = workInProgress.type._context; + } + + var newProps = workInProgress.pendingProps; + var oldProps = workInProgress.memoizedProps; + var newValue = newProps.value; + + { + 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?'); + } } + } - 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; + pushProvider(workInProgress, context, newValue); - while (node !== null) { - if (node.tag === SuspenseComponent) { - var state = node.memoizedState; + { + if (oldProps !== null) { + var oldValue = oldProps.value; - 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 (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); + } + } + } - 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; - } + var newChildren = newProps.children; + reconcileChildren(current, workInProgress, newChildren, renderLanes); + return workInProgress.child; +} - node = node.return; - } // $FlowFixMe[incompatible-use] found when upgrading Flow +function updateContextConsumer(current, workInProgress, renderLanes) { + var context; - node.sibling.return = node.return; - node = node.sibling; + { + context = workInProgress.type; + + { + if (context._context !== undefined) { + context = context._context; } } + } - 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; + var newProps = workInProgress.pendingProps; + var render = newProps.children; - while (row !== null) { - var currentRow = row.alternate; // New rows can't be content rows. + { + 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.'); + } + } - if (currentRow !== null && findFirstSuspended(currentRow) === null) { - lastContentRow = row; - } + prepareToReadContext(workInProgress, renderLanes); + var newValue = readContext(context); - row = row.sibling; - } + { + markComponentRenderStarted(workInProgress); + } - return lastContentRow; - } + var newChildren; - function validateRevealOrder(revealOrder) { - { - if ( - revealOrder !== undefined && - revealOrder !== "forwards" && - revealOrder !== "backwards" && - revealOrder !== "together" && - !didWarnAboutRevealOrder[revealOrder] - ) { - didWarnAboutRevealOrder[revealOrder] = true; - - 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() - ); + { + ReactSharedInternals.owner = workInProgress; + setIsRendering(true); + newChildren = render(newValue); + setIsRendering(false); + } - break; - } + { + markComponentRenderStopped(); + } // React DevTools reads this flag. - 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; - } + workInProgress.flags |= PerformedWork; + reconcileChildren(current, workInProgress, newChildren, renderLanes); + return workInProgress.child; +} - default: - error( - '"%s" is not a supported revealOrder on . ' + - 'Did you mean "together", "forwards" or "backwards"?', - revealOrder - ); +function markWorkInProgressReceivedUpdate() { + didReceiveUpdate = true; +} - break; - } - } else { - error( - "%s is not a supported value for revealOrder on . " + - 'Did you mean "together", "forwards" or "backwards"?', - revealOrder - ); - } - } - } - } +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 - function validateTailOptions(tailMode, revealOrder) { - { - 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; - - error( - ' is only valid if revealOrder is ' + - '"forwards" or "backwards". ' + - 'Did you mean to specify revealOrder="forwards"?', - tailMode - ); - } - } - } + workInProgress.flags |= Placement; } + } +} - function validateSuspenseListNestedChild(childSlot, index) { - { - var isAnArray = isArray(childSlot); - var isIterable = - !isAnArray && typeof getIteratorFn(childSlot) === "function"; - - if (isAnArray || isIterable) { - var type = isAnArray ? "array" : "iterable"; - - 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 bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes) { + if (current !== null) { + // Reuse previous dependencies + workInProgress.dependencies = current.dependencies; + } - return false; - } - } + { + // Don't update "base" render times for bailouts. + stopProfilerTimerIfRunning(); + } - return true; + markSkippedUpdateLanes(workInProgress.lanes); // Check if the children have any pending work. + + 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. - 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); - if (typeof iteratorFn === "function") { - var childrenIterator = iteratorFn.call(children); + cloneChildFibers(current, workInProgress); + return workInProgress.child; +} - if (childrenIterator) { - var step = childrenIterator.next(); - var _i = 0; +function remountFiber(current, oldWorkInProgress, newWorkInProgress) { + { + var returnFiber = oldWorkInProgress.return; - for (; !step.done; step = childrenIterator.next()) { - if (!validateSuspenseListNestedChild(step.value, _i)) { - return; - } + 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. - _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 initSuspenseListRenderState( - workInProgress, - isBackwards, - tail, - lastContentRow, - tailMode - ) { - var renderState = workInProgress.memoizedState; - - 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. - - 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 (shouldForceFallback) { - suspenseContext = setShallowSuspenseListContext( - suspenseContext, - ForceSuspenseFallback - ); - workInProgress.flags |= DidCapture; - } else { - var didSuspendBefore = - current !== null && (current.flags & DidCapture) !== NoFlags$1; + current.alternate = null; + oldWorkInProgress.alternate = null; // Connect to the new tree. - 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 - ); - } + newWorkInProgress.index = oldWorkInProgress.index; + newWorkInProgress.sibling = oldWorkInProgress.sibling; + newWorkInProgress.return = oldWorkInProgress.return; + newWorkInProgress.ref = oldWorkInProgress.ref; - suspenseContext = setDefaultShallowSuspenseListContext(suspenseContext); - } + { + newWorkInProgress._debugInfo = oldWorkInProgress._debugInfo; + } // Replace the child/sibling pointers above it. - 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; - } + if (oldWorkInProgress === returnFiber.child) { + returnFiber.child = newWorkInProgress; + } else { + var prevSibling = returnFiber.child; - initSuspenseListRenderState( - workInProgress, - false, // isBackwards - tail, - lastContentRow, - tailMode - ); - break; - } + 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 - 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; - while (row !== null) { - var currentRow = row.alternate; // New rows can't be content rows. + while (prevSibling.sibling !== oldWorkInProgress) { + // $FlowFixMe[incompatible-use] found when upgrading Flow + prevSibling = prevSibling.sibling; - if ( - currentRow !== null && - findFirstSuspended(currentRow) === null - ) { - // This is the beginning of the main content. - workInProgress.child = row; - break; - } + 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 - var nextRow = row.sibling; - row.sibling = _tail; - _tail = row; - row = nextRow; - } // TODO: If workInProgress.child is null, we can continue on the tail immediately. - - initSuspenseListRenderState( - workInProgress, - true, // isBackwards - _tail, - null, // last - tailMode - ); - break; - } - case "together": { - initSuspenseListRenderState( - workInProgress, - false, // isBackwards - null, // tail - null, // last - undefined - ); - break; - } + prevSibling.sibling = newWorkInProgress; + } // Delete the old fiber and place the new one. + // Since the old fiber is disconnected, we have to schedule it manually. - default: { - // The default reveal order is the same as not having - // a boundary. - workInProgress.memoizedState = null; - } - } - } - return workInProgress.child; + var deletions = returnFiber.deletions; + + if (deletions === null) { + returnFiber.deletions = [current]; + returnFiber.flags |= ChildDeletion; + } else { + deletions.push(current); } - function updatePortalComponent(current, workInProgress, renderLanes) { - pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); - var nextChildren = workInProgress.pendingProps; - - 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); - } + newWorkInProgress.flags |= Placement; // Restart work from the new fiber. - return workInProgress.child; - } + return newWorkInProgress; + } +} - var hasWarnedAboutUsingNoValuePropOnContextProvider = false; +function checkScheduledUpdateOrContext(current, renderLanes) { + // Before performing an early bailout, we must check if there are pending + // updates or context. + var updateLanes = current.lanes; - function updateContextProvider(current, workInProgress, renderLanes) { - var context; + if (includesSomeLane(updateLanes, renderLanes)) { + return true; + } // No pending update, but because context is propagated lazily, we need + + return false; +} + +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); { - context = workInProgress.type._context; + var cache = current.memoizedState.cache; + pushCacheProvider(workInProgress, cache); } + break; - var newProps = workInProgress.pendingProps; - var oldProps = workInProgress.memoizedProps; - var newValue = newProps.value; + case HostSingleton: + case HostComponent: + pushHostContext(workInProgress); + break; + case ClassComponent: { - if (!("value" in newProps)) { - if (!hasWarnedAboutUsingNoValuePropOnContextProvider) { - hasWarnedAboutUsingNoValuePropOnContextProvider = true; + var Component = workInProgress.type; - error( - "The `value` prop is required for the ``. Did you misspell it or forget to pass it?" - ); - } + if (isContextProvider(Component)) { + pushContextProvider(workInProgress); } + + break; } - pushProvider(workInProgress, context, newValue); + case HostPortal: + pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); + break; + case ContextProvider: { - if (oldProps !== null) { - var oldValue = oldProps.value; - - 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); - } - } - } + var newValue = workInProgress.memoizedProps.value; + var context; - var newChildren = newProps.children; - reconcileChildren(current, workInProgress, newChildren, renderLanes); - return workInProgress.child; - } + { + context = workInProgress.type._context; + } - function updateContextConsumer(current, workInProgress, renderLanes) { - var context; + pushProvider(workInProgress, context, newValue); + break; + } + case Profiler: { - context = workInProgress.type; + // Profiler should only call onRender when one of its descendants actually rendered. + var hasChildWork = includesSomeLane(renderLanes, workInProgress.childLanes); + + if (hasChildWork) { + workInProgress.flags |= Update; + } { - if (context._context !== undefined) { - context = context._context; - } + // 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 newProps = workInProgress.pendingProps; - var render = newProps.children; + break; + case SuspenseComponent: { - 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 state = workInProgress.memoizedState; - prepareToReadContext(workInProgress, renderLanes); - var newValue = readContext(context); + 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. - { - markComponentRenderStarted(workInProgress); - } + workInProgress.flags |= DidCapture; // We should never render the children of a dehydrated boundary until we + // upgrade it. We return null instead of bailoutOnAlreadyFinishedWork. - var newChildren; + 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. - { - ReactSharedInternals.owner = workInProgress; - setIsRendering(true); - newChildren = render(newValue); - setIsRendering(false); - } - { - markComponentRenderStopped(); - } // React DevTools reads this flag. + var primaryChildFragment = workInProgress.child; + var primaryChildLanes = primaryChildFragment.childLanes; - workInProgress.flags |= PerformedWork; - reconcileChildren(current, workInProgress, newChildren, renderLanes); - return workInProgress.child; - } + 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. - function markWorkInProgressReceivedUpdate() { - didReceiveUpdate = true; - } + var child = bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); - 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 - - workInProgress.flags |= Placement; + 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); } - } - } - function bailoutOnAlreadyFinishedWork( - current, - workInProgress, - renderLanes - ) { - if (current !== null) { - // Reuse previous dependencies - workInProgress.dependencies = current.dependencies; + break; } + case SuspenseListComponent: { - // Don't update "base" render times for bailouts. - stopProfilerTimerIfRunning(); - } + var didSuspendBefore = (current.flags & DidCapture) !== NoFlags$1; - markSkippedUpdateLanes(workInProgress.lanes); // Check if the children have any pending work. + var _hasChildWork = includesSomeLane(renderLanes, workInProgress.childLanes); - 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. + 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. - cloneChildFibers(current, workInProgress); - return workInProgress.child; - } - function remountFiber(current, oldWorkInProgress, newWorkInProgress) { - { - var returnFiber = oldWorkInProgress.return; + 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. - 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. - current.alternate = null; - oldWorkInProgress.alternate = null; // Connect to the new tree. + var renderState = workInProgress.memoizedState; - newWorkInProgress.index = oldWorkInProgress.index; - newWorkInProgress.sibling = oldWorkInProgress.sibling; - newWorkInProgress.return = oldWorkInProgress.return; - newWorkInProgress.ref = oldWorkInProgress.ref; + 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; + } - { - newWorkInProgress._debugInfo = oldWorkInProgress._debugInfo; - } // Replace the child/sibling pointers above it. + pushSuspenseListContext(workInProgress, suspenseStackCursor.current); - if (oldWorkInProgress === returnFiber.child) { - returnFiber.child = newWorkInProgress; + if (_hasChildWork) { + break; } else { - var prevSibling = returnFiber.child; + // 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 (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 + 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); + } - while (prevSibling.sibling !== oldWorkInProgress) { - // $FlowFixMe[incompatible-use] found when upgrading Flow - prevSibling = prevSibling.sibling; + case CacheComponent: + { + { + var _cache = current.memoizedState.cache; + pushCacheProvider(workInProgress, _cache); + } - 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 + break; + } + } - prevSibling.sibling = newWorkInProgress; - } // Delete the old fiber and place the new one. - // Since the old fiber is disconnected, we have to schedule it manually. + return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); +} - var deletions = returnFiber.deletions; +function beginWork(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 (deletions === null) { - returnFiber.deletions = [current]; - returnFiber.flags |= ChildDeletion; - } else { - deletions.push(current); - } + if (current !== null) { + var oldProps = current.memoizedProps; + var newProps = workInProgress.pendingProps; - newWorkInProgress.flags |= Placement; // Restart work from the new fiber. + 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); + + 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); + } - return newWorkInProgress; + 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; } } + } 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. - 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, - 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); + workInProgress.lanes = NoLanes; - { - var cache = current.memoizedState.cache; - pushCacheProvider(workInProgress, cache); - } - break; + switch (workInProgress.tag) { + case LazyComponent: + { + var elementType = workInProgress.elementType; + return mountLazyComponent(current, workInProgress, elementType, renderLanes); + } - case HostSingleton: - case HostComponent: - pushHostContext(workInProgress); - break; + case FunctionComponent: + { + var Component = workInProgress.type; + var unresolvedProps = workInProgress.pendingProps; + var resolvedProps = workInProgress.elementType === Component ? unresolvedProps : resolveDefaultPropsOnNonClassComponent(Component, unresolvedProps); + return updateFunctionComponent(current, workInProgress, Component, resolvedProps, renderLanes); + } - case ClassComponent: { - var Component = workInProgress.type; + case ClassComponent: + { + var _Component = workInProgress.type; + var _unresolvedProps = workInProgress.pendingProps; - if (isContextProvider(Component)) { - pushContextProvider(workInProgress); - } + var _resolvedProps4 = resolveClassComponentProps(_Component, _unresolvedProps, workInProgress.elementType === _Component); - break; - } + return updateClassComponent(current, workInProgress, _Component, _resolvedProps4, renderLanes); + } - case HostPortal: - pushHostContainer( - workInProgress, - workInProgress.stateNode.containerInfo - ); - break; + case HostRoot: + return updateHostRoot(current, workInProgress, renderLanes); - case ContextProvider: { - var newValue = workInProgress.memoizedProps.value; - var context; + case HostHoistable: - { - context = workInProgress.type._context; - } + // Fall through - pushProvider(workInProgress, context, newValue); - break; - } + case HostSingleton: - case Profiler: - { - // Profiler should only call onRender when one of its descendants actually rendered. - var hasChildWork = includesSomeLane( - renderLanes, - workInProgress.childLanes - ); + // Fall through - if (hasChildWork) { - workInProgress.flags |= Update; - } + case HostComponent: + return updateHostComponent$1(current, workInProgress, renderLanes); - { - // 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; - } - } + case HostText: + return updateHostText$1(); - break; + case SuspenseComponent: + return updateSuspenseComponent(current, workInProgress, renderLanes); - case SuspenseComponent: { - var state = workInProgress.memoizedState; + case HostPortal: + return updatePortalComponent(current, workInProgress, renderLanes); - 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. + case ForwardRef: + { + var type = workInProgress.type; + var _unresolvedProps2 = workInProgress.pendingProps; - workInProgress.flags |= DidCapture; // We should never render the children of a dehydrated boundary until we - // upgrade it. We return null instead of bailoutOnAlreadyFinishedWork. + var _resolvedProps5 = workInProgress.elementType === type ? _unresolvedProps2 : resolveDefaultPropsOnNonClassComponent(type, _unresolvedProps2); - 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. + return updateForwardRef(current, workInProgress, type, _resolvedProps5, renderLanes); + } - var primaryChildFragment = workInProgress.child; - var primaryChildLanes = primaryChildFragment.childLanes; - - 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. - - var child = bailoutOnAlreadyFinishedWork( - current, - workInProgress, - renderLanes - ); - - 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); - } + case Fragment: + return updateFragment(current, workInProgress, renderLanes); - break; - } + case Mode: + return updateMode(current, workInProgress, renderLanes); - case SuspenseListComponent: { - var didSuspendBefore = (current.flags & DidCapture) !== NoFlags$1; - - var _hasChildWork = includesSomeLane( - renderLanes, - workInProgress.childLanes - ); - - 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. - - 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. - - var renderState = workInProgress.memoizedState; - - 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; - } + case Profiler: + return updateProfiler(current, workInProgress, renderLanes); - pushSuspenseListContext(workInProgress, suspenseStackCursor.current); + case ContextProvider: + return updateContextProvider(current, workInProgress, renderLanes); - 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; - } - } + case ContextConsumer: + return updateContextConsumer(current, workInProgress, renderLanes); - 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); - } + case MemoComponent: + { + var _type = workInProgress.type; + var _unresolvedProps3 = workInProgress.pendingProps; // Resolve outer props first, then resolve inner props. - case CacheComponent: { - { - var _cache = current.memoizedState.cache; - pushCacheProvider(workInProgress, _cache); - } + var _resolvedProps6 = resolveDefaultPropsOnNonClassComponent(_type, _unresolvedProps3); - break; - } + _resolvedProps6 = resolveDefaultPropsOnNonClassComponent(_type.type, _resolvedProps6); + return updateMemoComponent(current, workInProgress, _type, _resolvedProps6, renderLanes); } - return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); - } - - function beginWork(current, workInProgress, renderLanes) { + case SimpleMemoComponent: { - 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 - ) - ); - } + return updateSimpleMemoComponent(current, workInProgress, workInProgress.type, workInProgress.pendingProps, renderLanes); } - if (current !== null) { - var oldProps = current.memoizedProps; - var newProps = workInProgress.pendingProps; - - 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 - ); - - 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 ((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; - } - } - } 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. - - workInProgress.lanes = NoLanes; - - switch (workInProgress.tag) { - case LazyComponent: { - var elementType = workInProgress.elementType; - return mountLazyComponent( - current, - workInProgress, - elementType, - renderLanes - ); - } + case IncompleteClassComponent: + { - case FunctionComponent: { - var Component = workInProgress.type; - var unresolvedProps = workInProgress.pendingProps; - var resolvedProps = - workInProgress.elementType === Component - ? unresolvedProps - : resolveDefaultPropsOnNonClassComponent( - Component, - unresolvedProps - ); - return updateFunctionComponent( - current, - workInProgress, - Component, - resolvedProps, - renderLanes - ); - } + var _Component2 = workInProgress.type; + var _unresolvedProps4 = workInProgress.pendingProps; - case ClassComponent: { - var _Component = workInProgress.type; - var _unresolvedProps = workInProgress.pendingProps; - - var _resolvedProps4 = resolveClassComponentProps( - _Component, - _unresolvedProps, - workInProgress.elementType === _Component - ); - - return updateClassComponent( - current, - workInProgress, - _Component, - _resolvedProps4, - renderLanes - ); - } + var _resolvedProps7 = resolveClassComponentProps(_Component2, _unresolvedProps4, workInProgress.elementType === _Component2); - case HostRoot: - return updateHostRoot(current, workInProgress, renderLanes); + return mountIncompleteClassComponent(current, workInProgress, _Component2, _resolvedProps7, renderLanes); + } - case HostHoistable: + case IncompleteFunctionComponent: + { - // Fall through + var _Component3 = workInProgress.type; + var _unresolvedProps5 = workInProgress.pendingProps; - case HostSingleton: + var _resolvedProps8 = resolveClassComponentProps(_Component3, _unresolvedProps5, workInProgress.elementType === _Component3); - // Fall through + return mountIncompleteFunctionComponent(current, workInProgress, _Component3, _resolvedProps8, renderLanes); + } - case HostComponent: - return updateHostComponent$1(current, workInProgress, renderLanes); + case SuspenseListComponent: + { + return updateSuspenseListComponent(current, workInProgress, renderLanes); + } - case HostText: - return updateHostText$1(); + case ScopeComponent: + { - case SuspenseComponent: - return updateSuspenseComponent(current, workInProgress, renderLanes); + break; + } - case HostPortal: - return updatePortalComponent(current, workInProgress, renderLanes); - - case ForwardRef: { - var type = workInProgress.type; - var _unresolvedProps2 = workInProgress.pendingProps; - - var _resolvedProps5 = - workInProgress.elementType === type - ? _unresolvedProps2 - : resolveDefaultPropsOnNonClassComponent(type, _unresolvedProps2); - - return updateForwardRef( - current, - workInProgress, - type, - _resolvedProps5, - renderLanes - ); - } + case OffscreenComponent: + { + return updateOffscreenComponent(current, workInProgress, renderLanes); + } - case Fragment: - return updateFragment(current, workInProgress, renderLanes); + case LegacyHiddenComponent: + { - case Mode: - return updateMode(current, workInProgress, renderLanes); + break; + } - case Profiler: - return updateProfiler(current, workInProgress, renderLanes); - - case ContextProvider: - return updateContextProvider(current, workInProgress, renderLanes); - - case ContextConsumer: - return updateContextConsumer(current, workInProgress, renderLanes); - - case MemoComponent: { - var _type = workInProgress.type; - var _unresolvedProps3 = workInProgress.pendingProps; // Resolve outer props first, then resolve inner props. - - var _resolvedProps6 = resolveDefaultPropsOnNonClassComponent( - _type, - _unresolvedProps3 - ); - - _resolvedProps6 = resolveDefaultPropsOnNonClassComponent( - _type.type, - _resolvedProps6 - ); - return updateMemoComponent( - current, - workInProgress, - _type, - _resolvedProps6, - renderLanes - ); + case CacheComponent: + { + { + return updateCacheComponent(current, workInProgress, renderLanes); } + } + } - case SimpleMemoComponent: { - return updateSimpleMemoComponent( - current, - workInProgress, - workInProgress.type, - workInProgress.pendingProps, - renderLanes - ); - } + throw new Error("Unknown unit of work tag (" + workInProgress.tag + "). This error is likely caused by a bug in " + 'React. Please file an issue.'); +} - case IncompleteClassComponent: { - var _Component2 = workInProgress.type; - var _unresolvedProps4 = workInProgress.pendingProps; - - var _resolvedProps7 = resolveClassComponentProps( - _Component2, - _unresolvedProps4, - workInProgress.elementType === _Component2 - ); - - return mountIncompleteClassComponent( - current, - workInProgress, - _Component2, - _resolvedProps7, - renderLanes - ); - } +var valueCursor = createCursor(null); - case IncompleteFunctionComponent: { - var _Component3 = workInProgress.type; - var _unresolvedProps5 = workInProgress.pendingProps; - - var _resolvedProps8 = resolveClassComponentProps( - _Component3, - _unresolvedProps5, - workInProgress.elementType === _Component3 - ); - - return mountIncompleteFunctionComponent( - current, - workInProgress, - _Component3, - _resolvedProps8, - renderLanes - ); - } +var renderer2CursorDEV; - case SuspenseListComponent: { - return updateSuspenseListComponent( - current, - workInProgress, - renderLanes - ); - } +{ + renderer2CursorDEV = createCursor(null); +} - case ScopeComponent: { - break; - } +var rendererSigil; - case OffscreenComponent: { - return updateOffscreenComponent(current, workInProgress, renderLanes); - } +{ + // Use this to detect multiple renderers using the same context + rendererSigil = {}; +} - case LegacyHiddenComponent: { - break; - } +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; + + { + isDisallowedContextReadInDEV = false; + } +} +function enterDisallowedContextReadInDEV() { + { + isDisallowedContextReadInDEV = true; + } +} +function exitDisallowedContextReadInDEV() { + { + isDisallowedContextReadInDEV = false; + } +} +function pushProvider(providerFiber, context, nextValue) { + { + push(valueCursor, context._currentValue2, providerFiber); + context._currentValue2 = nextValue; - case CacheComponent: { - { - return updateCacheComponent(current, workInProgress, renderLanes); - } - } + { + 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.'); } - throw new Error( - "Unknown unit of work tag (" + - workInProgress.tag + - "). This error is likely caused by a bug in " + - "React. Please file an issue." - ); + context._currentRenderer2 = rendererSigil; } + } +} +function popProvider(context, providerFiber) { + var currentValue = valueCursor.current; - var valueCursor = createCursor(null); - - var renderer2CursorDEV; + { + context._currentValue2 = currentValue; { - renderer2CursorDEV = createCursor(null); + var currentRenderer2 = renderer2CursorDEV.current; + pop(renderer2CursorDEV, providerFiber); + context._currentRenderer2 = currentRenderer2; } + } - var rendererSigil; + pop(valueCursor, providerFiber); +} +function scheduleContextWorkOnParentPath(parent, renderLanes, propagationRoot) { + // Update the child lanes of all the ancestors, including the alternates. + var node = parent; - { - // Use this to detect multiple renderers using the same context - rendererSigil = {}; - } + while (node !== null) { + var alternate = node.alternate; - 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 (!isSubsetOfLanes(node.childLanes, renderLanes)) { + node.childLanes = mergeLanes(node.childLanes, renderLanes); - { - isDisallowedContextReadInDEV = false; - } - } - function enterDisallowedContextReadInDEV() { - { - isDisallowedContextReadInDEV = true; - } - } - function exitDisallowedContextReadInDEV() { - { - isDisallowedContextReadInDEV = false; + 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 (node === propagationRoot) { + break; } - function pushProvider(providerFiber, context, nextValue) { - { - push(valueCursor, context._currentValue2, providerFiber); - context._currentValue2 = nextValue; - { - 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." - ); - } + node = node.return; + } - context._currentRenderer2 = rendererSigil; - } - } + { + 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 popProvider(context, providerFiber) { - var currentValue = valueCursor.current; + } +} +function propagateContextChange(workInProgress, context, renderLanes) { + { + propagateContextChange_eager(workInProgress, context, renderLanes); + } +} - { - context._currentValue2 = currentValue; +function propagateContextChange_eager(workInProgress, context, renderLanes) { - { - var currentRenderer2 = renderer2CursorDEV.current; - pop(renderer2CursorDEV, providerFiber); - context._currentRenderer2 = currentRenderer2; - } - } + var fiber = workInProgress.child; - pop(valueCursor, providerFiber); - } - function scheduleContextWorkOnParentPath( - parent, - renderLanes, - propagationRoot - ) { - // Update the child lanes of all the ancestors, including the alternates. - var node = parent; + if (fiber !== null) { + // Set the return pointer of the child to the work-in-progress fiber. + fiber.return = workInProgress; + } + + while (fiber !== null) { + var nextFiber = void 0; // Visit this fiber. + + var list = fiber.dependencies; + + if (list !== null) { + nextFiber = fiber.child; + var dependency = list.firstContext; + + 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 + + var updateQueue = fiber.updateQueue; + + if (updateQueue === null) ; else { + var sharedQueue = updateQueue.shared; + var pending = sharedQueue.pending; + + if (pending === null) { + // This is the first update. Create a circular list. + update.next = update; + } else { + update.next = pending.next; + pending.next = update; + } - while (node !== null) { - var alternate = node.alternate; + sharedQueue.pending = update; + } + } - if (!isSubsetOfLanes(node.childLanes, renderLanes)) { - node.childLanes = mergeLanes(node.childLanes, renderLanes); + fiber.lanes = mergeLanes(fiber.lanes, renderLanes); + var alternate = fiber.alternate; if (alternate !== null) { - alternate.childLanes = mergeLanes( - alternate.childLanes, - renderLanes - ); + alternate.lanes = mergeLanes(alternate.lanes, renderLanes); } - } else if ( - alternate !== null && - !isSubsetOfLanes(alternate.childLanes, renderLanes) - ) { - alternate.childLanes = mergeLanes(alternate.childLanes, renderLanes); - } else; - - if (node === propagationRoot) { + + scheduleContextWorkOnParentPath(fiber.return, renderLanes, workInProgress); // Mark the updated lanes on the list, too. + + list.lanes = mergeLanes(list.lanes, renderLanes); // Since we already found a match, we can stop traversing the + // dependency list. + break; } - node = node.return; + 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 (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); + 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.'); } - } - function propagateContextChange_eager( - workInProgress, - context, - renderLanes - ) { - var fiber = workInProgress.child; - - if (fiber !== null) { - // Set the return pointer of the child to the work-in-progress fiber. - fiber.return = workInProgress; - } + parentSuspense.lanes = mergeLanes(parentSuspense.lanes, renderLanes); + var _alternate = parentSuspense.alternate; - while (fiber !== null) { - var nextFiber = void 0; // Visit this fiber. + 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. - var list = fiber.dependencies; - if (list !== null) { - nextFiber = fiber.child; - var dependency = list.firstContext; + scheduleContextWorkOnParentPath(parentSuspense, renderLanes, workInProgress); + nextFiber = fiber.sibling; + } else { + // Traverse down. + nextFiber = fiber.child; + } - 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 (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; - var updateQueue = fiber.updateQueue; + while (nextFiber !== null) { + if (nextFiber === workInProgress) { + // We're back to the root of this subtree. Exit. + nextFiber = null; + break; + } - if (updateQueue === null); - else { - var sharedQueue = updateQueue.shared; - var pending = sharedQueue.pending; + var sibling = nextFiber.sibling; - if (pending === null) { - // This is the first update. Create a circular list. - update.next = update; - } else { - update.next = pending.next; - pending.next = update; - } + 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. - sharedQueue.pending = update; - } - } - fiber.lanes = mergeLanes(fiber.lanes, renderLanes); - var alternate = fiber.alternate; + nextFiber = nextFiber.return; + } + } - if (alternate !== null) { - alternate.lanes = mergeLanes(alternate.lanes, renderLanes); - } + fiber = nextFiber; + } +} +function prepareToReadContext(workInProgress, renderLanes) { + currentlyRenderingFiber = workInProgress; + lastContextDependency = null; + lastFullyObservedContext = null; + var dependencies = workInProgress.dependencies; - scheduleContextWorkOnParentPath( - fiber.return, - renderLanes, - workInProgress - ); // Mark the updated lanes on the list, too. + if (dependencies !== null) { + { + var firstContext = dependencies.firstContext; - list.lanes = mergeLanes(list.lanes, renderLanes); // Since we already found a match, we can stop traversing the - // dependency list. + 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 - 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." - ); - } + 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().'); + } + } - parentSuspense.lanes = mergeLanes(parentSuspense.lanes, renderLanes); - var _alternate = parentSuspense.alternate; - - 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. - - scheduleContextWorkOnParentPath( - parentSuspense, - renderLanes, - workInProgress - ); - nextFiber = fiber.sibling; - } else { - // Traverse down. - nextFiber = fiber.child; - } + return readContextForConsumer(currentlyRenderingFiber, context); +} +function readContextDuringReconciliation(consumer, context, renderLanes) { + if (currentlyRenderingFiber === null) { + prepareToReadContext(consumer, renderLanes); + } - 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; + return readContextForConsumer(consumer, context); +} - while (nextFiber !== null) { - if (nextFiber === workInProgress) { - // We're back to the root of this subtree. Exit. - nextFiber = null; - break; - } +function readContextForConsumer(consumer, context) { + var value = context._currentValue2; - var sibling = nextFiber.sibling; + if (lastFullyObservedContext === context) ; else { + var contextItem = { + context: context, + memoizedValue: value, + next: null + }; - 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. + 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. - nextFiber = nextFiber.return; - } - } - fiber = nextFiber; - } + lastContextDependency = contextItem; + consumer.dependencies = { + lanes: NoLanes, + firstContext: contextItem + }; + } else { + // Append a new context item. + lastContextDependency = lastContextDependency.next = contextItem; } - function prepareToReadContext(workInProgress, renderLanes) { - currentlyRenderingFiber = workInProgress; - lastContextDependency = null; - lastFullyObservedContext = null; - var dependencies = workInProgress.dependencies; + } - if (dependencies !== null) { - { - var firstContext = dependencies.firstContext; + return value; +} - 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 +// replace it with a lightweight shim that only has the features we use. - dependencies.firstContext = null; - } - } - } +var AbortControllerLocal = typeof AbortController !== 'undefined' ? AbortController : // $FlowFixMe[missing-this-annot] +// $FlowFixMe[prop-missing] +function AbortControllerShim() { + var listeners = []; + var signal = this.signal = { + aborted: false, + addEventListener: function (type, listener) { + listeners.push(listener); } - 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()." - ); - } - } + }; + + this.abort = function () { + signal.aborted = true; + listeners.forEach(function (listener) { + return listener(); + }); + }; +} ; // Intentionally not named imports because Rollup would +// use dynamic dispatch for CommonJS interop named imports. + +var scheduleCallback$1 = Scheduler$1.unstable_scheduleCallback, + NormalPriority = Scheduler$1.unstable_NormalPriority; +var CacheContext = { + $$typeof: REACT_CONTEXT_TYPE, + // We don't use Consumer/Provider for Cache components. So we'll cheat. + Consumer: null, + Provider: null, + // We'll initialize these at the root. + _currentValue: null, + _currentValue2: null, + _threadCount: 0 +} ; + +{ + CacheContext._currentRenderer = null; + CacheContext._currentRenderer2 = null; +} // Creates a new empty Cache instance with a ref-count of 0. The caller is responsible +// for retaining the cache once it is in use (retainCache), and releasing the cache +// once it is no longer needed (releaseCache). + + +function createCache() { + + var cache = { + controller: new AbortControllerLocal(), + data: new Map(), + refCount: 0 + }; + return cache; +} +function retainCache(cache) { - return readContextForConsumer(currentlyRenderingFiber, context); + { + if (cache.controller.signal.aborted) { + warn('A cache instance was retained after it was already freed. ' + 'This likely indicates a bug in React.'); } - function readContextDuringReconciliation(consumer, context, renderLanes) { - if (currentlyRenderingFiber === null) { - prepareToReadContext(consumer, renderLanes); - } + } + + cache.refCount++; +} // Cleanup a cache instance, potentially freeing it if there are no more references + +function releaseCache(cache) { - return readContextForConsumer(consumer, context); + cache.refCount--; + + { + if (cache.refCount < 0) { + warn('A cache instance was released after it was already freed. ' + 'This likely indicates a bug in React.'); } + } - function readContextForConsumer(consumer, context) { - var value = context._currentValue2; + if (cache.refCount === 0) { + scheduleCallback$1(NormalPriority, function () { + cache.controller.abort(); + }); + } +} +function pushCacheProvider(workInProgress, cache) { - if (lastFullyObservedContext === context); - else { - var contextItem = { - context: context, - memoizedValue: value, - next: null - }; + pushProvider(workInProgress, CacheContext, cache); +} +function popCacheProvider(workInProgress, cache) { - 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. + popProvider(CacheContext, workInProgress); +} - lastContextDependency = contextItem; - consumer.dependencies = { - lanes: NoLanes, - firstContext: contextItem - }; - } else { - // Append a new context item. - lastContextDependency = lastContextDependency.next = contextItem; - } - } +function requestCurrentTransition() { + var transition = ReactSharedInternals.T; - return value; - } + if (transition !== null) { + // Whenever a transition update is scheduled, register a callback on the + // transition object so we can get the return value of the scope function. + transition._callbacks.add(handleAsyncAction); + } - // replace it with a lightweight shim that only has the features we use. + return transition; +} - var AbortControllerLocal = - typeof AbortController !== "undefined" - ? AbortController // $FlowFixMe[missing-this-annot] - : // $FlowFixMe[prop-missing] - function AbortControllerShim() { - var listeners = []; - var signal = (this.signal = { - aborted: false, - addEventListener: function (type, listener) { - listeners.push(listener); - } - }); +function handleAsyncAction(transition, thenable) { + { + // This is an async action. + entangleAsyncAction(transition, thenable); + } +} - this.abort = function () { - signal.aborted = true; - listeners.forEach(function (listener) { - return listener(); - }); - }; - }; // Intentionally not named imports because Rollup would - // use dynamic dispatch for CommonJS interop named imports. - - var scheduleCallback$1 = Scheduler$1.unstable_scheduleCallback, - NormalPriority = Scheduler$1.unstable_NormalPriority; - var CacheContext = { - $$typeof: REACT_CONTEXT_TYPE, - // We don't use Consumer/Provider for Cache components. So we'll cheat. - Consumer: null, - Provider: null, - // We'll initialize these at the root. - _currentValue: null, - _currentValue2: null, - _threadCount: 0 - }; +function notifyTransitionCallbacks(transition, returnValue) { + var callbacks = transition._callbacks; + callbacks.forEach(function (callback) { + return callback(transition, returnValue); + }); +} // When retrying a Suspense/Offscreen boundary, we restore the cache that was +// used during the previous render by placing it here, on the stack. - { - CacheContext._currentRenderer = null; - CacheContext._currentRenderer2 = null; - } // Creates a new empty Cache instance with a ref-count of 0. The caller is responsible - // for retaining the cache once it is in use (retainCache), and releasing the cache - // once it is no longer needed (releaseCache). - - function createCache() { - var cache = { - controller: new AbortControllerLocal(), - data: new Map(), - refCount: 0 - }; - return cache; - } - function retainCache(cache) { - { - if (cache.controller.signal.aborted) { - warn( - "A cache instance was retained after it was already freed. " + - "This likely indicates a bug in React." - ); - } - } +var resumedCache = createCursor(null); // During the render/synchronous commit phase, we don't actually process the - cache.refCount++; - } // Cleanup a cache instance, potentially freeing it if there are no more references +function peekCacheFromPool() { + // If we're rendering inside a Suspense boundary that is currently hidden, + // we should use the same cache that we used during the previous render, if + // one exists. - function releaseCache(cache) { - cache.refCount--; - { - if (cache.refCount < 0) { - warn( - "A cache instance was released after it was already freed. " + - "This likely indicates a bug in React." - ); - } - } + var cacheResumedFromPreviousRender = resumedCache.current; - if (cache.refCount === 0) { - scheduleCallback$1(NormalPriority, function () { - cache.controller.abort(); - }); - } - } - function pushCacheProvider(workInProgress, cache) { - pushProvider(workInProgress, CacheContext, cache); - } - function popCacheProvider(workInProgress, cache) { - popProvider(CacheContext, workInProgress); - } + if (cacheResumedFromPreviousRender !== null) { + return cacheResumedFromPreviousRender; + } // Otherwise, check the root's cache pool. - function requestCurrentTransition() { - var transition = ReactSharedInternals.T; - if (transition !== null) { - // Whenever a transition update is scheduled, register a callback on the - // transition object so we can get the return value of the scope function. - transition._callbacks.add(handleAsyncAction); - } + var root = getWorkInProgressRoot(); + var cacheFromRootCachePool = root.pooledCache; + return cacheFromRootCachePool; +} - return transition; - } +function requestCacheFromPool(renderLanes) { + // Similar to previous function, except if there's not already a cache in the + // pool, we allocate a new one. + var cacheFromPool = peekCacheFromPool(); + + if (cacheFromPool !== null) { + return cacheFromPool; + } // Create a fresh cache and add it to the root cache pool. A cache can have + // multiple owners: + // - A cache pool that lives on the FiberRoot. This is where all fresh caches + // are originally created (TODO: except during refreshes, until we implement + // this correctly). The root takes ownership immediately when the cache is + // created. Conceptually, root.pooledCache is an Option> (owned), + // and the return value of this function is a &Arc (borrowed). + // - One of several fiber types: host root, cache boundary, suspense + // component. These retain and release in the commit phase. + + + var root = getWorkInProgressRoot(); + var freshCache = createCache(); + root.pooledCache = freshCache; + retainCache(freshCache); + + if (freshCache !== null) { + root.pooledCacheLanes |= renderLanes; + } + + return freshCache; +} +function pushTransition(offscreenWorkInProgress, prevCachePool, newTransitions) { + { + if (prevCachePool === null) { + push(resumedCache, resumedCache.current, offscreenWorkInProgress); + } else { + push(resumedCache, prevCachePool.pool, offscreenWorkInProgress); + } + } +} +function popTransition(workInProgress, current) { + if (current !== null) { - function handleAsyncAction(transition, thenable) { - { - // This is an async action. - entangleAsyncAction(transition, thenable); - } + { + pop(resumedCache, workInProgress); } + } +} +function getSuspendedCache() { + // cache that would have been used to render fresh data during this render, + // if there was any, so that we can resume rendering with the same cache when + // we receive more data. - function notifyTransitionCallbacks(transition, returnValue) { - var callbacks = transition._callbacks; - callbacks.forEach(function (callback) { - return callback(transition, returnValue); - }); - } // When retrying a Suspense/Offscreen boundary, we restore the cache that was - // used during the previous render by placing it here, on the stack. - var resumedCache = createCursor(null); // During the render/synchronous commit phase, we don't actually process the + var cacheFromPool = peekCacheFromPool(); - function peekCacheFromPool() { - // If we're rendering inside a Suspense boundary that is currently hidden, - // we should use the same cache that we used during the previous render, if - // one exists. + if (cacheFromPool === null) { + return null; + } - var cacheResumedFromPreviousRender = resumedCache.current; + return { + // We must also save the parent, so that when we resume we can detect + // a refresh. + parent: CacheContext._currentValue2, + pool: cacheFromPool + }; +} +function getOffscreenDeferredCache() { - if (cacheResumedFromPreviousRender !== null) { - return cacheResumedFromPreviousRender; - } // Otherwise, check the root's cache pool. + var cacheFromPool = peekCacheFromPool(); - var root = getWorkInProgressRoot(); - var cacheFromRootCachePool = root.pooledCache; - return cacheFromRootCachePool; - } - - function requestCacheFromPool(renderLanes) { - // Similar to previous function, except if there's not already a cache in the - // pool, we allocate a new one. - var cacheFromPool = peekCacheFromPool(); - - if (cacheFromPool !== null) { - return cacheFromPool; - } // Create a fresh cache and add it to the root cache pool. A cache can have - // multiple owners: - // - A cache pool that lives on the FiberRoot. This is where all fresh caches - // are originally created (TODO: except during refreshes, until we implement - // this correctly). The root takes ownership immediately when the cache is - // created. Conceptually, root.pooledCache is an Option> (owned), - // and the return value of this function is a &Arc (borrowed). - // - One of several fiber types: host root, cache boundary, suspense - // component. These retain and release in the commit phase. + if (cacheFromPool === null) { + return null; + } - var root = getWorkInProgressRoot(); - var freshCache = createCache(); - root.pooledCache = freshCache; - retainCache(freshCache); + return { + // We must also store the parent, so that when we resume we can detect + // a refresh. + parent: CacheContext._currentValue2, + pool: cacheFromPool + }; +} - if (freshCache !== null) { - root.pooledCacheLanes |= renderLanes; - } +/** + * Tag the fiber with an update effect. This turns a Placement into + * a PlacementAndUpdate. + */ - return freshCache; - } - function pushTransition( - offscreenWorkInProgress, - prevCachePool, - newTransitions - ) { - { - if (prevCachePool === null) { - push(resumedCache, resumedCache.current, offscreenWorkInProgress); - } else { - push(resumedCache, prevCachePool.pool, offscreenWorkInProgress); - } - } - } - function popTransition(workInProgress, current) { - if (current !== null) { - { - pop(resumedCache, workInProgress); - } - } - } - function getSuspendedCache() { - // cache that would have been used to render fresh data during this render, - // if there was any, so that we can resume rendering with the same cache when - // we receive more data. +function markUpdate(workInProgress) { + workInProgress.flags |= Update; +} - var cacheFromPool = peekCacheFromPool(); +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; - if (cacheFromPool === null) { - return null; + while (node !== null) { + if (node.tag === HostComponent || node.tag === HostText) { + appendInitialChild(parent, node.stateNode); + } else if (node.tag === HostPortal || (false)) ; else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; } - return { - // We must also save the parent, so that when we resume we can detect - // a refresh. - parent: CacheContext._currentValue2, - pool: cacheFromPool - }; - } - function getOffscreenDeferredCache() { - var cacheFromPool = peekCacheFromPool(); + if (node === workInProgress) { + return; + } // $FlowFixMe[incompatible-use] found when upgrading Flow - if (cacheFromPool === null) { - return null; - } - return { - // We must also store the parent, so that when we resume we can detect - // a refresh. - parent: CacheContext._currentValue2, - pool: cacheFromPool - }; - } + while (node.sibling === null) { + // $FlowFixMe[incompatible-use] found when upgrading Flow + if (node.return === null || node.return === workInProgress) { + return; + } - /** - * Tag the fiber with an update effect. This turns a Placement into - * a PlacementAndUpdate. - */ + node = node.return; + } // $FlowFixMe[incompatible-use] found when upgrading Flow - function markUpdate(workInProgress) { - workInProgress.flags |= Update; + + node.sibling.return = node.return; + node = node.sibling; + } + } +} // An unfortunate fork of appendAllChildren because we have two different parent types. + +function updateHostComponent(current, workInProgress, type, newProps, renderLanes) { + { + // If we have an alternate, that means this is an update and we need to + // schedule a side-effect to do the updates. + var oldProps = current.memoizedProps; + + if (oldProps === newProps) { + // In mutation mode, this is sufficient for a bailout because + // we won't touch this node even if children changed. + return; + } + + markUpdate(workInProgress); + } +} // This function must be called 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. +// 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. + + +function preloadInstanceAndSuspendIfNeeded(workInProgress, type, props, renderLanes) { + { + // 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 &= ~MaySuspendCommit; + return; + } // Mark this fiber with a flag. This gets set on all host instances +} + +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); + } + } +} + +function updateHostText(current, workInProgress, oldText, newText) { + { + // If the text differs, mark it as an update. All the work in done in commitWork. + if (oldText !== newText) { + markUpdate(workInProgress); } + } +} + +function cutOffTailIfNeeded(renderState, hasRenderedATailFallback) { - function appendAllChildren( - parent, - workInProgress, - needsVisibilityToggle, - isHidden - ) { + switch (renderState.tailMode) { + case 'hidden': { - // 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) { - if (node.tag === HostComponent || node.tag === HostText) { - appendInitialChild(parent, node.stateNode); - } else if (node.tag === HostPortal || false); - else if (node.child !== null) { - node.child.return = node; - node = node.child; - continue; - } + // 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 (node === workInProgress) { - return; - } // $FlowFixMe[incompatible-use] found when upgrading Flow + while (tailNode !== null) { + if (tailNode.alternate !== null) { + lastTailNode = tailNode; + } - while (node.sibling === null) { - // $FlowFixMe[incompatible-use] found when upgrading Flow - if (node.return === null || node.return === workInProgress) { - return; - } + tailNode = tailNode.sibling; + } // Next we're simply going to delete all insertions after the + // last rendered item. - node = node.return; - } // $FlowFixMe[incompatible-use] found when upgrading Flow - node.sibling.return = node.return; - node = node.sibling; + 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; } + + break; } - } // An unfortunate fork of appendAllChildren because we have two different parent types. - function updateHostComponent( - current, - workInProgress, - type, - newProps, - renderLanes - ) { + case 'collapsed': { - // If we have an alternate, that means this is an update and we need to - // schedule a side-effect to do the updates. - var oldProps = current.memoizedProps; + // 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 (oldProps === newProps) { - // In mutation mode, this is sufficient for a bailout because - // we won't touch this node even if children changed. - return; - } + while (_tailNode !== null) { + if (_tailNode.alternate !== null) { + _lastTailNode = _tailNode; + } - markUpdate(workInProgress); - } - } // This function must be called 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. - // 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. - - function preloadInstanceAndSuspendIfNeeded( - workInProgress, - type, - props, - renderLanes - ) { - { - // 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 &= ~MaySuspendCommit; - return; - } // Mark this fiber with a flag. This gets set on all host instances - } + _tailNode = _tailNode.sibling; + } // Next we're simply going to delete all insertions after the + // last rendered item. - 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); + 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; } + + break; + } + } +} + +function bubbleProperties(completedWork) { + var didBailout = completedWork.alternate !== null && completedWork.alternate.child === completedWork.child; + var newChildLanes = NoLanes; + var subtreeFlags = NoFlags$1; + + 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; + + 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 + + actualDuration += child.actualDuration; // $FlowFixMe[unsafe-addition] addition with possible null/undefined value + + treeBaseDuration += child.treeBaseDuration; + child = child.sibling; } - } - function updateHostText(current, workInProgress, oldText, newText) { - { - // If the text differs, mark it as an update. All the work in done in commitWork. - if (oldText !== newText) { - markUpdate(workInProgress); - } + completedWork.actualDuration = actualDuration; + completedWork.treeBaseDuration = treeBaseDuration; + } else { + var _child = completedWork.child; + + 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. + + _child.return = completedWork; + _child = _child.sibling; } } - 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; - - while (tailNode !== null) { - if (tailNode.alternate !== null) { - lastTailNode = tailNode; - } + 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; - tailNode = tailNode.sibling; - } // Next we're simply going to delete all insertions after the - // last rendered item. + 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. - 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; - } + subtreeFlags |= _child2.subtreeFlags & StaticMask; + subtreeFlags |= _child2.flags & StaticMask; // $FlowFixMe[unsafe-addition] addition with possible null/undefined value - break; - } + _treeBaseDuration += _child2.treeBaseDuration; + _child2 = _child2.sibling; + } - 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; - } + completedWork.treeBaseDuration = _treeBaseDuration; + } else { + var _child3 = completedWork.child; - _tailNode = _tailNode.sibling; - } // Next we're simply going to delete all insertions after the - // last rendered item. + 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 (_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; - } + 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. - break; - } + _child3.return = completedWork; + _child3 = _child3.sibling; } } - function bubbleProperties(completedWork) { - var didBailout = - completedWork.alternate !== null && - completedWork.alternate.child === completedWork.child; - var newChildLanes = NoLanes; - var subtreeFlags = NoFlags$1; + completedWork.subtreeFlags |= subtreeFlags; + } - 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; + completedWork.childLanes = newChildLanes; + return didBailout; +} - 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 - - actualDuration += child.actualDuration; // $FlowFixMe[unsafe-addition] addition with possible null/undefined value - - treeBaseDuration += child.treeBaseDuration; - child = child.sibling; - } +function completeDehydratedSuspenseBoundary(current, workInProgress, nextState) { + var wasHydrated = popHydrationState(); - completedWork.actualDuration = actualDuration; - completedWork.treeBaseDuration = treeBaseDuration; - } else { - var _child = completedWork.child; + 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.'); + } - 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. + prepareToHydrateHostSuspenseInstance(); + bubbleProperties(workInProgress); - _child.return = completedWork; - _child = _child.sibling; - } - } + { + if ((workInProgress.mode & ProfileMode) !== NoMode) { + var isTimedOutSuspense = nextState !== null; - 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; - - 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. - - subtreeFlags |= _child2.subtreeFlags & StaticMask; - subtreeFlags |= _child2.flags & StaticMask; // $FlowFixMe[unsafe-addition] addition with possible null/undefined value - - _treeBaseDuration += _child2.treeBaseDuration; - _child2 = _child2.sibling; - } + if (isTimedOutSuspense) { + // Don't count time spent in a timed out Suspense subtree as part of the base duration. + var primaryChildFragment = workInProgress.child; - completedWork.treeBaseDuration = _treeBaseDuration; - } else { - var _child3 = completedWork.child; - - 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. - - 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. - - _child3.return = completedWork; - _child3 = _child3.sibling; + if (primaryChildFragment !== null) { + // $FlowFixMe[unsafe-arithmetic] Flow doesn't support type casting in combination with the -= operator + workInProgress.treeBaseDuration -= primaryChildFragment.treeBaseDuration; + } } } - - completedWork.subtreeFlags |= subtreeFlags; } - completedWork.childLanes = newChildLanes; - return didBailout; - } + return false; + } else { + emitPendingHydrationWarnings(); // We might have reentered this boundary to hydrate it. If so, we need to reset the hydration - function completeDehydratedSuspenseBoundary( - current, - workInProgress, - nextState - ) { - var wasHydrated = popHydrationState(); + 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. - 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." - ); - } - prepareToHydrateHostSuspenseInstance(); - bubbleProperties(workInProgress); + workInProgress.flags |= Update; + bubbleProperties(workInProgress); - { - if ((workInProgress.mode & ProfileMode) !== NoMode) { - var isTimedOutSuspense = nextState !== null; + { + if ((workInProgress.mode & ProfileMode) !== NoMode) { + var _isTimedOutSuspense = nextState !== null; - if (isTimedOutSuspense) { - // Don't count time spent in a timed out Suspense subtree as part of the base duration. - var primaryChildFragment = workInProgress.child; + if (_isTimedOutSuspense) { + // 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[unsafe-arithmetic] Flow doesn't support type casting in combination with the -= operator - workInProgress.treeBaseDuration -= - primaryChildFragment.treeBaseDuration; - } - } + if (_primaryChildFragment !== null) { + // $FlowFixMe[unsafe-arithmetic] Flow doesn't support type casting in combination with the -= operator + workInProgress.treeBaseDuration -= _primaryChildFragment.treeBaseDuration; } } + } + } - return false; - } else { - emitPendingHydrationWarnings(); // We might have reentered this boundary to hydrate it. If so, we need to reset the hydration - - 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); + 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 - { - if ((workInProgress.mode & ProfileMode) !== NoMode) { - var _isTimedOutSuspense = nextState !== null; + return true; + } +} - if (_isTimedOutSuspense) { - // Don't count time spent in a timed out Suspense subtree as part of the base duration. - var _primaryChildFragment = workInProgress.child; +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 IncompleteFunctionComponent: + + case LazyComponent: + case SimpleMemoComponent: + case FunctionComponent: + case ForwardRef: + case Fragment: + case Mode: + case Profiler: + case ContextConsumer: + case MemoComponent: + bubbleProperties(workInProgress); + return null; - if (_primaryChildFragment !== null) { - // $FlowFixMe[unsafe-arithmetic] Flow doesn't support type casting in combination with the -= operator - workInProgress.treeBaseDuration -= - _primaryChildFragment.treeBaseDuration; - } - } - } - } + case ClassComponent: + { + var Component = workInProgress.type; - return false; + if (isContextProvider(Component)) { + popContext(workInProgress); } - } 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; + bubbleProperties(workInProgress); + return null; } - } - function completeWork(current, workInProgress, renderLanes) { - var newProps = workInProgress.pendingProps; // Note: This intentionally doesn't check if we're hydrating because comparing + case HostRoot: + { + var fiberRoot = workInProgress.stateNode; - switch (workInProgress.tag) { - case IncompleteFunctionComponent: + { + var previousCache = null; - case LazyComponent: - case SimpleMemoComponent: - case FunctionComponent: - case ForwardRef: - case Fragment: - case Mode: - case Profiler: - case ContextConsumer: - case MemoComponent: - bubbleProperties(workInProgress); - return null; + if (current !== null) { + previousCache = current.memoizedState.cache; + } - case ClassComponent: { - var Component = workInProgress.type; + var cache = workInProgress.memoizedState.cache; - if (isContextProvider(Component)) { - popContext(workInProgress); + if (cache !== previousCache) { + // Run passive effects to retain/release the cache. + workInProgress.flags |= Passive$1; } - bubbleProperties(workInProgress); - return null; + popCacheProvider(workInProgress); + } + popHostContainer(workInProgress); + popTopLevelContextObject(workInProgress); + + if (fiberRoot.pendingContext) { + fiberRoot.context = fiberRoot.pendingContext; + fiberRoot.pendingContext = null; } - case HostRoot: { - var fiberRoot = workInProgress.stateNode; + 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(); - { - var previousCache = null; + if (wasHydrated) { + emitPendingHydrationWarnings(); // 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) { - previousCache = current.memoizedState.cache; + var prevState = current.memoizedState; + + 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. + + upgradeHydrationErrorsToRecoverable(); + } } + } + } + bubbleProperties(workInProgress); - var cache = workInProgress.memoizedState.cache; + return null; + } - if (cache !== previousCache) { - // Run passive effects to retain/release the cache. - workInProgress.flags |= Passive$1; - } + case HostHoistable: - popCacheProvider(workInProgress); - } - popHostContainer(workInProgress); - popTopLevelContextObject(workInProgress); + case HostSingleton: - if (fiberRoot.pendingContext) { - fiberRoot.context = fiberRoot.pendingContext; - fiberRoot.pendingContext = null; - } + case HostComponent: + { + popHostContext(workInProgress); + var _type2 = workInProgress.type; - 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 (current !== null && workInProgress.stateNode != null) { + updateHostComponent(current, workInProgress, _type2, newProps); + } 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 (wasHydrated) { - emitPendingHydrationWarnings(); // 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; - - 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. - - upgradeHydrationErrorsToRecoverable(); - } - } - } + bubbleProperties(workInProgress); + return null; } - bubbleProperties(workInProgress); - - return null; - } - case HostHoistable: + var _currentHostContext = 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. - case HostSingleton: - case HostComponent: { - popHostContext(workInProgress); - var _type2 = workInProgress.type; + var _wasHydrated2 = popHydrationState(); - if (current !== null && workInProgress.stateNode != null) { - updateHostComponent(current, workInProgress, _type2, newProps); + if (_wasHydrated2) { + // TODO: Move this and createInstance step into the beginPhase + // to consolidate. + prepareToHydrateHostInstance(); } 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. - - bubbleProperties(workInProgress); - return null; - } + var _rootContainerInstance = getRootHostContainer(); - var _currentHostContext = 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. + var _instance3 = createInstance(_type2, newProps, _rootContainerInstance, _currentHostContext, workInProgress); // TODO: For persistent renderers, we should pass children as part + // of the initial instance creation - var _wasHydrated2 = popHydrationState(); - if (_wasHydrated2) { - // TODO: Move this and createInstance step into the beginPhase - // to consolidate. - prepareToHydrateHostInstance(); - } else { - var _rootContainerInstance = getRootHostContainer(); - - var _instance3 = createInstance( - _type2, - newProps, - _rootContainerInstance, - _currentHostContext, - workInProgress - ); // TODO: For persistent renderers, we should pass children as part - // of the initial instance creation - - appendAllChildren(_instance3, workInProgress); - workInProgress.stateNode = _instance3; // Certain renderers require commit-time effects for initial mount. - } + appendAllChildren(_instance3, workInProgress); + workInProgress.stateNode = _instance3; // Certain renderers require commit-time effects for initial mount. } - - 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. - - preloadInstanceAndSuspendIfNeeded(workInProgress); - return null; } - case HostText: { - var newText = newProps; + 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. - 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. - - 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. - } + preloadInstanceAndSuspendIfNeeded(workInProgress); + return null; + } - getRootHostContainer(); + case HostText: + { + var newText = newProps; - getHostContext(); + 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. - var _wasHydrated3 = popHydrationState(); + 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. - if (_wasHydrated3) { - prepareToHydrateHostTextInstance(); - } else { - workInProgress.stateNode = createTextInstance(newText); - } } - bubbleProperties(workInProgress); - return null; - } + getRootHostContainer(); - case SuspenseComponent: { - 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. - - if ( - current === null || - (current.memoizedState !== null && - current.memoizedState.dehydrated !== null) - ) { - var fallthroughToNormalSuspensePath = - completeDehydratedSuspenseBoundary( - current, - workInProgress, - nextState - ); - - if (!fallthroughToNormalSuspensePath) { - if (workInProgress.flags & ForceClientRender) { - popSuspenseHandler(workInProgress); // Special case. There were remaining unhydrated nodes. We treat - // this as a mismatch. Revert to client rendering. - - return workInProgress; - } else { - popSuspenseHandler(workInProgress); // Did not finish hydrating, either because this is the initial - // render or because something suspended. + getHostContext(); - return null; - } - } // Continue with the normal Suspense path. + var _wasHydrated3 = popHydrationState(); + + if (_wasHydrated3) { + prepareToHydrateHostTextInstance(); + } else { + workInProgress.stateNode = createTextInstance(newText); } + } - popSuspenseHandler(workInProgress); + bubbleProperties(workInProgress); + return null; + } - if ((workInProgress.flags & DidCapture) !== NoFlags$1) { - // Something suspended. Re-render with the fallback children. - workInProgress.lanes = renderLanes; // Do not reset the effect list. + case SuspenseComponent: + { + 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. - if ((workInProgress.mode & ProfileMode) !== NoMode) { - transferActualDuration(workInProgress); - } // Don't bubble properties in this case. + if (current === null || current.memoizedState !== null && current.memoizedState.dehydrated !== null) { + var fallthroughToNormalSuspensePath = completeDehydratedSuspenseBoundary(current, workInProgress, nextState); - return workInProgress; - } + if (!fallthroughToNormalSuspensePath) { + if (workInProgress.flags & ForceClientRender) { + popSuspenseHandler(workInProgress); // Special case. There were remaining unhydrated nodes. We treat + // this as a mismatch. Revert to client rendering. - var nextDidTimeout = nextState !== null; - var prevDidTimeout = - current !== null && current.memoizedState !== null; + return workInProgress; + } else { + popSuspenseHandler(workInProgress); // Did not finish hydrating, either because this is the initial + // render or because something suspended. - if (nextDidTimeout) { - var offscreenFiber = workInProgress.child; - var _previousCache = null; - - if ( - offscreenFiber.alternate !== null && - offscreenFiber.alternate.memoizedState !== null && - offscreenFiber.alternate.memoizedState.cachePool !== null - ) { - _previousCache = - offscreenFiber.alternate.memoizedState.cachePool.pool; + return null; } + } // Continue with the normal Suspense path. - var _cache = null; + } - if ( - offscreenFiber.memoizedState !== null && - offscreenFiber.memoizedState.cachePool !== null - ) { - _cache = offscreenFiber.memoizedState.cachePool.pool; - } + popSuspenseHandler(workInProgress); - if (_cache !== _previousCache) { - // Run passive effects to retain/release the cache. - offscreenFiber.flags |= Passive$1; - } - } // If the suspended state of the boundary changes, we need to schedule - // a passive effect, which is when we process the transitions - - 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 ((workInProgress.flags & DidCapture) !== NoFlags$1) { + // Something suspended. Re-render with the fallback children. + workInProgress.lanes = renderLanes; // Do not reset the effect list. - if (nextDidTimeout) { - var _offscreenFiber2 = workInProgress.child; - _offscreenFiber2.flags |= Visibility; - } - } + if ((workInProgress.mode & ProfileMode) !== NoMode) { + transferActualDuration(workInProgress); + } // Don't bubble properties in this case. - var retryQueue = workInProgress.updateQueue; - scheduleRetryEffect(workInProgress, retryQueue); - bubbleProperties(workInProgress); + return workInProgress; + } - { - 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[unsafe-arithmetic] Flow doesn't support type casting in combination with the -= operator - workInProgress.treeBaseDuration -= - primaryChildFragment.treeBaseDuration; - } - } - } - } + var nextDidTimeout = nextState !== null; + var prevDidTimeout = current !== null && current.memoizedState !== null; - return null; - } + if (nextDidTimeout) { + var offscreenFiber = workInProgress.child; + var _previousCache = null; - case HostPortal: - popHostContainer(workInProgress); + if (offscreenFiber.alternate !== null && offscreenFiber.alternate.memoizedState !== null && offscreenFiber.alternate.memoizedState.cachePool !== null) { + _previousCache = offscreenFiber.alternate.memoizedState.cachePool.pool; + } - bubbleProperties(workInProgress); - return null; + var _cache = null; - case ContextProvider: - // Pop provider fiber - var context; + if (offscreenFiber.memoizedState !== null && offscreenFiber.memoizedState.cachePool !== null) { + _cache = offscreenFiber.memoizedState.cachePool.pool; + } - { - context = workInProgress.type._context; + if (_cache !== _previousCache) { + // Run passive effects to retain/release the cache. + offscreenFiber.flags |= Passive$1; } + } // If the suspended state of the boundary changes, we need to schedule + // a passive effect, which is when we process the transitions - popProvider(context, workInProgress); - bubbleProperties(workInProgress); - return null; - case IncompleteClassComponent: { - // sequential to ensure this switch is compiled to a jump table. + 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 _Component = workInProgress.type; - if (isContextProvider(_Component)) { - popContext(workInProgress); + if (nextDidTimeout) { + var _offscreenFiber2 = workInProgress.child; + _offscreenFiber2.flags |= Visibility; } - - bubbleProperties(workInProgress); - return null; } - case SuspenseListComponent: { - popSuspenseListContext(workInProgress); - var renderState = workInProgress.memoizedState; - - if (renderState === null) { - // We're running in the default, "independent" mode. - // We don't do anything in this mode. - bubbleProperties(workInProgress); - return null; - } + var retryQueue = workInProgress.updateQueue; + scheduleRetryEffect(workInProgress, retryQueue); - var didSuspendAlready = - (workInProgress.flags & DidCapture) !== NoFlags$1; - var renderedTail = renderState.rendering; - - 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 (!cannotBeSuspended) { - var row = workInProgress.child; - - while (row !== null) { - var suspended = findFirstSuspended(row); - - 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. - - 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; - } + bubbleProperties(workInProgress); - row = row.sibling; - } - } + { + 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 ( - 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. - - 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 _retryQueue2 = _suspended.updateQueue; - workInProgress.updateQueue = _retryQueue2; - scheduleRetryEffect(workInProgress, _retryQueue2); - cutOffTailIfNeeded(renderState, true); // This might have been modified. - - 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. - - workInProgress.lanes = SomeRetryLane; + if (primaryChildFragment !== null) { + // $FlowFixMe[unsafe-arithmetic] Flow doesn't support type casting in combination with the -= operator + workInProgress.treeBaseDuration -= primaryChildFragment.treeBaseDuration; } } + } + } - 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; + return null; + } - if (previousSibling !== null) { - previousSibling.sibling = renderedTail; - } else { - workInProgress.child = renderedTail; - } + case HostPortal: + popHostContainer(workInProgress); - renderState.last = renderedTail; - } - } + bubbleProperties(workInProgress); + return null; - 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. - - var suspenseContext = suspenseStackCursor.current; - - if (didSuspendAlready) { - suspenseContext = setShallowSuspenseListContext( - suspenseContext, - ForceSuspenseFallback - ); - } else { - suspenseContext = - setDefaultShallowSuspenseListContext(suspenseContext); - } + case ContextProvider: + // Pop provider fiber + var context; - pushSuspenseListContext(workInProgress, suspenseContext); // Do a pass over the next row. - // Don't bubble properties in this case. + { + context = workInProgress.type._context; + } - return next; - } + popProvider(context, workInProgress); + bubbleProperties(workInProgress); + return null; - bubbleProperties(workInProgress); - return null; - } + case IncompleteClassComponent: + { + // sequential to ensure this switch is compiled to a jump table. - case ScopeComponent: { - break; + + var _Component = workInProgress.type; + + if (isContextProvider(_Component)) { + popContext(workInProgress); } - 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 + bubbleProperties(workInProgress); + return null; + } - { - if (current !== null) { - var _prevState = current.memoizedState; - var prevIsHidden = _prevState !== null; + case SuspenseListComponent: + { + popSuspenseListContext(workInProgress); + var renderState = workInProgress.memoizedState; - 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 (renderState === null) { + // We're running in the default, "independent" mode. + // We don't do anything in this mode. + bubbleProperties(workInProgress); + return null; + } + + var didSuspendAlready = (workInProgress.flags & DidCapture) !== NoFlags$1; + var renderedTail = renderState.rendering; + + 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 (!cannotBeSuspended) { + var row = workInProgress.child; + + while (row !== null) { + var suspended = findFirstSuspended(row); + + 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. + + 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; } } - } - 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.subtreeFlags & (Placement | Update)) { - workInProgress.flags |= Visibility; - } + 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. + + workInProgress.lanes = SomeRetryLane; } - } + } else { + cutOffTailIfNeeded(renderState, false); + } // Next we're going to render the tail. - var offscreenQueue = workInProgress.updateQueue; + } else { + // Append the rendered row to the child list. + if (!didSuspendAlready) { + var _suspended = findFirstSuspended(renderedTail); - if (offscreenQueue !== null) { - var _retryQueue3 = offscreenQueue.retryQueue; - scheduleRetryEffect(workInProgress, _retryQueue3); - } + 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 _previousCache2 = null; - - if ( - current !== null && - current.memoizedState !== null && - current.memoizedState.cachePool !== null - ) { - _previousCache2 = current.memoizedState.cachePool.pool; + var _retryQueue2 = _suspended.updateQueue; + workInProgress.updateQueue = _retryQueue2; + scheduleRetryEffect(workInProgress, _retryQueue2); + cutOffTailIfNeeded(renderState, true); // This might have been modified. + + 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. + + workInProgress.lanes = SomeRetryLane; } + } - var _cache2 = null; + 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; - if ( - workInProgress.memoizedState !== null && - workInProgress.memoizedState.cachePool !== null - ) { - _cache2 = workInProgress.memoizedState.cachePool.pool; + if (previousSibling !== null) { + previousSibling.sibling = renderedTail; + } else { + workInProgress.child = renderedTail; } - if (_cache2 !== _previousCache2) { - // Run passive effects to retain/release the cache. - workInProgress.flags |= Passive$1; - } + renderState.last = renderedTail; } - - popTransition(workInProgress, current); - return null; } - case CacheComponent: { - { - var _previousCache3 = null; - - if (current !== null) { - _previousCache3 = current.memoizedState.cache; - } - - var _cache3 = workInProgress.memoizedState.cache; + 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 (_cache3 !== _previousCache3) { - // Run passive effects to retain/release the cache. - workInProgress.flags |= Passive$1; - } + var suspenseContext = suspenseStackCursor.current; - popCacheProvider(workInProgress); - bubbleProperties(workInProgress); + if (didSuspendAlready) { + suspenseContext = setShallowSuspenseListContext(suspenseContext, ForceSuspenseFallback); + } else { + suspenseContext = setDefaultShallowSuspenseListContext(suspenseContext); } - return null; - } + pushSuspenseListContext(workInProgress, suspenseContext); // Do a pass over the next row. + // Don't bubble properties in this case. - case TracingMarkerComponent: { - return null; + return next; } - } - throw new Error( - "Unknown unit of work tag (" + - workInProgress.tag + - "). This error is likely caused by a bug in " + - "React. Please file an issue." - ); - } + bubbleProperties(workInProgress); + return null; + } - function unwindWork(current, workInProgress, renderLanes) { - switch (workInProgress.tag) { - case ClassComponent: { - var Component = workInProgress.type; + case ScopeComponent: + { - if (isContextProvider(Component)) { - popContext(workInProgress); - } + break; + } - var flags = workInProgress.flags; + 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 (flags & ShouldCapture) { - workInProgress.flags = (flags & ~ShouldCapture) | DidCapture; + { + if (current !== null) { + var _prevState = current.memoizedState; + var prevIsHidden = _prevState !== null; - if ((workInProgress.mode & ProfileMode) !== NoMode) { - transferActualDuration(workInProgress); + 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; } - - return workInProgress; } - - return null; } - case HostRoot: { - { - popCacheProvider(workInProgress); + 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.subtreeFlags & (Placement | Update)) { + workInProgress.flags |= Visibility; + } } - popHostContainer(workInProgress); - popTopLevelContextObject(workInProgress); - 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. - - return null; } - case HostHoistable: - case HostSingleton: - case HostComponent: { - // TODO: popHydrationState - popHostContext(workInProgress); - return null; + var offscreenQueue = workInProgress.updateQueue; + + if (offscreenQueue !== null) { + var _retryQueue3 = offscreenQueue.retryQueue; + scheduleRetryEffect(workInProgress, _retryQueue3); } - case SuspenseComponent: { - popSuspenseHandler(workInProgress); - var suspenseState = workInProgress.memoizedState; + { + var _previousCache2 = null; - 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 (current !== null && current.memoizedState !== null && current.memoizedState.cachePool !== null) { + _previousCache2 = current.memoizedState.cachePool.pool; } - var _flags2 = workInProgress.flags; + var _cache2 = null; - if (_flags2 & ShouldCapture) { - workInProgress.flags = (_flags2 & ~ShouldCapture) | DidCapture; // Captured a suspense effect. Re-render the boundary. - - if ((workInProgress.mode & ProfileMode) !== NoMode) { - transferActualDuration(workInProgress); - } - - return workInProgress; + if (workInProgress.memoizedState !== null && workInProgress.memoizedState.cachePool !== null) { + _cache2 = workInProgress.memoizedState.cachePool.pool; } - return null; + if (_cache2 !== _previousCache2) { + // Run passive effects to retain/release the cache. + workInProgress.flags |= Passive$1; + } } - 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. + popTransition(workInProgress, current); + return null; + } - return null; - } + case CacheComponent: + { + { + var _previousCache3 = null; - case HostPortal: - popHostContainer(workInProgress); - return null; + if (current !== null) { + _previousCache3 = current.memoizedState.cache; + } - case ContextProvider: - var context; + var _cache3 = workInProgress.memoizedState.cache; - { - context = workInProgress.type._context; + if (_cache3 !== _previousCache3) { + // Run passive effects to retain/release the cache. + workInProgress.flags |= Passive$1; } - popProvider(context, workInProgress); - return null; - - case OffscreenComponent: - case LegacyHiddenComponent: { - popSuspenseHandler(workInProgress); - popHiddenContext(workInProgress); - popTransition(workInProgress, current); - var _flags3 = workInProgress.flags; + popCacheProvider(workInProgress); + bubbleProperties(workInProgress); + } - if (_flags3 & ShouldCapture) { - workInProgress.flags = (_flags3 & ~ShouldCapture) | DidCapture; // Captured a suspense effect. Re-render the boundary. + return null; + } - if ((workInProgress.mode & ProfileMode) !== NoMode) { - transferActualDuration(workInProgress); - } + case TracingMarkerComponent: + { - return workInProgress; - } + return null; + } + } - 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.'); +} - case CacheComponent: - { - popCacheProvider(workInProgress); - } +function unwindWork(current, workInProgress, renderLanes) { - return null; + switch (workInProgress.tag) { + case ClassComponent: + { + var Component = workInProgress.type; - case TracingMarkerComponent: - return null; + if (isContextProvider(Component)) { + popContext(workInProgress); + } - default: - return null; - } - } + var flags = workInProgress.flags; - function unwindInterruptedWork(current, interruptedWork, renderLanes) { - switch (interruptedWork.tag) { - case ClassComponent: { - var childContextTypes = interruptedWork.type.childContextTypes; + if (flags & ShouldCapture) { + workInProgress.flags = flags & ~ShouldCapture | DidCapture; - if (childContextTypes !== null && childContextTypes !== undefined) { - popContext(interruptedWork); + if ((workInProgress.mode & ProfileMode) !== NoMode) { + transferActualDuration(workInProgress); } - break; + return workInProgress; } - case HostRoot: { - { - popCacheProvider(interruptedWork); - } - popHostContainer(interruptedWork); - popTopLevelContextObject(interruptedWork); - break; - } + return null; + } - case HostHoistable: - case HostSingleton: - case HostComponent: { - popHostContext(interruptedWork); - break; + case HostRoot: + { + + { + popCacheProvider(workInProgress); } + popHostContainer(workInProgress); + popTopLevelContextObject(workInProgress); + var _flags = workInProgress.flags; - case HostPortal: - popHostContainer(interruptedWork); - break; + 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. - case SuspenseComponent: - popSuspenseHandler(interruptedWork); - break; - case SuspenseListComponent: - popSuspenseListContext(interruptedWork); - break; + return null; + } + + case HostHoistable: + case HostSingleton: + case HostComponent: + { + // TODO: popHydrationState + popHostContext(workInProgress); + return null; + } - case ContextProvider: - var context; + case SuspenseComponent: + { + popSuspenseHandler(workInProgress); + var suspenseState = workInProgress.memoizedState; - { - context = interruptedWork.type._context; + 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.'); } + } - popProvider(context, interruptedWork); - break; + var _flags2 = workInProgress.flags; - case OffscreenComponent: - case LegacyHiddenComponent: - popSuspenseHandler(interruptedWork); - popHiddenContext(interruptedWork); - popTransition(interruptedWork, current); - break; + if (_flags2 & ShouldCapture) { + workInProgress.flags = _flags2 & ~ShouldCapture | DidCapture; // Captured a suspense effect. Re-render the boundary. - case CacheComponent: - { - popCacheProvider(interruptedWork); + if ((workInProgress.mode & ProfileMode) !== NoMode) { + transferActualDuration(workInProgress); } - break; + return workInProgress; + } + + return null; } - } - var didWarnAboutUndefinedSnapshotBeforeUpdate = 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. - { - 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; // Used to track if a form needs to be reset at the end of the mutation phase. - var PossiblyWeakSet = typeof WeakSet === "function" ? WeakSet : Set; - var nextEffect = null; // Used for Profiling builds to track updaters. - - function shouldProfile(current) { - return ( - (current.mode & ProfileMode) !== NoMode && - (getExecutionContext() & CommitContext) !== NoContext - ); - } - - function callComponentWillUnmountWithTimer(current, instance) { - instance.props = resolveClassComponentProps( - current.type, - current.memoizedProps, - current.elementType === current.type - ); - instance.state = current.memoizedState; - - if (shouldProfile(current)) { - try { - startLayoutEffectTimer(); - instance.componentWillUnmount(); - } finally { - recordLayoutEffectDuration(current); - } - } else { - instance.componentWillUnmount(); + return null; } - } // 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 HostPortal: + popHostContainer(workInProgress); + return null; - function safelyAttachRef(current, nearestMountedAncestor) { - try { - commitAttachRef(current); - } catch (error) { - captureCommitPhaseError(current, nearestMountedAncestor, error); + case ContextProvider: + var context; + + { + context = workInProgress.type._context; } - } - function safelyDetachRef(current, nearestMountedAncestor) { - var ref = current.ref; - var refCleanup = current.refCleanup; + popProvider(context, workInProgress); + return null; - if (ref !== null) { - 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; + case OffscreenComponent: + case LegacyHiddenComponent: + { + popSuspenseHandler(workInProgress); + popHiddenContext(workInProgress); + popTransition(workInProgress, current); + var _flags3 = workInProgress.flags; - if (finishedWork != null) { - finishedWork.refCleanup = null; - } - } - } else if (typeof ref === "function") { - var retVal; + if (_flags3 & ShouldCapture) { + workInProgress.flags = _flags3 & ~ShouldCapture | DidCapture; // Captured a suspense effect. Re-render the boundary. - try { - if (shouldProfile(current)) { - try { - startLayoutEffectTimer(); - retVal = ref(null); - } finally { - recordLayoutEffectDuration(current); - } - } else { - retVal = ref(null); - } - } catch (error) { - captureCommitPhaseError(current, nearestMountedAncestor, error); + if ((workInProgress.mode & ProfileMode) !== NoMode) { + transferActualDuration(workInProgress); } - { - 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[incompatible-use] unable to narrow type to RefObject - ref.current = null; + return workInProgress; } + + return null; } - } - function safelyCallDestroy(current, nearestMountedAncestor, destroy) { - try { - destroy(); - } catch (error) { - captureCommitPhaseError(current, nearestMountedAncestor, error); + case CacheComponent: + { + popCacheProvider(workInProgress); } - } - var shouldFireAfterActiveInstanceBlur = false; - function commitBeforeMutationEffects(root, firstChild) { - nextEffect = firstChild; - commitBeforeMutationEffects_begin(); // We no longer need to track the active instance fiber - var shouldFire = shouldFireAfterActiveInstanceBlur; - shouldFireAfterActiveInstanceBlur = false; - return shouldFire; - } + return null; - function commitBeforeMutationEffects_begin() { - while (nextEffect !== null) { - var fiber = nextEffect; // This phase is only used for beforeActiveInstanceBlur. + case TracingMarkerComponent: - var child = fiber.child; + return null; - if ( - (fiber.subtreeFlags & BeforeMutationMask) !== NoFlags$1 && - child !== null - ) { - child.return = fiber; - nextEffect = child; - } else { - commitBeforeMutationEffects_complete(); - } - } - } + default: + return null; + } +} - function commitBeforeMutationEffects_complete() { - while (nextEffect !== null) { - var fiber = nextEffect; - setCurrentFiber(fiber); +function unwindInterruptedWork(current, interruptedWork, renderLanes) { - try { - commitBeforeMutationEffectsOnFiber(fiber); - } catch (error) { - captureCommitPhaseError(fiber, fiber.return, error); + switch (interruptedWork.tag) { + case ClassComponent: + { + var childContextTypes = interruptedWork.type.childContextTypes; + + if (childContextTypes !== null && childContextTypes !== undefined) { + popContext(interruptedWork); } - resetCurrentFiber(); - var sibling = fiber.sibling; + break; + } - if (sibling !== null) { - sibling.return = fiber.return; - nextEffect = sibling; - return; + case HostRoot: + { + + { + popCacheProvider(interruptedWork); } + popHostContainer(interruptedWork); + popTopLevelContextObject(interruptedWork); + break; + } - nextEffect = fiber.return; + case HostHoistable: + case HostSingleton: + case HostComponent: + { + popHostContext(interruptedWork); + break; } - } - function commitBeforeMutationEffectsOnFiber(finishedWork) { - var current = finishedWork.alternate; - var flags = finishedWork.flags; + case HostPortal: + popHostContainer(interruptedWork); + break; + + case SuspenseComponent: + popSuspenseHandler(interruptedWork); + break; + + case SuspenseListComponent: + popSuspenseListContext(interruptedWork); + break; - if ((flags & Snapshot) !== NoFlags$1) { - setCurrentFiber(finishedWork); + case ContextProvider: + var context; + + { + context = interruptedWork.type._context; } - switch (finishedWork.tag) { - case FunctionComponent: { - break; - } + popProvider(context, interruptedWork); + break; - case ForwardRef: - case SimpleMemoComponent: { - break; - } + case OffscreenComponent: + case LegacyHiddenComponent: + popSuspenseHandler(interruptedWork); + popHiddenContext(interruptedWork); + popTransition(interruptedWork, current); + break; - 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 CacheComponent: + { + popCacheProvider(interruptedWork); + } - { - if ( - !finishedWork.type.defaultProps && - !("ref" in finishedWork.memoizedProps) && - !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" - ); - } + break; + } +} - 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" - ); - } - } - } +var didWarnAboutUndefinedSnapshotBeforeUpdate = null; - var snapshot = instance.getSnapshotBeforeUpdate( - resolveClassComponentProps( - finishedWork.type, - prevProps, - finishedWork.elementType === finishedWork.type - ), - prevState - ); +{ + 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 didWarnSet = didWarnAboutUndefinedSnapshotBeforeUpdate; - - 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; - } - } +var offscreenSubtreeIsHidden = false; +var offscreenSubtreeWasHidden = false; // Used to track if a form needs to be reset at the end of the mutation phase. +var PossiblyWeakSet = typeof WeakSet === 'function' ? WeakSet : Set; +var nextEffect = null; // Used for Profiling builds to track updaters. - break; - } +function shouldProfile(current) { + return (current.mode & ProfileMode) !== NoMode && (getExecutionContext() & CommitContext) !== NoContext; +} - case HostRoot: { - if ((flags & Snapshot) !== NoFlags$1) { - { - var root = finishedWork.stateNode; - clearContainer(root.containerInfo); - } - } +function callComponentWillUnmountWithTimer(current, instance) { + instance.props = resolveClassComponentProps(current.type, current.memoizedProps, current.elementType === current.type); + instance.state = current.memoizedState; + + if (shouldProfile(current)) { + try { + startLayoutEffectTimer(); + instance.componentWillUnmount(); + } finally { + recordLayoutEffectDuration(current); + } + } 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. + + +function safelyAttachRef(current, nearestMountedAncestor) { + try { + commitAttachRef(current); + } catch (error) { + captureCommitPhaseError(current, nearestMountedAncestor, error); + } +} - break; +function safelyDetachRef(current, nearestMountedAncestor) { + var ref = current.ref; + var refCleanup = current.refCleanup; + + if (ref !== null) { + 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; - case HostComponent: - case HostHoistable: - case HostSingleton: - case HostText: - case HostPortal: - case IncompleteClassComponent: - // Nothing to do for these component types - break; + if (finishedWork != null) { + finishedWork.refCleanup = null; + } + } + } else if (typeof ref === 'function') { + var retVal; - 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." - ); + try { + if (shouldProfile(current)) { + try { + startLayoutEffectTimer(); + retVal = ref(null); + } finally { + recordLayoutEffectDuration(current); } + } else { + retVal = ref(null); } + } catch (error) { + captureCommitPhaseError(current, nearestMountedAncestor, error); } - if ((flags & Snapshot) !== NoFlags$1) { - resetCurrentFiber(); + { + 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[incompatible-use] unable to narrow type to RefObject + ref.current = null; } + } +} - function commitHookEffectListUnmount( - flags, - finishedWork, - nearestMountedAncestor - ) { - var updateQueue = finishedWork.updateQueue; - var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null; - - if (lastEffect !== null) { - var firstEffect = lastEffect.next; - var effect = firstEffect; - - do { - if ((effect.tag & flags) === flags) { - // Unmount - var inst = effect.inst; - var destroy = inst.destroy; - - if (destroy !== undefined) { - inst.destroy = undefined; - - { - if ((flags & Passive) !== NoFlags) { - markComponentPassiveEffectUnmountStarted(finishedWork); - } else if ((flags & Layout) !== NoFlags) { - markComponentLayoutEffectUnmountStarted(finishedWork); - } - } +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 + + var shouldFire = shouldFireAfterActiveInstanceBlur; + shouldFireAfterActiveInstanceBlur = false; + return shouldFire; +} - { - if ((flags & Insertion) !== NoFlags) { - setIsRunningInsertionEffect(true); - } - } +function commitBeforeMutationEffects_begin() { + while (nextEffect !== null) { + var fiber = nextEffect; // This phase is only used for beforeActiveInstanceBlur. - safelyCallDestroy(finishedWork, nearestMountedAncestor, destroy); + var child = fiber.child; - { - if ((flags & Insertion) !== NoFlags) { - setIsRunningInsertionEffect(false); - } - } + if ((fiber.subtreeFlags & BeforeMutationMask) !== NoFlags$1 && child !== null) { + child.return = fiber; + nextEffect = child; + } else { + commitBeforeMutationEffects_complete(); + } + } +} - { - if ((flags & Passive) !== NoFlags) { - markComponentPassiveEffectUnmountStopped(); - } else if ((flags & Layout) !== NoFlags) { - markComponentLayoutEffectUnmountStopped(); - } - } - } - } +function commitBeforeMutationEffects_complete() { + while (nextEffect !== null) { + var fiber = nextEffect; + setCurrentFiber(fiber); - effect = effect.next; - } while (effect !== firstEffect); - } + try { + commitBeforeMutationEffectsOnFiber(fiber); + } catch (error) { + captureCommitPhaseError(fiber, fiber.return, error); } - function commitHookEffectListMount(flags, finishedWork) { - var updateQueue = finishedWork.updateQueue; - var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null; + resetCurrentFiber(); + var sibling = fiber.sibling; - if (lastEffect !== null) { - var firstEffect = lastEffect.next; - var effect = firstEffect; + if (sibling !== null) { + sibling.return = fiber.return; + nextEffect = sibling; + return; + } - do { - if ((effect.tag & flags) === flags) { - { - if ((flags & Passive) !== NoFlags) { - markComponentPassiveEffectMountStarted(finishedWork); - } else if ((flags & Layout) !== NoFlags) { - markComponentLayoutEffectMountStarted(finishedWork); - } - } // Mount + nextEffect = fiber.return; + } +} - var create = effect.create; +function commitBeforeMutationEffectsOnFiber(finishedWork) { + var current = finishedWork.alternate; + var flags = finishedWork.flags; - { - if ((flags & Insertion) !== NoFlags) { - setIsRunningInsertionEffect(true); - } - } + if ((flags & Snapshot) !== NoFlags$1) { + setCurrentFiber(finishedWork); + } - var inst = effect.inst; - var destroy = create(); - inst.destroy = destroy; + switch (finishedWork.tag) { + case FunctionComponent: + { - { - if ((flags & Insertion) !== NoFlags) { - setIsRunningInsertionEffect(false); - } - } + break; + } - { - if ((flags & Passive) !== NoFlags) { - markComponentPassiveEffectMountStopped(); - } else if ((flags & Layout) !== NoFlags) { - markComponentLayoutEffectMountStopped(); - } - } + case ForwardRef: + case SimpleMemoComponent: + { + break; + } - { - if (destroy !== undefined && typeof destroy !== "function") { - var hookName = void 0; + 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 ((effect.tag & Layout) !== NoFlags$1) { - hookName = "useLayoutEffect"; - } else if ((effect.tag & Insertion) !== NoFlags$1) { - hookName = "useInsertionEffect"; - } else { - hookName = "useEffect"; + { + if (!finishedWork.type.defaultProps && !('ref' in finishedWork.memoizedProps) && !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'); } - var addendum = void 0; - - 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://react.dev/link/hooks-data-fetching"; - } else { - addendum = " You returned: " + destroy; + 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'); } - - error( - "%s must not return anything besides a function, " + - "which is used for clean-up.%s", - hookName, - addendum - ); } } - } - effect = effect.next; - } while (effect !== firstEffect); - } - } + var snapshot = instance.getSnapshotBeforeUpdate(resolveClassComponentProps(finishedWork.type, prevProps, finishedWork.elementType === finishedWork.type), prevState); - 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. + { + var didWarnSet = didWarnAboutUndefinedSnapshotBeforeUpdate; - var commitTime = getCommitTime(); - var phase = finishedWork.alternate === null ? "mount" : "update"; + if (snapshot === undefined && !didWarnSet.has(finishedWork.type)) { + didWarnSet.add(finishedWork.type); - { - if (isCurrentUpdateNested()) { - phase = "nested-update"; - } + error('%s.getSnapshotBeforeUpdate(): A snapshot value (or null) ' + 'must be returned. You have returned undefined.', getComponentNameFromFiber(finishedWork)); } + } - 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; - } + instance.__reactInternalSnapshotBeforeUpdate = snapshot; + } + } - parentFiber = parentFiber.return; - } + break; + } - break; - } + case HostRoot: + { + if ((flags & Snapshot) !== NoFlags$1) { + { + var root = finishedWork.stateNode; + clearContainer(root.containerInfo); } } + + break; } - } - 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); - } + case HostComponent: + case HostHoistable: + case HostSingleton: + case HostText: + case HostPortal: + case IncompleteClassComponent: + // Nothing to do for these component types + break; - recordLayoutEffectDuration(finishedWork); - } else { - try { - commitHookEffectListMount(hookFlags, finishedWork); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); + 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.'); } } - } + } - function commitClassLayoutLifecycles(finishedWork, current) { - var instance = finishedWork.stateNode; + if ((flags & Snapshot) !== NoFlags$1) { + resetCurrentFiber(); + } +} - 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.defaultProps && - !("ref" in finishedWork.memoizedProps) && - !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" - ); - } +function commitHookEffectListUnmount(flags, finishedWork, nearestMountedAncestor) { + var updateQueue = finishedWork.updateQueue; + var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null; + + if (lastEffect !== null) { + var firstEffect = lastEffect.next; + var effect = firstEffect; + + do { + if ((effect.tag & flags) === flags) { + // Unmount + var inst = effect.inst; + var destroy = inst.destroy; + + if (destroy !== undefined) { + inst.destroy = undefined; - 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" - ); + { + if ((flags & Passive) !== NoFlags) { + markComponentPassiveEffectUnmountStarted(finishedWork); + } else if ((flags & Layout) !== NoFlags) { + markComponentLayoutEffectUnmountStarted(finishedWork); } } - } - if (shouldProfile(finishedWork)) { - try { - startLayoutEffectTimer(); - instance.componentDidMount(); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); + { + if ((flags & Insertion) !== NoFlags) { + setIsRunningInsertionEffect(true); + } } - recordLayoutEffectDuration(finishedWork); - } else { - try { - instance.componentDidMount(); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } - } - } else { - var prevProps = resolveClassComponentProps( - finishedWork.type, - current.memoizedProps, - finishedWork.elementType === finishedWork.type - ); - 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. + safelyCallDestroy(finishedWork, nearestMountedAncestor, destroy); - { - if ( - !finishedWork.type.defaultProps && - !("ref" in finishedWork.memoizedProps) && - !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 & Insertion) !== NoFlags) { + setIsRunningInsertionEffect(false); } + } - 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" - ); + { + if ((flags & Passive) !== NoFlags) { + markComponentPassiveEffectUnmountStopped(); + } else if ((flags & Layout) !== NoFlags) { + markComponentLayoutEffectUnmountStopped(); } } } + } - if (shouldProfile(finishedWork)) { - try { - startLayoutEffectTimer(); - instance.componentDidUpdate( - prevProps, - prevState, - instance.__reactInternalSnapshotBeforeUpdate - ); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); + effect = effect.next; + } while (effect !== firstEffect); + } +} + +function commitHookEffectListMount(flags, finishedWork) { + var updateQueue = finishedWork.updateQueue; + var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null; + + if (lastEffect !== null) { + var firstEffect = lastEffect.next; + var effect = firstEffect; + + do { + if ((effect.tag & flags) === flags) { + { + if ((flags & Passive) !== NoFlags) { + markComponentPassiveEffectMountStarted(finishedWork); + } else if ((flags & Layout) !== NoFlags) { + markComponentLayoutEffectMountStarted(finishedWork); } + } // Mount - recordLayoutEffectDuration(finishedWork); - } else { - try { - instance.componentDidUpdate( - prevProps, - prevState, - instance.__reactInternalSnapshotBeforeUpdate - ); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); + + var create = effect.create; + + { + if ((flags & Insertion) !== NoFlags) { + setIsRunningInsertionEffect(true); } } - } - } - 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; + var inst = effect.inst; + var destroy = create(); + inst.destroy = destroy; - if (updateQueue !== null) { - var instance = finishedWork.stateNode; + { + if ((flags & Insertion) !== NoFlags) { + setIsRunningInsertionEffect(false); + } + } + + { + if ((flags & Passive) !== NoFlags) { + markComponentPassiveEffectMountStopped(); + } else if ((flags & Layout) !== NoFlags) { + markComponentLayoutEffectMountStopped(); + } + } { - if ( - !finishedWork.type.defaultProps && - !("ref" in finishedWork.memoizedProps) && - !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 (destroy !== undefined && typeof destroy !== 'function') { + var hookName = void 0; + + if ((effect.tag & Layout) !== NoFlags$1) { + hookName = 'useLayoutEffect'; + } else if ((effect.tag & Insertion) !== NoFlags$1) { + hookName = 'useInsertionEffect'; + } else { + hookName = 'useEffect'; } - 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" - ); + var addendum = void 0; + + 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://react.dev/link/hooks-data-fetching'; + } else { + addendum = ' You returned: ' + destroy; } - } - } // 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); + error('%s must not return anything besides a function, ' + 'which is used for clean-up.%s', hookName, addendum); + } } } - } - function commitHostComponentMount(finishedWork) { - var type = finishedWork.type; - var props = finishedWork.memoizedProps; - var instance = finishedWork.stateNode; + effect = effect.next; + } while (effect !== firstEffect); + } +} - try { - commitMount(instance, type, props, finishedWork); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } - } +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. - 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"; + var commitTime = getCommitTime(); + var phase = finishedWork.alternate === null ? 'mount' : 'update'; + + { + if (isCurrentUpdateNested()) { + phase = 'nested-update'; + } } - } - if (typeof onRender === "function") { - onRender( - finishedWork.memoizedProps.id, - phase, - finishedWork.actualDuration, - finishedWork.treeBaseDuration, - finishedWork.actualStartTime, - commitTime - ); - } + 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. - 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. - - 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. var parentFiber = finishedWork.return; @@ -19618,4331 +16512,4042 @@ if (__DEV__) { switch (parentFiber.tag) { case HostRoot: var root = parentFiber.stateNode; - root.effectDuration += effectDuration; + root.passiveEffectDuration += passiveEffectDuration; break outer; case Profiler: var parentStateNode = parentFiber.stateNode; - parentStateNode.effectDuration += effectDuration; + parentStateNode.passiveEffectDuration += passiveEffectDuration; break outer; } parentFiber = parentFiber.return; } + + break; } - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); + } + } + } +} + +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); + } + } +} + +function commitClassLayoutLifecycles(finishedWork, current) { + var instance = finishedWork.stateNode; + + 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.defaultProps && !('ref' in finishedWork.memoizedProps) && !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 (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'); } } } - 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; + if (shouldProfile(finishedWork)) { + try { + startLayoutEffectTimer(); + instance.componentDidMount(); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } - switch (finishedWork.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); + recordLayoutEffectDuration(finishedWork); + } else { + try { + instance.componentDidMount(); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } + } + } else { + var prevProps = resolveClassComponentProps(finishedWork.type, current.memoizedProps, finishedWork.elementType === finishedWork.type); + 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 (flags & Update) { - commitHookLayoutEffects(finishedWork, Layout | HasEffect); - } + { + if (!finishedWork.type.defaultProps && !('ref' in finishedWork.memoizedProps) && !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'); + } - 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 ClassComponent: { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); + if (shouldProfile(finishedWork)) { + try { + startLayoutEffectTimer(); + instance.componentDidUpdate(prevProps, prevState, instance.__reactInternalSnapshotBeforeUpdate); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } - if (flags & Update) { - commitClassLayoutLifecycles(finishedWork, current); - } + recordLayoutEffectDuration(finishedWork); + } else { + try { + instance.componentDidUpdate(prevProps, prevState, instance.__reactInternalSnapshotBeforeUpdate); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } + } + } +} - if (flags & Callback) { - commitClassCallbacks(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 & Ref) { - safelyAttachRef(finishedWork, finishedWork.return); - } + if (updateQueue !== null) { + var instance = finishedWork.stateNode; - break; + { + if (!finishedWork.type.defaultProps && !('ref' in finishedWork.memoizedProps) && !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'); } - case HostRoot: { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); + 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. - 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; + try { + commitCallbacks(updateQueue, instance); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } + } +} - if (finishedWork.child !== null) { - switch (finishedWork.child.tag) { - case HostSingleton: - case HostComponent: - instance = getPublicInstance(finishedWork.child.stateNode); - break; +function commitHostComponentMount(finishedWork) { + var type = finishedWork.type; + var props = finishedWork.memoizedProps; + var instance = finishedWork.stateNode; - case ClassComponent: - instance = finishedWork.child.stateNode; - break; - } - } + try { + commitMount(instance, type, props, finishedWork); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } +} - try { - commitCallbacks(updateQueue, instance); - } 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'; - break; + if (enableProfilerNestedUpdatePhase) { + if (isCurrentUpdateNested()) { + phase = 'nested-update'; } + } - case HostHoistable: + if (typeof onRender === 'function') { + onRender(finishedWork.memoizedProps.id, phase, finishedWork.actualDuration, finishedWork.treeBaseDuration, finishedWork.actualStartTime, commitTime); + } - 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 (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 (flags & Ref) { - safelyAttachRef(finishedWork, finishedWork.return); + + 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. + + var parentFiber = finishedWork.return; + + 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; } - break; + parentFiber = parentFiber.return; } + } + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } + } +} - 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. +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; - if (flags & Update) { - commitProfilerUpdate(finishedWork, current); - } + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: + { + recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); - break; + if (flags & Update) { + commitHookLayoutEffects(finishedWork, Layout | HasEffect); } - case SuspenseComponent: { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); + break; + } - break; + case ClassComponent: + { + recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); + + if (flags & Update) { + commitClassLayoutLifecycles(finishedWork, current); + } + + if (flags & Callback) { + commitClassCallbacks(finishedWork); + } + + if (flags & Ref) { + safelyAttachRef(finishedWork, finishedWork.return); } - case OffscreenComponent: { - var isModernRoot = (finishedWork.mode & ConcurrentMode) !== NoMode; - - if (isModernRoot) { - var isHidden = finishedWork.memoizedState !== null; - var newOffscreenSubtreeIsHidden = - isHidden || offscreenSubtreeIsHidden; - - 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 (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); + 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; } + } - offscreenSubtreeIsHidden = prevOffscreenSubtreeIsHidden; - offscreenSubtreeWasHidden = prevOffscreenSubtreeWasHidden; + try { + commitCallbacks(updateQueue, instance); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); } - } else { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); } + } - if (flags & Ref) { - var props = finishedWork.memoizedProps; + break; + } - if (props.mode === "manual") { - safelyAttachRef(finishedWork, finishedWork.return); - } else { - safelyDetachRef(finishedWork, finishedWork.return); - } - } + case HostHoistable: - break; + 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); } - default: { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); - break; + if (flags & Ref) { + safelyAttachRef(finishedWork, finishedWork.return); } - } - } - function hideOrUnhideAllChildren(finishedWork, isHidden) { - // Only hide or unhide the top-most host nodes. - var hostSubtreeRoot = null; + break; + } + case Profiler: { - // We only have the top Fiber that was inserted but we need to recurse down its - // children to find all the terminal nodes. - var node = finishedWork; + recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); // TODO: Should this fire inside an offscreen tree? Or should it wait to + // fire when the tree becomes visible again. - while (true) { - if (node.tag === HostComponent || false || false) { - if (hostSubtreeRoot === null) { - hostSubtreeRoot = node; + if (flags & Update) { + commitProfilerUpdate(finishedWork, current); + } - try { - var instance = node.stateNode; + break; + } - if (isHidden) { - hideInstance(instance); - } else { - unhideInstance(node.stateNode, node.memoizedProps); - } - } catch (error) { - captureCommitPhaseError( - finishedWork, - finishedWork.return, - error - ); - } - } - } else if (node.tag === HostText) { - if (hostSubtreeRoot === null) { - try { - var _instance = node.stateNode; + case SuspenseComponent: + { + recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); - if (isHidden) { - hideTextInstance(_instance); - } else { - unhideTextInstance(_instance, node.memoizedProps); - } - } catch (error) { - captureCommitPhaseError( - finishedWork, - finishedWork.return, - error - ); - } - } - } else if ( - (node.tag === OffscreenComponent || - node.tag === LegacyHiddenComponent) && - node.memoizedState !== null && - node !== finishedWork - ); - else if (node.child !== null) { - node.child.return = node; - node = node.child; - continue; - } + break; + } - if (node === finishedWork) { - return; - } + case OffscreenComponent: + { + var isModernRoot = (finishedWork.mode & ConcurrentMode) !== NoMode; - while (node.sibling === null) { - if (node.return === null || node.return === finishedWork) { - return; - } + if (isModernRoot) { + var isHidden = finishedWork.memoizedState !== null; + var newOffscreenSubtreeIsHidden = isHidden || offscreenSubtreeIsHidden; - if (hostSubtreeRoot === node) { - hostSubtreeRoot = null; + 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 (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); } - node = node.return; + offscreenSubtreeIsHidden = prevOffscreenSubtreeIsHidden; + offscreenSubtreeWasHidden = prevOffscreenSubtreeWasHidden; } + } else { + recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); + } - if (hostSubtreeRoot === node) { - hostSubtreeRoot = null; - } + if (flags & Ref) { + var props = finishedWork.memoizedProps; - node.sibling.return = node.return; - node = node.sibling; + if (props.mode === 'manual') { + safelyAttachRef(finishedWork, finishedWork.return); + } else { + safelyDetachRef(finishedWork, finishedWork.return); + } } + + break; } - } - function commitAttachRef(finishedWork) { - var ref = finishedWork.ref; + default: + { + recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); + break; + } + } +} + +function hideOrUnhideAllChildren(finishedWork, isHidden) { + // Only hide or unhide the top-most host nodes. + var hostSubtreeRoot = null; - if (ref !== null) { - var instance = finishedWork.stateNode; - var instanceToUse; + { + // We only have the top Fiber that was inserted but we need to recurse down its + // children to find all the terminal nodes. + var node = finishedWork; - switch (finishedWork.tag) { - case HostHoistable: - case HostSingleton: - case HostComponent: - instanceToUse = getPublicInstance(instance); - break; + while (true) { + if (node.tag === HostComponent || (false) || (false)) { + if (hostSubtreeRoot === null) { + hostSubtreeRoot = node; - default: - instanceToUse = instance; - } // Moved outside to ensure DCE works with this flag + try { + var instance = node.stateNode; - if (typeof ref === "function") { - if (shouldProfile(finishedWork)) { - try { - startLayoutEffectTimer(); - finishedWork.refCleanup = ref(instanceToUse); - } finally { - recordLayoutEffectDuration(finishedWork); + if (isHidden) { + hideInstance(instance); + } else { + unhideInstance(node.stateNode, node.memoizedProps); } - } else { - finishedWork.refCleanup = ref(instanceToUse); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); } - } else { - { - // TODO: We should move these warnings to happen during the render - // phase (markRef). - if (!ref.hasOwnProperty("current")) { - error( - "Unexpected ref object provided for %s. " + - "Use either a ref-setter function or React.createRef().", - getComponentNameFromFiber(finishedWork) - ); - } - } // $FlowFixMe[incompatible-use] unable to narrow type to the non-function case + } + } else if (node.tag === HostText) { + if (hostSubtreeRoot === null) { + try { + var _instance = node.stateNode; - ref.current = instanceToUse; + if (isHidden) { + hideTextInstance(_instance); + } else { + unhideTextInstance(_instance, node.memoizedProps); + } + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } } + } else if ((node.tag === OffscreenComponent || node.tag === LegacyHiddenComponent) && node.memoizedState !== null && node !== finishedWork) ; else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; } - } - 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 (node === finishedWork) { + return; + } - if (alternate !== null) { - alternate.return = null; + while (node.sibling === null) { + if (node.return === null || node.return === finishedWork) { + return; + } + + if (hostSubtreeRoot === node) { + hostSubtreeRoot = null; + } + + node = node.return; + } + + if (hostSubtreeRoot === node) { + hostSubtreeRoot = null; } - fiber.return = null; + node.sibling.return = node.return; + node = node.sibling; } + } +} - function detachFiberAfterEffects(fiber) { - var alternate = fiber.alternate; +function commitAttachRef(finishedWork) { + var ref = finishedWork.ref; - 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 (ref !== null) { + var instance = finishedWork.stateNode; + var instanceToUse; - fiber.child = null; - fiber.deletions = null; - fiber.sibling = null; // The `stateNode` is cyclical because on host nodes it points to the host + switch (finishedWork.tag) { + case HostHoistable: + case HostSingleton: + case HostComponent: + instanceToUse = getPublicInstance(instance); + break; - fiber.stateNode = null; + default: + instanceToUse = instance; + } // Moved outside to ensure DCE works with this flag + if (typeof ref === 'function') { + if (shouldProfile(finishedWork)) { + try { + startLayoutEffectTimer(); + finishedWork.refCleanup = ref(instanceToUse); + } finally { + recordLayoutEffectDuration(finishedWork); + } + } else { + finishedWork.refCleanup = ref(instanceToUse); + } + } else { { - 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. + // TODO: We should move these warnings to happen during the render + // phase (markRef). + if (!ref.hasOwnProperty('current')) { + error('Unexpected ref object provided for %s. ' + 'Use either a ref-setter function or React.createRef().', getComponentNameFromFiber(finishedWork)); + } + } // $FlowFixMe[incompatible-use] unable to narrow type to the non-function case - 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; + ref.current = instanceToUse; } + } +} - function getHostParentFiber(fiber) { - var parent = fiber.return; +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; + } + + fiber.return = null; +} - while (parent !== null) { - if (isHostParent(parent)) { - return parent; - } +function detachFiberAfterEffects(fiber) { + var alternate = fiber.alternate; - parent = parent.return; - } + 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. - throw new Error( - "Expected to find a host parent. This error is likely caused by a bug " + - "in React. Please file an issue." - ); - } - function isHostParent(fiber) { - return ( - fiber.tag === HostComponent || - fiber.tag === HostRoot || - false || - false || - fiber.tag === HostPortal - ); - } + fiber.child = null; + fiber.deletions = null; + fiber.sibling = null; // The `stateNode` is cyclical because on host nodes it points to the host - function getHostSibling(fiber) { - // We're going to search forward into the tree until we find a sibling host - // node. Unfortunately, if multiple insertions are done in a row we have to - // search past them. This leads to exponential search for the next sibling. - // TODO: Find a more efficient way to do this. - var node = fiber; + fiber.stateNode = null; - siblings: while (true) { - // If we didn't find anything, let's try the next sibling. - while (node.sibling === null) { - if (node.return === null || isHostParent(node.return)) { - // If we pop out of the root or hit the parent the fiber we are the - // last sibling. - return null; - } // $FlowFixMe[incompatible-type] found when upgrading Flow + { + 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. - node = node.return; - } - node.sibling.return = node.return; - node = node.sibling; - - while ( - node.tag !== HostComponent && - node.tag !== HostText && - true && - node.tag !== DehydratedFragment - ) { - // If it is not host node and, we might have a host node inside it. - // Try to search down until we find one. - if (node.flags & Placement) { - // If we don't have a child, try the siblings instead. - continue siblings; - } // If we don't have a child, try the siblings instead. - // We also skip portals because they are not part of this host tree. - - if (node.child === null || node.tag === HostPortal) { - continue siblings; - } else { - node.child.return = node; - node = node.child; - } - } // Check if this host node is stable or about to be placed. + fiber.return = null; + fiber.dependencies = null; + fiber.memoizedProps = null; + fiber.memoizedState = null; + fiber.pendingProps = null; + fiber.stateNode = null; // TODO: Move to `commitPassiveUnmountInsideDeletedTreeOnFiber` instead. - if (!(node.flags & Placement)) { - // Found it! - return node.stateNode; - } - } + fiber.updateQueue = null; +} + +function getHostParentFiber(fiber) { + var parent = fiber.return; + + while (parent !== null) { + if (isHostParent(parent)) { + return parent; } - function commitPlacement(finishedWork) { - var parentFiber = getHostParentFiber(finishedWork); + parent = parent.return; + } - switch (parentFiber.tag) { - case HostSingleton: + throw new Error('Expected to find a host parent. This error is likely caused by a bug ' + 'in React. Please file an issue.'); +} - case HostComponent: { - var _parent = parentFiber.stateNode; +function isHostParent(fiber) { + return fiber.tag === HostComponent || fiber.tag === HostRoot || (false) || (false) || fiber.tag === HostPortal; +} - if (parentFiber.flags & ContentReset) { - parentFiber.flags &= ~ContentReset; - } +function getHostSibling(fiber) { + // We're going to search forward into the tree until we find a sibling host + // node. Unfortunately, if multiple insertions are done in a row we have to + // search past them. This leads to exponential search for the next sibling. + // TODO: Find a more efficient way to do this. + var node = fiber; + + siblings: while (true) { + // If we didn't find anything, let's try the next sibling. + while (node.sibling === null) { + if (node.return === null || isHostParent(node.return)) { + // If we pop out of the root or hit the parent the fiber we are the + // last sibling. + return null; + } // $FlowFixMe[incompatible-type] found when upgrading Flow - var _before = getHostSibling(finishedWork); // We only have the top Fiber that was inserted but we need to recurse down its - // children to find all the terminal nodes. - insertOrAppendPlacementNode(finishedWork, _before, _parent); - break; - } + node = node.return; + } - case HostRoot: - case HostPortal: { - var _parent2 = parentFiber.stateNode.containerInfo; + node.sibling.return = node.return; + node = node.sibling; - var _before2 = getHostSibling(finishedWork); + while (node.tag !== HostComponent && node.tag !== HostText && (true ) && node.tag !== DehydratedFragment) { + // If it is not host node and, we might have a host node inside it. + // Try to search down until we find one. + if (node.flags & Placement) { + // If we don't have a child, try the siblings instead. + continue siblings; + } // If we don't have a child, try the siblings instead. + // We also skip portals because they are not part of this host tree. - insertOrAppendPlacementNodeIntoContainer( - finishedWork, - _before2, - _parent2 - ); - break; - } - default: - throw new Error( - "Invalid host parent fiber. This error is likely caused by a bug " + - "in React. Please file an issue." - ); + if (node.child === null || node.tag === HostPortal) { + continue siblings; + } else { + node.child.return = node; + node = node.child; } - } + } // Check if this host node is stable or about to be placed. - function insertOrAppendPlacementNodeIntoContainer(node, before, parent) { - var tag = node.tag; - var isHost = tag === HostComponent || tag === HostText; - if (isHost) { - var stateNode = node.stateNode; + if (!(node.flags & Placement)) { + // Found it! + return node.stateNode; + } + } +} - if (before) { - insertInContainerBefore(parent, stateNode, before); - } else { - appendChildToContainer(parent, stateNode); - } - } else if (tag === HostPortal || false); - else { - var child = node.child; +function commitPlacement(finishedWork) { - if (child !== null) { - insertOrAppendPlacementNodeIntoContainer(child, before, parent); - var sibling = child.sibling; - while (sibling !== null) { - insertOrAppendPlacementNodeIntoContainer(sibling, before, parent); - sibling = sibling.sibling; - } - } - } - } + var parentFiber = getHostParentFiber(finishedWork); - function insertOrAppendPlacementNode(node, before, parent) { - var tag = node.tag; - var isHost = tag === HostComponent || tag === HostText; + switch (parentFiber.tag) { + case HostSingleton: - if (isHost) { - var stateNode = node.stateNode; + case HostComponent: + { + var _parent = parentFiber.stateNode; - if (before) { - insertBefore(parent, stateNode, before); - } else { - appendChild(parent, stateNode); + if (parentFiber.flags & ContentReset) { + + parentFiber.flags &= ~ContentReset; } - } else if (tag === HostPortal || false); - else { - var child = node.child; - if (child !== null) { - insertOrAppendPlacementNode(child, before, parent); - var sibling = child.sibling; + var _before = getHostSibling(finishedWork); // We only have the top Fiber that was inserted but we need to recurse down its + // children to find all the terminal nodes. - while (sibling !== null) { - insertOrAppendPlacementNode(sibling, before, parent); - sibling = sibling.sibling; - } - } - } - } // These are tracked on the stack as we recursively traverse a - // deleted subtree. - // TODO: Update these during the whole mutation phase, not just during - // a deletion. - var hostParent = null; - var hostParentIsContainer = false; + insertOrAppendPlacementNode(finishedWork, _before, _parent); + break; + } - function commitDeletionEffects(root, returnFiber, deletedFiber) { + case HostRoot: + case HostPortal: { - // We only have the top Fiber that was deleted but we need to recurse down its - // children to find all the terminal nodes. - // Recursively delete all host nodes from the parent, detach refs, clean - // up mounted layout effects, and call componentWillUnmount. - // We only need to remove the topmost host child in each branch. But then we - // still need to keep traversing to unmount effects, refs, and cWU. TODO: We - // could split this into two separate traversals functions, where the second - // one doesn't include any removeChild logic. This is maybe the same - // function as "disappearLayoutEffects" (or whatever that turns into after - // the layout phase is refactored to use recursion). - // Before starting, find the nearest host parent on the stack so we know - // which instance/container to remove the children from. - // TODO: Instead of searching up the fiber return path on every deletion, we - // can track the nearest host component on the JS stack as we traverse the - // tree during the commit phase. This would make insertions faster, too. - var parent = returnFiber; - - findParent: while (parent !== null) { - switch (parent.tag) { - case HostSingleton: - case HostComponent: { - hostParent = parent.stateNode; - hostParentIsContainer = false; - break findParent; - } + var _parent2 = parentFiber.stateNode.containerInfo; - case HostRoot: { - hostParent = parent.stateNode.containerInfo; - hostParentIsContainer = true; - break findParent; - } + var _before2 = getHostSibling(finishedWork); - case HostPortal: { - hostParent = parent.stateNode.containerInfo; - hostParentIsContainer = true; - break findParent; - } - } + insertOrAppendPlacementNodeIntoContainer(finishedWork, _before2, _parent2); + break; + } - parent = parent.return; - } + default: + throw new Error('Invalid host parent fiber. This error is likely caused by a bug ' + 'in React. Please file an issue.'); + } +} - if (hostParent === null) { - throw new Error( - "Expected to find a host parent. This error is likely caused by " + - "a bug in React. Please file an issue." - ); - } +function insertOrAppendPlacementNodeIntoContainer(node, before, parent) { + var tag = node.tag; + var isHost = tag === HostComponent || tag === HostText; - commitDeletionEffectsOnFiber(root, returnFiber, deletedFiber); - hostParent = null; - hostParentIsContainer = false; - } + if (isHost) { + var stateNode = node.stateNode; - detachFiberMutation(deletedFiber); + if (before) { + insertInContainerBefore(parent, stateNode, before); + } else { + appendChildToContainer(parent, stateNode); } + } else if (tag === HostPortal || (false)) ; else { + var child = node.child; - function recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - parent - ) { - // TODO: Use a static flag to skip trees that don't have unmount effects - var child = parent.child; + if (child !== null) { + insertOrAppendPlacementNodeIntoContainer(child, before, parent); + var sibling = child.sibling; - while (child !== null) { - commitDeletionEffectsOnFiber( - finishedRoot, - nearestMountedAncestor, - child - ); - child = child.sibling; + while (sibling !== null) { + insertOrAppendPlacementNodeIntoContainer(sibling, before, parent); + sibling = sibling.sibling; } } + } +} - 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: - +function insertOrAppendPlacementNode(node, before, parent) { + var tag = node.tag; + var isHost = tag === HostComponent || tag === HostText; + + if (isHost) { + var stateNode = node.stateNode; + + if (before) { + insertBefore(parent, stateNode, before); + } else { + appendChild(parent, stateNode); + } + } else if (tag === HostPortal || (false)) ; else { + var child = node.child; + + if (child !== null) { + insertOrAppendPlacementNode(child, before, parent); + var sibling = child.sibling; + + while (sibling !== null) { + insertOrAppendPlacementNode(sibling, before, parent); + sibling = sibling.sibling; + } + } + } +} // These are tracked on the stack as we recursively traverse a +// deleted subtree. +// TODO: Update these during the whole mutation phase, not just during +// a deletion. + + +var hostParent = null; +var hostParentIsContainer = false; + +function commitDeletionEffects(root, returnFiber, deletedFiber) { + { + // We only have the top Fiber that was deleted but we need to recurse down its + // children to find all the terminal nodes. + // Recursively delete all host nodes from the parent, detach refs, clean + // up mounted layout effects, and call componentWillUnmount. + // We only need to remove the topmost host child in each branch. But then we + // still need to keep traversing to unmount effects, refs, and cWU. TODO: We + // could split this into two separate traversals functions, where the second + // one doesn't include any removeChild logic. This is maybe the same + // function as "disappearLayoutEffects" (or whatever that turns into after + // the layout phase is refactored to use recursion). + // Before starting, find the nearest host parent on the stack so we know + // which instance/container to remove the children from. + // TODO: Instead of searching up the fiber return path on every deletion, we + // can track the nearest host component on the JS stack as we traverse the + // tree during the commit phase. This would make insertions faster, too. + var parent = returnFiber; + + findParent: while (parent !== null) { + switch (parent.tag) { case HostSingleton: + case HostComponent: + { + hostParent = parent.stateNode; + hostParentIsContainer = false; + break findParent; + } - case HostComponent: { - if (!offscreenSubtreeWasHidden) { - safelyDetachRef(deletedFiber, nearestMountedAncestor); - } // Intentional fallthrough to next branch - } + case HostRoot: + { + hostParent = parent.stateNode.containerInfo; + hostParentIsContainer = true; + break findParent; + } - 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. + case HostPortal: { - var _prevHostParent = hostParent; - var _prevHostParentIsContainer = hostParentIsContainer; - hostParent = null; - recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - deletedFiber - ); - hostParent = _prevHostParent; - hostParentIsContainer = _prevHostParentIsContainer; - - if (hostParent !== null) { - // Now that all the child effects have unmounted, we can remove the - // node from the tree. - if (hostParentIsContainer) { - removeChildFromContainer(hostParent, deletedFiber.stateNode); - } else { - removeChild(hostParent, deletedFiber.stateNode); - } - } + hostParent = parent.stateNode.containerInfo; + hostParentIsContainer = true; + break findParent; } + } - return; - } + parent = parent.return; + } + + if (hostParent === null) { + throw new Error('Expected to find a host parent. This error is likely caused by ' + 'a bug in React. Please file an issue.'); + } - case DehydratedFragment: { - // Delete the dehydrated suspense boundary and all of its content. + commitDeletionEffectsOnFiber(root, returnFiber, deletedFiber); + hostParent = null; + hostParentIsContainer = false; + } - { - if (hostParent !== null) { - if (hostParentIsContainer) { - clearSuspenseBoundaryFromContainer(); - } else { - clearSuspenseBoundary(); - } + 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) { + commitDeletionEffectsOnFiber(finishedRoot, nearestMountedAncestor, child); + child = child.sibling; + } +} + +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: + + case HostSingleton: + + case HostComponent: + { + if (!offscreenSubtreeWasHidden) { + safelyDetachRef(deletedFiber, nearestMountedAncestor); + } // Intentional fallthrough to next branch + + } + + 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. + { + var _prevHostParent = hostParent; + var _prevHostParentIsContainer = hostParentIsContainer; + hostParent = null; + recursivelyTraverseDeletionEffects(finishedRoot, nearestMountedAncestor, deletedFiber); + hostParent = _prevHostParent; + hostParentIsContainer = _prevHostParentIsContainer; + + if (hostParent !== null) { + // Now that all the child effects have unmounted, we can remove the + // node from the tree. + if (hostParentIsContainer) { + removeChildFromContainer(hostParent, deletedFiber.stateNode); + } else { + removeChild(hostParent, deletedFiber.stateNode); } } - - return; } - case HostPortal: { - { - // When we go into a portal, it becomes the parent to remove from. - var _prevHostParent2 = hostParent; - var _prevHostParentIsContainer2 = hostParentIsContainer; - hostParent = deletedFiber.stateNode.containerInfo; - hostParentIsContainer = true; - recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - deletedFiber - ); - hostParent = _prevHostParent2; - hostParentIsContainer = _prevHostParentIsContainer2; - } + return; + } - return; - } + case DehydratedFragment: + { + // Delete the dehydrated suspense boundary and all of its content. - case FunctionComponent: - case ForwardRef: - case MemoComponent: - case SimpleMemoComponent: { - if (!offscreenSubtreeWasHidden) { - var updateQueue = deletedFiber.updateQueue; - if (updateQueue !== null) { - var lastEffect = updateQueue.lastEffect; + { + if (hostParent !== null) { + if (hostParentIsContainer) { + clearSuspenseBoundaryFromContainer(); + } else { + clearSuspenseBoundary(); + } + } + } - if (lastEffect !== null) { - var firstEffect = lastEffect.next; - var effect = firstEffect; + return; + } - do { - var tag = effect.tag; - var inst = effect.inst; - var destroy = inst.destroy; + case HostPortal: + { + { + // When we go into a portal, it becomes the parent to remove from. + var _prevHostParent2 = hostParent; + var _prevHostParentIsContainer2 = hostParentIsContainer; + hostParent = deletedFiber.stateNode.containerInfo; + hostParentIsContainer = true; + recursivelyTraverseDeletionEffects(finishedRoot, nearestMountedAncestor, deletedFiber); + hostParent = _prevHostParent2; + hostParentIsContainer = _prevHostParentIsContainer2; + } - if (destroy !== undefined) { - if ((tag & Insertion) !== NoFlags) { - inst.destroy = undefined; - safelyCallDestroy( - deletedFiber, - nearestMountedAncestor, - destroy - ); - } else if ((tag & Layout) !== NoFlags) { - { - markComponentLayoutEffectUnmountStarted(deletedFiber); - } + return; + } - if (shouldProfile(deletedFiber)) { - startLayoutEffectTimer(); - inst.destroy = undefined; - safelyCallDestroy( - deletedFiber, - nearestMountedAncestor, - destroy - ); - recordLayoutEffectDuration(deletedFiber); - } else { - inst.destroy = undefined; - safelyCallDestroy( - deletedFiber, - nearestMountedAncestor, - destroy - ); - } + case FunctionComponent: + case ForwardRef: + case MemoComponent: + case SimpleMemoComponent: + { + if (!offscreenSubtreeWasHidden) { + var updateQueue = deletedFiber.updateQueue; - { - markComponentLayoutEffectUnmountStopped(); - } + if (updateQueue !== null) { + var lastEffect = updateQueue.lastEffect; + + if (lastEffect !== null) { + var firstEffect = lastEffect.next; + var effect = firstEffect; + + do { + var tag = effect.tag; + var inst = effect.inst; + var destroy = inst.destroy; + + if (destroy !== undefined) { + if ((tag & Insertion) !== NoFlags) { + inst.destroy = undefined; + safelyCallDestroy(deletedFiber, nearestMountedAncestor, destroy); + } else if ((tag & Layout) !== NoFlags) { + { + markComponentLayoutEffectUnmountStarted(deletedFiber); } - } - effect = effect.next; - } while (effect !== firstEffect); - } - } - } + if (shouldProfile(deletedFiber)) { + startLayoutEffectTimer(); + inst.destroy = undefined; + safelyCallDestroy(deletedFiber, nearestMountedAncestor, destroy); + recordLayoutEffectDuration(deletedFiber); + } else { + inst.destroy = undefined; + safelyCallDestroy(deletedFiber, nearestMountedAncestor, destroy); + } - recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - deletedFiber - ); - return; - } + { + markComponentLayoutEffectUnmountStopped(); + } + } + } - case ClassComponent: { - if (!offscreenSubtreeWasHidden) { - safelyDetachRef(deletedFiber, nearestMountedAncestor); - var instance = deletedFiber.stateNode; - - if (typeof instance.componentWillUnmount === "function") { - safelyCallComponentWillUnmount( - deletedFiber, - nearestMountedAncestor, - instance - ); + effect = effect.next; + } while (effect !== firstEffect); } } - - recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - deletedFiber - ); - return; } - case ScopeComponent: { - recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - deletedFiber - ); - return; - } + recursivelyTraverseDeletionEffects(finishedRoot, nearestMountedAncestor, deletedFiber); + return; + } - case OffscreenComponent: { + case ClassComponent: + { + if (!offscreenSubtreeWasHidden) { safelyDetachRef(deletedFiber, nearestMountedAncestor); + var instance = deletedFiber.stateNode; - 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 - ); + if (typeof instance.componentWillUnmount === 'function') { + safelyCallComponentWillUnmount(deletedFiber, nearestMountedAncestor, instance); } - - break; } - default: { - recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - deletedFiber - ); - return; - } + recursivelyTraverseDeletionEffects(finishedRoot, nearestMountedAncestor, deletedFiber); + return; } - } - - 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 SuspenseComponent: - case SuspenseListComponent: { - var retryCache = finishedWork.stateNode; + case ScopeComponent: + { - if (retryCache === null) { - retryCache = finishedWork.stateNode = new PossiblyWeakSet(); - } + recursivelyTraverseDeletionEffects(finishedRoot, nearestMountedAncestor, deletedFiber); + return; + } - return retryCache; + case OffscreenComponent: + { + safelyDetachRef(deletedFiber, nearestMountedAncestor); + + 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); } - case OffscreenComponent: { - var instance = finishedWork.stateNode; - var _retryCache = instance._retryCache; + break; + } - if (_retryCache === null) { - _retryCache = instance._retryCache = new PossiblyWeakSet(); - } + default: + { + recursivelyTraverseDeletionEffects(finishedRoot, nearestMountedAncestor, deletedFiber); + return; + } + } +} - return _retryCache; - } +function commitSuspenseCallback(finishedWork) { +} - default: { - throw new Error( - "Unexpected Suspense handler tag (" + - finishedWork.tag + - "). This is a " + - "bug in React." - ); - } - } - } +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; - function detachOffscreenInstance(instance) { - var fiber = instance._current; + if (retryCache === null) { + retryCache = finishedWork.stateNode = new PossiblyWeakSet(); + } - if (fiber === null) { - throw new Error( - "Calling Offscreen.detach before instance handle has been set." - ); + return retryCache; } - 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. + case OffscreenComponent: + { + var instance = finishedWork.stateNode; + var _retryCache = instance._retryCache; - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + if (_retryCache === null) { + _retryCache = instance._retryCache = new PossiblyWeakSet(); + } - if (root !== null) { - instance._pendingVisibility |= OffscreenDetached; - scheduleUpdateOnFiber(root, fiber, SyncLane); + return _retryCache; } - } - function attachOffscreenInstance(instance) { - var fiber = instance._current; - if (fiber === null) { - throw new Error( - "Calling Offscreen.detach before instance handle has been set." - ); + default: + { + throw new Error("Unexpected Suspense handler tag (" + finishedWork.tag + "). This is a " + 'bug in React.'); } + } +} - if ((instance._pendingVisibility & OffscreenDetached) === NoFlags$1) { - // The instance is already attached, this is a noop. - return; - } +function detachOffscreenInstance(instance) { + var fiber = instance._current; - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + if (fiber === null) { + throw new Error('Calling Offscreen.detach before instance handle has been set.'); + } - if (root !== null) { - instance._pendingVisibility &= ~OffscreenDetached; - scheduleUpdateOnFiber(root, fiber, SyncLane); - } - } + 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. - 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); + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - wakeable.then(retry, retry); - } - }); - } // This function detects when a Suspense boundary goes from visible to hidden. - function commitMutationEffects(root, finishedWork, committedLanes) { - setCurrentFiber(finishedWork); - commitMutationEffectsOnFiber(finishedWork, root); - setCurrentFiber(finishedWork); - } + if (root !== null) { + instance._pendingVisibility |= OffscreenDetached; + scheduleUpdateOnFiber(root, fiber, SyncLane); + } +} +function attachOffscreenInstance(instance) { + var fiber = instance._current; - 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; + if (fiber === null) { + throw new Error('Calling Offscreen.detach before instance handle has been set.'); + } - if (deletions !== null) { - for (var i = 0; i < deletions.length; i++) { - var childToDelete = deletions[i]; + if ((instance._pendingVisibility & OffscreenDetached) === NoFlags$1) { + // The instance is already attached, this is a noop. + return; + } - try { - commitDeletionEffects(root, parentFiber, childToDelete); - } catch (error) { - captureCommitPhaseError(childToDelete, parentFiber, error); - } - } - } + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - var prevDebugFiber = getCurrentFiber(); + if (root !== null) { + instance._pendingVisibility &= ~OffscreenDetached; + scheduleUpdateOnFiber(root, fiber, SyncLane); + } +} - if (parentFiber.subtreeFlags & MutationMask) { - var child = parentFiber.child; +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); + + wakeable.then(retry, retry); + } + }); +} // This function detects when a Suspense boundary goes from visible to hidden. +function commitMutationEffects(root, finishedWork, committedLanes) { + setCurrentFiber(finishedWork); + commitMutationEffectsOnFiber(finishedWork, root); + setCurrentFiber(finishedWork); +} - while (child !== null) { - setCurrentFiber(child); - commitMutationEffectsOnFiber(child, root); - child = child.sibling; - } +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; + + if (deletions !== null) { + for (var i = 0; i < deletions.length; i++) { + var childToDelete = deletions[i]; + + try { + commitDeletionEffects(root, parentFiber, childToDelete); + } catch (error) { + captureCommitPhaseError(childToDelete, parentFiber, error); } + } + } + + var prevDebugFiber = getCurrentFiber(); - setCurrentFiber(prevDebugFiber); + if (parentFiber.subtreeFlags & MutationMask) { + var child = parentFiber.child; + + while (child !== null) { + setCurrentFiber(child); + commitMutationEffectsOnFiber(child, root); + child = child.sibling; } + } + + 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. +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); + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case MemoComponent: + case SimpleMemoComponent: + { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); - if (flags & Update) { + 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 { - commitHookEffectListUnmount( - Insertion | HasEffect, - finishedWork, - finishedWork.return - ); - commitHookEffectListMount(Insertion | HasEffect, finishedWork); + startLayoutEffectTimer(); + commitHookEffectListUnmount(Layout | HasEffect, finishedWork, finishedWork.return); } 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 - ); - } + recordLayoutEffectDuration(finishedWork); + } else { + try { + commitHookEffectListUnmount(Layout | HasEffect, finishedWork, finishedWork.return); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); } } - - return; } - case ClassComponent: { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); + return; + } - if (flags & Ref) { - if (current !== null) { - safelyDetachRef(current, current.return); - } + case ClassComponent: + { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); + + if (flags & Ref) { + if (current !== null) { + safelyDetachRef(current, current.return); } + } - if (flags & Callback && offscreenSubtreeIsHidden) { - var updateQueue = finishedWork.updateQueue; + if (flags & Callback && offscreenSubtreeIsHidden) { + var updateQueue = finishedWork.updateQueue; - if (updateQueue !== null) { - deferHiddenCallbacks(updateQueue); - } + if (updateQueue !== null) { + deferHiddenCallbacks(updateQueue); } - - return; } - case HostHoistable: - - case HostSingleton: + return; + } - case HostComponent: { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); + case HostHoistable: - if (flags & Ref) { - if (current !== null) { - safelyDetachRef(current, current.return); - } - } + case HostSingleton: - { - // TODO: ContentReset gets cleared by the children during the commit - // phase. This is a refactor hazard because it means we must read - // flags the flags after `commitReconciliationEffects` has already run; - // the order matters. We should refactor so that ContentReset does not - // rely on mutating the flag during commit. Like by setting a flag - // during the render phase instead. - if (finishedWork.flags & ContentReset) { - var instance = finishedWork.stateNode; + case HostComponent: + { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); - try { - resetTextContent(instance); - } catch (error) { - captureCommitPhaseError( - finishedWork, - finishedWork.return, - error - ); - } - } + if (flags & Ref) { + if (current !== null) { + safelyDetachRef(current, current.return); + } + } - if (flags & Update) { - var _instance2 = finishedWork.stateNode; - - if (_instance2 != null) { - // Commit the work prepared earlier. - var newProps = finishedWork.memoizedProps; // For hydration we reuse the update path but we treat the oldProps - // as the newProps. The updatePayload will contain the real change in - // this case. - - var oldProps = - current !== null ? current.memoizedProps : newProps; - var type = finishedWork.type; // TODO: Type the updateQueue to be specific to host components. - - var _updatePayload = finishedWork.updateQueue; - finishedWork.updateQueue = null; - - try { - commitUpdate( - _instance2, - _updatePayload, - type, - oldProps, - newProps, - finishedWork - ); - } catch (error) { - captureCommitPhaseError( - finishedWork, - finishedWork.return, - error - ); - } - } - } + { + // TODO: ContentReset gets cleared by the children during the commit + // phase. This is a refactor hazard because it means we must read + // flags the flags after `commitReconciliationEffects` has already run; + // the order matters. We should refactor so that ContentReset does not + // rely on mutating the flag during commit. Like by setting a flag + // during the render phase instead. + if (finishedWork.flags & ContentReset) { + var instance = finishedWork.stateNode; - if (flags & FormReset) { - { - if (finishedWork.type !== "form") { - // Paranoid coding. In case we accidentally start using the - // FormReset bit for something else. - error( - "Unexpected host component type. Expected a form. This is a " + - "bug in React." - ); - } - } + try { + resetTextContent(instance); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); } } - return; - } - - case HostText: { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); - if (flags & Update) { - { - if (finishedWork.stateNode === null) { - throw new Error( - "This should have a text node initialized. This error is likely " + - "caused by a bug in React. Please file an issue." - ); - } + var _instance2 = finishedWork.stateNode; - var textInstance = finishedWork.stateNode; - var newText = finishedWork.memoizedProps; // For hydration we reuse the update path but we treat the oldProps + if (_instance2 != null) { + // Commit the work prepared earlier. + var newProps = finishedWork.memoizedProps; // For hydration we reuse the update path but we treat the oldProps // as the newProps. The updatePayload will contain the real change in // this case. - var oldText = current !== null ? current.memoizedProps : newText; + var oldProps = current !== null ? current.memoizedProps : newProps; + var type = finishedWork.type; // TODO: Type the updateQueue to be specific to host components. + + var _updatePayload = finishedWork.updateQueue; + finishedWork.updateQueue = null; try { - commitTextUpdate(textInstance, oldText, newText); + commitUpdate(_instance2, _updatePayload, type, oldProps, newProps, finishedWork); } catch (error) { - captureCommitPhaseError( - finishedWork, - finishedWork.return, - error - ); + captureCommitPhaseError(finishedWork, finishedWork.return, error); } } } - return; - } + if (flags & FormReset) { - case HostRoot: { - { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); + { + if (finishedWork.type !== 'form') { + // Paranoid coding. In case we accidentally start using the + // FormReset bit for something else. + error('Unexpected host component type. Expected a form. This is a ' + 'bug in React.'); + } + } } - - return; } - case HostPortal: { - { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); - } - - return; - } + return; + } - case SuspenseComponent: { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); // TODO: We should mark a flag on the Suspense fiber itself, rather than - // relying on the Offscreen fiber having a flag also being marked. The - // reason is that this offscreen fiber might not be part of the work-in- - // progress tree! It could have been reused from a previous render. This - // doesn't lead to incorrect behavior because we don't rely on the flag - // check alone; we also compare the states explicitly below. But for - // modeling purposes, we _should_ be able to rely on the flag check alone. - // So this is a bit fragile. - // - // Also, all this logic could/should move to the passive phase so it - // doesn't block paint. + case HostText: + { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); - var offscreenFiber = finishedWork.child; + if (flags & Update) { + { + if (finishedWork.stateNode === null) { + throw new Error('This should have a text node initialized. This error is likely ' + 'caused by a bug in React. Please file an issue.'); + } - if (offscreenFiber.flags & Visibility) { - // Throttle the appearance and disappearance of Suspense fallbacks. - var isShowingFallback = finishedWork.memoizedState !== null; - var wasShowingFallback = - current !== null && current.memoizedState !== null; + var textInstance = finishedWork.stateNode; + var newText = finishedWork.memoizedProps; // For hydration we reuse the update path but we treat the oldProps + // as the newProps. The updatePayload will contain the real change in + // this case. - { - if (isShowingFallback && !wasShowingFallback) { - // Old behavior. Only mark when a fallback appears, not when - // it disappears. - markCommitTimeOfFallback(); - } - } - } + var oldText = current !== null ? current.memoizedProps : newText; - if (flags & Update) { try { - commitSuspenseCallback(finishedWork); + commitTextUpdate(textInstance, oldText, newText); } catch (error) { captureCommitPhaseError(finishedWork, finishedWork.return, error); } + } + } + + return; + } - var retryQueue = finishedWork.updateQueue; + case HostRoot: + { + { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); + } - if (retryQueue !== null) { - finishedWork.updateQueue = null; - attachSuspenseRetryListeners(finishedWork, retryQueue); - } - } + return; + } - return; + case HostPortal: + { + { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); } - case OffscreenComponent: { - if (flags & Ref) { - if (current !== null) { - safelyDetachRef(current, current.return); + return; + } + + case SuspenseComponent: + { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); // TODO: We should mark a flag on the Suspense fiber itself, rather than + // relying on the Offscreen fiber having a flag also being marked. The + // reason is that this offscreen fiber might not be part of the work-in- + // progress tree! It could have been reused from a previous render. This + // doesn't lead to incorrect behavior because we don't rely on the flag + // check alone; we also compare the states explicitly below. But for + // modeling purposes, we _should_ be able to rely on the flag check alone. + // So this is a bit fragile. + // + // Also, all this logic could/should move to the passive phase so it + // doesn't block paint. + + var offscreenFiber = finishedWork.child; + + if (offscreenFiber.flags & Visibility) { + // Throttle the appearance and disappearance of Suspense fallbacks. + var isShowingFallback = finishedWork.memoizedState !== null; + var wasShowingFallback = current !== null && current.memoizedState !== null; + + { + if (isShowingFallback && !wasShowingFallback) { + // Old behavior. Only mark when a fallback appears, not when + // it disappears. + markCommitTimeOfFallback(); } } + } - var newState = finishedWork.memoizedState; - var isHidden = newState !== null; - var wasHidden = current !== null && current.memoizedState !== null; + if (flags & Update) { + try { + commitSuspenseCallback(finishedWork); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } - 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); + var retryQueue = finishedWork.updateQueue; + + if (retryQueue !== null) { + finishedWork.updateQueue = null; + attachSuspenseRetryListeners(finishedWork, retryQueue); } + } - commitReconciliationEffects(finishedWork); - var offscreenInstance = finishedWork.stateNode; // TODO: Add explicit effect flag to set _current. + return; + } - offscreenInstance._current = finishedWork; // Offscreen stores pending changes to visibility in `_pendingVisibility`. This is - // to support batching of `attach` and `detach` calls. + case OffscreenComponent: + { + if (flags & Ref) { + if (current !== null) { + safelyDetachRef(current, current.return); + } + } - offscreenInstance._visibility &= ~OffscreenDetached; - offscreenInstance._visibility |= - offscreenInstance._pendingVisibility & OffscreenDetached; + var newState = finishedWork.memoizedState; + var isHidden = newState !== null; + var wasHidden = current !== null && current.memoizedState !== null; - 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 (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 (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 (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. + commitReconciliationEffects(finishedWork); + var offscreenInstance = finishedWork.stateNode; // TODO: Add explicit effect flag to set _current. - if (!isOffscreenManual(finishedWork)) { - // TODO: This needs to run whenever there's an insertion or update - // inside a hidden Offscreen tree. - hideOrUnhideAllChildren(finishedWork, isHidden); - } - } // TODO: Move to passive phase + offscreenInstance._current = finishedWork; // Offscreen stores pending changes to visibility in `_pendingVisibility`. This is + // to support batching of `attach` and `detach` calls. - if (flags & Update) { - var offscreenQueue = finishedWork.updateQueue; + offscreenInstance._visibility &= ~OffscreenDetached; + offscreenInstance._visibility |= offscreenInstance._pendingVisibility & OffscreenDetached; - if (offscreenQueue !== null) { - var _retryQueue = offscreenQueue.retryQueue; + 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 (_retryQueue !== null) { - offscreenQueue.retryQueue = null; - attachSuspenseRetryListeners(finishedWork, _retryQueue); + 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 (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. + + + if (!isOffscreenManual(finishedWork)) { + // TODO: This needs to run whenever there's an insertion or update + // inside a hidden Offscreen tree. + hideOrUnhideAllChildren(finishedWork, isHidden); } + } // TODO: Move to passive phase - return; - } - case SuspenseListComponent: { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); + if (flags & Update) { + var offscreenQueue = finishedWork.updateQueue; - if (flags & Update) { - var _retryQueue2 = finishedWork.updateQueue; + if (offscreenQueue !== null) { + var _retryQueue = offscreenQueue.retryQueue; - if (_retryQueue2 !== null) { - finishedWork.updateQueue = null; - attachSuspenseRetryListeners(finishedWork, _retryQueue2); + if (_retryQueue !== null) { + offscreenQueue.retryQueue = null; + attachSuspenseRetryListeners(finishedWork, _retryQueue); } } - - return; - } - - case ScopeComponent: { - return; } - default: { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); - return; - } + return; } - } - 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 SuspenseListComponent: + { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); - 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 (flags & Update) { + var _retryQueue2 = finishedWork.updateQueue; - finishedWork.flags &= ~Placement; - } + if (_retryQueue2 !== null) { + finishedWork.updateQueue = null; + attachSuspenseRetryListeners(finishedWork, _retryQueue2); + } + } - if (flags & Hydrating) { - finishedWork.flags &= ~Hydrating; + return; } - } - - function commitLayoutEffects(finishedWork, root, committedLanes) { - var current = finishedWork.alternate; - commitLayoutEffectOnFiber(root, current, finishedWork); - } - function recursivelyTraverseLayoutEffects(root, parentFiber, lanes) { - var prevDebugFiber = getCurrentFiber(); + case ScopeComponent: + { - if (parentFiber.subtreeFlags & LayoutMask) { - var child = parentFiber.child; + return; + } - while (child !== null) { - setCurrentFiber(child); - var current = child.alternate; - commitLayoutEffectOnFiber(root, current, child); - child = child.sibling; - } + default: + { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); + return; } + } +} - setCurrentFiber(prevDebugFiber); - } +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; + + 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. + + + finishedWork.flags &= ~Placement; + } + + if (flags & Hydrating) { + finishedWork.flags &= ~Hydrating; + } +} - function disappearLayoutEffects(finishedWork) { - switch (finishedWork.tag) { - case FunctionComponent: - case ForwardRef: - case MemoComponent: - case SimpleMemoComponent: { - // TODO (Offscreen) Check: flags & LayoutStatic - if (shouldProfile(finishedWork)) { - try { - startLayoutEffectTimer(); - commitHookEffectListUnmount( - Layout, - finishedWork, - finishedWork.return - ); - } finally { - recordLayoutEffectDuration(finishedWork); - } - } else { - commitHookEffectListUnmount( - Layout, - finishedWork, - finishedWork.return - ); - } +function commitLayoutEffects(finishedWork, root, committedLanes) { + var current = finishedWork.alternate; + commitLayoutEffectOnFiber(root, current, finishedWork); +} - recursivelyTraverseDisappearLayoutEffects(finishedWork); - break; - } +function recursivelyTraverseLayoutEffects(root, parentFiber, lanes) { + var prevDebugFiber = getCurrentFiber(); - case ClassComponent: { - // TODO (Offscreen) Check: flags & RefStatic - safelyDetachRef(finishedWork, finishedWork.return); - var instance = finishedWork.stateNode; + if (parentFiber.subtreeFlags & LayoutMask) { + var child = parentFiber.child; - if (typeof instance.componentWillUnmount === "function") { - safelyCallComponentWillUnmount( - finishedWork, - finishedWork.return, - instance - ); - } + while (child !== null) { + setCurrentFiber(child); + var current = child.alternate; + commitLayoutEffectOnFiber(root, current, child); + child = child.sibling; + } + } - recursivelyTraverseDisappearLayoutEffects(finishedWork); - break; - } + setCurrentFiber(prevDebugFiber); +} - case HostHoistable: - case HostSingleton: - case HostComponent: { - // TODO (Offscreen) Check: flags & RefStatic - safelyDetachRef(finishedWork, finishedWork.return); - recursivelyTraverseDisappearLayoutEffects(finishedWork); - break; +function disappearLayoutEffects(finishedWork) { + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case MemoComponent: + case SimpleMemoComponent: + { + // TODO (Offscreen) Check: flags & LayoutStatic + if (shouldProfile(finishedWork)) { + try { + startLayoutEffectTimer(); + commitHookEffectListUnmount(Layout, finishedWork, finishedWork.return); + } finally { + recordLayoutEffectDuration(finishedWork); + } + } else { + commitHookEffectListUnmount(Layout, finishedWork, finishedWork.return); } - case OffscreenComponent: { - // TODO (Offscreen) Check: flags & RefStatic - safelyDetachRef(finishedWork, finishedWork.return); - var isHidden = finishedWork.memoizedState !== null; + recursivelyTraverseDisappearLayoutEffects(finishedWork); + break; + } - if (isHidden); - else { - recursivelyTraverseDisappearLayoutEffects(finishedWork); - } + 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); } - default: { - recursivelyTraverseDisappearLayoutEffects(finishedWork); - break; - } + recursivelyTraverseDisappearLayoutEffects(finishedWork); + break; } - } - - function recursivelyTraverseDisappearLayoutEffects(parentFiber) { - // TODO (Offscreen) Check: flags & (RefStatic | LayoutStatic) - var child = parentFiber.child; - while (child !== null) { - disappearLayoutEffects(child); - child = child.sibling; + case HostHoistable: + case HostSingleton: + case HostComponent: + { + // TODO (Offscreen) Check: flags & RefStatic + safelyDetachRef(finishedWork, finishedWork.return); + recursivelyTraverseDisappearLayoutEffects(finishedWork); + break; } - } - 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; + case OffscreenComponent: + { + // TODO (Offscreen) Check: flags & RefStatic + safelyDetachRef(finishedWork, finishedWork.return); + var isHidden = finishedWork.memoizedState !== null; - switch (finishedWork.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - recursivelyTraverseReappearLayoutEffects( - finishedRoot, - finishedWork, - includeWorkInProgressEffects - ); // TODO: Check flags & LayoutStatic - - commitHookLayoutEffects(finishedWork, Layout); - break; + if (isHidden) ; else { + recursivelyTraverseDisappearLayoutEffects(finishedWork); } - case ClassComponent: { - recursivelyTraverseReappearLayoutEffects( - finishedRoot, - finishedWork, - includeWorkInProgressEffects - ); // TODO: Check for LayoutStatic flag + break; + } - var instance = finishedWork.stateNode; + default: + { + recursivelyTraverseDisappearLayoutEffects(finishedWork); + break; + } + } +} - 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. +function recursivelyTraverseDisappearLayoutEffects(parentFiber) { + // TODO (Offscreen) Check: flags & (RefStatic | LayoutStatic) + var child = parentFiber.child; - var updateQueue = finishedWork.updateQueue; + while (child !== null) { + disappearLayoutEffects(child); + child = child.sibling; + } +} - if (updateQueue !== null) { - commitHiddenCallbacks(updateQueue, instance); - } // If this is newly finished work, check for setState callbacks +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; - if (includeWorkInProgressEffects && flags & Callback) { - commitClassCallbacks(finishedWork); - } // TODO: Check flags & RefStatic + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: + { + recursivelyTraverseReappearLayoutEffects(finishedRoot, finishedWork, includeWorkInProgressEffects); // TODO: Check flags & LayoutStatic - 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. - - if ( - includeWorkInProgressEffects && - current === null && - flags & Update - ) { - commitHostComponentMount(finishedWork); - } // TODO: Check flags & Ref + commitHookLayoutEffects(finishedWork, Layout); + break; + } - safelyAttachRef(finishedWork, finishedWork.return); - break; - } + case ClassComponent: + { + recursivelyTraverseReappearLayoutEffects(finishedRoot, finishedWork, includeWorkInProgressEffects); // TODO: Check for LayoutStatic flag - case Profiler: { - recursivelyTraverseReappearLayoutEffects( - finishedRoot, - finishedWork, - includeWorkInProgressEffects - ); // TODO: Figure out how Profiler updates should work with Offscreen + var instance = finishedWork.stateNode; - if (includeWorkInProgressEffects && flags & Update) { - commitProfilerUpdate(finishedWork, current); + 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. - break; - } - case SuspenseComponent: { - recursivelyTraverseReappearLayoutEffects( - finishedRoot, - finishedWork, - includeWorkInProgressEffects - ); // TODO: Figure out how Suspense hydration callbacks should work + var updateQueue = finishedWork.updateQueue; - break; - } + if (updateQueue !== null) { + commitHiddenCallbacks(updateQueue, instance); + } // If this is newly finished work, check for setState callbacks - case OffscreenComponent: { - var offscreenState = finishedWork.memoizedState; - var isHidden = offscreenState !== null; - if (isHidden); - else { - recursivelyTraverseReappearLayoutEffects( - finishedRoot, - finishedWork, - includeWorkInProgressEffects - ); - } // TODO: Check flags & Ref + if (includeWorkInProgressEffects && flags & Callback) { + commitClassCallbacks(finishedWork); + } // TODO: Check flags & RefStatic - safelyAttachRef(finishedWork, finishedWork.return); - break; - } - default: { - recursivelyTraverseReappearLayoutEffects( - finishedRoot, - finishedWork, - includeWorkInProgressEffects - ); - break; - } + 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: { + // ... + // } - 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) + 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 prevDebugFiber = getCurrentFiber(); - var child = parentFiber.child; + if (includeWorkInProgressEffects && current === null && flags & Update) { + commitHostComponentMount(finishedWork); + } // TODO: Check flags & Ref - while (child !== null) { - var current = child.alternate; - reappearLayoutEffects( - finishedRoot, - current, - child, - childShouldIncludeWorkInProgressEffects - ); - child = child.sibling; - } - setCurrentFiber(prevDebugFiber); - } + safelyAttachRef(finishedWork, finishedWork.return); + break; + } - function commitHookPassiveMountEffects(finishedWork, hookFlags) { - if (shouldProfile(finishedWork)) { - startPassiveEffectTimer(); + case Profiler: + { + recursivelyTraverseReappearLayoutEffects(finishedRoot, finishedWork, includeWorkInProgressEffects); // TODO: Figure out how Profiler updates should work with Offscreen - try { - commitHookEffectListMount(hookFlags, finishedWork); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); + if (includeWorkInProgressEffects && flags & Update) { + commitProfilerUpdate(finishedWork, current); } - recordPassiveEffectDuration(finishedWork); - } else { - try { - commitHookEffectListMount(hookFlags, finishedWork); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } + break; } - } - function commitOffscreenPassiveMountEffects( - current, - finishedWork, - instance - ) { + case SuspenseComponent: { - var previousCache = null; - - if ( - current !== null && - current.memoizedState !== null && - current.memoizedState.cachePool !== null - ) { - previousCache = current.memoizedState.cachePool.pool; - } + recursivelyTraverseReappearLayoutEffects(finishedRoot, finishedWork, includeWorkInProgressEffects); // TODO: Figure out how Suspense hydration callbacks should work - var nextCache = null; - - if ( - finishedWork.memoizedState !== null && - finishedWork.memoizedState.cachePool !== null - ) { - nextCache = finishedWork.memoizedState.cachePool.pool; - } // Retain/release the cache used for pending (suspended) nodes. - // Note that this is only reached in the non-suspended/visible case: - // when the content is suspended/hidden, the retain/release occurs - // via the parent Suspense component (see case above). - - if (nextCache !== previousCache) { - if (nextCache != null) { - retainCache(nextCache); - } - - if (previousCache != null) { - releaseCache(previousCache); - } - } + break; } - } - function commitCachePassiveMountEffect(current, finishedWork) { + case OffscreenComponent: { - var previousCache = null; - - if (finishedWork.alternate !== null) { - previousCache = finishedWork.alternate.memoizedState.cache; - } + var offscreenState = finishedWork.memoizedState; + var isHidden = offscreenState !== null; - var nextCache = finishedWork.memoizedState.cache; // Retain/release the cache. In theory the cache component - // could be "borrowing" a cache instance owned by some parent, - // in which case we could avoid retaining/releasing. But it - // is non-trivial to determine when that is the case, so we - // always retain/release. + if (isHidden) ; else { + recursivelyTraverseReappearLayoutEffects(finishedRoot, finishedWork, includeWorkInProgressEffects); + } // TODO: Check flags & Ref - if (nextCache !== previousCache) { - retainCache(nextCache); - if (previousCache != null) { - releaseCache(previousCache); - } - } + safelyAttachRef(finishedWork, finishedWork.return); + break; } - } - function commitPassiveMountEffects( - root, - finishedWork, - committedLanes, - committedTransitions - ) { - setCurrentFiber(finishedWork); - commitPassiveMountOnFiber( - root, - finishedWork, - committedLanes, - committedTransitions - ); - 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, - committedLanes, - committedTransitions - ); - child = child.sibling; - } + default: + { + recursivelyTraverseReappearLayoutEffects(finishedRoot, finishedWork, includeWorkInProgressEffects); + break; } + } +} - 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 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) - switch (finishedWork.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - recursivelyTraversePassiveMountEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions - ); - - if (flags & Passive$1) { - commitHookPassiveMountEffects(finishedWork, Passive | HasEffect); - } + var prevDebugFiber = getCurrentFiber(); + var child = parentFiber.child; - break; - } + while (child !== null) { + var current = child.alternate; + reappearLayoutEffects(finishedRoot, current, child, childShouldIncludeWorkInProgressEffects); + child = child.sibling; + } - case HostRoot: { - recursivelyTraversePassiveMountEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions - ); + setCurrentFiber(prevDebugFiber); +} - if (flags & Passive$1) { - { - var previousCache = null; +function commitHookPassiveMountEffects(finishedWork, hookFlags) { + if (shouldProfile(finishedWork)) { + startPassiveEffectTimer(); - if (finishedWork.alternate !== null) { - previousCache = finishedWork.alternate.memoizedState.cache; - } + try { + commitHookEffectListMount(hookFlags, finishedWork); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } - var nextCache = finishedWork.memoizedState.cache; // Retain/release the root cache. - // Note that on initial mount, previousCache and nextCache will be the same - // and this retain won't occur. To counter this, we instead retain the HostRoot's - // initial cache when creating the root itself (see createFiberRoot() in - // ReactFiberRoot.js). Subsequent updates that change the cache are reflected - // here, such that previous/next caches are retained correctly. + recordPassiveEffectDuration(finishedWork); + } else { + try { + commitHookEffectListMount(hookFlags, finishedWork); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } + } +} - if (nextCache !== previousCache) { - retainCache(nextCache); +function commitOffscreenPassiveMountEffects(current, finishedWork, instance) { + { + var previousCache = null; - if (previousCache != null) { - releaseCache(previousCache); - } - } - } - } + if (current !== null && current.memoizedState !== null && current.memoizedState.cachePool !== null) { + previousCache = current.memoizedState.cachePool.pool; + } - break; - } + var nextCache = null; - case LegacyHiddenComponent: { - break; - } + if (finishedWork.memoizedState !== null && finishedWork.memoizedState.cachePool !== null) { + nextCache = finishedWork.memoizedState.cachePool.pool; + } // Retain/release the cache used for pending (suspended) nodes. + // Note that this is only reached in the non-suspended/visible case: + // when the content is suspended/hidden, the retain/release occurs + // via the parent Suspense component (see case above). - case OffscreenComponent: { - // TODO: Pass `current` as argument to this function - var _instance3 = finishedWork.stateNode; - var nextState = finishedWork.memoizedState; - var isHidden = nextState !== null; - if (isHidden) { - if (_instance3._visibility & OffscreenPassiveEffectsConnected) { - // The effects are currently connected. Update them. - recursivelyTraversePassiveMountEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions - ); - } else { - if (finishedWork.mode & ConcurrentMode) { - // The effects are currently disconnected. Since the tree is hidden, - // don't connect them. This also applies to the initial render. - { - // "Atomic" effects are ones that need to fire on every commit, - // even during pre-rendering. An example is updating the reference - // count on cache instances. - recursivelyTraverseAtomicPassiveEffects( - finishedRoot, - finishedWork - ); - } - } else { - // Legacy Mode: Fire the effects even if the tree is hidden. - _instance3._visibility |= OffscreenPassiveEffectsConnected; - recursivelyTraversePassiveMountEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions - ); - } - } - } else { - // Tree is visible - if (_instance3._visibility & OffscreenPassiveEffectsConnected) { - // The effects are currently connected. Update them. - recursivelyTraversePassiveMountEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions - ); - } 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; - var includeWorkInProgressEffects = - (finishedWork.subtreeFlags & PassiveMask) !== NoFlags$1; - recursivelyTraverseReconnectPassiveEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions, - includeWorkInProgressEffects - ); - } - } + if (nextCache !== previousCache) { + if (nextCache != null) { + retainCache(nextCache); + } - if (flags & Passive$1) { - var _current = finishedWork.alternate; - commitOffscreenPassiveMountEffects(_current, finishedWork); - } + if (previousCache != null) { + releaseCache(previousCache); + } + } + } +} - break; - } +function commitCachePassiveMountEffect(current, finishedWork) { + { + var previousCache = null; - case CacheComponent: { - recursivelyTraversePassiveMountEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions - ); - - if (flags & Passive$1) { - // TODO: Pass `current` as argument to this function - var _current2 = finishedWork.alternate; - commitCachePassiveMountEffect(_current2, finishedWork); - } + if (finishedWork.alternate !== null) { + previousCache = finishedWork.alternate.memoizedState.cache; + } - break; - } + var nextCache = finishedWork.memoizedState.cache; // Retain/release the cache. In theory the cache component + // could be "borrowing" a cache instance owned by some parent, + // in which case we could avoid retaining/releasing. But it + // is non-trivial to determine when that is the case, so we + // always retain/release. - case TracingMarkerComponent: + if (nextCache !== previousCache) { + retainCache(nextCache); - default: { - recursivelyTraversePassiveMountEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions - ); - break; - } + if (previousCache != null) { + releaseCache(previousCache); } } + } +} - function recursivelyTraverseReconnectPassiveEffects( - finishedRoot, - parentFiber, - committedLanes, - committedTransitions, - 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 & PassiveMask) !== NoFlags$1; // TODO (Offscreen) Check: flags & (RefStatic | LayoutStatic) +function commitPassiveMountEffects(root, finishedWork, committedLanes, committedTransitions) { + setCurrentFiber(finishedWork); + commitPassiveMountOnFiber(root, finishedWork, committedLanes, committedTransitions); + resetCurrentFiber(); +} - var prevDebugFiber = getCurrentFiber(); - var child = parentFiber.child; +function recursivelyTraversePassiveMountEffects(root, parentFiber, committedLanes, committedTransitions) { + var prevDebugFiber = getCurrentFiber(); - while (child !== null) { - reconnectPassiveEffects( - finishedRoot, - child, - committedLanes, - committedTransitions, - childShouldIncludeWorkInProgressEffects - ); - child = child.sibling; - } + if (parentFiber.subtreeFlags & PassiveMask) { + var child = parentFiber.child; - setCurrentFiber(prevDebugFiber); + while (child !== null) { + setCurrentFiber(child); + commitPassiveMountOnFiber(root, child, committedLanes, committedTransitions); + 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 - ) { - var flags = finishedWork.flags; +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; - switch (finishedWork.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - recursivelyTraverseReconnectPassiveEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions, - includeWorkInProgressEffects - ); // TODO: Check for PassiveStatic flag - - 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: { - // ... - // } - - case LegacyHiddenComponent: { - break; + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: + { + recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork, committedLanes, committedTransitions); + + if (flags & Passive$1) { + commitHookPassiveMountEffects(finishedWork, Passive | HasEffect); } - case OffscreenComponent: { - var _instance4 = finishedWork.stateNode; - var nextState = finishedWork.memoizedState; - var isHidden = nextState !== null; + break; + } - if (isHidden) { - if (_instance4._visibility & OffscreenPassiveEffectsConnected) { - // The effects are currently connected. Update them. - recursivelyTraverseReconnectPassiveEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions, - includeWorkInProgressEffects - ); - } else { - if (finishedWork.mode & ConcurrentMode) { - // The effects are currently disconnected. Since the tree is hidden, - // don't connect them. This also applies to the initial render. - { - // "Atomic" effects are ones that need to fire on every commit, - // even during pre-rendering. An example is updating the reference - // count on cache instances. - recursivelyTraverseAtomicPassiveEffects( - finishedRoot, - finishedWork - ); - } - } else { - // Legacy Mode: Fire the effects even if the tree is hidden. - _instance4._visibility |= OffscreenPassiveEffectsConnected; - recursivelyTraverseReconnectPassiveEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions, - includeWorkInProgressEffects - ); + case HostRoot: + { + recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork, committedLanes, committedTransitions); + + if (flags & Passive$1) { + { + var previousCache = null; + + if (finishedWork.alternate !== null) { + previousCache = finishedWork.alternate.memoizedState.cache; + } + + var nextCache = finishedWork.memoizedState.cache; // Retain/release the root cache. + // Note that on initial mount, previousCache and nextCache will be the same + // and this retain won't occur. To counter this, we instead retain the HostRoot's + // initial cache when creating the root itself (see createFiberRoot() in + // ReactFiberRoot.js). Subsequent updates that change the cache are reflected + // here, such that previous/next caches are retained correctly. + + if (nextCache !== previousCache) { + retainCache(nextCache); + + if (previousCache != null) { + releaseCache(previousCache); } } - } 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, - committedLanes, - committedTransitions, - includeWorkInProgressEffects - ); } + } - if (includeWorkInProgressEffects && flags & Passive$1) { - // TODO: Pass `current` as argument to this function - var _current3 = finishedWork.alternate; - commitOffscreenPassiveMountEffects(_current3, finishedWork); - } + break; + } - break; - } + case LegacyHiddenComponent: + { - case CacheComponent: { - recursivelyTraverseReconnectPassiveEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions, - includeWorkInProgressEffects - ); - - if (includeWorkInProgressEffects && flags & Passive$1) { - // TODO: Pass `current` as argument to this function - var _current4 = finishedWork.alternate; - commitCachePassiveMountEffect(_current4, finishedWork); - } + break; + } - break; + case OffscreenComponent: + { + // TODO: Pass `current` as argument to this function + var _instance3 = finishedWork.stateNode; + var nextState = finishedWork.memoizedState; + var isHidden = nextState !== null; + + if (isHidden) { + if (_instance3._visibility & OffscreenPassiveEffectsConnected) { + // The effects are currently connected. Update them. + recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork, committedLanes, committedTransitions); + } else { + if (finishedWork.mode & ConcurrentMode) { + // The effects are currently disconnected. Since the tree is hidden, + // don't connect them. This also applies to the initial render. + { + // "Atomic" effects are ones that need to fire on every commit, + // even during pre-rendering. An example is updating the reference + // count on cache instances. + recursivelyTraverseAtomicPassiveEffects(finishedRoot, finishedWork); + } + } else { + // Legacy Mode: Fire the effects even if the tree is hidden. + _instance3._visibility |= OffscreenPassiveEffectsConnected; + recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork, committedLanes, committedTransitions); + } + } + } else { + // Tree is visible + if (_instance3._visibility & OffscreenPassiveEffectsConnected) { + // The effects are currently connected. Update them. + recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork, committedLanes, committedTransitions); + } 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; + var includeWorkInProgressEffects = (finishedWork.subtreeFlags & PassiveMask) !== NoFlags$1; + recursivelyTraverseReconnectPassiveEffects(finishedRoot, finishedWork, committedLanes, committedTransitions, includeWorkInProgressEffects); + } } - case TracingMarkerComponent: - - default: { - recursivelyTraverseReconnectPassiveEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions, - includeWorkInProgressEffects - ); - break; + if (flags & Passive$1) { + var _current = finishedWork.alternate; + commitOffscreenPassiveMountEffects(_current, finishedWork); } - } - } - function recursivelyTraverseAtomicPassiveEffects( - finishedRoot, - parentFiber, - committedLanes, - committedTransitions - ) { - // "Atomic" effects are ones that need to fire on every commit, even during - // pre-rendering. We call this function when traversing a hidden tree whose - // regular effects are currently disconnected. - var prevDebugFiber = getCurrentFiber(); // TODO: Add special flag for atomic effects + break; + } - if (parentFiber.subtreeFlags & PassiveMask) { - var child = parentFiber.child; + case CacheComponent: + { + recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork, committedLanes, committedTransitions); - while (child !== null) { - setCurrentFiber(child); - commitAtomicPassiveEffects(finishedRoot, child); - child = child.sibling; + if (flags & Passive$1) { + // TODO: Pass `current` as argument to this function + var _current2 = finishedWork.alternate; + commitCachePassiveMountEffect(_current2, finishedWork); } + + break; } - setCurrentFiber(prevDebugFiber); - } + case TracingMarkerComponent: - function commitAtomicPassiveEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions - ) { - // "Atomic" effects are ones that need to fire on every commit, even during - // pre-rendering. We call this function when traversing a hidden tree whose - // regular effects are currently disconnected. - var flags = finishedWork.flags; + default: + { + recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork, committedLanes, committedTransitions); + break; + } + } +} - switch (finishedWork.tag) { - case OffscreenComponent: { - recursivelyTraverseAtomicPassiveEffects(finishedRoot, finishedWork); +function recursivelyTraverseReconnectPassiveEffects(finishedRoot, parentFiber, committedLanes, committedTransitions, 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 & PassiveMask) !== NoFlags$1; // TODO (Offscreen) Check: flags & (RefStatic | LayoutStatic) - if (flags & Passive$1) { - // TODO: Pass `current` as argument to this function - var current = finishedWork.alternate; - commitOffscreenPassiveMountEffects(current, finishedWork); - } + var prevDebugFiber = getCurrentFiber(); + var child = parentFiber.child; - break; - } + while (child !== null) { + reconnectPassiveEffects(finishedRoot, child, committedLanes, committedTransitions, childShouldIncludeWorkInProgressEffects); + child = child.sibling; + } - case CacheComponent: { - recursivelyTraverseAtomicPassiveEffects(finishedRoot, finishedWork); + setCurrentFiber(prevDebugFiber); +} - if (flags & Passive$1) { - // TODO: Pass `current` as argument to this function - var _current5 = finishedWork.alternate; - commitCachePassiveMountEffect(_current5, finishedWork); - } +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) { + var flags = finishedWork.flags; - break; - } + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: + { + recursivelyTraverseReconnectPassiveEffects(finishedRoot, finishedWork, committedLanes, committedTransitions, includeWorkInProgressEffects); // TODO: Check for PassiveStatic flag - default: { - recursivelyTraverseAtomicPassiveEffects(finishedRoot, finishedWork); - break; - } + 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: { + // ... + // } - function commitPassiveUnmountEffects(finishedWork) { - setCurrentFiber(finishedWork); - commitPassiveUnmountOnFiber(finishedWork); - resetCurrentFiber(); - } // If we're inside a brand new tree, or a tree that was already visible, then we - // should only suspend host components that have a ShouldSuspendCommit flag. - // Components without it haven't changed since the last commit, so we can skip - // over those. - // - // When we enter a tree that is being revealed (going from hidden -> visible), - // we need to suspend _any_ component that _may_ suspend. Even if they're - // already in the "current" tree. Because their visibility has changed, the - // browser may not have prerendered them yet. So we check the MaySuspendCommit - // flag instead. - - var suspenseyCommitFlag = ShouldSuspendCommit; - function accumulateSuspenseyCommit(finishedWork) { - accumulateSuspenseyCommitOnFiber(finishedWork); - } - - function recursivelyAccumulateSuspenseyCommit(parentFiber) { - if (parentFiber.subtreeFlags & suspenseyCommitFlag) { - var child = parentFiber.child; + case LegacyHiddenComponent: + { - while (child !== null) { - accumulateSuspenseyCommitOnFiber(child); - child = child.sibling; - } + break; } - } - function accumulateSuspenseyCommitOnFiber(fiber) { - switch (fiber.tag) { - case HostHoistable: { - recursivelyAccumulateSuspenseyCommit(fiber); + case OffscreenComponent: + { + var _instance4 = finishedWork.stateNode; + var nextState = finishedWork.memoizedState; + var isHidden = nextState !== null; - if (fiber.flags & suspenseyCommitFlag) { - if (fiber.memoizedState !== null) { - suspendResource(); + if (isHidden) { + if (_instance4._visibility & OffscreenPassiveEffectsConnected) { + // The effects are currently connected. Update them. + recursivelyTraverseReconnectPassiveEffects(finishedRoot, finishedWork, committedLanes, committedTransitions, includeWorkInProgressEffects); + } else { + if (finishedWork.mode & ConcurrentMode) { + // The effects are currently disconnected. Since the tree is hidden, + // don't connect them. This also applies to the initial render. + { + // "Atomic" effects are ones that need to fire on every commit, + // even during pre-rendering. An example is updating the reference + // count on cache instances. + recursivelyTraverseAtomicPassiveEffects(finishedRoot, finishedWork); + } + } else { + // Legacy Mode: Fire the effects even if the tree is hidden. + _instance4._visibility |= OffscreenPassiveEffectsConnected; + recursivelyTraverseReconnectPassiveEffects(finishedRoot, finishedWork, committedLanes, committedTransitions, includeWorkInProgressEffects); } } - - break; + } 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, committedLanes, committedTransitions, includeWorkInProgressEffects); } - case HostComponent: { - recursivelyAccumulateSuspenseyCommit(fiber); - - break; + if (includeWorkInProgressEffects && flags & Passive$1) { + // TODO: Pass `current` as argument to this function + var _current3 = finishedWork.alternate; + commitOffscreenPassiveMountEffects(_current3, finishedWork); } - case HostRoot: - case HostPortal: { - { - recursivelyAccumulateSuspenseyCommit(fiber); - } + break; + } - break; + case CacheComponent: + { + recursivelyTraverseReconnectPassiveEffects(finishedRoot, finishedWork, committedLanes, committedTransitions, includeWorkInProgressEffects); + + if (includeWorkInProgressEffects && flags & Passive$1) { + // TODO: Pass `current` as argument to this function + var _current4 = finishedWork.alternate; + commitCachePassiveMountEffect(_current4, finishedWork); } - case OffscreenComponent: { - var isHidden = fiber.memoizedState !== null; + break; + } - if (isHidden); - else { - var current = fiber.alternate; - var wasHidden = current !== null && current.memoizedState !== null; + case TracingMarkerComponent: - if (wasHidden) { - // This tree is being revealed. Visit all newly visible suspensey - // instances, even if they're in the current tree. - var prevFlags = suspenseyCommitFlag; - suspenseyCommitFlag = MaySuspendCommit; - recursivelyAccumulateSuspenseyCommit(fiber); - suspenseyCommitFlag = prevFlags; - } else { - recursivelyAccumulateSuspenseyCommit(fiber); - } - } + default: + { + recursivelyTraverseReconnectPassiveEffects(finishedRoot, finishedWork, committedLanes, committedTransitions, includeWorkInProgressEffects); + break; + } + } +} - break; - } +function recursivelyTraverseAtomicPassiveEffects(finishedRoot, parentFiber, committedLanes, committedTransitions) { + // "Atomic" effects are ones that need to fire on every commit, even during + // pre-rendering. We call this function when traversing a hidden tree whose + // regular effects are currently disconnected. + var prevDebugFiber = getCurrentFiber(); // TODO: Add special flag for atomic effects - default: { - recursivelyAccumulateSuspenseyCommit(fiber); - } - } - } + if (parentFiber.subtreeFlags & PassiveMask) { + var child = parentFiber.child; - 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; + while (child !== null) { + setCurrentFiber(child); + commitAtomicPassiveEffects(finishedRoot, child); + child = child.sibling; + } + } - if (previousFiber !== null) { - var detachedChild = previousFiber.child; + setCurrentFiber(prevDebugFiber); +} - if (detachedChild !== null) { - previousFiber.child = null; +function commitAtomicPassiveEffects(finishedRoot, finishedWork, committedLanes, committedTransitions) { + // "Atomic" effects are ones that need to fire on every commit, even during + // pre-rendering. We call this function when traversing a hidden tree whose + // regular effects are currently disconnected. + var flags = finishedWork.flags; - do { - // $FlowFixMe[incompatible-use] found when upgrading Flow - var detachedSibling = detachedChild.sibling; // $FlowFixMe[incompatible-use] found when upgrading Flow + switch (finishedWork.tag) { + case OffscreenComponent: + { + recursivelyTraverseAtomicPassiveEffects(finishedRoot, finishedWork); - detachedChild.sibling = null; - detachedChild = detachedSibling; - } while (detachedChild !== null); + if (flags & Passive$1) { + // TODO: Pass `current` as argument to this function + var current = finishedWork.alternate; + commitOffscreenPassiveMountEffects(current, finishedWork); } - } - } - function commitHookPassiveUnmountEffects( - finishedWork, - nearestMountedAncestor, - hookFlags - ) { - if (shouldProfile(finishedWork)) { - startPassiveEffectTimer(); - commitHookEffectListUnmount( - hookFlags, - finishedWork, - nearestMountedAncestor - ); - recordPassiveEffectDuration(finishedWork); - } else { - commitHookEffectListUnmount( - hookFlags, - finishedWork, - nearestMountedAncestor - ); + break; } - } - 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 ((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 + case CacheComponent: + { + recursivelyTraverseAtomicPassiveEffects(finishedRoot, finishedWork); - nextEffect = childToDelete; - commitPassiveUnmountEffectsInsideOfDeletedTree_begin( - childToDelete, - parentFiber - ); - } + if (flags & Passive$1) { + // TODO: Pass `current` as argument to this function + var _current5 = finishedWork.alternate; + commitCachePassiveMountEffect(_current5, finishedWork); } - detachAlternateSiblings(parentFiber); + break; } - var prevDebugFiber = getCurrentFiber(); // TODO: Split PassiveMask into separate masks for mount and unmount? + default: + { + recursivelyTraverseAtomicPassiveEffects(finishedRoot, finishedWork); + break; + } + } +} - if (parentFiber.subtreeFlags & PassiveMask) { - var child = parentFiber.child; +function commitPassiveUnmountEffects(finishedWork) { + setCurrentFiber(finishedWork); + commitPassiveUnmountOnFiber(finishedWork); + resetCurrentFiber(); +} // If we're inside a brand new tree, or a tree that was already visible, then we +// should only suspend host components that have a ShouldSuspendCommit flag. +// Components without it haven't changed since the last commit, so we can skip +// over those. +// +// When we enter a tree that is being revealed (going from hidden -> visible), +// we need to suspend _any_ component that _may_ suspend. Even if they're +// already in the "current" tree. Because their visibility has changed, the +// browser may not have prerendered them yet. So we check the MaySuspendCommit +// flag instead. + +var suspenseyCommitFlag = ShouldSuspendCommit; +function accumulateSuspenseyCommit(finishedWork) { + accumulateSuspenseyCommitOnFiber(finishedWork); +} - while (child !== null) { - setCurrentFiber(child); - commitPassiveUnmountOnFiber(child); - child = child.sibling; - } - } +function recursivelyAccumulateSuspenseyCommit(parentFiber) { + if (parentFiber.subtreeFlags & suspenseyCommitFlag) { + var child = parentFiber.child; - setCurrentFiber(prevDebugFiber); + while (child !== null) { + accumulateSuspenseyCommitOnFiber(child); + child = child.sibling; } + } +} - function commitPassiveUnmountOnFiber(finishedWork) { - switch (finishedWork.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - recursivelyTraversePassiveUnmountEffects(finishedWork); +function accumulateSuspenseyCommitOnFiber(fiber) { + switch (fiber.tag) { + case HostHoistable: + { + recursivelyAccumulateSuspenseyCommit(fiber); - if (finishedWork.flags & Passive$1) { - commitHookPassiveUnmountEffects( - finishedWork, - finishedWork.return, - Passive | HasEffect - ); + if (fiber.flags & suspenseyCommitFlag) { + if (fiber.memoizedState !== null) { + suspendResource(); } - - break; } - case OffscreenComponent: { - var instance = finishedWork.stateNode; - var nextState = finishedWork.memoizedState; - var isHidden = nextState !== null; - - 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); - } + break; + } - break; - } + case HostComponent: + { + recursivelyAccumulateSuspenseyCommit(fiber); - default: { - recursivelyTraversePassiveUnmountEffects(finishedWork); - break; + break; + } + + case HostRoot: + case HostPortal: + { + { + recursivelyAccumulateSuspenseyCommit(fiber); } + + break; } - } - 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; + case OffscreenComponent: + { + var isHidden = fiber.memoizedState !== null; - 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 (isHidden) ; else { + var current = fiber.alternate; + var wasHidden = current !== null && current.memoizedState !== null; - nextEffect = childToDelete; - commitPassiveUnmountEffectsInsideOfDeletedTree_begin( - childToDelete, - parentFiber - ); + if (wasHidden) { + // This tree is being revealed. Visit all newly visible suspensey + // instances, even if they're in the current tree. + var prevFlags = suspenseyCommitFlag; + suspenseyCommitFlag = MaySuspendCommit; + recursivelyAccumulateSuspenseyCommit(fiber); + suspenseyCommitFlag = prevFlags; + } else { + recursivelyAccumulateSuspenseyCommit(fiber); } } - detachAlternateSiblings(parentFiber); + break; } - var prevDebugFiber = getCurrentFiber(); // TODO: Check PassiveStatic flag - - var child = parentFiber.child; - - while (child !== null) { - setCurrentFiber(child); - disconnectPassiveEffect(child); - child = child.sibling; + default: + { + recursivelyAccumulateSuspenseyCommit(fiber); } + } +} - setCurrentFiber(prevDebugFiber); - } +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; - 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 + do { + // $FlowFixMe[incompatible-use] found when upgrading Flow + var detachedSibling = detachedChild.sibling; // $FlowFixMe[incompatible-use] found when upgrading Flow - recursivelyTraverseDisconnectPassiveEffects(finishedWork); - break; - } + detachedChild.sibling = null; + detachedChild = detachedSibling; + } while (detachedChild !== null); + } + } +} - case OffscreenComponent: { - var instance = finishedWork.stateNode; +function commitHookPassiveUnmountEffects(finishedWork, nearestMountedAncestor, hookFlags) { + if (shouldProfile(finishedWork)) { + startPassiveEffectTimer(); + commitHookEffectListUnmount(hookFlags, finishedWork, nearestMountedAncestor); + recordPassiveEffectDuration(finishedWork); + } else { + commitHookEffectListUnmount(hookFlags, finishedWork, nearestMountedAncestor); + } +} - if (instance._visibility & OffscreenPassiveEffectsConnected) { - instance._visibility &= ~OffscreenPassiveEffectsConnected; - recursivelyTraverseDisconnectPassiveEffects(finishedWork); - } +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; - break; - } + 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 - default: { - recursivelyTraverseDisconnectPassiveEffects(finishedWork); - break; - } + nextEffect = childToDelete; + commitPassiveUnmountEffectsInsideOfDeletedTree_begin(childToDelete, parentFiber); } } - 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 + detachAlternateSiblings(parentFiber); + } - setCurrentFiber(fiber); - commitPassiveUnmountInsideDeletedTreeOnFiber( - fiber, - nearestMountedAncestor - ); - resetCurrentFiber(); - var child = fiber.child; // TODO: Only traverse subtree if it has a PassiveStatic flag. + var prevDebugFiber = getCurrentFiber(); // TODO: Split PassiveMask into separate masks for mount and unmount? - if (child !== null) { - child.return = fiber; - nextEffect = child; - } else { - commitPassiveUnmountEffectsInsideOfDeletedTree_complete( - deletedSubtreeRoot - ); - } - } + if (parentFiber.subtreeFlags & PassiveMask) { + var child = parentFiber.child; + + while (child !== null) { + setCurrentFiber(child); + commitPassiveUnmountOnFiber(child); + child = child.sibling; } + } - 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. + setCurrentFiber(prevDebugFiber); +} - detachFiberAfterEffects(fiber); +function commitPassiveUnmountOnFiber(finishedWork) { + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: + { + recursivelyTraversePassiveUnmountEffects(finishedWork); - if (fiber === deletedSubtreeRoot) { - nextEffect = null; - return; + if (finishedWork.flags & Passive$1) { + commitHookPassiveUnmountEffects(finishedWork, finishedWork.return, Passive | HasEffect); } - if (sibling !== null) { - sibling.return = returnFiber; - nextEffect = sibling; - return; + break; + } + + case OffscreenComponent: + { + var instance = finishedWork.stateNode; + var nextState = finishedWork.memoizedState; + var isHidden = nextState !== null; + + 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); } - nextEffect = returnFiber; + break; + } + + default: + { + recursivelyTraversePassiveUnmountEffects(finishedWork); + break; + } + } +} + +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; + + 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); } } - function commitPassiveUnmountInsideDeletedTreeOnFiber( - current, - nearestMountedAncestor - ) { - switch (current.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - commitHookPassiveUnmountEffects( - current, - nearestMountedAncestor, - Passive - ); - break; - } - // TODO: run passive unmount effects when unmounting a root. - // Because passive unmount effects are not currently run, - // the cache instance owned by the root will never be freed. - // When effects are run, the cache should be freed here: - // case HostRoot: { - // if (enableCache) { - // const cache = current.memoizedState.cache; - // releaseCache(cache); - // } - // break; - // } - - case LegacyHiddenComponent: - case OffscreenComponent: { - { - if ( - current.memoizedState !== null && - current.memoizedState.cachePool !== null - ) { - var cache = current.memoizedState.cachePool.pool; // Retain/release the cache used for pending (suspended) nodes. - // Note that this is only reached in the non-suspended/visible case: - // when the content is suspended/hidden, the retain/release occurs - // via the parent Suspense component (see case above). - - if (cache != null) { - retainCache(cache); - } - } - } + detachAlternateSiblings(parentFiber); + } - break; - } + var prevDebugFiber = getCurrentFiber(); // TODO: Check PassiveStatic flag - case SuspenseComponent: { - break; - } + var child = parentFiber.child; - case CacheComponent: { - { - var _cache = current.memoizedState.cache; - releaseCache(_cache); - } + while (child !== null) { + setCurrentFiber(child); + disconnectPassiveEffect(child); + child = child.sibling; + } - break; + setCurrentFiber(prevDebugFiber); +} + +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 + + recursivelyTraverseDisconnectPassiveEffects(finishedWork); + break; + } + + case OffscreenComponent: + { + var instance = finishedWork.stateNode; + + if (instance._visibility & OffscreenPassiveEffectsConnected) { + instance._visibility &= ~OffscreenPassiveEffectsConnected; + recursivelyTraverseDisconnectPassiveEffects(finishedWork); } + + break; } - } - function invokeLayoutEffectMountInDEV(fiber) { + default: { - // 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); - } + recursivelyTraverseDisconnectPassiveEffects(finishedWork); + break; + } + } +} - break; - } +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 - case ClassComponent: { - var instance = fiber.stateNode; + setCurrentFiber(fiber); + commitPassiveUnmountInsideDeletedTreeOnFiber(fiber, nearestMountedAncestor); + resetCurrentFiber(); + var child = fiber.child; // TODO: Only traverse subtree if it has a PassiveStatic flag. - if (typeof instance.componentDidMount === "function") { - try { - instance.componentDidMount(); - } catch (error) { - captureCommitPhaseError(fiber, fiber.return, error); - } - } + if (child !== null) { + child.return = fiber; + nextEffect = child; + } else { + commitPassiveUnmountEffectsInsideOfDeletedTree_complete(deletedSubtreeRoot); + } + } +} - break; - } - } - } +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; + return; + } + + if (sibling !== null) { + sibling.return = returnFiber; + nextEffect = sibling; + return; } - function invokePassiveEffectMountInDEV(fiber) { + nextEffect = returnFiber; + } +} + +function commitPassiveUnmountInsideDeletedTreeOnFiber(current, nearestMountedAncestor) { + switch (current.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: + { + commitHookPassiveUnmountEffects(current, nearestMountedAncestor, Passive); + break; + } + // TODO: run passive unmount effects when unmounting a root. + // Because passive unmount effects are not currently run, + // the cache instance owned by the root will never be freed. + // When effects are run, the cache should be freed here: + // case HostRoot: { + // if (enableCache) { + // const cache = current.memoizedState.cache; + // releaseCache(cache); + // } + // break; + // } + + case LegacyHiddenComponent: + case OffscreenComponent: { - // 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); + { + if (current.memoizedState !== null && current.memoizedState.cachePool !== null) { + var cache = current.memoizedState.cachePool.pool; // Retain/release the cache used for pending (suspended) nodes. + // Note that this is only reached in the non-suspended/visible case: + // when the content is suspended/hidden, the retain/release occurs + // via the parent Suspense component (see case above). + + if (cache != null) { + retainCache(cache); } - - break; } } + + break; } - } - function invokeLayoutEffectUnmountInDEV(fiber) { + case SuspenseComponent: { - // 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); - } - break; - } + break; + } - case ClassComponent: { - var instance = fiber.stateNode; + case CacheComponent: + { + { + var _cache = current.memoizedState.cache; + releaseCache(_cache); + } - if (typeof instance.componentWillUnmount === "function") { - safelyCallComponentWillUnmount(fiber, fiber.return, instance); - } + break; + } + } +} - break; +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); } + + 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: { + case ClassComponent: + { + var instance = fiber.stateNode; + + if (typeof instance.componentDidMount === 'function') { try { - commitHookEffectListUnmount( - Passive | HasEffect, - fiber, - fiber.return - ); + instance.componentDidMount(); } catch (error) { captureCommitPhaseError(fiber, fiber.return, error); } } - } - } - } - function getCacheForType(resourceType) { - var cache = readContext(CacheContext); - var cacheForType = cache.data.get(resourceType); - - if (cacheForType === undefined) { - cacheForType = resourceType(); - cache.data.set(resourceType, cacheForType); - } - - return cacheForType; + break; + } } + } +} - var DefaultCacheDispatcher = { - getCacheForType: getCacheForType - }; +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); + } - 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"); + break; + } } + } +} - 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. - 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; // $FlowFixMe[cannot-resolve-name] - Flow doesn't know about jest +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); + } - var jestIsDefined = typeof jest !== "undefined"; - return jestIsDefined && isReactActEnvironmentGlobal !== false; - } - } - 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 && - ReactSharedInternals.actQueue !== null - ) { - // TODO: Include link to relevant documentation page. - error( - "The current testing environment is not configured to support " + - "act(...)" - ); + break; } - return isReactActEnvironmentGlobal; - } - } - - var PossiblyWeakMap = typeof WeakMap === "function" ? WeakMap : Map; - 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 executionContext = NoContext; // The root we're working on - - var workInProgressRoot = null; // The fiber we're working on - - var workInProgress = null; // The lanes we're rendering - - 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 entangledRenderLanes. + case ClassComponent: + { + var instance = fiber.stateNode; - var entangledRenderLanes = NoLanes; // Whether to root completed, errored, suspended, etc. + if (typeof instance.componentWillUnmount === 'function') { + safelyCallComponentWillUnmount(fiber, fiber.return, instance); + } - var workInProgressRootExitStatus = RootInProgress; // The work left over by components that were visited during this render. Only - // includes unprocessed updates, not work in bailed out children. + break; + } + } + } +} - var workInProgressRootSkippedLanes = NoLanes; // Lanes that were updated (in an interleaved event) during this render. +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); + } + } + } + } +} - var workInProgressRootInterleavedUpdatedLanes = NoLanes; // Lanes that were updated during the render phase (*not* an interleaved event). +function getCacheForType(resourceType) { - var workInProgressRootPingedLanes = NoLanes; // If this lane scheduled deferred work, this is the lane of the deferred task. + var cache = readContext(CacheContext); + var cacheForType = cache.data.get(resourceType); - var workInProgressDeferredLane = NoLane; // Errors that are thrown during the render phase. + if (cacheForType === undefined) { + cacheForType = resourceType(); + cache.data.set(resourceType, cacheForType); + } - var workInProgressRootConcurrentErrors = null; // These are errors that we recovered from without surfacing them to the UI. - // We will log them once the tree commits. + return cacheForType; +} - var workInProgressRootRecoverableErrors = null; // Tracks when an update occurs during the render phase. +var DefaultCacheDispatcher = { + getCacheForType: getCacheForType +}; + +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'); +} - var workInProgressRootDidIncludeRecursiveRenderUpdate = false; // Thacks when an update occurs during the commit phase. It's a separate - // filled in with the resolved UI. This lets us throttle the appearance of new - // content as it streams in, to minimize jank. - // TODO: Think of a better name for this variable? +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. + 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; // $FlowFixMe[cannot-resolve-name] - Flow doesn't know about jest + + var jestIsDefined = typeof jest !== 'undefined'; + return jestIsDefined && isReactActEnvironmentGlobal !== false; + } +} +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; - var globalMostRecentFallbackTime = 0; - var FALLBACK_THROTTLE_MS = 300; // The absolute time for when we should start giving up on rendering - // more and prefer CPU suspense heuristics instead. + if (!isReactActEnvironmentGlobal && ReactSharedInternals.actQueue !== null) { + // TODO: Include link to relevant documentation page. + error('The current testing environment is not configured to support ' + 'act(...)'); + } - 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. + return isReactActEnvironmentGlobal; + } +} - var RENDER_TIMEOUT_MS = 500; - var workInProgressTransitions = null; +var PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map; +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 executionContext = NoContext; // The root we're working on + +var workInProgressRoot = null; // The fiber we're working on + +var workInProgress = null; // The lanes we're rendering + +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 entangledRenderLanes. + +var entangledRenderLanes = NoLanes; // Whether to root completed, errored, suspended, etc. + +var workInProgressRootExitStatus = RootInProgress; // The work left over by components that were visited during this render. Only +// includes unprocessed updates, not work in bailed out children. + +var workInProgressRootSkippedLanes = NoLanes; // Lanes that were updated (in an interleaved event) during this render. + +var workInProgressRootInterleavedUpdatedLanes = NoLanes; // Lanes that were updated during the render phase (*not* an interleaved event). + +var workInProgressRootPingedLanes = NoLanes; // If this lane scheduled deferred work, this is the lane of the deferred task. + +var workInProgressDeferredLane = NoLane; // Errors that are thrown during the render phase. + +var workInProgressRootConcurrentErrors = null; // These are errors that we recovered from without surfacing them to the UI. +// We will log them once the tree commits. + +var workInProgressRootRecoverableErrors = null; // Tracks when an update occurs during the render phase. + +var workInProgressRootDidIncludeRecursiveRenderUpdate = false; // Thacks when an update occurs during the commit phase. It's a separate +// filled in with the resolved UI. This lets us throttle the appearance of new +// content as it streams in, to minimize jank. +// TODO: Think of a better name for this variable? + +var globalMostRecentFallbackTime = 0; +var FALLBACK_THROTTLE_MS = 300; // The absolute time for when we should start giving up on rendering +// more and prefer CPU suspense heuristics instead. + +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 RENDER_TIMEOUT_MS = 500; +var workInProgressTransitions = null; + +function resetRenderTimer() { + workInProgressRootRenderTargetTime = now$1() + RENDER_TIMEOUT_MS; +} - function resetRenderTimer() { - workInProgressRootRenderTargetTime = now$1() + RENDER_TIMEOUT_MS; - } +function getRenderTargetTime() { + return workInProgressRootRenderTargetTime; +} +var legacyErrorBoundariesThatAlreadyFailed = null; +var rootDoesHavePassiveEffects = false; +var rootWithPendingPassiveEffects = null; +var pendingPassiveEffectsLanes = NoLanes; +var pendingPassiveProfilerEffects = []; +var pendingPassiveEffectsRemainingLanes = NoLanes; +var pendingPassiveTransitions = null; // Use these to prevent an infinite loop of nested updates + +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; +var isRunningInsertionEffect = false; +function getWorkInProgressRoot() { + return workInProgressRoot; +} +function getWorkInProgressRootRenderLanes() { + return workInProgressRootRenderLanes; +} +function isWorkLoopSuspendedOnData() { + return workInProgressSuspendedReason === SuspendedOnData; +} +function requestUpdateLane(fiber) { + // Special cases + var mode = fiber.mode; + + 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); + } + + var transition = requestCurrentTransition(); + + if (transition !== null) { + { + if (!transition._updatedFibers) { + transition._updatedFibers = new Set(); + } - function getRenderTargetTime() { - return workInProgressRootRenderTargetTime; + transition._updatedFibers.add(fiber); } - var legacyErrorBoundariesThatAlreadyFailed = null; - var rootDoesHavePassiveEffects = false; - var rootWithPendingPassiveEffects = null; - var pendingPassiveEffectsLanes = NoLanes; - var pendingPassiveProfilerEffects = []; - var pendingPassiveEffectsRemainingLanes = NoLanes; - var pendingPassiveTransitions = null; // Use these to prevent an infinite loop of nested updates - 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; - var isRunningInsertionEffect = false; - function getWorkInProgressRoot() { - return workInProgressRoot; - } - function getWorkInProgressRootRenderLanes() { - return workInProgressRootRenderLanes; - } - function isWorkLoopSuspendedOnData() { - return workInProgressSuspendedReason === SuspendedOnData; - } - function requestUpdateLane(fiber) { - // Special cases - var mode = fiber.mode; + var actionScopeLane = peekEntangledActionLane(); + return actionScopeLane !== NoLane ? // We're inside an async action scope. Reuse the same lane. + actionScopeLane : // We may or may not be inside an async action scope. If we are, this + // is the first update in that scope. Either way, we need to get a + // fresh transition lane. + requestTransitionLane(); + } - 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); - } + return eventPriorityToLane(resolveUpdatePriority()); +} - var transition = requestCurrentTransition(); +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 (transition !== null) { - { - if (!transition._updatedFibers) { - transition._updatedFibers = new Set(); - } + if ((mode & ConcurrentMode) === NoMode) { + return SyncLane; + } - transition._updatedFibers.add(fiber); - } + return claimNextRetryLane(); +} - var actionScopeLane = peekEntangledActionLane(); - return actionScopeLane !== NoLane // We're inside an async action scope. Reuse the same lane. - ? actionScopeLane // We may or may not be inside an async action scope. If we are, this - : // is the first update in that scope. Either way, we need to get a - // fresh transition lane. - requestTransitionLane(); - } +function requestDeferredLane() { + if (workInProgressDeferredLane === NoLane) { + // If there are multiple useDeferredValue hooks in the same render, the + // tasks that they spawn should all be batched together, so they should all + // receive the same lane. + // Check the priority of the current render to decide the priority of the + // deferred task. + // OffscreenLane is used for prerendering, but we also use OffscreenLane + // for incremental hydration. It's given the lowest priority because the + // initial HTML is the same as the final UI. But useDeferredValue during + // hydration is an exception — we need to upgrade the UI to the final + // value. So if we're currently hydrating, we treat it like a transition. + var isPrerendering = includesSomeLane(workInProgressRootRenderLanes, OffscreenLane) && !getIsHydrating(); + + if (isPrerendering) { + // There's only one OffscreenLane, so if it contains deferred work, we + // should just reschedule using the same lane. + workInProgressDeferredLane = OffscreenLane; + } else { + // Everything else is spawned as a transition. + workInProgressDeferredLane = claimNextTransitionLane(); + } + } // Mark the parent Suspense boundary so it knows to spawn the deferred lane. + + + var suspenseHandler = getSuspenseHandler(); + + if (suspenseHandler !== null) { + // TODO: As an optimization, we shouldn't entangle the lanes at the root; we + // can entangle them using the baseLanes of the Suspense boundary instead. + // We only need to do something special if there's no Suspense boundary. + suspenseHandler.flags |= DidDefer; + } + + return workInProgressDeferredLane; +} +function peekDeferredLane() { + return workInProgressDeferredLane; +} +function scheduleUpdateOnFiber(root, fiber, lane) { + { + if (isRunningInsertionEffect) { + error('useInsertionEffect must not schedule updates.'); + } + } - return eventPriorityToLane(resolveUpdatePriority()); + { + if (isFlushingPassiveEffects) { + didScheduleUpdateDuringPassiveEffects = true; } + } // Check if the work loop is currently suspended and waiting for data to + // finish loading. - 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 ((mode & ConcurrentMode) === NoMode) { - return SyncLane; - } + if ( // Suspended render phase + root === workInProgressRoot && workInProgressSuspendedReason === SuspendedOnData || // Suspended commit phase + root.cancelPendingCommit !== null) { + // The incoming update might unblock the current render. Interrupt the + // current attempt and restart from the top. + prepareFreshStack(root, NoLanes); + markRootSuspended(root, workInProgressRootRenderLanes, workInProgressDeferredLane); + } // Mark that the root has a pending update. - return claimNextRetryLane(); - } - function requestDeferredLane() { - if (workInProgressDeferredLane === NoLane) { - // If there are multiple useDeferredValue hooks in the same render, the - // tasks that they spawn should all be batched together, so they should all - // receive the same lane. - // Check the priority of the current render to decide the priority of the - // deferred task. - // OffscreenLane is used for prerendering, but we also use OffscreenLane - // for incremental hydration. It's given the lowest priority because the - // initial HTML is the same as the final UI. But useDeferredValue during - // hydration is an exception — we need to upgrade the UI to the final - // value. So if we're currently hydrating, we treat it like a transition. - var isPrerendering = - includesSomeLane(workInProgressRootRenderLanes, OffscreenLane) && - !getIsHydrating(); + markRootUpdated(root, lane); - if (isPrerendering) { - // There's only one OffscreenLane, so if it contains deferred work, we - // should just reschedule using the same lane. - workInProgressDeferredLane = OffscreenLane; - } else { - // Everything else is spawned as a transition. - workInProgressDeferredLane = claimNextTransitionLane(); - } - } // Mark the parent Suspense boundary so it knows to spawn the deferred lane. + 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 { - var suspenseHandler = getSuspenseHandler(); + warnIfUpdatesNotWrappedWithActDEV(fiber); - if (suspenseHandler !== null) { - // TODO: As an optimization, we shouldn't entangle the lanes at the root; we - // can entangle them using the baseLanes of the Suspense boundary instead. - // We only need to do something special if there's no Suspense boundary. - suspenseHandler.flags |= DidDefer; + 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. + if ((executionContext & RenderContext) === NoContext) { + workInProgressRootInterleavedUpdatedLanes = mergeLanes(workInProgressRootInterleavedUpdatedLanes, lane); } - return workInProgressDeferredLane; - } - function peekDeferredLane() { - return workInProgressDeferredLane; - } - function scheduleUpdateOnFiber(root, fiber, lane) { - { - if (isRunningInsertionEffect) { - error("useInsertionEffect must not schedule updates."); - } + 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, workInProgressDeferredLane); } + } - { - if (isFlushingPassiveEffects) { - didScheduleUpdateDuringPassiveEffects = true; - } - } // Check if the work loop is currently suspended and waiting for data to - // finish loading. - - if ( - // Suspended render phase - (root === workInProgressRoot && - workInProgressSuspendedReason === SuspendedOnData) || // Suspended commit phase - root.cancelPendingCommit !== null - ) { - // The incoming update might unblock the current render. Interrupt the - // current attempt and restart from the top. - prepareFreshStack(root, NoLanes); - markRootSuspended( - root, - workInProgressRootRenderLanes, - workInProgressDeferredLane - ); - } // Mark that the root has a pending update. - - markRootUpdated(root, lane); - - 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 { - warnIfUpdatesNotWrappedWithActDEV(fiber); - - 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. - 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, - workInProgressDeferredLane - ); - } - } + ensureRootIsScheduled(root); - ensureRootIsScheduled(root); - - if ( - lane === SyncLane && - executionContext === NoContext && - !disableLegacyMode && - (fiber.mode & ConcurrentMode) === NoMode - ) { - if (ReactSharedInternals.isBatchingLegacy); - else { - // 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(); - flushSyncWorkOnLegacyRootsOnly(); - } - } + if (lane === SyncLane && executionContext === NoContext && !disableLegacyMode && (fiber.mode & ConcurrentMode) === NoMode) { + if (ReactSharedInternals.isBatchingLegacy) ; else { + // 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(); + flushSyncWorkOnLegacyRootsOnly(); } } - 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 (executionContext & RenderContext) !== NoContext; - } // This is the entry point for every concurrent task, i.e. anything that - // goes through Scheduler. + } +} +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 (executionContext & RenderContext) !== NoContext; +} // This is the entry point for every concurrent task, i.e. anything that +// goes through Scheduler. + +function performConcurrentWorkOnRoot(root, didTimeout) { + { + resetNestedUpdateFlag(); + } + + 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 originalCallbackNode = root.callbackNode; + var didFlushPassiveEffects = flushPassiveEffects(); + + 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. + // TODO: This was already computed in the caller. Pass it as an argument. - function performConcurrentWorkOnRoot(root, didTimeout) { - { - resetNestedUpdateFlag(); - } - 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 lanes = getNextLanes(root, root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes); - var originalCallbackNode = root.callbackNode; - var didFlushPassiveEffects = flushPassiveEffects(); + 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. - 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. - // TODO: This was already computed in the caller. Pass it as an argument. - var lanes = getNextLanes( - root, - root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes - ); + var shouldTimeSlice = !includesBlockingLane(root, lanes) && !includesExpiredLane(root, lanes) && (!didTimeout); + var exitStatus = shouldTimeSlice ? renderRootConcurrent(root, lanes) : renderRootSync(root, lanes); - 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. - - var shouldTimeSlice = - !includesBlockingLane(root, lanes) && - !includesExpiredLane(root, lanes) && - !didTimeout; - var exitStatus = shouldTimeSlice - ? renderRootConcurrent(root, lanes) - : renderRootSync(root, lanes); - - if (exitStatus !== RootInProgress) { - var renderWasConcurrent = shouldTimeSlice; + if (exitStatus !== RootInProgress) { + var renderWasConcurrent = shouldTimeSlice; - do { - 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, NoLane); - } 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 finishedWork = root.current.alternate; - - if ( - renderWasConcurrent && - !isRenderConsistentWithExternalStores(finishedWork) - ) { - // A store was mutated in an interleaved event. Render again, - // synchronously, to block further mutations. - exitStatus = renderRootSync(root, lanes); // We assume the tree is now consistent because we didn't yield to any - // concurrent events. - - renderWasConcurrent = false; // Need to check the exit status again. + do { + 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, NoLane); + } 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 finishedWork = root.current.alternate; + + if (renderWasConcurrent && !isRenderConsistentWithExternalStores(finishedWork)) { + // A store was mutated in an interleaved event. Render again, + // synchronously, to block further mutations. + exitStatus = renderRootSync(root, lanes); // We assume the tree is now consistent because we didn't yield to any + // concurrent events. + + renderWasConcurrent = false; // Need to check the exit status again. + continue; + } // Check if something threw + + + if (exitStatus === RootErrored) { + var lanesThatJustErrored = lanes; + var errorRetryLanes = getLanesToRetrySynchronouslyOnError(root, lanesThatJustErrored); + + if (errorRetryLanes !== NoLanes) { + lanes = errorRetryLanes; + exitStatus = recoverFromConcurrentError(root, lanesThatJustErrored, errorRetryLanes); + renderWasConcurrent = false; // Need to check the exit status again. + + if (exitStatus !== RootErrored) { + // The root did not error this time. Restart the exit algorithm + // from the beginning. + // TODO: Refactor the exit algorithm to be less confusing. Maybe + // more branches + recursion instead of a loop. I think the only + // thing that causes it to be a loop is the RootDidNotComplete + // check. If that's true, then we don't need a loop/recursion + // at all. continue; - } // Check if something threw - - if (exitStatus === RootErrored) { - var lanesThatJustErrored = lanes; - var errorRetryLanes = getLanesToRetrySynchronouslyOnError( - root, - lanesThatJustErrored - ); - - if (errorRetryLanes !== NoLanes) { - lanes = errorRetryLanes; - exitStatus = recoverFromConcurrentError( - root, - lanesThatJustErrored, - errorRetryLanes - ); - renderWasConcurrent = false; // Need to check the exit status again. - - if (exitStatus !== RootErrored) { - // The root did not error this time. Restart the exit algorithm - // from the beginning. - // TODO: Refactor the exit algorithm to be less confusing. Maybe - // more branches + recursion instead of a loop. I think the only - // thing that causes it to be a loop is the RootDidNotComplete - // check. If that's true, then we don't need a loop/recursion - // at all. - continue; - } - } } - - if (exitStatus === RootFatalErrored) { - prepareFreshStack(root, NoLanes); - markRootSuspended(root, lanes, NoLane); - break; - } // 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); } - - break; - } while (true); - } - - ensureRootIsScheduled(root); - return getContinuationForRoot(root, originalCallbackNode); - } - - 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 = supportsHydration; - - var exitStatus = renderRootSync(root, errorRetryLanes); - - 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. - - 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. - - 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 (errorsFromSecondAttempt !== null) { - queueRecoverableErrors(errorsFromSecondAttempt); - } - } - - return exitStatus; - } - - function queueRecoverableErrors(errors) { - if (workInProgressRootRecoverableErrors === null) { - workInProgressRootRecoverableErrors = errors; - } else { - // $FlowFixMe[method-unbinding] - workInProgressRootRecoverableErrors.push.apply( - workInProgressRootRecoverableErrors, - errors - ); - } - } - - function finishConcurrentRender(root, exitStatus, finishedWork, lanes) { - // TODO: The fact that most of these branches are identical suggests that some - // of the exit statuses are not best modeled as exit statuses and should be - // tracked orthogonally. - switch (exitStatus) { - case RootInProgress: - case RootFatalErrored: { - throw new Error("Root did not complete. This is a bug in React."); - } - - case RootSuspendedWithDelay: { - 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. - markRootSuspended(root, lanes, workInProgressDeferredLane); - return; - } // Commit the placeholder. - - break; } - case RootErrored: { - // This render errored. Ignore any recoverable errors because we weren't actually - // able to recover. Instead, whatever the final errors were is the ones we log. - // This ensures that we only log the actual client side error if it's just a plain - // error thrown from a component on the server and the client. - workInProgressRootRecoverableErrors = null; + if (exitStatus === RootFatalErrored) { + prepareFreshStack(root, NoLanes); + markRootSuspended(root, lanes, NoLane); break; - } + } // 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. - case RootSuspended: - case RootCompleted: { - break; - } - default: { - throw new Error("Unknown root exit status."); - } + root.finishedWork = finishedWork; + root.finishedLanes = lanes; + finishConcurrentRender(root, exitStatus, finishedWork, lanes); } - if (shouldForceFlushFallbacksInDEV()) { - // We're inside an `act` scope. Commit immediately. - commitRoot( - root, - workInProgressRootRecoverableErrors, - workInProgressTransitions, - workInProgressRootDidIncludeRecursiveRenderUpdate, - workInProgressDeferredLane - ); - } else { - if (includesOnlyRetries(lanes) && exitStatus === RootSuspended) { - // 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. - - if (msUntilTimeout > 10) { - markRootSuspended(root, lanes, workInProgressDeferredLane); - var nextLanes = getNextLanes(root, NoLanes); - - if (nextLanes !== NoLanes) { - // There's additional work we can do on this root. We might as well - // attempt to work on that while we're suspended. - return; - } // 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. - // TODO: Combine retry throttling with Suspensey commits. Right now they - // run one after the other. - - root.timeoutHandle = scheduleTimeout( - commitRootWhenReady.bind( - null, - root, - finishedWork, - workInProgressRootRecoverableErrors, - workInProgressTransitions, - workInProgressRootDidIncludeRecursiveRenderUpdate, - lanes, - workInProgressDeferredLane - ), - msUntilTimeout - ); - return; - } - } + break; + } while (true); + } - commitRootWhenReady( - root, - finishedWork, - workInProgressRootRecoverableErrors, - workInProgressTransitions, - workInProgressRootDidIncludeRecursiveRenderUpdate, - lanes, - workInProgressDeferredLane - ); - } - } - - function commitRootWhenReady( - root, - finishedWork, - recoverableErrors, - transitions, - didIncludeRenderPhaseUpdate, - lanes, - spawnedLane - ) { - // TODO: Combine retry throttling with Suspensey commits. Right now they run - // one after the other. - if (includesOnlyNonUrgentLanes(lanes)) { - // the suspensey resources. The renderer is responsible for accumulating - // all the load events. This all happens in a single synchronous - // transaction, so it track state in its own module scope. - - accumulateSuspenseyCommit(finishedWork); // At the end, ask the renderer if it's ready to commit, or if we should - // suspend. If it's not ready, it will return a callback to subscribe to - // a ready event. - - var schedulePendingCommit = waitForCommitToBeReady(); - - 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, - recoverableErrors, - transitions, - didIncludeRenderPhaseUpdate - ) - ); - markRootSuspended(root, lanes, spawnedLane); - return; - } - } // Otherwise, commit immediately. + ensureRootIsScheduled(root); + return getContinuationForRoot(root, originalCallbackNode); +} - commitRoot( - root, - recoverableErrors, - transitions, - didIncludeRenderPhaseUpdate, - spawnedLane - ); - } +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 = supportsHydration ; + + var exitStatus = renderRootSync(root, errorRetryLanes); + + 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. - 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; + 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. - while (true) { - if (node.flags & StoreConsistency) { - var updateQueue = node.updateQueue; - if (updateQueue !== null) { - var checks = updateQueue.stores; - - if (checks !== null) { - for (var i = 0; i < checks.length; i++) { - var check = checks[i]; - var getSnapshot = check.getSnapshot; - var renderedValue = check.value; - - 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; - } - } - } - } - } + 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. - var child = node.child; + if (errorsFromSecondAttempt !== null) { + queueRecoverableErrors(errorsFromSecondAttempt); + } + } - if (node.subtreeFlags & StoreConsistency && child !== null) { - child.return = node; - node = child; - continue; - } + return exitStatus; +} - if (node === finishedWork) { - return true; - } +function queueRecoverableErrors(errors) { + if (workInProgressRootRecoverableErrors === null) { + workInProgressRootRecoverableErrors = errors; + } else { + // $FlowFixMe[method-unbinding] + workInProgressRootRecoverableErrors.push.apply(workInProgressRootRecoverableErrors, errors); + } +} - while (node.sibling === null) { - if (node.return === null || node.return === finishedWork) { - return true; - } +function finishConcurrentRender(root, exitStatus, finishedWork, lanes) { + // TODO: The fact that most of these branches are identical suggests that some + // of the exit statuses are not best modeled as exit statuses and should be + // tracked orthogonally. + switch (exitStatus) { + case RootInProgress: + case RootFatalErrored: + { + throw new Error('Root did not complete. This is a bug in React.'); + } - node = node.return; - } + case RootSuspendedWithDelay: + { + 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. + markRootSuspended(root, lanes, workInProgressDeferredLane); + return; + } // Commit the placeholder. - 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 true; - } // The extra indirections around markRootUpdated and markRootSuspended is - // needed to avoid a circular dependency between this module and - // ReactFiberLane. There's probably a better way to split up these modules and - // avoid this problem. Perhaps all the root-marking functions should move into - // the work loop. - - function markRootUpdated(root, updatedLanes) { - markRootUpdated$1(root, updatedLanes); - } - - function markRootPinged(root, pingedLanes) { - markRootPinged$1(root, pingedLanes); - } - - function markRootSuspended(root, suspendedLanes, spawnedLane) { - // When suspending, we should always exclude lanes that were pinged or (more - // rarely, since we try to avoid it) updated during the render phase. - suspendedLanes = removeLanes( - suspendedLanes, - workInProgressRootPingedLanes - ); - suspendedLanes = removeLanes( - suspendedLanes, - workInProgressRootInterleavedUpdatedLanes - ); - - markRootSuspended$1(root, suspendedLanes, spawnedLane); - } // This is the entry point for synchronous tasks that don't go - // through Scheduler - - function performSyncWorkOnRoot(root, lanes) { - if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { - throw new Error("Should not already be working."); - } - - var didFlushPassiveEffects = flushPassiveEffects(); - - if (didFlushPassiveEffects) { - // If passive effects were flushed, exit to the outer work loop in the root - // scheduler, so we can recompute the priority. - // TODO: We don't actually need this `ensureRootIsScheduled` call because - // this path is only reachable if the root is already part of the schedule. - // I'm including it only for consistency with the other exit points from - // this function. Can address in a subsequent refactor. - ensureRootIsScheduled(root); - return null; + break; } + case RootErrored: { - syncNestedUpdateFlag(); - } - - 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 - ); - } + // This render errored. Ignore any recoverable errors because we weren't actually + // able to recover. Instead, whatever the final errors were is the ones we log. + // This ensures that we only log the actual client side error if it's just a plain + // error thrown from a component on the server and the client. + workInProgressRootRecoverableErrors = null; + break; } - if (exitStatus === RootFatalErrored) { - prepareFreshStack(root, NoLanes); - markRootSuspended(root, lanes, NoLane); - ensureRootIsScheduled(root); - return null; + case RootSuspended: + case RootCompleted: + { + 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, workInProgressDeferredLane); - ensureRootIsScheduled(root); - 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, - workInProgressRootDidIncludeRecursiveRenderUpdate, - workInProgressDeferredLane - ); // Before exiting, make sure there's a callback scheduled for the next - // pending level. - - ensureRootIsScheduled(root); - return null; - } - function getExecutionContext() { - return executionContext; - } - function batchedUpdates(fn, a) { + default: { - var prevExecutionContext = executionContext; - executionContext |= BatchedContext; - - 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 ( - executionContext === NoContext && // Treat `act` as if it's inside `batchedUpdates`, even in legacy mode. - !ReactSharedInternals.isBatchingLegacy - ) { - resetRenderTimer(); - flushSyncWorkOnLegacyRootsOnly(); - } - } - } - } - // 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 flushSyncFromReconciler(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 && - !disableLegacyMode && - rootWithPendingPassiveEffects.tag === LegacyRoot && - (executionContext & (RenderContext | CommitContext)) === NoContext - ) { - flushPassiveEffects(); + throw new Error('Unknown root exit status.'); } + } - var prevExecutionContext = executionContext; - executionContext |= BatchedContext; - var prevTransition = ReactSharedInternals.T; - var previousPriority = getCurrentUpdatePriority(); + if (shouldForceFlushFallbacksInDEV()) { + // We're inside an `act` scope. Commit immediately. + commitRoot(root, workInProgressRootRecoverableErrors, workInProgressTransitions, workInProgressRootDidIncludeRecursiveRenderUpdate, workInProgressDeferredLane); + } else { + if (includesOnlyRetries(lanes) && (exitStatus === RootSuspended)) { + // 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. - try { - setCurrentUpdatePriority(DiscreteEventPriority); - ReactSharedInternals.T = null; + if (msUntilTimeout > 10) { + markRootSuspended(root, lanes, workInProgressDeferredLane); + var nextLanes = getNextLanes(root, NoLanes); - if (fn) { - return fn(); - } else { - return undefined; - } - } finally { - setCurrentUpdatePriority(previousPriority); - ReactSharedInternals.T = 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 - ) { - flushSyncWorkOnAllRoots(); - } - } - } // If called outside of a render or commit will flush all sync work on all roots - // Returns whether the the call was during a render or not + if (nextLanes !== NoLanes) { + // There's additional work we can do on this root. We might as well + // attempt to work on that while we're suspended. + return; + } // 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. + // TODO: Combine retry throttling with Suspensey commits. Right now they + // run one after the other. - function flushSyncWork() { - if ((executionContext & (RenderContext | CommitContext)) === NoContext) { - flushSyncWorkOnAllRoots(); - return false; - } - return true; + root.timeoutHandle = scheduleTimeout(commitRootWhenReady.bind(null, root, finishedWork, workInProgressRootRecoverableErrors, workInProgressTransitions, workInProgressRootDidIncludeRecursiveRenderUpdate, lanes, workInProgressDeferredLane), msUntilTimeout); + return; + } } - // 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 setEntangledRenderLanes(newEntangledRenderLanes) { - entangledRenderLanes = newEntangledRenderLanes; - } - function getEntangledRenderLanes() { - return entangledRenderLanes; - } + commitRootWhenReady(root, finishedWork, workInProgressRootRecoverableErrors, workInProgressTransitions, workInProgressRootDidIncludeRecursiveRenderUpdate, lanes, workInProgressDeferredLane); + } +} - function resetWorkInProgressStack() { - if (workInProgress === null) return; - var interruptedWork; +function commitRootWhenReady(root, finishedWork, recoverableErrors, transitions, didIncludeRenderPhaseUpdate, lanes, spawnedLane) { + // TODO: Combine retry throttling with Suspensey commits. Right now they run + // one after the other. + if (includesOnlyNonUrgentLanes(lanes)) { + // the suspensey resources. The renderer is responsible for accumulating + // all the load events. This all happens in a single synchronous + // transaction, so it track state in its own module scope. - 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(workInProgress); - interruptedWork = workInProgress; - } + accumulateSuspenseyCommit(finishedWork); // At the end, ask the renderer if it's ready to commit, or if we should + // suspend. If it's not ready, it will return a callback to subscribe to + // a ready event. - while (interruptedWork !== null) { - var current = interruptedWork.alternate; - unwindInterruptedWork(current, interruptedWork); - interruptedWork = interruptedWork.return; - } + var schedulePendingCommit = waitForCommitToBeReady(); - workInProgress = null; + 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, recoverableErrors, transitions, didIncludeRenderPhaseUpdate)); + markRootSuspended(root, lanes, spawnedLane); + return; } + } // Otherwise, commit immediately. - 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[incompatible-call] Complains noTimeout is not a TimeoutID, despite the check above + commitRoot(root, recoverableErrors, transitions, didIncludeRenderPhaseUpdate, spawnedLane); +} - cancelTimeout(timeoutHandle); - } +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; - var cancelPendingCommit = root.cancelPendingCommit; + while (true) { + if (node.flags & StoreConsistency) { + var updateQueue = node.updateQueue; - if (cancelPendingCommit !== null) { - root.cancelPendingCommit = null; - cancelPendingCommit(); + if (updateQueue !== null) { + var checks = updateQueue.stores; + + if (checks !== null) { + for (var i = 0; i < checks.length; i++) { + var check = checks[i]; + var getSnapshot = check.getSnapshot; + var renderedValue = check.value; + + 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; + } + } + } } + } - resetWorkInProgressStack(); - workInProgressRoot = root; - var rootWorkInProgress = createWorkInProgress(root.current, null); - workInProgress = rootWorkInProgress; - workInProgressRootRenderLanes = lanes; - workInProgressSuspendedReason = NotSuspended; - workInProgressThrownValue = null; - workInProgressRootDidAttachPingListener = false; - workInProgressRootExitStatus = RootInProgress; - workInProgressRootSkippedLanes = NoLanes; - workInProgressRootInterleavedUpdatedLanes = NoLanes; - workInProgressRootPingedLanes = NoLanes; - workInProgressDeferredLane = NoLane; - workInProgressRootConcurrentErrors = null; - workInProgressRootRecoverableErrors = null; - workInProgressRootDidIncludeRecursiveRenderUpdate = false; // Get the lanes that are entangled with whatever we're about to render. We - // track these separately so we can distinguish the priority of the render - // task from the priority of the lanes it is entangled with. For example, a - // transition may not be allowed to finish unless it includes the Sync lane, - // which is currently suspended. We should be able to render the Transition - // and Sync lane in the same batch, but at Transition priority, because the - // Sync lane already suspended. + var child = node.child; - entangledRenderLanes = getEntangledLanes(root, lanes); - finishQueueingConcurrentUpdates(); + if (node.subtreeFlags & StoreConsistency && child !== null) { + child.return = node; + node = child; + continue; + } - { - ReactStrictModeWarnings.discardPendingWarnings(); + if (node === finishedWork) { + return true; + } + + while (node.sibling === null) { + if (node.return === null || node.return === finishedWork) { + return true; } - return rootWorkInProgress; + node = node.return; } - function resetSuspendedWorkLoopOnUnwind(fiber) { - // Reset module-level state that was set during the render phase. - resetContextDependencies(); - resetHooksOnUnwind(fiber); - resetChildReconcilerOnUnwind(); - } + node.sibling.return = node.return; + node = node.sibling; + } // Flow doesn't know this is unreachable, but eslint does + // eslint-disable-next-line no-unreachable - 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(); - { - ReactSharedInternals.owner = null; - } - - 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; - } - - workInProgressThrownValue = thrownValue; - var erroredWork = workInProgress; - - if (erroredWork === null) { - // This is a fatal error - workInProgressRootExitStatus = RootFatalErrored; - logUncaughtError( - root, - createCapturedValueAtFiber(thrownValue, root.current) - ); - return; - } + return true; +} // The extra indirections around markRootUpdated and markRootSuspended is +// needed to avoid a circular dependency between this module and +// ReactFiberLane. There's probably a better way to split up these modules and +// avoid this problem. Perhaps all the root-marking functions should move into +// the work loop. - 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); - } - { - markComponentRenderStopped(); +function markRootUpdated(root, updatedLanes) { + markRootUpdated$1(root, updatedLanes); +} - switch (workInProgressSuspendedReason) { - case SuspendedOnError: { - markComponentErrored( - erroredWork, - thrownValue, - workInProgressRootRenderLanes - ); - break; - } +function markRootPinged(root, pingedLanes) { + markRootPinged$1(root, pingedLanes); +} - case SuspendedOnData: - case SuspendedOnImmediate: - case SuspendedOnDeprecatedThrowPromise: - case SuspendedAndReadyToContinue: { - var wakeable = thrownValue; - markComponentSuspended( - erroredWork, - wakeable, - workInProgressRootRenderLanes - ); - break; - } - } +function markRootSuspended(root, suspendedLanes, spawnedLane) { + // When suspending, we should always exclude lanes that were pinged or (more + // rarely, since we try to avoid it) updated during the render phase. + suspendedLanes = removeLanes(suspendedLanes, workInProgressRootPingedLanes); + suspendedLanes = removeLanes(suspendedLanes, workInProgressRootInterleavedUpdatedLanes); + + markRootSuspended$1(root, suspendedLanes, spawnedLane); +} // This is the entry point for synchronous tasks that don't go +// through Scheduler + + +function performSyncWorkOnRoot(root, lanes) { + if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { + throw new Error('Should not already be working.'); + } + + var didFlushPassiveEffects = flushPassiveEffects(); + + if (didFlushPassiveEffects) { + // If passive effects were flushed, exit to the outer work loop in the root + // scheduler, so we can recompute the priority. + // TODO: We don't actually need this `ensureRootIsScheduled` call because + // this path is only reachable if the root is already part of the schedule. + // I'm including it only for consistency with the other exit points from + // this function. Can address in a subsequent refactor. + ensureRootIsScheduled(root); + return null; + } + + { + syncNestedUpdateFlag(); + } + + 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 (exitStatus === RootFatalErrored) { + prepareFreshStack(root, NoLanes); + markRootSuspended(root, lanes, NoLane); + ensureRootIsScheduled(root); + return null; + } + + 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, workInProgressDeferredLane); + ensureRootIsScheduled(root); + 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, workInProgressRootDidIncludeRecursiveRenderUpdate, workInProgressDeferredLane); // Before exiting, make sure there's a callback scheduled for the next + // pending level. + + ensureRootIsScheduled(root); + return null; +} +function getExecutionContext() { + return executionContext; +} +function batchedUpdates(fn, a) { + { + var prevExecutionContext = executionContext; + executionContext |= BatchedContext; + + 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 (executionContext === NoContext && // Treat `act` as if it's inside `batchedUpdates`, even in legacy mode. + !(ReactSharedInternals.isBatchingLegacy)) { + resetRenderTimer(); + flushSyncWorkOnLegacyRootsOnly(); } } + } +} +// 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 flushSyncFromReconciler(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 && !disableLegacyMode && rootWithPendingPassiveEffects.tag === LegacyRoot && (executionContext & (RenderContext | CommitContext)) === NoContext) { + flushPassiveEffects(); + } + + var prevExecutionContext = executionContext; + executionContext |= BatchedContext; + var prevTransition = ReactSharedInternals.T; + var previousPriority = getCurrentUpdatePriority(); + + try { + setCurrentUpdatePriority(DiscreteEventPriority); + ReactSharedInternals.T = null; + + if (fn) { + return fn(); + } else { + return undefined; + } + } finally { + setCurrentUpdatePriority(previousPriority); + ReactSharedInternals.T = 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) { + flushSyncWorkOnAllRoots(); + } + } +} // If called outside of a render or commit will flush all sync work on all roots +// Returns whether the the call was during a render or not - 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. - var handler = getSuspenseHandler(); +function flushSyncWork() { + if ((executionContext & (RenderContext | CommitContext)) === NoContext) { + flushSyncWorkOnAllRoots(); + return false; + } - if (handler === null) { - // There's no Suspense boundary that can provide a fallback. We have no - // choice but to remain on the previous screen. - // NOTE: We do this even for sync updates, for lack of any better option. In - // the future, we may change how we handle this, like by putting the whole - // root into a "detached" mode. - return true; - } // 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; - } - } + return true; +} +// 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 - if ( - includesOnlyRetries(workInProgressRootRenderLanes) || // In this context, an OffscreenLane counts as a Retry - // TODO: It's become increasingly clear that Retries and Offscreen are - // deeply connected. They probably can be unified further. - includesSomeLane(workInProgressRootRenderLanes, OffscreenLane) - ) { - // 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. - // - // The reason we must check if this is a retry is because it guarantees - // that suspending the work loop won't block an actual update, because - // retries don't "update" anything; they fill in fallbacks that were left - // behind by a previous transition. - return handler === getShellBoundary(); - } // For all other Lanes besides Transitions and Retries, we should not wait - // for the data to load. +function setEntangledRenderLanes(newEntangledRenderLanes) { + entangledRenderLanes = newEntangledRenderLanes; +} +function getEntangledRenderLanes() { + return entangledRenderLanes; +} - return false; - } +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(workInProgress); + interruptedWork = workInProgress; + } + + while (interruptedWork !== null) { + var current = interruptedWork.alternate; + unwindInterruptedWork(current, interruptedWork); + interruptedWork = interruptedWork.return; + } + + workInProgress = null; +} - function pushDispatcher(container) { - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = ContextOnlyDispatcher; +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[incompatible-call] Complains noTimeout is not a TimeoutID, despite the check above + + cancelTimeout(timeoutHandle); + } + + var cancelPendingCommit = root.cancelPendingCommit; + + if (cancelPendingCommit !== null) { + root.cancelPendingCommit = null; + cancelPendingCommit(); + } + + resetWorkInProgressStack(); + workInProgressRoot = root; + var rootWorkInProgress = createWorkInProgress(root.current, null); + workInProgress = rootWorkInProgress; + workInProgressRootRenderLanes = lanes; + workInProgressSuspendedReason = NotSuspended; + workInProgressThrownValue = null; + workInProgressRootDidAttachPingListener = false; + workInProgressRootExitStatus = RootInProgress; + workInProgressRootSkippedLanes = NoLanes; + workInProgressRootInterleavedUpdatedLanes = NoLanes; + workInProgressRootPingedLanes = NoLanes; + workInProgressDeferredLane = NoLane; + workInProgressRootConcurrentErrors = null; + workInProgressRootRecoverableErrors = null; + workInProgressRootDidIncludeRecursiveRenderUpdate = false; // Get the lanes that are entangled with whatever we're about to render. We + // track these separately so we can distinguish the priority of the render + // task from the priority of the lanes it is entangled with. For example, a + // transition may not be allowed to finish unless it includes the Sync lane, + // which is currently suspended. We should be able to render the Transition + // and Sync lane in the same batch, but at Transition priority, because the + // Sync lane already suspended. + + entangledRenderLanes = getEntangledLanes(root, lanes); + finishQueueingConcurrentUpdates(); + + { + ReactStrictModeWarnings.discardPendingWarnings(); + } + + return rootWorkInProgress; +} - 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; - } - } +function resetSuspendedWorkLoopOnUnwind(fiber) { + // Reset module-level state that was set during the render phase. + resetContextDependencies(); + resetHooksOnUnwind(fiber); + resetChildReconcilerOnUnwind(); +} - function popDispatcher(prevDispatcher) { - ReactSharedInternals.H = prevDispatcher; - } +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(); + + { + ReactSharedInternals.owner = null; + } + + 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; + } + + workInProgressThrownValue = thrownValue; + var erroredWork = workInProgress; + + if (erroredWork === null) { + // This is a fatal error + workInProgressRootExitStatus = RootFatalErrored; + logUncaughtError(root, createCapturedValueAtFiber(thrownValue, root.current)); + 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); + } + + { + markComponentRenderStopped(); + + switch (workInProgressSuspendedReason) { + case SuspendedOnError: + { + markComponentErrored(erroredWork, thrownValue, workInProgressRootRenderLanes); + break; + } - function pushCacheDispatcher() { - { - var prevCacheDispatcher = ReactSharedInternals.C; - ReactSharedInternals.C = DefaultCacheDispatcher; - return prevCacheDispatcher; - } + case SuspendedOnData: + case SuspendedOnImmediate: + case SuspendedOnDeprecatedThrowPromise: + case SuspendedAndReadyToContinue: + { + var wakeable = thrownValue; + markComponentSuspended(erroredWork, wakeable, workInProgressRootRenderLanes); + break; + } } + } +} - function popCacheDispatcher(prevCacheDispatcher) { - { - ReactSharedInternals.C = prevCacheDispatcher; - } +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. + var handler = getSuspenseHandler(); + + if (handler === null) { + // There's no Suspense boundary that can provide a fallback. We have no + // choice but to remain on the previous screen. + // NOTE: We do this even for sync updates, for lack of any better option. In + // the future, we may change how we handle this, like by putting the whole + // root into a "detached" mode. + return true; + } // 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; } + } - 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. + if (includesOnlyRetries(workInProgressRootRenderLanes) || // In this context, an OffscreenLane counts as a Retry + // TODO: It's become increasingly clear that Retries and Offscreen are + // deeply connected. They probably can be unified further. + includesSomeLane(workInProgressRootRenderLanes, OffscreenLane)) { + // 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. + // + // The reason we must check if this is a retry is because it guarantees + // that suspending the work loop won't block an actual update, because + // retries don't "update" anything; they fill in fallbacks that were left + // behind by a previous transition. + return handler === getShellBoundary(); + } // For all other Lanes besides Transitions and Retries, we should not wait + // for the data to load. - if ( - (includesNonIdleWork(workInProgressRootSkippedLanes) || - includesNonIdleWork(workInProgressRootInterleavedUpdatedLanes)) && - workInProgressRoot !== null - ) { - // 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. - markRootSuspended( - workInProgressRoot, - workInProgressRootRenderLanes, - workInProgressDeferredLane - ); - } - } - function renderDidError() { - if (workInProgressRootExitStatus !== RootSuspendedWithDelay) { - workInProgressRootExitStatus = RootErrored; - } - } - function queueConcurrentError(error) { - 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. - - 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. - - function renderRootSync(root, lanes) { - var prevExecutionContext = executionContext; - executionContext |= RenderContext; - var prevDispatcher = pushDispatcher(); - var prevCacheDispatcher = pushCacheDispatcher(); // If the root or lanes have changed, throw out the existing stack - // and prepare a fresh one. Otherwise we'll continue where we left off. - - if ( - workInProgressRoot !== root || - workInProgressRootRenderLanes !== lanes - ) { - workInProgressTransitions = getTransitionsForLanes(); - prepareFreshStack(root, lanes); - } - { - markRenderStarted(lanes); - } + return false; +} - var didSuspendInShell = false; +function pushDispatcher(container) { + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = ContextOnlyDispatcher; + + 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; + } +} - 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; - - 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; - } +function popDispatcher(prevDispatcher) { + ReactSharedInternals.H = prevDispatcher; +} - case SuspendedOnImmediate: - case SuspendedOnData: { - if (!didSuspendInShell && getSuspenseHandler() === null) { - didSuspendInShell = true; - } // Intentional fallthrough - } +function pushCacheDispatcher() { + { + var prevCacheDispatcher = ReactSharedInternals.C; + ReactSharedInternals.C = DefaultCacheDispatcher; + return prevCacheDispatcher; + } +} - default: { - // Unwind then continue with the normal work loop. - workInProgressSuspendedReason = NotSuspended; - workInProgressThrownValue = null; - throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); - break; - } +function popCacheDispatcher(prevCacheDispatcher) { + { + ReactSharedInternals.C = prevCacheDispatcher; + } +} + +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. + + if ((includesNonIdleWork(workInProgressRootSkippedLanes) || includesNonIdleWork(workInProgressRootInterleavedUpdatedLanes)) && workInProgressRoot !== null) { + // 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. + markRootSuspended(workInProgressRoot, workInProgressRootRenderLanes, workInProgressDeferredLane); + } +} +function renderDidError() { + if (workInProgressRootExitStatus !== RootSuspendedWithDelay) { + workInProgressRootExitStatus = RootErrored; + } +} +function queueConcurrentError(error) { + 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. + +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. + +function renderRootSync(root, lanes) { + var prevExecutionContext = executionContext; + executionContext |= RenderContext; + var prevDispatcher = pushDispatcher(); + var prevCacheDispatcher = pushCacheDispatcher(); // If the root or lanes have changed, throw out the existing stack + // and prepare a fresh one. Otherwise we'll continue where we left off. + + if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) { + + workInProgressTransitions = getTransitionsForLanes(); + prepareFreshStack(root, lanes); + } + + { + markRenderStarted(lanes); + } + + var didSuspendInShell = false; + + 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; + + 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; } - } - workLoopSync(); - break; - } catch (thrownValue) { - handleThrow(root, thrownValue); - } - } while (true); // Check if something suspended in the shell. We use this to detect an - // infinite ping loop caused by an uncached promise. - // - // Only increment this counter once per synchronous render attempt across the - // whole tree. Even if there are many sibling components that suspend, this - // counter only gets incremented once. + case SuspendedOnImmediate: + case SuspendedOnData: + { + if (!didSuspendInShell && getSuspenseHandler() === null) { + didSuspendInShell = true; + } // Intentional fallthrough + + } - if (didSuspendInShell) { - root.shellSuspendCounter++; + default: + { + // Unwind then continue with the normal work loop. + workInProgressSuspendedReason = NotSuspended; + workInProgressThrownValue = null; + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); + break; + } + } } - resetContextDependencies(); - executionContext = prevExecutionContext; - popDispatcher(prevDispatcher); - popCacheDispatcher(prevCacheDispatcher); + workLoopSync(); + break; + } catch (thrownValue) { + handleThrow(root, thrownValue); + } + } while (true); // Check if something suspended in the shell. We use this to detect an + // infinite ping loop caused by an uncached promise. + // + // Only increment this counter once per synchronous render attempt across the + // whole tree. Even if there are many sibling components that suspend, this + // counter only gets incremented once. - 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." - ); - } - { - markRenderStopped(); - } // Set this to null to indicate there's no in-progress render. + if (didSuspendInShell) { + root.shellSuspendCounter++; + } - workInProgressRoot = null; - workInProgressRootRenderLanes = NoLanes; // It's safe to process the queue now that the render phase is complete. + resetContextDependencies(); + executionContext = prevExecutionContext; + popDispatcher(prevDispatcher); + popCacheDispatcher(prevCacheDispatcher); - finishQueueingConcurrentUpdates(); - return workInProgressRootExitStatus; - } // The work loop is an extremely hot path. Tell Closure not to inline it. + 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.'); + } - /** @noinline */ + { + markRenderStopped(); + } // Set this to null to indicate there's no in-progress render. - function workLoopSync() { - // Perform work without checking if we need to yield between fiber. - while (workInProgress !== null) { - performUnitOfWork(workInProgress); - } - } - function renderRootConcurrent(root, lanes) { - var prevExecutionContext = executionContext; - executionContext |= RenderContext; - var prevDispatcher = pushDispatcher(); - var prevCacheDispatcher = pushCacheDispatcher(); // If the root or lanes have changed, throw out the existing stack - // and prepare a fresh one. Otherwise we'll continue where we left off. + workInProgressRoot = null; + workInProgressRootRenderLanes = NoLanes; // It's safe to process the queue now that the render phase is complete. - if ( - workInProgressRoot !== root || - workInProgressRootRenderLanes !== lanes - ) { - workInProgressTransitions = getTransitionsForLanes(); - resetRenderTimer(); - prepareFreshStack(root, lanes); - } + finishQueueingConcurrentUpdates(); + return workInProgressRootExitStatus; +} // The work loop is an extremely hot path. Tell Closure not to inline it. - { - markRenderStarted(lanes); - } +/** @noinline */ - 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; - - resumeOrUnwind: switch (workInProgressSuspendedReason) { - case SuspendedOnError: { - // Unwind then continue with the normal work loop. + +function workLoopSync() { + // Perform work without checking if we need to yield between fiber. + while (workInProgress !== null) { + performUnitOfWork(workInProgress); + } +} + +function renderRootConcurrent(root, lanes) { + var prevExecutionContext = executionContext; + executionContext |= RenderContext; + var prevDispatcher = pushDispatcher(); + var prevCacheDispatcher = pushCacheDispatcher(); // If the root or lanes have changed, throw out the existing stack + // and prepare a fresh one. Otherwise we'll continue where we left off. + + if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) { + + workInProgressTransitions = getTransitionsForLanes(); + resetRenderTimer(); + prepareFreshStack(root, lanes); + } + + { + markRenderStarted(lanes); + } + + 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; + + resumeOrUnwind: switch (workInProgressSuspendedReason) { + case SuspendedOnError: + { + // Unwind then continue with the normal work loop. + workInProgressSuspendedReason = NotSuspended; + workInProgressThrownValue = null; + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); + break; + } + + case SuspendedOnData: + { + var thenable = thrownValue; + + if (isThenableResolved(thenable)) { + // The data resolved. Try rendering the component again. workInProgressSuspendedReason = NotSuspended; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); + 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. - case SuspendedOnData: { - var thenable = thrownValue; - 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. - - 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. - - ensureRootIsScheduled(root); - }; - - thenable.then(onResolution, onResolution); - break outer; - } + 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. - 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; - } + ensureRootIsScheduled(root); + }; + + thenable.then(onResolution, onResolution); + break outer; + } - case SuspendedAndReadyToContinue: { - var _thenable = thrownValue; + 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; + } - 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(root, unitOfWork, thrownValue); - } + case SuspendedOnInstance: + { + workInProgressSuspendedReason = SuspendedOnInstanceAndReadyToContinue; + break outer; + } - break; + 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(root, unitOfWork, thrownValue); } - case SuspendedOnInstanceAndReadyToContinue: { - switch (workInProgress.tag) { - case HostComponent: - case HostHoistable: - case HostSingleton: { + 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. @@ -23981,3891 +20586,3431 @@ if (__DEV__) { break; } - default: { + 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." - ); + error('Unexpected type of fiber triggered a suspensey commit. ' + 'This is a bug in React.'); } break; } - } // Otherwise, unwind then continue with the normal work loop. - - workInProgressSuspendedReason = NotSuspended; - workInProgressThrownValue = null; - throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); - break; - } - - 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(root, unitOfWork, thrownValue); - break; - } + } // Otherwise, unwind then continue with the normal work loop. - 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; - } - default: { - throw new Error( - "Unexpected SuspendedReason. This is a bug in React." - ); - } + workInProgressSuspendedReason = NotSuspended; + workInProgressThrownValue = null; + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); + break; } - } - - if (true && ReactSharedInternals.actQueue !== 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(); - } - break; - } catch (thrownValue) { - handleThrow(root, thrownValue); - } - } while (true); + 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(root, unitOfWork, thrownValue); + break; + } - resetContextDependencies(); - popDispatcher(prevDispatcher); - popCacheDispatcher(prevCacheDispatcher); - executionContext = prevExecutionContext; + 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 (workInProgress !== null) { - // Still work remaining. - { - markRenderYielded(); + default: + { + throw new Error('Unexpected SuspendedReason. This is a bug in React.'); + } } + } - return RootInProgress; + if (true && ReactSharedInternals.actQueue !== 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 { - // Completed the tree. - { - markRenderStopped(); - } // Set this to null to indicate there's no in-progress render. + workLoopConcurrent(); + } - workInProgressRoot = null; - workInProgressRootRenderLanes = NoLanes; // It's safe to process the queue now that the render phase is complete. + break; + } catch (thrownValue) { + handleThrow(root, thrownValue); + } + } while (true); - finishQueueingConcurrentUpdates(); // Return the final exit status. + resetContextDependencies(); + popDispatcher(prevDispatcher); + popCacheDispatcher(prevCacheDispatcher); + executionContext = prevExecutionContext; - return workInProgressRootExitStatus; - } - } - /** @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 (workInProgress !== null) { + // Still work remaining. + { + markRenderYielded(); } - 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; + return RootInProgress; + } else { + // Completed the tree. + { + markRenderStopped(); + } // Set this to null to indicate there's no in-progress render. - if ((unitOfWork.mode & ProfileMode) !== NoMode) { - startProfilerTimer(unitOfWork); - next = beginWork(current, unitOfWork, entangledRenderLanes); - stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true); - } else { - next = beginWork(current, unitOfWork, entangledRenderLanes); - } - resetCurrentFiber(); - unitOfWork.memoizedProps = unitOfWork.pendingProps; + workInProgressRoot = null; + workInProgressRootRenderLanes = NoLanes; // It's safe to process the queue now that the render phase is complete. - if (next === null) { - // If this doesn't spawn new work, complete the current work. - completeUnitOfWork(unitOfWork); - } else { - workInProgress = next; + finishQueueingConcurrentUpdates(); // Return the final exit status. + + return workInProgressRootExitStatus; + } +} +/** @noinline */ + + +function workLoopConcurrent() { + // Perform work until Scheduler asks us to yield + while (workInProgress !== null && !shouldYield()) { + // $FlowFixMe[incompatible-call] found when upgrading Flow + performUnitOfWork(workInProgress); + } +} + +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; + + if ((unitOfWork.mode & ProfileMode) !== NoMode) { + startProfilerTimer(unitOfWork); + next = beginWork(current, unitOfWork, entangledRenderLanes); + stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true); + } else { + next = beginWork(current, unitOfWork, entangledRenderLanes); + } + + resetCurrentFiber(); + unitOfWork.memoizedProps = unitOfWork.pendingProps; + + if (next === null) { + // If this doesn't spawn new work, complete the current work. + completeUnitOfWork(unitOfWork); + } else { + workInProgress = next; + } + + { + ReactSharedInternals.owner = null; + } +} + +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; + + if (isProfilingMode) { + startProfilerTimer(unitOfWork); + } + + switch (unitOfWork.tag) { + case SimpleMemoComponent: + case FunctionComponent: + { + // 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 : resolveDefaultPropsOnNonClassComponent(Component, unresolvedProps); + var context; + + { + var unmaskedContext = getUnmaskedContext(unitOfWork, Component, true); + context = getMaskedContext(unitOfWork, unmaskedContext); + } + + next = replayFunctionComponent(current, unitOfWork, resolvedProps, Component, context, workInProgressRootRenderLanes); + break; } + case ForwardRef: { - ReactSharedInternals.owner = null; + // 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.render; + var _unresolvedProps = unitOfWork.pendingProps; + + var _resolvedProps = unitOfWork.elementType === _Component ? _unresolvedProps : resolveDefaultPropsOnNonClassComponent(_Component, _unresolvedProps); + + next = replayFunctionComponent(current, unitOfWork, _resolvedProps, _Component, unitOfWork.ref, workInProgressRootRenderLanes); + break; } - } - 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; + case HostComponent: + { + // Some host components are stateful (that's how we implement form + // actions) but we don't bother to reuse the memoized state because it's + // not worth the extra code. The main reason to reuse the previous hooks + // is to reuse uncached promises, but we happen to know that the only + // promises that a host component might suspend on are definitely cached + // because they are controlled by us. So don't bother. + resetHooksOnUnwind(unitOfWork); // Fallthrough to the next branch. + } - if (isProfilingMode) { - startProfilerTimer(unitOfWork); + 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, entangledRenderLanes); + next = beginWork(current, unitOfWork, entangledRenderLanes); + break; } + } - switch (unitOfWork.tag) { - case SimpleMemoComponent: - case FunctionComponent: { - // 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 - : resolveDefaultPropsOnNonClassComponent( - Component, - unresolvedProps - ); - var context; + if (isProfilingMode) { + stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true); + } // The begin phase finished successfully without suspending. Return to the + // normal work loop. - { - var unmaskedContext = getUnmaskedContext( - unitOfWork, - Component, - true - ); - context = getMaskedContext(unitOfWork, unmaskedContext); - } - next = replayFunctionComponent( - current, - unitOfWork, - resolvedProps, - Component, - context, - workInProgressRootRenderLanes - ); - break; - } + resetCurrentFiber(); + unitOfWork.memoizedProps = unitOfWork.pendingProps; - 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.render; - var _unresolvedProps = unitOfWork.pendingProps; - - var _resolvedProps = - unitOfWork.elementType === _Component - ? _unresolvedProps - : resolveDefaultPropsOnNonClassComponent( - _Component, - _unresolvedProps - ); - - next = replayFunctionComponent( - current, - unitOfWork, - _resolvedProps, - _Component, - unitOfWork.ref, - workInProgressRootRenderLanes - ); - break; - } + if (next === null) { + // If this doesn't spawn new work, complete the current work. + completeUnitOfWork(unitOfWork); + } else { + workInProgress = next; + } - case HostComponent: { - // Some host components are stateful (that's how we implement form - // actions) but we don't bother to reuse the memoized state because it's - // not worth the extra code. The main reason to reuse the previous hooks - // is to reuse uncached promises, but we happen to know that the only - // promises that a host component might suspend on are definitely cached - // because they are controlled by us. So don't bother. - resetHooksOnUnwind(unitOfWork); // Fallthrough to the next branch. - } + { + ReactSharedInternals.owner = 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, - entangledRenderLanes - ); - next = beginWork(current, unitOfWork, entangledRenderLanes); - break; - } - } +function throwAndUnwindWorkLoop(root, 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(unitOfWork); + var returnFiber = unitOfWork.return; + + try { + // Find and mark the nearest Suspense or error boundary that can handle + // this "exception". + var didFatal = throwException(root, returnFiber, unitOfWork, thrownValue, workInProgressRootRenderLanes); + + if (didFatal) { + panicOnRootError(root, thrownValue); + return; + } + } 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. + if (returnFiber !== null) { + workInProgress = returnFiber; + throw error; + } else { + panicOnRootError(root, 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 (isProfilingMode) { - stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true); - } // The begin phase finished successfully without suspending. Return to the - // normal work loop. +function panicOnRootError(root, error) { + // There's no ancestor that can handle this exception. This should never + // happen because the root is supposed to capture all errors that weren't + // caught by an error boundary. This is a fatal error, or panic condition, + // because we've run out of ways to recover. + workInProgressRootExitStatus = RootFatalErrored; + logUncaughtError(root, createCapturedValueAtFiber(error, root.current)); // 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. + + workInProgress = null; +} - resetCurrentFiber(); - unitOfWork.memoizedProps = unitOfWork.pendingProps; +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 (next === null) { - // If this doesn't spawn new work, complete the current work. - completeUnitOfWork(unitOfWork); - } else { - workInProgress = next; + 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."); } + } // 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. - { - ReactSharedInternals.owner = null; - } - } - function throwAndUnwindWorkLoop(root, 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(unitOfWork); - var returnFiber = unitOfWork.return; + var current = completedWork.alternate; + var returnFiber = completedWork.return; + setCurrentFiber(completedWork); + var next = void 0; - try { - // Find and mark the nearest Suspense or error boundary that can handle - // this "exception". - var didFatal = throwException( - root, - returnFiber, - unitOfWork, - thrownValue, - workInProgressRootRenderLanes - ); - - if (didFatal) { - panicOnRootError(root, thrownValue); - return; - } - } 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. - if (returnFiber !== null) { - workInProgress = returnFiber; - throw error; - } else { - panicOnRootError(root, thrownValue); - return; - } - } + if ((completedWork.mode & ProfileMode) === NoMode) { + next = completeWork(current, completedWork, entangledRenderLanes); + } else { + startProfilerTimer(completedWork); + next = completeWork(current, completedWork, entangledRenderLanes); // Update render duration assuming we didn't error. - 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); - } + stopProfilerTimerIfRunningAndRecordDelta(completedWork, false); } - function panicOnRootError(root, error) { - // There's no ancestor that can handle this exception. This should never - // happen because the root is supposed to capture all errors that weren't - // caught by an error boundary. This is a fatal error, or panic condition, - // because we've run out of ways to recover. - workInProgressRootExitStatus = RootFatalErrored; - logUncaughtError(root, createCapturedValueAtFiber(error, root.current)); // 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. + resetCurrentFiber(); - workInProgress = null; + if (next !== null) { + // Completing this fiber spawned new work. Work on that next. + workInProgress = next; + return; } - 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; + var siblingFiber = completedWork.sibling; + + 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 + + + completedWork = returnFiber; // Update the next thing we're working on in case something throws. + + workInProgress = completedWork; + } while (completedWork !== null); // We've reached the root. + + + if (workInProgressRootExitStatus === RootInProgress) { + workInProgressRootExitStatus = RootCompleted; + } +} + +function unwindUnitOfWork(unitOfWork) { + var incompleteWork = unitOfWork; + + 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. + + var next = unwindWork(current, incompleteWork); // Because this fiber did not complete, don't reset its lanes. + + 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. + + + 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. + + var actualDuration = incompleteWork.actualDuration; + var child = incompleteWork.child; + + while (child !== null) { + // $FlowFixMe[unsafe-addition] addition with possible null/undefined value + actualDuration += child.actualDuration; + child = child.sibling; + } - 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." - ); - } - } // 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. + 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 current = completedWork.alternate; - var returnFiber = completedWork.return; - setCurrentFiber(completedWork); - var next = void 0; - if ((completedWork.mode & ProfileMode) === NoMode) { - next = completeWork(current, completedWork, entangledRenderLanes); - } else { - startProfilerTimer(completedWork); - next = completeWork(current, completedWork, entangledRenderLanes); // Update render duration assuming we didn't error. + var returnFiber = incompleteWork.return; - stopProfilerTimerIfRunningAndRecordDelta(completedWork, false); - } + 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; + } // NOTE: If we re-enable sibling prerendering in some cases, here we + // would switch to the normal completion path: check if a sibling + // exists, and if so, begin work on it. + // Otherwise, return to the parent + // $FlowFixMe[incompatible-type] we bail out when we get a null - resetCurrentFiber(); - if (next !== null) { - // Completing this fiber spawned new work. Work on that next. - workInProgress = next; - return; - } + incompleteWork = returnFiber; // Update the next thing we're working on in case something throws. - var siblingFiber = completedWork.sibling; + workInProgress = incompleteWork; + } while (incompleteWork !== null); // We've unwound all the way to the root. - 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 - completedWork = returnFiber; // Update the next thing we're working on in case something throws. + workInProgressRootExitStatus = RootDidNotComplete; + workInProgress = null; +} - workInProgress = completedWork; - } while (completedWork !== null); // We've reached the root. +function commitRoot(root, recoverableErrors, transitions, didIncludeRenderPhaseUpdate, spawnedLane) { + // TODO: This no longer makes any sense. We already wrap the mutation and + // layout phases. Should be able to remove. + var prevTransition = ReactSharedInternals.T; + var previousUpdateLanePriority = getCurrentUpdatePriority(); + + try { + setCurrentUpdatePriority(DiscreteEventPriority); + ReactSharedInternals.T = null; + commitRootImpl(root, recoverableErrors, transitions, didIncludeRenderPhaseUpdate, previousUpdateLanePriority, spawnedLane); + } finally { + ReactSharedInternals.T = prevTransition; + setCurrentUpdatePriority(previousUpdateLanePriority); + } + + return null; +} - if (workInProgressRootExitStatus === RootInProgress) { - workInProgressRootExitStatus = RootCompleted; - } - } +function commitRootImpl(root, recoverableErrors, transitions, didIncludeRenderPhaseUpdate, renderPriorityLevel, spawnedLane) { + 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); - function unwindUnitOfWork(unitOfWork) { - var incompleteWork = unitOfWork; + flushRenderPhaseStrictModeWarningsInDEV(); - 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. - - var next = unwindWork(current, incompleteWork); // Because this fiber did not complete, don't reset its lanes. - - 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. + if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { + throw new Error('Should not already be working.'); + } - 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. + var finishedWork = root.finishedWork; + var lanes = root.finishedLanes; - var actualDuration = incompleteWork.actualDuration; - var child = incompleteWork.child; + { + markCommitStarted(lanes); + } - while (child !== null) { - // $FlowFixMe[unsafe-addition] addition with possible null/undefined value - actualDuration += child.actualDuration; - child = child.sibling; - } + if (finishedWork === null) { - 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; - - 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; - } // NOTE: If we re-enable sibling prerendering in some cases, here we - // would switch to the normal completion path: check if a sibling - // exists, and if so, begin work on it. - // Otherwise, return to the parent - // $FlowFixMe[incompatible-type] we bail out when we get a null - - incompleteWork = returnFiber; // Update the next thing we're working on in case something throws. - - workInProgress = incompleteWork; - } while (incompleteWork !== null); // We've unwound all the way to the root. - - workInProgressRootExitStatus = RootDidNotComplete; - workInProgress = null; - } - - function commitRoot( - root, - recoverableErrors, - transitions, - didIncludeRenderPhaseUpdate, - spawnedLane - ) { - // TODO: This no longer makes any sense. We already wrap the mutation and - // layout phases. Should be able to remove. - var prevTransition = ReactSharedInternals.T; - var previousUpdateLanePriority = getCurrentUpdatePriority(); + { + markCommitStopped(); + } - try { - setCurrentUpdatePriority(DiscreteEventPriority); - ReactSharedInternals.T = null; - commitRootImpl( - root, - recoverableErrors, - transitions, - didIncludeRenderPhaseUpdate, - previousUpdateLanePriority, - spawnedLane - ); - } finally { - ReactSharedInternals.T = prevTransition; - setCurrentUpdatePriority(previousUpdateLanePriority); + return null; + } else { + { + if (lanes === NoLanes) { + error('root.finishedLanes should not be empty during a commit. This is a ' + 'bug in React.'); } - - return null; } + } - function commitRootImpl( - root, - recoverableErrors, - transitions, - didIncludeRenderPhaseUpdate, - renderPriorityLevel, - spawnedLane - ) { - 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); + root.finishedWork = null; + root.finishedLanes = NoLanes; - flushRenderPhaseStrictModeWarningsInDEV(); + 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. - if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { - throw new Error("Should not already be working."); - } - var finishedWork = root.finishedWork; - var lanes = root.finishedLanes; + 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. - { - markCommitStarted(lanes); - } + 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. - if (finishedWork === null) { - { - markCommitStopped(); - } + var concurrentlyUpdatedLanes = getConcurrentlyUpdatedLanes(); + remainingLanes = mergeLanes(remainingLanes, concurrentlyUpdatedLanes); + markRootFinished(root, remainingLanes, spawnedLane); // Reset this before firing side effects so we can detect recursive updates. - return null; - } else { - { - if (lanes === NoLanes) { - error( - "root.finishedLanes should not be empty during a commit. This is a " + - "bug in React." - ); - } - } - } + 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. - root.finishedWork = null; - root.finishedLanes = NoLanes; - - 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. - - 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. - - 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. - - var concurrentlyUpdatedLanes = getConcurrentlyUpdatedLanes(); - remainingLanes = mergeLanes(remainingLanes, concurrentlyUpdatedLanes); - markRootFinished(root, remainingLanes, spawnedLane); // Reset this before firing side effects so we can detect recursive updates. - - 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. - - if ( - (finishedWork.subtreeFlags & PassiveMask) !== NoFlags$1 || - (finishedWork.flags & PassiveMask) !== NoFlags$1 - ) { - if (!rootDoesHavePassiveEffects) { - rootDoesHavePassiveEffects = true; - pendingPassiveEffectsRemainingLanes = remainingLanes; // workInProgressTransitions might be overwritten, so we want - // to store it in pendingPassiveTransitions until they get processed - // We need to pass this through as an argument to commitRoot - // because workInProgressTransitions might have changed between - // the previous render and commit if we throttle the commit - // with setTimeout - - pendingPassiveTransitions = transitions; - scheduleCallback(NormalPriority$1, 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) - 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. - - var subtreeHasEffects = - (finishedWork.subtreeFlags & - (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !== - NoFlags$1; - var rootHasEffect = - (finishedWork.flags & - (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !== - NoFlags$1; - - if (subtreeHasEffects || rootHasEffect) { - var prevTransition = ReactSharedInternals.T; - ReactSharedInternals.T = null; - var previousPriority = getCurrentUpdatePriority(); - setCurrentUpdatePriority(DiscreteEventPriority); - var prevExecutionContext = executionContext; - executionContext |= CommitContext; // Reset this to null before calling lifecycles + if ((finishedWork.subtreeFlags & PassiveMask) !== NoFlags$1 || (finishedWork.flags & PassiveMask) !== NoFlags$1) { + if (!rootDoesHavePassiveEffects) { + rootDoesHavePassiveEffects = true; + pendingPassiveEffectsRemainingLanes = remainingLanes; // workInProgressTransitions might be overwritten, so we want + // to store it in pendingPassiveTransitions until they get processed + // We need to pass this through as an argument to commitRoot + // because workInProgressTransitions might have changed between + // the previous render and commit if we throttle the commit + // with setTimeout - { - ReactSharedInternals.owner = 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. + pendingPassiveTransitions = transitions; + scheduleCallback(NormalPriority$1, 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) + + 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. - commitBeforeMutationEffects(root, finishedWork); - { - // Mark the current commit time to be shared by all Profilers in this - // batch. This enables them to be grouped later. - recordCommitTime(); - } // The next phase is the mutation phase, where we mutate the host tree. + var subtreeHasEffects = (finishedWork.subtreeFlags & (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !== NoFlags$1; + var rootHasEffect = (finishedWork.flags & (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !== NoFlags$1; - commitMutationEffects(root, finishedWork); - // 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 (subtreeHasEffects || rootHasEffect) { + var prevTransition = ReactSharedInternals.T; + ReactSharedInternals.T = null; + var previousPriority = getCurrentUpdatePriority(); + setCurrentUpdatePriority(DiscreteEventPriority); + var prevExecutionContext = executionContext; + executionContext |= CommitContext; // Reset this to null before calling lifecycles - root.current = finishedWork; // The next phase is the layout phase, where we call effects that read + { + ReactSharedInternals.owner = 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. - { - markLayoutEffectsStarted(lanes); - } - commitLayoutEffects(finishedWork, root); + commitBeforeMutationEffects(root, finishedWork); - { - markLayoutEffectsStopped(); - } // Tell Scheduler to yield at the end of the frame, so the browser has an - // opportunity to paint. + { + // Mark the current commit time to be shared by all Profilers in this + // batch. This enables them to be grouped later. + recordCommitTime(); + } // The next phase is the mutation phase, where we mutate the host tree. - requestPaint(); - executionContext = prevExecutionContext; // Reset the priority to the previous non-sync value. - setCurrentUpdatePriority(previousPriority); - ReactSharedInternals.T = 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. + commitMutationEffects(root, finishedWork); + // 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. - { - recordCommitTime(); - } - } + root.current = finishedWork; // The next phase is the layout phase, where we call effects that read - var rootDidHavePassiveEffects = rootDoesHavePassiveEffects; + { + markLayoutEffectsStarted(lanes); + } - 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 { - // There were no passive effects, so we can immediately release the cache - // pool for this render. - releaseRootPooledCache(root, remainingLanes); + commitLayoutEffects(finishedWork, root); - { - nestedPassiveUpdateCount = 0; - rootWithPassiveNestedUpdates = null; - } - } // Read this again, since an effect might have updated it + { + markLayoutEffectsStopped(); + } // Tell Scheduler to yield at the end of the frame, so the browser has an + // opportunity to paint. - 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; - } + requestPaint(); + executionContext = prevExecutionContext; // Reset the priority to the previous non-sync value. - { - if (!rootDidHavePassiveEffects) { - commitDoubleInvokeEffectsInDEV(root, false); - } - } + setCurrentUpdatePriority(previousPriority); + ReactSharedInternals.T = 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. - onCommitRoot(finishedWork.stateNode, renderPriorityLevel); - // additional work on this root is scheduled. + { + recordCommitTime(); + } + } - ensureRootIsScheduled(root); + var rootDidHavePassiveEffects = rootDoesHavePassiveEffects; - 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 (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 { + // There were no passive effects, so we can immediately release the cache + // pool for this render. + releaseRootPooledCache(root, remainingLanes); - for (var i = 0; i < recoverableErrors.length; i++) { - var recoverableError = recoverableErrors[i]; - var errorInfo = makeErrorInfo(recoverableError.stack); - onRecoverableError(recoverableError.value, errorInfo); - } - } // 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; // Check if this render scheduled a cascading synchronous update. This is a - // heurstic to detect infinite update loops. We are intentionally excluding - // hydration lanes in this check, because render triggered by selective - // hydration is conceptually not an update. - - if ( - // Check if there was a recursive update spawned by this render, in either - // the render phase or the commit phase. We track these explicitly because - // we can't infer from the remaining lanes alone. - // Was the finished render the result of an update (not hydration)? - includesSomeLane(lanes, UpdateLanes) && // Did it schedule a sync update? - includesSomeLane(remainingLanes, SyncUpdateLanes) - ) { - { - markNestedUpdateScheduled(); - } // Count the number of times the root synchronously re-renders without - // finishing. If there are too many, it indicates an infinite update loop. + { + nestedPassiveUpdateCount = 0; + rootWithPassiveNestedUpdates = null; + } + } // Read this again, since an effect might have updated it - if (root === rootWithNestedUpdates) { - nestedUpdateCount++; - } else { - nestedUpdateCount = 0; - rootWithNestedUpdates = root; - } - } else { - nestedUpdateCount = 0; - } // If layout work was scheduled, flush it now. - flushSyncWorkOnAllRoots(); + 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. - { - markCommitStopped(); - } + if (remainingLanes === NoLanes) { + // If there's no remaining work, we can clear the set of already failed + // error boundaries. + legacyErrorBoundariesThatAlreadyFailed = null; + } - return null; + { + if (!rootDidHavePassiveEffects) { + commitDoubleInvokeEffectsInDEV(root, false); } + } - function makeErrorInfo(componentStack) { - var errorInfo = { - componentStack: componentStack - }; + onCommitRoot(finishedWork.stateNode, renderPriorityLevel); + // additional work on this root is scheduled. - { - Object.defineProperty(errorInfo, "digest", { - get: function () { - error( - 'You are accessing "digest" from the errorInfo object passed to onRecoverableError.' + - " This property is no longer provided as part of errorInfo but can be accessed as a property" + - " of the Error instance itself." - ); - } - }); - } - return errorInfo; + ensureRootIsScheduled(root); + + 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; + + for (var i = 0; i < recoverableErrors.length; i++) { + var recoverableError = recoverableErrors[i]; + var errorInfo = makeErrorInfo(recoverableError.stack); + onRecoverableError(recoverableError.value, errorInfo); } + } // 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. - function releaseRootPooledCache(root, remainingLanes) { - { - var pooledCacheLanes = (root.pooledCacheLanes &= remainingLanes); - if (pooledCacheLanes === NoLanes) { - // None of the remaining work relies on the cache pool. Clear it so - // subsequent requests get a new cache - var pooledCache = root.pooledCache; + if (includesSyncLane(pendingPassiveEffectsLanes) && (root.tag !== LegacyRoot)) { + flushPassiveEffects(); + } // Read this again, since a passive effect might have updated it - if (pooledCache != null) { - root.pooledCache = null; - releaseCache(pooledCache); - } - } - } - } - 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) { - // Cache the root since rootWithPendingPassiveEffects is cleared in - // flushPassiveEffectsImpl - var root = rootWithPendingPassiveEffects; // Cache and clear the remaining lanes flag; it must be reset since this - // method can be called from various places, not always from commitRoot - // where the remaining lanes are known - - var remainingLanes = pendingPassiveEffectsRemainingLanes; - pendingPassiveEffectsRemainingLanes = NoLanes; - var renderPriority = lanesToEventPriority(pendingPassiveEffectsLanes); - var priority = lowerEventPriority(DefaultEventPriority, renderPriority); - var prevTransition = ReactSharedInternals.T; - var previousPriority = getCurrentUpdatePriority(); + remainingLanes = root.pendingLanes; // Check if this render scheduled a cascading synchronous update. This is a + // heurstic to detect infinite update loops. We are intentionally excluding + // hydration lanes in this check, because render triggered by selective + // hydration is conceptually not an update. - try { - setCurrentUpdatePriority(priority); - ReactSharedInternals.T = null; - return flushPassiveEffectsImpl(); - } finally { - setCurrentUpdatePriority(previousPriority); - ReactSharedInternals.T = prevTransition; // Once passive effects have run for the tree - giving components a - // chance to retain cache instances they use - release the pooled - // cache at the root (if there is one) + if ( // Check if there was a recursive update spawned by this render, in either + // the render phase or the commit phase. We track these explicitly because + // we can't infer from the remaining lanes alone. + // Was the finished render the result of an update (not hydration)? + includesSomeLane(lanes, UpdateLanes) && // Did it schedule a sync update? + includesSomeLane(remainingLanes, SyncUpdateLanes)) { + { + markNestedUpdateScheduled(); + } // Count the number of times the root synchronously re-renders without + // finishing. If there are too many, it indicates an infinite update loop. - releaseRootPooledCache(root, remainingLanes); - } - } - return false; + if (root === rootWithNestedUpdates) { + nestedUpdateCount++; + } else { + nestedUpdateCount = 0; + rootWithNestedUpdates = root; } - function enqueuePendingPassiveProfilerEffect(fiber) { - { - pendingPassiveProfilerEffects.push(fiber); + } else { + nestedUpdateCount = 0; + } // If layout work was scheduled, flush it now. - if (!rootDoesHavePassiveEffects) { - rootDoesHavePassiveEffects = true; - scheduleCallback(NormalPriority$1, function () { - flushPassiveEffects(); - return null; - }); - } - } - } - function flushPassiveEffectsImpl() { - if (rootWithPendingPassiveEffects === null) { - return false; - } // Cache and clear the transitions flag + flushSyncWorkOnAllRoots(); - var transitions = pendingPassiveTransitions; - pendingPassiveTransitions = null; - 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. + { + markCommitStopped(); + } - pendingPassiveEffectsLanes = NoLanes; + return null; +} - if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { - throw new Error( - "Cannot flush passive effects while already rendering." - ); - } +function makeErrorInfo(componentStack) { + var errorInfo = { + componentStack: componentStack + }; - { - isFlushingPassiveEffects = true; - didScheduleUpdateDuringPassiveEffects = false; + { + Object.defineProperty(errorInfo, 'digest', { + get: function () { + error('You are accessing "digest" from the errorInfo object passed to onRecoverableError.' + ' This property is no longer provided as part of errorInfo but can be accessed as a property' + ' of the Error instance itself.'); } + }); + } - { - markPassiveEffectsStarted(lanes); - } + return errorInfo; +} - var prevExecutionContext = executionContext; - executionContext |= CommitContext; - commitPassiveUnmountEffects(root.current); - commitPassiveMountEffects(root, root.current, lanes, transitions); // TODO: Move to commitPassiveMountEffects +function releaseRootPooledCache(root, remainingLanes) { + { + var pooledCacheLanes = root.pooledCacheLanes &= remainingLanes; - { - var profilerEffects = pendingPassiveProfilerEffects; - pendingPassiveProfilerEffects = []; + if (pooledCacheLanes === NoLanes) { + // None of the remaining work relies on the cache pool. Clear it so + // subsequent requests get a new cache + var pooledCache = root.pooledCache; - for (var i = 0; i < profilerEffects.length; i++) { - var fiber = profilerEffects[i]; - commitPassiveEffectDurations(root, fiber); - } + if (pooledCache != null) { + root.pooledCache = null; + releaseCache(pooledCache); } + } + } +} - { - markPassiveEffectsStopped(); - } +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) { + // Cache the root since rootWithPendingPassiveEffects is cleared in + // flushPassiveEffectsImpl + var root = rootWithPendingPassiveEffects; // Cache and clear the remaining lanes flag; it must be reset since this + // method can be called from various places, not always from commitRoot + // where the remaining lanes are known + + var remainingLanes = pendingPassiveEffectsRemainingLanes; + pendingPassiveEffectsRemainingLanes = NoLanes; + var renderPriority = lanesToEventPriority(pendingPassiveEffectsLanes); + var priority = lowerEventPriority(DefaultEventPriority, renderPriority); + var prevTransition = ReactSharedInternals.T; + var previousPriority = getCurrentUpdatePriority(); + + try { + setCurrentUpdatePriority(priority); + ReactSharedInternals.T = null; + return flushPassiveEffectsImpl(); + } finally { + setCurrentUpdatePriority(previousPriority); + ReactSharedInternals.T = prevTransition; // Once passive effects have run for the tree - giving components a + // chance to retain cache instances they use - release the pooled + // cache at the root (if there is one) + + releaseRootPooledCache(root, remainingLanes); + } + } + + return false; +} +function enqueuePendingPassiveProfilerEffect(fiber) { + { + pendingPassiveProfilerEffects.push(fiber); - { - commitDoubleInvokeEffectsInDEV(root, true); - } + if (!rootDoesHavePassiveEffects) { + rootDoesHavePassiveEffects = true; + scheduleCallback(NormalPriority$1, function () { + flushPassiveEffects(); + return null; + }); + } + } +} - executionContext = prevExecutionContext; - flushSyncWorkOnAllRoots(); +function flushPassiveEffectsImpl() { + if (rootWithPendingPassiveEffects === null) { + return false; + } // Cache and clear the transitions flag - { - // 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 { - nestedPassiveUpdateCount = 0; - } - isFlushingPassiveEffects = false; - didScheduleUpdateDuringPassiveEffects = false; - } // TODO: Move to commitPassiveMountEffects + var transitions = pendingPassiveTransitions; + pendingPassiveTransitions = null; + 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. - onPostCommitRoot(root); + pendingPassiveEffectsLanes = NoLanes; - { - var stateNode = root.current.stateNode; - stateNode.effectDuration = 0; - stateNode.passiveEffectDuration = 0; - } + if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { + throw new Error('Cannot flush passive effects while already rendering.'); + } - return true; - } + { + isFlushingPassiveEffects = true; + didScheduleUpdateDuringPassiveEffects = false; + } - function isAlreadyFailedLegacyErrorBoundary(instance) { - return ( - legacyErrorBoundariesThatAlreadyFailed !== null && - legacyErrorBoundariesThatAlreadyFailed.has(instance) - ); - } - function markLegacyErrorBoundaryAsFailed(instance) { - if (legacyErrorBoundariesThatAlreadyFailed === null) { - legacyErrorBoundariesThatAlreadyFailed = new Set([instance]); - } else { - legacyErrorBoundariesThatAlreadyFailed.add(instance); - } + { + markPassiveEffectsStarted(lanes); + } + + var prevExecutionContext = executionContext; + executionContext |= CommitContext; + commitPassiveUnmountEffects(root.current); + commitPassiveMountEffects(root, root.current, lanes, transitions); // TODO: Move to commitPassiveMountEffects + + { + var profilerEffects = pendingPassiveProfilerEffects; + pendingPassiveProfilerEffects = []; + + for (var i = 0; i < profilerEffects.length; i++) { + var fiber = profilerEffects[i]; + commitPassiveEffectDurations(root, fiber); } + } - function captureCommitPhaseErrorOnRoot(rootFiber, sourceFiber, error) { - var errorInfo = createCapturedValueAtFiber(error, sourceFiber); - var update = createRootErrorUpdate( - rootFiber.stateNode, - errorInfo, - SyncLane - ); - var root = enqueueUpdate(rootFiber, update, SyncLane); + { + markPassiveEffectsStopped(); + } - if (root !== null) { - markRootUpdated(root, SyncLane); - ensureRootIsScheduled(root); + { + commitDoubleInvokeEffectsInDEV(root, true); + } + + executionContext = prevExecutionContext; + flushSyncWorkOnAllRoots(); + + { + // 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 { + nestedPassiveUpdateCount = 0; } - function captureCommitPhaseError( - sourceFiber, - nearestMountedAncestor, - error$1 - ) { - { - setIsRunningInsertionEffect(false); - } + isFlushingPassiveEffects = false; + didScheduleUpdateDuringPassiveEffects = false; + } // TODO: Move to commitPassiveMountEffects - 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; - } - var fiber = nearestMountedAncestor; + onPostCommitRoot(root); - 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; + { + var stateNode = root.current.stateNode; + stateNode.effectDuration = 0; + stateNode.passiveEffectDuration = 0; + } - if ( - typeof ctor.getDerivedStateFromError === "function" || - (typeof instance.componentDidCatch === "function" && - !isAlreadyFailedLegacyErrorBoundary(instance)) - ) { - var errorInfo = createCapturedValueAtFiber(error$1, sourceFiber); - var update = createClassErrorUpdate(SyncLane); - var root = enqueueUpdate(fiber, update, SyncLane); - - if (root !== null) { - initializeClassErrorUpdate(update, root, fiber, errorInfo); - markRootUpdated(root, SyncLane); - ensureRootIsScheduled(root); - } + return true; +} - return; - } - } +function isAlreadyFailedLegacyErrorBoundary(instance) { + return legacyErrorBoundariesThatAlreadyFailed !== null && legacyErrorBoundariesThatAlreadyFailed.has(instance); +} +function markLegacyErrorBoundaryAsFailed(instance) { + if (legacyErrorBoundariesThatAlreadyFailed === null) { + legacyErrorBoundariesThatAlreadyFailed = new Set([instance]); + } else { + legacyErrorBoundariesThatAlreadyFailed.add(instance); + } +} - fiber = fiber.return; - } +function captureCommitPhaseErrorOnRoot(rootFiber, sourceFiber, error) { + var errorInfo = createCapturedValueAtFiber(error, sourceFiber); + var update = createRootErrorUpdate(rootFiber.stateNode, errorInfo, SyncLane); + var root = enqueueUpdate(rootFiber, update, SyncLane); - { - error( - "Internal React error: Attempted to capture a commit phase error " + - "inside a detached tree. This indicates a bug in React. Potential " + - "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; - - if (pingCache === null) { - pingCache = root.pingCache = new PossiblyWeakMap(); - threadIDs = new Set(); - pingCache.set(wakeable, threadIDs); - } else { - threadIDs = pingCache.get(wakeable); + if (root !== null) { + markRootUpdated(root, SyncLane); + ensureRootIsScheduled(root); + } +} + +function captureCommitPhaseError(sourceFiber, nearestMountedAncestor, 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; + } + + var fiber = nearestMountedAncestor; + + 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 (typeof ctor.getDerivedStateFromError === 'function' || typeof instance.componentDidCatch === 'function' && !isAlreadyFailedLegacyErrorBoundary(instance)) { + var errorInfo = createCapturedValueAtFiber(error$1, sourceFiber); + var update = createClassErrorUpdate(SyncLane); + var root = enqueueUpdate(fiber, update, SyncLane); - if (threadIDs === undefined) { - threadIDs = new Set(); - pingCache.set(wakeable, threadIDs); + if (root !== null) { + initializeClassErrorUpdate(update, root, fiber, errorInfo); + markRootUpdated(root, SyncLane); + ensureRootIsScheduled(root); } + + return; } + } - if (!threadIDs.has(lanes)) { - workInProgressRootDidAttachPingListener = true; // Memoize using the thread ID to prevent redundant listeners. + fiber = fiber.return; + } - threadIDs.add(lanes); - var ping = pingSuspendedRoot.bind(null, root, wakeable, lanes); + { + error('Internal React error: Attempted to capture a commit phase error ' + 'inside a detached tree. This indicates a bug in React. Potential ' + '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; + + if (pingCache === null) { + pingCache = root.pingCache = new PossiblyWeakMap(); + threadIDs = new Set(); + pingCache.set(wakeable, threadIDs); + } else { + threadIDs = pingCache.get(wakeable); + + if (threadIDs === undefined) { + threadIDs = new Set(); + pingCache.set(wakeable, threadIDs); + } + } + + if (!threadIDs.has(lanes)) { + workInProgressRootDidAttachPingListener = true; // Memoize using the thread ID to prevent redundant listeners. + + threadIDs.add(lanes); + var ping = pingSuspendedRoot.bind(null, root, wakeable, lanes); + + wakeable.then(ping, ping); + } +} - wakeable.then(ping, ping); +function pingSuspendedRoot(root, wakeable, pingedLanes) { + var pingCache = root.pingCache; + + if (pingCache !== null) { + // The wakeable resolved, so we no longer need to memoize, because it will + // never be thrown again. + pingCache.delete(wakeable); + } + + markRootPinged(root, pingedLanes); + warnIfSuspenseResolutionNotWrappedWithActDEV(root); + + 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); } + } - function pingSuspendedRoot(root, wakeable, pingedLanes) { - var pingCache = root.pingCache; + ensureRootIsScheduled(root); +} - if (pingCache !== null) { - // The wakeable resolved, so we no longer need to memoize, because it will - // never be thrown again. - pingCache.delete(wakeable); - } +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? - markRootPinged(root, pingedLanes); - warnIfSuspenseResolutionNotWrappedWithActDEV(root); - 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 - ); - } - } + var root = enqueueConcurrentRenderForLane(boundaryFiber, retryLane); - ensureRootIsScheduled(root); - } + if (root !== null) { + markRootUpdated(root, retryLane); + ensureRootIsScheduled(root); + } +} - 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? +function retryDehydratedSuspenseBoundary(boundaryFiber) { + var suspenseState = boundaryFiber.memoizedState; + var retryLane = NoLane; - var root = enqueueConcurrentRenderForLane(boundaryFiber, retryLane); + if (suspenseState !== null) { + retryLane = suspenseState.retryLane; + } - if (root !== null) { - markRootUpdated(root, retryLane); - ensureRootIsScheduled(root); - } - } + retryTimedOutBoundary(boundaryFiber, retryLane); +} +function resolveRetryWakeable(boundaryFiber, wakeable) { + var retryLane = NoLane; // Default + + var retryCache; - function retryDehydratedSuspenseBoundary(boundaryFiber) { + switch (boundaryFiber.tag) { + case SuspenseComponent: + retryCache = boundaryFiber.stateNode; var suspenseState = boundaryFiber.memoizedState; - var retryLane = NoLane; if (suspenseState !== null) { retryLane = suspenseState.retryLane; } - retryTimedOutBoundary(boundaryFiber, retryLane); - } - function resolveRetryWakeable(boundaryFiber, wakeable) { - var retryLane = NoLane; // Default + break; - var retryCache; + case SuspenseListComponent: + retryCache = boundaryFiber.stateNode; + break; - switch (boundaryFiber.tag) { - case SuspenseComponent: - retryCache = boundaryFiber.stateNode; - var suspenseState = boundaryFiber.memoizedState; + case OffscreenComponent: + { + var instance = boundaryFiber.stateNode; + retryCache = instance._retryCache; + break; + } - if (suspenseState !== null) { - retryLane = suspenseState.retryLane; - } + default: + throw new Error('Pinged unknown suspense boundary type. ' + 'This is probably a bug in React.'); + } - break; + if (retryCache !== null) { + // The wakeable resolved, so we no longer need to memoize, because it will + // never be thrown again. + retryCache.delete(wakeable); + } - case SuspenseListComponent: - retryCache = boundaryFiber.stateNode; - break; + retryTimedOutBoundary(boundaryFiber, retryLane); +} +function throwIfInfiniteUpdateLoopDetected() { + if (nestedUpdateCount > NESTED_UPDATE_LIMIT) { + nestedUpdateCount = 0; + nestedPassiveUpdateCount = 0; + rootWithNestedUpdates = null; + rootWithPassiveNestedUpdates = null; - case OffscreenComponent: { - var instance = boundaryFiber.stateNode; - retryCache = instance._retryCache; - break; - } + 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.'); + } - default: - throw new Error( - "Pinged unknown suspense boundary type. " + - "This is probably a bug in React." - ); - } + { + if (nestedPassiveUpdateCount > NESTED_PASSIVE_UPDATE_LIMIT) { + nestedPassiveUpdateCount = 0; + rootWithPassiveNestedUpdates = null; - if (retryCache !== null) { - // The wakeable resolved, so we no longer need to memoize, because it will - // never be thrown again. - retryCache.delete(wakeable); - } + 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.'); + } + } +} + +function flushRenderPhaseStrictModeWarningsInDEV() { + { + ReactStrictModeWarnings.flushLegacyContextWarning(); + ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings(); + } +} - retryTimedOutBoundary(boundaryFiber, retryLane); +function commitDoubleInvokeEffectsInDEV(root, hasPassiveEffects) { + { + { + legacyCommitDoubleInvokeEffectsInDEV(root.current, hasPassiveEffects); } - function throwIfInfiniteUpdateLoopDetected() { - if (nestedUpdateCount > NESTED_UPDATE_LIMIT) { - nestedUpdateCount = 0; - nestedPassiveUpdateCount = 0; - rootWithNestedUpdates = null; - rootWithPassiveNestedUpdates = null; + } +} + +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); + + if (hasPassiveEffects) { + invokeEffectsInDev(fiber, MountPassiveDev, invokePassiveEffectMountInDEV); + } + + resetCurrentFiber(); +} - 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." - ); +function invokeEffectsInDev(firstChild, fiberFlags, invokeEffectFn) { + var current = firstChild; + var subtreeRoot = null; + + while (current != null) { + var primarySubtreeFlag = current.subtreeFlags & fiberFlags; + + if (current !== subtreeRoot && current.child != null && primarySubtreeFlag !== NoFlags$1) { + current = current.child; + } else { + if ((current.flags & fiberFlags) !== NoFlags$1) { + invokeEffectFn(current); } - { - 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." - ); - } + if (current.sibling !== null) { + current = current.sibling; + } else { + current = subtreeRoot = current.return; } } + } +} - function flushRenderPhaseStrictModeWarningsInDEV() { - { - ReactStrictModeWarnings.flushLegacyContextWarning(); - ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings(); - } +var didWarnStateUpdateForNotYetMountedComponent = null; +function warnAboutUpdateOnNotYetMountedFiberInDEV(fiber) { + { + if ((executionContext & RenderContext) !== NoContext) { + // We let the other warning about render phase updates deal with this one. + return; } - function commitDoubleInvokeEffectsInDEV(root, hasPassiveEffects) { - { - { - legacyCommitDoubleInvokeEffectsInDEV(root.current, hasPassiveEffects); - } - } + if (!(fiber.mode & ConcurrentMode)) { + return; } - 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); + var tag = fiber.tag; - if (hasPassiveEffects) { - invokeEffectsInDev( - fiber, - MountPassiveDev, - invokePassiveEffectUnmountInDEV - ); - } + if (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. - invokeEffectsInDev(fiber, MountLayoutDev, invokeLayoutEffectMountInDEV); - if (hasPassiveEffects) { - invokeEffectsInDev( - fiber, - MountPassiveDev, - invokePassiveEffectMountInDEV - ); - } + var componentName = getComponentNameFromFiber(fiber) || 'ReactComponent'; - resetCurrentFiber(); - } + if (didWarnStateUpdateForNotYetMountedComponent !== null) { + if (didWarnStateUpdateForNotYetMountedComponent.has(componentName)) { + return; + } // $FlowFixMe[incompatible-use] found when upgrading Flow - function invokeEffectsInDev(firstChild, fiberFlags, invokeEffectFn) { - var current = firstChild; - var subtreeRoot = null; - while (current != null) { - var primarySubtreeFlag = current.subtreeFlags & fiberFlags; + didWarnStateUpdateForNotYetMountedComponent.add(componentName); + } else { + didWarnStateUpdateForNotYetMountedComponent = new Set([componentName]); + } - if ( - current !== subtreeRoot && - current.child != null && - primarySubtreeFlag !== NoFlags$1 - ) { - current = current.child; - } else { - if ((current.flags & fiberFlags) !== NoFlags$1) { - invokeEffectFn(current); - } + var previousFiber = current; - if (current.sibling !== null) { - current = current.sibling; - } else { - current = subtreeRoot = current.return; - } - } + 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 didWarnAboutUpdateInRender = false; +var didWarnAboutUpdateInRenderForAnotherComponent; - var didWarnStateUpdateForNotYetMountedComponent = null; - function warnAboutUpdateOnNotYetMountedFiberInDEV(fiber) { - { - if ((executionContext & RenderContext) !== NoContext) { - // We let the other warning about render phase updates deal with this one. - return; - } +{ + didWarnAboutUpdateInRenderForAnotherComponent = new Set(); +} - if (!(fiber.mode & ConcurrentMode)) { - return; - } +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. - var tag = fiber.tag; - - if ( - 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. + var dedupeKey = renderingComponentName; - var componentName = - getComponentNameFromFiber(fiber) || "ReactComponent"; + if (!didWarnAboutUpdateInRenderForAnotherComponent.has(dedupeKey)) { + didWarnAboutUpdateInRenderForAnotherComponent.add(dedupeKey); + var setStateComponentName = getComponentNameFromFiber(fiber) || 'Unknown'; - if (didWarnStateUpdateForNotYetMountedComponent !== null) { - if (didWarnStateUpdateForNotYetMountedComponent.has(componentName)) { - return; - } // $FlowFixMe[incompatible-use] found when upgrading Flow + 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://react.dev/link/setstate-in-render', setStateComponentName, renderingComponentName, renderingComponentName); + } - didWarnStateUpdateForNotYetMountedComponent.add(componentName); - } else { - didWarnStateUpdateForNotYetMountedComponent = new Set([ - componentName - ]); - } + break; + } - var previousFiber = current; + 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.'); - try { - setCurrentFiber(fiber); + didWarnAboutUpdateInRender = true; + } - 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(); + break; } - } } } - var didWarnAboutUpdateInRender = false; - var didWarnAboutUpdateInRenderForAnotherComponent; + } +} +var fakeActCallbackNode = {}; // $FlowFixMe[missing-local-annot] - { - didWarnAboutUpdateInRenderForAnotherComponent = new Set(); - } +function scheduleCallback(priorityLevel, callback) { + { + // If we're currently inside an `act` scope, bypass Scheduler and push to + // the `act` queue instead. + var actQueue = ReactSharedInternals.actQueue; - 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. - - var dedupeKey = renderingComponentName; - - 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://react.dev/link/setstate-in-render", - setStateComponentName, - renderingComponentName, - renderingComponentName - ); - } + if (actQueue !== null) { + actQueue.push(callback); + return fakeActCallbackNode; + } else { + return scheduleCallback$3(priorityLevel, callback); + } + } +} - break; - } +function shouldForceFlushFallbacksInDEV() { + // Never force flush in production. This function should get stripped out. + return ReactSharedInternals.actQueue !== 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." - ); +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; + } - didWarnAboutUpdateInRender = true; - } + if (executionContext !== NoContext) { + // Legacy mode doesn't warn if the update is batched, i.e. + // batchedUpdates or flushSync. + return; + } - break; - } - } - } + 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; } } - var fakeActCallbackNode = {}; // $FlowFixMe[missing-local-annot] - function scheduleCallback(priorityLevel, callback) { - { - // If we're currently inside an `act` scope, bypass Scheduler and push to - // the `act` queue instead. - var actQueue = ReactSharedInternals.actQueue; + if (ReactSharedInternals.actQueue === null) { + var previousFiber = current; + + try { + setCurrentFiber(fiber); - if (actQueue !== null) { - actQueue.push(callback); - return fakeActCallbackNode; + 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://react.dev/link/wrap-tests-with-act', getComponentNameFromFiber(fiber)); + } finally { + if (previousFiber) { + setCurrentFiber(fiber); } else { - return scheduleCallback$3(priorityLevel, callback); + resetCurrentFiber(); } } } + } +} - function shouldForceFlushFallbacksInDEV() { - // Never force flush in production. This function should get stripped out. - return ReactSharedInternals.actQueue !== null; +function warnIfSuspenseResolutionNotWrappedWithActDEV(root) { + { + if ((root.tag !== LegacyRoot) && isConcurrentActEnvironment() && ReactSharedInternals.actQueue === 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://react.dev/link/wrap-tests-with-act'); } + } +} - 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 (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; - } - } - - if (ReactSharedInternals.actQueue === null) { - var previousFiber = current; +function setIsRunningInsertionEffect(isRunning) { + { + isRunningInsertionEffect = isRunning; + } +} - try { - setCurrentFiber(fiber); - - 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://react.dev/link/wrap-tests-with-act", - getComponentNameFromFiber(fiber) - ); - } finally { - if (previousFiber) { - setCurrentFiber(fiber); - } else { - resetCurrentFiber(); - } - } - } - } - } +/* eslint-disable react-internal/prod-error-codes */ +// Used by React Refresh runtime through DevTools Global Hook. - function warnIfSuspenseResolutionNotWrappedWithActDEV(root) { - { - if ( - root.tag !== LegacyRoot && - isConcurrentActEnvironment() && - ReactSharedInternals.actQueue === 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://react.dev/link/wrap-tests-with-act" - ); - } - } +var resolveFamily = null; +var failedBoundaries = null; +var setRefreshHandler = function (handler) { + { + resolveFamily = handler; + } +}; +function resolveFunctionForHotReloading(type) { + { + if (resolveFamily === null) { + // Hot reloading is disabled. + return type; } - function setIsRunningInsertionEffect(isRunning) { - { - isRunningInsertionEffect = isRunning; - } - } + var family = resolveFamily(type); - /* eslint-disable react-internal/prod-error-codes */ - // Used by React Refresh runtime through DevTools Global Hook. + if (family === undefined) { + return type; + } // Use the latest known implementation. - var resolveFamily = null; - var failedBoundaries = null; - var setRefreshHandler = function (handler) { - { - resolveFamily = handler; - } - }; - function resolveFunctionForHotReloading(type) { - { - if (resolveFamily === null) { - // Hot reloading is disabled. - return type; - } - var family = resolveFamily(type); + return family.current; + } +} +function resolveClassForHotReloading(type) { + // No implementation differences. + return resolveFunctionForHotReloading(type); +} +function resolveForwardRefForHotReloading(type) { + { + if (resolveFamily === null) { + // Hot reloading is disabled. + return type; + } + + var family = resolveFamily(type); + + 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 (type.render !== currentRender) { + var syntheticType = { + $$typeof: REACT_FORWARD_REF_TYPE, + render: currentRender + }; - if (family === undefined) { - return type; - } // Use the latest known implementation. + if (type.displayName !== undefined) { + syntheticType.displayName = type.displayName; + } - 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 syntheticType; } + } - var family = resolveFamily(type); - - 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 (type.render !== currentRender) { - var syntheticType = { - $$typeof: REACT_FORWARD_REF_TYPE, - render: currentRender - }; - - if (type.displayName !== undefined) { - syntheticType.displayName = type.displayName; - } - - return syntheticType; - } - } + return type; + } // Use the latest known implementation. - return type; - } // Use the latest known implementation. - return family.current; - } + return family.current; + } +} +function isCompatibleFamilyForHotReloading(fiber, element) { + { + if (resolveFamily === null) { + // Hot reloading is disabled. + return false; } - 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 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; + var needsCompareFamilies = false; + var $$typeofNextType = typeof nextType === 'object' && nextType !== null ? nextType.$$typeof : null; - switch (fiber.tag) { - case ClassComponent: { - if (typeof nextType === "function") { - needsCompareFamilies = true; - } - - break; + switch (fiber.tag) { + case ClassComponent: + { + if (typeof nextType === 'function') { + needsCompareFamilies = true; } - 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; - } + break; + } - break; + 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; } - case ForwardRef: { - if ($$typeofNextType === REACT_FORWARD_REF_TYPE) { - needsCompareFamilies = true; - } else if ($$typeofNextType === REACT_LAZY_TYPE) { - needsCompareFamilies = true; - } + break; + } - break; + case ForwardRef: + { + if ($$typeofNextType === REACT_FORWARD_REF_TYPE) { + needsCompareFamilies = true; + } else if ($$typeofNextType === REACT_LAZY_TYPE) { + needsCompareFamilies = true; } - 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; - } + break; + } - break; + 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; } - default: - return false; - } // Check if both types have a family and it's the same one. - - 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 - - if ( - prevFamily !== undefined && - prevFamily === resolveFamily(nextType) - ) { - return true; - } + break; } + default: return false; - } - } - function markFailedErrorBoundaryForHotReloading(fiber) { - { - if (resolveFamily === null) { - // Hot reloading is disabled. - return; - } + } // Check if both types have a family and it's the same one. - if (typeof WeakSet !== "function") { - return; - } - if (failedBoundaries === null) { - failedBoundaries = new WeakSet(); - } + 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 - failedBoundaries.add(fiber); + if (prevFamily !== undefined && prevFamily === resolveFamily(nextType)) { + return true; } } - var scheduleRefresh = function (root, update) { - { - if (resolveFamily === null) { - // Hot reloading is disabled. - return; - } - var staleFamilies = update.staleFamilies, - updatedFamilies = update.updatedFamilies; - flushPassiveEffects(); - scheduleFibersWithFamiliesRecursively( - root.current, - updatedFamilies, - staleFamilies - ); - flushSyncWork(); - } - }; - 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; - } + return false; + } +} +function markFailedErrorBoundaryForHotReloading(fiber) { + { + if (resolveFamily === null) { + // Hot reloading is disabled. + return; + } - updateContainerSync(element, root, null, null); - flushSyncWork(); - } - }; + if (typeof WeakSet !== 'function') { + return; + } - function scheduleFibersWithFamiliesRecursively( - fiber, - updatedFamilies, - staleFamilies - ) { - { - var alternate = fiber.alternate, - 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; + if (failedBoundaries === null) { + failedBoundaries = new WeakSet(); + } - case ForwardRef: - candidateType = type.render; - break; - } + failedBoundaries.add(fiber); + } +} +var scheduleRefresh = function (root, update) { + { + if (resolveFamily === null) { + // Hot reloading is disabled. + return; + } + + var staleFamilies = update.staleFamilies, + updatedFamilies = update.updatedFamilies; + flushPassiveEffects(); + scheduleFibersWithFamiliesRecursively(root.current, updatedFamilies, staleFamilies); + flushSyncWork(); + } +}; +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; + } + + updateContainerSync(element, root, null, null); + flushSyncWork(); + } +}; + +function scheduleFibersWithFamiliesRecursively(fiber, updatedFamilies, staleFamilies) { + { + var alternate = fiber.alternate, + child = fiber.child, + sibling = fiber.sibling, + tag = fiber.tag, + type = fiber.type; + var candidateType = null; - if (resolveFamily === null) { - throw new Error( - "Expected resolveFamily to be set during hot reload." - ); - } + switch (tag) { + case FunctionComponent: + case SimpleMemoComponent: + case ClassComponent: + candidateType = type; + break; - var needsRender = false; - var needsRemount = false; + case ForwardRef: + candidateType = type.render; + break; + } - if (candidateType !== null) { - var family = resolveFamily(candidateType); + if (resolveFamily === null) { + throw new Error('Expected resolveFamily to be set during hot reload.'); + } - if (family !== undefined) { - if (staleFamilies.has(family)) { - needsRemount = true; - } else if (updatedFamilies.has(family)) { - if (tag === ClassComponent) { - needsRemount = true; - } else { - needsRender = true; - } - } - } - } + var needsRender = false; + var needsRemount = false; - if (failedBoundaries !== null) { - if ( - failedBoundaries.has(fiber) || // $FlowFixMe[incompatible-use] found when upgrading Flow - (alternate !== null && failedBoundaries.has(alternate)) - ) { + if (candidateType !== null) { + var family = resolveFamily(candidateType); + + if (family !== undefined) { + if (staleFamilies.has(family)) { + needsRemount = true; + } else if (updatedFamilies.has(family)) { + if (tag === ClassComponent) { needsRemount = true; + } else { + needsRender = true; } } + } + } - if (needsRemount) { - fiber._debugNeedsRemount = true; - } - - if (needsRemount || needsRender) { - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + if (failedBoundaries !== null) { + if (failedBoundaries.has(fiber) || // $FlowFixMe[incompatible-use] found when upgrading Flow + alternate !== null && failedBoundaries.has(alternate)) { + needsRemount = true; + } + } - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane); - } - } + if (needsRemount) { + fiber._debugNeedsRemount = true; + } - if (child !== null && !needsRemount) { - scheduleFibersWithFamiliesRecursively( - child, - updatedFamilies, - staleFamilies - ); - } + if (needsRemount || needsRender) { + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - if (sibling !== null) { - scheduleFibersWithFamiliesRecursively( - sibling, - updatedFamilies, - staleFamilies - ); - } + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane); } } - 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; - } - }; + if (child !== null && !needsRemount) { + scheduleFibersWithFamiliesRecursively(child, updatedFamilies, staleFamilies); + } - 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; + if (sibling !== null) { + scheduleFibersWithFamiliesRecursively(sibling, updatedFamilies, staleFamilies); + } + } +} - case ForwardRef: - candidateType = type.render; - break; - } +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; - var didMatch = false; + switch (tag) { + case FunctionComponent: + case SimpleMemoComponent: + case ClassComponent: + candidateType = type; + break; - if (candidateType !== null) { - if (types.has(candidateType)) { - didMatch = true; - } - } + case ForwardRef: + candidateType = type.render; + break; + } - 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 - ); - } - } + var didMatch = false; - if (sibling !== null) { - findHostInstancesForMatchingFibersRecursively( - sibling, - types, - hostInstances - ); - } + if (candidateType !== null) { + if (types.has(candidateType)) { + didMatch = true; } } - function findHostInstancesForFiberShallowly(fiber, hostInstances) { - { - var foundHostInstances = findChildHostInstancesForFiberShallowly( - fiber, - hostInstances - ); + 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); + } + } - if (foundHostInstances) { - return; - } // If we didn't find any host children, fallback to closest host parent. + if (sibling !== null) { + findHostInstancesForMatchingFibersRecursively(sibling, types, hostInstances); + } + } +} - var node = fiber; +function findHostInstancesForFiberShallowly(fiber, hostInstances) { + { + var foundHostInstances = findChildHostInstancesForFiberShallowly(fiber, hostInstances); - while (true) { - switch (node.tag) { - case HostSingleton: - case HostComponent: - hostInstances.add(node.stateNode); - return; + if (foundHostInstances) { + return; + } // If we didn't find any host children, fallback to closest host parent. - case HostPortal: - hostInstances.add(node.stateNode.containerInfo); - return; - case HostRoot: - hostInstances.add(node.stateNode.containerInfo); - return; - } + var node = fiber; - if (node.return === null) { - throw new Error("Expected to reach root first."); - } + while (true) { + switch (node.tag) { + case HostSingleton: + case HostComponent: + hostInstances.add(node.stateNode); + return; - node = node.return; - } + case HostPortal: + hostInstances.add(node.stateNode.containerInfo); + return; + + case HostRoot: + hostInstances.add(node.stateNode.containerInfo); + return; } - } - function findChildHostInstancesForFiberShallowly(fiber, hostInstances) { - { - var node = fiber; - var foundHostInstances = false; - - 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; - } + if (node.return === null) { + throw new Error('Expected to reach root first.'); + } - if (node === fiber) { - return foundHostInstances; - } + node = node.return; + } + } +} - while (node.sibling === null) { - if (node.return === null || node.return === fiber) { - return foundHostInstances; - } +function findChildHostInstancesForFiberShallowly(fiber, hostInstances) { + { + var node = fiber; + var foundHostInstances = false; - node = node.return; - } + 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; + } - node.sibling.return = node.return; - node = node.sibling; + if (node === fiber) { + return foundHostInstances; + } + + while (node.sibling === null) { + if (node.return === null || node.return === fiber) { + return foundHostInstances; } + + node = node.return; } - return false; + node.sibling.return = node.return; + node = node.sibling; } + } - var hasBadMapPolyfill; - - { - hasBadMapPolyfill = false; + return false; +} - try { - var nonExtensibleObject = Object.preventExtensions({}); - /* eslint-disable no-new */ - - new Map([[nonExtensibleObject, null]]); - new Set([nonExtensibleObject]); - /* eslint-enable no-new */ - } catch (e) { - // TODO: Consider warning about bad polyfills - hasBadMapPolyfill = true; - } - } - - function FiberNode(tag, pendingProps, key, mode) { - // Instance - this.tag = tag; - this.key = key; - this.elementType = null; - this.type = null; - this.stateNode = null; // Fiber - - 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.flags = NoFlags$1; - this.subtreeFlags = NoFlags$1; - this.deletions = null; - this.lanes = NoLanes; - this.childLanes = NoLanes; - this.alternate = null; +var hasBadMapPolyfill; - { - // 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). - - this.actualDuration = 0; - this.actualStartTime = -1; - this.selfBaseDuration = 0; - this.treeBaseDuration = 0; - } +{ + hasBadMapPolyfill = false; - { - // This isn't directly used but is handy for debugging internals: - this._debugInfo = null; - this._debugOwner = null; - this._debugNeedsRemount = false; - this._debugHookTypes = null; - - 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[invalid-constructor]: the shapes are exact here but Flow doesn't like constructors - return new FiberNode(tag, pendingProps, key, mode); - } - - function shouldConstruct(Component) { - var prototype = Component.prototype; - return !!(prototype && prototype.isReactComponent); - } - - function isSimpleFunctionComponent(type) { - return ( - typeof type === "function" && - !shouldConstruct(type) && - type.defaultProps === undefined - ); - } - function isFunctionClassComponent(type) { - return shouldConstruct(type); - } // This is used to create an alternate fiber to do work on. - - function createWorkInProgress(current, pendingProps) { - var workInProgress = current.alternate; - - 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; + try { + var nonExtensibleObject = Object.preventExtensions({}); + /* eslint-disable no-new */ - { - // DEV-only fields - workInProgress._debugOwner = current._debugOwner; - workInProgress._debugHookTypes = current._debugHookTypes; - } + new Map([[nonExtensibleObject, null]]); + new Set([nonExtensibleObject]); + /* eslint-enable no-new */ + } catch (e) { + // TODO: Consider warning about bad polyfills + hasBadMapPolyfill = true; + } +} - workInProgress.alternate = current; - current.alternate = workInProgress; - } else { - workInProgress.pendingProps = pendingProps; // Needed because Blocks store data on type. +function FiberNode(tag, pendingProps, key, mode) { + // Instance + this.tag = tag; + this.key = key; + this.elementType = null; + this.type = null; + this.stateNode = null; // Fiber + + 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.flags = NoFlags$1; + this.subtreeFlags = NoFlags$1; + this.deletions = null; + this.lanes = NoLanes; + this.childLanes = NoLanes; + this.alternate = null; + + { + // 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). + + this.actualDuration = 0; + this.actualStartTime = -1; + this.selfBaseDuration = 0; + this.treeBaseDuration = 0; + } + + { + // This isn't directly used but is handy for debugging internals: + this._debugInfo = null; + this._debugOwner = null; + this._debugNeedsRemount = false; + this._debugHookTypes = null; + + 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[invalid-constructor]: the shapes are exact here but Flow doesn't like constructors + return new FiberNode(tag, pendingProps, key, mode); +} - workInProgress.type = current.type; // We already have an alternate. - // Reset the effect tag. +function shouldConstruct(Component) { + var prototype = Component.prototype; + return !!(prototype && prototype.isReactComponent); +} - workInProgress.flags = NoFlags$1; // The effects are no longer valid. +function isSimpleFunctionComponent(type) { + return typeof type === 'function' && !shouldConstruct(type) && type.defaultProps === undefined; +} +function isFunctionClassComponent(type) { + return shouldConstruct(type); +} // This is used to create an alternate fiber to do work on. + +function createWorkInProgress(current, pendingProps) { + var workInProgress = current.alternate; + + 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; - workInProgress.subtreeFlags = NoFlags$1; - workInProgress.deletions = null; + { + // DEV-only fields + workInProgress._debugOwner = current._debugOwner; + workInProgress._debugHookTypes = current._debugHookTypes; + } - { - // 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. - - 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 - - workInProgress.sibling = current.sibling; - workInProgress.index = current.index; - workInProgress.ref = current.ref; - workInProgress.refCleanup = current.refCleanup; + workInProgress.alternate = current; + current.alternate = workInProgress; + } else { + workInProgress.pendingProps = pendingProps; // Needed because Blocks store data on type. - { - workInProgress.selfBaseDuration = current.selfBaseDuration; - workInProgress.treeBaseDuration = current.treeBaseDuration; - } + workInProgress.type = current.type; // We already have an alternate. + // Reset the effect tag. - { - workInProgress._debugInfo = current._debugInfo; - workInProgress._debugNeedsRemount = current._debugNeedsRemount; + workInProgress.flags = NoFlags$1; // The effects are no longer valid. - switch (workInProgress.tag) { - case FunctionComponent: - case SimpleMemoComponent: - workInProgress.type = resolveFunctionForHotReloading(current.type); - break; + workInProgress.subtreeFlags = NoFlags$1; + workInProgress.deletions = null; - case ClassComponent: - workInProgress.type = resolveClassForHotReloading(current.type); - break; + { + // 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. + + + 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 + + workInProgress.sibling = current.sibling; + workInProgress.index = current.index; + workInProgress.ref = current.ref; + workInProgress.refCleanup = current.refCleanup; + + { + workInProgress.selfBaseDuration = current.selfBaseDuration; + workInProgress.treeBaseDuration = current.treeBaseDuration; + } + + { + workInProgress._debugInfo = current._debugInfo; + workInProgress._debugNeedsRemount = current._debugNeedsRemount; + + switch (workInProgress.tag) { + case FunctionComponent: + case SimpleMemoComponent: + workInProgress.type = resolveFunctionForHotReloading(current.type); + break; + + case ClassComponent: + workInProgress.type = resolveClassForHotReloading(current.type); + break; + + case ForwardRef: + workInProgress.type = resolveForwardRefForHotReloading(current.type); + break; + } + } + + 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 current = workInProgress.alternate; + + 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; - case ForwardRef: - workInProgress.type = resolveForwardRefForHotReloading( - current.type - ); - break; - } - } + { + // 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. + + workInProgress.type = current.type; // 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 + }; - return workInProgress; - } // Used to reuse a Fiber for a second pass. + { + // 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; + } + } - 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. + return workInProgress; +} +function createHostRootFiber(tag, isStrictMode, concurrentUpdatesByDefaultOverride) { + var mode; - var current = workInProgress.alternate; + if (tag === ConcurrentRoot) { + mode = ConcurrentMode; - 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 (isStrictMode === true) { + mode |= StrictLegacyMode | StrictEffectsMode; + } - { - // 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. - - workInProgress.type = current.type; // 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 - }; + if ( // Only for internal experiments. + concurrentUpdatesByDefaultOverride) { + mode |= ConcurrentUpdatesByDefaultMode; + } + } else { + mode = NoMode; + } - { - // 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; - } - } + 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; + } - return workInProgress; - } - function createHostRootFiber( - tag, - isStrictMode, - concurrentUpdatesByDefaultOverride - ) { - var mode; + return createFiber(HostRoot, null, null, mode); +} +function createFiberFromTypeAndProps(type, // React$ElementType +key, pendingProps, owner, mode, lanes) { + var fiberTag = FunctionComponent; // The resolved type is set if we know what the final type will be. I.e. it's not lazy. - if (tag === ConcurrentRoot) { - mode = ConcurrentMode; + var resolvedType = type; - if (isStrictMode === true) { - mode |= StrictLegacyMode | StrictEffectsMode; - } + if (typeof type === 'function') { + if (shouldConstruct(type)) { + fiberTag = ClassComponent; - if ( - // Only for internal experiments. - concurrentUpdatesByDefaultOverride - ) { - mode |= ConcurrentUpdatesByDefaultMode; - } - } else { - mode = NoMode; + { + resolvedType = resolveClassForHotReloading(resolvedType); } - - 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; + } else { + { + resolvedType = resolveFunctionForHotReloading(resolvedType); } - - return createFiber(HostRoot, null, null, mode); } - function createFiberFromTypeAndProps( - type, // React$ElementType - key, - pendingProps, - owner, - mode, - lanes - ) { - var fiberTag = FunctionComponent; // The resolved type is set if we know what the final type will be. I.e. it's not lazy. - - var resolvedType = type; + } else if (typeof type === 'string') { + { + fiberTag = HostComponent; + } + } else { + getTag: switch (type) { + case REACT_FRAGMENT_TYPE: + return createFiberFromFragment(pendingProps.children, mode, lanes, key); - if (typeof type === "function") { - if (shouldConstruct(type)) { - fiberTag = ClassComponent; + case REACT_STRICT_MODE_TYPE: + fiberTag = Mode; + mode |= StrictLegacyMode; - { - resolvedType = resolveClassForHotReloading(resolvedType); - } - } else { - { - resolvedType = resolveFunctionForHotReloading(resolvedType); - } - } - } else if (typeof type === "string") { - { - fiberTag = HostComponent; + if ((mode & ConcurrentMode) !== NoMode) { + // Strict effects should never run on legacy roots + mode |= StrictEffectsMode; } - } 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; - } - - break; + break; - case REACT_PROFILER_TYPE: - return createFiberFromProfiler(pendingProps, mode, lanes, key); + case REACT_PROFILER_TYPE: + return createFiberFromProfiler(pendingProps, mode, lanes, key); - case REACT_SUSPENSE_TYPE: - return createFiberFromSuspense(pendingProps, mode, lanes, key); + case REACT_SUSPENSE_TYPE: + return createFiberFromSuspense(pendingProps, mode, lanes, key); - case REACT_SUSPENSE_LIST_TYPE: - return createFiberFromSuspenseList(pendingProps, mode, lanes, key); + case REACT_SUSPENSE_LIST_TYPE: + return createFiberFromSuspenseList(pendingProps, mode, lanes, key); - case REACT_OFFSCREEN_TYPE: - return createFiberFromOffscreen(pendingProps, mode, lanes, key); + case REACT_OFFSCREEN_TYPE: + return createFiberFromOffscreen(pendingProps, mode, lanes, key); - case REACT_LEGACY_HIDDEN_TYPE: + case REACT_LEGACY_HIDDEN_TYPE: - // Fall through + // Fall through - case REACT_SCOPE_TYPE: + case REACT_SCOPE_TYPE: - // Fall through + // Fall through - case REACT_TRACING_MARKER_TYPE: + case REACT_TRACING_MARKER_TYPE: - // Fall through + // Fall through - case REACT_DEBUG_TRACING_MODE_TYPE: + case REACT_DEBUG_TRACING_MODE_TYPE: - // Fall through + // Fall through - default: { - if (typeof type === "object" && type !== null) { - switch (type.$$typeof) { - case REACT_PROVIDER_TYPE: { + default: + { + if (typeof type === 'object' && type !== null) { + switch (type.$$typeof) { + case REACT_PROVIDER_TYPE: + { fiberTag = ContextProvider; break getTag; } - // Fall through + // Fall through - case REACT_CONTEXT_TYPE: { + case REACT_CONTEXT_TYPE: + { fiberTag = ContextConsumer; break getTag; } - case REACT_CONSUMER_TYPE: + case REACT_CONSUMER_TYPE: - // Fall through + // Fall through - case REACT_FORWARD_REF_TYPE: - fiberTag = ForwardRef; + case REACT_FORWARD_REF_TYPE: + fiberTag = ForwardRef; - { - resolvedType = - resolveForwardRefForHotReloading(resolvedType); - } + { + resolvedType = resolveForwardRefForHotReloading(resolvedType); + } - break getTag; + break getTag; - case REACT_MEMO_TYPE: - fiberTag = MemoComponent; - break getTag; + case REACT_MEMO_TYPE: + fiberTag = MemoComponent; + break getTag; - case REACT_LAZY_TYPE: - fiberTag = LazyComponent; - resolvedType = null; - break getTag; - } + case REACT_LAZY_TYPE: + fiberTag = LazyComponent; + resolvedType = null; + break getTag; } + } - var info = ""; + var info = ''; - { - 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 (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 ownerName = owner ? getComponentNameFromOwner(owner) : null; + var ownerName = owner ? getComponentNameFromOwner(owner) : null; - if (ownerName) { - info += "\n\nCheck the render method of `" + ownerName + "`."; - } + if (ownerName) { + info += '\n\nCheck the render method of `' + ownerName + '`.'; } - - 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) - ); } + + 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)); } - } + } + } - var fiber = createFiber(fiberTag, pendingProps, key, mode); - fiber.elementType = type; - fiber.type = resolvedType; - fiber.lanes = lanes; + var fiber = createFiber(fiberTag, pendingProps, key, mode); + fiber.elementType = type; + fiber.type = resolvedType; + fiber.lanes = lanes; - { - fiber._debugOwner = owner; - } + { + fiber._debugOwner = owner; + } - return fiber; - } - function createFiberFromElement(element, mode, lanes) { - var owner = null; + return fiber; +} +function createFiberFromElement(element, mode, lanes) { + var owner = null; - { - owner = element._owner; - } + { + owner = element._owner; + } - var type = element.type; - var key = element.key; - var pendingProps = element.props; - var fiber = createFiberFromTypeAndProps( - type, - key, - pendingProps, - owner, - mode, - lanes - ); + var type = element.type; + var key = element.key; + var pendingProps = element.props; + var fiber = createFiberFromTypeAndProps(type, key, pendingProps, owner, mode, lanes); - { - fiber._debugOwner = element._owner; - } + { + fiber._debugOwner = element._owner; + } - return fiber; - } - function createFiberFromFragment(elements, mode, lanes, key) { - var fiber = createFiber(Fragment, elements, key, mode); - fiber.lanes = lanes; - return fiber; + return fiber; +} +function createFiberFromFragment(elements, mode, lanes, key) { + var fiber = createFiber(Fragment, elements, key, mode); + fiber.lanes = lanes; + return fiber; +} + +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); } + } - 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 - ); - } - } + var fiber = createFiber(Profiler, pendingProps, key, mode | ProfileMode); + fiber.elementType = REACT_PROFILER_TYPE; + fiber.lanes = lanes; - var fiber = createFiber(Profiler, pendingProps, key, mode | ProfileMode); - fiber.elementType = REACT_PROFILER_TYPE; - fiber.lanes = lanes; + { + fiber.stateNode = { + effectDuration: 0, + passiveEffectDuration: 0 + }; + } - { - fiber.stateNode = { - effectDuration: 0, - passiveEffectDuration: 0 - }; - } + return fiber; +} - return fiber; - } - - 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 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; - } - - function FiberRootNode( - containerInfo, // $FlowFixMe[missing-local-annot] - tag, - hydrate, - identifierPrefix, - onUncaughtError, - onCaughtError, - onRecoverableError, - formState - ) { - 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.next = null; - this.callbackNode = null; - this.callbackPriority = NoLane; - this.expirationTimes = createLaneMap(NoTimestamp); - this.pendingLanes = NoLanes; - this.suspendedLanes = NoLanes; - this.pingedLanes = NoLanes; - this.expiredLanes = NoLanes; - this.finishedLanes = NoLanes; - this.errorRecoveryDisabledLanes = NoLanes; - this.shellSuspendCounter = 0; - this.entangledLanes = NoLanes; - this.entanglements = createLaneMap(NoLanes); - this.hiddenUpdates = createLaneMap(null); - this.identifierPrefix = identifierPrefix; - this.onUncaughtError = onUncaughtError; - this.onCaughtError = onCaughtError; - this.onRecoverableError = onRecoverableError; +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 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; +} - { - this.pooledCache = null; - this.pooledCacheLanes = NoLanes; +function FiberRootNode(containerInfo, // $FlowFixMe[missing-local-annot] +tag, hydrate, identifierPrefix, onUncaughtError, onCaughtError, onRecoverableError, formState) { + 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.next = null; + this.callbackNode = null; + this.callbackPriority = NoLane; + this.expirationTimes = createLaneMap(NoTimestamp); + this.pendingLanes = NoLanes; + this.suspendedLanes = NoLanes; + this.pingedLanes = NoLanes; + this.expiredLanes = NoLanes; + this.finishedLanes = NoLanes; + this.errorRecoveryDisabledLanes = NoLanes; + this.shellSuspendCounter = 0; + this.entangledLanes = NoLanes; + this.entanglements = createLaneMap(NoLanes); + this.hiddenUpdates = createLaneMap(null); + this.identifierPrefix = identifierPrefix; + this.onUncaughtError = onUncaughtError; + this.onCaughtError = onCaughtError; + this.onRecoverableError = onRecoverableError; + + { + this.pooledCache = null; + this.pooledCacheLanes = NoLanes; + } + + this.formState = formState; + this.incompleteTransitions = new Map(); + + { + this.effectDuration = 0; + this.passiveEffectDuration = 0; + } + + { + { + switch (tag) { + case ConcurrentRoot: + this._debugRootType = hydrate ? 'hydrateRoot()' : 'createRoot()'; + break; + + case LegacyRoot: + this._debugRootType = hydrate ? 'hydrate()' : 'render()'; + break; } + } + } +} - this.formState = formState; - this.incompleteTransitions = new Map(); +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, onUncaughtError, onCaughtError, onRecoverableError, transitionCallbacks, formState) { + // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions + var root = new FiberRootNode(containerInfo, tag, hydrate, identifierPrefix, onUncaughtError, onCaughtError, onRecoverableError, formState); + // stateNode is any. + + + var uninitializedFiber = createHostRootFiber(tag, isStrictMode, concurrentUpdatesByDefaultOverride); + root.current = uninitializedFiber; + uninitializedFiber.stateNode = root; + + { + var initialCache = createCache(); + retainCache(initialCache); // The pooledCache is a fresh cache instance that is used temporarily + // for newly mounted boundaries during a render. In general, the + // pooledCache is always cleared from the root at the end of a render: + // it is either released when render commits, or moved to an Offscreen + // component if rendering suspends. Because the lifetime of the pooled + // cache is distinct from the main memoizedState.cache, it must be + // retained separately. + + root.pooledCache = initialCache; + retainCache(initialCache); + var initialState = { + element: initialChildren, + isDehydrated: hydrate, + cache: initialCache + }; + uninitializedFiber.memoizedState = initialState; + } - { - this.effectDuration = 0; - this.passiveEffectDuration = 0; - } + initializeUpdateQueue(uninitializedFiber); + return root; +} - { - { - switch (tag) { - case ConcurrentRoot: - this._debugRootType = hydrate ? "hydrateRoot()" : "createRoot()"; - break; +var ReactVersion = '19.0.0-canary-8eb36427'; - case LegacyRoot: - this._debugRootType = hydrate ? "hydrate()" : "render()"; - break; - } - } - } +/* + * 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[incompatible-return] 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[incompatible-return] + + return type; + } +} // $FlowFixMe[incompatible-return] only called in DEV, so void return is not possible. + + +function willCoercionThrow(value) { + { + try { + testStringCoercion(value); + return false; + } catch (e) { + return true; } + } +} - 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, - onUncaughtError, - onCaughtError, - onRecoverableError, - transitionCallbacks, - formState - ) { - // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions - var root = new FiberRootNode( - containerInfo, - tag, - hydrate, - identifierPrefix, - onUncaughtError, - onCaughtError, - onRecoverableError, - formState - ); - // stateNode is any. - - var uninitializedFiber = createHostRootFiber( - tag, - isStrictMode, - concurrentUpdatesByDefaultOverride - ); - root.current = uninitializedFiber; - uninitializedFiber.stateNode = root; - - { - var initialCache = createCache(); - retainCache(initialCache); // The pooledCache is a fresh cache instance that is used temporarily - // for newly mounted boundaries during a render. In general, the - // pooledCache is always cleared from the root at the end of a render: - // it is either released when render commits, or moved to an Offscreen - // component if rendering suspends. Because the lifetime of the pooled - // cache is distinct from the main memoizedState.cache, it must be - // retained separately. - - root.pooledCache = initialCache; - retainCache(initialCache); - var initialState = { - element: initialChildren, - isDehydrated: hydrate, - cache: initialCache - }; - uninitializedFiber.memoizedState = initialState; - } +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 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 using it here.', propName, typeName(value)); - initializeUpdateQueue(uninitializedFiber); - return root; + return testStringCoercion(value); // throw (to help callers find troubleshooting comments) } + } +} - var ReactVersion = "19.0.0-canary-a47ffde4"; - - /* - * 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[incompatible-return] 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[incompatible-return] +// Might add PROFILE later. - return type; - } - } // $FlowFixMe[incompatible-return] only called in DEV, so void return is not possible. +var didWarnAboutNestedUpdates; - function willCoercionThrow(value) { - { - try { - testStringCoercion(value); - return false; - } catch (e) { - return true; - } - } - } +{ + didWarnAboutNestedUpdates = false; +} - 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 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 using it here.", - propName, - typeName(value) - ); - - return testStringCoercion(value); // throw (to help callers find troubleshooting comments) - } - } - } +function getContextForSubtree(parentComponent) { + if (!parentComponent) { + return emptyContextObject; + } - // Might add PROFILE later. + var fiber = get(parentComponent); + var parentContext = findCurrentUnmaskedContext(fiber); - var didWarnAboutNestedUpdates; + if (fiber.tag === ClassComponent) { + var Component = fiber.type; - { - didWarnAboutNestedUpdates = false; + if (isContextProvider(Component)) { + return processChildContext(fiber, Component, parentContext); } + } - function getContextForSubtree(parentComponent) { - if (!parentComponent) { - return emptyContextObject; - } + return parentContext; +} - var fiber = get(parentComponent); - var parentContext = findCurrentUnmaskedContext(fiber); +function createContainer(containerInfo, tag, hydrationCallbacks, isStrictMode, concurrentUpdatesByDefaultOverride, identifierPrefix, onUncaughtError, onCaughtError, onRecoverableError, transitionCallbacks) { + var hydrate = false; + var initialChildren = null; + return createFiberRoot(containerInfo, tag, hydrate, initialChildren, hydrationCallbacks, isStrictMode, concurrentUpdatesByDefaultOverride, identifierPrefix, onUncaughtError, onCaughtError, onRecoverableError, transitionCallbacks, null); +} +function updateContainer(element, container, parentComponent, callback) { + var current = container.current; + var lane = requestUpdateLane(current); + updateContainerImpl(current, lane, element, container, parentComponent, callback); + return lane; +} +function updateContainerSync(element, container, parentComponent, callback) { + if (container.tag === LegacyRoot) { + flushPassiveEffects(); + } + + var current = container.current; + updateContainerImpl(current, SyncLane, element, container, parentComponent, callback); + return SyncLane; +} - if (fiber.tag === ClassComponent) { - var Component = fiber.type; +function updateContainerImpl(rootFiber, lane, element, container, parentComponent, callback) { + { + onScheduleRoot(container, element); + } - if (isContextProvider(Component)) { - return processChildContext(fiber, Component, parentContext); - } - } + { + markRenderScheduled(lane); + } - return parentContext; - } + var context = getContextForSubtree(parentComponent); - function createContainer( - containerInfo, - tag, - hydrationCallbacks, - isStrictMode, - concurrentUpdatesByDefaultOverride, - identifierPrefix, - onUncaughtError, - onCaughtError, - onRecoverableError, - transitionCallbacks - ) { - var hydrate = false; - var initialChildren = null; - return createFiberRoot( - containerInfo, - tag, - hydrate, - initialChildren, - hydrationCallbacks, - isStrictMode, - concurrentUpdatesByDefaultOverride, - identifierPrefix, - onUncaughtError, - onCaughtError, - onRecoverableError, - transitionCallbacks, - null - ); - } - function updateContainer(element, container, parentComponent, callback) { - var current = container.current; - var lane = requestUpdateLane(current); - updateContainerImpl( - current, - lane, - element, - container, - parentComponent, - callback - ); - return lane; - } - function updateContainerSync( - element, - container, - parentComponent, - callback - ) { - if (container.tag === LegacyRoot) { - flushPassiveEffects(); - } + if (container.context === null) { + container.context = context; + } else { + container.pendingContext = context; + } - var current = container.current; - updateContainerImpl( - current, - SyncLane, - element, - container, - parentComponent, - callback - ); - return SyncLane; - } + { + if (isRendering && current !== null && !didWarnAboutNestedUpdates) { + didWarnAboutNestedUpdates = true; - function updateContainerImpl( - rootFiber, - lane, - element, - container, - parentComponent, - callback - ) { - { - onScheduleRoot(container, element); - } + 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'); + } + } - { - markRenderScheduled(lane); - } + var update = createUpdate(lane); // Caution: React DevTools currently depends on this property + // being called "element". - var context = getContextForSubtree(parentComponent); + update.payload = { + element: element + }; + callback = callback === undefined ? null : callback; - if (container.context === null) { - container.context = context; - } else { - container.pendingContext = context; + if (callback !== null) { + { + if (typeof callback !== 'function') { + error('Expected the last optional `callback` argument to be a ' + 'function. Instead received: %s.', callback); } + } - { - 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" - ); - } - } + update.callback = callback; + } - var update = createUpdate(lane); // Caution: React DevTools currently depends on this property - // being called "element". + var root = enqueueUpdate(rootFiber, update, lane); - update.payload = { - element: element - }; - callback = callback === undefined ? null : callback; + if (root !== null) { + scheduleUpdateOnFiber(root, rootFiber, lane); + entangleTransitions(root, rootFiber, lane); + } +} +function getPublicRootInstance(container) { + var containerFiber = container.current; - if (callback !== null) { - { - if (typeof callback !== "function") { - error( - "Expected the last optional `callback` argument to be a " + - "function. Instead received: %s.", - callback - ); - } - } + if (!containerFiber.child) { + return null; + } - update.callback = callback; - } + switch (containerFiber.child.tag) { + case HostSingleton: + case HostComponent: + return getPublicInstance(containerFiber.child.stateNode); - var root = enqueueUpdate(rootFiber, update, lane); + default: + return containerFiber.child.stateNode; + } +} - if (root !== null) { - scheduleUpdateOnFiber(root, rootFiber, lane); - entangleTransitions(root, rootFiber, lane); - } - } - function getPublicRootInstance(container) { - var containerFiber = container.current; +var shouldErrorImpl = function (fiber) { + return null; +}; - if (!containerFiber.child) { - return null; - } +function shouldError(fiber) { + return shouldErrorImpl(fiber); +} - switch (containerFiber.child.tag) { - case HostSingleton: - case HostComponent: - return getPublicInstance(containerFiber.child.stateNode); +var shouldSuspendImpl = function (fiber) { + return false; +}; - default: - return containerFiber.child.stateNode; +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; + +{ + var copyWithDeleteImpl = function (obj, path, index) { + var key = path[index]; + var updated = isArray(obj) ? obj.slice() : assign({}, obj); + + if (index + 1 === path.length) { + if (isArray(updated)) { + updated.splice(key, 1); + } else { + delete updated[key]; } - } - - var shouldErrorImpl = function (fiber) { - return null; - }; - function shouldError(fiber) { - return shouldErrorImpl(fiber); - } + return updated; + } // $FlowFixMe[incompatible-use] number or string is fine here - var shouldSuspendImpl = function (fiber) { - return false; - }; - 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; + updated[key] = copyWithDeleteImpl(obj[key], path, index + 1); + return updated; + }; - { - var copyWithDeleteImpl = function (obj, path, index) { - var key = path[index]; - var updated = isArray(obj) ? obj.slice() : assign({}, obj); + var copyWithDelete = function (obj, path) { + return copyWithDeleteImpl(obj, path, 0); + }; - if (index + 1 === path.length) { - if (isArray(updated)) { - updated.splice(key, 1); - } else { - delete updated[key]; - } + var copyWithRenameImpl = function (obj, oldPath, newPath, index) { + var oldKey = oldPath[index]; + var updated = isArray(obj) ? obj.slice() : assign({}, obj); - return updated; - } // $FlowFixMe[incompatible-use] number or string is fine here + if (index + 1 === oldPath.length) { + var newKey = newPath[index]; // $FlowFixMe[incompatible-use] number or string is fine here - updated[key] = copyWithDeleteImpl(obj[key], path, index + 1); - return updated; - }; + updated[newKey] = updated[oldKey]; - var copyWithDelete = function (obj, path) { - return copyWithDeleteImpl(obj, path, 0); - }; + if (isArray(updated)) { + updated.splice(oldKey, 1); + } else { + delete updated[oldKey]; + } + } else { + // $FlowFixMe[incompatible-use] number or string is fine here + updated[oldKey] = copyWithRenameImpl( // $FlowFixMe[incompatible-use] number or string is fine here + obj[oldKey], oldPath, newPath, index + 1); + } - var copyWithRenameImpl = function (obj, oldPath, newPath, index) { - var oldKey = oldPath[index]; - var updated = isArray(obj) ? obj.slice() : assign({}, obj); + return updated; + }; - if (index + 1 === oldPath.length) { - var newKey = newPath[index]; // $FlowFixMe[incompatible-use] number or string is fine here + var copyWithRename = function (obj, oldPath, newPath) { + if (oldPath.length !== newPath.length) { + warn('copyWithRename() expects paths of the same length'); - updated[newKey] = updated[oldKey]; + 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'); - if (isArray(updated)) { - updated.splice(oldKey, 1); - } else { - delete updated[oldKey]; - } - } else { - // $FlowFixMe[incompatible-use] number or string is fine here - updated[oldKey] = copyWithRenameImpl( - // $FlowFixMe[incompatible-use] number or string is fine here - obj[oldKey], - oldPath, - newPath, - index + 1 - ); + return; } + } + } - return updated; - }; - - var copyWithRename = function (obj, oldPath, newPath) { - if (oldPath.length !== newPath.length) { - warn("copyWithRename() expects paths of the same length"); + return copyWithRenameImpl(obj, oldPath, newPath, 0); + }; - 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" - ); + var copyWithSetImpl = function (obj, path, index, value) { + if (index >= path.length) { + return value; + } - return; - } - } - } + var key = path[index]; + var updated = isArray(obj) ? obj.slice() : assign({}, obj); // $FlowFixMe[incompatible-use] number or string is fine here - return copyWithRenameImpl(obj, oldPath, newPath, 0); - }; + updated[key] = copyWithSetImpl(obj[key], path, index + 1, value); + return updated; + }; - var copyWithSetImpl = function (obj, path, index, value) { - if (index >= path.length) { - return value; - } + var copyWithSet = function (obj, path, value) { + return copyWithSetImpl(obj, path, 0, value); + }; - var key = path[index]; - var updated = isArray(obj) ? obj.slice() : assign({}, obj); // $FlowFixMe[incompatible-use] number or string is fine here + 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; - updated[key] = copyWithSetImpl(obj[key], path, index + 1, value); - return updated; - }; + while (currentHook !== null && id > 0) { + currentHook = currentHook.next; + id--; + } - var copyWithSet = function (obj, path, value) { - return copyWithSetImpl(obj, path, 0, value); - }; + return currentHook; + }; // Support DevTools editable values for useState and useReducer. - 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; - while (currentHook !== null && id > 0) { - currentHook = currentHook.next; - id--; - } + overrideHookState = function (fiber, id, path, value) { + var hook = findHook(fiber, id); - return currentHook; - }; // Support DevTools editable values for useState and useReducer. + 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. - overrideHookState = function (fiber, id, path, value) { - var hook = findHook(fiber, id); + fiber.memoizedProps = assign({}, fiber.memoizedProps); + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - 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. + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane); + } + } + }; - fiber.memoizedProps = assign({}, fiber.memoizedProps); - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + overrideHookStateDeletePath = function (fiber, id, path) { + var hook = findHook(fiber, id); - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane); - } - } - }; + 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. - overrideHookStateDeletePath = function (fiber, id, path) { - var hook = findHook(fiber, id); + fiber.memoizedProps = assign({}, fiber.memoizedProps); + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - 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 (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane); + } + } + }; - fiber.memoizedProps = assign({}, fiber.memoizedProps); - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + overrideHookStateRenamePath = function (fiber, id, oldPath, newPath) { + var hook = findHook(fiber, id); - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane); - } - } - }; + 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. - overrideHookStateRenamePath = function (fiber, id, oldPath, newPath) { - var hook = findHook(fiber, id); + fiber.memoizedProps = assign({}, fiber.memoizedProps); + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - 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 (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane); + } + } + }; // Support DevTools props for function components, forwardRef, memo, host components, etc. - fiber.memoizedProps = assign({}, fiber.memoizedProps); - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane); - } - } - }; // Support DevTools props for function components, forwardRef, memo, host components, etc. + overrideProps = function (fiber, path, value) { + fiber.pendingProps = copyWithSet(fiber.memoizedProps, path, value); - overrideProps = function (fiber, path, value) { - fiber.pendingProps = copyWithSet(fiber.memoizedProps, path, value); + if (fiber.alternate) { + fiber.alternate.pendingProps = fiber.pendingProps; + } - if (fiber.alternate) { - fiber.alternate.pendingProps = fiber.pendingProps; - } + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane); + } + }; - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane); - } - }; + overridePropsDeletePath = function (fiber, path) { + fiber.pendingProps = copyWithDelete(fiber.memoizedProps, path); - overridePropsDeletePath = function (fiber, path) { - fiber.pendingProps = copyWithDelete(fiber.memoizedProps, path); + if (fiber.alternate) { + fiber.alternate.pendingProps = fiber.pendingProps; + } - if (fiber.alternate) { - fiber.alternate.pendingProps = fiber.pendingProps; - } + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane); + } + }; - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane); - } - }; + overridePropsRenamePath = function (fiber, oldPath, newPath) { + fiber.pendingProps = copyWithRename(fiber.memoizedProps, oldPath, newPath); - overridePropsRenamePath = function (fiber, oldPath, newPath) { - fiber.pendingProps = copyWithRename( - fiber.memoizedProps, - oldPath, - newPath - ); + if (fiber.alternate) { + fiber.alternate.pendingProps = fiber.pendingProps; + } - if (fiber.alternate) { - fiber.alternate.pendingProps = fiber.pendingProps; - } + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane); + } + }; - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane); - } - }; + scheduleUpdate = function (fiber) { + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - scheduleUpdate = function (fiber) { - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane); + } + }; - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane); - } - }; + setErrorHandler = function (newShouldErrorImpl) { + shouldErrorImpl = newShouldErrorImpl; + }; - setErrorHandler = function (newShouldErrorImpl) { - shouldErrorImpl = newShouldErrorImpl; - }; + setSuspenseHandler = function (newShouldSuspendImpl) { + shouldSuspendImpl = newShouldSuspendImpl; + }; +} - setSuspenseHandler = function (newShouldSuspendImpl) { - shouldSuspendImpl = newShouldSuspendImpl; - }; - } +function findHostInstanceByFiber(fiber) { + var hostFiber = findCurrentHostFiber(fiber); - function findHostInstanceByFiber(fiber) { - var hostFiber = findCurrentHostFiber(fiber); + if (hostFiber === null) { + return null; + } - if (hostFiber === null) { - return null; - } + return hostFiber.stateNode; +} - return hostFiber.stateNode; - } +function emptyFindFiberByHostInstance(instance) { + return null; +} - function emptyFindFiberByHostInstance(instance) { - return null; - } +function getCurrentFiberForDevTools() { + return current; +} - function getCurrentFiberForDevTools() { - return current; - } - - function injectIntoDevTools(devToolsConfig) { - var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; - 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: ReactSharedInternals, - 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 injectIntoDevTools(devToolsConfig) { + var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; + 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: ReactSharedInternals, + 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 + }); +} - var act = React.act; // TODO: Remove from public bundle +var act = React.act; // TODO: Remove from public bundle - var defaultTestOptions = { - createNodeMock: function () { - return null; - } - }; +var defaultTestOptions = { + createNodeMock: function () { + return null; + } +}; - function toJSON(inst) { - if (inst.isHidden) { - // Omit timed out children from output entirely. This seems like the least - // surprising behavior. We could perhaps add a separate API that includes - // them, if it turns out people need it. - return null; - } +function toJSON(inst) { + if (inst.isHidden) { + // Omit timed out children from output entirely. This seems like the least + // surprising behavior. We could perhaps add a separate API that includes + // them, if it turns out people need it. + return null; + } - switch (inst.tag) { - case "TEXT": - return inst.text; + switch (inst.tag) { + case 'TEXT': + return inst.text; - case "INSTANCE": { - /* eslint-disable no-unused-vars */ - // We don't include the `children` prop in JSON. - // Instead, we will include the actual rendered children. - var _inst$props = inst.props, + case 'INSTANCE': + { + /* eslint-disable no-unused-vars */ + // We don't include the `children` prop in JSON. + // Instead, we will include the actual rendered children. + var _inst$props = inst.props, props = _objectWithoutPropertiesLoose(_inst$props, ["children"]); - /* eslint-enable */ + /* eslint-enable */ - var renderedChildren = null; - if (inst.children && inst.children.length) { - for (var i = 0; i < inst.children.length; i++) { - var renderedChild = toJSON(inst.children[i]); + var renderedChildren = null; - if (renderedChild !== null) { - if (renderedChildren === null) { - renderedChildren = [renderedChild]; - } else { - renderedChildren.push(renderedChild); - } + if (inst.children && inst.children.length) { + for (var i = 0; i < inst.children.length; i++) { + var renderedChild = toJSON(inst.children[i]); + + if (renderedChild !== null) { + if (renderedChildren === null) { + renderedChildren = [renderedChild]; + } else { + renderedChildren.push(renderedChild); } } } - - var json = { - type: inst.type, - props: props, - children: renderedChildren - }; - Object.defineProperty(json, "$$typeof", { - value: Symbol.for("react.test.json") - }); - return json; } - default: - throw new Error("Unexpected node type in toJSON: " + inst.tag); + var json = { + type: inst.type, + props: props, + children: renderedChildren + }; + Object.defineProperty(json, '$$typeof', { + value: Symbol.for('react.test.json') + }); + return json; } - } - function childrenToTree(node) { - if (!node) { - return null; - } + default: + throw new Error("Unexpected node type in toJSON: " + inst.tag); + } +} - var children = nodeAndSiblingsArray(node); +function childrenToTree(node) { + if (!node) { + return null; + } - if (children.length === 0) { - return null; - } else if (children.length === 1) { - return toTree(children[0]); - } + var children = nodeAndSiblingsArray(node); - return flatten(children.map(toTree)); - } // $FlowFixMe[missing-local-annot] + if (children.length === 0) { + return null; + } else if (children.length === 1) { + return toTree(children[0]); + } - function nodeAndSiblingsArray(nodeWithSibling) { - var array = []; - var node = nodeWithSibling; + return flatten(children.map(toTree)); +} // $FlowFixMe[missing-local-annot] - while (node != null) { - array.push(node); - node = node.sibling; - } - return array; - } // $FlowFixMe[missing-local-annot] +function nodeAndSiblingsArray(nodeWithSibling) { + var array = []; + var node = nodeWithSibling; - function flatten(arr) { - var result = []; - var stack = [ - { - i: 0, - array: arr - } - ]; + while (node != null) { + array.push(node); + node = node.sibling; + } - while (stack.length) { - var n = stack.pop(); + return array; +} // $FlowFixMe[missing-local-annot] - while (n.i < n.array.length) { - var el = n.array[n.i]; - n.i += 1; - if (isArray(el)) { - stack.push(n); - stack.push({ - i: 0, - array: el - }); - break; - } +function flatten(arr) { + var result = []; + var stack = [{ + i: 0, + array: arr + }]; - result.push(el); - } - } + while (stack.length) { + var n = stack.pop(); - return result; - } + while (n.i < n.array.length) { + var el = n.array[n.i]; + n.i += 1; - function toTree(node) { - if (node == null) { - return null; + if (isArray(el)) { + stack.push(n); + stack.push({ + i: 0, + array: el + }); + break; } - switch (node.tag) { - case HostRoot: - return childrenToTree(node.child); + result.push(el); + } + } - case HostPortal: - return childrenToTree(node.child); + return result; +} - case ClassComponent: - return { - nodeType: "component", - type: node.type, - props: assign({}, node.memoizedProps), - instance: node.stateNode, - rendered: childrenToTree(node.child) - }; +function toTree(node) { + if (node == null) { + return null; + } - case FunctionComponent: - case SimpleMemoComponent: - return { - nodeType: "component", - type: node.type, - props: assign({}, node.memoizedProps), - instance: null, - rendered: childrenToTree(node.child) - }; + switch (node.tag) { + case HostRoot: + return childrenToTree(node.child); - case HostHoistable: - case HostSingleton: - case HostComponent: { - return { - nodeType: "host", - type: node.type, - props: assign({}, node.memoizedProps), - instance: null, - // TODO: use createNodeMock here somehow? - rendered: flatten(nodeAndSiblingsArray(node.child).map(toTree)) - }; - } + case HostPortal: + return childrenToTree(node.child); - case HostText: - return node.stateNode.text; + case ClassComponent: + return { + nodeType: 'component', + type: node.type, + props: assign({}, node.memoizedProps), + instance: node.stateNode, + rendered: childrenToTree(node.child) + }; - case Fragment: - case ContextProvider: - case ContextConsumer: - case Mode: - case Profiler: - case ForwardRef: - case MemoComponent: - case IncompleteClassComponent: - case ScopeComponent: - return childrenToTree(node.child); + case FunctionComponent: + case SimpleMemoComponent: + return { + nodeType: 'component', + type: node.type, + props: assign({}, node.memoizedProps), + instance: null, + rendered: childrenToTree(node.child) + }; - default: - throw new Error( - "toTree() does not yet know how to handle nodes with tag=" + - node.tag - ); + case HostHoistable: + case HostSingleton: + case HostComponent: + { + return { + nodeType: 'host', + type: node.type, + props: assign({}, node.memoizedProps), + instance: null, + // TODO: use createNodeMock here somehow? + rendered: flatten(nodeAndSiblingsArray(node.child).map(toTree)) + }; } - } - var validWrapperTypes = new Set([ - FunctionComponent, - ClassComponent, - HostComponent, - ForwardRef, - MemoComponent, - SimpleMemoComponent, // Normally skipped, but used when there's more than one root child. - HostRoot - ]); + case HostText: + return node.stateNode.text; - function getChildren(parent) { - var children = []; - var startingNode = parent; - var node = startingNode; + case Fragment: + case ContextProvider: + case ContextConsumer: + case Mode: + case Profiler: + case ForwardRef: + case MemoComponent: + case IncompleteClassComponent: + case ScopeComponent: + return childrenToTree(node.child); - if (node.child === null) { - return children; - } + default: + throw new Error("toTree() does not yet know how to handle nodes with tag=" + node.tag); + } +} - node.child.return = node; - node = node.child; +var validWrapperTypes = new Set([FunctionComponent, ClassComponent, HostComponent, ForwardRef, MemoComponent, SimpleMemoComponent, // Normally skipped, but used when there's more than one root child. +HostRoot]); - outer: while (true) { - var descend = false; +function getChildren(parent) { + var children = []; + var startingNode = parent; + var node = startingNode; - if (validWrapperTypes.has(node.tag)) { - children.push(wrapFiber(node)); - } else if (node.tag === HostText) { - { - checkPropStringCoercion(node.memoizedProps, "memoizedProps"); - } + if (node.child === null) { + return children; + } - children.push("" + node.memoizedProps); - } else { - descend = true; - } + node.child.return = node; + node = node.child; - if (descend && node.child !== null) { - node.child.return = node; - node = node.child; - continue; - } + outer: while (true) { + var descend = false; - while (node.sibling === null) { - if (node.return === startingNode) { - break outer; - } + if (validWrapperTypes.has(node.tag)) { + children.push(wrapFiber(node)); + } else if (node.tag === HostText) { + { + checkPropStringCoercion(node.memoizedProps, 'memoizedProps'); + } - node = node.return; - } + children.push('' + node.memoizedProps); + } else { + descend = true; + } + + if (descend && node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } - node.sibling.return = node.return; - node = node.sibling; + while (node.sibling === null) { + if (node.return === startingNode) { + break outer; } - return children; + node = node.return; } - var ReactTestInstance = /*#__PURE__*/ (function () { - var _proto = ReactTestInstance.prototype; + node.sibling.return = node.return; + node = node.sibling; + } - _proto._currentFiber = function _currentFiber() { - // Throws if this component has been unmounted. - var fiber = findCurrentFiberUsingSlowPath(this._fiber); + return children; +} - if (fiber === null) { - throw new Error( - "Can't read from currently-mounting component. This error is likely " + - "caused by a bug in React. Please file an issue." - ); - } +var ReactTestInstance = /*#__PURE__*/function () { + var _proto = ReactTestInstance.prototype; - return fiber; - }; + _proto._currentFiber = function _currentFiber() { + // Throws if this component has been unmounted. + var fiber = findCurrentFiberUsingSlowPath(this._fiber); - function ReactTestInstance(fiber) { - this._fiber = void 0; + if (fiber === null) { + throw new Error("Can't read from currently-mounting component. This error is likely " + 'caused by a bug in React. Please file an issue.'); + } - if (!validWrapperTypes.has(fiber.tag)) { - throw new Error( - "Unexpected object passed to ReactTestInstance constructor (tag: " + - fiber.tag + - "). " + - "This is probably a bug in React." - ); - } + return fiber; + }; - this._fiber = fiber; - } + function ReactTestInstance(fiber) { + this._fiber = void 0; - // Custom search functions - _proto.find = function find(predicate) { - return expectOne( - this.findAll(predicate, { - deep: false - }), - "matching custom predicate: " + predicate.toString() - ); - }; + if (!validWrapperTypes.has(fiber.tag)) { + throw new Error("Unexpected object passed to ReactTestInstance constructor (tag: " + fiber.tag + "). " + 'This is probably a bug in React.'); + } - _proto.findByType = function findByType(type) { - return expectOne( - this.findAllByType(type, { - deep: false - }), - 'with node type: "' + - (getComponentNameFromType(type) || "Unknown") + - '"' - ); - }; + this._fiber = fiber; + } - _proto.findByProps = function findByProps(props) { - return expectOne( - this.findAllByProps(props, { - deep: false - }), - "with props: " + JSON.stringify(props) - ); - }; + // Custom search functions + _proto.find = function find(predicate) { + return expectOne(this.findAll(predicate, { + deep: false + }), "matching custom predicate: " + predicate.toString()); + }; - _proto.findAll = function findAll(predicate) { - var options = - arguments.length > 1 && arguments[1] !== undefined - ? arguments[1] - : null; - return _findAll(this, predicate, options); - }; + _proto.findByType = function findByType(type) { + return expectOne(this.findAllByType(type, { + deep: false + }), "with node type: \"" + (getComponentNameFromType(type) || 'Unknown') + "\""); + }; - _proto.findAllByType = function findAllByType(type) { - var options = - arguments.length > 1 && arguments[1] !== undefined - ? arguments[1] - : null; - return _findAll( - this, - function (node) { - return node.type === type; - }, - options - ); - }; + _proto.findByProps = function findByProps(props) { + return expectOne(this.findAllByProps(props, { + deep: false + }), "with props: " + JSON.stringify(props)); + }; - _proto.findAllByProps = function findAllByProps(props) { - var options = - arguments.length > 1 && arguments[1] !== undefined - ? arguments[1] - : null; - return _findAll( - this, - function (node) { - return node.props && propsMatch(node.props, props); - }, - options - ); - }; + _proto.findAll = function findAll(predicate) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + return _findAll(this, predicate, options); + }; - _createClass(ReactTestInstance, [ - { - key: "instance", - get: function () { - var tag = this._fiber.tag; - - if ( - tag === HostComponent || - tag === HostHoistable || - tag === HostSingleton - ) { - return getPublicInstance(this._fiber.stateNode); - } else { - return this._fiber.stateNode; - } - } - }, - { - key: "type", - get: function () { - return this._fiber.type; - } - }, - { - key: "props", - get: function () { - return this._currentFiber().memoizedProps; - } - }, - { - key: "parent", - get: function () { - var parent = this._fiber.return; - - while (parent !== null) { - if (validWrapperTypes.has(parent.tag)) { - if (parent.tag === HostRoot) { - // Special case: we only "materialize" instances for roots - // if they have more than a single child. So we'll check that now. - if (getChildren(parent).length < 2) { - return null; - } - } + _proto.findAllByType = function findAllByType(type) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + return _findAll(this, function (node) { + return node.type === type; + }, options); + }; - return wrapFiber(parent); - } + _proto.findAllByProps = function findAllByProps(props) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + return _findAll(this, function (node) { + return node.props && propsMatch(node.props, props); + }, options); + }; - parent = parent.return; - } + _createClass(ReactTestInstance, [{ + key: "instance", + get: function () { + var tag = this._fiber.tag; - return null; - } - }, - { - key: "children", - get: function () { - return getChildren(this._currentFiber()); + if (tag === HostComponent || tag === HostHoistable || tag === HostSingleton) { + return getPublicInstance(this._fiber.stateNode); + } else { + return this._fiber.stateNode; + } + } + }, { + key: "type", + get: function () { + return this._fiber.type; + } + }, { + key: "props", + get: function () { + return this._currentFiber().memoizedProps; + } + }, { + key: "parent", + get: function () { + var parent = this._fiber.return; + + while (parent !== null) { + if (validWrapperTypes.has(parent.tag)) { + if (parent.tag === HostRoot) { + // Special case: we only "materialize" instances for roots + // if they have more than a single child. So we'll check that now. + if (getChildren(parent).length < 2) { + return null; + } } + + return wrapFiber(parent); } - ]); - return ReactTestInstance; - })(); + parent = parent.return; + } - function _findAll(root, predicate, options) { - var deep = options ? options.deep : true; - var results = []; + return null; + } + }, { + key: "children", + get: function () { + return getChildren(this._currentFiber()); + } + }]); - if (predicate(root)) { - results.push(root); + return ReactTestInstance; +}(); - if (!deep) { - return results; - } - } +function _findAll(root, predicate, options) { + var deep = options ? options.deep : true; + var results = []; - root.children.forEach(function (child) { - if (typeof child === "string") { - return; - } + if (predicate(root)) { + results.push(root); - results.push.apply(results, _findAll(child, predicate, options)); - }); + if (!deep) { return results; } + } - function expectOne(all, message) { - if (all.length === 1) { - return all[0]; - } - - var prefix = - all.length === 0 - ? "No instances found " - : "Expected 1 but found " + all.length + " instances "; - throw new Error(prefix + message); + root.children.forEach(function (child) { + if (typeof child === 'string') { + return; } - function propsMatch(props, filter) { - for (var key in filter) { - if (props[key] !== filter[key]) { - return false; - } - } + results.push.apply(results, _findAll(child, predicate, options)); + }); + return results; +} - return true; +function expectOne(all, message) { + if (all.length === 1) { + return all[0]; + } + + var prefix = all.length === 0 ? 'No instances found ' : "Expected 1 but found " + all.length + " instances "; + throw new Error(prefix + message); +} + +function propsMatch(props, filter) { + for (var key in filter) { + if (props[key] !== filter[key]) { + return false; } + } - function create(element, options) { - var createNodeMock = defaultTestOptions.createNodeMock; - var isConcurrentOnly = disableLegacyMode === true; - var isConcurrent = isConcurrentOnly; - var isStrictMode = false; - var concurrentUpdatesByDefault = null; + return true; +} - if (typeof options === "object" && options !== null) { - if (typeof options.createNodeMock === "function") { - // $FlowFixMe[incompatible-type] found when upgrading Flow - createNodeMock = options.createNodeMock; - } +function create(element, options) { - { - isConcurrent = options.unstable_isConcurrent; - } + var createNodeMock = defaultTestOptions.createNodeMock; + var isConcurrentOnly = disableLegacyMode === true ; + var isConcurrent = isConcurrentOnly; + var isStrictMode = false; + var concurrentUpdatesByDefault = null; - if (options.unstable_strictMode === true) { - isStrictMode = true; - } + if (typeof options === 'object' && options !== null) { + if (typeof options.createNodeMock === 'function') { + // $FlowFixMe[incompatible-type] found when upgrading Flow + createNodeMock = options.createNodeMock; + } - { - if (options.unstable_concurrentUpdatesByDefault !== undefined) { - concurrentUpdatesByDefault = - options.unstable_concurrentUpdatesByDefault; - } - } - } + { + isConcurrent = options.unstable_isConcurrent; + } - var container = { - children: [], - createNodeMock: createNodeMock, - tag: "CONTAINER" - }; - var root = createContainer( - container, - isConcurrent ? ConcurrentRoot : LegacyRoot, - null, - isStrictMode, - concurrentUpdatesByDefault, - "", - defaultOnUncaughtError, - defaultOnCaughtError, - defaultOnRecoverableError, - null - ); - - if (root == null) { - throw new Error("something went wrong"); - } - - updateContainer(element, root, null, null); - var entry = { - _Scheduler: Scheduler, - root: undefined, - // makes flow happy - // we define a 'getter' for 'root' below using 'Object.defineProperty' - toJSON: function () { - if (root == null || root.current == null || container == null) { - return null; - } + if (options.unstable_strictMode === true) { + isStrictMode = true; + } - if (container.children.length === 0) { - return null; - } + { + if (options.unstable_concurrentUpdatesByDefault !== undefined) { + concurrentUpdatesByDefault = options.unstable_concurrentUpdatesByDefault; + } + } + } + + var container = { + children: [], + createNodeMock: createNodeMock, + tag: 'CONTAINER' + }; + var root = createContainer(container, isConcurrent ? ConcurrentRoot : LegacyRoot, null, isStrictMode, concurrentUpdatesByDefault, '', defaultOnUncaughtError, defaultOnCaughtError, defaultOnRecoverableError, null); + + if (root == null) { + throw new Error('something went wrong'); + } + + updateContainer(element, root, null, null); + var entry = { + _Scheduler: Scheduler, + root: undefined, + // makes flow happy + // we define a 'getter' for 'root' below using 'Object.defineProperty' + toJSON: function () { + if (root == null || root.current == null || container == null) { + return null; + } - if (container.children.length === 1) { - return toJSON(container.children[0]); - } + if (container.children.length === 0) { + return null; + } - if ( - container.children.length === 2 && - container.children[0].isHidden === true && - container.children[1].isHidden === false - ) { - // Omit timed out children from output entirely, including the fact that we - // temporarily wrap fallback and timed out children in an array. - return toJSON(container.children[1]); - } + if (container.children.length === 1) { + return toJSON(container.children[0]); + } - var renderedChildren = null; + if (container.children.length === 2 && container.children[0].isHidden === true && container.children[1].isHidden === false) { + // Omit timed out children from output entirely, including the fact that we + // temporarily wrap fallback and timed out children in an array. + return toJSON(container.children[1]); + } - if (container.children && container.children.length) { - for (var i = 0; i < container.children.length; i++) { - var renderedChild = toJSON(container.children[i]); + var renderedChildren = null; - if (renderedChild !== null) { - if (renderedChildren === null) { - renderedChildren = [renderedChild]; - } else { - renderedChildren.push(renderedChild); - } - } + if (container.children && container.children.length) { + for (var i = 0; i < container.children.length; i++) { + var renderedChild = toJSON(container.children[i]); + + if (renderedChild !== null) { + if (renderedChildren === null) { + renderedChildren = [renderedChild]; + } else { + renderedChildren.push(renderedChild); } } + } + } - return renderedChildren; - }, - toTree: function () { - if (root == null || root.current == null) { - return null; - } + return renderedChildren; + }, + toTree: function () { + if (root == null || root.current == null) { + return null; + } - return toTree(root.current); - }, - update: function (newElement) { - if (root == null || root.current == null) { - return; - } + return toTree(root.current); + }, + update: function (newElement) { + if (root == null || root.current == null) { + return; + } - updateContainer(newElement, root, null, null); - }, - unmount: function () { - if (root == null || root.current == null) { - return; - } + updateContainer(newElement, root, null, null); + }, + unmount: function () { + if (root == null || root.current == null) { + return; + } - updateContainer(null, root, null, null); // $FlowFixMe[incompatible-type] found when upgrading Flow + updateContainer(null, root, null, null); // $FlowFixMe[incompatible-type] found when upgrading Flow - container = null; - root = null; - }, - getInstance: function () { - if (root == null || root.current == null) { - return null; - } + container = null; + root = null; + }, + getInstance: function () { + if (root == null || root.current == null) { + return null; + } - return getPublicRootInstance(root); - }, - unstable_flushSync: flushSyncFromReconciler - }; - Object.defineProperty(entry, "root", { - configurable: true, - enumerable: true, - get: function () { - if (root === null) { - throw new Error("Can't access .root on unmounted test renderer"); - } + return getPublicRootInstance(root); + }, + unstable_flushSync: flushSyncFromReconciler + }; + Object.defineProperty(entry, 'root', { + configurable: true, + enumerable: true, + get: function () { + if (root === null) { + throw new Error("Can't access .root on unmounted test renderer"); + } - var children = getChildren(root.current); + var children = getChildren(root.current); - if (children.length === 0) { - throw new Error("Can't access .root on unmounted test renderer"); - } else if (children.length === 1) { - // Normally, we skip the root and just give you the child. - return children[0]; - } else { - // However, we give you the root if there's more than one root child. - // We could make this the behavior for all cases but it would be a breaking change. - // $FlowFixMe[incompatible-use] found when upgrading Flow - return wrapFiber(root.current); - } - } - }); - return entry; + if (children.length === 0) { + throw new Error("Can't access .root on unmounted test renderer"); + } else if (children.length === 1) { + // Normally, we skip the root and just give you the child. + return children[0]; + } else { + // However, we give you the root if there's more than one root child. + // We could make this the behavior for all cases but it would be a breaking change. + // $FlowFixMe[incompatible-use] found when upgrading Flow + return wrapFiber(root.current); + } } + }); + return entry; +} - var fiberToWrapper = new WeakMap(); +var fiberToWrapper = new WeakMap(); - function wrapFiber(fiber) { - var wrapper = fiberToWrapper.get(fiber); +function wrapFiber(fiber) { + var wrapper = fiberToWrapper.get(fiber); - if (wrapper === undefined && fiber.alternate !== null) { - wrapper = fiberToWrapper.get(fiber.alternate); - } + if (wrapper === undefined && fiber.alternate !== null) { + wrapper = fiberToWrapper.get(fiber.alternate); + } - if (wrapper === undefined) { - wrapper = new ReactTestInstance(fiber); - fiberToWrapper.set(fiber, wrapper); - } + if (wrapper === undefined) { + wrapper = new ReactTestInstance(fiber); + fiberToWrapper.set(fiber, wrapper); + } - return wrapper; - } // Enable ReactTestRenderer to be used to test DevTools integration. + return wrapper; +} // Enable ReactTestRenderer to be used to test DevTools integration. - injectIntoDevTools({ - findFiberByHostInstance: function () { - throw new Error( - "TestRenderer does not support findFiberByHostInstance()" - ); - }, - bundleType: 1, - version: ReactVersion, - rendererPackageName: "react-test-renderer" - }); - exports._Scheduler = Scheduler; - exports.act = act; - exports.create = create; - exports.unstable_batchedUpdates = batchedUpdates; +injectIntoDevTools({ + findFiberByHostInstance: function () { + throw new Error('TestRenderer does not support findFiberByHostInstance()'); + }, + bundleType: 1 , + version: ReactVersion, + rendererPackageName: 'react-test-renderer' +}); + +exports._Scheduler = Scheduler; +exports.act = act; +exports.create = create; +exports.unstable_batchedUpdates = batchedUpdates; })(); } diff --git a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/JSXDEVRuntime-dev.js b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/JSXDEVRuntime-dev.js index ee31c6647610e..c6f601d067d08 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/JSXDEVRuntime-dev.js +++ b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/JSXDEVRuntime-dev.js @@ -7,1685 +7,1514 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<<7bcb460fce55ee6870184e537edd4d8f>> + * @generated SignedSource<<8f878889d9995d2ae240b302c52058bd>> */ -"use strict"; +'use strict'; if (__DEV__) { - (function () { - "use strict"; - - var React = require("react"); - var dynamicFlagsUntyped = require("ReactNativeInternalFeatureFlags"); - - // 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"); // TODO: Delete with enableRenderableContext - - var REACT_CONSUMER_TYPE = Symbol.for("react.consumer"); - var REACT_CONTEXT_TYPE = Symbol.for("react.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_OFFSCREEN_TYPE = Symbol.for("react.offscreen"); - var MAYBE_ITERATOR_SYMBOL = Symbol.iterator; - var FAUX_ITERATOR_SYMBOL = "@@iterator"; - function getIteratorFn(maybeIterable) { - if (maybeIterable === null || typeof maybeIterable !== "object") { - return null; - } + (function() { +'use strict'; + +var React = require('react'); +var dynamicFlagsUntyped = require('ReactNativeInternalFeatureFlags'); + +// 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'); // TODO: Delete with enableRenderableContext + +var REACT_CONSUMER_TYPE = Symbol.for('react.consumer'); +var REACT_CONTEXT_TYPE = Symbol.for('react.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_OFFSCREEN_TYPE = Symbol.for('react.offscreen'); +var MAYBE_ITERATOR_SYMBOL = Symbol.iterator; +var FAUX_ITERATOR_SYMBOL = '@@iterator'; +function getIteratorFn(maybeIterable) { + if (maybeIterable === null || typeof maybeIterable !== 'object') { + return null; + } + + var maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]; + + if (typeof maybeIterator === 'function') { + return maybeIterator; + } + + return null; +} - var maybeIterator = - (MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL]) || - maybeIterable[FAUX_ITERATOR_SYMBOL]; +var ReactSharedInternals = React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE; - if (typeof maybeIterator === "function") { - return maybeIterator; +function error(format) { + { + { + for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { + args[_key2 - 1] = arguments[_key2]; } - return null; + printWarning('error', format, args); } + } +} - var ReactSharedInternals = - React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE; +function printWarning(level, format, args) { + // When changing this logic, you might want to also + // update consoleWithStackDev.www.js as well. + { + var stack = ReactSharedInternals.getStackAddendum(); - function error(format) { - { - { - for ( - var _len2 = arguments.length, - args = new Array(_len2 > 1 ? _len2 - 1 : 0), - _key2 = 1; - _key2 < _len2; - _key2++ - ) { - args[_key2 - 1] = arguments[_key2]; - } + if (stack !== '') { + format += '%s'; + args = args.concat([stack]); + } // eslint-disable-next-line react-internal/safe-string-coercion - printWarning("error", format, args); - } - } - } - function printWarning(level, format, args) { - // When changing this logic, you might want to also - // update consoleWithStackDev.www.js as well. - { - var stack = ReactSharedInternals.getStackAddendum(); + var argsWithFormat = args.map(function (item) { + return String(item); + }); // Careful: RN currently depends on this prefix - if (stack !== "") { - format += "%s"; - args = args.concat([stack]); - } // eslint-disable-next-line react-internal/safe-string-coercion + argsWithFormat.unshift('Warning: ' + format); // We intentionally don't use spread (or .apply) directly because it + // breaks IE9: https://github.com/facebook/react/issues/13610 + // eslint-disable-next-line react-internal/no-production-logging - var argsWithFormat = args.map(function (item) { - return String(item); - }); // Careful: RN currently depends on this prefix + Function.prototype.apply.call(console[level], console, argsWithFormat); + } +} - argsWithFormat.unshift("Warning: " + format); // We intentionally don't use spread (or .apply) directly because it - // breaks IE9: https://github.com/facebook/react/issues/13610 - // eslint-disable-next-line react-internal/no-production-logging +// Re-export dynamic flags from the internal module. +var dynamicFlags = dynamicFlagsUntyped; // We destructure each value before re-exporting to avoid a dynamic look-up on +// the exports object every time a flag is read. - Function.prototype.apply.call(console[level], console, argsWithFormat); - } - } +var enableComponentStackLocations = dynamicFlags.enableComponentStackLocations, + enableRenderableContext = dynamicFlags.enableRenderableContext, + disableDefaultPropsExceptForClasses = dynamicFlags.disableDefaultPropsExceptForClasses; // The rest of the flags are static for better dead code elimination. +var enableDebugTracing = false; +var enableScopeAPI = false; +var enableLegacyHidden = false; +var enableTransitionTracing = false; - // Re-export dynamic flags from the internal module. - var dynamicFlags = dynamicFlagsUntyped; // We destructure each value before re-exporting to avoid a dynamic look-up on - // the exports object every time a flag is read. - - var enableComponentStackLocations = - dynamicFlags.enableComponentStackLocations, - enableRenderableContext = dynamicFlags.enableRenderableContext, - disableDefaultPropsExceptForClasses = - dynamicFlags.disableDefaultPropsExceptForClasses; // The rest of the flags are static for better dead code elimination. - var enableDebugTracing = false; - var enableScopeAPI = false; - var enableLegacyHidden = false; - var enableTransitionTracing = false; - - function getWrappedName$1(outerType, innerType, wrapperName) { - var displayName = outerType.displayName; - - if (displayName) { - return displayName; - } +function getWrappedName$1(outerType, innerType, wrapperName) { + var displayName = outerType.displayName; - var functionName = innerType.displayName || innerType.name || ""; - return functionName !== "" - ? wrapperName + "(" + functionName + ")" - : wrapperName; - } // Keep in sync with react-reconciler/getComponentNameFromFiber + if (displayName) { + return displayName; + } - function getContextName$1(type) { - return type.displayName || "Context"; - } + var functionName = innerType.displayName || innerType.name || ''; + return functionName !== '' ? wrapperName + "(" + functionName + ")" : wrapperName; +} // Keep in sync with react-reconciler/getComponentNameFromFiber - var REACT_CLIENT_REFERENCE$2 = Symbol.for("react.client.reference"); // 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; - } +function getContextName$1(type) { + return type.displayName || 'Context'; +} - if (typeof type === "function") { - if (type.$$typeof === REACT_CLIENT_REFERENCE$2) { - // TODO: Create a convention for naming client references with debug info. - return null; - } +var REACT_CLIENT_REFERENCE$2 = Symbol.for('react.client.reference'); // Note that the reconciler package should generally prefer to use getComponentNameFromFiber() instead. - return type.displayName || type.name || null; - } +function getComponentNameFromType(type) { + if (type == null) { + // Host root, text node or just invalid type. + return null; + } - if (typeof type === "string") { - return type; - } + if (typeof type === 'function') { + if (type.$$typeof === REACT_CLIENT_REFERENCE$2) { + // TODO: Create a convention for naming client references with debug info. + return null; + } - switch (type) { - case REACT_FRAGMENT_TYPE: - return "Fragment"; + return type.displayName || type.name || null; + } - case REACT_PORTAL_TYPE: - return "Portal"; + if (typeof type === 'string') { + return type; + } - case REACT_PROFILER_TYPE: - return "Profiler"; + switch (type) { + case REACT_FRAGMENT_TYPE: + return 'Fragment'; - case REACT_STRICT_MODE_TYPE: - return "StrictMode"; + case REACT_PORTAL_TYPE: + return 'Portal'; - case REACT_SUSPENSE_TYPE: - return "Suspense"; + case REACT_PROFILER_TYPE: + return 'Profiler'; - case REACT_SUSPENSE_LIST_TYPE: - return "SuspenseList"; + case REACT_STRICT_MODE_TYPE: + return 'StrictMode'; + + case REACT_SUSPENSE_TYPE: + return 'Suspense'; + + case REACT_SUSPENSE_LIST_TYPE: + return 'SuspenseList'; + + } + + if (typeof type === 'object') { + { + if (typeof type.tag === 'number') { + error('Received an unexpected object in getComponentNameFromType(). ' + 'This is likely a bug in React. Please file an issue.'); } + } - if (typeof type === "object") { - { - if (typeof type.tag === "number") { - error( - "Received an unexpected object in getComponentNameFromType(). " + - "This is likely a bug in React. Please file an issue." - ); - } + switch (type.$$typeof) { + case REACT_PROVIDER_TYPE: + if (enableRenderableContext) { + return null; + } else { + var provider = type; + return getContextName$1(provider._context) + '.Provider'; } - switch (type.$$typeof) { - case REACT_PROVIDER_TYPE: - if (enableRenderableContext) { - return null; - } else { - var provider = type; - return getContextName$1(provider._context) + ".Provider"; - } - - case REACT_CONTEXT_TYPE: - var context = type; + case REACT_CONTEXT_TYPE: + var context = type; - if (enableRenderableContext) { - return getContextName$1(context) + ".Provider"; - } else { - return getContextName$1(context) + ".Consumer"; - } + if (enableRenderableContext) { + return getContextName$1(context) + '.Provider'; + } else { + return getContextName$1(context) + '.Consumer'; + } - case REACT_CONSUMER_TYPE: - if (enableRenderableContext) { - var consumer = type; - return getContextName$1(consumer._context) + ".Consumer"; - } else { - return null; - } + case REACT_CONSUMER_TYPE: + if (enableRenderableContext) { + var consumer = type; + return getContextName$1(consumer._context) + '.Consumer'; + } else { + return null; + } - case REACT_FORWARD_REF_TYPE: - return getWrappedName$1(type, type.render, "ForwardRef"); + case REACT_FORWARD_REF_TYPE: + return getWrappedName$1(type, type.render, 'ForwardRef'); - case REACT_MEMO_TYPE: - var outerName = type.displayName || null; + case REACT_MEMO_TYPE: + var outerName = type.displayName || null; - if (outerName !== null) { - return outerName; - } + if (outerName !== null) { + return outerName; + } - return getComponentNameFromType(type.type) || "Memo"; + return getComponentNameFromType(type.type) || 'Memo'; - case REACT_LAZY_TYPE: { - var lazyComponent = type; - var payload = lazyComponent._payload; - var init = lazyComponent._init; + case REACT_LAZY_TYPE: + { + var lazyComponent = type; + var payload = lazyComponent._payload; + var init = lazyComponent._init; - try { - return getComponentNameFromType(init(payload)); - } catch (x) { - return null; - } + try { + return getComponentNameFromType(init(payload)); + } catch (x) { + return null; } } - } - - return null; } + } - // $FlowFixMe[method-unbinding] - var hasOwnProperty = Object.prototype.hasOwnProperty; - - var assign = Object.assign; - - /* - * 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[incompatible-return] 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[incompatible-return] + return null; +} - return type; - } - } // $FlowFixMe[incompatible-return] only called in DEV, so void return is not possible. +// $FlowFixMe[method-unbinding] +var hasOwnProperty = Object.prototype.hasOwnProperty; - function willCoercionThrow(value) { - { - try { - testStringCoercion(value); - return false; - } catch (e) { - return true; - } - } - } +var assign = Object.assign; - 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; +/* + * 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[incompatible-return] 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[incompatible-return] + + return type; + } +} // $FlowFixMe[incompatible-return] only called in DEV, so void return is not possible. + + +function willCoercionThrow(value) { + { + try { + testStringCoercion(value); + return false; + } catch (e) { + return true; } - function checkKeyStringCoercion(value) { - { - if (willCoercionThrow(value)) { - error( - "The provided key is an unsupported type %s." + - " This value must be coerced to a string before using it here.", - typeName(value) - ); - - return testStringCoercion(value); // throw (to help callers find troubleshooting comments) - } - } + } +} + +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 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 using it here.", - propName, - 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 using it here.', propName, typeName(value)); + + return testStringCoercion(value); // throw (to help callers find troubleshooting comments) } + } +} - var REACT_CLIENT_REFERENCE$1 = Symbol.for("react.client.reference"); - function isValidElementType(type) { - if (typeof type === "string" || typeof type === "function") { - return true; - } // Note: typeof might be other than 'symbol' or 'number' (e.g. if it's a polyfill). - - if ( - type === REACT_FRAGMENT_TYPE || - type === REACT_PROFILER_TYPE || - enableDebugTracing || - type === REACT_STRICT_MODE_TYPE || - type === REACT_SUSPENSE_TYPE || - type === REACT_SUSPENSE_LIST_TYPE || - enableLegacyHidden || - type === REACT_OFFSCREEN_TYPE || - enableScopeAPI || - enableTransitionTracing - ) { - return true; - } +var REACT_CLIENT_REFERENCE$1 = Symbol.for('react.client.reference'); +function isValidElementType(type) { + if (typeof type === 'string' || typeof type === 'function') { + return true; + } // Note: typeof might be other than 'symbol' or 'number' (e.g. if it's a polyfill). - if (typeof type === "object" && type !== null) { - if ( - type.$$typeof === REACT_LAZY_TYPE || - type.$$typeof === REACT_MEMO_TYPE || - type.$$typeof === REACT_CONTEXT_TYPE || - (!enableRenderableContext && type.$$typeof === REACT_PROVIDER_TYPE) || - (enableRenderableContext && type.$$typeof === REACT_CONSUMER_TYPE) || - type.$$typeof === REACT_FORWARD_REF_TYPE || // This needs to include all possible module reference object - // types supported by any Flight configuration anywhere since - // we don't know which Flight build this will end up being used - // with. - type.$$typeof === REACT_CLIENT_REFERENCE$1 || - type.getModuleId !== undefined - ) { - return true; - } - } - return false; + if (type === REACT_FRAGMENT_TYPE || type === REACT_PROFILER_TYPE || enableDebugTracing || type === REACT_STRICT_MODE_TYPE || type === REACT_SUSPENSE_TYPE || type === REACT_SUSPENSE_LIST_TYPE || enableLegacyHidden || type === REACT_OFFSCREEN_TYPE || enableScopeAPI || enableTransitionTracing ) { + return true; + } + + if (typeof type === 'object' && type !== null) { + if (type.$$typeof === REACT_LAZY_TYPE || type.$$typeof === REACT_MEMO_TYPE || type.$$typeof === REACT_CONTEXT_TYPE || !enableRenderableContext && type.$$typeof === REACT_PROVIDER_TYPE || enableRenderableContext && type.$$typeof === REACT_CONSUMER_TYPE || type.$$typeof === REACT_FORWARD_REF_TYPE || // This needs to include all possible module reference object + // types supported by any Flight configuration anywhere since + // we don't know which Flight build this will end up being used + // with. + type.$$typeof === REACT_CLIENT_REFERENCE$1 || type.getModuleId !== undefined) { + return true; } + } - var isArrayImpl = Array.isArray; // eslint-disable-next-line no-redeclare + return false; +} - function isArray(a) { - return isArrayImpl(a); - } +var isArrayImpl = Array.isArray; // eslint-disable-next-line no-redeclare - // 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[cannot-write] 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 */ - } +function isArray(a) { + return isArrayImpl(a); +} - disabledDepth++; - } +// 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[cannot-write] 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 */ } - function reenableLogs() { - { - disabledDepth--; - - if (disabledDepth === 0) { - /* eslint-disable react-internal/no-production-logging */ - var props = { - configurable: true, - enumerable: true, - writable: true - }; // $FlowFixMe[cannot-write] 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." - ); - } - } + disabledDepth++; + } +} +function reenableLogs() { + { + disabledDepth--; + + if (disabledDepth === 0) { + /* eslint-disable react-internal/no-production-logging */ + var props = { + configurable: true, + enumerable: true, + writable: true + }; // $FlowFixMe[cannot-write] 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 */ } - var prefix; - function describeBuiltInComponentFrame(name) { - if (enableComponentStackLocations) { - if (prefix === undefined) { - // Extract the VM specific prefix used by each line. - try { - throw Error(); - } catch (x) { - var match = x.stack.trim().match(/\n( *(at )?)/); - prefix = (match && match[1]) || ""; - } - } // We use the prefix to ensure our stacks line up with native stack frames. - - return "\n" + prefix + name; - } else { - return describeComponentFrame(name); - } + if (disabledDepth < 0) { + error('disabledDepth fell below zero. ' + 'This is a bug in React. Please file an issue.'); } - var reentry = false; - var componentFrameCache; + } +} - { - var PossiblyWeakMap = typeof WeakMap === "function" ? WeakMap : Map; - componentFrameCache = new PossiblyWeakMap(); - } - /** - * Leverages native browser/VM stack frames to get proper details (e.g. - * filename, line + col number) for a single component in a component stack. We - * do this by: - * (1) throwing and catching an error in the function - this will be our - * control error. - * (2) calling the component which will eventually throw an error that we'll - * catch - this will be our sample error. - * (3) diffing the control and sample error stacks to find the stack frame - * which represents our component. - */ - - function describeNativeComponentFrame(fn, construct) { - // If something asked for a stack inside a fake render, it should get ignored. - if (!fn || reentry) { - return ""; +var prefix; +function describeBuiltInComponentFrame(name) { + if (enableComponentStackLocations) { + if (prefix === undefined) { + // Extract the VM specific prefix used by each line. + try { + throw Error(); + } catch (x) { + var match = x.stack.trim().match(/\n( *(at )?)/); + prefix = match && match[1] || ''; } + } // We use the prefix to ensure our stacks line up with native stack frames. - { - var frame = componentFrameCache.get(fn); - if (frame !== undefined) { - return frame; - } - } + return '\n' + prefix + name; + } else { + return describeComponentFrame(name); + } +} +var reentry = false; +var componentFrameCache; - reentry = true; - var previousPrepareStackTrace = Error.prepareStackTrace; // $FlowFixMe[incompatible-type] It does accept undefined. +{ + var PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map; + componentFrameCache = new PossiblyWeakMap(); +} +/** + * Leverages native browser/VM stack frames to get proper details (e.g. + * filename, line + col number) for a single component in a component stack. We + * do this by: + * (1) throwing and catching an error in the function - this will be our + * control error. + * (2) calling the component which will eventually throw an error that we'll + * catch - this will be our sample error. + * (3) diffing the control and sample error stacks to find the stack frame + * which represents our component. + */ - Error.prepareStackTrace = undefined; - var previousDispatcher = null; - { - previousDispatcher = ReactSharedInternals.H; // Set the dispatcher in DEV because this might be call in the render function - // for warnings. +function describeNativeComponentFrame(fn, construct) { + // If something asked for a stack inside a fake render, it should get ignored. + if (!fn || reentry) { + return ''; + } - ReactSharedInternals.H = null; - disableLogs(); - } - /** - * Finding a common stack frame between sample and control errors can be - * tricky given the different types and levels of stack trace truncation from - * different JS VMs. So instead we'll attempt to control what that common - * frame should be through this object method: - * Having both the sample and control errors be in the function under the - * `DescribeNativeComponentFrameRoot` property, + setting the `name` and - * `displayName` properties of the function ensures that a stack - * frame exists that has the method name `DescribeNativeComponentFrameRoot` in - * it for both control and sample stacks. - */ - - var RunInRootFrame = { - DetermineComponentFrameRoot: function () { - var control; + { + var frame = componentFrameCache.get(fn); - try { - // This should throw. - if (construct) { - // Something should be setting the props in the constructor. - var Fake = function () { - throw Error(); - }; // $FlowFixMe[prop-missing] - - Object.defineProperty(Fake.prototype, "props", { - set: function () { - // We use a throwing setter instead of frozen or non-writable props - // because that won't throw in a non-strict mode function. - throw Error(); - } - }); - - if (typeof Reflect === "object" && Reflect.construct) { - // We construct a different control for this case to include any extra - // frames added by the construct call. - try { - Reflect.construct(Fake, []); - } catch (x) { - control = x; - } + if (frame !== undefined) { + return frame; + } + } + + reentry = true; + var previousPrepareStackTrace = Error.prepareStackTrace; // $FlowFixMe[incompatible-type] It does accept undefined. + + Error.prepareStackTrace = undefined; + var previousDispatcher = null; + + { + previousDispatcher = ReactSharedInternals.H; // Set the dispatcher in DEV because this might be call in the render function + // for warnings. + + ReactSharedInternals.H = null; + disableLogs(); + } + /** + * Finding a common stack frame between sample and control errors can be + * tricky given the different types and levels of stack trace truncation from + * different JS VMs. So instead we'll attempt to control what that common + * frame should be through this object method: + * Having both the sample and control errors be in the function under the + * `DescribeNativeComponentFrameRoot` property, + setting the `name` and + * `displayName` properties of the function ensures that a stack + * frame exists that has the method name `DescribeNativeComponentFrameRoot` in + * it for both control and sample stacks. + */ + + + var RunInRootFrame = { + DetermineComponentFrameRoot: function () { + var control; - Reflect.construct(fn, [], Fake); - } else { - try { - Fake.call(); - } catch (x) { - control = x; - } // $FlowFixMe[prop-missing] found when upgrading Flow + try { + // This should throw. + if (construct) { + // Something should be setting the props in the constructor. + var Fake = function () { + throw Error(); + }; // $FlowFixMe[prop-missing] - fn.call(Fake.prototype); - } - } else { - try { - throw Error(); - } catch (x) { - control = x; - } // TODO(luna): This will currently only throw if the function component - // tries to access React/ReactDOM/props. We should probably make this throw - // in simple components too - - var maybePromise = fn(); // If the function component returns a promise, it's likely an async - // component, which we don't yet support. Attach a noop catch handler to - // silence the error. - // TODO: Implement component stacks for async client components? - - if (maybePromise && typeof maybePromise.catch === "function") { - maybePromise.catch(function () {}); - } + + Object.defineProperty(Fake.prototype, 'props', { + set: function () { + // We use a throwing setter instead of frozen or non-writable props + // because that won't throw in a non-strict mode function. + throw Error(); } - } catch (sample) { - // This is inlined manually because closure doesn't do it for us. - if (sample && control && typeof sample.stack === "string") { - return [sample.stack, control.stack]; + }); + + if (typeof Reflect === 'object' && Reflect.construct) { + // We construct a different control for this case to include any extra + // frames added by the construct call. + try { + Reflect.construct(Fake, []); + } catch (x) { + control = x; } - } - return [null, null]; - } - }; // $FlowFixMe[prop-missing] - - RunInRootFrame.DetermineComponentFrameRoot.displayName = - "DetermineComponentFrameRoot"; - var namePropDescriptor = Object.getOwnPropertyDescriptor( - RunInRootFrame.DetermineComponentFrameRoot, - "name" - ); // Before ES6, the `name` property was not configurable. - - if (namePropDescriptor && namePropDescriptor.configurable) { - // V8 utilizes a function's `name` property when generating a stack trace. - Object.defineProperty( - RunInRootFrame.DetermineComponentFrameRoot, // Configurable properties can be updated even if its writable descriptor - // is set to `false`. - // $FlowFixMe[cannot-write] - "name", - { - value: "DetermineComponentFrameRoot" - } - ); - } + Reflect.construct(fn, [], Fake); + } else { + try { + Fake.call(); + } catch (x) { + control = x; + } // $FlowFixMe[prop-missing] found when upgrading Flow - try { - var _RunInRootFrame$Deter = - RunInRootFrame.DetermineComponentFrameRoot(), - sampleStack = _RunInRootFrame$Deter[0], - controlStack = _RunInRootFrame$Deter[1]; - - if (sampleStack && controlStack) { - // This extracts the first frame from the sample that isn't also in the control. - // Skipping one frame that we assume is the frame that calls the two. - var sampleLines = sampleStack.split("\n"); - var controlLines = controlStack.split("\n"); - var s = 0; - var c = 0; - - while ( - s < sampleLines.length && - !sampleLines[s].includes("DetermineComponentFrameRoot") - ) { - s++; - } - while ( - c < controlLines.length && - !controlLines[c].includes("DetermineComponentFrameRoot") - ) { - c++; - } // We couldn't find our intentionally injected common root frame, attempt - // to find another common root frame by search from the bottom of the - // control stack... - - if (s === sampleLines.length || c === controlLines.length) { - s = sampleLines.length - 1; - c = controlLines.length - 1; - - while (s >= 1 && c >= 0 && sampleLines[s] !== controlLines[c]) { - // We expect at least one stack frame to be shared. - // Typically this will be the root most one. However, stack frames may be - // cut off due to maximum stack limits. In this case, one maybe cut off - // earlier than the other. We assume that the sample is longer or the same - // and there for cut off earlier. So we should find the root most frame in - // the sample somewhere in the control. - c--; - } + fn.call(Fake.prototype); } + } else { + try { + throw Error(); + } catch (x) { + control = x; + } // TODO(luna): This will currently only throw if the function component + // tries to access React/ReactDOM/props. We should probably make this throw + // in simple components too - for (; s >= 1 && c >= 0; s--, c--) { - // Next we find the first one that isn't the same which should be the - // frame that called our sample function and the control. - if (sampleLines[s] !== controlLines[c]) { - // In V8, the first line is describing the message but other VMs don't. - // If we're about to return the first line, and the control is also on the same - // line, that's a pretty good indicator that our sample threw at same line as - // the control. I.e. before we entered the sample frame. So we ignore this result. - // This can happen if you passed a class to function component, or non-function. - if (s !== 1 || c !== 1) { - do { - s--; - c--; // We may still have similar intermediate frames from the construct call. - // The next one that isn't the same should be our match though. - - if (c < 0 || sampleLines[s] !== controlLines[c]) { - // V8 adds a "new" prefix for native classes. Let's remove it to make it prettier. - var _frame = - "\n" + sampleLines[s].replace(" at new ", " at "); // If our component frame is labeled "" - // but we have a user-provided "displayName" - // splice it in to make the stack more readable. - - if (fn.displayName && _frame.includes("")) { - _frame = _frame.replace("", fn.displayName); - } - - if (true) { - if (typeof fn === "function") { - componentFrameCache.set(fn, _frame); - } - } // Return the line we found. - - return _frame; - } - } while (s >= 1 && c >= 0); - } - break; - } + var maybePromise = fn(); // If the function component returns a promise, it's likely an async + // component, which we don't yet support. Attach a noop catch handler to + // silence the error. + // TODO: Implement component stacks for async client components? + + if (maybePromise && typeof maybePromise.catch === 'function') { + maybePromise.catch(function () {}); } } - } finally { - reentry = false; + } catch (sample) { + // This is inlined manually because closure doesn't do it for us. + if (sample && control && typeof sample.stack === 'string') { + return [sample.stack, control.stack]; + } + } - { - ReactSharedInternals.H = previousDispatcher; - reenableLogs(); + return [null, null]; + } + }; // $FlowFixMe[prop-missing] + + RunInRootFrame.DetermineComponentFrameRoot.displayName = 'DetermineComponentFrameRoot'; + var namePropDescriptor = Object.getOwnPropertyDescriptor(RunInRootFrame.DetermineComponentFrameRoot, 'name'); // Before ES6, the `name` property was not configurable. + + if (namePropDescriptor && namePropDescriptor.configurable) { + // V8 utilizes a function's `name` property when generating a stack trace. + Object.defineProperty(RunInRootFrame.DetermineComponentFrameRoot, // Configurable properties can be updated even if its writable descriptor + // is set to `false`. + // $FlowFixMe[cannot-write] + 'name', { + value: 'DetermineComponentFrameRoot' + }); + } + + try { + var _RunInRootFrame$Deter = RunInRootFrame.DetermineComponentFrameRoot(), + sampleStack = _RunInRootFrame$Deter[0], + controlStack = _RunInRootFrame$Deter[1]; + + if (sampleStack && controlStack) { + // This extracts the first frame from the sample that isn't also in the control. + // Skipping one frame that we assume is the frame that calls the two. + var sampleLines = sampleStack.split('\n'); + var controlLines = controlStack.split('\n'); + var s = 0; + var c = 0; + + while (s < sampleLines.length && !sampleLines[s].includes('DetermineComponentFrameRoot')) { + s++; + } + + while (c < controlLines.length && !controlLines[c].includes('DetermineComponentFrameRoot')) { + c++; + } // We couldn't find our intentionally injected common root frame, attempt + // to find another common root frame by search from the bottom of the + // control stack... + + + if (s === sampleLines.length || c === controlLines.length) { + s = sampleLines.length - 1; + c = controlLines.length - 1; + + while (s >= 1 && c >= 0 && sampleLines[s] !== controlLines[c]) { + // We expect at least one stack frame to be shared. + // Typically this will be the root most one. However, stack frames may be + // cut off due to maximum stack limits. In this case, one maybe cut off + // earlier than the other. We assume that the sample is longer or the same + // and there for cut off earlier. So we should find the root most frame in + // the sample somewhere in the control. + c--; } + } - Error.prepareStackTrace = previousPrepareStackTrace; - } // Fallback to just using the name if we couldn't make it throw. + for (; s >= 1 && c >= 0; s--, c--) { + // Next we find the first one that isn't the same which should be the + // frame that called our sample function and the control. + if (sampleLines[s] !== controlLines[c]) { + // In V8, the first line is describing the message but other VMs don't. + // If we're about to return the first line, and the control is also on the same + // line, that's a pretty good indicator that our sample threw at same line as + // the control. I.e. before we entered the sample frame. So we ignore this result. + // This can happen if you passed a class to function component, or non-function. + if (s !== 1 || c !== 1) { + do { + s--; + c--; // We may still have similar intermediate frames from the construct call. + // The next one that isn't the same should be our match though. + + if (c < 0 || sampleLines[s] !== controlLines[c]) { + // V8 adds a "new" prefix for native classes. Let's remove it to make it prettier. + var _frame = '\n' + sampleLines[s].replace(' at new ', ' at '); // If our component frame is labeled "" + // but we have a user-provided "displayName" + // splice it in to make the stack more readable. + + + if (fn.displayName && _frame.includes('')) { + _frame = _frame.replace('', fn.displayName); + } - var name = fn ? fn.displayName || fn.name : ""; - var syntheticFrame = name ? describeBuiltInComponentFrame(name) : ""; + if (true) { + if (typeof fn === 'function') { + componentFrameCache.set(fn, _frame); + } + } // Return the line we found. - { - if (typeof fn === "function") { - componentFrameCache.set(fn, syntheticFrame); + + return _frame; + } + } while (s >= 1 && c >= 0); + } + + break; } } + } + } finally { + reentry = false; - return syntheticFrame; + { + ReactSharedInternals.H = previousDispatcher; + reenableLogs(); } - function describeComponentFrame(name) { - return "\n in " + (name || "Unknown"); + Error.prepareStackTrace = previousPrepareStackTrace; + } // Fallback to just using the name if we couldn't make it throw. + + + var name = fn ? fn.displayName || fn.name : ''; + var syntheticFrame = name ? describeBuiltInComponentFrame(name) : ''; + + { + if (typeof fn === 'function') { + componentFrameCache.set(fn, syntheticFrame); } - function describeFunctionComponentFrame(fn) { - if (enableComponentStackLocations) { - return describeNativeComponentFrame(fn, false); - } else { - if (!fn) { - return ""; - } + } - var name = fn.displayName || fn.name || null; - return describeComponentFrame(name); - } + return syntheticFrame; +} + +function describeComponentFrame(name) { + return '\n in ' + (name || 'Unknown'); +} +function describeFunctionComponentFrame(fn) { + if (enableComponentStackLocations) { + return describeNativeComponentFrame(fn, false); + } else { + if (!fn) { + return ''; } - function shouldConstruct(Component) { - var prototype = Component.prototype; - return !!(prototype && prototype.isReactComponent); + var name = fn.displayName || fn.name || null; + return describeComponentFrame(name); + } +} + +function shouldConstruct(Component) { + var prototype = Component.prototype; + return !!(prototype && prototype.isReactComponent); +} + +function describeUnknownElementTypeFrameInDEV(type) { + + if (type == null) { + return ''; + } + + if (typeof type === 'function') { + if (enableComponentStackLocations) { + return describeNativeComponentFrame(type, shouldConstruct(type)); + } else { + return describeFunctionComponentFrame(type); } + } - function describeUnknownElementTypeFrameInDEV(type) { - if (type == null) { - return ""; - } + if (typeof type === 'string') { + return describeBuiltInComponentFrame(type); + } - if (typeof type === "function") { - if (enableComponentStackLocations) { - return describeNativeComponentFrame(type, shouldConstruct(type)); - } else { - return describeFunctionComponentFrame(type); + switch (type) { + case REACT_SUSPENSE_TYPE: + return describeBuiltInComponentFrame('Suspense'); + + case REACT_SUSPENSE_LIST_TYPE: + return describeBuiltInComponentFrame('SuspenseList'); + } + + if (typeof type === 'object') { + switch (type.$$typeof) { + case REACT_FORWARD_REF_TYPE: + return describeFunctionComponentFrame(type.render); + + case REACT_MEMO_TYPE: + // Memo may contain any component type so we recursively resolve it. + return describeUnknownElementTypeFrameInDEV(type.type); + + 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)); + } catch (x) {} } + } + } + + return ''; +} + +var FunctionComponent = 0; +var ClassComponent = 1; +var HostRoot = 3; // Root of a host tree. Could be nested inside another node. + +var HostPortal = 4; // A subtree. Could be an entry point to a different renderer. + +var HostComponent = 5; +var HostText = 6; +var Fragment = 7; +var Mode = 8; +var ContextConsumer = 9; +var ContextProvider = 10; +var ForwardRef = 11; +var Profiler = 12; +var SuspenseComponent = 13; +var MemoComponent = 14; +var SimpleMemoComponent = 15; +var LazyComponent = 16; +var IncompleteClassComponent = 17; +var DehydratedFragment = 18; +var SuspenseListComponent = 19; +var ScopeComponent = 21; +var OffscreenComponent = 22; +var CacheComponent = 24; +var TracingMarkerComponent = 25; +var HostHoistable = 26; +var HostSingleton = 27; +var IncompleteFunctionComponent = 28; + +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'; +} +function getComponentNameFromFiber(fiber) { + var tag = fiber.tag, + type = fiber.type; + + switch (tag) { + case CacheComponent: + return 'Cache'; + + case ContextConsumer: + if (enableRenderableContext) { + var consumer = type; + return getContextName(consumer._context) + '.Consumer'; + } else { + var context = type; + return getContextName(context) + '.Consumer'; } - if (typeof type === "string") { - return describeBuiltInComponentFrame(type); + case ContextProvider: + if (enableRenderableContext) { + var _context = type; + return getContextName(_context) + '.Provider'; + } else { + var provider = type; + return getContextName(provider._context) + '.Provider'; } - switch (type) { - case REACT_SUSPENSE_TYPE: - return describeBuiltInComponentFrame("Suspense"); + case DehydratedFragment: + return 'DehydratedFragment'; - case REACT_SUSPENSE_LIST_TYPE: - return describeBuiltInComponentFrame("SuspenseList"); - } + case ForwardRef: + return getWrappedName(type, type.render, 'ForwardRef'); - if (typeof type === "object") { - switch (type.$$typeof) { - case REACT_FORWARD_REF_TYPE: - return describeFunctionComponentFrame(type.render); + case Fragment: + return 'Fragment'; - case REACT_MEMO_TYPE: - // Memo may contain any component type so we recursively resolve it. - return describeUnknownElementTypeFrameInDEV(type.type); + case HostHoistable: + case HostSingleton: + case HostComponent: + // Host component type is the display name (e.g. "div", "View") + return type; - case REACT_LAZY_TYPE: { - var lazyComponent = type; - var payload = lazyComponent._payload; - var init = lazyComponent._init; + case HostPortal: + return 'Portal'; - try { - // Lazy may contain any component type so we recursively resolve it. - return describeUnknownElementTypeFrameInDEV(init(payload)); - } catch (x) {} - } - } - } + case HostRoot: + return 'Root'; - return ""; - } + case HostText: + return 'Text'; - var FunctionComponent = 0; - var ClassComponent = 1; - var HostRoot = 3; // Root of a host tree. Could be nested inside another node. - - var HostPortal = 4; // A subtree. Could be an entry point to a different renderer. - - var HostComponent = 5; - var HostText = 6; - var Fragment = 7; - var Mode = 8; - var ContextConsumer = 9; - var ContextProvider = 10; - var ForwardRef = 11; - var Profiler = 12; - var SuspenseComponent = 13; - var MemoComponent = 14; - var SimpleMemoComponent = 15; - var LazyComponent = 16; - var IncompleteClassComponent = 17; - var DehydratedFragment = 18; - var SuspenseListComponent = 19; - var ScopeComponent = 21; - var OffscreenComponent = 22; - var CacheComponent = 24; - var TracingMarkerComponent = 25; - var HostHoistable = 26; - var HostSingleton = 27; - var IncompleteFunctionComponent = 28; - - 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"; - } - function getComponentNameFromFiber(fiber) { - var tag = fiber.tag, - type = fiber.type; - - switch (tag) { - case CacheComponent: - return "Cache"; - - case ContextConsumer: - if (enableRenderableContext) { - var consumer = type; - return getContextName(consumer._context) + ".Consumer"; - } else { - var context = type; - return getContextName(context) + ".Consumer"; - } + case LazyComponent: + // Name comes from the type in this case; we don't have a tag. + return getComponentNameFromType(type); - case ContextProvider: - if (enableRenderableContext) { - var _context = type; - return getContextName(_context) + ".Provider"; - } else { - var provider = type; - return getContextName(provider._context) + ".Provider"; - } + case Mode: + if (type === REACT_STRICT_MODE_TYPE) { + // Don't be less specific than shared/getComponentNameFromType + return 'StrictMode'; + } - case DehydratedFragment: - return "DehydratedFragment"; + return 'Mode'; - case ForwardRef: - return getWrappedName(type, type.render, "ForwardRef"); + case OffscreenComponent: + return 'Offscreen'; - case Fragment: - return "Fragment"; + case Profiler: + return 'Profiler'; - case HostHoistable: - case HostSingleton: - case HostComponent: - // Host component type is the display name (e.g. "div", "View") - return type; + case ScopeComponent: + return 'Scope'; - case HostPortal: - return "Portal"; + case SuspenseComponent: + return 'Suspense'; - case HostRoot: - return "Root"; + case SuspenseListComponent: + return 'SuspenseList'; - case HostText: - return "Text"; + case TracingMarkerComponent: + return 'TracingMarker'; + // The display name for these tags come from the user-provided type: - case LazyComponent: - // Name comes from the type in this case; we don't have a tag. - return getComponentNameFromType(type); + case IncompleteClassComponent: + case IncompleteFunctionComponent: - case Mode: - if (type === REACT_STRICT_MODE_TYPE) { - // Don't be less specific than shared/getComponentNameFromType - return "StrictMode"; - } + // Fallthrough - return "Mode"; + case ClassComponent: + case FunctionComponent: + case MemoComponent: + case SimpleMemoComponent: + if (typeof type === 'function') { + return type.displayName || type.name || null; + } - case OffscreenComponent: - return "Offscreen"; + if (typeof type === 'string') { + return type; + } - case Profiler: - return "Profiler"; + break; - case ScopeComponent: - return "Scope"; + } - case SuspenseComponent: - return "Suspense"; + return null; +} - case SuspenseListComponent: - return "SuspenseList"; +var REACT_CLIENT_REFERENCE = Symbol.for('react.client.reference'); +var specialPropKeyWarningShown; +var specialPropRefWarningShown; +var didWarnAboutStringRefs; - case TracingMarkerComponent: - return "TracingMarker"; - // The display name for these tags come from the user-provided type: +{ + didWarnAboutStringRefs = {}; +} - case IncompleteClassComponent: - case IncompleteFunctionComponent: +function hasValidRef(config) { + { + if (hasOwnProperty.call(config, 'ref')) { + var getter = Object.getOwnPropertyDescriptor(config, 'ref').get; - // Fallthrough + if (getter && getter.isReactWarning) { + return false; + } + } + } - case ClassComponent: - case FunctionComponent: - case MemoComponent: - case SimpleMemoComponent: - if (typeof type === "function") { - return type.displayName || type.name || null; - } + return config.ref !== undefined; +} - if (typeof type === "string") { - return type; - } +function hasValidKey(config) { + { + if (hasOwnProperty.call(config, 'key')) { + var getter = Object.getOwnPropertyDescriptor(config, 'key').get; - break; + if (getter && getter.isReactWarning) { + return false; } - - return null; } + } - var REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference"); - var specialPropKeyWarningShown; - var specialPropRefWarningShown; - var didWarnAboutStringRefs; + return config.key !== undefined; +} - { - didWarnAboutStringRefs = {}; - } +function warnIfStringRefCannotBeAutoConverted(config, self) { + { + if (typeof config.ref === 'string' && ReactSharedInternals.owner && self && ReactSharedInternals.owner.stateNode !== self) { + var componentName = getComponentNameFromType(ReactSharedInternals.owner.type); - function hasValidRef(config) { - { - if (hasOwnProperty.call(config, "ref")) { - var getter = Object.getOwnPropertyDescriptor(config, "ref").get; + if (!didWarnAboutStringRefs[componentName]) { + error('Component "%s" contains the string ref "%s". ' + 'Support for string refs will be removed in a future major release. ' + 'This case cannot be automatically converted to an arrow function. ' + 'We ask you to manually fix this case by using useRef() or createRef() instead. ' + 'Learn more about using refs safely here: ' + 'https://react.dev/link/strict-mode-string-ref', getComponentNameFromType(ReactSharedInternals.owner.type), config.ref); - if (getter && getter.isReactWarning) { - return false; - } - } + didWarnAboutStringRefs[componentName] = true; } - - return config.ref !== undefined; } + } +} - function hasValidKey(config) { - { - if (hasOwnProperty.call(config, "key")) { - var getter = Object.getOwnPropertyDescriptor(config, "key").get; +function defineKeyPropWarningGetter(props, displayName) { + { + var warnAboutAccessingKey = function () { + if (!specialPropKeyWarningShown) { + specialPropKeyWarningShown = true; - if (getter && getter.isReactWarning) { - return false; - } - } + error('%s: `key` is not a prop. Trying to access it will result ' + 'in `undefined` being returned. If you need to access the same ' + 'value within the child component, you should pass it as a different ' + 'prop. (https://react.dev/link/special-props)', displayName); } + }; + + warnAboutAccessingKey.isReactWarning = true; + Object.defineProperty(props, 'key', { + get: warnAboutAccessingKey, + configurable: true + }); + } +} - return config.key !== undefined; - } +function defineRefPropWarningGetter(props, displayName) { + { + { + var warnAboutAccessingRef = function () { + if (!specialPropRefWarningShown) { + specialPropRefWarningShown = true; - function warnIfStringRefCannotBeAutoConverted(config, self) { - { - if ( - typeof config.ref === "string" && - ReactSharedInternals.owner && - self && - ReactSharedInternals.owner.stateNode !== self - ) { - var componentName = getComponentNameFromType( - ReactSharedInternals.owner.type - ); - - if (!didWarnAboutStringRefs[componentName]) { - error( - 'Component "%s" contains the string ref "%s". ' + - "Support for string refs will be removed in a future major release. " + - "This case cannot be automatically converted to an arrow function. " + - "We ask you to manually fix this case by using useRef() or createRef() instead. " + - "Learn more about using refs safely here: " + - "https://react.dev/link/strict-mode-string-ref", - getComponentNameFromType(ReactSharedInternals.owner.type), - config.ref - ); - - didWarnAboutStringRefs[componentName] = true; - } + error('%s: `ref` is not a prop. Trying to access it will result ' + 'in `undefined` being returned. If you need to access the same ' + 'value within the child component, you should pass it as a different ' + 'prop. (https://react.dev/link/special-props)', displayName); } - } + }; + + warnAboutAccessingRef.isReactWarning = true; + Object.defineProperty(props, 'ref', { + get: warnAboutAccessingRef, + configurable: true + }); } + } +} +/** + * Factory method to create a new React element. This no longer adheres to + * the class pattern, so do not use new to call it. Also, instanceof check + * will not work. Instead test $$typeof field against Symbol.for('react.element') to check + * if something is a React Element. + * + * @param {*} type + * @param {*} props + * @param {*} key + * @param {string|object} ref + * @param {*} owner + * @param {*} self A *temporary* helper to detect places where `this` is + * different from the `owner` when React.createElement is called, so that we + * can warn. We want to get rid of owner and replace string `ref`s with arrow + * functions, and as long as `this` and owner are the same, there will be no + * change in behavior. + * @param {*} source An annotation object (added by a transpiler or otherwise) + * indicating filename, line number, and/or other information. + * @internal + */ - function defineKeyPropWarningGetter(props, displayName) { - { - var warnAboutAccessingKey = function () { - if (!specialPropKeyWarningShown) { - specialPropKeyWarningShown = true; - - error( - "%s: `key` is not a prop. Trying to access it will result " + - "in `undefined` being returned. If you need to access the same " + - "value within the child component, you should pass it as a different " + - "prop. (https://react.dev/link/special-props)", - displayName - ); - } - }; - warnAboutAccessingKey.isReactWarning = true; - Object.defineProperty(props, "key", { - get: warnAboutAccessingKey, - configurable: true - }); - } +function ReactElement(type, key, _ref, self, source, owner, props) { + var ref; + + { + ref = _ref; + } + + var element; + + { + // In prod, `ref` is a regular property. It will be removed in a + // future release. + element = { + // This tag allows us to uniquely identify this as a React Element + $$typeof: REACT_ELEMENT_TYPE, + // Built-in properties that belong on the element + type: type, + key: key, + ref: ref, + props: props, + // Record the component responsible for creating this element. + _owner: owner + }; + } + + { + // The validation flag is currently mutative. We put it on + // an external backing store so that we can freeze the whole object. + // This can be replaced with a WeakMap once they are implemented in + // commonly used development environments. + element._store = {}; // To make comparing ReactElements easier for testing purposes, we make + // the validation flag non-enumerable (where possible, which should + // include every environment we run tests in), so the test framework + // ignores it. + + Object.defineProperty(element._store, 'validated', { + configurable: false, + enumerable: false, + writable: true, + value: false + }); // debugInfo contains Server Component debug information. + + Object.defineProperty(element, '_debugInfo', { + configurable: false, + enumerable: false, + writable: true, + value: null + }); + + if (Object.freeze) { + Object.freeze(element.props); + Object.freeze(element); } + } - function defineRefPropWarningGetter(props, displayName) { - { - { - var warnAboutAccessingRef = function () { - if (!specialPropRefWarningShown) { - specialPropRefWarningShown = true; - - error( - "%s: `ref` is not a prop. Trying to access it will result " + - "in `undefined` being returned. If you need to access the same " + - "value within the child component, you should pass it as a different " + - "prop. (https://react.dev/link/special-props)", - displayName - ); - } - }; + return element; +} +var didWarnAboutKeySpread = {}; +/** + * https://github.com/reactjs/rfcs/pull/107 + * @param {*} type + * @param {object} props + * @param {string} key + */ - warnAboutAccessingRef.isReactWarning = true; - Object.defineProperty(props, "ref", { - get: warnAboutAccessingRef, - configurable: true - }); - } - } - } - /** - * Factory method to create a new React element. This no longer adheres to - * the class pattern, so do not use new to call it. Also, instanceof check - * will not work. Instead test $$typeof field against Symbol.for('react.element') to check - * if something is a React Element. - * - * @param {*} type - * @param {*} props - * @param {*} key - * @param {string|object} ref - * @param {*} owner - * @param {*} self A *temporary* helper to detect places where `this` is - * different from the `owner` when React.createElement is called, so that we - * can warn. We want to get rid of owner and replace string `ref`s with arrow - * functions, and as long as `this` and owner are the same, there will be no - * change in behavior. - * @param {*} source An annotation object (added by a transpiler or otherwise) - * indicating filename, line number, and/or other information. - * @internal - */ - - function ReactElement(type, key, _ref, self, source, owner, props) { - var ref; +function jsxDEV$1(type, config, maybeKey, isStaticChildren, source, self) { + { + if (!isValidElementType(type)) { + // This is an invalid element type. + // + // We warn in this case but don't throw. We expect the element creation to + // succeed and there will likely be errors in render. + var info = ''; - { - ref = _ref; + 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 element; + var typeString; - { - // In prod, `ref` is a regular property. It will be removed in a - // future release. - element = { - // This tag allows us to uniquely identify this as a React Element - $$typeof: REACT_ELEMENT_TYPE, - // Built-in properties that belong on the element - type: type, - key: key, - ref: ref, - props: props, - // Record the component responsible for creating this element. - _owner: owner - }; + if (type === null) { + typeString = 'null'; + } else if (isArray(type)) { + typeString = 'array'; + } else if (type !== undefined && type.$$typeof === REACT_ELEMENT_TYPE) { + typeString = "<" + (getComponentNameFromType(type.type) || 'Unknown') + " />"; + info = ' Did you accidentally export a JSX literal instead of a component?'; + } else { + typeString = typeof type; } - { - // The validation flag is currently mutative. We put it on - // an external backing store so that we can freeze the whole object. - // This can be replaced with a WeakMap once they are implemented in - // commonly used development environments. - element._store = {}; // To make comparing ReactElements easier for testing purposes, we make - // the validation flag non-enumerable (where possible, which should - // include every environment we run tests in), so the test framework - // ignores it. - - Object.defineProperty(element._store, "validated", { - configurable: false, - enumerable: false, - writable: true, - value: false - }); // debugInfo contains Server Component debug information. - - Object.defineProperty(element, "_debugInfo", { - configurable: false, - enumerable: false, - writable: true, - value: null - }); - - if (Object.freeze) { - Object.freeze(element.props); - Object.freeze(element); + error('React.jsx: type is invalid -- expected a string (for ' + 'built-in components) or a class/function (for composite ' + 'components) but got: %s.%s', typeString, info); + } else { + // This is a valid element type. + // Skip key warning if the type isn't valid since our key validation logic + // doesn't expect a non-string/function type and can throw confusing + // errors. We don't want exception behavior to differ between dev and + // prod. (Rendering will throw with a helpful message and as soon as the + // type is fixed, the key warnings will appear.) + var children = config.children; + + if (children !== undefined) { + if (isStaticChildren) { + if (isArray(children)) { + for (var i = 0; i < children.length; i++) { + validateChildKeys(children[i], type); + } + + if (Object.freeze) { + Object.freeze(children); + } + } else { + error('React.jsx: Static children should always be an array. ' + 'You are likely explicitly calling React.jsxs or React.jsxDEV. ' + 'Use the Babel transform instead.'); + } + } else { + validateChildKeys(children, type); } } + } // Warn about key spread regardless of whether the type is valid. - return element; - } - var didWarnAboutKeySpread = {}; - /** - * https://github.com/reactjs/rfcs/pull/107 - * @param {*} type - * @param {object} props - * @param {string} key - */ - - function jsxDEV$1(type, config, maybeKey, isStaticChildren, source, self) { - { - if (!isValidElementType(type)) { - // This is an invalid element type. - // - // We warn in this case but don't throw. We expect the element creation to - // succeed and there will likely be errors in render. - var info = ""; - - 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 typeString; - - if (type === null) { - typeString = "null"; - } else if (isArray(type)) { - typeString = "array"; - } else if ( - type !== undefined && - type.$$typeof === REACT_ELEMENT_TYPE - ) { - typeString = - "<" + (getComponentNameFromType(type.type) || "Unknown") + " />"; - info = - " Did you accidentally export a JSX literal instead of a component?"; - } else { - typeString = typeof type; - } + if (hasOwnProperty.call(config, 'key')) { + var componentName = getComponentNameFromType(type); + var keys = Object.keys(config).filter(function (k) { + return k !== 'key'; + }); + var beforeExample = keys.length > 0 ? '{key: someKey, ' + keys.join(': ..., ') + ': ...}' : '{key: someKey}'; - error( - "React.jsx: type is invalid -- expected a string (for " + - "built-in components) or a class/function (for composite " + - "components) but got: %s.%s", - typeString, - info - ); - } else { - // This is a valid element type. - // Skip key warning if the type isn't valid since our key validation logic - // doesn't expect a non-string/function type and can throw confusing - // errors. We don't want exception behavior to differ between dev and - // prod. (Rendering will throw with a helpful message and as soon as the - // type is fixed, the key warnings will appear.) - var children = config.children; - - if (children !== undefined) { - if (isStaticChildren) { - if (isArray(children)) { - for (var i = 0; i < children.length; i++) { - validateChildKeys(children[i], type); - } + if (!didWarnAboutKeySpread[componentName + beforeExample]) { + var afterExample = keys.length > 0 ? '{' + keys.join(': ..., ') + ': ...}' : '{}'; - if (Object.freeze) { - Object.freeze(children); - } - } else { - error( - "React.jsx: Static children should always be an array. " + - "You are likely explicitly calling React.jsxs or React.jsxDEV. " + - "Use the Babel transform instead." - ); - } - } else { - validateChildKeys(children, type); - } - } - } // Warn about key spread regardless of whether the type is valid. + error('A props object containing a "key" prop is being spread into JSX:\n' + ' let props = %s;\n' + ' <%s {...props} />\n' + 'React keys must be passed directly to JSX without using spread:\n' + ' let props = %s;\n' + ' <%s key={someKey} {...props} />', beforeExample, componentName, afterExample, componentName); - if (hasOwnProperty.call(config, "key")) { - var componentName = getComponentNameFromType(type); - var keys = Object.keys(config).filter(function (k) { - return k !== "key"; - }); - var beforeExample = - keys.length > 0 - ? "{key: someKey, " + keys.join(": ..., ") + ": ...}" - : "{key: someKey}"; - - if (!didWarnAboutKeySpread[componentName + beforeExample]) { - var afterExample = - keys.length > 0 ? "{" + keys.join(": ..., ") + ": ...}" : "{}"; - - error( - 'A props object containing a "key" prop is being spread into JSX:\n' + - " let props = %s;\n" + - " <%s {...props} />\n" + - "React keys must be passed directly to JSX without using spread:\n" + - " let props = %s;\n" + - " <%s key={someKey} {...props} />", - beforeExample, - componentName, - afterExample, - componentName - ); - - didWarnAboutKeySpread[componentName + beforeExample] = true; - } - } + didWarnAboutKeySpread[componentName + beforeExample] = true; + } + } - var key = null; - var ref = null; // Currently, key can be spread in as a prop. This causes a potential - // issue if key is also explicitly declared (ie.
- // or
). We want to deprecate key spread, - // but as an intermediary step, we will use jsxDEV for everything except - //
, because we aren't currently able to tell if - // key is explicitly declared to be undefined or not. + var key = null; + var ref = null; // Currently, key can be spread in as a prop. This causes a potential + // issue if key is also explicitly declared (ie.
+ // or
). We want to deprecate key spread, + // but as an intermediary step, we will use jsxDEV for everything except + //
, because we aren't currently able to tell if + // key is explicitly declared to be undefined or not. - if (maybeKey !== undefined) { - { - checkKeyStringCoercion(maybeKey); - } + if (maybeKey !== undefined) { + { + checkKeyStringCoercion(maybeKey); + } - key = "" + maybeKey; - } + key = '' + maybeKey; + } - if (hasValidKey(config)) { - { - checkKeyStringCoercion(config.key); - } + if (hasValidKey(config)) { + { + checkKeyStringCoercion(config.key); + } + + key = '' + config.key; + } + + if (hasValidRef(config)) { + { + ref = config.ref; - key = "" + config.key; + { + ref = coerceStringRef(ref, ReactSharedInternals.owner, type); } + } - if (hasValidRef(config)) { - { - ref = config.ref; + { + warnIfStringRefCannotBeAutoConverted(config, self); + } + } - { - ref = coerceStringRef(ref, ReactSharedInternals.owner, type); - } - } + var props; + { + // We need to remove reserved props (key, prop, ref). Create a fresh props + // object and copy over all the non-reserved props. We don't use `delete` + // because in V8 it will deopt the object to dictionary mode. + props = {}; + + for (var propName in config) { + // Skip over reserved prop names + if (propName !== 'key' && (propName !== 'ref')) { { - warnIfStringRefCannotBeAutoConverted(config, self); + props[propName] = config[propName]; } } + } + } - var props; + if (!disableDefaultPropsExceptForClasses) { + // Resolve default props + if (type && type.defaultProps) { + var defaultProps = type.defaultProps; - { - // We need to remove reserved props (key, prop, ref). Create a fresh props - // object and copy over all the non-reserved props. We don't use `delete` - // because in V8 it will deopt the object to dictionary mode. - props = {}; - - for (var propName in config) { - // Skip over reserved prop names - if (propName !== "key" && propName !== "ref") { - { - props[propName] = config[propName]; - } - } + for (var _propName2 in defaultProps) { + if (props[_propName2] === undefined) { + props[_propName2] = defaultProps[_propName2]; } } + } + } - if (!disableDefaultPropsExceptForClasses) { - // Resolve default props - if (type && type.defaultProps) { - var defaultProps = type.defaultProps; + if (key || ref) { + var displayName = typeof type === 'function' ? type.displayName || type.name || 'Unknown' : type; - for (var _propName2 in defaultProps) { - if (props[_propName2] === undefined) { - props[_propName2] = defaultProps[_propName2]; - } - } - } - } + if (key) { + defineKeyPropWarningGetter(props, displayName); + } - if (key || ref) { - var displayName = - typeof type === "function" - ? type.displayName || type.name || "Unknown" - : type; + if (ref) { + defineRefPropWarningGetter(props, displayName); + } + } - if (key) { - defineKeyPropWarningGetter(props, displayName); - } + var element = ReactElement(type, key, ref, self, source, ReactSharedInternals.owner, props); - if (ref) { - defineRefPropWarningGetter(props, displayName); - } - } + if (type === REACT_FRAGMENT_TYPE) { + validateFragmentProps(element); + } - var element = ReactElement( - type, - key, - ref, - self, - source, - ReactSharedInternals.owner, - props - ); - - if (type === REACT_FRAGMENT_TYPE) { - validateFragmentProps(element); - } + return element; + } +} + +function getDeclarationErrorAddendum() { + { + if (ReactSharedInternals.owner) { + var name = getComponentNameFromType(ReactSharedInternals.owner.type); - return element; + if (name) { + return '\n\nCheck the render method of `' + name + '`.'; } } - function getDeclarationErrorAddendum() { - { - if (ReactSharedInternals.owner) { - var name = getComponentNameFromType(ReactSharedInternals.owner.type); + return ''; + } +} +/** + * Ensure that every element either is passed in a static location, in an + * array with an explicit keys property defined, or in an object literal + * with valid key property. + * + * @internal + * @param {ReactNode} node Statically passed child of any type. + * @param {*} parentType node's parent's type. + */ - if (name) { - return "\n\nCheck the render method of `" + name + "`."; - } - } - return ""; - } +function validateChildKeys(node, parentType) { + { + if (typeof node !== 'object' || !node) { + return; } - /** - * Ensure that every element either is passed in a static location, in an - * array with an explicit keys property defined, or in an object literal - * with valid key property. - * - * @internal - * @param {ReactNode} node Statically passed child of any type. - * @param {*} parentType node's parent's type. - */ - - function validateChildKeys(node, parentType) { - { - if (typeof node !== "object" || !node) { - return; - } - if (node.$$typeof === REACT_CLIENT_REFERENCE); - else if (isArray(node)) { - for (var i = 0; i < node.length; i++) { - var child = node[i]; + if (node.$$typeof === REACT_CLIENT_REFERENCE) ; else if (isArray(node)) { + for (var i = 0; i < node.length; i++) { + var child = node[i]; - if (isValidElement(child)) { - validateExplicitKey(child, parentType); - } - } - } else if (isValidElement(node)) { - // This element was passed in a valid location. - if (node._store) { - node._store.validated = true; - } - } else { - var iteratorFn = getIteratorFn(node); - - if (typeof iteratorFn === "function") { - // Entry iterators used to provide implicit keys, - // but now we print a separate warning for them later. - if (iteratorFn !== node.entries) { - var iterator = iteratorFn.call(node); - var step; - - while (!(step = iterator.next()).done) { - if (isValidElement(step.value)) { - validateExplicitKey(step.value, parentType); - } - } + if (isValidElement(child)) { + validateExplicitKey(child, parentType); + } + } + } else if (isValidElement(node)) { + // This element was passed in a valid location. + if (node._store) { + node._store.validated = true; + } + } else { + var iteratorFn = getIteratorFn(node); + + if (typeof iteratorFn === 'function') { + // Entry iterators used to provide implicit keys, + // but now we print a separate warning for them later. + if (iteratorFn !== node.entries) { + var iterator = iteratorFn.call(node); + var step; + + while (!(step = iterator.next()).done) { + if (isValidElement(step.value)) { + validateExplicitKey(step.value, parentType); } } } } } - /** - * Verifies the object is a ReactElement. - * See https://reactjs.org/docs/react-api.html#isvalidelement - * @param {?object} object - * @return {boolean} True if `object` is a ReactElement. - * @final - */ - - function isValidElement(object) { - return ( - typeof object === "object" && - object !== null && - object.$$typeof === REACT_ELEMENT_TYPE - ); - } - var ownerHasKeyUseWarning = {}; - /** - * Warn if the element doesn't have an explicit key assigned to it. - * This element is in an array. The array could grow and shrink or be - * reordered. All children that haven't already been validated are required to - * have a "key" property assigned to it. Error statuses are cached so a warning - * will only be shown once. - * - * @internal - * @param {ReactElement} element Element that requires a key. - * @param {*} parentType element's parent's type. - */ - - function validateExplicitKey(element, parentType) { - { - if ( - !element._store || - element._store.validated || - element.key != null - ) { - return; - } + } +} +/** + * Verifies the object is a ReactElement. + * See https://reactjs.org/docs/react-api.html#isvalidelement + * @param {?object} object + * @return {boolean} True if `object` is a ReactElement. + * @final + */ - element._store.validated = true; - var currentComponentErrorInfo = - getCurrentComponentErrorInfo(parentType); - if (ownerHasKeyUseWarning[currentComponentErrorInfo]) { - return; - } +function isValidElement(object) { + return typeof object === 'object' && object !== null && object.$$typeof === REACT_ELEMENT_TYPE; +} +var ownerHasKeyUseWarning = {}; +/** + * Warn if the element doesn't have an explicit key assigned to it. + * This element is in an array. The array could grow and shrink or be + * reordered. All children that haven't already been validated are required to + * have a "key" property assigned to it. Error statuses are cached so a warning + * will only be shown once. + * + * @internal + * @param {ReactElement} element Element that requires a key. + * @param {*} parentType element's parent's type. + */ - ownerHasKeyUseWarning[currentComponentErrorInfo] = true; // Usually the current owner is the offender, but if it accepts children as a - // property, it may be the creator of the child that's responsible for - // assigning it a key. +function validateExplicitKey(element, parentType) { + { + if (!element._store || element._store.validated || element.key != null) { + return; + } - var childOwner = ""; + element._store.validated = true; + var currentComponentErrorInfo = getCurrentComponentErrorInfo(parentType); - if ( - element && - element._owner != null && - element._owner !== ReactSharedInternals.owner - ) { - var ownerName = null; + if (ownerHasKeyUseWarning[currentComponentErrorInfo]) { + return; + } - if (typeof element._owner.tag === "number") { - ownerName = getComponentNameFromType(element._owner.type); - } else if (typeof element._owner.name === "string") { - ownerName = element._owner.name; - } // Give the component that originally created this child. + ownerHasKeyUseWarning[currentComponentErrorInfo] = true; // Usually the current owner is the offender, but if it accepts children as a + // property, it may be the creator of the child that's responsible for + // assigning it a key. - childOwner = " It was passed a child from " + ownerName + "."; - } + var childOwner = ''; - setCurrentlyValidatingElement(element); + if (element && element._owner != null && element._owner !== ReactSharedInternals.owner) { + var ownerName = null; - error( - 'Each child in a list should have a unique "key" prop.' + - "%s%s See https://react.dev/link/warning-keys for more information.", - currentComponentErrorInfo, - childOwner - ); + if (typeof element._owner.tag === 'number') { + ownerName = getComponentNameFromType(element._owner.type); + } else if (typeof element._owner.name === 'string') { + ownerName = element._owner.name; + } // Give the component that originally created this child. - setCurrentlyValidatingElement(null); - } - } - function setCurrentlyValidatingElement(element) { - { - if (element) { - var stack = describeUnknownElementTypeFrameInDEV(element.type); - ReactSharedInternals.setExtraStackFrame(stack); - } else { - ReactSharedInternals.setExtraStackFrame(null); - } - } + childOwner = " It was passed a child from " + ownerName + "."; } - function getCurrentComponentErrorInfo(parentType) { - { - var info = getDeclarationErrorAddendum(); + setCurrentlyValidatingElement(element); - if (!info) { - var parentName = getComponentNameFromType(parentType); + error('Each child in a list should have a unique "key" prop.' + '%s%s See https://react.dev/link/warning-keys for more information.', currentComponentErrorInfo, childOwner); - if (parentName) { - info = - "\n\nCheck the top-level render call using <" + parentName + ">."; - } - } + setCurrentlyValidatingElement(null); + } +} - return info; - } +function setCurrentlyValidatingElement(element) { + { + if (element) { + var stack = describeUnknownElementTypeFrameInDEV(element.type); + ReactSharedInternals.setExtraStackFrame(stack); + } else { + ReactSharedInternals.setExtraStackFrame(null); } - /** - * Given a fragment, validate that it can only be provided with fragment props - * @param {ReactElement} fragment - */ - - function validateFragmentProps(fragment) { - // TODO: Move this to render phase instead of at element creation. - { - var keys = Object.keys(fragment.props); + } +} - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; +function getCurrentComponentErrorInfo(parentType) { + { + var info = getDeclarationErrorAddendum(); - if (key !== "children" && key !== "key") { - setCurrentlyValidatingElement(fragment); + if (!info) { + var parentName = getComponentNameFromType(parentType); - error( - "Invalid prop `%s` supplied to `React.Fragment`. " + - "React.Fragment can only have `key` and `children` props.", - key - ); + if (parentName) { + info = "\n\nCheck the top-level render call using <" + parentName + ">."; + } + } - setCurrentlyValidatingElement(null); - break; - } - } + return info; + } +} +/** + * Given a fragment, validate that it can only be provided with fragment props + * @param {ReactElement} fragment + */ - if (fragment.ref !== null) { - setCurrentlyValidatingElement(fragment); - error("Invalid attribute `ref` supplied to `React.Fragment`."); +function validateFragmentProps(fragment) { + // TODO: Move this to render phase instead of at element creation. + { + var keys = Object.keys(fragment.props); - setCurrentlyValidatingElement(null); - } - } - } + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; - function coerceStringRef(mixedRef, owner, type) { - var stringRef; + if (key !== 'children' && key !== 'key') { + setCurrentlyValidatingElement(fragment); - if (typeof mixedRef === "string") { - stringRef = mixedRef; - } else { - if (typeof mixedRef === "number" || typeof mixedRef === "boolean") { - { - checkPropStringCoercion(mixedRef, "ref"); - } + error('Invalid prop `%s` supplied to `React.Fragment`. ' + 'React.Fragment can only have `key` and `children` props.', key); - stringRef = "" + mixedRef; - } else { - return mixedRef; - } + setCurrentlyValidatingElement(null); + break; } + } - var callback = stringRefAsCallbackRef.bind(null, stringRef, type, owner); // This is used to check whether two callback refs conceptually represent - // the same string ref, and can therefore be reused by the reconciler. Needed - // for backwards compatibility with old Meta code that relies on string refs - // not being reattached on every render. + if (fragment.ref !== null) { + setCurrentlyValidatingElement(fragment); - callback.__stringRef = stringRef; - callback.__type = type; - callback.__owner = owner; - return callback; + error('Invalid attribute `ref` supplied to `React.Fragment`.'); + + setCurrentlyValidatingElement(null); } + } +} - function stringRefAsCallbackRef(stringRef, type, owner, value) { - if (!owner) { - throw new Error( - "Element ref was specified as a string (" + - stringRef + - ") 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://react.dev/link/refs-must-have-owner for more information." - ); - } +function coerceStringRef(mixedRef, owner, type) { - if (owner.tag !== ClassComponent) { - throw new Error( - "Function components cannot have string refs. " + - "We recommend using useRef() instead. " + - "Learn more about using refs safely here: " + - "https://react.dev/link/strict-mode-string-ref" - ); - } + var stringRef; + if (typeof mixedRef === 'string') { + stringRef = mixedRef; + } else { + if (typeof mixedRef === 'number' || typeof mixedRef === 'boolean') { { - if ( - // Will already warn with "Function components cannot be given refs" - !(typeof type === "function" && !isReactClass(type)) - ) { - var componentName = getComponentNameFromFiber(owner) || "Component"; - - 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://react.dev/link/strict-mode-string-ref", - componentName, - stringRef - ); - - didWarnAboutStringRefs[componentName] = true; - } - } + checkPropStringCoercion(mixedRef, 'ref'); } - var inst = owner.stateNode; + stringRef = '' + mixedRef; + } else { + return mixedRef; + } + } - if (!inst) { - throw new Error( - "Missing owner for string ref " + - stringRef + - ". This error is likely caused by a " + - "bug in React. Please file an issue." - ); - } + var callback = stringRefAsCallbackRef.bind(null, stringRef, type, owner); // This is used to check whether two callback refs conceptually represent + // the same string ref, and can therefore be reused by the reconciler. Needed + // for backwards compatibility with old Meta code that relies on string refs + // not being reattached on every render. + + callback.__stringRef = stringRef; + callback.__type = type; + callback.__owner = owner; + return callback; +} - var refs = inst.refs; +function stringRefAsCallbackRef(stringRef, type, owner, value) { - if (value === null) { - delete refs[stringRef]; - } else { - refs[stringRef] = value; + if (!owner) { + throw new Error("Element ref was specified as a string (" + stringRef + ") 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://react.dev/link/refs-must-have-owner for more information.'); + } + + if (owner.tag !== ClassComponent) { + throw new Error('Function components cannot have string refs. ' + 'We recommend using useRef() instead. ' + 'Learn more about using refs safely here: ' + 'https://react.dev/link/strict-mode-string-ref'); + } + + { + if ( // Will already warn with "Function components cannot be given refs" + !(typeof type === 'function' && !isReactClass(type))) { + var componentName = getComponentNameFromFiber(owner) || 'Component'; + + 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://react.dev/link/strict-mode-string-ref', componentName, stringRef); + + didWarnAboutStringRefs[componentName] = true; } } + } - function isReactClass(type) { - return type.prototype && type.prototype.isReactComponent; - } + var inst = owner.stateNode; + + if (!inst) { + throw new Error("Missing owner for string ref " + stringRef + ". This error is likely caused by a " + 'bug in React. Please file an issue.'); + } + + var refs = inst.refs; + + if (value === null) { + delete refs[stringRef]; + } else { + refs[stringRef] = value; + } +} + +function isReactClass(type) { + return type.prototype && type.prototype.isReactComponent; +} - var jsxDEV = jsxDEV$1; +var jsxDEV = jsxDEV$1 ; - exports.Fragment = REACT_FRAGMENT_TYPE; - exports.jsxDEV = jsxDEV; +exports.Fragment = REACT_FRAGMENT_TYPE; +exports.jsxDEV = jsxDEV; })(); } diff --git a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/JSXRuntime-dev.js b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/JSXRuntime-dev.js index e5b32204fffff..0cc9c98978f82 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/JSXRuntime-dev.js +++ b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/JSXRuntime-dev.js @@ -7,1725 +7,1542 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<<7b2e78bcb8542591ec0d9c0850e3ca30>> + * @generated SignedSource<<63334719117bc7e81815150b27588000>> */ -"use strict"; +'use strict'; if (__DEV__) { - (function () { - "use strict"; - - var React = require("react"); - var dynamicFlagsUntyped = require("ReactNativeInternalFeatureFlags"); - - // 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"); // TODO: Delete with enableRenderableContext - - var REACT_CONSUMER_TYPE = Symbol.for("react.consumer"); - var REACT_CONTEXT_TYPE = Symbol.for("react.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_OFFSCREEN_TYPE = Symbol.for("react.offscreen"); - var MAYBE_ITERATOR_SYMBOL = Symbol.iterator; - var FAUX_ITERATOR_SYMBOL = "@@iterator"; - function getIteratorFn(maybeIterable) { - if (maybeIterable === null || typeof maybeIterable !== "object") { - return null; - } + (function() { +'use strict'; + +var React = require('react'); +var dynamicFlagsUntyped = require('ReactNativeInternalFeatureFlags'); + +// 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'); // TODO: Delete with enableRenderableContext + +var REACT_CONSUMER_TYPE = Symbol.for('react.consumer'); +var REACT_CONTEXT_TYPE = Symbol.for('react.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_OFFSCREEN_TYPE = Symbol.for('react.offscreen'); +var MAYBE_ITERATOR_SYMBOL = Symbol.iterator; +var FAUX_ITERATOR_SYMBOL = '@@iterator'; +function getIteratorFn(maybeIterable) { + if (maybeIterable === null || typeof maybeIterable !== 'object') { + return null; + } + + var maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]; + + if (typeof maybeIterator === 'function') { + return maybeIterator; + } + + return null; +} - var maybeIterator = - (MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL]) || - maybeIterable[FAUX_ITERATOR_SYMBOL]; +var ReactSharedInternals = React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE; - if (typeof maybeIterator === "function") { - return maybeIterator; +function error(format) { + { + { + for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { + args[_key2 - 1] = arguments[_key2]; } - return null; + printWarning('error', format, args); } + } +} - var ReactSharedInternals = - React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE; +function printWarning(level, format, args) { + // When changing this logic, you might want to also + // update consoleWithStackDev.www.js as well. + { + var stack = ReactSharedInternals.getStackAddendum(); - function error(format) { - { - { - for ( - var _len2 = arguments.length, - args = new Array(_len2 > 1 ? _len2 - 1 : 0), - _key2 = 1; - _key2 < _len2; - _key2++ - ) { - args[_key2 - 1] = arguments[_key2]; - } + if (stack !== '') { + format += '%s'; + args = args.concat([stack]); + } // eslint-disable-next-line react-internal/safe-string-coercion - printWarning("error", format, args); - } - } - } - function printWarning(level, format, args) { - // When changing this logic, you might want to also - // update consoleWithStackDev.www.js as well. - { - var stack = ReactSharedInternals.getStackAddendum(); + var argsWithFormat = args.map(function (item) { + return String(item); + }); // Careful: RN currently depends on this prefix - if (stack !== "") { - format += "%s"; - args = args.concat([stack]); - } // eslint-disable-next-line react-internal/safe-string-coercion + argsWithFormat.unshift('Warning: ' + format); // We intentionally don't use spread (or .apply) directly because it + // breaks IE9: https://github.com/facebook/react/issues/13610 + // eslint-disable-next-line react-internal/no-production-logging - var argsWithFormat = args.map(function (item) { - return String(item); - }); // Careful: RN currently depends on this prefix + Function.prototype.apply.call(console[level], console, argsWithFormat); + } +} - argsWithFormat.unshift("Warning: " + format); // We intentionally don't use spread (or .apply) directly because it - // breaks IE9: https://github.com/facebook/react/issues/13610 - // eslint-disable-next-line react-internal/no-production-logging +// Re-export dynamic flags from the internal module. +var dynamicFlags = dynamicFlagsUntyped; // We destructure each value before re-exporting to avoid a dynamic look-up on +// the exports object every time a flag is read. - Function.prototype.apply.call(console[level], console, argsWithFormat); - } - } +var enableComponentStackLocations = dynamicFlags.enableComponentStackLocations, + enableRenderableContext = dynamicFlags.enableRenderableContext, + disableDefaultPropsExceptForClasses = dynamicFlags.disableDefaultPropsExceptForClasses; // The rest of the flags are static for better dead code elimination. +var enableDebugTracing = false; +var enableScopeAPI = false; +var enableLegacyHidden = false; +var enableTransitionTracing = false; - // Re-export dynamic flags from the internal module. - var dynamicFlags = dynamicFlagsUntyped; // We destructure each value before re-exporting to avoid a dynamic look-up on - // the exports object every time a flag is read. - - var enableComponentStackLocations = - dynamicFlags.enableComponentStackLocations, - enableRenderableContext = dynamicFlags.enableRenderableContext, - disableDefaultPropsExceptForClasses = - dynamicFlags.disableDefaultPropsExceptForClasses; // The rest of the flags are static for better dead code elimination. - var enableDebugTracing = false; - var enableScopeAPI = false; - var enableLegacyHidden = false; - var enableTransitionTracing = false; - - function getWrappedName$1(outerType, innerType, wrapperName) { - var displayName = outerType.displayName; - - if (displayName) { - return displayName; - } +function getWrappedName$1(outerType, innerType, wrapperName) { + var displayName = outerType.displayName; - var functionName = innerType.displayName || innerType.name || ""; - return functionName !== "" - ? wrapperName + "(" + functionName + ")" - : wrapperName; - } // Keep in sync with react-reconciler/getComponentNameFromFiber + if (displayName) { + return displayName; + } - function getContextName$1(type) { - return type.displayName || "Context"; - } + var functionName = innerType.displayName || innerType.name || ''; + return functionName !== '' ? wrapperName + "(" + functionName + ")" : wrapperName; +} // Keep in sync with react-reconciler/getComponentNameFromFiber - var REACT_CLIENT_REFERENCE$2 = Symbol.for("react.client.reference"); // 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; - } +function getContextName$1(type) { + return type.displayName || 'Context'; +} - if (typeof type === "function") { - if (type.$$typeof === REACT_CLIENT_REFERENCE$2) { - // TODO: Create a convention for naming client references with debug info. - return null; - } +var REACT_CLIENT_REFERENCE$2 = Symbol.for('react.client.reference'); // Note that the reconciler package should generally prefer to use getComponentNameFromFiber() instead. - return type.displayName || type.name || null; - } +function getComponentNameFromType(type) { + if (type == null) { + // Host root, text node or just invalid type. + return null; + } - if (typeof type === "string") { - return type; - } + if (typeof type === 'function') { + if (type.$$typeof === REACT_CLIENT_REFERENCE$2) { + // TODO: Create a convention for naming client references with debug info. + return null; + } - switch (type) { - case REACT_FRAGMENT_TYPE: - return "Fragment"; + return type.displayName || type.name || null; + } - case REACT_PORTAL_TYPE: - return "Portal"; + if (typeof type === 'string') { + return type; + } - case REACT_PROFILER_TYPE: - return "Profiler"; + switch (type) { + case REACT_FRAGMENT_TYPE: + return 'Fragment'; - case REACT_STRICT_MODE_TYPE: - return "StrictMode"; + case REACT_PORTAL_TYPE: + return 'Portal'; - case REACT_SUSPENSE_TYPE: - return "Suspense"; + case REACT_PROFILER_TYPE: + return 'Profiler'; - case REACT_SUSPENSE_LIST_TYPE: - return "SuspenseList"; + case REACT_STRICT_MODE_TYPE: + return 'StrictMode'; + + case REACT_SUSPENSE_TYPE: + return 'Suspense'; + + case REACT_SUSPENSE_LIST_TYPE: + return 'SuspenseList'; + + } + + if (typeof type === 'object') { + { + if (typeof type.tag === 'number') { + error('Received an unexpected object in getComponentNameFromType(). ' + 'This is likely a bug in React. Please file an issue.'); } + } - if (typeof type === "object") { - { - if (typeof type.tag === "number") { - error( - "Received an unexpected object in getComponentNameFromType(). " + - "This is likely a bug in React. Please file an issue." - ); - } + switch (type.$$typeof) { + case REACT_PROVIDER_TYPE: + if (enableRenderableContext) { + return null; + } else { + var provider = type; + return getContextName$1(provider._context) + '.Provider'; } - switch (type.$$typeof) { - case REACT_PROVIDER_TYPE: - if (enableRenderableContext) { - return null; - } else { - var provider = type; - return getContextName$1(provider._context) + ".Provider"; - } + case REACT_CONTEXT_TYPE: + var context = type; - case REACT_CONTEXT_TYPE: - var context = type; - - if (enableRenderableContext) { - return getContextName$1(context) + ".Provider"; - } else { - return getContextName$1(context) + ".Consumer"; - } + if (enableRenderableContext) { + return getContextName$1(context) + '.Provider'; + } else { + return getContextName$1(context) + '.Consumer'; + } - case REACT_CONSUMER_TYPE: - if (enableRenderableContext) { - var consumer = type; - return getContextName$1(consumer._context) + ".Consumer"; - } else { - return null; - } + case REACT_CONSUMER_TYPE: + if (enableRenderableContext) { + var consumer = type; + return getContextName$1(consumer._context) + '.Consumer'; + } else { + return null; + } - case REACT_FORWARD_REF_TYPE: - return getWrappedName$1(type, type.render, "ForwardRef"); + case REACT_FORWARD_REF_TYPE: + return getWrappedName$1(type, type.render, 'ForwardRef'); - case REACT_MEMO_TYPE: - var outerName = type.displayName || null; + case REACT_MEMO_TYPE: + var outerName = type.displayName || null; - if (outerName !== null) { - return outerName; - } + if (outerName !== null) { + return outerName; + } - return getComponentNameFromType(type.type) || "Memo"; + return getComponentNameFromType(type.type) || 'Memo'; - case REACT_LAZY_TYPE: { - var lazyComponent = type; - var payload = lazyComponent._payload; - var init = lazyComponent._init; + case REACT_LAZY_TYPE: + { + var lazyComponent = type; + var payload = lazyComponent._payload; + var init = lazyComponent._init; - try { - return getComponentNameFromType(init(payload)); - } catch (x) { - return null; - } + try { + return getComponentNameFromType(init(payload)); + } catch (x) { + return null; } } - } - - return null; } + } - // $FlowFixMe[method-unbinding] - var hasOwnProperty = Object.prototype.hasOwnProperty; - - var assign = Object.assign; - - /* - * 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[incompatible-return] 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[incompatible-return] + return null; +} - return type; - } - } // $FlowFixMe[incompatible-return] only called in DEV, so void return is not possible. +// $FlowFixMe[method-unbinding] +var hasOwnProperty = Object.prototype.hasOwnProperty; - function willCoercionThrow(value) { - { - try { - testStringCoercion(value); - return false; - } catch (e) { - return true; - } - } - } +var assign = Object.assign; - 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; +/* + * 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[incompatible-return] 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[incompatible-return] + + return type; + } +} // $FlowFixMe[incompatible-return] only called in DEV, so void return is not possible. + + +function willCoercionThrow(value) { + { + try { + testStringCoercion(value); + return false; + } catch (e) { + return true; } - function checkKeyStringCoercion(value) { - { - if (willCoercionThrow(value)) { - error( - "The provided key is an unsupported type %s." + - " This value must be coerced to a string before using it here.", - typeName(value) - ); - - return testStringCoercion(value); // throw (to help callers find troubleshooting comments) - } - } + } +} + +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 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 using it here.", - propName, - 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 using it here.', propName, typeName(value)); + + return testStringCoercion(value); // throw (to help callers find troubleshooting comments) } + } +} - var REACT_CLIENT_REFERENCE$1 = Symbol.for("react.client.reference"); - function isValidElementType(type) { - if (typeof type === "string" || typeof type === "function") { - return true; - } // Note: typeof might be other than 'symbol' or 'number' (e.g. if it's a polyfill). - - if ( - type === REACT_FRAGMENT_TYPE || - type === REACT_PROFILER_TYPE || - enableDebugTracing || - type === REACT_STRICT_MODE_TYPE || - type === REACT_SUSPENSE_TYPE || - type === REACT_SUSPENSE_LIST_TYPE || - enableLegacyHidden || - type === REACT_OFFSCREEN_TYPE || - enableScopeAPI || - enableTransitionTracing - ) { - return true; - } +var REACT_CLIENT_REFERENCE$1 = Symbol.for('react.client.reference'); +function isValidElementType(type) { + if (typeof type === 'string' || typeof type === 'function') { + return true; + } // Note: typeof might be other than 'symbol' or 'number' (e.g. if it's a polyfill). - if (typeof type === "object" && type !== null) { - if ( - type.$$typeof === REACT_LAZY_TYPE || - type.$$typeof === REACT_MEMO_TYPE || - type.$$typeof === REACT_CONTEXT_TYPE || - (!enableRenderableContext && type.$$typeof === REACT_PROVIDER_TYPE) || - (enableRenderableContext && type.$$typeof === REACT_CONSUMER_TYPE) || - type.$$typeof === REACT_FORWARD_REF_TYPE || // This needs to include all possible module reference object - // types supported by any Flight configuration anywhere since - // we don't know which Flight build this will end up being used - // with. - type.$$typeof === REACT_CLIENT_REFERENCE$1 || - type.getModuleId !== undefined - ) { - return true; - } - } - return false; + if (type === REACT_FRAGMENT_TYPE || type === REACT_PROFILER_TYPE || enableDebugTracing || type === REACT_STRICT_MODE_TYPE || type === REACT_SUSPENSE_TYPE || type === REACT_SUSPENSE_LIST_TYPE || enableLegacyHidden || type === REACT_OFFSCREEN_TYPE || enableScopeAPI || enableTransitionTracing ) { + return true; + } + + if (typeof type === 'object' && type !== null) { + if (type.$$typeof === REACT_LAZY_TYPE || type.$$typeof === REACT_MEMO_TYPE || type.$$typeof === REACT_CONTEXT_TYPE || !enableRenderableContext && type.$$typeof === REACT_PROVIDER_TYPE || enableRenderableContext && type.$$typeof === REACT_CONSUMER_TYPE || type.$$typeof === REACT_FORWARD_REF_TYPE || // This needs to include all possible module reference object + // types supported by any Flight configuration anywhere since + // we don't know which Flight build this will end up being used + // with. + type.$$typeof === REACT_CLIENT_REFERENCE$1 || type.getModuleId !== undefined) { + return true; } + } - var isArrayImpl = Array.isArray; // eslint-disable-next-line no-redeclare + return false; +} - function isArray(a) { - return isArrayImpl(a); - } +var isArrayImpl = Array.isArray; // eslint-disable-next-line no-redeclare - // 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[cannot-write] 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 */ - } +function isArray(a) { + return isArrayImpl(a); +} - disabledDepth++; - } +// 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[cannot-write] 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 */ } - function reenableLogs() { - { - disabledDepth--; - - if (disabledDepth === 0) { - /* eslint-disable react-internal/no-production-logging */ - var props = { - configurable: true, - enumerable: true, - writable: true - }; // $FlowFixMe[cannot-write] 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." - ); - } - } + disabledDepth++; + } +} +function reenableLogs() { + { + disabledDepth--; + + if (disabledDepth === 0) { + /* eslint-disable react-internal/no-production-logging */ + var props = { + configurable: true, + enumerable: true, + writable: true + }; // $FlowFixMe[cannot-write] 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 */ } - var prefix; - function describeBuiltInComponentFrame(name) { - if (enableComponentStackLocations) { - if (prefix === undefined) { - // Extract the VM specific prefix used by each line. - try { - throw Error(); - } catch (x) { - var match = x.stack.trim().match(/\n( *(at )?)/); - prefix = (match && match[1]) || ""; - } - } // We use the prefix to ensure our stacks line up with native stack frames. - - return "\n" + prefix + name; - } else { - return describeComponentFrame(name); - } + if (disabledDepth < 0) { + error('disabledDepth fell below zero. ' + 'This is a bug in React. Please file an issue.'); } - var reentry = false; - var componentFrameCache; + } +} - { - var PossiblyWeakMap = typeof WeakMap === "function" ? WeakMap : Map; - componentFrameCache = new PossiblyWeakMap(); - } - /** - * Leverages native browser/VM stack frames to get proper details (e.g. - * filename, line + col number) for a single component in a component stack. We - * do this by: - * (1) throwing and catching an error in the function - this will be our - * control error. - * (2) calling the component which will eventually throw an error that we'll - * catch - this will be our sample error. - * (3) diffing the control and sample error stacks to find the stack frame - * which represents our component. - */ - - function describeNativeComponentFrame(fn, construct) { - // If something asked for a stack inside a fake render, it should get ignored. - if (!fn || reentry) { - return ""; +var prefix; +function describeBuiltInComponentFrame(name) { + if (enableComponentStackLocations) { + if (prefix === undefined) { + // Extract the VM specific prefix used by each line. + try { + throw Error(); + } catch (x) { + var match = x.stack.trim().match(/\n( *(at )?)/); + prefix = match && match[1] || ''; } + } // We use the prefix to ensure our stacks line up with native stack frames. - { - var frame = componentFrameCache.get(fn); - if (frame !== undefined) { - return frame; - } - } + return '\n' + prefix + name; + } else { + return describeComponentFrame(name); + } +} +var reentry = false; +var componentFrameCache; - reentry = true; - var previousPrepareStackTrace = Error.prepareStackTrace; // $FlowFixMe[incompatible-type] It does accept undefined. +{ + var PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map; + componentFrameCache = new PossiblyWeakMap(); +} +/** + * Leverages native browser/VM stack frames to get proper details (e.g. + * filename, line + col number) for a single component in a component stack. We + * do this by: + * (1) throwing and catching an error in the function - this will be our + * control error. + * (2) calling the component which will eventually throw an error that we'll + * catch - this will be our sample error. + * (3) diffing the control and sample error stacks to find the stack frame + * which represents our component. + */ - Error.prepareStackTrace = undefined; - var previousDispatcher = null; - { - previousDispatcher = ReactSharedInternals.H; // Set the dispatcher in DEV because this might be call in the render function - // for warnings. +function describeNativeComponentFrame(fn, construct) { + // If something asked for a stack inside a fake render, it should get ignored. + if (!fn || reentry) { + return ''; + } - ReactSharedInternals.H = null; - disableLogs(); - } - /** - * Finding a common stack frame between sample and control errors can be - * tricky given the different types and levels of stack trace truncation from - * different JS VMs. So instead we'll attempt to control what that common - * frame should be through this object method: - * Having both the sample and control errors be in the function under the - * `DescribeNativeComponentFrameRoot` property, + setting the `name` and - * `displayName` properties of the function ensures that a stack - * frame exists that has the method name `DescribeNativeComponentFrameRoot` in - * it for both control and sample stacks. - */ - - var RunInRootFrame = { - DetermineComponentFrameRoot: function () { - var control; + { + var frame = componentFrameCache.get(fn); - try { - // This should throw. - if (construct) { - // Something should be setting the props in the constructor. - var Fake = function () { - throw Error(); - }; // $FlowFixMe[prop-missing] - - Object.defineProperty(Fake.prototype, "props", { - set: function () { - // We use a throwing setter instead of frozen or non-writable props - // because that won't throw in a non-strict mode function. - throw Error(); - } - }); - - if (typeof Reflect === "object" && Reflect.construct) { - // We construct a different control for this case to include any extra - // frames added by the construct call. - try { - Reflect.construct(Fake, []); - } catch (x) { - control = x; - } + if (frame !== undefined) { + return frame; + } + } + + reentry = true; + var previousPrepareStackTrace = Error.prepareStackTrace; // $FlowFixMe[incompatible-type] It does accept undefined. + + Error.prepareStackTrace = undefined; + var previousDispatcher = null; + + { + previousDispatcher = ReactSharedInternals.H; // Set the dispatcher in DEV because this might be call in the render function + // for warnings. + + ReactSharedInternals.H = null; + disableLogs(); + } + /** + * Finding a common stack frame between sample and control errors can be + * tricky given the different types and levels of stack trace truncation from + * different JS VMs. So instead we'll attempt to control what that common + * frame should be through this object method: + * Having both the sample and control errors be in the function under the + * `DescribeNativeComponentFrameRoot` property, + setting the `name` and + * `displayName` properties of the function ensures that a stack + * frame exists that has the method name `DescribeNativeComponentFrameRoot` in + * it for both control and sample stacks. + */ + + + var RunInRootFrame = { + DetermineComponentFrameRoot: function () { + var control; - Reflect.construct(fn, [], Fake); - } else { - try { - Fake.call(); - } catch (x) { - control = x; - } // $FlowFixMe[prop-missing] found when upgrading Flow + try { + // This should throw. + if (construct) { + // Something should be setting the props in the constructor. + var Fake = function () { + throw Error(); + }; // $FlowFixMe[prop-missing] - fn.call(Fake.prototype); - } - } else { - try { - throw Error(); - } catch (x) { - control = x; - } // TODO(luna): This will currently only throw if the function component - // tries to access React/ReactDOM/props. We should probably make this throw - // in simple components too - - var maybePromise = fn(); // If the function component returns a promise, it's likely an async - // component, which we don't yet support. Attach a noop catch handler to - // silence the error. - // TODO: Implement component stacks for async client components? - - if (maybePromise && typeof maybePromise.catch === "function") { - maybePromise.catch(function () {}); - } + + Object.defineProperty(Fake.prototype, 'props', { + set: function () { + // We use a throwing setter instead of frozen or non-writable props + // because that won't throw in a non-strict mode function. + throw Error(); } - } catch (sample) { - // This is inlined manually because closure doesn't do it for us. - if (sample && control && typeof sample.stack === "string") { - return [sample.stack, control.stack]; + }); + + if (typeof Reflect === 'object' && Reflect.construct) { + // We construct a different control for this case to include any extra + // frames added by the construct call. + try { + Reflect.construct(Fake, []); + } catch (x) { + control = x; } - } - return [null, null]; - } - }; // $FlowFixMe[prop-missing] - - RunInRootFrame.DetermineComponentFrameRoot.displayName = - "DetermineComponentFrameRoot"; - var namePropDescriptor = Object.getOwnPropertyDescriptor( - RunInRootFrame.DetermineComponentFrameRoot, - "name" - ); // Before ES6, the `name` property was not configurable. - - if (namePropDescriptor && namePropDescriptor.configurable) { - // V8 utilizes a function's `name` property when generating a stack trace. - Object.defineProperty( - RunInRootFrame.DetermineComponentFrameRoot, // Configurable properties can be updated even if its writable descriptor - // is set to `false`. - // $FlowFixMe[cannot-write] - "name", - { - value: "DetermineComponentFrameRoot" - } - ); - } + Reflect.construct(fn, [], Fake); + } else { + try { + Fake.call(); + } catch (x) { + control = x; + } // $FlowFixMe[prop-missing] found when upgrading Flow - try { - var _RunInRootFrame$Deter = - RunInRootFrame.DetermineComponentFrameRoot(), - sampleStack = _RunInRootFrame$Deter[0], - controlStack = _RunInRootFrame$Deter[1]; - - if (sampleStack && controlStack) { - // This extracts the first frame from the sample that isn't also in the control. - // Skipping one frame that we assume is the frame that calls the two. - var sampleLines = sampleStack.split("\n"); - var controlLines = controlStack.split("\n"); - var s = 0; - var c = 0; - - while ( - s < sampleLines.length && - !sampleLines[s].includes("DetermineComponentFrameRoot") - ) { - s++; - } - while ( - c < controlLines.length && - !controlLines[c].includes("DetermineComponentFrameRoot") - ) { - c++; - } // We couldn't find our intentionally injected common root frame, attempt - // to find another common root frame by search from the bottom of the - // control stack... - - if (s === sampleLines.length || c === controlLines.length) { - s = sampleLines.length - 1; - c = controlLines.length - 1; - - while (s >= 1 && c >= 0 && sampleLines[s] !== controlLines[c]) { - // We expect at least one stack frame to be shared. - // Typically this will be the root most one. However, stack frames may be - // cut off due to maximum stack limits. In this case, one maybe cut off - // earlier than the other. We assume that the sample is longer or the same - // and there for cut off earlier. So we should find the root most frame in - // the sample somewhere in the control. - c--; - } + fn.call(Fake.prototype); } + } else { + try { + throw Error(); + } catch (x) { + control = x; + } // TODO(luna): This will currently only throw if the function component + // tries to access React/ReactDOM/props. We should probably make this throw + // in simple components too - for (; s >= 1 && c >= 0; s--, c--) { - // Next we find the first one that isn't the same which should be the - // frame that called our sample function and the control. - if (sampleLines[s] !== controlLines[c]) { - // In V8, the first line is describing the message but other VMs don't. - // If we're about to return the first line, and the control is also on the same - // line, that's a pretty good indicator that our sample threw at same line as - // the control. I.e. before we entered the sample frame. So we ignore this result. - // This can happen if you passed a class to function component, or non-function. - if (s !== 1 || c !== 1) { - do { - s--; - c--; // We may still have similar intermediate frames from the construct call. - // The next one that isn't the same should be our match though. - - if (c < 0 || sampleLines[s] !== controlLines[c]) { - // V8 adds a "new" prefix for native classes. Let's remove it to make it prettier. - var _frame = - "\n" + sampleLines[s].replace(" at new ", " at "); // If our component frame is labeled "" - // but we have a user-provided "displayName" - // splice it in to make the stack more readable. - - if (fn.displayName && _frame.includes("")) { - _frame = _frame.replace("", fn.displayName); - } - - if (true) { - if (typeof fn === "function") { - componentFrameCache.set(fn, _frame); - } - } // Return the line we found. - - return _frame; - } - } while (s >= 1 && c >= 0); - } - break; - } + var maybePromise = fn(); // If the function component returns a promise, it's likely an async + // component, which we don't yet support. Attach a noop catch handler to + // silence the error. + // TODO: Implement component stacks for async client components? + + if (maybePromise && typeof maybePromise.catch === 'function') { + maybePromise.catch(function () {}); } } - } finally { - reentry = false; + } catch (sample) { + // This is inlined manually because closure doesn't do it for us. + if (sample && control && typeof sample.stack === 'string') { + return [sample.stack, control.stack]; + } + } - { - ReactSharedInternals.H = previousDispatcher; - reenableLogs(); + return [null, null]; + } + }; // $FlowFixMe[prop-missing] + + RunInRootFrame.DetermineComponentFrameRoot.displayName = 'DetermineComponentFrameRoot'; + var namePropDescriptor = Object.getOwnPropertyDescriptor(RunInRootFrame.DetermineComponentFrameRoot, 'name'); // Before ES6, the `name` property was not configurable. + + if (namePropDescriptor && namePropDescriptor.configurable) { + // V8 utilizes a function's `name` property when generating a stack trace. + Object.defineProperty(RunInRootFrame.DetermineComponentFrameRoot, // Configurable properties can be updated even if its writable descriptor + // is set to `false`. + // $FlowFixMe[cannot-write] + 'name', { + value: 'DetermineComponentFrameRoot' + }); + } + + try { + var _RunInRootFrame$Deter = RunInRootFrame.DetermineComponentFrameRoot(), + sampleStack = _RunInRootFrame$Deter[0], + controlStack = _RunInRootFrame$Deter[1]; + + if (sampleStack && controlStack) { + // This extracts the first frame from the sample that isn't also in the control. + // Skipping one frame that we assume is the frame that calls the two. + var sampleLines = sampleStack.split('\n'); + var controlLines = controlStack.split('\n'); + var s = 0; + var c = 0; + + while (s < sampleLines.length && !sampleLines[s].includes('DetermineComponentFrameRoot')) { + s++; + } + + while (c < controlLines.length && !controlLines[c].includes('DetermineComponentFrameRoot')) { + c++; + } // We couldn't find our intentionally injected common root frame, attempt + // to find another common root frame by search from the bottom of the + // control stack... + + + if (s === sampleLines.length || c === controlLines.length) { + s = sampleLines.length - 1; + c = controlLines.length - 1; + + while (s >= 1 && c >= 0 && sampleLines[s] !== controlLines[c]) { + // We expect at least one stack frame to be shared. + // Typically this will be the root most one. However, stack frames may be + // cut off due to maximum stack limits. In this case, one maybe cut off + // earlier than the other. We assume that the sample is longer or the same + // and there for cut off earlier. So we should find the root most frame in + // the sample somewhere in the control. + c--; } + } - Error.prepareStackTrace = previousPrepareStackTrace; - } // Fallback to just using the name if we couldn't make it throw. + for (; s >= 1 && c >= 0; s--, c--) { + // Next we find the first one that isn't the same which should be the + // frame that called our sample function and the control. + if (sampleLines[s] !== controlLines[c]) { + // In V8, the first line is describing the message but other VMs don't. + // If we're about to return the first line, and the control is also on the same + // line, that's a pretty good indicator that our sample threw at same line as + // the control. I.e. before we entered the sample frame. So we ignore this result. + // This can happen if you passed a class to function component, or non-function. + if (s !== 1 || c !== 1) { + do { + s--; + c--; // We may still have similar intermediate frames from the construct call. + // The next one that isn't the same should be our match though. + + if (c < 0 || sampleLines[s] !== controlLines[c]) { + // V8 adds a "new" prefix for native classes. Let's remove it to make it prettier. + var _frame = '\n' + sampleLines[s].replace(' at new ', ' at '); // If our component frame is labeled "" + // but we have a user-provided "displayName" + // splice it in to make the stack more readable. + + + if (fn.displayName && _frame.includes('')) { + _frame = _frame.replace('', fn.displayName); + } + + if (true) { + if (typeof fn === 'function') { + componentFrameCache.set(fn, _frame); + } + } // Return the line we found. - var name = fn ? fn.displayName || fn.name : ""; - var syntheticFrame = name ? describeBuiltInComponentFrame(name) : ""; - { - if (typeof fn === "function") { - componentFrameCache.set(fn, syntheticFrame); + return _frame; + } + } while (s >= 1 && c >= 0); + } + + break; } } + } + } finally { + reentry = false; - return syntheticFrame; + { + ReactSharedInternals.H = previousDispatcher; + reenableLogs(); } - function describeComponentFrame(name) { - return "\n in " + (name || "Unknown"); + Error.prepareStackTrace = previousPrepareStackTrace; + } // Fallback to just using the name if we couldn't make it throw. + + + var name = fn ? fn.displayName || fn.name : ''; + var syntheticFrame = name ? describeBuiltInComponentFrame(name) : ''; + + { + if (typeof fn === 'function') { + componentFrameCache.set(fn, syntheticFrame); } - function describeFunctionComponentFrame(fn) { - if (enableComponentStackLocations) { - return describeNativeComponentFrame(fn, false); - } else { - if (!fn) { - return ""; - } + } - var name = fn.displayName || fn.name || null; - return describeComponentFrame(name); - } + return syntheticFrame; +} + +function describeComponentFrame(name) { + return '\n in ' + (name || 'Unknown'); +} +function describeFunctionComponentFrame(fn) { + if (enableComponentStackLocations) { + return describeNativeComponentFrame(fn, false); + } else { + if (!fn) { + return ''; } - function shouldConstruct(Component) { - var prototype = Component.prototype; - return !!(prototype && prototype.isReactComponent); + var name = fn.displayName || fn.name || null; + return describeComponentFrame(name); + } +} + +function shouldConstruct(Component) { + var prototype = Component.prototype; + return !!(prototype && prototype.isReactComponent); +} + +function describeUnknownElementTypeFrameInDEV(type) { + + if (type == null) { + return ''; + } + + if (typeof type === 'function') { + if (enableComponentStackLocations) { + return describeNativeComponentFrame(type, shouldConstruct(type)); + } else { + return describeFunctionComponentFrame(type); } + } - function describeUnknownElementTypeFrameInDEV(type) { - if (type == null) { - return ""; - } + if (typeof type === 'string') { + return describeBuiltInComponentFrame(type); + } - if (typeof type === "function") { - if (enableComponentStackLocations) { - return describeNativeComponentFrame(type, shouldConstruct(type)); - } else { - return describeFunctionComponentFrame(type); + switch (type) { + case REACT_SUSPENSE_TYPE: + return describeBuiltInComponentFrame('Suspense'); + + case REACT_SUSPENSE_LIST_TYPE: + return describeBuiltInComponentFrame('SuspenseList'); + } + + if (typeof type === 'object') { + switch (type.$$typeof) { + case REACT_FORWARD_REF_TYPE: + return describeFunctionComponentFrame(type.render); + + case REACT_MEMO_TYPE: + // Memo may contain any component type so we recursively resolve it. + return describeUnknownElementTypeFrameInDEV(type.type); + + 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)); + } catch (x) {} } + } + } + + return ''; +} + +var FunctionComponent = 0; +var ClassComponent = 1; +var HostRoot = 3; // Root of a host tree. Could be nested inside another node. + +var HostPortal = 4; // A subtree. Could be an entry point to a different renderer. + +var HostComponent = 5; +var HostText = 6; +var Fragment = 7; +var Mode = 8; +var ContextConsumer = 9; +var ContextProvider = 10; +var ForwardRef = 11; +var Profiler = 12; +var SuspenseComponent = 13; +var MemoComponent = 14; +var SimpleMemoComponent = 15; +var LazyComponent = 16; +var IncompleteClassComponent = 17; +var DehydratedFragment = 18; +var SuspenseListComponent = 19; +var ScopeComponent = 21; +var OffscreenComponent = 22; +var CacheComponent = 24; +var TracingMarkerComponent = 25; +var HostHoistable = 26; +var HostSingleton = 27; +var IncompleteFunctionComponent = 28; + +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'; +} +function getComponentNameFromFiber(fiber) { + var tag = fiber.tag, + type = fiber.type; + + switch (tag) { + case CacheComponent: + return 'Cache'; + + case ContextConsumer: + if (enableRenderableContext) { + var consumer = type; + return getContextName(consumer._context) + '.Consumer'; + } else { + var context = type; + return getContextName(context) + '.Consumer'; } - if (typeof type === "string") { - return describeBuiltInComponentFrame(type); + case ContextProvider: + if (enableRenderableContext) { + var _context = type; + return getContextName(_context) + '.Provider'; + } else { + var provider = type; + return getContextName(provider._context) + '.Provider'; } - switch (type) { - case REACT_SUSPENSE_TYPE: - return describeBuiltInComponentFrame("Suspense"); + case DehydratedFragment: + return 'DehydratedFragment'; - case REACT_SUSPENSE_LIST_TYPE: - return describeBuiltInComponentFrame("SuspenseList"); - } + case ForwardRef: + return getWrappedName(type, type.render, 'ForwardRef'); - if (typeof type === "object") { - switch (type.$$typeof) { - case REACT_FORWARD_REF_TYPE: - return describeFunctionComponentFrame(type.render); + case Fragment: + return 'Fragment'; - case REACT_MEMO_TYPE: - // Memo may contain any component type so we recursively resolve it. - return describeUnknownElementTypeFrameInDEV(type.type); + case HostHoistable: + case HostSingleton: + case HostComponent: + // Host component type is the display name (e.g. "div", "View") + return type; - case REACT_LAZY_TYPE: { - var lazyComponent = type; - var payload = lazyComponent._payload; - var init = lazyComponent._init; + case HostPortal: + return 'Portal'; - try { - // Lazy may contain any component type so we recursively resolve it. - return describeUnknownElementTypeFrameInDEV(init(payload)); - } catch (x) {} - } - } - } + case HostRoot: + return 'Root'; - return ""; - } + case HostText: + return 'Text'; - var FunctionComponent = 0; - var ClassComponent = 1; - var HostRoot = 3; // Root of a host tree. Could be nested inside another node. - - var HostPortal = 4; // A subtree. Could be an entry point to a different renderer. - - var HostComponent = 5; - var HostText = 6; - var Fragment = 7; - var Mode = 8; - var ContextConsumer = 9; - var ContextProvider = 10; - var ForwardRef = 11; - var Profiler = 12; - var SuspenseComponent = 13; - var MemoComponent = 14; - var SimpleMemoComponent = 15; - var LazyComponent = 16; - var IncompleteClassComponent = 17; - var DehydratedFragment = 18; - var SuspenseListComponent = 19; - var ScopeComponent = 21; - var OffscreenComponent = 22; - var CacheComponent = 24; - var TracingMarkerComponent = 25; - var HostHoistable = 26; - var HostSingleton = 27; - var IncompleteFunctionComponent = 28; - - 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"; - } - function getComponentNameFromFiber(fiber) { - var tag = fiber.tag, - type = fiber.type; - - switch (tag) { - case CacheComponent: - return "Cache"; - - case ContextConsumer: - if (enableRenderableContext) { - var consumer = type; - return getContextName(consumer._context) + ".Consumer"; - } else { - var context = type; - return getContextName(context) + ".Consumer"; - } + case LazyComponent: + // Name comes from the type in this case; we don't have a tag. + return getComponentNameFromType(type); - case ContextProvider: - if (enableRenderableContext) { - var _context = type; - return getContextName(_context) + ".Provider"; - } else { - var provider = type; - return getContextName(provider._context) + ".Provider"; - } + case Mode: + if (type === REACT_STRICT_MODE_TYPE) { + // Don't be less specific than shared/getComponentNameFromType + return 'StrictMode'; + } - case DehydratedFragment: - return "DehydratedFragment"; + return 'Mode'; - case ForwardRef: - return getWrappedName(type, type.render, "ForwardRef"); + case OffscreenComponent: + return 'Offscreen'; - case Fragment: - return "Fragment"; + case Profiler: + return 'Profiler'; - case HostHoistable: - case HostSingleton: - case HostComponent: - // Host component type is the display name (e.g. "div", "View") - return type; + case ScopeComponent: + return 'Scope'; - case HostPortal: - return "Portal"; + case SuspenseComponent: + return 'Suspense'; - case HostRoot: - return "Root"; + case SuspenseListComponent: + return 'SuspenseList'; - case HostText: - return "Text"; + case TracingMarkerComponent: + return 'TracingMarker'; + // The display name for these tags come from the user-provided type: - case LazyComponent: - // Name comes from the type in this case; we don't have a tag. - return getComponentNameFromType(type); + case IncompleteClassComponent: + case IncompleteFunctionComponent: - case Mode: - if (type === REACT_STRICT_MODE_TYPE) { - // Don't be less specific than shared/getComponentNameFromType - return "StrictMode"; - } + // Fallthrough - return "Mode"; + case ClassComponent: + case FunctionComponent: + case MemoComponent: + case SimpleMemoComponent: + if (typeof type === 'function') { + return type.displayName || type.name || null; + } - case OffscreenComponent: - return "Offscreen"; + if (typeof type === 'string') { + return type; + } - case Profiler: - return "Profiler"; + break; - case ScopeComponent: - return "Scope"; + } - case SuspenseComponent: - return "Suspense"; + return null; +} - case SuspenseListComponent: - return "SuspenseList"; +var REACT_CLIENT_REFERENCE = Symbol.for('react.client.reference'); +var specialPropKeyWarningShown; +var specialPropRefWarningShown; +var didWarnAboutStringRefs; - case TracingMarkerComponent: - return "TracingMarker"; - // The display name for these tags come from the user-provided type: +{ + didWarnAboutStringRefs = {}; +} - case IncompleteClassComponent: - case IncompleteFunctionComponent: +function hasValidRef(config) { + { + if (hasOwnProperty.call(config, 'ref')) { + var getter = Object.getOwnPropertyDescriptor(config, 'ref').get; - // Fallthrough + if (getter && getter.isReactWarning) { + return false; + } + } + } - case ClassComponent: - case FunctionComponent: - case MemoComponent: - case SimpleMemoComponent: - if (typeof type === "function") { - return type.displayName || type.name || null; - } + return config.ref !== undefined; +} - if (typeof type === "string") { - return type; - } +function hasValidKey(config) { + { + if (hasOwnProperty.call(config, 'key')) { + var getter = Object.getOwnPropertyDescriptor(config, 'key').get; - break; + if (getter && getter.isReactWarning) { + return false; } - - return null; } + } - var REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference"); - var specialPropKeyWarningShown; - var specialPropRefWarningShown; - var didWarnAboutStringRefs; + return config.key !== undefined; +} - { - didWarnAboutStringRefs = {}; - } +function warnIfStringRefCannotBeAutoConverted(config, self) { + { + if (typeof config.ref === 'string' && ReactSharedInternals.owner && self && ReactSharedInternals.owner.stateNode !== self) { + var componentName = getComponentNameFromType(ReactSharedInternals.owner.type); - function hasValidRef(config) { - { - if (hasOwnProperty.call(config, "ref")) { - var getter = Object.getOwnPropertyDescriptor(config, "ref").get; + if (!didWarnAboutStringRefs[componentName]) { + error('Component "%s" contains the string ref "%s". ' + 'Support for string refs will be removed in a future major release. ' + 'This case cannot be automatically converted to an arrow function. ' + 'We ask you to manually fix this case by using useRef() or createRef() instead. ' + 'Learn more about using refs safely here: ' + 'https://react.dev/link/strict-mode-string-ref', getComponentNameFromType(ReactSharedInternals.owner.type), config.ref); - if (getter && getter.isReactWarning) { - return false; - } - } + didWarnAboutStringRefs[componentName] = true; } - - return config.ref !== undefined; } + } +} - function hasValidKey(config) { - { - if (hasOwnProperty.call(config, "key")) { - var getter = Object.getOwnPropertyDescriptor(config, "key").get; +function defineKeyPropWarningGetter(props, displayName) { + { + var warnAboutAccessingKey = function () { + if (!specialPropKeyWarningShown) { + specialPropKeyWarningShown = true; - if (getter && getter.isReactWarning) { - return false; - } - } + error('%s: `key` is not a prop. Trying to access it will result ' + 'in `undefined` being returned. If you need to access the same ' + 'value within the child component, you should pass it as a different ' + 'prop. (https://react.dev/link/special-props)', displayName); } + }; + + warnAboutAccessingKey.isReactWarning = true; + Object.defineProperty(props, 'key', { + get: warnAboutAccessingKey, + configurable: true + }); + } +} - return config.key !== undefined; - } +function defineRefPropWarningGetter(props, displayName) { + { + { + var warnAboutAccessingRef = function () { + if (!specialPropRefWarningShown) { + specialPropRefWarningShown = true; - function warnIfStringRefCannotBeAutoConverted(config, self) { - { - if ( - typeof config.ref === "string" && - ReactSharedInternals.owner && - self && - ReactSharedInternals.owner.stateNode !== self - ) { - var componentName = getComponentNameFromType( - ReactSharedInternals.owner.type - ); - - if (!didWarnAboutStringRefs[componentName]) { - error( - 'Component "%s" contains the string ref "%s". ' + - "Support for string refs will be removed in a future major release. " + - "This case cannot be automatically converted to an arrow function. " + - "We ask you to manually fix this case by using useRef() or createRef() instead. " + - "Learn more about using refs safely here: " + - "https://react.dev/link/strict-mode-string-ref", - getComponentNameFromType(ReactSharedInternals.owner.type), - config.ref - ); - - didWarnAboutStringRefs[componentName] = true; - } + error('%s: `ref` is not a prop. Trying to access it will result ' + 'in `undefined` being returned. If you need to access the same ' + 'value within the child component, you should pass it as a different ' + 'prop. (https://react.dev/link/special-props)', displayName); } - } + }; + + warnAboutAccessingRef.isReactWarning = true; + Object.defineProperty(props, 'ref', { + get: warnAboutAccessingRef, + configurable: true + }); } + } +} +/** + * Factory method to create a new React element. This no longer adheres to + * the class pattern, so do not use new to call it. Also, instanceof check + * will not work. Instead test $$typeof field against Symbol.for('react.element') to check + * if something is a React Element. + * + * @param {*} type + * @param {*} props + * @param {*} key + * @param {string|object} ref + * @param {*} owner + * @param {*} self A *temporary* helper to detect places where `this` is + * different from the `owner` when React.createElement is called, so that we + * can warn. We want to get rid of owner and replace string `ref`s with arrow + * functions, and as long as `this` and owner are the same, there will be no + * change in behavior. + * @param {*} source An annotation object (added by a transpiler or otherwise) + * indicating filename, line number, and/or other information. + * @internal + */ - function defineKeyPropWarningGetter(props, displayName) { - { - var warnAboutAccessingKey = function () { - if (!specialPropKeyWarningShown) { - specialPropKeyWarningShown = true; - - error( - "%s: `key` is not a prop. Trying to access it will result " + - "in `undefined` being returned. If you need to access the same " + - "value within the child component, you should pass it as a different " + - "prop. (https://react.dev/link/special-props)", - displayName - ); - } - }; - warnAboutAccessingKey.isReactWarning = true; - Object.defineProperty(props, "key", { - get: warnAboutAccessingKey, - configurable: true - }); - } +function ReactElement(type, key, _ref, self, source, owner, props) { + var ref; + + { + ref = _ref; + } + + var element; + + { + // In prod, `ref` is a regular property. It will be removed in a + // future release. + element = { + // This tag allows us to uniquely identify this as a React Element + $$typeof: REACT_ELEMENT_TYPE, + // Built-in properties that belong on the element + type: type, + key: key, + ref: ref, + props: props, + // Record the component responsible for creating this element. + _owner: owner + }; + } + + { + // The validation flag is currently mutative. We put it on + // an external backing store so that we can freeze the whole object. + // This can be replaced with a WeakMap once they are implemented in + // commonly used development environments. + element._store = {}; // To make comparing ReactElements easier for testing purposes, we make + // the validation flag non-enumerable (where possible, which should + // include every environment we run tests in), so the test framework + // ignores it. + + Object.defineProperty(element._store, 'validated', { + configurable: false, + enumerable: false, + writable: true, + value: false + }); // debugInfo contains Server Component debug information. + + Object.defineProperty(element, '_debugInfo', { + configurable: false, + enumerable: false, + writable: true, + value: null + }); + + if (Object.freeze) { + Object.freeze(element.props); + Object.freeze(element); } + } - function defineRefPropWarningGetter(props, displayName) { - { - { - var warnAboutAccessingRef = function () { - if (!specialPropRefWarningShown) { - specialPropRefWarningShown = true; - - error( - "%s: `ref` is not a prop. Trying to access it will result " + - "in `undefined` being returned. If you need to access the same " + - "value within the child component, you should pass it as a different " + - "prop. (https://react.dev/link/special-props)", - displayName - ); - } - }; + return element; +} +// support `jsx` and `jsxs` when running in development. This supports the case +// where a third-party dependency ships code that was compiled for production; +// we want to still provide warnings in development. +// +// So these functions are the _dev_ implementations of the _production_ +// API signatures. +// +// Since these functions are dev-only, it's ok to add an indirection here. They +// only exist to provide different versions of `isStaticChildren`. (We shouldn't +// use this pattern for the prod versions, though, because it will add an call +// frame.) + +function jsxProdSignatureRunningInDevWithDynamicChildren(type, config, maybeKey, source, self) { + { + var isStaticChildren = false; + return jsxDEV(type, config, maybeKey, isStaticChildren, source, self); + } +} +function jsxProdSignatureRunningInDevWithStaticChildren(type, config, maybeKey, source, self) { + { + var isStaticChildren = true; + return jsxDEV(type, config, maybeKey, isStaticChildren, source, self); + } +} +var didWarnAboutKeySpread = {}; +/** + * https://github.com/reactjs/rfcs/pull/107 + * @param {*} type + * @param {object} props + * @param {string} key + */ - warnAboutAccessingRef.isReactWarning = true; - Object.defineProperty(props, "ref", { - get: warnAboutAccessingRef, - configurable: true - }); - } - } - } - /** - * Factory method to create a new React element. This no longer adheres to - * the class pattern, so do not use new to call it. Also, instanceof check - * will not work. Instead test $$typeof field against Symbol.for('react.element') to check - * if something is a React Element. - * - * @param {*} type - * @param {*} props - * @param {*} key - * @param {string|object} ref - * @param {*} owner - * @param {*} self A *temporary* helper to detect places where `this` is - * different from the `owner` when React.createElement is called, so that we - * can warn. We want to get rid of owner and replace string `ref`s with arrow - * functions, and as long as `this` and owner are the same, there will be no - * change in behavior. - * @param {*} source An annotation object (added by a transpiler or otherwise) - * indicating filename, line number, and/or other information. - * @internal - */ - - function ReactElement(type, key, _ref, self, source, owner, props) { - var ref; +function jsxDEV(type, config, maybeKey, isStaticChildren, source, self) { + { + if (!isValidElementType(type)) { + // This is an invalid element type. + // + // We warn in this case but don't throw. We expect the element creation to + // succeed and there will likely be errors in render. + var info = ''; - { - ref = _ref; + 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 element; + var typeString; - { - // In prod, `ref` is a regular property. It will be removed in a - // future release. - element = { - // This tag allows us to uniquely identify this as a React Element - $$typeof: REACT_ELEMENT_TYPE, - // Built-in properties that belong on the element - type: type, - key: key, - ref: ref, - props: props, - // Record the component responsible for creating this element. - _owner: owner - }; + if (type === null) { + typeString = 'null'; + } else if (isArray(type)) { + typeString = 'array'; + } else if (type !== undefined && type.$$typeof === REACT_ELEMENT_TYPE) { + typeString = "<" + (getComponentNameFromType(type.type) || 'Unknown') + " />"; + info = ' Did you accidentally export a JSX literal instead of a component?'; + } else { + typeString = typeof type; } - { - // The validation flag is currently mutative. We put it on - // an external backing store so that we can freeze the whole object. - // This can be replaced with a WeakMap once they are implemented in - // commonly used development environments. - element._store = {}; // To make comparing ReactElements easier for testing purposes, we make - // the validation flag non-enumerable (where possible, which should - // include every environment we run tests in), so the test framework - // ignores it. - - Object.defineProperty(element._store, "validated", { - configurable: false, - enumerable: false, - writable: true, - value: false - }); // debugInfo contains Server Component debug information. - - Object.defineProperty(element, "_debugInfo", { - configurable: false, - enumerable: false, - writable: true, - value: null - }); - - if (Object.freeze) { - Object.freeze(element.props); - Object.freeze(element); + error('React.jsx: type is invalid -- expected a string (for ' + 'built-in components) or a class/function (for composite ' + 'components) but got: %s.%s', typeString, info); + } else { + // This is a valid element type. + // Skip key warning if the type isn't valid since our key validation logic + // doesn't expect a non-string/function type and can throw confusing + // errors. We don't want exception behavior to differ between dev and + // prod. (Rendering will throw with a helpful message and as soon as the + // type is fixed, the key warnings will appear.) + var children = config.children; + + if (children !== undefined) { + if (isStaticChildren) { + if (isArray(children)) { + for (var i = 0; i < children.length; i++) { + validateChildKeys(children[i], type); + } + + if (Object.freeze) { + Object.freeze(children); + } + } else { + error('React.jsx: Static children should always be an array. ' + 'You are likely explicitly calling React.jsxs or React.jsxDEV. ' + 'Use the Babel transform instead.'); + } + } else { + validateChildKeys(children, type); } } + } // Warn about key spread regardless of whether the type is valid. - return element; - } - // support `jsx` and `jsxs` when running in development. This supports the case - // where a third-party dependency ships code that was compiled for production; - // we want to still provide warnings in development. - // - // So these functions are the _dev_ implementations of the _production_ - // API signatures. - // - // Since these functions are dev-only, it's ok to add an indirection here. They - // only exist to provide different versions of `isStaticChildren`. (We shouldn't - // use this pattern for the prod versions, though, because it will add an call - // frame.) - - function jsxProdSignatureRunningInDevWithDynamicChildren( - type, - config, - maybeKey, - source, - self - ) { - { - var isStaticChildren = false; - return jsxDEV(type, config, maybeKey, isStaticChildren, source, self); + + if (hasOwnProperty.call(config, 'key')) { + var componentName = getComponentNameFromType(type); + var keys = Object.keys(config).filter(function (k) { + return k !== 'key'; + }); + var beforeExample = keys.length > 0 ? '{key: someKey, ' + keys.join(': ..., ') + ': ...}' : '{key: someKey}'; + + if (!didWarnAboutKeySpread[componentName + beforeExample]) { + var afterExample = keys.length > 0 ? '{' + keys.join(': ..., ') + ': ...}' : '{}'; + + error('A props object containing a "key" prop is being spread into JSX:\n' + ' let props = %s;\n' + ' <%s {...props} />\n' + 'React keys must be passed directly to JSX without using spread:\n' + ' let props = %s;\n' + ' <%s key={someKey} {...props} />', beforeExample, componentName, afterExample, componentName); + + didWarnAboutKeySpread[componentName + beforeExample] = true; } } - function jsxProdSignatureRunningInDevWithStaticChildren( - type, - config, - maybeKey, - source, - self - ) { + + var key = null; + var ref = null; // Currently, key can be spread in as a prop. This causes a potential + // issue if key is also explicitly declared (ie.
+ // or
). We want to deprecate key spread, + // but as an intermediary step, we will use jsxDEV for everything except + //
, because we aren't currently able to tell if + // key is explicitly declared to be undefined or not. + + if (maybeKey !== undefined) { { - var isStaticChildren = true; - return jsxDEV(type, config, maybeKey, isStaticChildren, source, self); + checkKeyStringCoercion(maybeKey); } + + key = '' + maybeKey; } - var didWarnAboutKeySpread = {}; - /** - * https://github.com/reactjs/rfcs/pull/107 - * @param {*} type - * @param {object} props - * @param {string} key - */ - - function jsxDEV(type, config, maybeKey, isStaticChildren, source, self) { - { - if (!isValidElementType(type)) { - // This is an invalid element type. - // - // We warn in this case but don't throw. We expect the element creation to - // succeed and there will likely be errors in render. - var info = ""; - - 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 typeString; - - if (type === null) { - typeString = "null"; - } else if (isArray(type)) { - typeString = "array"; - } else if ( - type !== undefined && - type.$$typeof === REACT_ELEMENT_TYPE - ) { - typeString = - "<" + (getComponentNameFromType(type.type) || "Unknown") + " />"; - info = - " Did you accidentally export a JSX literal instead of a component?"; - } else { - typeString = typeof type; - } + if (hasValidKey(config)) { + { + checkKeyStringCoercion(config.key); + } - error( - "React.jsx: type is invalid -- expected a string (for " + - "built-in components) or a class/function (for composite " + - "components) but got: %s.%s", - typeString, - info - ); - } else { - // This is a valid element type. - // Skip key warning if the type isn't valid since our key validation logic - // doesn't expect a non-string/function type and can throw confusing - // errors. We don't want exception behavior to differ between dev and - // prod. (Rendering will throw with a helpful message and as soon as the - // type is fixed, the key warnings will appear.) - var children = config.children; - - if (children !== undefined) { - if (isStaticChildren) { - if (isArray(children)) { - for (var i = 0; i < children.length; i++) { - validateChildKeys(children[i], type); - } + key = '' + config.key; + } - if (Object.freeze) { - Object.freeze(children); - } - } else { - error( - "React.jsx: Static children should always be an array. " + - "You are likely explicitly calling React.jsxs or React.jsxDEV. " + - "Use the Babel transform instead." - ); - } - } else { - validateChildKeys(children, type); - } - } - } // Warn about key spread regardless of whether the type is valid. + if (hasValidRef(config)) { + { + ref = config.ref; - if (hasOwnProperty.call(config, "key")) { - var componentName = getComponentNameFromType(type); - var keys = Object.keys(config).filter(function (k) { - return k !== "key"; - }); - var beforeExample = - keys.length > 0 - ? "{key: someKey, " + keys.join(": ..., ") + ": ...}" - : "{key: someKey}"; - - if (!didWarnAboutKeySpread[componentName + beforeExample]) { - var afterExample = - keys.length > 0 ? "{" + keys.join(": ..., ") + ": ...}" : "{}"; - - error( - 'A props object containing a "key" prop is being spread into JSX:\n' + - " let props = %s;\n" + - " <%s {...props} />\n" + - "React keys must be passed directly to JSX without using spread:\n" + - " let props = %s;\n" + - " <%s key={someKey} {...props} />", - beforeExample, - componentName, - afterExample, - componentName - ); - - didWarnAboutKeySpread[componentName + beforeExample] = true; - } + { + ref = coerceStringRef(ref, ReactSharedInternals.owner, type); } + } - var key = null; - var ref = null; // Currently, key can be spread in as a prop. This causes a potential - // issue if key is also explicitly declared (ie.
- // or
). We want to deprecate key spread, - // but as an intermediary step, we will use jsxDEV for everything except - //
, because we aren't currently able to tell if - // key is explicitly declared to be undefined or not. - - if (maybeKey !== undefined) { - { - checkKeyStringCoercion(maybeKey); - } + { + warnIfStringRefCannotBeAutoConverted(config, self); + } + } - key = "" + maybeKey; - } + var props; - if (hasValidKey(config)) { + { + // We need to remove reserved props (key, prop, ref). Create a fresh props + // object and copy over all the non-reserved props. We don't use `delete` + // because in V8 it will deopt the object to dictionary mode. + props = {}; + + for (var propName in config) { + // Skip over reserved prop names + if (propName !== 'key' && (propName !== 'ref')) { { - checkKeyStringCoercion(config.key); + props[propName] = config[propName]; } - - key = "" + config.key; } + } + } - if (hasValidRef(config)) { - { - ref = config.ref; - - { - ref = coerceStringRef(ref, ReactSharedInternals.owner, type); - } - } + if (!disableDefaultPropsExceptForClasses) { + // Resolve default props + if (type && type.defaultProps) { + var defaultProps = type.defaultProps; - { - warnIfStringRefCannotBeAutoConverted(config, self); + for (var _propName2 in defaultProps) { + if (props[_propName2] === undefined) { + props[_propName2] = defaultProps[_propName2]; } } + } + } - var props; - - { - // We need to remove reserved props (key, prop, ref). Create a fresh props - // object and copy over all the non-reserved props. We don't use `delete` - // because in V8 it will deopt the object to dictionary mode. - props = {}; - - for (var propName in config) { - // Skip over reserved prop names - if (propName !== "key" && propName !== "ref") { - { - props[propName] = config[propName]; - } - } - } - } + if (key || ref) { + var displayName = typeof type === 'function' ? type.displayName || type.name || 'Unknown' : type; - if (!disableDefaultPropsExceptForClasses) { - // Resolve default props - if (type && type.defaultProps) { - var defaultProps = type.defaultProps; + if (key) { + defineKeyPropWarningGetter(props, displayName); + } - for (var _propName2 in defaultProps) { - if (props[_propName2] === undefined) { - props[_propName2] = defaultProps[_propName2]; - } - } - } - } + if (ref) { + defineRefPropWarningGetter(props, displayName); + } + } - if (key || ref) { - var displayName = - typeof type === "function" - ? type.displayName || type.name || "Unknown" - : type; + var element = ReactElement(type, key, ref, self, source, ReactSharedInternals.owner, props); - if (key) { - defineKeyPropWarningGetter(props, displayName); - } + if (type === REACT_FRAGMENT_TYPE) { + validateFragmentProps(element); + } - if (ref) { - defineRefPropWarningGetter(props, displayName); - } - } + return element; + } +} - var element = ReactElement( - type, - key, - ref, - self, - source, - ReactSharedInternals.owner, - props - ); - - if (type === REACT_FRAGMENT_TYPE) { - validateFragmentProps(element); - } +function getDeclarationErrorAddendum() { + { + if (ReactSharedInternals.owner) { + var name = getComponentNameFromType(ReactSharedInternals.owner.type); - return element; + if (name) { + return '\n\nCheck the render method of `' + name + '`.'; } } - function getDeclarationErrorAddendum() { - { - if (ReactSharedInternals.owner) { - var name = getComponentNameFromType(ReactSharedInternals.owner.type); + return ''; + } +} +/** + * Ensure that every element either is passed in a static location, in an + * array with an explicit keys property defined, or in an object literal + * with valid key property. + * + * @internal + * @param {ReactNode} node Statically passed child of any type. + * @param {*} parentType node's parent's type. + */ - if (name) { - return "\n\nCheck the render method of `" + name + "`."; - } - } - return ""; - } +function validateChildKeys(node, parentType) { + { + if (typeof node !== 'object' || !node) { + return; } - /** - * Ensure that every element either is passed in a static location, in an - * array with an explicit keys property defined, or in an object literal - * with valid key property. - * - * @internal - * @param {ReactNode} node Statically passed child of any type. - * @param {*} parentType node's parent's type. - */ - - function validateChildKeys(node, parentType) { - { - if (typeof node !== "object" || !node) { - return; - } - if (node.$$typeof === REACT_CLIENT_REFERENCE); - else if (isArray(node)) { - for (var i = 0; i < node.length; i++) { - var child = node[i]; + if (node.$$typeof === REACT_CLIENT_REFERENCE) ; else if (isArray(node)) { + for (var i = 0; i < node.length; i++) { + var child = node[i]; - if (isValidElement(child)) { - validateExplicitKey(child, parentType); - } - } - } else if (isValidElement(node)) { - // This element was passed in a valid location. - if (node._store) { - node._store.validated = true; - } - } else { - var iteratorFn = getIteratorFn(node); - - if (typeof iteratorFn === "function") { - // Entry iterators used to provide implicit keys, - // but now we print a separate warning for them later. - if (iteratorFn !== node.entries) { - var iterator = iteratorFn.call(node); - var step; - - while (!(step = iterator.next()).done) { - if (isValidElement(step.value)) { - validateExplicitKey(step.value, parentType); - } - } + if (isValidElement(child)) { + validateExplicitKey(child, parentType); + } + } + } else if (isValidElement(node)) { + // This element was passed in a valid location. + if (node._store) { + node._store.validated = true; + } + } else { + var iteratorFn = getIteratorFn(node); + + if (typeof iteratorFn === 'function') { + // Entry iterators used to provide implicit keys, + // but now we print a separate warning for them later. + if (iteratorFn !== node.entries) { + var iterator = iteratorFn.call(node); + var step; + + while (!(step = iterator.next()).done) { + if (isValidElement(step.value)) { + validateExplicitKey(step.value, parentType); } } } } } - /** - * Verifies the object is a ReactElement. - * See https://reactjs.org/docs/react-api.html#isvalidelement - * @param {?object} object - * @return {boolean} True if `object` is a ReactElement. - * @final - */ - - function isValidElement(object) { - return ( - typeof object === "object" && - object !== null && - object.$$typeof === REACT_ELEMENT_TYPE - ); - } - var ownerHasKeyUseWarning = {}; - /** - * Warn if the element doesn't have an explicit key assigned to it. - * This element is in an array. The array could grow and shrink or be - * reordered. All children that haven't already been validated are required to - * have a "key" property assigned to it. Error statuses are cached so a warning - * will only be shown once. - * - * @internal - * @param {ReactElement} element Element that requires a key. - * @param {*} parentType element's parent's type. - */ - - function validateExplicitKey(element, parentType) { - { - if ( - !element._store || - element._store.validated || - element.key != null - ) { - return; - } + } +} +/** + * Verifies the object is a ReactElement. + * See https://reactjs.org/docs/react-api.html#isvalidelement + * @param {?object} object + * @return {boolean} True if `object` is a ReactElement. + * @final + */ - element._store.validated = true; - var currentComponentErrorInfo = - getCurrentComponentErrorInfo(parentType); - if (ownerHasKeyUseWarning[currentComponentErrorInfo]) { - return; - } +function isValidElement(object) { + return typeof object === 'object' && object !== null && object.$$typeof === REACT_ELEMENT_TYPE; +} +var ownerHasKeyUseWarning = {}; +/** + * Warn if the element doesn't have an explicit key assigned to it. + * This element is in an array. The array could grow and shrink or be + * reordered. All children that haven't already been validated are required to + * have a "key" property assigned to it. Error statuses are cached so a warning + * will only be shown once. + * + * @internal + * @param {ReactElement} element Element that requires a key. + * @param {*} parentType element's parent's type. + */ - ownerHasKeyUseWarning[currentComponentErrorInfo] = true; // Usually the current owner is the offender, but if it accepts children as a - // property, it may be the creator of the child that's responsible for - // assigning it a key. +function validateExplicitKey(element, parentType) { + { + if (!element._store || element._store.validated || element.key != null) { + return; + } - var childOwner = ""; + element._store.validated = true; + var currentComponentErrorInfo = getCurrentComponentErrorInfo(parentType); - if ( - element && - element._owner != null && - element._owner !== ReactSharedInternals.owner - ) { - var ownerName = null; + if (ownerHasKeyUseWarning[currentComponentErrorInfo]) { + return; + } - if (typeof element._owner.tag === "number") { - ownerName = getComponentNameFromType(element._owner.type); - } else if (typeof element._owner.name === "string") { - ownerName = element._owner.name; - } // Give the component that originally created this child. + ownerHasKeyUseWarning[currentComponentErrorInfo] = true; // Usually the current owner is the offender, but if it accepts children as a + // property, it may be the creator of the child that's responsible for + // assigning it a key. - childOwner = " It was passed a child from " + ownerName + "."; - } + var childOwner = ''; - setCurrentlyValidatingElement(element); + if (element && element._owner != null && element._owner !== ReactSharedInternals.owner) { + var ownerName = null; - error( - 'Each child in a list should have a unique "key" prop.' + - "%s%s See https://react.dev/link/warning-keys for more information.", - currentComponentErrorInfo, - childOwner - ); + if (typeof element._owner.tag === 'number') { + ownerName = getComponentNameFromType(element._owner.type); + } else if (typeof element._owner.name === 'string') { + ownerName = element._owner.name; + } // Give the component that originally created this child. - setCurrentlyValidatingElement(null); - } - } - function setCurrentlyValidatingElement(element) { - { - if (element) { - var stack = describeUnknownElementTypeFrameInDEV(element.type); - ReactSharedInternals.setExtraStackFrame(stack); - } else { - ReactSharedInternals.setExtraStackFrame(null); - } - } + childOwner = " It was passed a child from " + ownerName + "."; } - function getCurrentComponentErrorInfo(parentType) { - { - var info = getDeclarationErrorAddendum(); + setCurrentlyValidatingElement(element); - if (!info) { - var parentName = getComponentNameFromType(parentType); + error('Each child in a list should have a unique "key" prop.' + '%s%s See https://react.dev/link/warning-keys for more information.', currentComponentErrorInfo, childOwner); - if (parentName) { - info = - "\n\nCheck the top-level render call using <" + parentName + ">."; - } - } + setCurrentlyValidatingElement(null); + } +} - return info; - } +function setCurrentlyValidatingElement(element) { + { + if (element) { + var stack = describeUnknownElementTypeFrameInDEV(element.type); + ReactSharedInternals.setExtraStackFrame(stack); + } else { + ReactSharedInternals.setExtraStackFrame(null); } - /** - * Given a fragment, validate that it can only be provided with fragment props - * @param {ReactElement} fragment - */ - - function validateFragmentProps(fragment) { - // TODO: Move this to render phase instead of at element creation. - { - var keys = Object.keys(fragment.props); + } +} - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; +function getCurrentComponentErrorInfo(parentType) { + { + var info = getDeclarationErrorAddendum(); - if (key !== "children" && key !== "key") { - setCurrentlyValidatingElement(fragment); + if (!info) { + var parentName = getComponentNameFromType(parentType); - error( - "Invalid prop `%s` supplied to `React.Fragment`. " + - "React.Fragment can only have `key` and `children` props.", - key - ); + if (parentName) { + info = "\n\nCheck the top-level render call using <" + parentName + ">."; + } + } - setCurrentlyValidatingElement(null); - break; - } - } + return info; + } +} +/** + * Given a fragment, validate that it can only be provided with fragment props + * @param {ReactElement} fragment + */ - if (fragment.ref !== null) { - setCurrentlyValidatingElement(fragment); - error("Invalid attribute `ref` supplied to `React.Fragment`."); +function validateFragmentProps(fragment) { + // TODO: Move this to render phase instead of at element creation. + { + var keys = Object.keys(fragment.props); - setCurrentlyValidatingElement(null); - } - } - } + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; - function coerceStringRef(mixedRef, owner, type) { - var stringRef; + if (key !== 'children' && key !== 'key') { + setCurrentlyValidatingElement(fragment); - if (typeof mixedRef === "string") { - stringRef = mixedRef; - } else { - if (typeof mixedRef === "number" || typeof mixedRef === "boolean") { - { - checkPropStringCoercion(mixedRef, "ref"); - } + error('Invalid prop `%s` supplied to `React.Fragment`. ' + 'React.Fragment can only have `key` and `children` props.', key); - stringRef = "" + mixedRef; - } else { - return mixedRef; - } + setCurrentlyValidatingElement(null); + break; } + } - var callback = stringRefAsCallbackRef.bind(null, stringRef, type, owner); // This is used to check whether two callback refs conceptually represent - // the same string ref, and can therefore be reused by the reconciler. Needed - // for backwards compatibility with old Meta code that relies on string refs - // not being reattached on every render. + if (fragment.ref !== null) { + setCurrentlyValidatingElement(fragment); - callback.__stringRef = stringRef; - callback.__type = type; - callback.__owner = owner; - return callback; + error('Invalid attribute `ref` supplied to `React.Fragment`.'); + + setCurrentlyValidatingElement(null); } + } +} - function stringRefAsCallbackRef(stringRef, type, owner, value) { - if (!owner) { - throw new Error( - "Element ref was specified as a string (" + - stringRef + - ") 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://react.dev/link/refs-must-have-owner for more information." - ); - } +function coerceStringRef(mixedRef, owner, type) { - if (owner.tag !== ClassComponent) { - throw new Error( - "Function components cannot have string refs. " + - "We recommend using useRef() instead. " + - "Learn more about using refs safely here: " + - "https://react.dev/link/strict-mode-string-ref" - ); - } + var stringRef; + if (typeof mixedRef === 'string') { + stringRef = mixedRef; + } else { + if (typeof mixedRef === 'number' || typeof mixedRef === 'boolean') { { - if ( - // Will already warn with "Function components cannot be given refs" - !(typeof type === "function" && !isReactClass(type)) - ) { - var componentName = getComponentNameFromFiber(owner) || "Component"; - - 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://react.dev/link/strict-mode-string-ref", - componentName, - stringRef - ); - - didWarnAboutStringRefs[componentName] = true; - } - } + checkPropStringCoercion(mixedRef, 'ref'); } - var inst = owner.stateNode; + stringRef = '' + mixedRef; + } else { + return mixedRef; + } + } - if (!inst) { - throw new Error( - "Missing owner for string ref " + - stringRef + - ". This error is likely caused by a " + - "bug in React. Please file an issue." - ); - } + var callback = stringRefAsCallbackRef.bind(null, stringRef, type, owner); // This is used to check whether two callback refs conceptually represent + // the same string ref, and can therefore be reused by the reconciler. Needed + // for backwards compatibility with old Meta code that relies on string refs + // not being reattached on every render. + + callback.__stringRef = stringRef; + callback.__type = type; + callback.__owner = owner; + return callback; +} - var refs = inst.refs; +function stringRefAsCallbackRef(stringRef, type, owner, value) { - if (value === null) { - delete refs[stringRef]; - } else { - refs[stringRef] = value; + if (!owner) { + throw new Error("Element ref was specified as a string (" + stringRef + ") 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://react.dev/link/refs-must-have-owner for more information.'); + } + + if (owner.tag !== ClassComponent) { + throw new Error('Function components cannot have string refs. ' + 'We recommend using useRef() instead. ' + 'Learn more about using refs safely here: ' + 'https://react.dev/link/strict-mode-string-ref'); + } + + { + if ( // Will already warn with "Function components cannot be given refs" + !(typeof type === 'function' && !isReactClass(type))) { + var componentName = getComponentNameFromFiber(owner) || 'Component'; + + 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://react.dev/link/strict-mode-string-ref', componentName, stringRef); + + didWarnAboutStringRefs[componentName] = true; } } + } - function isReactClass(type) { - return type.prototype && type.prototype.isReactComponent; - } + var inst = owner.stateNode; + + if (!inst) { + throw new Error("Missing owner for string ref " + stringRef + ". This error is likely caused by a " + 'bug in React. Please file an issue.'); + } + + var refs = inst.refs; + + if (value === null) { + delete refs[stringRef]; + } else { + refs[stringRef] = value; + } +} + +function isReactClass(type) { + return type.prototype && type.prototype.isReactComponent; +} - var jsx = jsxProdSignatureRunningInDevWithDynamicChildren; // we may want to special case jsxs internally to take advantage of static children. - // for now we can ship identical prod functions +var jsx = jsxProdSignatureRunningInDevWithDynamicChildren ; // we may want to special case jsxs internally to take advantage of static children. +// for now we can ship identical prod functions - var jsxs = jsxProdSignatureRunningInDevWithStaticChildren; +var jsxs = jsxProdSignatureRunningInDevWithStaticChildren ; - exports.Fragment = REACT_FRAGMENT_TYPE; - exports.jsx = jsx; - exports.jsxs = jsxs; +exports.Fragment = REACT_FRAGMENT_TYPE; +exports.jsx = jsx; +exports.jsxs = jsxs; })(); } 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 e6ce3bb8a1614..7d765da45b958 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 @@ -7,3870 +7,3419 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<<150980e4b77b12c241c9997159b4f67a>> + * @generated SignedSource<<1ccd58cd787da0b40cbf5543503953db>> */ -"use strict"; +'use strict'; if (__DEV__) { - (function () { - "use strict"; - - /* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */ - if ( - typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== "undefined" && - typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart === - "function" - ) { - __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error()); - } - var dynamicFlagsUntyped = require("ReactNativeInternalFeatureFlags"); - - var ReactVersion = "19.0.0-canary-a13a0c2f"; - - // 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"); // TODO: Delete with enableRenderableContext - - var REACT_CONSUMER_TYPE = Symbol.for("react.consumer"); - var REACT_CONTEXT_TYPE = Symbol.for("react.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_TRACING_MARKER_TYPE = Symbol.for("react.tracing_marker"); - var MAYBE_ITERATOR_SYMBOL = Symbol.iterator; - var FAUX_ITERATOR_SYMBOL = "@@iterator"; - function getIteratorFn(maybeIterable) { - if (maybeIterable === null || typeof maybeIterable !== "object") { - return null; - } - - var maybeIterator = - (MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL]) || - maybeIterable[FAUX_ITERATOR_SYMBOL]; - - if (typeof maybeIterator === "function") { - return maybeIterator; - } + (function() { - return null; - } + 'use strict'; - // Re-export dynamic flags from the internal module. - var dynamicFlags = dynamicFlagsUntyped; // We destructure each value before re-exporting to avoid a dynamic look-up on - // the exports object every time a flag is read. - - var enableAsyncActions = dynamicFlags.enableAsyncActions, - enableComponentStackLocations = - dynamicFlags.enableComponentStackLocations, - enableRenderableContext = dynamicFlags.enableRenderableContext, - disableDefaultPropsExceptForClasses = - dynamicFlags.disableDefaultPropsExceptForClasses; // The rest of the flags are static for better dead code elimination. - var enableDebugTracing = false; - var enableScopeAPI = false; - var enableLegacyHidden = false; - var enableTransitionTracing = false; - // because JSX is an extremely hot path. - - var enableRefAsProp = false; - var disableLegacyMode = false; - - var ReactSharedInternals = { - H: null, - C: null, - T: null - }; +/* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */ +if ( + typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' && + typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart === + 'function' +) { + __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error()); +} + var dynamicFlagsUntyped = require('ReactNativeInternalFeatureFlags'); + +var ReactVersion = '19.0.0-canary-c627bf44'; + +// 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'); // TODO: Delete with enableRenderableContext + +var REACT_CONSUMER_TYPE = Symbol.for('react.consumer'); +var REACT_CONTEXT_TYPE = Symbol.for('react.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_TRACING_MARKER_TYPE = Symbol.for('react.tracing_marker'); +var MAYBE_ITERATOR_SYMBOL = Symbol.iterator; +var FAUX_ITERATOR_SYMBOL = '@@iterator'; +function getIteratorFn(maybeIterable) { + if (maybeIterable === null || typeof maybeIterable !== 'object') { + return null; + } + + var maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]; + + if (typeof maybeIterator === 'function') { + return maybeIterator; + } + + return null; +} - { - ReactSharedInternals.owner = null; - } +// Re-export dynamic flags from the internal module. +var dynamicFlags = dynamicFlagsUntyped; // We destructure each value before re-exporting to avoid a dynamic look-up on +// the exports object every time a flag is read. + +var enableAsyncActions = dynamicFlags.enableAsyncActions, + enableComponentStackLocations = dynamicFlags.enableComponentStackLocations, + enableRenderableContext = dynamicFlags.enableRenderableContext, + disableDefaultPropsExceptForClasses = dynamicFlags.disableDefaultPropsExceptForClasses; // The rest of the flags are static for better dead code elimination. +var enableDebugTracing = false; +var enableScopeAPI = false; +var enableLegacyHidden = false; +var enableTransitionTracing = false; +// because JSX is an extremely hot path. + +var enableRefAsProp = false; +var disableLegacyMode = false; + +var ReactSharedInternals = { + H: null, + C: null, + T: null +}; + +{ + ReactSharedInternals.owner = null; +} - { - ReactSharedInternals.actQueue = null; - ReactSharedInternals.isBatchingLegacy = false; - ReactSharedInternals.didScheduleLegacyUpdate = false; - ReactSharedInternals.didUsePromise = false; - ReactSharedInternals.thrownErrors = []; - var currentExtraStackFrame = null; +{ + ReactSharedInternals.actQueue = null; + ReactSharedInternals.isBatchingLegacy = false; + ReactSharedInternals.didScheduleLegacyUpdate = false; + ReactSharedInternals.didUsePromise = false; + ReactSharedInternals.thrownErrors = []; + var currentExtraStackFrame = null; - ReactSharedInternals.setExtraStackFrame = function (stack) { - currentExtraStackFrame = stack; - }; // Stack implementation injected by the current renderer. + ReactSharedInternals.setExtraStackFrame = function (stack) { + currentExtraStackFrame = stack; + }; // Stack implementation injected by the current renderer. - ReactSharedInternals.getCurrentStack = null; - ReactSharedInternals.getStackAddendum = function () { - var stack = ""; // Add an extra top frame while an element is being validated + ReactSharedInternals.getCurrentStack = null; - if (currentExtraStackFrame) { - stack += currentExtraStackFrame; - } // Delegate to the injected renderer-specific implementation + ReactSharedInternals.getStackAddendum = function () { + var stack = ''; // Add an extra top frame while an element is being validated - var impl = ReactSharedInternals.getCurrentStack; + if (currentExtraStackFrame) { + stack += currentExtraStackFrame; + } // Delegate to the injected renderer-specific implementation - if (impl) { - stack += impl() || ""; - } - return stack; - }; + var impl = ReactSharedInternals.getCurrentStack; + + if (impl) { + stack += impl() || ''; } - // by calls to these methods by a Babel plugin. - // - // In PROD (or in packages without access to React internals), - // they are left as they are instead. + return stack; + }; +} - function warn(format) { - { - { - for ( - var _len = arguments.length, - args = new Array(_len > 1 ? _len - 1 : 0), - _key = 1; - _key < _len; - _key++ - ) { - args[_key - 1] = arguments[_key]; - } +// by calls to these methods by a Babel plugin. +// +// In PROD (or in packages without access to React internals), +// they are left as they are instead. - printWarning("warn", format, args); - } +function warn(format) { + { + { + for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; } - } - function error(format) { - { - { - for ( - var _len2 = arguments.length, - args = new Array(_len2 > 1 ? _len2 - 1 : 0), - _key2 = 1; - _key2 < _len2; - _key2++ - ) { - args[_key2 - 1] = arguments[_key2]; - } - printWarning("error", format, args); - } - } + printWarning('warn', format, args); } - - function printWarning(level, format, args) { - // When changing this logic, you might want to also - // update consoleWithStackDev.www.js as well. - { - var stack = ReactSharedInternals.getStackAddendum(); - - if (stack !== "") { - format += "%s"; - args = args.concat([stack]); - } // eslint-disable-next-line react-internal/safe-string-coercion - - var argsWithFormat = args.map(function (item) { - return String(item); - }); // Careful: RN currently depends on this prefix - - argsWithFormat.unshift("Warning: " + format); // We intentionally don't use spread (or .apply) directly because it - // breaks IE9: https://github.com/facebook/react/issues/13610 - // eslint-disable-next-line react-internal/no-production-logging - - Function.prototype.apply.call(console[level], console, argsWithFormat); + } +} +function error(format) { + { + { + for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { + args[_key2 - 1] = arguments[_key2]; } - } - - var didWarnStateUpdateForUnmountedComponent = {}; - - function warnNoop(publicInstance, callerName) { - { - var _constructor = publicInstance.constructor; - var componentName = - (_constructor && (_constructor.displayName || _constructor.name)) || - "ReactClass"; - var warningKey = componentName + "." + callerName; - - if (didWarnStateUpdateForUnmountedComponent[warningKey]) { - return; - } - - error( - "Can't call %s on a component that is not yet mounted. " + - "This is a no-op, but it might indicate a bug in your application. " + - "Instead, assign to `this.state` directly or define a `state = {};` " + - "class property with the desired state in the %s component.", - callerName, - componentName - ); - - didWarnStateUpdateForUnmountedComponent[warningKey] = true; - } - } - /** - * This is the abstract API for an update queue. - */ - - var ReactNoopUpdateQueue = { - /** - * Checks whether or not this composite component is mounted. - * @param {ReactClass} publicInstance The instance we want to test. - * @return {boolean} True if mounted, false otherwise. - * @protected - * @final - */ - isMounted: function (publicInstance) { - return false; - }, - /** - * Forces an update. This should only be invoked when it is known with - * certainty that we are **not** in a DOM transaction. - * - * You may want to call this when you know that some deeper aspect of the - * component's state has changed but `setState` was not called. - * - * This will not invoke `shouldComponentUpdate`, but it will invoke - * `componentWillUpdate` and `componentDidUpdate`. - * - * @param {ReactClass} publicInstance The instance that should rerender. - * @param {?function} callback Called after component is updated. - * @param {?string} callerName name of the calling function in the public API. - * @internal - */ - enqueueForceUpdate: function (publicInstance, callback, callerName) { - warnNoop(publicInstance, "forceUpdate"); - }, + printWarning('error', format, args); + } + } +} - /** - * Replaces all of the state. Always use this or `setState` to mutate state. - * You should treat `this.state` as immutable. - * - * There is no guarantee that `this.state` will be immediately updated, so - * accessing `this.state` after calling this method may return the old value. - * - * @param {ReactClass} publicInstance The instance that should rerender. - * @param {object} completeState Next state. - * @param {?function} callback Called after component is updated. - * @param {?string} callerName name of the calling function in the public API. - * @internal - */ - enqueueReplaceState: function ( - publicInstance, - completeState, - callback, - callerName - ) { - warnNoop(publicInstance, "replaceState"); - }, +function printWarning(level, format, args) { + // When changing this logic, you might want to also + // update consoleWithStackDev.www.js as well. + { + var stack = ReactSharedInternals.getStackAddendum(); - /** - * Sets a subset of the state. This only exists because _pendingState is - * internal. This provides a merging strategy that is not available to deep - * properties which is confusing. TODO: Expose pendingState or don't use it - * during the merge. - * - * @param {ReactClass} publicInstance The instance that should rerender. - * @param {object} partialState Next partial state to be merged with state. - * @param {?function} callback Called after component is updated. - * @param {?string} Name of the calling function in the public API. - * @internal - */ - enqueueSetState: function ( - publicInstance, - partialState, - callback, - callerName - ) { - warnNoop(publicInstance, "setState"); - } - }; + if (stack !== '') { + format += '%s'; + args = args.concat([stack]); + } // eslint-disable-next-line react-internal/safe-string-coercion - var assign = Object.assign; - var emptyObject = {}; + var argsWithFormat = args.map(function (item) { + return String(item); + }); // Careful: RN currently depends on this prefix - { - Object.freeze(emptyObject); - } - /** - * Base class helpers for the updating state of a component. - */ - - function Component(props, context, updater) { - this.props = props; - this.context = context; // If a component has string refs, we will assign a different object later. - - this.refs = emptyObject; // We initialize the default updater but the real one gets injected by the - // renderer. - - this.updater = updater || ReactNoopUpdateQueue; - } - - Component.prototype.isReactComponent = {}; - /** - * Sets a subset of the state. Always use this to mutate - * state. You should treat `this.state` as immutable. - * - * There is no guarantee that `this.state` will be immediately updated, so - * accessing `this.state` after calling this method may return the old value. - * - * There is no guarantee that calls to `setState` will run synchronously, - * as they may eventually be batched together. You can provide an optional - * callback that will be executed when the call to setState is actually - * completed. - * - * When a function is provided to setState, it will be called at some point in - * the future (not synchronously). It will be called with the up to date - * component arguments (state, props, context). These values can be different - * from this.* because your function may be called after receiveProps but before - * shouldComponentUpdate, and this new state, props, and context will not yet be - * assigned to this. - * - * @param {object|function} partialState Next partial state or function to - * produce next partial state to be merged with current state. - * @param {?function} callback Called after state is updated. - * @final - * @protected - */ - - Component.prototype.setState = function (partialState, callback) { - if ( - typeof partialState !== "object" && - typeof partialState !== "function" && - partialState != null - ) { - throw new Error( - "takes an object of state variables to update or a " + - "function which returns an object of state variables." - ); - } - - this.updater.enqueueSetState(this, partialState, callback, "setState"); - }; - /** - * Forces an update. This should only be invoked when it is known with - * certainty that we are **not** in a DOM transaction. - * - * You may want to call this when you know that some deeper aspect of the - * component's state has changed but `setState` was not called. - * - * This will not invoke `shouldComponentUpdate`, but it will invoke - * `componentWillUpdate` and `componentDidUpdate`. - * - * @param {?function} callback Called after update is complete. - * @final - * @protected - */ - - Component.prototype.forceUpdate = function (callback) { - this.updater.enqueueForceUpdate(this, callback, "forceUpdate"); - }; - /** - * Deprecated APIs. These APIs used to exist on classic React classes but since - * we would like to deprecate them, we're not going to move them over to this - * modern base class. Instead, we define a getter that warns if it's accessed. - */ + argsWithFormat.unshift('Warning: ' + format); // We intentionally don't use spread (or .apply) directly because it + // breaks IE9: https://github.com/facebook/react/issues/13610 + // eslint-disable-next-line react-internal/no-production-logging - { - var deprecatedAPIs = { - isMounted: [ - "isMounted", - "Instead, make sure to clean up subscriptions and pending requests in " + - "componentWillUnmount to prevent memory leaks." - ], - replaceState: [ - "replaceState", - "Refactor your code to use setState instead (see " + - "https://github.com/facebook/react/issues/3236)." - ] - }; + Function.prototype.apply.call(console[level], console, argsWithFormat); + } +} - var defineDeprecationWarning = function (methodName, info) { - Object.defineProperty(Component.prototype, methodName, { - get: function () { - warn( - "%s(...) is deprecated in plain JavaScript React classes. %s", - info[0], - info[1] - ); +var didWarnStateUpdateForUnmountedComponent = {}; - return undefined; - } - }); - }; +function warnNoop(publicInstance, callerName) { + { + var _constructor = publicInstance.constructor; + var componentName = _constructor && (_constructor.displayName || _constructor.name) || 'ReactClass'; + var warningKey = componentName + "." + callerName; - for (var fnName in deprecatedAPIs) { - if (deprecatedAPIs.hasOwnProperty(fnName)) { - defineDeprecationWarning(fnName, deprecatedAPIs[fnName]); - } - } + if (didWarnStateUpdateForUnmountedComponent[warningKey]) { + return; } - function ComponentDummy() {} + error("Can't call %s on a component that is not yet mounted. " + 'This is a no-op, but it might indicate a bug in your application. ' + 'Instead, assign to `this.state` directly or define a `state = {};` ' + 'class property with the desired state in the %s component.', callerName, componentName); - ComponentDummy.prototype = Component.prototype; - /** - * Convenience component with default shallow equality check for sCU. - */ + didWarnStateUpdateForUnmountedComponent[warningKey] = true; + } +} +/** + * This is the abstract API for an update queue. + */ - function PureComponent(props, context, updater) { - this.props = props; - this.context = context; // If a component has string refs, we will assign a different object later. - this.refs = emptyObject; - this.updater = updater || ReactNoopUpdateQueue; - } +var ReactNoopUpdateQueue = { + /** + * Checks whether or not this composite component is mounted. + * @param {ReactClass} publicInstance The instance we want to test. + * @return {boolean} True if mounted, false otherwise. + * @protected + * @final + */ + isMounted: function (publicInstance) { + return false; + }, + + /** + * Forces an update. This should only be invoked when it is known with + * certainty that we are **not** in a DOM transaction. + * + * You may want to call this when you know that some deeper aspect of the + * component's state has changed but `setState` was not called. + * + * This will not invoke `shouldComponentUpdate`, but it will invoke + * `componentWillUpdate` and `componentDidUpdate`. + * + * @param {ReactClass} publicInstance The instance that should rerender. + * @param {?function} callback Called after component is updated. + * @param {?string} callerName name of the calling function in the public API. + * @internal + */ + enqueueForceUpdate: function (publicInstance, callback, callerName) { + warnNoop(publicInstance, 'forceUpdate'); + }, + + /** + * Replaces all of the state. Always use this or `setState` to mutate state. + * You should treat `this.state` as immutable. + * + * There is no guarantee that `this.state` will be immediately updated, so + * accessing `this.state` after calling this method may return the old value. + * + * @param {ReactClass} publicInstance The instance that should rerender. + * @param {object} completeState Next state. + * @param {?function} callback Called after component is updated. + * @param {?string} callerName name of the calling function in the public API. + * @internal + */ + enqueueReplaceState: function (publicInstance, completeState, callback, callerName) { + warnNoop(publicInstance, 'replaceState'); + }, + + /** + * Sets a subset of the state. This only exists because _pendingState is + * internal. This provides a merging strategy that is not available to deep + * properties which is confusing. TODO: Expose pendingState or don't use it + * during the merge. + * + * @param {ReactClass} publicInstance The instance that should rerender. + * @param {object} partialState Next partial state to be merged with state. + * @param {?function} callback Called after component is updated. + * @param {?string} Name of the calling function in the public API. + * @internal + */ + enqueueSetState: function (publicInstance, partialState, callback, callerName) { + warnNoop(publicInstance, 'setState'); + } +}; + +var assign = Object.assign; + +var emptyObject = {}; + +{ + Object.freeze(emptyObject); +} +/** + * Base class helpers for the updating state of a component. + */ - var pureComponentPrototype = (PureComponent.prototype = - new ComponentDummy()); - pureComponentPrototype.constructor = PureComponent; // Avoid an extra prototype jump for these methods. - assign(pureComponentPrototype, Component.prototype); - pureComponentPrototype.isPureReactComponent = true; +function Component(props, context, updater) { + this.props = props; + this.context = context; // If a component has string refs, we will assign a different object later. - // an immutable object with a single mutable value - function createRef() { - var refObject = { - current: null - }; + this.refs = emptyObject; // We initialize the default updater but the real one gets injected by the + // renderer. - { - Object.seal(refObject); - } + this.updater = updater || ReactNoopUpdateQueue; +} - return refObject; - } +Component.prototype.isReactComponent = {}; +/** + * Sets a subset of the state. Always use this to mutate + * state. You should treat `this.state` as immutable. + * + * There is no guarantee that `this.state` will be immediately updated, so + * accessing `this.state` after calling this method may return the old value. + * + * There is no guarantee that calls to `setState` will run synchronously, + * as they may eventually be batched together. You can provide an optional + * callback that will be executed when the call to setState is actually + * completed. + * + * When a function is provided to setState, it will be called at some point in + * the future (not synchronously). It will be called with the up to date + * component arguments (state, props, context). These values can be different + * from this.* because your function may be called after receiveProps but before + * shouldComponentUpdate, and this new state, props, and context will not yet be + * assigned to this. + * + * @param {object|function} partialState Next partial state or function to + * produce next partial state to be merged with current state. + * @param {?function} callback Called after state is updated. + * @final + * @protected + */ - var isArrayImpl = Array.isArray; // eslint-disable-next-line no-redeclare +Component.prototype.setState = function (partialState, callback) { + if (typeof partialState !== 'object' && typeof partialState !== 'function' && partialState != null) { + throw new Error('takes an object of state variables to update or a ' + 'function which returns an object of state variables.'); + } - function isArray(a) { - return isArrayImpl(a); - } + this.updater.enqueueSetState(this, partialState, callback, 'setState'); +}; +/** + * Forces an update. This should only be invoked when it is known with + * certainty that we are **not** in a DOM transaction. + * + * You may want to call this when you know that some deeper aspect of the + * component's state has changed but `setState` was not called. + * + * This will not invoke `shouldComponentUpdate`, but it will invoke + * `componentWillUpdate` and `componentDidUpdate`. + * + * @param {?function} callback Called after update is complete. + * @final + * @protected + */ - /* - * 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[incompatible-return] 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[incompatible-return] - return type; - } - } // $FlowFixMe[incompatible-return] only called in DEV, so void return is not possible. +Component.prototype.forceUpdate = function (callback) { + this.updater.enqueueForceUpdate(this, callback, 'forceUpdate'); +}; +/** + * Deprecated APIs. These APIs used to exist on classic React classes but since + * we would like to deprecate them, we're not going to move them over to this + * modern base class. Instead, we define a getter that warns if it's accessed. + */ - function willCoercionThrow(value) { - { - try { - testStringCoercion(value); - return false; - } catch (e) { - return true; - } - } - } - 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 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 using it here.", - propName, - typeName(value) - ); - - return testStringCoercion(value); // throw (to help callers find troubleshooting comments) - } - } - } +{ + var deprecatedAPIs = { + isMounted: ['isMounted', 'Instead, make sure to clean up subscriptions and pending requests in ' + 'componentWillUnmount to prevent memory leaks.'], + replaceState: ['replaceState', 'Refactor your code to use setState instead (see ' + 'https://github.com/facebook/react/issues/3236).'] + }; - function getWrappedName$1(outerType, innerType, wrapperName) { - var displayName = outerType.displayName; + var defineDeprecationWarning = function (methodName, info) { + Object.defineProperty(Component.prototype, methodName, { + get: function () { + warn('%s(...) is deprecated in plain JavaScript React classes. %s', info[0], info[1]); - if (displayName) { - return displayName; + return undefined; } + }); + }; - 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"; + for (var fnName in deprecatedAPIs) { + if (deprecatedAPIs.hasOwnProperty(fnName)) { + defineDeprecationWarning(fnName, deprecatedAPIs[fnName]); } + } +} - var REACT_CLIENT_REFERENCE$2 = Symbol.for("react.client.reference"); // Note that the reconciler package should generally prefer to use getComponentNameFromFiber() instead. +function ComponentDummy() {} - function getComponentNameFromType(type) { - if (type == null) { - // Host root, text node or just invalid type. - return null; - } +ComponentDummy.prototype = Component.prototype; +/** + * Convenience component with default shallow equality check for sCU. + */ - if (typeof type === "function") { - if (type.$$typeof === REACT_CLIENT_REFERENCE$2) { - // TODO: Create a convention for naming client references with debug info. - return null; - } +function PureComponent(props, context, updater) { + this.props = props; + this.context = context; // If a component has string refs, we will assign a different object later. - return type.displayName || type.name || null; - } + this.refs = emptyObject; + this.updater = updater || ReactNoopUpdateQueue; +} - if (typeof type === "string") { - return type; - } +var pureComponentPrototype = PureComponent.prototype = new ComponentDummy(); +pureComponentPrototype.constructor = PureComponent; // Avoid an extra prototype jump for these methods. - switch (type) { - case REACT_FRAGMENT_TYPE: - return "Fragment"; +assign(pureComponentPrototype, Component.prototype); +pureComponentPrototype.isPureReactComponent = true; - case REACT_PORTAL_TYPE: - return "Portal"; +// an immutable object with a single mutable value +function createRef() { + var refObject = { + current: null + }; - case REACT_PROFILER_TYPE: - return "Profiler"; + { + Object.seal(refObject); + } - case REACT_STRICT_MODE_TYPE: - return "StrictMode"; + return refObject; +} - case REACT_SUSPENSE_TYPE: - return "Suspense"; +var isArrayImpl = Array.isArray; // eslint-disable-next-line no-redeclare - case REACT_SUSPENSE_LIST_TYPE: - return "SuspenseList"; - } +function isArray(a) { + return isArrayImpl(a); +} - if (typeof type === "object") { - { - if (typeof type.tag === "number") { - error( - "Received an unexpected object in getComponentNameFromType(). " + - "This is likely a bug in React. Please file an issue." - ); - } - } +/* + * 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[incompatible-return] 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[incompatible-return] + + return type; + } +} // $FlowFixMe[incompatible-return] only called in DEV, so void return is not possible. + + +function willCoercionThrow(value) { + { + try { + testStringCoercion(value); + return false; + } catch (e) { + return true; + } + } +} - switch (type.$$typeof) { - case REACT_PROVIDER_TYPE: - if (enableRenderableContext) { - return null; - } else { - var provider = type; - return getContextName$1(provider._context) + ".Provider"; - } +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 using it here.', typeName(value)); - case REACT_CONTEXT_TYPE: - var context = type; + 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 using it here.', propName, typeName(value)); - if (enableRenderableContext) { - return getContextName$1(context) + ".Provider"; - } else { - return getContextName$1(context) + ".Consumer"; - } + return testStringCoercion(value); // throw (to help callers find troubleshooting comments) + } + } +} - case REACT_CONSUMER_TYPE: - if (enableRenderableContext) { - var consumer = type; - return getContextName$1(consumer._context) + ".Consumer"; - } else { - return null; - } +function getWrappedName$1(outerType, innerType, wrapperName) { + var displayName = outerType.displayName; - case REACT_FORWARD_REF_TYPE: - return getWrappedName$1(type, type.render, "ForwardRef"); + if (displayName) { + return displayName; + } - case REACT_MEMO_TYPE: - var outerName = type.displayName || null; + var functionName = innerType.displayName || innerType.name || ''; + return functionName !== '' ? wrapperName + "(" + functionName + ")" : wrapperName; +} // Keep in sync with react-reconciler/getComponentNameFromFiber - if (outerName !== null) { - return outerName; - } - return getComponentNameFromType(type.type) || "Memo"; +function getContextName$1(type) { + return type.displayName || 'Context'; +} - case REACT_LAZY_TYPE: { - var lazyComponent = type; - var payload = lazyComponent._payload; - var init = lazyComponent._init; +var REACT_CLIENT_REFERENCE$2 = Symbol.for('react.client.reference'); // Note that the reconciler package should generally prefer to use getComponentNameFromFiber() instead. - try { - return getComponentNameFromType(init(payload)); - } catch (x) { - return null; - } - } - } - } +function getComponentNameFromType(type) { + if (type == null) { + // Host root, text node or just invalid type. + return null; + } + if (typeof type === 'function') { + if (type.$$typeof === REACT_CLIENT_REFERENCE$2) { + // TODO: Create a convention for naming client references with debug info. return null; } - // $FlowFixMe[method-unbinding] - var hasOwnProperty = Object.prototype.hasOwnProperty; - - var REACT_CLIENT_REFERENCE$1 = Symbol.for("react.client.reference"); - function isValidElementType(type) { - if (typeof type === "string" || typeof type === "function") { - return true; - } // Note: typeof might be other than 'symbol' or 'number' (e.g. if it's a polyfill). - - if ( - type === REACT_FRAGMENT_TYPE || - type === REACT_PROFILER_TYPE || - enableDebugTracing || - type === REACT_STRICT_MODE_TYPE || - type === REACT_SUSPENSE_TYPE || - type === REACT_SUSPENSE_LIST_TYPE || - enableLegacyHidden || - type === REACT_OFFSCREEN_TYPE || - enableScopeAPI || - enableTransitionTracing - ) { - return true; - } - - if (typeof type === "object" && type !== null) { - if ( - type.$$typeof === REACT_LAZY_TYPE || - type.$$typeof === REACT_MEMO_TYPE || - type.$$typeof === REACT_CONTEXT_TYPE || - (!enableRenderableContext && type.$$typeof === REACT_PROVIDER_TYPE) || - (enableRenderableContext && type.$$typeof === REACT_CONSUMER_TYPE) || - type.$$typeof === REACT_FORWARD_REF_TYPE || // This needs to include all possible module reference object - // types supported by any Flight configuration anywhere since - // we don't know which Flight build this will end up being used - // with. - type.$$typeof === REACT_CLIENT_REFERENCE$1 || - type.getModuleId !== undefined - ) { - return true; - } - } + return type.displayName || type.name || null; + } - return false; - } + if (typeof type === 'string') { + return type; + } - // 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; + switch (type) { + case REACT_FRAGMENT_TYPE: + return 'Fragment'; - function disabledLog() {} + case REACT_PORTAL_TYPE: + return 'Portal'; - 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[cannot-write] 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 */ - } + case REACT_PROFILER_TYPE: + return 'Profiler'; - disabledDepth++; - } - } - function reenableLogs() { - { - disabledDepth--; - - if (disabledDepth === 0) { - /* eslint-disable react-internal/no-production-logging */ - var props = { - configurable: true, - enumerable: true, - writable: true - }; // $FlowFixMe[cannot-write] 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 */ - } + case REACT_STRICT_MODE_TYPE: + return 'StrictMode'; - if (disabledDepth < 0) { - error( - "disabledDepth fell below zero. " + - "This is a bug in React. Please file an issue." - ); - } - } - } + case REACT_SUSPENSE_TYPE: + return 'Suspense'; - var prefix; - function describeBuiltInComponentFrame(name) { - if (enableComponentStackLocations) { - if (prefix === undefined) { - // Extract the VM specific prefix used by each line. - try { - throw Error(); - } catch (x) { - var match = x.stack.trim().match(/\n( *(at )?)/); - prefix = (match && match[1]) || ""; - } - } // We use the prefix to ensure our stacks line up with native stack frames. + case REACT_SUSPENSE_LIST_TYPE: + return 'SuspenseList'; - return "\n" + prefix + name; - } else { - return describeComponentFrame(name); - } - } - var reentry = false; - var componentFrameCache; + } + if (typeof type === 'object') { { - var PossiblyWeakMap = typeof WeakMap === "function" ? WeakMap : Map; - componentFrameCache = new PossiblyWeakMap(); - } - /** - * Leverages native browser/VM stack frames to get proper details (e.g. - * filename, line + col number) for a single component in a component stack. We - * do this by: - * (1) throwing and catching an error in the function - this will be our - * control error. - * (2) calling the component which will eventually throw an error that we'll - * catch - this will be our sample error. - * (3) diffing the control and sample error stacks to find the stack frame - * which represents our component. - */ - - function describeNativeComponentFrame(fn, construct) { - // If something asked for a stack inside a fake render, it should get ignored. - if (!fn || reentry) { - return ""; + if (typeof type.tag === 'number') { + error('Received an unexpected object in getComponentNameFromType(). ' + 'This is likely a bug in React. Please file an issue.'); } + } - { - var frame = componentFrameCache.get(fn); - - if (frame !== undefined) { - return frame; + switch (type.$$typeof) { + case REACT_PROVIDER_TYPE: + if (enableRenderableContext) { + return null; + } else { + var provider = type; + return getContextName$1(provider._context) + '.Provider'; } - } - - reentry = true; - var previousPrepareStackTrace = Error.prepareStackTrace; // $FlowFixMe[incompatible-type] It does accept undefined. - Error.prepareStackTrace = undefined; - var previousDispatcher = null; + case REACT_CONTEXT_TYPE: + var context = type; - { - previousDispatcher = ReactSharedInternals.H; // Set the dispatcher in DEV because this might be call in the render function - // for warnings. - - ReactSharedInternals.H = null; - disableLogs(); - } - /** - * Finding a common stack frame between sample and control errors can be - * tricky given the different types and levels of stack trace truncation from - * different JS VMs. So instead we'll attempt to control what that common - * frame should be through this object method: - * Having both the sample and control errors be in the function under the - * `DescribeNativeComponentFrameRoot` property, + setting the `name` and - * `displayName` properties of the function ensures that a stack - * frame exists that has the method name `DescribeNativeComponentFrameRoot` in - * it for both control and sample stacks. - */ - - var RunInRootFrame = { - DetermineComponentFrameRoot: function () { - var control; + if (enableRenderableContext) { + return getContextName$1(context) + '.Provider'; + } else { + return getContextName$1(context) + '.Consumer'; + } - try { - // This should throw. - if (construct) { - // Something should be setting the props in the constructor. - var Fake = function () { - throw Error(); - }; // $FlowFixMe[prop-missing] - - Object.defineProperty(Fake.prototype, "props", { - set: function () { - // We use a throwing setter instead of frozen or non-writable props - // because that won't throw in a non-strict mode function. - throw Error(); - } - }); - - if (typeof Reflect === "object" && Reflect.construct) { - // We construct a different control for this case to include any extra - // frames added by the construct call. - try { - Reflect.construct(Fake, []); - } catch (x) { - control = x; - } + case REACT_CONSUMER_TYPE: + if (enableRenderableContext) { + var consumer = type; + return getContextName$1(consumer._context) + '.Consumer'; + } else { + return null; + } - Reflect.construct(fn, [], Fake); - } else { - try { - Fake.call(); - } catch (x) { - control = x; - } // $FlowFixMe[prop-missing] found when upgrading Flow + case REACT_FORWARD_REF_TYPE: + return getWrappedName$1(type, type.render, 'ForwardRef'); - fn.call(Fake.prototype); - } - } else { - try { - throw Error(); - } catch (x) { - control = x; - } // TODO(luna): This will currently only throw if the function component - // tries to access React/ReactDOM/props. We should probably make this throw - // in simple components too - - var maybePromise = fn(); // If the function component returns a promise, it's likely an async - // component, which we don't yet support. Attach a noop catch handler to - // silence the error. - // TODO: Implement component stacks for async client components? - - if (maybePromise && typeof maybePromise.catch === "function") { - maybePromise.catch(function () {}); - } - } - } catch (sample) { - // This is inlined manually because closure doesn't do it for us. - if (sample && control && typeof sample.stack === "string") { - return [sample.stack, control.stack]; - } - } + case REACT_MEMO_TYPE: + var outerName = type.displayName || null; - return [null, null]; + if (outerName !== null) { + return outerName; } - }; // $FlowFixMe[prop-missing] - - RunInRootFrame.DetermineComponentFrameRoot.displayName = - "DetermineComponentFrameRoot"; - var namePropDescriptor = Object.getOwnPropertyDescriptor( - RunInRootFrame.DetermineComponentFrameRoot, - "name" - ); // Before ES6, the `name` property was not configurable. - - if (namePropDescriptor && namePropDescriptor.configurable) { - // V8 utilizes a function's `name` property when generating a stack trace. - Object.defineProperty( - RunInRootFrame.DetermineComponentFrameRoot, // Configurable properties can be updated even if its writable descriptor - // is set to `false`. - // $FlowFixMe[cannot-write] - "name", - { - value: "DetermineComponentFrameRoot" - } - ); - } - - try { - var _RunInRootFrame$Deter = - RunInRootFrame.DetermineComponentFrameRoot(), - sampleStack = _RunInRootFrame$Deter[0], - controlStack = _RunInRootFrame$Deter[1]; - - if (sampleStack && controlStack) { - // This extracts the first frame from the sample that isn't also in the control. - // Skipping one frame that we assume is the frame that calls the two. - var sampleLines = sampleStack.split("\n"); - var controlLines = controlStack.split("\n"); - var s = 0; - var c = 0; - - while ( - s < sampleLines.length && - !sampleLines[s].includes("DetermineComponentFrameRoot") - ) { - s++; - } - while ( - c < controlLines.length && - !controlLines[c].includes("DetermineComponentFrameRoot") - ) { - c++; - } // We couldn't find our intentionally injected common root frame, attempt - // to find another common root frame by search from the bottom of the - // control stack... - - if (s === sampleLines.length || c === controlLines.length) { - s = sampleLines.length - 1; - c = controlLines.length - 1; - - while (s >= 1 && c >= 0 && sampleLines[s] !== controlLines[c]) { - // We expect at least one stack frame to be shared. - // Typically this will be the root most one. However, stack frames may be - // cut off due to maximum stack limits. In this case, one maybe cut off - // earlier than the other. We assume that the sample is longer or the same - // and there for cut off earlier. So we should find the root most frame in - // the sample somewhere in the control. - c--; - } - } + return getComponentNameFromType(type.type) || 'Memo'; - for (; s >= 1 && c >= 0; s--, c--) { - // Next we find the first one that isn't the same which should be the - // frame that called our sample function and the control. - if (sampleLines[s] !== controlLines[c]) { - // In V8, the first line is describing the message but other VMs don't. - // If we're about to return the first line, and the control is also on the same - // line, that's a pretty good indicator that our sample threw at same line as - // the control. I.e. before we entered the sample frame. So we ignore this result. - // This can happen if you passed a class to function component, or non-function. - if (s !== 1 || c !== 1) { - do { - s--; - c--; // We may still have similar intermediate frames from the construct call. - // The next one that isn't the same should be our match though. - - if (c < 0 || sampleLines[s] !== controlLines[c]) { - // V8 adds a "new" prefix for native classes. Let's remove it to make it prettier. - var _frame = - "\n" + sampleLines[s].replace(" at new ", " at "); // If our component frame is labeled "" - // but we have a user-provided "displayName" - // splice it in to make the stack more readable. - - if (fn.displayName && _frame.includes("")) { - _frame = _frame.replace("", fn.displayName); - } - - if (true) { - if (typeof fn === "function") { - componentFrameCache.set(fn, _frame); - } - } // Return the line we found. - - return _frame; - } - } while (s >= 1 && c >= 0); - } + case REACT_LAZY_TYPE: + { + var lazyComponent = type; + var payload = lazyComponent._payload; + var init = lazyComponent._init; - break; - } + try { + return getComponentNameFromType(init(payload)); + } catch (x) { + return null; } } - } finally { - reentry = false; + } + } - { - ReactSharedInternals.H = previousDispatcher; - reenableLogs(); - } + return null; +} - Error.prepareStackTrace = previousPrepareStackTrace; - } // Fallback to just using the name if we couldn't make it throw. +// $FlowFixMe[method-unbinding] +var hasOwnProperty = Object.prototype.hasOwnProperty; - var name = fn ? fn.displayName || fn.name : ""; - var syntheticFrame = name ? describeBuiltInComponentFrame(name) : ""; +var REACT_CLIENT_REFERENCE$1 = Symbol.for('react.client.reference'); +function isValidElementType(type) { + if (typeof type === 'string' || typeof type === 'function') { + return true; + } // Note: typeof might be other than 'symbol' or 'number' (e.g. if it's a polyfill). - { - if (typeof fn === "function") { - componentFrameCache.set(fn, syntheticFrame); - } - } - return syntheticFrame; - } + if (type === REACT_FRAGMENT_TYPE || type === REACT_PROFILER_TYPE || enableDebugTracing || type === REACT_STRICT_MODE_TYPE || type === REACT_SUSPENSE_TYPE || type === REACT_SUSPENSE_LIST_TYPE || enableLegacyHidden || type === REACT_OFFSCREEN_TYPE || enableScopeAPI || enableTransitionTracing ) { + return true; + } - function describeComponentFrame(name) { - return "\n in " + (name || "Unknown"); + if (typeof type === 'object' && type !== null) { + if (type.$$typeof === REACT_LAZY_TYPE || type.$$typeof === REACT_MEMO_TYPE || type.$$typeof === REACT_CONTEXT_TYPE || !enableRenderableContext && type.$$typeof === REACT_PROVIDER_TYPE || enableRenderableContext && type.$$typeof === REACT_CONSUMER_TYPE || type.$$typeof === REACT_FORWARD_REF_TYPE || // This needs to include all possible module reference object + // types supported by any Flight configuration anywhere since + // we don't know which Flight build this will end up being used + // with. + type.$$typeof === REACT_CLIENT_REFERENCE$1 || type.getModuleId !== undefined) { + return true; } - function describeFunctionComponentFrame(fn) { - if (enableComponentStackLocations) { - return describeNativeComponentFrame(fn, false); - } else { - if (!fn) { - return ""; - } + } - var name = fn.displayName || fn.name || null; - return describeComponentFrame(name); - } + return false; +} + +// 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[cannot-write] 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 */ } - function shouldConstruct(Component) { - var prototype = Component.prototype; - return !!(prototype && prototype.isReactComponent); + disabledDepth++; + } +} +function reenableLogs() { + { + disabledDepth--; + + if (disabledDepth === 0) { + /* eslint-disable react-internal/no-production-logging */ + var props = { + configurable: true, + enumerable: true, + writable: true + }; // $FlowFixMe[cannot-write] 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 */ } - function describeUnknownElementTypeFrameInDEV(type) { - if (type == null) { - return ""; - } + if (disabledDepth < 0) { + error('disabledDepth fell below zero. ' + 'This is a bug in React. Please file an issue.'); + } + } +} - if (typeof type === "function") { - if (enableComponentStackLocations) { - return describeNativeComponentFrame(type, shouldConstruct(type)); - } else { - return describeFunctionComponentFrame(type); - } +var prefix; +function describeBuiltInComponentFrame(name) { + if (enableComponentStackLocations) { + if (prefix === undefined) { + // Extract the VM specific prefix used by each line. + try { + throw Error(); + } catch (x) { + var match = x.stack.trim().match(/\n( *(at )?)/); + prefix = match && match[1] || ''; } + } // We use the prefix to ensure our stacks line up with native stack frames. - if (typeof type === "string") { - return describeBuiltInComponentFrame(type); - } - switch (type) { - case REACT_SUSPENSE_TYPE: - return describeBuiltInComponentFrame("Suspense"); + return '\n' + prefix + name; + } else { + return describeComponentFrame(name); + } +} +var reentry = false; +var componentFrameCache; - case REACT_SUSPENSE_LIST_TYPE: - return describeBuiltInComponentFrame("SuspenseList"); - } +{ + var PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map; + componentFrameCache = new PossiblyWeakMap(); +} +/** + * Leverages native browser/VM stack frames to get proper details (e.g. + * filename, line + col number) for a single component in a component stack. We + * do this by: + * (1) throwing and catching an error in the function - this will be our + * control error. + * (2) calling the component which will eventually throw an error that we'll + * catch - this will be our sample error. + * (3) diffing the control and sample error stacks to find the stack frame + * which represents our component. + */ - if (typeof type === "object") { - switch (type.$$typeof) { - case REACT_FORWARD_REF_TYPE: - return describeFunctionComponentFrame(type.render); - case REACT_MEMO_TYPE: - // Memo may contain any component type so we recursively resolve it. - return describeUnknownElementTypeFrameInDEV(type.type); +function describeNativeComponentFrame(fn, construct) { + // If something asked for a stack inside a fake render, it should get ignored. + if (!fn || reentry) { + return ''; + } - case REACT_LAZY_TYPE: { - var lazyComponent = type; - var payload = lazyComponent._payload; - var init = lazyComponent._init; + { + var frame = componentFrameCache.get(fn); - try { - // Lazy may contain any component type so we recursively resolve it. - return describeUnknownElementTypeFrameInDEV(init(payload)); - } catch (x) {} - } - } - } + if (frame !== undefined) { + return frame; + } + } - return ""; - } - - var FunctionComponent = 0; - var ClassComponent = 1; - var HostRoot = 3; // Root of a host tree. Could be nested inside another node. - - var HostPortal = 4; // A subtree. Could be an entry point to a different renderer. - - var HostComponent = 5; - var HostText = 6; - var Fragment = 7; - var Mode = 8; - var ContextConsumer = 9; - var ContextProvider = 10; - var ForwardRef = 11; - var Profiler = 12; - var SuspenseComponent = 13; - var MemoComponent = 14; - var SimpleMemoComponent = 15; - var LazyComponent = 16; - var IncompleteClassComponent = 17; - var DehydratedFragment = 18; - var SuspenseListComponent = 19; - var ScopeComponent = 21; - var OffscreenComponent = 22; - var CacheComponent = 24; - var TracingMarkerComponent = 25; - var HostHoistable = 26; - var HostSingleton = 27; - var IncompleteFunctionComponent = 28; - - 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"; - } - function getComponentNameFromFiber(fiber) { - var tag = fiber.tag, - type = fiber.type; - - switch (tag) { - case CacheComponent: - return "Cache"; - - case ContextConsumer: - if (enableRenderableContext) { - var consumer = type; - return getContextName(consumer._context) + ".Consumer"; - } else { - var context = type; - return getContextName(context) + ".Consumer"; - } + reentry = true; + var previousPrepareStackTrace = Error.prepareStackTrace; // $FlowFixMe[incompatible-type] It does accept undefined. - case ContextProvider: - if (enableRenderableContext) { - var _context = type; - return getContextName(_context) + ".Provider"; - } else { - var provider = type; - return getContextName(provider._context) + ".Provider"; - } + Error.prepareStackTrace = undefined; + var previousDispatcher = null; - case DehydratedFragment: - return "DehydratedFragment"; + { + previousDispatcher = ReactSharedInternals.H; // Set the dispatcher in DEV because this might be call in the render function + // for warnings. - case ForwardRef: - return getWrappedName(type, type.render, "ForwardRef"); + ReactSharedInternals.H = null; + disableLogs(); + } + /** + * Finding a common stack frame between sample and control errors can be + * tricky given the different types and levels of stack trace truncation from + * different JS VMs. So instead we'll attempt to control what that common + * frame should be through this object method: + * Having both the sample and control errors be in the function under the + * `DescribeNativeComponentFrameRoot` property, + setting the `name` and + * `displayName` properties of the function ensures that a stack + * frame exists that has the method name `DescribeNativeComponentFrameRoot` in + * it for both control and sample stacks. + */ - case Fragment: - return "Fragment"; - case HostHoistable: - case HostSingleton: - case HostComponent: - // Host component type is the display name (e.g. "div", "View") - return type; + var RunInRootFrame = { + DetermineComponentFrameRoot: function () { + var control; - case HostPortal: - return "Portal"; + try { + // This should throw. + if (construct) { + // Something should be setting the props in the constructor. + var Fake = function () { + throw Error(); + }; // $FlowFixMe[prop-missing] - case HostRoot: - return "Root"; - case HostText: - return "Text"; + Object.defineProperty(Fake.prototype, 'props', { + set: function () { + // We use a throwing setter instead of frozen or non-writable props + // because that won't throw in a non-strict mode function. + throw Error(); + } + }); - case LazyComponent: - // Name comes from the type in this case; we don't have a tag. - return getComponentNameFromType(type); + if (typeof Reflect === 'object' && Reflect.construct) { + // We construct a different control for this case to include any extra + // frames added by the construct call. + try { + Reflect.construct(Fake, []); + } catch (x) { + control = x; + } - case Mode: - if (type === REACT_STRICT_MODE_TYPE) { - // Don't be less specific than shared/getComponentNameFromType - return "StrictMode"; - } - - return "Mode"; + Reflect.construct(fn, [], Fake); + } else { + try { + Fake.call(); + } catch (x) { + control = x; + } // $FlowFixMe[prop-missing] found when upgrading Flow - case OffscreenComponent: - return "Offscreen"; - case Profiler: - return "Profiler"; + fn.call(Fake.prototype); + } + } else { + try { + throw Error(); + } catch (x) { + control = x; + } // TODO(luna): This will currently only throw if the function component + // tries to access React/ReactDOM/props. We should probably make this throw + // in simple components too - case ScopeComponent: - return "Scope"; - case SuspenseComponent: - return "Suspense"; + var maybePromise = fn(); // If the function component returns a promise, it's likely an async + // component, which we don't yet support. Attach a noop catch handler to + // silence the error. + // TODO: Implement component stacks for async client components? - case SuspenseListComponent: - return "SuspenseList"; + if (maybePromise && typeof maybePromise.catch === 'function') { + maybePromise.catch(function () {}); + } + } + } catch (sample) { + // This is inlined manually because closure doesn't do it for us. + if (sample && control && typeof sample.stack === 'string') { + return [sample.stack, control.stack]; + } + } - case TracingMarkerComponent: - return "TracingMarker"; - // The display name for these tags come from the user-provided type: + return [null, null]; + } + }; // $FlowFixMe[prop-missing] - case IncompleteClassComponent: - case IncompleteFunctionComponent: + RunInRootFrame.DetermineComponentFrameRoot.displayName = 'DetermineComponentFrameRoot'; + var namePropDescriptor = Object.getOwnPropertyDescriptor(RunInRootFrame.DetermineComponentFrameRoot, 'name'); // Before ES6, the `name` property was not configurable. - // Fallthrough + if (namePropDescriptor && namePropDescriptor.configurable) { + // V8 utilizes a function's `name` property when generating a stack trace. + Object.defineProperty(RunInRootFrame.DetermineComponentFrameRoot, // Configurable properties can be updated even if its writable descriptor + // is set to `false`. + // $FlowFixMe[cannot-write] + 'name', { + value: 'DetermineComponentFrameRoot' + }); + } - case ClassComponent: - case FunctionComponent: - case MemoComponent: - case SimpleMemoComponent: - if (typeof type === "function") { - return type.displayName || type.name || null; - } + try { + var _RunInRootFrame$Deter = RunInRootFrame.DetermineComponentFrameRoot(), + sampleStack = _RunInRootFrame$Deter[0], + controlStack = _RunInRootFrame$Deter[1]; - if (typeof type === "string") { - return type; - } + if (sampleStack && controlStack) { + // This extracts the first frame from the sample that isn't also in the control. + // Skipping one frame that we assume is the frame that calls the two. + var sampleLines = sampleStack.split('\n'); + var controlLines = controlStack.split('\n'); + var s = 0; + var c = 0; - break; + while (s < sampleLines.length && !sampleLines[s].includes('DetermineComponentFrameRoot')) { + s++; } - return null; - } - - var REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference"); - var specialPropKeyWarningShown; - var specialPropRefWarningShown; - var didWarnAboutStringRefs; - var didWarnAboutOldJSXRuntime; + while (c < controlLines.length && !controlLines[c].includes('DetermineComponentFrameRoot')) { + c++; + } // We couldn't find our intentionally injected common root frame, attempt + // to find another common root frame by search from the bottom of the + // control stack... - { - didWarnAboutStringRefs = {}; - } - function hasValidRef(config) { - { - if (hasOwnProperty.call(config, "ref")) { - var getter = Object.getOwnPropertyDescriptor(config, "ref").get; + if (s === sampleLines.length || c === controlLines.length) { + s = sampleLines.length - 1; + c = controlLines.length - 1; - if (getter && getter.isReactWarning) { - return false; - } + while (s >= 1 && c >= 0 && sampleLines[s] !== controlLines[c]) { + // We expect at least one stack frame to be shared. + // Typically this will be the root most one. However, stack frames may be + // cut off due to maximum stack limits. In this case, one maybe cut off + // earlier than the other. We assume that the sample is longer or the same + // and there for cut off earlier. So we should find the root most frame in + // the sample somewhere in the control. + c--; } } - return config.ref !== undefined; - } + for (; s >= 1 && c >= 0; s--, c--) { + // Next we find the first one that isn't the same which should be the + // frame that called our sample function and the control. + if (sampleLines[s] !== controlLines[c]) { + // In V8, the first line is describing the message but other VMs don't. + // If we're about to return the first line, and the control is also on the same + // line, that's a pretty good indicator that our sample threw at same line as + // the control. I.e. before we entered the sample frame. So we ignore this result. + // This can happen if you passed a class to function component, or non-function. + if (s !== 1 || c !== 1) { + do { + s--; + c--; // We may still have similar intermediate frames from the construct call. + // The next one that isn't the same should be our match though. - function hasValidKey(config) { - { - if (hasOwnProperty.call(config, "key")) { - var getter = Object.getOwnPropertyDescriptor(config, "key").get; + if (c < 0 || sampleLines[s] !== controlLines[c]) { + // V8 adds a "new" prefix for native classes. Let's remove it to make it prettier. + var _frame = '\n' + sampleLines[s].replace(' at new ', ' at '); // If our component frame is labeled "" + // but we have a user-provided "displayName" + // splice it in to make the stack more readable. - if (getter && getter.isReactWarning) { - return false; - } - } - } - return config.key !== undefined; - } + if (fn.displayName && _frame.includes('')) { + _frame = _frame.replace('', fn.displayName); + } - function warnIfStringRefCannotBeAutoConverted(config, self) { - { - if ( - typeof config.ref === "string" && - ReactSharedInternals.owner && - self && - ReactSharedInternals.owner.stateNode !== self - ) { - var componentName = getComponentNameFromType( - ReactSharedInternals.owner.type - ); - - if (!didWarnAboutStringRefs[componentName]) { - error( - 'Component "%s" contains the string ref "%s". ' + - "Support for string refs will be removed in a future major release. " + - "This case cannot be automatically converted to an arrow function. " + - "We ask you to manually fix this case by using useRef() or createRef() instead. " + - "Learn more about using refs safely here: " + - "https://react.dev/link/strict-mode-string-ref", - getComponentNameFromType(ReactSharedInternals.owner.type), - config.ref - ); - - didWarnAboutStringRefs[componentName] = true; + if (true) { + if (typeof fn === 'function') { + componentFrameCache.set(fn, _frame); + } + } // Return the line we found. + + + return _frame; + } + } while (s >= 1 && c >= 0); } + + break; } } } + } finally { + reentry = false; - function defineKeyPropWarningGetter(props, displayName) { - { - var warnAboutAccessingKey = function () { - if (!specialPropKeyWarningShown) { - specialPropKeyWarningShown = true; - - error( - "%s: `key` is not a prop. Trying to access it will result " + - "in `undefined` being returned. If you need to access the same " + - "value within the child component, you should pass it as a different " + - "prop. (https://react.dev/link/special-props)", - displayName - ); - } - }; - - warnAboutAccessingKey.isReactWarning = true; - Object.defineProperty(props, "key", { - get: warnAboutAccessingKey, - configurable: true - }); - } + { + ReactSharedInternals.H = previousDispatcher; + reenableLogs(); } - function defineRefPropWarningGetter(props, displayName) { - { - { - var warnAboutAccessingRef = function () { - if (!specialPropRefWarningShown) { - specialPropRefWarningShown = true; - - error( - "%s: `ref` is not a prop. Trying to access it will result " + - "in `undefined` being returned. If you need to access the same " + - "value within the child component, you should pass it as a different " + - "prop. (https://react.dev/link/special-props)", - displayName - ); - } - }; + Error.prepareStackTrace = previousPrepareStackTrace; + } // Fallback to just using the name if we couldn't make it throw. - warnAboutAccessingRef.isReactWarning = true; - Object.defineProperty(props, "ref", { - get: warnAboutAccessingRef, - configurable: true - }); - } - } + + var name = fn ? fn.displayName || fn.name : ''; + var syntheticFrame = name ? describeBuiltInComponentFrame(name) : ''; + + { + if (typeof fn === 'function') { + componentFrameCache.set(fn, syntheticFrame); } - /** - * Factory method to create a new React element. This no longer adheres to - * the class pattern, so do not use new to call it. Also, instanceof check - * will not work. Instead test $$typeof field against Symbol.for('react.element') to check - * if something is a React Element. - * - * @param {*} type - * @param {*} props - * @param {*} key - * @param {string|object} ref - * @param {*} owner - * @param {*} self A *temporary* helper to detect places where `this` is - * different from the `owner` when React.createElement is called, so that we - * can warn. We want to get rid of owner and replace string `ref`s with arrow - * functions, and as long as `this` and owner are the same, there will be no - * change in behavior. - * @param {*} source An annotation object (added by a transpiler or otherwise) - * indicating filename, line number, and/or other information. - * @internal - */ - - function ReactElement(type, key, _ref, self, source, owner, props) { - var ref; + } - { - ref = _ref; - } + return syntheticFrame; +} - var element; +function describeComponentFrame(name) { + return '\n in ' + (name || 'Unknown'); +} +function describeFunctionComponentFrame(fn) { + if (enableComponentStackLocations) { + return describeNativeComponentFrame(fn, false); + } else { + if (!fn) { + return ''; + } - { - // In prod, `ref` is a regular property. It will be removed in a - // future release. - element = { - // This tag allows us to uniquely identify this as a React Element - $$typeof: REACT_ELEMENT_TYPE, - // Built-in properties that belong on the element - type: type, - key: key, - ref: ref, - props: props, - // Record the component responsible for creating this element. - _owner: owner - }; - } + var name = fn.displayName || fn.name || null; + return describeComponentFrame(name); + } +} - { - // The validation flag is currently mutative. We put it on - // an external backing store so that we can freeze the whole object. - // This can be replaced with a WeakMap once they are implemented in - // commonly used development environments. - element._store = {}; // To make comparing ReactElements easier for testing purposes, we make - // the validation flag non-enumerable (where possible, which should - // include every environment we run tests in), so the test framework - // ignores it. - - Object.defineProperty(element._store, "validated", { - configurable: false, - enumerable: false, - writable: true, - value: false - }); // debugInfo contains Server Component debug information. - - Object.defineProperty(element, "_debugInfo", { - configurable: false, - enumerable: false, - writable: true, - value: null - }); +function shouldConstruct(Component) { + var prototype = Component.prototype; + return !!(prototype && prototype.isReactComponent); +} - if (Object.freeze) { - Object.freeze(element.props); - Object.freeze(element); - } - } +function describeUnknownElementTypeFrameInDEV(type) { - return element; - } - // support `jsx` and `jsxs` when running in development. This supports the case - // where a third-party dependency ships code that was compiled for production; - // we want to still provide warnings in development. - // - // So these functions are the _dev_ implementations of the _production_ - // API signatures. - // - // Since these functions are dev-only, it's ok to add an indirection here. They - // only exist to provide different versions of `isStaticChildren`. (We shouldn't - // use this pattern for the prod versions, though, because it will add an call - // frame.) - - function jsxProdSignatureRunningInDevWithDynamicChildren( - type, - config, - maybeKey, - source, - self - ) { - { - var isStaticChildren = false; - return jsxDEV$1(type, config, maybeKey, isStaticChildren, source, self); - } - } - function jsxProdSignatureRunningInDevWithStaticChildren( - type, - config, - maybeKey, - source, - self - ) { - { - var isStaticChildren = true; - return jsxDEV$1(type, config, maybeKey, isStaticChildren, source, self); - } - } - var didWarnAboutKeySpread = {}; - /** - * https://github.com/reactjs/rfcs/pull/107 - * @param {*} type - * @param {object} props - * @param {string} key - */ + if (type == null) { + return ''; + } - function jsxDEV$1(type, config, maybeKey, isStaticChildren, source, self) { - { - if (!isValidElementType(type)) { - // This is an invalid element type. - // - // We warn in this case but don't throw. We expect the element creation to - // succeed and there will likely be errors in render. - var info = ""; - - 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 (typeof type === 'function') { + if (enableComponentStackLocations) { + return describeNativeComponentFrame(type, shouldConstruct(type)); + } else { + return describeFunctionComponentFrame(type); + } + } - var typeString; - - if (type === null) { - typeString = "null"; - } else if (isArray(type)) { - typeString = "array"; - } else if ( - type !== undefined && - type.$$typeof === REACT_ELEMENT_TYPE - ) { - typeString = - "<" + (getComponentNameFromType(type.type) || "Unknown") + " />"; - info = - " Did you accidentally export a JSX literal instead of a component?"; - } else { - typeString = typeof type; - } + if (typeof type === 'string') { + return describeBuiltInComponentFrame(type); + } - error( - "React.jsx: type is invalid -- expected a string (for " + - "built-in components) or a class/function (for composite " + - "components) but got: %s.%s", - typeString, - info - ); - } else { - // This is a valid element type. - // Skip key warning if the type isn't valid since our key validation logic - // doesn't expect a non-string/function type and can throw confusing - // errors. We don't want exception behavior to differ between dev and - // prod. (Rendering will throw with a helpful message and as soon as the - // type is fixed, the key warnings will appear.) - var children = config.children; - - if (children !== undefined) { - if (isStaticChildren) { - if (isArray(children)) { - for (var i = 0; i < children.length; i++) { - validateChildKeys(children[i], type); - } + switch (type) { + case REACT_SUSPENSE_TYPE: + return describeBuiltInComponentFrame('Suspense'); - if (Object.freeze) { - Object.freeze(children); - } - } else { - error( - "React.jsx: Static children should always be an array. " + - "You are likely explicitly calling React.jsxs or React.jsxDEV. " + - "Use the Babel transform instead." - ); - } - } else { - validateChildKeys(children, type); - } - } - } // Warn about key spread regardless of whether the type is valid. + case REACT_SUSPENSE_LIST_TYPE: + return describeBuiltInComponentFrame('SuspenseList'); + } - if (hasOwnProperty.call(config, "key")) { - var componentName = getComponentNameFromType(type); - var keys = Object.keys(config).filter(function (k) { - return k !== "key"; - }); - var beforeExample = - keys.length > 0 - ? "{key: someKey, " + keys.join(": ..., ") + ": ...}" - : "{key: someKey}"; - - if (!didWarnAboutKeySpread[componentName + beforeExample]) { - var afterExample = - keys.length > 0 ? "{" + keys.join(": ..., ") + ": ...}" : "{}"; - - error( - 'A props object containing a "key" prop is being spread into JSX:\n' + - " let props = %s;\n" + - " <%s {...props} />\n" + - "React keys must be passed directly to JSX without using spread:\n" + - " let props = %s;\n" + - " <%s key={someKey} {...props} />", - beforeExample, - componentName, - afterExample, - componentName - ); - - didWarnAboutKeySpread[componentName + beforeExample] = true; - } - } + if (typeof type === 'object') { + switch (type.$$typeof) { + case REACT_FORWARD_REF_TYPE: + return describeFunctionComponentFrame(type.render); - var key = null; - var ref = null; // Currently, key can be spread in as a prop. This causes a potential - // issue if key is also explicitly declared (ie.
- // or
). We want to deprecate key spread, - // but as an intermediary step, we will use jsxDEV for everything except - //
, because we aren't currently able to tell if - // key is explicitly declared to be undefined or not. + case REACT_MEMO_TYPE: + // Memo may contain any component type so we recursively resolve it. + return describeUnknownElementTypeFrameInDEV(type.type); - if (maybeKey !== undefined) { - { - checkKeyStringCoercion(maybeKey); - } + case REACT_LAZY_TYPE: + { + var lazyComponent = type; + var payload = lazyComponent._payload; + var init = lazyComponent._init; - key = "" + maybeKey; + try { + // Lazy may contain any component type so we recursively resolve it. + return describeUnknownElementTypeFrameInDEV(init(payload)); + } catch (x) {} } + } + } - if (hasValidKey(config)) { - { - checkKeyStringCoercion(config.key); - } + return ''; +} - key = "" + config.key; - } +var FunctionComponent = 0; +var ClassComponent = 1; +var HostRoot = 3; // Root of a host tree. Could be nested inside another node. + +var HostPortal = 4; // A subtree. Could be an entry point to a different renderer. + +var HostComponent = 5; +var HostText = 6; +var Fragment = 7; +var Mode = 8; +var ContextConsumer = 9; +var ContextProvider = 10; +var ForwardRef = 11; +var Profiler = 12; +var SuspenseComponent = 13; +var MemoComponent = 14; +var SimpleMemoComponent = 15; +var LazyComponent = 16; +var IncompleteClassComponent = 17; +var DehydratedFragment = 18; +var SuspenseListComponent = 19; +var ScopeComponent = 21; +var OffscreenComponent = 22; +var CacheComponent = 24; +var TracingMarkerComponent = 25; +var HostHoistable = 26; +var HostSingleton = 27; +var IncompleteFunctionComponent = 28; + +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'; +} +function getComponentNameFromFiber(fiber) { + var tag = fiber.tag, + type = fiber.type; - if (hasValidRef(config)) { - { - ref = config.ref; + switch (tag) { + case CacheComponent: + return 'Cache'; - { - ref = coerceStringRef(ref, ReactSharedInternals.owner, type); - } - } + case ContextConsumer: + if (enableRenderableContext) { + var consumer = type; + return getContextName(consumer._context) + '.Consumer'; + } else { + var context = type; + return getContextName(context) + '.Consumer'; + } - { - warnIfStringRefCannotBeAutoConverted(config, self); - } - } + case ContextProvider: + if (enableRenderableContext) { + var _context = type; + return getContextName(_context) + '.Provider'; + } else { + var provider = type; + return getContextName(provider._context) + '.Provider'; + } - var props; + case DehydratedFragment: + return 'DehydratedFragment'; - { - // We need to remove reserved props (key, prop, ref). Create a fresh props - // object and copy over all the non-reserved props. We don't use `delete` - // because in V8 it will deopt the object to dictionary mode. - props = {}; - - for (var propName in config) { - // Skip over reserved prop names - if (propName !== "key" && propName !== "ref") { - { - props[propName] = config[propName]; - } - } - } - } + case ForwardRef: + return getWrappedName(type, type.render, 'ForwardRef'); - if (!disableDefaultPropsExceptForClasses) { - // Resolve default props - if (type && type.defaultProps) { - var defaultProps = type.defaultProps; + case Fragment: + return 'Fragment'; - for (var _propName2 in defaultProps) { - if (props[_propName2] === undefined) { - props[_propName2] = defaultProps[_propName2]; - } - } - } - } + case HostHoistable: + case HostSingleton: + case HostComponent: + // Host component type is the display name (e.g. "div", "View") + return type; - if (key || ref) { - var displayName = - typeof type === "function" - ? type.displayName || type.name || "Unknown" - : type; + case HostPortal: + return 'Portal'; - if (key) { - defineKeyPropWarningGetter(props, displayName); - } + case HostRoot: + return 'Root'; - if (ref) { - defineRefPropWarningGetter(props, displayName); - } - } + case HostText: + return 'Text'; - var element = ReactElement( - type, - key, - ref, - self, - source, - ReactSharedInternals.owner, - props - ); - - if (type === REACT_FRAGMENT_TYPE) { - validateFragmentProps(element); - } + case LazyComponent: + // Name comes from the type in this case; we don't have a tag. + return getComponentNameFromType(type); - return element; + case Mode: + if (type === REACT_STRICT_MODE_TYPE) { + // Don't be less specific than shared/getComponentNameFromType + return 'StrictMode'; } - } - /** - * Create and return a new ReactElement of the given type. - * See https://reactjs.org/docs/react-api.html#createelement - */ - function createElement(type, config, children) { - { - if (!isValidElementType(type)) { - // This is an invalid element type. - // - // We warn in this case but don't throw. We expect the element creation to - // succeed and there will likely be errors in render. - var info = ""; - - 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."; - } + return 'Mode'; - var typeString; - - if (type === null) { - typeString = "null"; - } else if (isArray(type)) { - typeString = "array"; - } else if ( - type !== undefined && - type.$$typeof === REACT_ELEMENT_TYPE - ) { - typeString = - "<" + (getComponentNameFromType(type.type) || "Unknown") + " />"; - info = - " Did you accidentally export a JSX literal instead of a component?"; - } else { - typeString = typeof type; - } + case OffscreenComponent: + return 'Offscreen'; - error( - "React.createElement: type is invalid -- expected a string (for " + - "built-in components) or a class/function (for composite " + - "components) but got: %s.%s", - typeString, - info - ); - } else { - // This is a valid element type. - // Skip key warning if the type isn't valid since our key validation logic - // doesn't expect a non-string/function type and can throw confusing - // errors. We don't want exception behavior to differ between dev and - // prod. (Rendering will throw with a helpful message and as soon as the - // type is fixed, the key warnings will appear.) - for (var i = 2; i < arguments.length; i++) { - validateChildKeys(arguments[i], type); - } - } // Unlike the jsx() runtime, createElement() doesn't warn about key spread. - } + case Profiler: + return 'Profiler'; - var propName; // Reserved names are extracted + case ScopeComponent: + return 'Scope'; - var props = {}; - var key = null; - var ref = null; + case SuspenseComponent: + return 'Suspense'; - if (config != null) { - { - if ( - !didWarnAboutOldJSXRuntime && - "__self" in config && // Do not assume this is the result of an oudated JSX transform if key - // is present, because the modern JSX transform sometimes outputs - // createElement to preserve precedence between a static key and a - // spread key. To avoid false positive warnings, we never warn if - // there's a key. - !("key" in config) - ) { - didWarnAboutOldJSXRuntime = true; - - warn( - "Your app (or one of its dependencies) is using an outdated JSX " + - "transform. Update to the modern JSX transform for " + - "faster performance: " + // TODO: Create a short link for this - "https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html" - ); - } - } + case SuspenseListComponent: + return 'SuspenseList'; - if (hasValidRef(config)) { - { - ref = config.ref; + case TracingMarkerComponent: + return 'TracingMarker'; + // The display name for these tags come from the user-provided type: - { - ref = coerceStringRef(ref, ReactSharedInternals.owner, type); - } - } + case IncompleteClassComponent: + case IncompleteFunctionComponent: - { - warnIfStringRefCannotBeAutoConverted(config, config.__self); - } - } + // Fallthrough - if (hasValidKey(config)) { - { - checkKeyStringCoercion(config.key); - } + case ClassComponent: + case FunctionComponent: + case MemoComponent: + case SimpleMemoComponent: + if (typeof type === 'function') { + return type.displayName || type.name || null; + } - key = "" + config.key; - } // Remaining properties are added to a new props object - - for (propName in config) { - if ( - hasOwnProperty.call(config, propName) && // Skip over reserved prop names - propName !== "key" && - propName !== "ref" && // Even though we don't use these anymore in the runtime, we don't want - // them to appear as props, so in createElement we filter them out. - // We don't have to do this in the jsx() runtime because the jsx() - // transform never passed these as props; it used separate arguments. - propName !== "__self" && - propName !== "__source" - ) { - { - props[propName] = config[propName]; - } - } - } - } // Children can be more than one argument, and those are transferred onto - // the newly allocated props object. + if (typeof type === 'string') { + return type; + } - var childrenLength = arguments.length - 2; + break; - if (childrenLength === 1) { - props.children = children; - } else if (childrenLength > 1) { - var childArray = Array(childrenLength); + } - for (var _i = 0; _i < childrenLength; _i++) { - childArray[_i] = arguments[_i + 2]; - } + return null; +} - { - if (Object.freeze) { - Object.freeze(childArray); - } - } +var REACT_CLIENT_REFERENCE = Symbol.for('react.client.reference'); +var specialPropKeyWarningShown; +var specialPropRefWarningShown; +var didWarnAboutStringRefs; +var didWarnAboutOldJSXRuntime; - props.children = childArray; - } // Resolve default props +{ + didWarnAboutStringRefs = {}; +} - if (type && type.defaultProps) { - var defaultProps = type.defaultProps; +function hasValidRef(config) { + { + if (hasOwnProperty.call(config, 'ref')) { + var getter = Object.getOwnPropertyDescriptor(config, 'ref').get; - for (propName in defaultProps) { - if (props[propName] === undefined) { - props[propName] = defaultProps[propName]; - } - } + if (getter && getter.isReactWarning) { + return false; } + } + } - { - if (key || ref) { - var displayName = - typeof type === "function" - ? type.displayName || type.name || "Unknown" - : type; - - if (key) { - defineKeyPropWarningGetter(props, displayName); - } + return config.ref !== undefined; +} - if (ref) { - defineRefPropWarningGetter(props, displayName); - } - } +function hasValidKey(config) { + { + if (hasOwnProperty.call(config, 'key')) { + var getter = Object.getOwnPropertyDescriptor(config, 'key').get; + + if (getter && getter.isReactWarning) { + return false; } + } + } - var element = ReactElement( - type, - key, - ref, - undefined, - undefined, - ReactSharedInternals.owner, - props - ); + return config.key !== undefined; +} - if (type === REACT_FRAGMENT_TYPE) { - validateFragmentProps(element); - } +function warnIfStringRefCannotBeAutoConverted(config, self) { + { + if (typeof config.ref === 'string' && ReactSharedInternals.owner && self && ReactSharedInternals.owner.stateNode !== self) { + var componentName = getComponentNameFromType(ReactSharedInternals.owner.type); - return element; - } - function cloneAndReplaceKey(oldElement, newKey) { - return ReactElement( - oldElement.type, - newKey, // When enableRefAsProp is on, this argument is ignored. This check only - // exists to avoid the `ref` access warning. - oldElement.ref, - undefined, - undefined, - oldElement._owner, - oldElement.props - ); - } - /** - * Clone and return a new ReactElement using element as the starting point. - * See https://reactjs.org/docs/react-api.html#cloneelement - */ + if (!didWarnAboutStringRefs[componentName]) { + error('Component "%s" contains the string ref "%s". ' + 'Support for string refs will be removed in a future major release. ' + 'This case cannot be automatically converted to an arrow function. ' + 'We ask you to manually fix this case by using useRef() or createRef() instead. ' + 'Learn more about using refs safely here: ' + 'https://react.dev/link/strict-mode-string-ref', getComponentNameFromType(ReactSharedInternals.owner.type), config.ref); - function cloneElement(element, config, children) { - if (element === null || element === undefined) { - throw new Error( - "The argument must be a React element, but you passed " + - element + - "." - ); + didWarnAboutStringRefs[componentName] = true; } + } + } +} - var propName; // Original props are copied +function defineKeyPropWarningGetter(props, displayName) { + { + var warnAboutAccessingKey = function () { + if (!specialPropKeyWarningShown) { + specialPropKeyWarningShown = true; - var props = assign({}, element.props); // Reserved names are extracted + error('%s: `key` is not a prop. Trying to access it will result ' + 'in `undefined` being returned. If you need to access the same ' + 'value within the child component, you should pass it as a different ' + 'prop. (https://react.dev/link/special-props)', displayName); + } + }; - var key = element.key; - var ref = element.ref; // Owner will be preserved, unless ref is overridden + warnAboutAccessingKey.isReactWarning = true; + Object.defineProperty(props, 'key', { + get: warnAboutAccessingKey, + configurable: true + }); + } +} - var owner = element._owner; +function defineRefPropWarningGetter(props, displayName) { + { + { + var warnAboutAccessingRef = function () { + if (!specialPropRefWarningShown) { + specialPropRefWarningShown = true; - if (config != null) { - if (hasValidRef(config)) { - owner = ReactSharedInternals.owner; + error('%s: `ref` is not a prop. Trying to access it will result ' + 'in `undefined` being returned. If you need to access the same ' + 'value within the child component, you should pass it as a different ' + 'prop. (https://react.dev/link/special-props)', displayName); + } + }; - { - // Silently steal the ref from the parent. - ref = config.ref; + warnAboutAccessingRef.isReactWarning = true; + Object.defineProperty(props, 'ref', { + get: warnAboutAccessingRef, + configurable: true + }); + } + } +} +/** + * Factory method to create a new React element. This no longer adheres to + * the class pattern, so do not use new to call it. Also, instanceof check + * will not work. Instead test $$typeof field against Symbol.for('react.element') to check + * if something is a React Element. + * + * @param {*} type + * @param {*} props + * @param {*} key + * @param {string|object} ref + * @param {*} owner + * @param {*} self A *temporary* helper to detect places where `this` is + * different from the `owner` when React.createElement is called, so that we + * can warn. We want to get rid of owner and replace string `ref`s with arrow + * functions, and as long as `this` and owner are the same, there will be no + * change in behavior. + * @param {*} source An annotation object (added by a transpiler or otherwise) + * indicating filename, line number, and/or other information. + * @internal + */ - { - ref = coerceStringRef(ref, owner, element.type); - } - } - } - if (hasValidKey(config)) { - { - checkKeyStringCoercion(config.key); - } +function ReactElement(type, key, _ref, self, source, owner, props) { + var ref; + + { + ref = _ref; + } + + var element; + + { + // In prod, `ref` is a regular property. It will be removed in a + // future release. + element = { + // This tag allows us to uniquely identify this as a React Element + $$typeof: REACT_ELEMENT_TYPE, + // Built-in properties that belong on the element + type: type, + key: key, + ref: ref, + props: props, + // Record the component responsible for creating this element. + _owner: owner + }; + } + + { + // The validation flag is currently mutative. We put it on + // an external backing store so that we can freeze the whole object. + // This can be replaced with a WeakMap once they are implemented in + // commonly used development environments. + element._store = {}; // To make comparing ReactElements easier for testing purposes, we make + // the validation flag non-enumerable (where possible, which should + // include every environment we run tests in), so the test framework + // ignores it. + + Object.defineProperty(element._store, 'validated', { + configurable: false, + enumerable: false, + writable: true, + value: false + }); // debugInfo contains Server Component debug information. + + Object.defineProperty(element, '_debugInfo', { + configurable: false, + enumerable: false, + writable: true, + value: null + }); + + if (Object.freeze) { + Object.freeze(element.props); + Object.freeze(element); + } + } + + return element; +} +// support `jsx` and `jsxs` when running in development. This supports the case +// where a third-party dependency ships code that was compiled for production; +// we want to still provide warnings in development. +// +// So these functions are the _dev_ implementations of the _production_ +// API signatures. +// +// Since these functions are dev-only, it's ok to add an indirection here. They +// only exist to provide different versions of `isStaticChildren`. (We shouldn't +// use this pattern for the prod versions, though, because it will add an call +// frame.) + +function jsxProdSignatureRunningInDevWithDynamicChildren(type, config, maybeKey, source, self) { + { + var isStaticChildren = false; + return jsxDEV$1(type, config, maybeKey, isStaticChildren, source, self); + } +} +function jsxProdSignatureRunningInDevWithStaticChildren(type, config, maybeKey, source, self) { + { + var isStaticChildren = true; + return jsxDEV$1(type, config, maybeKey, isStaticChildren, source, self); + } +} +var didWarnAboutKeySpread = {}; +/** + * https://github.com/reactjs/rfcs/pull/107 + * @param {*} type + * @param {object} props + * @param {string} key + */ + +function jsxDEV$1(type, config, maybeKey, isStaticChildren, source, self) { + { + if (!isValidElementType(type)) { + // This is an invalid element type. + // + // We warn in this case but don't throw. We expect the element creation to + // succeed and there will likely be errors in render. + var info = ''; - key = "" + config.key; - } // Remaining properties override existing props + 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 defaultProps; + var typeString; - if ( - !disableDefaultPropsExceptForClasses && - element.type && - element.type.defaultProps - ) { - defaultProps = element.type.defaultProps; - } + if (type === null) { + typeString = 'null'; + } else if (isArray(type)) { + typeString = 'array'; + } else if (type !== undefined && type.$$typeof === REACT_ELEMENT_TYPE) { + typeString = "<" + (getComponentNameFromType(type.type) || 'Unknown') + " />"; + info = ' Did you accidentally export a JSX literal instead of a component?'; + } else { + typeString = typeof type; + } + + error('React.jsx: type is invalid -- expected a string (for ' + 'built-in components) or a class/function (for composite ' + 'components) but got: %s.%s', typeString, info); + } else { + // This is a valid element type. + // Skip key warning if the type isn't valid since our key validation logic + // doesn't expect a non-string/function type and can throw confusing + // errors. We don't want exception behavior to differ between dev and + // prod. (Rendering will throw with a helpful message and as soon as the + // type is fixed, the key warnings will appear.) + var children = config.children; + + if (children !== undefined) { + if (isStaticChildren) { + if (isArray(children)) { + for (var i = 0; i < children.length; i++) { + validateChildKeys(children[i], type); + } - for (propName in config) { - if ( - hasOwnProperty.call(config, propName) && // Skip over reserved prop names - propName !== "key" && - propName !== "ref" && // ...and maybe these, too, though we currently rely on them for - // warnings and debug information in dev. Need to decide if we're OK - // with dropping them. In the jsx() runtime it's not an issue because - // the data gets passed as separate arguments instead of props, but - // it would be nice to stop relying on them entirely so we can drop - // them from the internal Fiber field. - propName !== "__self" && - propName !== "__source" && // Undefined `ref` is ignored by cloneElement. We treat it the same as - // if the property were missing. This is mostly for - // backwards compatibility. - !enableRefAsProp - ) { - if ( - !disableDefaultPropsExceptForClasses && - config[propName] === undefined && - defaultProps !== undefined - ) { - // Resolve default props - props[propName] = defaultProps[propName]; - } else { - { - props[propName] = config[propName]; - } + if (Object.freeze) { + Object.freeze(children); } + } else { + error('React.jsx: Static children should always be an array. ' + 'You are likely explicitly calling React.jsxs or React.jsxDEV. ' + 'Use the Babel transform instead.'); } + } else { + validateChildKeys(children, type); } - } // Children can be more than one argument, and those are transferred onto - // the newly allocated props object. + } + } // Warn about key spread regardless of whether the type is valid. - var childrenLength = arguments.length - 2; - if (childrenLength === 1) { - props.children = children; - } else if (childrenLength > 1) { - var childArray = Array(childrenLength); + if (hasOwnProperty.call(config, 'key')) { + var componentName = getComponentNameFromType(type); + var keys = Object.keys(config).filter(function (k) { + return k !== 'key'; + }); + var beforeExample = keys.length > 0 ? '{key: someKey, ' + keys.join(': ..., ') + ': ...}' : '{key: someKey}'; - for (var i = 0; i < childrenLength; i++) { - childArray[i] = arguments[i + 2]; - } + if (!didWarnAboutKeySpread[componentName + beforeExample]) { + var afterExample = keys.length > 0 ? '{' + keys.join(': ..., ') + ': ...}' : '{}'; - props.children = childArray; + error('A props object containing a "key" prop is being spread into JSX:\n' + ' let props = %s;\n' + ' <%s {...props} />\n' + 'React keys must be passed directly to JSX without using spread:\n' + ' let props = %s;\n' + ' <%s key={someKey} {...props} />', beforeExample, componentName, afterExample, componentName); + + didWarnAboutKeySpread[componentName + beforeExample] = true; } + } - var clonedElement = ReactElement( - element.type, - key, - ref, - undefined, - undefined, - owner, - props - ); + var key = null; + var ref = null; // Currently, key can be spread in as a prop. This causes a potential + // issue if key is also explicitly declared (ie.
+ // or
). We want to deprecate key spread, + // but as an intermediary step, we will use jsxDEV for everything except + //
, because we aren't currently able to tell if + // key is explicitly declared to be undefined or not. - for (var _i2 = 2; _i2 < arguments.length; _i2++) { - validateChildKeys(arguments[_i2], clonedElement.type); + if (maybeKey !== undefined) { + { + checkKeyStringCoercion(maybeKey); } - return clonedElement; + key = '' + maybeKey; } - function getDeclarationErrorAddendum() { + if (hasValidKey(config)) { { - if (ReactSharedInternals.owner) { - var name = getComponentNameFromType(ReactSharedInternals.owner.type); - - if (name) { - return "\n\nCheck the render method of `" + name + "`."; - } - } - - return ""; + checkKeyStringCoercion(config.key); } + + key = '' + config.key; } - /** - * Ensure that every element either is passed in a static location, in an - * array with an explicit keys property defined, or in an object literal - * with valid key property. - * - * @internal - * @param {ReactNode} node Statically passed child of any type. - * @param {*} parentType node's parent's type. - */ - function validateChildKeys(node, parentType) { + if (hasValidRef(config)) { { - if (typeof node !== "object" || !node) { - return; + ref = config.ref; + + { + ref = coerceStringRef(ref, ReactSharedInternals.owner, type); } + } - if (node.$$typeof === REACT_CLIENT_REFERENCE); - else if (isArray(node)) { - for (var i = 0; i < node.length; i++) { - var child = node[i]; + { + warnIfStringRefCannotBeAutoConverted(config, self); + } + } - if (isValidElement(child)) { - validateExplicitKey(child, parentType); - } - } - } else if (isValidElement(node)) { - // This element was passed in a valid location. - if (node._store) { - node._store.validated = true; - } - } else { - var iteratorFn = getIteratorFn(node); - - if (typeof iteratorFn === "function") { - // Entry iterators used to provide implicit keys, - // but now we print a separate warning for them later. - if (iteratorFn !== node.entries) { - var iterator = iteratorFn.call(node); - var step; - - while (!(step = iterator.next()).done) { - if (isValidElement(step.value)) { - validateExplicitKey(step.value, parentType); - } - } - } + var props; + + { + // We need to remove reserved props (key, prop, ref). Create a fresh props + // object and copy over all the non-reserved props. We don't use `delete` + // because in V8 it will deopt the object to dictionary mode. + props = {}; + + for (var propName in config) { + // Skip over reserved prop names + if (propName !== 'key' && (propName !== 'ref')) { + { + props[propName] = config[propName]; } } } } - /** - * Verifies the object is a ReactElement. - * See https://reactjs.org/docs/react-api.html#isvalidelement - * @param {?object} object - * @return {boolean} True if `object` is a ReactElement. - * @final - */ - - function isValidElement(object) { - return ( - typeof object === "object" && - object !== null && - object.$$typeof === REACT_ELEMENT_TYPE - ); - } - var ownerHasKeyUseWarning = {}; - /** - * Warn if the element doesn't have an explicit key assigned to it. - * This element is in an array. The array could grow and shrink or be - * reordered. All children that haven't already been validated are required to - * have a "key" property assigned to it. Error statuses are cached so a warning - * will only be shown once. - * - * @internal - * @param {ReactElement} element Element that requires a key. - * @param {*} parentType element's parent's type. - */ - - function validateExplicitKey(element, parentType) { - { - if ( - !element._store || - element._store.validated || - element.key != null - ) { - return; - } - element._store.validated = true; - var currentComponentErrorInfo = - getCurrentComponentErrorInfo(parentType); + if (!disableDefaultPropsExceptForClasses) { + // Resolve default props + if (type && type.defaultProps) { + var defaultProps = type.defaultProps; - if (ownerHasKeyUseWarning[currentComponentErrorInfo]) { - return; + for (var _propName2 in defaultProps) { + if (props[_propName2] === undefined) { + props[_propName2] = defaultProps[_propName2]; + } } + } + } - ownerHasKeyUseWarning[currentComponentErrorInfo] = true; // Usually the current owner is the offender, but if it accepts children as a - // property, it may be the creator of the child that's responsible for - // assigning it a key. - - var childOwner = ""; + if (key || ref) { + var displayName = typeof type === 'function' ? type.displayName || type.name || 'Unknown' : type; - if ( - element && - element._owner != null && - element._owner !== ReactSharedInternals.owner - ) { - var ownerName = null; + if (key) { + defineKeyPropWarningGetter(props, displayName); + } - if (typeof element._owner.tag === "number") { - ownerName = getComponentNameFromType(element._owner.type); - } else if (typeof element._owner.name === "string") { - ownerName = element._owner.name; - } // Give the component that originally created this child. + if (ref) { + defineRefPropWarningGetter(props, displayName); + } + } - childOwner = " It was passed a child from " + ownerName + "."; - } + var element = ReactElement(type, key, ref, self, source, ReactSharedInternals.owner, props); - setCurrentlyValidatingElement(element); + if (type === REACT_FRAGMENT_TYPE) { + validateFragmentProps(element); + } - error( - 'Each child in a list should have a unique "key" prop.' + - "%s%s See https://react.dev/link/warning-keys for more information.", - currentComponentErrorInfo, - childOwner - ); + return element; + } +} +/** + * Create and return a new ReactElement of the given type. + * See https://reactjs.org/docs/react-api.html#createelement + */ - setCurrentlyValidatingElement(null); +function createElement(type, config, children) { + { + if (!isValidElementType(type)) { + // This is an invalid element type. + // + // We warn in this case but don't throw. We expect the element creation to + // succeed and there will likely be errors in render. + var info = ''; + + 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."; } - } - function setCurrentlyValidatingElement(element) { - { - if (element) { - var stack = describeUnknownElementTypeFrameInDEV(element.type); - ReactSharedInternals.setExtraStackFrame(stack); - } else { - ReactSharedInternals.setExtraStackFrame(null); - } + var typeString; + + if (type === null) { + typeString = 'null'; + } else if (isArray(type)) { + typeString = 'array'; + } else if (type !== undefined && type.$$typeof === REACT_ELEMENT_TYPE) { + typeString = "<" + (getComponentNameFromType(type.type) || 'Unknown') + " />"; + info = ' Did you accidentally export a JSX literal instead of a component?'; + } else { + typeString = typeof type; } - } - function getCurrentComponentErrorInfo(parentType) { - { - var info = getDeclarationErrorAddendum(); + error('React.createElement: type is invalid -- expected a string (for ' + 'built-in components) or a class/function (for composite ' + 'components) but got: %s.%s', typeString, info); + } else { + // This is a valid element type. + // Skip key warning if the type isn't valid since our key validation logic + // doesn't expect a non-string/function type and can throw confusing + // errors. We don't want exception behavior to differ between dev and + // prod. (Rendering will throw with a helpful message and as soon as the + // type is fixed, the key warnings will appear.) + for (var i = 2; i < arguments.length; i++) { + validateChildKeys(arguments[i], type); + } + } // Unlike the jsx() runtime, createElement() doesn't warn about key spread. - if (!info) { - var parentName = getComponentNameFromType(parentType); + } - if (parentName) { - info = - "\n\nCheck the top-level render call using <" + parentName + ">."; - } - } + var propName; // Reserved names are extracted + + var props = {}; + var key = null; + var ref = null; + + if (config != null) { + { + if (!didWarnAboutOldJSXRuntime && '__self' in config && // Do not assume this is the result of an oudated JSX transform if key + // is present, because the modern JSX transform sometimes outputs + // createElement to preserve precedence between a static key and a + // spread key. To avoid false positive warnings, we never warn if + // there's a key. + !('key' in config)) { + didWarnAboutOldJSXRuntime = true; - return info; + warn('Your app (or one of its dependencies) is using an outdated JSX ' + 'transform. Update to the modern JSX transform for ' + 'faster performance: ' + // TODO: Create a short link for this + 'https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html'); } } - /** - * Given a fragment, validate that it can only be provided with fragment props - * @param {ReactElement} fragment - */ - function validateFragmentProps(fragment) { - // TODO: Move this to render phase instead of at element creation. + if (hasValidRef(config)) { { - var keys = Object.keys(fragment.props); + ref = config.ref; - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - - if (key !== "children" && key !== "key") { - setCurrentlyValidatingElement(fragment); + { + ref = coerceStringRef(ref, ReactSharedInternals.owner, type); + } + } - error( - "Invalid prop `%s` supplied to `React.Fragment`. " + - "React.Fragment can only have `key` and `children` props.", - key - ); + { + warnIfStringRefCannotBeAutoConverted(config, config.__self); + } + } - setCurrentlyValidatingElement(null); - break; - } - } + if (hasValidKey(config)) { + { + checkKeyStringCoercion(config.key); + } - if (fragment.ref !== null) { - setCurrentlyValidatingElement(fragment); + key = '' + config.key; + } // Remaining properties are added to a new props object - error("Invalid attribute `ref` supplied to `React.Fragment`."); - setCurrentlyValidatingElement(null); + for (propName in config) { + if (hasOwnProperty.call(config, propName) && // Skip over reserved prop names + propName !== 'key' && (propName !== 'ref') && // Even though we don't use these anymore in the runtime, we don't want + // them to appear as props, so in createElement we filter them out. + // We don't have to do this in the jsx() runtime because the jsx() + // transform never passed these as props; it used separate arguments. + propName !== '__self' && propName !== '__source') { + { + props[propName] = config[propName]; } } } + } // Children can be more than one argument, and those are transferred onto + // the newly allocated props object. - function coerceStringRef(mixedRef, owner, type) { - var stringRef; - - if (typeof mixedRef === "string") { - stringRef = mixedRef; - } else { - if (typeof mixedRef === "number" || typeof mixedRef === "boolean") { - { - checkPropStringCoercion(mixedRef, "ref"); - } - stringRef = "" + mixedRef; - } else { - return mixedRef; - } - } + var childrenLength = arguments.length - 2; - var callback = stringRefAsCallbackRef.bind(null, stringRef, type, owner); // This is used to check whether two callback refs conceptually represent - // the same string ref, and can therefore be reused by the reconciler. Needed - // for backwards compatibility with old Meta code that relies on string refs - // not being reattached on every render. + if (childrenLength === 1) { + props.children = children; + } else if (childrenLength > 1) { + var childArray = Array(childrenLength); - callback.__stringRef = stringRef; - callback.__type = type; - callback.__owner = owner; - return callback; + for (var _i = 0; _i < childrenLength; _i++) { + childArray[_i] = arguments[_i + 2]; } - function stringRefAsCallbackRef(stringRef, type, owner, value) { - if (!owner) { - throw new Error( - "Element ref was specified as a string (" + - stringRef + - ") 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://react.dev/link/refs-must-have-owner for more information." - ); + { + if (Object.freeze) { + Object.freeze(childArray); } + } - if (owner.tag !== ClassComponent) { - throw new Error( - "Function components cannot have string refs. " + - "We recommend using useRef() instead. " + - "Learn more about using refs safely here: " + - "https://react.dev/link/strict-mode-string-ref" - ); - } + props.children = childArray; + } // Resolve default props - { - if ( - // Will already warn with "Function components cannot be given refs" - !(typeof type === "function" && !isReactClass(type)) - ) { - var componentName = getComponentNameFromFiber(owner) || "Component"; - - 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://react.dev/link/strict-mode-string-ref", - componentName, - stringRef - ); - - didWarnAboutStringRefs[componentName] = true; - } - } - } - var inst = owner.stateNode; + if (type && type.defaultProps) { + var defaultProps = type.defaultProps; - if (!inst) { - throw new Error( - "Missing owner for string ref " + - stringRef + - ". This error is likely caused by a " + - "bug in React. Please file an issue." - ); + for (propName in defaultProps) { + if (props[propName] === undefined) { + props[propName] = defaultProps[propName]; } + } + } - var refs = inst.refs; + { + if (key || ref) { + var displayName = typeof type === 'function' ? type.displayName || type.name || 'Unknown' : type; - if (value === null) { - delete refs[stringRef]; - } else { - refs[stringRef] = value; + if (key) { + defineKeyPropWarningGetter(props, displayName); } - } - function isReactClass(type) { - return type.prototype && type.prototype.isReactComponent; + if (ref) { + defineRefPropWarningGetter(props, displayName); + } } + } - var SEPARATOR = "."; - var SUBSEPARATOR = ":"; - /** - * Escape and wrap key so it is safe to use as a reactid - * - * @param {string} key to be escaped. - * @return {string} the escaped key. - */ + var element = ReactElement(type, key, ref, undefined, undefined, ReactSharedInternals.owner, props); - function escape(key) { - var escapeRegex = /[=:]/g; - var escaperLookup = { - "=": "=0", - ":": "=2" - }; - var escapedString = key.replace(escapeRegex, function (match) { - return escaperLookup[match]; - }); - return "$" + escapedString; - } - /** - * TODO: Test that a single child and an array with one item have the same key - * pattern. - */ - - var didWarnAboutMaps = false; - var userProvidedKeyEscapeRegex = /\/+/g; - - function escapeUserProvidedKey(text) { - return text.replace(userProvidedKeyEscapeRegex, "$&/"); - } - /** - * Generate a key string that identifies a element within a set. - * - * @param {*} element A element that could contain a manual key. - * @param {number} index Index that is used if a manual key is not provided. - * @return {string} - */ - - function getElementKey(element, index) { - // Do some typechecking here since we call this blindly. We want to ensure - // that we don't block potential future ES APIs. - if ( - typeof element === "object" && - element !== null && - element.key != null - ) { - // Explicit key - { - checkKeyStringCoercion(element.key); - } + if (type === REACT_FRAGMENT_TYPE) { + validateFragmentProps(element); + } - return escape("" + element.key); - } // Implicit key determined by the index in the set + return element; +} +function cloneAndReplaceKey(oldElement, newKey) { + return ReactElement(oldElement.type, newKey, // When enableRefAsProp is on, this argument is ignored. This check only + // exists to avoid the `ref` access warning. + oldElement.ref, undefined, undefined, oldElement._owner, oldElement.props); +} +/** + * Clone and return a new ReactElement using element as the starting point. + * See https://reactjs.org/docs/react-api.html#cloneelement + */ - return index.toString(36); - } +function cloneElement(element, config, children) { + if (element === null || element === undefined) { + throw new Error("The argument must be a React element, but you passed " + element + "."); + } - function noop$1() {} + var propName; // Original props are copied - function resolveThenable(thenable) { - switch (thenable.status) { - case "fulfilled": { - var fulfilledValue = thenable.value; - return fulfilledValue; - } + var props = assign({}, element.props); // Reserved names are extracted - case "rejected": { - var rejectedError = thenable.reason; - throw rejectedError; - } + var key = element.key; + var ref = element.ref; // Owner will be preserved, unless ref is overridden - 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 { - // This is an uncached thenable that we haven't seen before. - // TODO: Detect infinite ping loops caused by uncached promises. - 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. + var owner = element._owner; - switch (thenable.status) { - case "fulfilled": { - var fulfilledThenable = thenable; - return fulfilledThenable.value; - } + if (config != null) { + if (hasValidRef(config)) { + owner = ReactSharedInternals.owner; - case "rejected": { - var rejectedThenable = thenable; - var _rejectedError = rejectedThenable.reason; - throw _rejectedError; - } - } + { + // Silently steal the ref from the parent. + ref = config.ref; + + { + ref = coerceStringRef(ref, owner, element.type); } } - - throw thenable; } - function mapIntoArray(children, array, escapedPrefix, nameSoFar, callback) { - var type = typeof children; - - if (type === "undefined" || type === "boolean") { - // All of the above are perceived as null. - children = null; + if (hasValidKey(config)) { + { + checkKeyStringCoercion(config.key); } - var invokeCallback = false; + key = '' + config.key; + } // Remaining properties override existing props - if (children === null) { - invokeCallback = true; - } else { - switch (type) { - case "bigint": - case "string": - case "number": - invokeCallback = true; - break; - case "object": - switch (children.$$typeof) { - case REACT_ELEMENT_TYPE: - case REACT_PORTAL_TYPE: - invokeCallback = true; - break; - - case REACT_LAZY_TYPE: - var payload = children._payload; - var init = children._init; - return mapIntoArray( - init(payload), - array, - escapedPrefix, - nameSoFar, - callback - ); - } + var defaultProps; + + if (!disableDefaultPropsExceptForClasses && element.type && element.type.defaultProps) { + defaultProps = element.type.defaultProps; + } + + for (propName in config) { + if (hasOwnProperty.call(config, propName) && // Skip over reserved prop names + propName !== 'key' && (propName !== 'ref') && // ...and maybe these, too, though we currently rely on them for + // warnings and debug information in dev. Need to decide if we're OK + // with dropping them. In the jsx() runtime it's not an issue because + // the data gets passed as separate arguments instead of props, but + // it would be nice to stop relying on them entirely so we can drop + // them from the internal Fiber field. + propName !== '__self' && propName !== '__source' && // Undefined `ref` is ignored by cloneElement. We treat it the same as + // if the property were missing. This is mostly for + // backwards compatibility. + !(enableRefAsProp )) { + if (!disableDefaultPropsExceptForClasses && config[propName] === undefined && defaultProps !== undefined) { + // Resolve default props + props[propName] = defaultProps[propName]; + } else { + { + props[propName] = config[propName]; + } } } + } + } // Children can be more than one argument, and those are transferred onto + // the newly allocated props object. - if (invokeCallback) { - var _child = children; - var mappedChild = callback(_child); // If it's the only child, treat the name as if it was wrapped in an array - // so that it's consistent if the number of children grows: - var childKey = - nameSoFar === "" ? SEPARATOR + getElementKey(_child, 0) : nameSoFar; + var childrenLength = arguments.length - 2; - if (isArray(mappedChild)) { - var escapedChildKey = ""; + if (childrenLength === 1) { + props.children = children; + } else if (childrenLength > 1) { + var childArray = Array(childrenLength); - if (childKey != null) { - escapedChildKey = escapeUserProvidedKey(childKey) + "/"; - } + for (var i = 0; i < childrenLength; i++) { + childArray[i] = arguments[i + 2]; + } - mapIntoArray(mappedChild, array, escapedChildKey, "", function (c) { - return c; - }); - } else if (mappedChild != null) { - if (isValidElement(mappedChild)) { - { - // The `if` statement here prevents auto-disabling of the safe - // coercion ESLint rule, so we must manually disable it below. - // $FlowFixMe[incompatible-type] Flow incorrectly thinks React.Portal doesn't have a key - if ( - mappedChild.key && - (!_child || _child.key !== mappedChild.key) - ) { - checkKeyStringCoercion(mappedChild.key); - } - } + props.children = childArray; + } - mappedChild = cloneAndReplaceKey( - mappedChild, // Keep both the (mapped) and old keys if they differ, just as - // traverseAllChildren used to do for objects as children - escapedPrefix + // $FlowFixMe[incompatible-type] Flow incorrectly thinks React.Portal doesn't have a key - (mappedChild.key && (!_child || _child.key !== mappedChild.key) - ? escapeUserProvidedKey( - // $FlowFixMe[unsafe-addition] - "" + mappedChild.key // eslint-disable-line react-internal/safe-string-coercion - ) + "/" - : "") + - childKey - ); - } + var clonedElement = ReactElement(element.type, key, ref, undefined, undefined, owner, props); - array.push(mappedChild); - } + for (var _i2 = 2; _i2 < arguments.length; _i2++) { + validateChildKeys(arguments[_i2], clonedElement.type); + } - return 1; - } + return clonedElement; +} - var child; - var nextName; - var subtreeCount = 0; // Count of children found in the current subtree. +function getDeclarationErrorAddendum() { + { + if (ReactSharedInternals.owner) { + var name = getComponentNameFromType(ReactSharedInternals.owner.type); - var nextNamePrefix = - nameSoFar === "" ? SEPARATOR : nameSoFar + SUBSEPARATOR; + if (name) { + return '\n\nCheck the render method of `' + name + '`.'; + } + } - if (isArray(children)) { - for (var i = 0; i < children.length; i++) { - child = children[i]; - nextName = nextNamePrefix + getElementKey(child, i); - subtreeCount += mapIntoArray( - child, - array, - escapedPrefix, - nextName, - callback - ); - } - } else { - var iteratorFn = getIteratorFn(children); + return ''; + } +} +/** + * Ensure that every element either is passed in a static location, in an + * array with an explicit keys property defined, or in an object literal + * with valid key property. + * + * @internal + * @param {ReactNode} node Statically passed child of any type. + * @param {*} parentType node's parent's type. + */ - if (typeof iteratorFn === "function") { - var iterableChildren = children; - { - // Warn about using Maps as children - if (iteratorFn === iterableChildren.entries) { - if (!didWarnAboutMaps) { - warn( - "Using Maps as children is not supported. " + - "Use an array of keyed ReactElements instead." - ); - } +function validateChildKeys(node, parentType) { + { + if (typeof node !== 'object' || !node) { + return; + } - didWarnAboutMaps = true; - } - } + if (node.$$typeof === REACT_CLIENT_REFERENCE) ; else if (isArray(node)) { + for (var i = 0; i < node.length; i++) { + var child = node[i]; - var iterator = iteratorFn.call(iterableChildren); + if (isValidElement(child)) { + validateExplicitKey(child, parentType); + } + } + } else if (isValidElement(node)) { + // This element was passed in a valid location. + if (node._store) { + node._store.validated = true; + } + } else { + var iteratorFn = getIteratorFn(node); + + if (typeof iteratorFn === 'function') { + // Entry iterators used to provide implicit keys, + // but now we print a separate warning for them later. + if (iteratorFn !== node.entries) { + var iterator = iteratorFn.call(node); var step; - var ii = 0; // $FlowFixMe[incompatible-use] `iteratorFn` might return null according to typing. while (!(step = iterator.next()).done) { - child = step.value; - nextName = nextNamePrefix + getElementKey(child, ii++); - subtreeCount += mapIntoArray( - child, - array, - escapedPrefix, - nextName, - callback - ); + if (isValidElement(step.value)) { + validateExplicitKey(step.value, parentType); + } } - } else if (type === "object") { - if (typeof children.then === "function") { - return mapIntoArray( - resolveThenable(children), - array, - escapedPrefix, - nameSoFar, - callback - ); - } // eslint-disable-next-line react-internal/safe-string-coercion - - var childrenString = String(children); - throw new Error( - "Objects are not valid as a React child (found: " + - (childrenString === "[object Object]" - ? "object with keys {" + Object.keys(children).join(", ") + "}" - : childrenString) + - "). " + - "If you meant to render a collection of children, use an array " + - "instead." - ); } } + } + } +} +/** + * Verifies the object is a ReactElement. + * See https://reactjs.org/docs/react-api.html#isvalidelement + * @param {?object} object + * @return {boolean} True if `object` is a ReactElement. + * @final + */ - return subtreeCount; - } - /** - * Maps children that are typically specified as `props.children`. - * - * See https://reactjs.org/docs/react-api.html#reactchildrenmap - * - * The provided mapFunction(child, index) will be called for each - * leaf child. - * - * @param {?*} children Children tree container. - * @param {function(*, int)} func The map function. - * @param {*} context Context for mapFunction. - * @return {object} Object containing the ordered map of results. - */ - - function mapChildren(children, func, context) { - if (children == null) { - // $FlowFixMe limitation refining abstract types in Flow - return children; - } - - var result = []; - var count = 0; - mapIntoArray(children, result, "", "", function (child) { - return func.call(context, child, count++); - }); - return result; - } - /** - * Count the number of children that are typically specified as - * `props.children`. - * - * See https://reactjs.org/docs/react-api.html#reactchildrencount - * - * @param {?*} children Children tree container. - * @return {number} The number of children. - */ - - function countChildren(children) { - var n = 0; - mapChildren(children, function () { - n++; // Don't return anything - }); - return n; - } - /** - * Iterates through children that are typically specified as `props.children`. - * - * See https://reactjs.org/docs/react-api.html#reactchildrenforeach - * - * The provided forEachFunc(child, index) will be called for each - * leaf child. - * - * @param {?*} children Children tree container. - * @param {function(*, int)} forEachFunc - * @param {*} forEachContext Context for forEachContext. - */ - - function forEachChildren(children, forEachFunc, forEachContext) { - mapChildren( - children, // $FlowFixMe[missing-this-annot] - function () { - forEachFunc.apply(this, arguments); // Don't return anything. - }, - forEachContext - ); - } - /** - * Flatten a children object (typically specified as `props.children`) and - * return an array with appropriately re-keyed children. - * - * See https://reactjs.org/docs/react-api.html#reactchildrentoarray - */ - - function toArray(children) { - return ( - mapChildren(children, function (child) { - return child; - }) || [] - ); - } - /** - * Returns the first child in a collection of children and verifies that there - * is only one child in the collection. - * - * See https://reactjs.org/docs/react-api.html#reactchildrenonly - * - * The current implementation of this function assumes that a single child gets - * passed without a wrapper, but the purpose of this helper function is to - * abstract away the particular structure of children. - * - * @param {?object} children Child collection structure. - * @return {ReactElement} The first and only `ReactElement` contained in the - * structure. - */ - - function onlyChild(children) { - if (!isValidElement(children)) { - throw new Error( - "React.Children.only expected to receive a single React element child." - ); - } - - return children; - } - - function createContext(defaultValue) { - // TODO: Second argument used to be an optional `calculateChangedBits` - // function. Warn to reserve for future use? - var context = { - $$typeof: REACT_CONTEXT_TYPE, - // As a workaround to support multiple concurrent renderers, we categorize - // some renderers as primary and others as secondary. We only expect - // there to be two concurrent renderers at most: React Native (primary) and - // Fabric (secondary); React DOM (primary) and React ART (secondary). - // Secondary renderers store their context values on separate fields. - _currentValue: defaultValue, - _currentValue2: defaultValue, - // Used to track how many concurrent renderers this context currently - // supports within in a single renderer. Such as parallel server rendering. - _threadCount: 0, - // These are circular - Provider: null, - Consumer: null - }; - if (enableRenderableContext) { - context.Provider = context; - context.Consumer = { - $$typeof: REACT_CONSUMER_TYPE, - _context: context - }; - } else { - context.Provider = { - $$typeof: REACT_PROVIDER_TYPE, - _context: context - }; +function isValidElement(object) { + return typeof object === 'object' && object !== null && object.$$typeof === REACT_ELEMENT_TYPE; +} +var ownerHasKeyUseWarning = {}; +/** + * Warn if the element doesn't have an explicit key assigned to it. + * This element is in an array. The array could grow and shrink or be + * reordered. All children that haven't already been validated are required to + * have a "key" property assigned to it. Error statuses are cached so a warning + * will only be shown once. + * + * @internal + * @param {ReactElement} element Element that requires a key. + * @param {*} parentType element's parent's type. + */ - { - var Consumer = { - $$typeof: REACT_CONTEXT_TYPE, - _context: context - }; - Object.defineProperties(Consumer, { - Provider: { - get: function () { - return context.Provider; - }, - set: function (_Provider) { - context.Provider = _Provider; - } - }, - _currentValue: { - get: function () { - return context._currentValue; - }, - set: function (_currentValue) { - context._currentValue = _currentValue; - } - }, - _currentValue2: { - get: function () { - return context._currentValue2; - }, - set: function (_currentValue2) { - context._currentValue2 = _currentValue2; - } - }, - _threadCount: { - get: function () { - return context._threadCount; - }, - set: function (_threadCount) { - context._threadCount = _threadCount; - } - }, - Consumer: { - get: function () { - return context.Consumer; - } - }, - displayName: { - get: function () { - return context.displayName; - }, - set: function (displayName) {} - } - }); - context.Consumer = Consumer; - } - } +function validateExplicitKey(element, parentType) { + { + if (!element._store || element._store.validated || element.key != null) { + return; + } - { - context._currentRenderer = null; - context._currentRenderer2 = null; - } - - return context; - } - - var Uninitialized = -1; - var Pending = 0; - var Resolved = 1; - var Rejected = 2; - - function lazyInitializer(payload) { - if (payload._status === Uninitialized) { - var ctor = payload._result; - var thenable = ctor(); // Transition to the next state. - // This might throw either because it's missing or throws. If so, we treat it - // as still uninitialized and try again next time. Which is the same as what - // happens if the ctor or any wrappers processing the ctor throws. This might - // end up fixing it if the resolution was a concurrency bug. - - thenable.then( - function (moduleObject) { - if ( - payload._status === Pending || - payload._status === Uninitialized - ) { - // Transition to the next state. - var resolved = payload; - resolved._status = Resolved; - resolved._result = moduleObject; - } - }, - function (error) { - if ( - payload._status === Pending || - payload._status === Uninitialized - ) { - // Transition to the next state. - var rejected = payload; - rejected._status = Rejected; - rejected._result = error; - } - } - ); - - if (payload._status === Uninitialized) { - // In case, we're still uninitialized, then we're waiting for the thenable - // to resolve. Set it as pending in the meantime. - var pending = payload; - pending._status = Pending; - pending._result = thenable; - } - } + element._store.validated = true; + var currentComponentErrorInfo = getCurrentComponentErrorInfo(parentType); - if (payload._status === Resolved) { - var moduleObject = payload._result; + if (ownerHasKeyUseWarning[currentComponentErrorInfo]) { + return; + } - { - if (moduleObject === undefined) { - error( - "lazy: Expected the result of a dynamic imp" + - "ort() call. " + - "Instead received: %s\n\nYour code should look like: \n " + // Break up imports to avoid accidentally parsing them as dependencies. - "const MyComponent = lazy(() => imp" + - "ort('./MyComponent'))\n\n" + - "Did you accidentally put curly braces around the import?", - moduleObject - ); - } - } + ownerHasKeyUseWarning[currentComponentErrorInfo] = true; // Usually the current owner is the offender, but if it accepts children as a + // property, it may be the creator of the child that's responsible for + // assigning it a key. - { - if (!("default" in moduleObject)) { - error( - "lazy: Expected the result of a dynamic imp" + - "ort() call. " + - "Instead received: %s\n\nYour code should look like: \n " + // Break up imports to avoid accidentally parsing them as dependencies. - "const MyComponent = lazy(() => imp" + - "ort('./MyComponent'))", - moduleObject - ); - } - } + var childOwner = ''; - return moduleObject.default; - } else { - throw payload._result; - } - } + if (element && element._owner != null && element._owner !== ReactSharedInternals.owner) { + var ownerName = null; - function lazy(ctor) { - var payload = { - // We use these fields to store the result. - _status: Uninitialized, - _result: ctor - }; - var lazyType = { - $$typeof: REACT_LAZY_TYPE, - _payload: payload, - _init: lazyInitializer - }; + if (typeof element._owner.tag === 'number') { + ownerName = getComponentNameFromType(element._owner.type); + } else if (typeof element._owner.name === 'string') { + ownerName = element._owner.name; + } // Give the component that originally created this child. - if (!disableDefaultPropsExceptForClasses) { - { - // In production, this would just set it on the object. - var defaultProps; // $FlowFixMe[prop-missing] - - Object.defineProperties(lazyType, { - defaultProps: { - configurable: true, - get: function () { - return defaultProps; - }, - // $FlowFixMe[missing-local-annot] - set: function (newDefaultProps) { - error( - "It is not supported to assign `defaultProps` to " + - "a lazy component import. Either specify them where the component " + - "is defined, or create a wrapping component around it." - ); - - defaultProps = newDefaultProps; // Match production behavior more closely: - // $FlowFixMe[prop-missing] - - Object.defineProperty(lazyType, "defaultProps", { - enumerable: true - }); - } - } - }); - } - } - return lazyType; + childOwner = " It was passed a child from " + ownerName + "."; } - function forwardRef(render) { - { - if (render != null && render.$$typeof === REACT_MEMO_TYPE) { - error( - "forwardRef requires a render function but received a `memo` " + - "component. Instead of forwardRef(memo(...)), use " + - "memo(forwardRef(...))." - ); - } else if (typeof render !== "function") { - error( - "forwardRef requires a render function but was given %s.", - render === null ? "null" : typeof render - ); - } else { - if (render.length !== 0 && render.length !== 2) { - error( - "forwardRef render functions accept exactly two parameters: props and ref. %s", - render.length === 1 - ? "Did you forget to use the ref parameter?" - : "Any additional parameter will be undefined." - ); - } - } - - if (render != null) { - if (render.defaultProps != null) { - error( - "forwardRef render functions do not support defaultProps. " + - "Did you accidentally pass a React component?" - ); - } - } - } + setCurrentlyValidatingElement(element); - var elementType = { - $$typeof: REACT_FORWARD_REF_TYPE, - render: render - }; + error('Each child in a list should have a unique "key" prop.' + '%s%s See https://react.dev/link/warning-keys for more information.', currentComponentErrorInfo, childOwner); - { - var ownName; - Object.defineProperty(elementType, "displayName", { - enumerable: false, - configurable: true, - get: function () { - return ownName; - }, - set: function (name) { - ownName = name; // The inner component shouldn't inherit this display name in most cases, - // because the component may be used elsewhere. - // But it's nice for anonymous functions to inherit the name, - // so that our component-stack generation logic will display their frames. - // An anonymous function generally suggests a pattern like: - // React.forwardRef((props, ref) => {...}); - // This kind of inner function is not used elsewhere so the side effect is okay. - - if (!render.name && !render.displayName) { - render.displayName = name; - } - } - }); - } + setCurrentlyValidatingElement(null); + } +} - return elementType; +function setCurrentlyValidatingElement(element) { + { + if (element) { + var stack = describeUnknownElementTypeFrameInDEV(element.type); + ReactSharedInternals.setExtraStackFrame(stack); + } else { + ReactSharedInternals.setExtraStackFrame(null); } + } +} - function memo(type, compare) { - { - if (!isValidElementType(type)) { - error( - "memo: The first argument must be a component. Instead " + - "received: %s", - type === null ? "null" : typeof type - ); - } - } +function getCurrentComponentErrorInfo(parentType) { + { + var info = getDeclarationErrorAddendum(); - var elementType = { - $$typeof: REACT_MEMO_TYPE, - type: type, - compare: compare === undefined ? null : compare - }; + if (!info) { + var parentName = getComponentNameFromType(parentType); - { - var ownName; - Object.defineProperty(elementType, "displayName", { - enumerable: false, - configurable: true, - get: function () { - return ownName; - }, - set: function (name) { - ownName = name; // The inner component shouldn't inherit this display name in most cases, - // because the component may be used elsewhere. - // But it's nice for anonymous functions to inherit the name, - // so that our component-stack generation logic will display their frames. - // An anonymous function generally suggests a pattern like: - // React.memo((props) => {...}); - // This kind of inner function is not used elsewhere so the side effect is okay. - - if (!type.name && !type.displayName) { - type.displayName = name; - } - } - }); + if (parentName) { + info = "\n\nCheck the top-level render call using <" + parentName + ">."; } - - return elementType; } - function noopCache(fn) { - // On the client (i.e. not a Server Components environment) `cache` has - // no caching behavior. We just return the function as-is. - // - // We intend to implement client caching in a future major release. In the - // meantime, it's only exposed as an API so that Shared Components can use - // per-request caching on the server without breaking on the client. But it - // does mean they need to be aware of the behavioral difference. - // - // The rest of the behavior is the same as the server implementation — it - // returns a new reference, extra properties like `displayName` are not - // preserved, the length of the new function is 0, etc. That way apps can't - // accidentally depend on those details. - return function () { - // $FlowFixMe[incompatible-call]: We don't want to use rest arguments since we transpile the code. - return fn.apply(null, arguments); - }; - } - var cache = noopCache; + return info; + } +} +/** + * Given a fragment, validate that it can only be provided with fragment props + * @param {ReactElement} fragment + */ - function resolveDispatcher() { - var dispatcher = ReactSharedInternals.H; - { - if (dispatcher === null) { - 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://react.dev/link/invalid-hook-call for tips about how to debug and fix this problem." - ); - } - } // Will result in a null access error if accessed outside render phase. We - // intentionally don't throw our own error because this is in a hot path. - // Also helps ensure this is inlined. +function validateFragmentProps(fragment) { + // TODO: Move this to render phase instead of at element creation. + { + var keys = Object.keys(fragment.props); - return dispatcher; - } + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; - function getCacheForType(resourceType) { - var dispatcher = ReactSharedInternals.C; + if (key !== 'children' && key !== 'key') { + setCurrentlyValidatingElement(fragment); - if (!dispatcher) { - // If there is no dispatcher, then we treat this as not being cached. - return resourceType(); - } + error('Invalid prop `%s` supplied to `React.Fragment`. ' + 'React.Fragment can only have `key` and `children` props.', key); - return dispatcher.getCacheForType(resourceType); + setCurrentlyValidatingElement(null); + break; + } } - function useContext(Context) { - var dispatcher = resolveDispatcher(); - { - if (Context.$$typeof === REACT_CONSUMER_TYPE) { - error( - "Calling useContext(Context.Consumer) is not supported and will cause bugs. " + - "Did you mean to call useContext(Context) instead?" - ); - } - } + if (fragment.ref !== null) { + setCurrentlyValidatingElement(fragment); - return dispatcher.useContext(Context); - } - function useState(initialState) { - var dispatcher = resolveDispatcher(); - return dispatcher.useState(initialState); - } - function useReducer(reducer, initialArg, init) { - var dispatcher = resolveDispatcher(); - return dispatcher.useReducer(reducer, initialArg, init); - } - function useRef(initialValue) { - var dispatcher = resolveDispatcher(); - return dispatcher.useRef(initialValue); - } - function useEffect(create, deps) { - var dispatcher = resolveDispatcher(); - return dispatcher.useEffect(create, deps); - } - function useInsertionEffect(create, deps) { - var dispatcher = resolveDispatcher(); - return dispatcher.useInsertionEffect(create, deps); - } - function useLayoutEffect(create, deps) { - var dispatcher = resolveDispatcher(); - return dispatcher.useLayoutEffect(create, deps); - } - function useCallback(callback, deps) { - var dispatcher = resolveDispatcher(); - return dispatcher.useCallback(callback, deps); - } - function useMemo(create, deps) { - var dispatcher = resolveDispatcher(); - return dispatcher.useMemo(create, deps); - } - function useImperativeHandle(ref, create, deps) { - var dispatcher = resolveDispatcher(); - return dispatcher.useImperativeHandle(ref, create, deps); + error('Invalid attribute `ref` supplied to `React.Fragment`.'); + + setCurrentlyValidatingElement(null); } - function useDebugValue(value, formatterFn) { + } +} + +function coerceStringRef(mixedRef, owner, type) { + + var stringRef; + + if (typeof mixedRef === 'string') { + stringRef = mixedRef; + } else { + if (typeof mixedRef === 'number' || typeof mixedRef === 'boolean') { { - var dispatcher = resolveDispatcher(); - return dispatcher.useDebugValue(value, formatterFn); + checkPropStringCoercion(mixedRef, 'ref'); } - } - function useTransition() { - var dispatcher = resolveDispatcher(); - return dispatcher.useTransition(); - } - function useDeferredValue(value, initialValue) { - var dispatcher = resolveDispatcher(); - return dispatcher.useDeferredValue(value, initialValue); - } - function useId() { - var dispatcher = resolveDispatcher(); - return dispatcher.useId(); - } - function useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) { - var dispatcher = resolveDispatcher(); - return dispatcher.useSyncExternalStore( - subscribe, - getSnapshot, - getServerSnapshot - ); - } - function useCacheRefresh() { - var dispatcher = resolveDispatcher(); // $FlowFixMe[not-a-function] This is unstable, thus optional - return dispatcher.useCacheRefresh(); - } - function use(usable) { - var dispatcher = resolveDispatcher(); - return dispatcher.use(usable); + stringRef = '' + mixedRef; + } else { + return mixedRef; } - function useMemoCache(size) { - var dispatcher = resolveDispatcher(); // $FlowFixMe[not-a-function] This is unstable, thus optional + } - return dispatcher.useMemoCache(size); - } - function useEffectEvent(callback) { - var dispatcher = resolveDispatcher(); // $FlowFixMe[not-a-function] This is unstable, thus optional + var callback = stringRefAsCallbackRef.bind(null, stringRef, type, owner); // This is used to check whether two callback refs conceptually represent + // the same string ref, and can therefore be reused by the reconciler. Needed + // for backwards compatibility with old Meta code that relies on string refs + // not being reattached on every render. - return dispatcher.useEffectEvent(callback); - } - function useOptimistic(passthrough, reducer) { - var dispatcher = resolveDispatcher(); // $FlowFixMe[not-a-function] This is unstable, thus optional + callback.__stringRef = stringRef; + callback.__type = type; + callback.__owner = owner; + return callback; +} - return dispatcher.useOptimistic(passthrough, reducer); - } - function useActionState(action, initialState, permalink) { - if (!enableAsyncActions) { - throw new Error("Not implemented."); - } else { - var dispatcher = resolveDispatcher(); // $FlowFixMe[not-a-function] This is unstable, thus optional - - return dispatcher.useActionState(action, initialState, permalink); - } - } - - var reportGlobalError = - typeof reportError === "function" // In modern browsers, reportError will dispatch an error event, - ? // emulating an uncaught JavaScript error. - reportError - : function (error) { - if ( - typeof window === "object" && - typeof window.ErrorEvent === "function" - ) { - // Browser Polyfill - var message = - typeof error === "object" && - error !== null && - typeof error.message === "string" // eslint-disable-next-line react-internal/safe-string-coercion - ? String(error.message) // eslint-disable-next-line react-internal/safe-string-coercion - : String(error); - var event = new window.ErrorEvent("error", { - bubbles: true, - cancelable: true, - message: message, - error: error - }); - var shouldLog = window.dispatchEvent(event); - - if (!shouldLog) { - return; - } - } else if ( - typeof process === "object" && // $FlowFixMe[method-unbinding] - typeof process.emit === "function" - ) { - // Node Polyfill - process.emit("uncaughtException", error); - return; - } // eslint-disable-next-line react-internal/no-production-logging - - console["error"](error); - }; - - function startTransition(scope, options) { - var prevTransition = ReactSharedInternals.T; // Each renderer registers a callback to receive the return value of - // the scope function. This is used to implement async actions. - - var callbacks = new Set(); - var transition = { - _callbacks: callbacks - }; - ReactSharedInternals.T = transition; - var currentTransition = ReactSharedInternals.T; +function stringRefAsCallbackRef(stringRef, type, owner, value) { - { - ReactSharedInternals.T._updatedFibers = new Set(); - } + if (!owner) { + throw new Error("Element ref was specified as a string (" + stringRef + ") 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://react.dev/link/refs-must-have-owner for more information.'); + } - if (enableAsyncActions) { - try { - var returnValue = scope(); - - if ( - typeof returnValue === "object" && - returnValue !== null && - typeof returnValue.then === "function" - ) { - callbacks.forEach(function (callback) { - return callback(currentTransition, returnValue); - }); - returnValue.then(noop, reportGlobalError); - } - } catch (error) { - reportGlobalError(error); - } finally { - warnAboutTransitionSubscriptions(prevTransition, currentTransition); - ReactSharedInternals.T = prevTransition; - } - } else { - // When async actions are not enabled, startTransition does not - // capture errors. - try { - scope(); - } finally { - warnAboutTransitionSubscriptions(prevTransition, currentTransition); - ReactSharedInternals.T = prevTransition; - } + if (owner.tag !== ClassComponent) { + throw new Error('Function components cannot have string refs. ' + 'We recommend using useRef() instead. ' + 'Learn more about using refs safely here: ' + 'https://react.dev/link/strict-mode-string-ref'); + } + + { + if ( // Will already warn with "Function components cannot be given refs" + !(typeof type === 'function' && !isReactClass(type))) { + var componentName = getComponentNameFromFiber(owner) || 'Component'; + + 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://react.dev/link/strict-mode-string-ref', componentName, stringRef); + + didWarnAboutStringRefs[componentName] = true; } } + } - function warnAboutTransitionSubscriptions( - prevTransition, - currentTransition - ) { - { - if (prevTransition === null && currentTransition._updatedFibers) { - var updatedFibersCount = currentTransition._updatedFibers.size; + var inst = owner.stateNode; - currentTransition._updatedFibers.clear(); + if (!inst) { + throw new Error("Missing owner for string ref " + stringRef + ". This error is likely caused by a " + 'bug in React. Please file an issue.'); + } - 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." - ); - } - } - } + var refs = inst.refs; + + if (value === null) { + delete refs[stringRef]; + } else { + refs[stringRef] = value; + } +} + +function isReactClass(type) { + return type.prototype && type.prototype.isReactComponent; +} + +var SEPARATOR = '.'; +var SUBSEPARATOR = ':'; +/** + * Escape and wrap key so it is safe to use as a reactid + * + * @param {string} key to be escaped. + * @return {string} the escaped key. + */ + +function escape(key) { + var escapeRegex = /[=:]/g; + var escaperLookup = { + '=': '=0', + ':': '=2' + }; + var escapedString = key.replace(escapeRegex, function (match) { + return escaperLookup[match]; + }); + return '$' + escapedString; +} +/** + * TODO: Test that a single child and an array with one item have the same key + * pattern. + */ + + +var didWarnAboutMaps = false; +var userProvidedKeyEscapeRegex = /\/+/g; + +function escapeUserProvidedKey(text) { + return text.replace(userProvidedKeyEscapeRegex, '$&/'); +} +/** + * Generate a key string that identifies a element within a set. + * + * @param {*} element A element that could contain a manual key. + * @param {number} index Index that is used if a manual key is not provided. + * @return {string} + */ + + +function getElementKey(element, index) { + // Do some typechecking here since we call this blindly. We want to ensure + // that we don't block potential future ES APIs. + if (typeof element === 'object' && element !== null && element.key != null) { + // Explicit key + { + checkKeyStringCoercion(element.key); } - function noop() {} + return escape('' + element.key); + } // Implicit key determined by the index in the set - var didWarnAboutMessageChannel = false; - var enqueueTaskImpl = null; - function enqueueTask(task) { - if (enqueueTaskImpl === null) { - try { - // read require off the module object to get around the bundlers. - // we don't want them to detect a require and bundle a Node polyfill. - var requireString = ("require" + Math.random()).slice(0, 7); - var nodeRequire = module && module[requireString]; // assuming we're in node, let's try to get node's - // version of setImmediate, bypassing fake timers if any. - - enqueueTaskImpl = nodeRequire.call(module, "timers").setImmediate; - } catch (_err) { - // we're in a browser - // we can't use regular timers because they may still be faked - // so we try MessageChannel+postMessage instead - enqueueTaskImpl = function (callback) { + + return index.toString(36); +} + +function noop$1() {} + +function resolveThenable(thenable) { + switch (thenable.status) { + case 'fulfilled': + { + var fulfilledValue = thenable.value; + return fulfilledValue; + } + + case 'rejected': + { + var rejectedError = thenable.reason; + throw rejectedError; + } + + 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 { + // This is an uncached thenable that we haven't seen before. + // TODO: Detect infinite ping loops caused by uncached promises. + 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. + + + switch (thenable.status) { + case 'fulfilled': { - if (didWarnAboutMessageChannel === false) { - didWarnAboutMessageChannel = true; - - if (typeof MessageChannel === "undefined") { - error( - "This browser does not have a MessageChannel implementation, " + - "so enqueuing tasks via await act(async () => ...) will fail. " + - "Please file an issue at https://github.com/facebook/react/issues " + - "if you encounter this warning." - ); - } - } + var fulfilledThenable = thenable; + return fulfilledThenable.value; } - var channel = new MessageChannel(); - channel.port1.onmessage = callback; - channel.port2.postMessage(undefined); - }; + case 'rejected': + { + var rejectedThenable = thenable; + var _rejectedError = rejectedThenable.reason; + throw _rejectedError; + } } } + } + + throw thenable; +} + +function mapIntoArray(children, array, escapedPrefix, nameSoFar, callback) { + var type = typeof children; + + if (type === 'undefined' || type === 'boolean') { + // All of the above are perceived as null. + children = null; + } + + var invokeCallback = false; + + if (children === null) { + invokeCallback = true; + } else { + switch (type) { + case 'bigint': + case 'string': + case 'number': + invokeCallback = true; + break; + + case 'object': + switch (children.$$typeof) { + case REACT_ELEMENT_TYPE: + case REACT_PORTAL_TYPE: + invokeCallback = true; + break; + + case REACT_LAZY_TYPE: + var payload = children._payload; + var init = children._init; + return mapIntoArray(init(payload), array, escapedPrefix, nameSoFar, callback); + } - return enqueueTaskImpl(task); } + } - // number of `act` scopes on the stack. + if (invokeCallback) { + var _child = children; + var mappedChild = callback(_child); // If it's the only child, treat the name as if it was wrapped in an array + // so that it's consistent if the number of children grows: - var actScopeDepth = 0; // We only warn the first time you neglect to await an async `act` scope. + var childKey = nameSoFar === '' ? SEPARATOR + getElementKey(_child, 0) : nameSoFar; + + if (isArray(mappedChild)) { + var escapedChildKey = ''; + + if (childKey != null) { + escapedChildKey = escapeUserProvidedKey(childKey) + '/'; + } - var didWarnNoAwaitAct = false; + mapIntoArray(mappedChild, array, escapedChildKey, '', function (c) { + return c; + }); + } else if (mappedChild != null) { + if (isValidElement(mappedChild)) { + { + // The `if` statement here prevents auto-disabling of the safe + // coercion ESLint rule, so we must manually disable it below. + // $FlowFixMe[incompatible-type] Flow incorrectly thinks React.Portal doesn't have a key + if (mappedChild.key && (!_child || _child.key !== mappedChild.key)) { + checkKeyStringCoercion(mappedChild.key); + } + } - function aggregateErrors(errors) { - if (errors.length > 1 && typeof AggregateError === "function") { - // eslint-disable-next-line no-undef - return new AggregateError(errors); + mappedChild = cloneAndReplaceKey(mappedChild, // Keep both the (mapped) and old keys if they differ, just as + // traverseAllChildren used to do for objects as children + escapedPrefix + ( // $FlowFixMe[incompatible-type] Flow incorrectly thinks React.Portal doesn't have a key + mappedChild.key && (!_child || _child.key !== mappedChild.key) ? escapeUserProvidedKey( // $FlowFixMe[unsafe-addition] + '' + mappedChild.key // eslint-disable-line react-internal/safe-string-coercion + ) + '/' : '') + childKey); } - return errors[0]; + array.push(mappedChild); + } + + return 1; + } + + var child; + var nextName; + var subtreeCount = 0; // Count of children found in the current subtree. + + var nextNamePrefix = nameSoFar === '' ? SEPARATOR : nameSoFar + SUBSEPARATOR; + + if (isArray(children)) { + for (var i = 0; i < children.length; i++) { + child = children[i]; + nextName = nextNamePrefix + getElementKey(child, i); + subtreeCount += mapIntoArray(child, array, escapedPrefix, nextName, callback); } + } else { + var iteratorFn = getIteratorFn(children); + + if (typeof iteratorFn === 'function') { + var iterableChildren = children; - function act(callback) { { - // When ReactSharedInternals.actQueue is not null, it signals to React that - // we're currently inside an `act` scope. React will push all its tasks to - // this queue instead of scheduling them with platform APIs. - // - // We set this to an empty array when we first enter an `act` scope, and - // only unset it once we've left the outermost `act` scope — remember that - // `act` calls can be nested. - // - // If we're already inside an `act` scope, reuse the existing queue. - var prevIsBatchingLegacy = ReactSharedInternals.isBatchingLegacy; - var prevActQueue = ReactSharedInternals.actQueue; - var prevActScopeDepth = actScopeDepth; - actScopeDepth++; - var queue = (ReactSharedInternals.actQueue = - prevActQueue !== null ? prevActQueue : []); // Used to reproduce behavior of `batchedUpdates` in legacy mode. Only - // set to `true` while the given callback is executed, not for updates - // triggered during an async event, because this is how the legacy - // implementation of `act` behaved. + // Warn about using Maps as children + if (iteratorFn === iterableChildren.entries) { + if (!didWarnAboutMaps) { + warn('Using Maps as children is not supported. ' + 'Use an array of keyed ReactElements instead.'); + } - { - ReactSharedInternals.isBatchingLegacy = true; + didWarnAboutMaps = true; } + } - var result; // This tracks whether the `act` call is awaited. In certain cases, not - // awaiting it is a mistake, so we will detect that and warn. + var iterator = iteratorFn.call(iterableChildren); + var step; + var ii = 0; // $FlowFixMe[incompatible-use] `iteratorFn` might return null according to typing. - var didAwaitActCall = false; + while (!(step = iterator.next()).done) { + child = step.value; + nextName = nextNamePrefix + getElementKey(child, ii++); + subtreeCount += mapIntoArray(child, array, escapedPrefix, nextName, callback); + } + } else if (type === 'object') { + if (typeof children.then === 'function') { + return mapIntoArray(resolveThenable(children), array, escapedPrefix, nameSoFar, callback); + } // eslint-disable-next-line react-internal/safe-string-coercion - try { - // Reset this to `false` right before entering the React work loop. The - // only place we ever read this fields is just below, right after running - // the callback. So we don't need to reset after the callback runs. - if (!disableLegacyMode) { - ReactSharedInternals.didScheduleLegacyUpdate = false; - } - result = callback(); - var didScheduleLegacyUpdate = !disableLegacyMode - ? ReactSharedInternals.didScheduleLegacyUpdate - : false; // Replicate behavior of original `act` implementation in legacy mode, - // which flushed updates immediately after the scope function exits, even - // if it's an async function. - - if (!prevIsBatchingLegacy && didScheduleLegacyUpdate) { - flushActQueue(queue); - } // `isBatchingLegacy` gets reset using the regular stack, not the async - // one used to track `act` scopes. Why, you may be wondering? Because - // that's how it worked before version 18. Yes, it's confusing! We should - // delete legacy mode!! - - if (!disableLegacyMode) { - ReactSharedInternals.isBatchingLegacy = prevIsBatchingLegacy; + var childrenString = String(children); + throw new Error("Objects are not valid as a React child (found: " + (childrenString === '[object Object]' ? 'object with keys {' + Object.keys(children).join(', ') + '}' : childrenString) + "). " + 'If you meant to render a collection of children, use an array ' + 'instead.'); + } + } + + return subtreeCount; +} +/** + * Maps children that are typically specified as `props.children`. + * + * See https://reactjs.org/docs/react-api.html#reactchildrenmap + * + * The provided mapFunction(child, index) will be called for each + * leaf child. + * + * @param {?*} children Children tree container. + * @param {function(*, int)} func The map function. + * @param {*} context Context for mapFunction. + * @return {object} Object containing the ordered map of results. + */ + + +function mapChildren(children, func, context) { + if (children == null) { + // $FlowFixMe limitation refining abstract types in Flow + return children; + } + + var result = []; + var count = 0; + mapIntoArray(children, result, '', '', function (child) { + return func.call(context, child, count++); + }); + return result; +} +/** + * Count the number of children that are typically specified as + * `props.children`. + * + * See https://reactjs.org/docs/react-api.html#reactchildrencount + * + * @param {?*} children Children tree container. + * @return {number} The number of children. + */ + + +function countChildren(children) { + var n = 0; + mapChildren(children, function () { + n++; // Don't return anything + }); + return n; +} +/** + * Iterates through children that are typically specified as `props.children`. + * + * See https://reactjs.org/docs/react-api.html#reactchildrenforeach + * + * The provided forEachFunc(child, index) will be called for each + * leaf child. + * + * @param {?*} children Children tree container. + * @param {function(*, int)} forEachFunc + * @param {*} forEachContext Context for forEachContext. + */ + + +function forEachChildren(children, forEachFunc, forEachContext) { + mapChildren(children, // $FlowFixMe[missing-this-annot] + function () { + forEachFunc.apply(this, arguments); // Don't return anything. + }, forEachContext); +} +/** + * Flatten a children object (typically specified as `props.children`) and + * return an array with appropriately re-keyed children. + * + * See https://reactjs.org/docs/react-api.html#reactchildrentoarray + */ + + +function toArray(children) { + return mapChildren(children, function (child) { + return child; + }) || []; +} +/** + * Returns the first child in a collection of children and verifies that there + * is only one child in the collection. + * + * See https://reactjs.org/docs/react-api.html#reactchildrenonly + * + * The current implementation of this function assumes that a single child gets + * passed without a wrapper, but the purpose of this helper function is to + * abstract away the particular structure of children. + * + * @param {?object} children Child collection structure. + * @return {ReactElement} The first and only `ReactElement` contained in the + * structure. + */ + + +function onlyChild(children) { + if (!isValidElement(children)) { + throw new Error('React.Children.only expected to receive a single React element child.'); + } + + return children; +} + +function createContext(defaultValue) { + // TODO: Second argument used to be an optional `calculateChangedBits` + // function. Warn to reserve for future use? + var context = { + $$typeof: REACT_CONTEXT_TYPE, + // As a workaround to support multiple concurrent renderers, we categorize + // some renderers as primary and others as secondary. We only expect + // there to be two concurrent renderers at most: React Native (primary) and + // Fabric (secondary); React DOM (primary) and React ART (secondary). + // Secondary renderers store their context values on separate fields. + _currentValue: defaultValue, + _currentValue2: defaultValue, + // Used to track how many concurrent renderers this context currently + // supports within in a single renderer. Such as parallel server rendering. + _threadCount: 0, + // These are circular + Provider: null, + Consumer: null + }; + + if (enableRenderableContext) { + context.Provider = context; + context.Consumer = { + $$typeof: REACT_CONSUMER_TYPE, + _context: context + }; + } else { + context.Provider = { + $$typeof: REACT_PROVIDER_TYPE, + _context: context + }; + + { + var Consumer = { + $$typeof: REACT_CONTEXT_TYPE, + _context: context + }; + Object.defineProperties(Consumer, { + Provider: { + get: function () { + return context.Provider; + }, + set: function (_Provider) { + context.Provider = _Provider; } - } catch (error) { - // `isBatchingLegacy` gets reset using the regular stack, not the async - // one used to track `act` scopes. Why, you may be wondering? Because - // that's how it worked before version 18. Yes, it's confusing! We should - // delete legacy mode!! - ReactSharedInternals.thrownErrors.push(error); + }, + _currentValue: { + get: function () { + return context._currentValue; + }, + set: function (_currentValue) { + context._currentValue = _currentValue; + } + }, + _currentValue2: { + get: function () { + return context._currentValue2; + }, + set: function (_currentValue2) { + context._currentValue2 = _currentValue2; + } + }, + _threadCount: { + get: function () { + return context._threadCount; + }, + set: function (_threadCount) { + context._threadCount = _threadCount; + } + }, + Consumer: { + get: function () { + return context.Consumer; + } + }, + displayName: { + get: function () { + return context.displayName; + }, + set: function (displayName) {} } + }); + context.Consumer = Consumer; + } + } - if (ReactSharedInternals.thrownErrors.length > 0) { - { - ReactSharedInternals.isBatchingLegacy = prevIsBatchingLegacy; + { + context._currentRenderer = null; + context._currentRenderer2 = null; + } + + return context; +} + +var Uninitialized = -1; +var Pending = 0; +var Resolved = 1; +var Rejected = 2; + +function lazyInitializer(payload) { + if (payload._status === Uninitialized) { + var ctor = payload._result; + var thenable = ctor(); // Transition to the next state. + // This might throw either because it's missing or throws. If so, we treat it + // as still uninitialized and try again next time. Which is the same as what + // happens if the ctor or any wrappers processing the ctor throws. This might + // end up fixing it if the resolution was a concurrency bug. + + thenable.then(function (moduleObject) { + if (payload._status === Pending || payload._status === Uninitialized) { + // Transition to the next state. + var resolved = payload; + resolved._status = Resolved; + resolved._result = moduleObject; + } + }, function (error) { + if (payload._status === Pending || payload._status === Uninitialized) { + // Transition to the next state. + var rejected = payload; + rejected._status = Rejected; + rejected._result = error; + } + }); + + if (payload._status === Uninitialized) { + // In case, we're still uninitialized, then we're waiting for the thenable + // to resolve. Set it as pending in the meantime. + var pending = payload; + pending._status = Pending; + pending._result = thenable; + } + } + + if (payload._status === Resolved) { + var moduleObject = payload._result; + + { + if (moduleObject === undefined) { + error('lazy: Expected the result of a dynamic imp' + 'ort() call. ' + 'Instead received: %s\n\nYour code should look like: \n ' + // Break up imports to avoid accidentally parsing them as dependencies. + 'const MyComponent = lazy(() => imp' + "ort('./MyComponent'))\n\n" + 'Did you accidentally put curly braces around the import?', moduleObject); + } + } + + { + if (!('default' in moduleObject)) { + error('lazy: Expected the result of a dynamic imp' + 'ort() call. ' + 'Instead received: %s\n\nYour code should look like: \n ' + // Break up imports to avoid accidentally parsing them as dependencies. + 'const MyComponent = lazy(() => imp' + "ort('./MyComponent'))", moduleObject); + } + } + + return moduleObject.default; + } else { + throw payload._result; + } +} + +function lazy(ctor) { + var payload = { + // We use these fields to store the result. + _status: Uninitialized, + _result: ctor + }; + var lazyType = { + $$typeof: REACT_LAZY_TYPE, + _payload: payload, + _init: lazyInitializer + }; + + if (!disableDefaultPropsExceptForClasses) { + { + // In production, this would just set it on the object. + var defaultProps; // $FlowFixMe[prop-missing] + + Object.defineProperties(lazyType, { + defaultProps: { + configurable: true, + get: function () { + return defaultProps; + }, + // $FlowFixMe[missing-local-annot] + set: function (newDefaultProps) { + error('It is not supported to assign `defaultProps` to ' + 'a lazy component import. Either specify them where the component ' + 'is defined, or create a wrapping component around it.'); + + defaultProps = newDefaultProps; // Match production behavior more closely: + // $FlowFixMe[prop-missing] + + Object.defineProperty(lazyType, 'defaultProps', { + enumerable: true + }); } + } + }); + } + } + + return lazyType; +} - popActScope(prevActQueue, prevActScopeDepth); - var thrownError = aggregateErrors(ReactSharedInternals.thrownErrors); - ReactSharedInternals.thrownErrors.length = 0; - throw thrownError; +function forwardRef(render) { + { + if (render != null && render.$$typeof === REACT_MEMO_TYPE) { + error('forwardRef requires a render function but received a `memo` ' + 'component. Instead of forwardRef(memo(...)), use ' + 'memo(forwardRef(...)).'); + } else if (typeof render !== 'function') { + error('forwardRef requires a render function but was given %s.', render === null ? 'null' : typeof render); + } else { + if (render.length !== 0 && render.length !== 2) { + error('forwardRef render functions accept exactly two parameters: props and ref. %s', render.length === 1 ? 'Did you forget to use the ref parameter?' : 'Any additional parameter will be undefined.'); + } + } + + if (render != null) { + if (render.defaultProps != null) { + error('forwardRef render functions do not support defaultProps. ' + 'Did you accidentally pass a React component?'); + } + } + } + + var elementType = { + $$typeof: REACT_FORWARD_REF_TYPE, + render: render + }; + + { + var ownName; + Object.defineProperty(elementType, 'displayName', { + enumerable: false, + configurable: true, + get: function () { + return ownName; + }, + set: function (name) { + ownName = name; // The inner component shouldn't inherit this display name in most cases, + // because the component may be used elsewhere. + // But it's nice for anonymous functions to inherit the name, + // so that our component-stack generation logic will display their frames. + // An anonymous function generally suggests a pattern like: + // React.forwardRef((props, ref) => {...}); + // This kind of inner function is not used elsewhere so the side effect is okay. + + if (!render.name && !render.displayName) { + render.displayName = name; } + } + }); + } - if ( - result !== null && - typeof result === "object" && // $FlowFixMe[method-unbinding] - typeof result.then === "function" - ) { - // A promise/thenable was returned from the callback. Wait for it to - // resolve before flushing the queue. - // - // If `act` were implemented as an async function, this whole block could - // be a single `await` call. That's really the only difference between - // this branch and the next one. - var thenable = result; // Warn if the an `act` call with an async scope is not awaited. In a - // future release, consider making this an error. + return elementType; +} - queueSeveralMicrotasks(function () { - if (!didAwaitActCall && !didWarnNoAwaitAct) { - didWarnNoAwaitAct = true; +function memo(type, compare) { + { + if (!isValidElementType(type)) { + error('memo: The first argument must be a component. Instead ' + 'received: %s', type === null ? 'null' : typeof type); + } + } + + var elementType = { + $$typeof: REACT_MEMO_TYPE, + type: type, + compare: compare === undefined ? null : compare + }; + + { + var ownName; + Object.defineProperty(elementType, 'displayName', { + enumerable: false, + configurable: true, + get: function () { + return ownName; + }, + set: function (name) { + ownName = name; // The inner component shouldn't inherit this display name in most cases, + // because the component may be used elsewhere. + // But it's nice for anonymous functions to inherit the name, + // so that our component-stack generation logic will display their frames. + // An anonymous function generally suggests a pattern like: + // React.memo((props) => {...}); + // This kind of inner function is not used elsewhere so the side effect is okay. - error( - "You called act(async () => ...) without await. " + - "This could lead to unexpected testing behaviour, " + - "interleaving multiple act calls and mixing their " + - "scopes. " + - "You should - await act(async () => ...);" - ); - } - }); - return { - then: function (resolve, reject) { - didAwaitActCall = true; - thenable.then( - function (returnValue) { - popActScope(prevActQueue, prevActScopeDepth); - - if (prevActScopeDepth === 0) { - // We're exiting the outermost `act` scope. Flush the queue. - try { - flushActQueue(queue); - enqueueTask(function () { - return ( - // Recursively flush tasks scheduled by a microtask. - recursivelyFlushAsyncActWork( - returnValue, - resolve, - reject - ) - ); - }); - } catch (error) { - // `thenable` might not be a real promise, and `flushActQueue` - // might throw, so we need to wrap `flushActQueue` in a - // try/catch. - ReactSharedInternals.thrownErrors.push(error); - } - - if (ReactSharedInternals.thrownErrors.length > 0) { - var _thrownError = aggregateErrors( - ReactSharedInternals.thrownErrors - ); - - ReactSharedInternals.thrownErrors.length = 0; - reject(_thrownError); - } - } else { - resolve(returnValue); - } - }, - function (error) { - popActScope(prevActQueue, prevActScopeDepth); - - if (ReactSharedInternals.thrownErrors.length > 0) { - var _thrownError2 = aggregateErrors( - ReactSharedInternals.thrownErrors - ); - - ReactSharedInternals.thrownErrors.length = 0; - reject(_thrownError2); - } else { - reject(error); - } - } - ); - } - }; - } else { - var returnValue = result; // The callback is not an async function. Exit the current - // scope immediately. + if (!type.name && !type.displayName) { + type.displayName = name; + } + } + }); + } - popActScope(prevActQueue, prevActScopeDepth); + return elementType; +} - if (prevActScopeDepth === 0) { - // We're exiting the outermost `act` scope. Flush the queue. - flushActQueue(queue); // If the queue is not empty, it implies that we intentionally yielded - // to the main thread, because something suspended. We will continue - // in an asynchronous task. - // - // Warn if something suspends but the `act` call is not awaited. - // In a future release, consider making this an error. - - if (queue.length !== 0) { - queueSeveralMicrotasks(function () { - if (!didAwaitActCall && !didWarnNoAwaitAct) { - didWarnNoAwaitAct = true; - - error( - "A component suspended inside an `act` scope, but the " + - "`act` call was not awaited. When testing React " + - "components that depend on asynchronous data, you must " + - "await the result:\n\n" + - "await act(() => ...)" - ); - } - }); - } // Like many things in this module, this is next part is confusing. - // - // We do not currently require every `act` call that is passed a - // callback to be awaited, through arguably we should. Since this - // callback was synchronous, we need to exit the current scope before - // returning. - // - // However, if thenable we're about to return *is* awaited, we'll - // immediately restore the current scope. So it shouldn't observable. - // - // This doesn't affect the case where the scope callback is async, - // because we always require those calls to be awaited. - // - // TODO: In a future version, consider always requiring all `act` calls - // to be awaited, regardless of whether the callback is sync or async. - - ReactSharedInternals.actQueue = null; - } +function noopCache(fn) { + // On the client (i.e. not a Server Components environment) `cache` has + // no caching behavior. We just return the function as-is. + // + // We intend to implement client caching in a future major release. In the + // meantime, it's only exposed as an API so that Shared Components can use + // per-request caching on the server without breaking on the client. But it + // does mean they need to be aware of the behavioral difference. + // + // The rest of the behavior is the same as the server implementation — it + // returns a new reference, extra properties like `displayName` are not + // preserved, the length of the new function is 0, etc. That way apps can't + // accidentally depend on those details. + return function () { + // $FlowFixMe[incompatible-call]: We don't want to use rest arguments since we transpile the code. + return fn.apply(null, arguments); + }; +} +var cache = noopCache ; + +function resolveDispatcher() { + var dispatcher = ReactSharedInternals.H; + + { + if (dispatcher === null) { + 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://react.dev/link/invalid-hook-call for tips about how to debug and fix this problem.'); + } + } // Will result in a null access error if accessed outside render phase. We + // intentionally don't throw our own error because this is in a hot path. + // Also helps ensure this is inlined. + + + return dispatcher; +} + +function getCacheForType(resourceType) { + var dispatcher = ReactSharedInternals.C; + + if (!dispatcher) { + // If there is no dispatcher, then we treat this as not being cached. + return resourceType(); + } + + return dispatcher.getCacheForType(resourceType); +} +function useContext(Context) { + var dispatcher = resolveDispatcher(); + + { + if (Context.$$typeof === REACT_CONSUMER_TYPE) { + error('Calling useContext(Context.Consumer) is not supported and will cause bugs. ' + 'Did you mean to call useContext(Context) instead?'); + } + } + + return dispatcher.useContext(Context); +} +function useState(initialState) { + var dispatcher = resolveDispatcher(); + return dispatcher.useState(initialState); +} +function useReducer(reducer, initialArg, init) { + var dispatcher = resolveDispatcher(); + return dispatcher.useReducer(reducer, initialArg, init); +} +function useRef(initialValue) { + var dispatcher = resolveDispatcher(); + return dispatcher.useRef(initialValue); +} +function useEffect(create, deps) { + var dispatcher = resolveDispatcher(); + return dispatcher.useEffect(create, deps); +} +function useInsertionEffect(create, deps) { + var dispatcher = resolveDispatcher(); + return dispatcher.useInsertionEffect(create, deps); +} +function useLayoutEffect(create, deps) { + var dispatcher = resolveDispatcher(); + return dispatcher.useLayoutEffect(create, deps); +} +function useCallback(callback, deps) { + var dispatcher = resolveDispatcher(); + return dispatcher.useCallback(callback, deps); +} +function useMemo(create, deps) { + var dispatcher = resolveDispatcher(); + return dispatcher.useMemo(create, deps); +} +function useImperativeHandle(ref, create, deps) { + var dispatcher = resolveDispatcher(); + return dispatcher.useImperativeHandle(ref, create, deps); +} +function useDebugValue(value, formatterFn) { + { + var dispatcher = resolveDispatcher(); + return dispatcher.useDebugValue(value, formatterFn); + } +} +function useTransition() { + var dispatcher = resolveDispatcher(); + return dispatcher.useTransition(); +} +function useDeferredValue(value, initialValue) { + var dispatcher = resolveDispatcher(); + return dispatcher.useDeferredValue(value, initialValue); +} +function useId() { + var dispatcher = resolveDispatcher(); + return dispatcher.useId(); +} +function useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) { + var dispatcher = resolveDispatcher(); + return dispatcher.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot); +} +function useCacheRefresh() { + var dispatcher = resolveDispatcher(); // $FlowFixMe[not-a-function] This is unstable, thus optional + + return dispatcher.useCacheRefresh(); +} +function use(usable) { + var dispatcher = resolveDispatcher(); + return dispatcher.use(usable); +} +function useMemoCache(size) { + var dispatcher = resolveDispatcher(); // $FlowFixMe[not-a-function] This is unstable, thus optional + + return dispatcher.useMemoCache(size); +} +function useEffectEvent(callback) { + var dispatcher = resolveDispatcher(); // $FlowFixMe[not-a-function] This is unstable, thus optional - if (ReactSharedInternals.thrownErrors.length > 0) { - var _thrownError3 = aggregateErrors( - ReactSharedInternals.thrownErrors - ); + return dispatcher.useEffectEvent(callback); +} +function useOptimistic(passthrough, reducer) { + var dispatcher = resolveDispatcher(); // $FlowFixMe[not-a-function] This is unstable, thus optional + + return dispatcher.useOptimistic(passthrough, reducer); +} +function useActionState(action, initialState, permalink) { + if (!enableAsyncActions) { + throw new Error('Not implemented.'); + } else { + var dispatcher = resolveDispatcher(); // $FlowFixMe[not-a-function] This is unstable, thus optional + + return dispatcher.useActionState(action, initialState, permalink); + } +} - ReactSharedInternals.thrownErrors.length = 0; - throw _thrownError3; +var reportGlobalError = typeof reportError === 'function' ? // In modern browsers, reportError will dispatch an error event, +// emulating an uncaught JavaScript error. +reportError : function (error) { + if (typeof window === 'object' && typeof window.ErrorEvent === 'function') { + // Browser Polyfill + var message = typeof error === 'object' && error !== null && typeof error.message === 'string' ? // eslint-disable-next-line react-internal/safe-string-coercion + String(error.message) : // eslint-disable-next-line react-internal/safe-string-coercion + String(error); + var event = new window.ErrorEvent('error', { + bubbles: true, + cancelable: true, + message: message, + error: error + }); + var shouldLog = window.dispatchEvent(event); + + if (!shouldLog) { + return; + } + } else if (typeof process === 'object' && // $FlowFixMe[method-unbinding] + typeof process.emit === 'function') { + // Node Polyfill + process.emit('uncaughtException', error); + return; + } // eslint-disable-next-line react-internal/no-production-logging + + + console['error'](error); +}; + +function startTransition(scope, options) { + var prevTransition = ReactSharedInternals.T; // Each renderer registers a callback to receive the return value of + // the scope function. This is used to implement async actions. + + var callbacks = new Set(); + var transition = { + _callbacks: callbacks + }; + ReactSharedInternals.T = transition; + var currentTransition = ReactSharedInternals.T; + + { + ReactSharedInternals.T._updatedFibers = new Set(); + } + + if (enableAsyncActions) { + try { + var returnValue = scope(); + + if (typeof returnValue === 'object' && returnValue !== null && typeof returnValue.then === 'function') { + callbacks.forEach(function (callback) { + return callback(currentTransition, returnValue); + }); + returnValue.then(noop, reportGlobalError); + } + } catch (error) { + reportGlobalError(error); + } finally { + warnAboutTransitionSubscriptions(prevTransition, currentTransition); + ReactSharedInternals.T = prevTransition; + } + } else { + // When async actions are not enabled, startTransition does not + // capture errors. + try { + scope(); + } finally { + warnAboutTransitionSubscriptions(prevTransition, currentTransition); + ReactSharedInternals.T = prevTransition; + } + } +} + +function warnAboutTransitionSubscriptions(prevTransition, currentTransition) { + { + 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.'); + } + } + } +} + +function noop() {} + +var didWarnAboutMessageChannel = false; +var enqueueTaskImpl = null; +function enqueueTask(task) { + if (enqueueTaskImpl === null) { + try { + // read require off the module object to get around the bundlers. + // we don't want them to detect a require and bundle a Node polyfill. + var requireString = ('require' + Math.random()).slice(0, 7); + var nodeRequire = module && module[requireString]; // assuming we're in node, let's try to get node's + // version of setImmediate, bypassing fake timers if any. + + enqueueTaskImpl = nodeRequire.call(module, 'timers').setImmediate; + } catch (_err) { + // we're in a browser + // we can't use regular timers because they may still be faked + // so we try MessageChannel+postMessage instead + enqueueTaskImpl = function (callback) { + { + if (didWarnAboutMessageChannel === false) { + didWarnAboutMessageChannel = true; + + if (typeof MessageChannel === 'undefined') { + error('This browser does not have a MessageChannel implementation, ' + 'so enqueuing tasks via await act(async () => ...) will fail. ' + 'Please file an issue at https://github.com/facebook/react/issues ' + 'if you encounter this warning.'); + } } + } + + var channel = new MessageChannel(); + channel.port1.onmessage = callback; + channel.port2.postMessage(undefined); + }; + } + } + + return enqueueTaskImpl(task); +} + +// number of `act` scopes on the stack. + +var actScopeDepth = 0; // We only warn the first time you neglect to await an async `act` scope. + +var didWarnNoAwaitAct = false; + +function aggregateErrors(errors) { + if (errors.length > 1 && typeof AggregateError === 'function') { + // eslint-disable-next-line no-undef + return new AggregateError(errors); + } + + return errors[0]; +} + +function act(callback) { + { + // When ReactSharedInternals.actQueue is not null, it signals to React that + // we're currently inside an `act` scope. React will push all its tasks to + // this queue instead of scheduling them with platform APIs. + // + // We set this to an empty array when we first enter an `act` scope, and + // only unset it once we've left the outermost `act` scope — remember that + // `act` calls can be nested. + // + // If we're already inside an `act` scope, reuse the existing queue. + var prevIsBatchingLegacy = ReactSharedInternals.isBatchingLegacy ; + var prevActQueue = ReactSharedInternals.actQueue; + var prevActScopeDepth = actScopeDepth; + actScopeDepth++; + var queue = ReactSharedInternals.actQueue = prevActQueue !== null ? prevActQueue : []; // Used to reproduce behavior of `batchedUpdates` in legacy mode. Only + // set to `true` while the given callback is executed, not for updates + // triggered during an async event, because this is how the legacy + // implementation of `act` behaved. + + { + ReactSharedInternals.isBatchingLegacy = true; + } - return { - then: function (resolve, reject) { - didAwaitActCall = true; + var result; // This tracks whether the `act` call is awaited. In certain cases, not + // awaiting it is a mistake, so we will detect that and warn. + + var didAwaitActCall = false; + + try { + // Reset this to `false` right before entering the React work loop. The + // only place we ever read this fields is just below, right after running + // the callback. So we don't need to reset after the callback runs. + if (!disableLegacyMode) { + ReactSharedInternals.didScheduleLegacyUpdate = false; + } + + result = callback(); + var didScheduleLegacyUpdate = !disableLegacyMode ? ReactSharedInternals.didScheduleLegacyUpdate : false; // Replicate behavior of original `act` implementation in legacy mode, + // which flushed updates immediately after the scope function exits, even + // if it's an async function. + + if (!prevIsBatchingLegacy && didScheduleLegacyUpdate) { + flushActQueue(queue); + } // `isBatchingLegacy` gets reset using the regular stack, not the async + // one used to track `act` scopes. Why, you may be wondering? Because + // that's how it worked before version 18. Yes, it's confusing! We should + // delete legacy mode!! + + + if (!disableLegacyMode) { + ReactSharedInternals.isBatchingLegacy = prevIsBatchingLegacy; + } + } catch (error) { + // `isBatchingLegacy` gets reset using the regular stack, not the async + // one used to track `act` scopes. Why, you may be wondering? Because + // that's how it worked before version 18. Yes, it's confusing! We should + // delete legacy mode!! + ReactSharedInternals.thrownErrors.push(error); + } - if (prevActScopeDepth === 0) { - // If the `act` call is awaited, restore the queue we were - // using before (see long comment above) so we can flush it. - ReactSharedInternals.actQueue = queue; + if (ReactSharedInternals.thrownErrors.length > 0) { + { + ReactSharedInternals.isBatchingLegacy = prevIsBatchingLegacy; + } + + popActScope(prevActQueue, prevActScopeDepth); + var thrownError = aggregateErrors(ReactSharedInternals.thrownErrors); + ReactSharedInternals.thrownErrors.length = 0; + throw thrownError; + } + + if (result !== null && typeof result === 'object' && // $FlowFixMe[method-unbinding] + typeof result.then === 'function') { + // A promise/thenable was returned from the callback. Wait for it to + // resolve before flushing the queue. + // + // If `act` were implemented as an async function, this whole block could + // be a single `await` call. That's really the only difference between + // this branch and the next one. + var thenable = result; // Warn if the an `act` call with an async scope is not awaited. In a + // future release, consider making this an error. + + queueSeveralMicrotasks(function () { + if (!didAwaitActCall && !didWarnNoAwaitAct) { + didWarnNoAwaitAct = true; + + error('You called act(async () => ...) without await. ' + 'This could lead to unexpected testing behaviour, ' + 'interleaving multiple act calls and mixing their ' + 'scopes. ' + 'You should - await act(async () => ...);'); + } + }); + return { + then: function (resolve, reject) { + didAwaitActCall = true; + thenable.then(function (returnValue) { + popActScope(prevActQueue, prevActScopeDepth); + + if (prevActScopeDepth === 0) { + // We're exiting the outermost `act` scope. Flush the queue. + try { + flushActQueue(queue); enqueueTask(function () { - return ( - // Recursively flush tasks scheduled by a microtask. + return (// Recursively flush tasks scheduled by a microtask. recursivelyFlushAsyncActWork(returnValue, resolve, reject) ); }); - } else { - resolve(returnValue); + } catch (error) { + // `thenable` might not be a real promise, and `flushActQueue` + // might throw, so we need to wrap `flushActQueue` in a + // try/catch. + ReactSharedInternals.thrownErrors.push(error); } + + if (ReactSharedInternals.thrownErrors.length > 0) { + var _thrownError = aggregateErrors(ReactSharedInternals.thrownErrors); + + ReactSharedInternals.thrownErrors.length = 0; + reject(_thrownError); + } + } else { + resolve(returnValue); + } + }, function (error) { + popActScope(prevActQueue, prevActScopeDepth); + + if (ReactSharedInternals.thrownErrors.length > 0) { + var _thrownError2 = aggregateErrors(ReactSharedInternals.thrownErrors); + + ReactSharedInternals.thrownErrors.length = 0; + reject(_thrownError2); + } else { + reject(error); } - }; + }); } + }; + } else { + var returnValue = result; // The callback is not an async function. Exit the current + // scope immediately. + + popActScope(prevActQueue, prevActScopeDepth); + + if (prevActScopeDepth === 0) { + // We're exiting the outermost `act` scope. Flush the queue. + flushActQueue(queue); // If the queue is not empty, it implies that we intentionally yielded + // to the main thread, because something suspended. We will continue + // in an asynchronous task. + // + // Warn if something suspends but the `act` call is not awaited. + // In a future release, consider making this an error. + + if (queue.length !== 0) { + queueSeveralMicrotasks(function () { + if (!didAwaitActCall && !didWarnNoAwaitAct) { + didWarnNoAwaitAct = true; + + error('A component suspended inside an `act` scope, but the ' + '`act` call was not awaited. When testing React ' + 'components that depend on asynchronous data, you must ' + 'await the result:\n\n' + 'await act(() => ...)'); + } + }); + } // Like many things in this module, this is next part is confusing. + // + // We do not currently require every `act` call that is passed a + // callback to be awaited, through arguably we should. Since this + // callback was synchronous, we need to exit the current scope before + // returning. + // + // However, if thenable we're about to return *is* awaited, we'll + // immediately restore the current scope. So it shouldn't observable. + // + // This doesn't affect the case where the scope callback is async, + // because we always require those calls to be awaited. + // + // TODO: In a future version, consider always requiring all `act` calls + // to be awaited, regardless of whether the callback is sync or async. + + + ReactSharedInternals.actQueue = null; } - } - function popActScope(prevActQueue, prevActScopeDepth) { - { - if (prevActScopeDepth !== actScopeDepth - 1) { - error( - "You seem to have overlapping act() calls, this is not supported. " + - "Be sure to await previous act() calls before making a new one. " - ); - } + if (ReactSharedInternals.thrownErrors.length > 0) { + var _thrownError3 = aggregateErrors(ReactSharedInternals.thrownErrors); - actScopeDepth = prevActScopeDepth; + ReactSharedInternals.thrownErrors.length = 0; + throw _thrownError3; } - } - function recursivelyFlushAsyncActWork(returnValue, resolve, reject) { - { - // Check if any tasks were scheduled asynchronously. - var queue = ReactSharedInternals.actQueue; + return { + then: function (resolve, reject) { + didAwaitActCall = true; - if (queue !== null) { - if (queue.length !== 0) { - // Async tasks were scheduled, mostly likely in a microtask. - // Keep flushing until there are no more. - try { - flushActQueue(queue); // The work we just performed may have schedule additional async - // tasks. Wait a macrotask and check again. - - enqueueTask(function () { - return recursivelyFlushAsyncActWork( - returnValue, - resolve, - reject - ); - }); - return; - } catch (error) { - // Leave remaining tasks on the queue if something throws. - ReactSharedInternals.thrownErrors.push(error); - } + if (prevActScopeDepth === 0) { + // If the `act` call is awaited, restore the queue we were + // using before (see long comment above) so we can flush it. + ReactSharedInternals.actQueue = queue; + enqueueTask(function () { + return (// Recursively flush tasks scheduled by a microtask. + recursivelyFlushAsyncActWork(returnValue, resolve, reject) + ); + }); } else { - // The queue is empty. We can finish. - ReactSharedInternals.actQueue = null; + resolve(returnValue); } } + }; + } + } +} - if (ReactSharedInternals.thrownErrors.length > 0) { - var thrownError = aggregateErrors(ReactSharedInternals.thrownErrors); - ReactSharedInternals.thrownErrors.length = 0; - reject(thrownError); - } else { - resolve(returnValue); - } - } +function popActScope(prevActQueue, prevActScopeDepth) { + { + if (prevActScopeDepth !== actScopeDepth - 1) { + error('You seem to have overlapping act() calls, this is not supported. ' + 'Be sure to await previous act() calls before making a new one. '); } - var isFlushing = false; + actScopeDepth = prevActScopeDepth; + } +} - function flushActQueue(queue) { - { - if (!isFlushing) { - // Prevent re-entrance. - isFlushing = true; - var i = 0; +function recursivelyFlushAsyncActWork(returnValue, resolve, reject) { + { + // Check if any tasks were scheduled asynchronously. + var queue = ReactSharedInternals.actQueue; - try { - for (; i < queue.length; i++) { - var callback = queue[i]; - - do { - ReactSharedInternals.didUsePromise = false; - var continuation = callback(false); - - if (continuation !== null) { - if (ReactSharedInternals.didUsePromise) { - // The component just suspended. Yield to the main thread in - // case the promise is already resolved. If so, it will ping in - // a microtask and we can resume without unwinding the stack. - queue[i] = callback; - queue.splice(0, i); - return; - } + if (queue !== null) { + if (queue.length !== 0) { + // Async tasks were scheduled, mostly likely in a microtask. + // Keep flushing until there are no more. + try { + flushActQueue(queue); // The work we just performed may have schedule additional async + // tasks. Wait a macrotask and check again. - callback = continuation; - } else { - break; - } - } while (true); - } // We flushed the entire queue. - - queue.length = 0; - } catch (error) { - // If something throws, leave the remaining callbacks on the queue. - queue.splice(0, i + 1); - ReactSharedInternals.thrownErrors.push(error); - } finally { - isFlushing = false; - } + enqueueTask(function () { + return recursivelyFlushAsyncActWork(returnValue, resolve, reject); + }); + return; + } catch (error) { + // Leave remaining tasks on the queue if something throws. + ReactSharedInternals.thrownErrors.push(error); } + } else { + // The queue is empty. We can finish. + ReactSharedInternals.actQueue = null; } - } // Some of our warnings attempt to detect if the `act` call is awaited by - // checking in an asynchronous task. Wait a few microtasks before checking. The - // only reason one isn't sufficient is we want to accommodate the case where an - // `act` call is returned from an async function without first being awaited, - // since that's a somewhat common pattern. If you do this too many times in a - // nested sequence, you might get a warning, but you can always fix by awaiting - // the call. - // - // A macrotask would also work (and is the fallback) but depending on the test - // environment it may cause the warning to fire too late. - - var queueSeveralMicrotasks = - typeof queueMicrotask === "function" - ? function (callback) { - queueMicrotask(function () { - return queueMicrotask(callback); - }); - } - : enqueueTask; - - var Children = { - map: mapChildren, - forEach: forEachChildren, - count: countChildren, - toArray: toArray, - only: onlyChild - }; + } - var jsx = jsxProdSignatureRunningInDevWithDynamicChildren; // we may want to special case jsxs internally to take advantage of static children. - // for now we can ship identical prod functions - - var jsxs = jsxProdSignatureRunningInDevWithStaticChildren; - var jsxDEV = jsxDEV$1; - - exports.Children = Children; - exports.Component = Component; - exports.Fragment = REACT_FRAGMENT_TYPE; - exports.Profiler = REACT_PROFILER_TYPE; - exports.PureComponent = PureComponent; - exports.StrictMode = REACT_STRICT_MODE_TYPE; - exports.Suspense = REACT_SUSPENSE_TYPE; - exports.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE = - ReactSharedInternals; - exports.act = act; - exports.cache = cache; - exports.cloneElement = cloneElement; - exports.createContext = createContext; - exports.createElement = createElement; - exports.createRef = createRef; - exports.experimental_useEffectEvent = useEffectEvent; - exports.forwardRef = forwardRef; - exports.isValidElement = isValidElement; - exports.jsx = jsx; - exports.jsxDEV = jsxDEV; - exports.jsxs = jsxs; - exports.lazy = lazy; - exports.memo = memo; - exports.startTransition = startTransition; - exports.unstable_Activity = REACT_OFFSCREEN_TYPE; - exports.unstable_DebugTracingMode = REACT_DEBUG_TRACING_MODE_TYPE; - exports.unstable_LegacyHidden = REACT_LEGACY_HIDDEN_TYPE; - exports.unstable_Scope = REACT_SCOPE_TYPE; - exports.unstable_SuspenseList = REACT_SUSPENSE_LIST_TYPE; - exports.unstable_TracingMarker = REACT_TRACING_MARKER_TYPE; - exports.unstable_getCacheForType = getCacheForType; - exports.unstable_useCacheRefresh = useCacheRefresh; - exports.unstable_useMemoCache = useMemoCache; - exports.use = use; - exports.useActionState = useActionState; - exports.useCallback = useCallback; - exports.useContext = useContext; - exports.useDebugValue = useDebugValue; - exports.useDeferredValue = useDeferredValue; - exports.useEffect = useEffect; - exports.useId = useId; - exports.useImperativeHandle = useImperativeHandle; - exports.useInsertionEffect = useInsertionEffect; - exports.useLayoutEffect = useLayoutEffect; - exports.useMemo = useMemo; - exports.useOptimistic = useOptimistic; - exports.useReducer = useReducer; - exports.useRef = useRef; - exports.useState = useState; - exports.useSyncExternalStore = useSyncExternalStore; - exports.useTransition = useTransition; - exports.version = ReactVersion; - /* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */ - if ( - typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== "undefined" && - typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop === - "function" - ) { - __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(new Error()); + if (ReactSharedInternals.thrownErrors.length > 0) { + var thrownError = aggregateErrors(ReactSharedInternals.thrownErrors); + ReactSharedInternals.thrownErrors.length = 0; + reject(thrownError); + } else { + resolve(returnValue); } + } +} + +var isFlushing = false; + +function flushActQueue(queue) { + { + if (!isFlushing) { + // Prevent re-entrance. + isFlushing = true; + var i = 0; + + try { + for (; i < queue.length; i++) { + var callback = queue[i]; + + do { + ReactSharedInternals.didUsePromise = false; + var continuation = callback(false); + + if (continuation !== null) { + if (ReactSharedInternals.didUsePromise) { + // The component just suspended. Yield to the main thread in + // case the promise is already resolved. If so, it will ping in + // a microtask and we can resume without unwinding the stack. + queue[i] = callback; + queue.splice(0, i); + return; + } + + callback = continuation; + } else { + break; + } + } while (true); + } // We flushed the entire queue. + + + queue.length = 0; + } catch (error) { + // If something throws, leave the remaining callbacks on the queue. + queue.splice(0, i + 1); + ReactSharedInternals.thrownErrors.push(error); + } finally { + isFlushing = false; + } + } + } +} // Some of our warnings attempt to detect if the `act` call is awaited by +// checking in an asynchronous task. Wait a few microtasks before checking. The +// only reason one isn't sufficient is we want to accommodate the case where an +// `act` call is returned from an async function without first being awaited, +// since that's a somewhat common pattern. If you do this too many times in a +// nested sequence, you might get a warning, but you can always fix by awaiting +// the call. +// +// A macrotask would also work (and is the fallback) but depending on the test +// environment it may cause the warning to fire too late. + + +var queueSeveralMicrotasks = typeof queueMicrotask === 'function' ? function (callback) { + queueMicrotask(function () { + return queueMicrotask(callback); + }); +} : enqueueTask; + +var Children = { + map: mapChildren, + forEach: forEachChildren, + count: countChildren, + toArray: toArray, + only: onlyChild +}; + +var jsx = jsxProdSignatureRunningInDevWithDynamicChildren ; // we may want to special case jsxs internally to take advantage of static children. +// for now we can ship identical prod functions + +var jsxs = jsxProdSignatureRunningInDevWithStaticChildren ; +var jsxDEV = jsxDEV$1 ; + +exports.Children = Children; +exports.Component = Component; +exports.Fragment = REACT_FRAGMENT_TYPE; +exports.Profiler = REACT_PROFILER_TYPE; +exports.PureComponent = PureComponent; +exports.StrictMode = REACT_STRICT_MODE_TYPE; +exports.Suspense = REACT_SUSPENSE_TYPE; +exports.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE = ReactSharedInternals; +exports.act = act; +exports.cache = cache; +exports.cloneElement = cloneElement; +exports.createContext = createContext; +exports.createElement = createElement; +exports.createRef = createRef; +exports.experimental_useEffectEvent = useEffectEvent; +exports.forwardRef = forwardRef; +exports.isValidElement = isValidElement; +exports.jsx = jsx; +exports.jsxDEV = jsxDEV; +exports.jsxs = jsxs; +exports.lazy = lazy; +exports.memo = memo; +exports.startTransition = startTransition; +exports.unstable_Activity = REACT_OFFSCREEN_TYPE; +exports.unstable_DebugTracingMode = REACT_DEBUG_TRACING_MODE_TYPE; +exports.unstable_LegacyHidden = REACT_LEGACY_HIDDEN_TYPE; +exports.unstable_Scope = REACT_SCOPE_TYPE; +exports.unstable_SuspenseList = REACT_SUSPENSE_LIST_TYPE; +exports.unstable_TracingMarker = REACT_TRACING_MARKER_TYPE; +exports.unstable_getCacheForType = getCacheForType; +exports.unstable_useCacheRefresh = useCacheRefresh; +exports.unstable_useMemoCache = useMemoCache; +exports.use = use; +exports.useActionState = useActionState; +exports.useCallback = useCallback; +exports.useContext = useContext; +exports.useDebugValue = useDebugValue; +exports.useDeferredValue = useDeferredValue; +exports.useEffect = useEffect; +exports.useId = useId; +exports.useImperativeHandle = useImperativeHandle; +exports.useInsertionEffect = useInsertionEffect; +exports.useLayoutEffect = useLayoutEffect; +exports.useMemo = useMemo; +exports.useOptimistic = useOptimistic; +exports.useReducer = useReducer; +exports.useRef = useRef; +exports.useState = useState; +exports.useSyncExternalStore = useSyncExternalStore; +exports.useTransition = useTransition; +exports.version = ReactVersion; + /* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */ +if ( + typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' && + typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop === + 'function' +) { + __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(new Error()); +} + })(); } diff --git a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/scheduler/cjs/Scheduler-dev.js b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/scheduler/cjs/Scheduler-dev.js index 58701090969d8..9d540981f04b3 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/scheduler/cjs/Scheduler-dev.js +++ b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/scheduler/cjs/Scheduler-dev.js @@ -7,617 +7,621 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<<58af4bb9ea8656229bd048421236ac87>> + * @generated SignedSource<> */ -"use strict"; +'use strict'; if (__DEV__) { - (function () { - "use strict"; - - /* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */ - if ( - typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== "undefined" && - typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart === - "function" - ) { - __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error()); - } - var enableSchedulerDebugging = false; - var enableProfiling = false; - var frameYieldMs = 5; - var userBlockingPriorityTimeout = 250; - var normalPriorityTimeout = 5000; - var lowPriorityTimeout = 10000; - - function push(heap, node) { - var index = heap.length; - heap.push(node); - siftUp(heap, node, index); - } - function peek(heap) { - return heap.length === 0 ? null : heap[0]; - } - function pop(heap) { - if (heap.length === 0) { - return null; - } + (function() { - var first = heap[0]; - var last = heap.pop(); + 'use strict'; - if (last !== first) { - heap[0] = last; - siftDown(heap, last, 0); - } +/* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */ +if ( + typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' && + typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart === + 'function' +) { + __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error()); +} + var enableSchedulerDebugging = false; +var enableProfiling = false; +var frameYieldMs = 5; +var userBlockingPriorityTimeout = 250; +var normalPriorityTimeout = 5000; +var lowPriorityTimeout = 10000; + +function push(heap, node) { + var index = heap.length; + heap.push(node); + siftUp(heap, node, index); +} +function peek(heap) { + return heap.length === 0 ? null : heap[0]; +} +function pop(heap) { + if (heap.length === 0) { + return null; + } - return first; - } + var first = heap[0]; + var last = heap.pop(); - function siftUp(heap, node, i) { - var index = i; - - while (index > 0) { - var parentIndex = (index - 1) >>> 1; - var parent = heap[parentIndex]; - - if (compare(parent, node) > 0) { - // The parent is larger. Swap positions. - heap[parentIndex] = node; - heap[index] = parent; - index = parentIndex; - } else { - // The parent is smaller. Exit. - return; - } - } + if (last !== first) { + heap[0] = last; + siftDown(heap, last, 0); + } + + return first; +} + +function siftUp(heap, node, i) { + var index = i; + + while (index > 0) { + var parentIndex = index - 1 >>> 1; + var parent = heap[parentIndex]; + + if (compare(parent, node) > 0) { + // The parent is larger. Swap positions. + heap[parentIndex] = node; + heap[index] = parent; + index = parentIndex; + } else { + // The parent is smaller. Exit. + return; } + } +} - function siftDown(heap, node, i) { - var index = i; - var length = heap.length; - var halfLength = length >>> 1; - - while (index < halfLength) { - var leftIndex = (index + 1) * 2 - 1; - var left = heap[leftIndex]; - var rightIndex = leftIndex + 1; - var right = heap[rightIndex]; // If the left or right node is smaller, swap with the smaller of those. - - if (compare(left, node) < 0) { - if (rightIndex < length && compare(right, left) < 0) { - heap[index] = right; - heap[rightIndex] = node; - index = rightIndex; - } else { - heap[index] = left; - heap[leftIndex] = node; - index = leftIndex; - } - } else if (rightIndex < length && compare(right, node) < 0) { - heap[index] = right; - heap[rightIndex] = node; - index = rightIndex; - } else { - // Neither child is smaller. Exit. - return; - } +function siftDown(heap, node, i) { + var index = i; + var length = heap.length; + var halfLength = length >>> 1; + + while (index < halfLength) { + var leftIndex = (index + 1) * 2 - 1; + var left = heap[leftIndex]; + var rightIndex = leftIndex + 1; + var right = heap[rightIndex]; // If the left or right node is smaller, swap with the smaller of those. + + if (compare(left, node) < 0) { + if (rightIndex < length && compare(right, left) < 0) { + heap[index] = right; + heap[rightIndex] = node; + index = rightIndex; + } else { + heap[index] = left; + heap[leftIndex] = node; + index = leftIndex; } + } else if (rightIndex < length && compare(right, node) < 0) { + heap[index] = right; + heap[rightIndex] = node; + index = rightIndex; + } else { + // Neither child is smaller. Exit. + return; } + } +} - function compare(a, b) { - // Compare sort index first, then task id. - var diff = a.sortIndex - b.sortIndex; - return diff !== 0 ? diff : a.id - b.id; - } +function compare(a, b) { + // Compare sort index first, then task id. + var diff = a.sortIndex - b.sortIndex; + return diff !== 0 ? diff : a.id - b.id; +} + +// TODO: Use symbols? +var ImmediatePriority = 1; +var UserBlockingPriority = 2; +var NormalPriority = 3; +var LowPriority = 4; +var IdlePriority = 5; - // TODO: Use symbols? - var ImmediatePriority = 1; - var UserBlockingPriority = 2; - var NormalPriority = 3; - var LowPriority = 4; - var IdlePriority = 5; +function markTaskErrored(task, ms) { +} - function markTaskErrored(task, ms) {} +/* eslint-disable no-var */ +exports.unstable_now = void 0; +var hasPerformanceNow = // $FlowFixMe[method-unbinding] +typeof performance === 'object' && typeof performance.now === 'function'; + +if (hasPerformanceNow) { + var localPerformance = performance; + + exports.unstable_now = function () { + return localPerformance.now(); + }; +} else { + var localDate = Date; + var initialTime = localDate.now(); + + exports.unstable_now = function () { + return localDate.now() - initialTime; + }; +} // Max 31 bit integer. The max integer size in V8 for 32-bit systems. +// Math.pow(2, 30) - 1 +// 0b111111111111111111111111111111 + + +var maxSigned31BitInt = 1073741823; // Tasks are stored on a min heap + +var taskQueue = []; +var timerQueue = []; // Incrementing id counter. Used to maintain insertion order. + +var taskIdCounter = 1; // Pausing the scheduler is useful for debugging. +var currentTask = null; +var currentPriorityLevel = NormalPriority; // This is set while performing work, to prevent re-entrance. + +var isPerformingWork = false; +var isHostCallbackScheduled = false; +var isHostTimeoutScheduled = false; // Capture local references to native APIs, in case a polyfill overrides them. + +var localSetTimeout = typeof setTimeout === 'function' ? setTimeout : null; +var localClearTimeout = typeof clearTimeout === 'function' ? clearTimeout : null; +var localSetImmediate = typeof setImmediate !== 'undefined' ? setImmediate : null; // IE and Node.js + jsdom + +function advanceTimers(currentTime) { + // Check for tasks that are no longer delayed and add them to the queue. + var timer = peek(timerQueue); + + while (timer !== null) { + if (timer.callback === null) { + // Timer was cancelled. + pop(timerQueue); + } else if (timer.startTime <= currentTime) { + // Timer fired. Transfer to the task queue. + pop(timerQueue); + timer.sortIndex = timer.expirationTime; + push(taskQueue, timer); + } else { + // Remaining timers are pending. + return; + } - /* eslint-disable no-var */ - exports.unstable_now = void 0; - var hasPerformanceNow = // $FlowFixMe[method-unbinding] - typeof performance === "object" && typeof performance.now === "function"; + timer = peek(timerQueue); + } +} - if (hasPerformanceNow) { - var localPerformance = performance; +function handleTimeout(currentTime) { + isHostTimeoutScheduled = false; + advanceTimers(currentTime); - exports.unstable_now = function () { - return localPerformance.now(); - }; + if (!isHostCallbackScheduled) { + if (peek(taskQueue) !== null) { + isHostCallbackScheduled = true; + requestHostCallback(); } else { - var localDate = Date; - var initialTime = localDate.now(); - - exports.unstable_now = function () { - return localDate.now() - initialTime; - }; - } // Max 31 bit integer. The max integer size in V8 for 32-bit systems. - // Math.pow(2, 30) - 1 - // 0b111111111111111111111111111111 - - var maxSigned31BitInt = 1073741823; // Tasks are stored on a min heap - - var taskQueue = []; - var timerQueue = []; // Incrementing id counter. Used to maintain insertion order. - - var taskIdCounter = 1; // Pausing the scheduler is useful for debugging. - var currentTask = null; - var currentPriorityLevel = NormalPriority; // This is set while performing work, to prevent re-entrance. - - var isPerformingWork = false; - var isHostCallbackScheduled = false; - var isHostTimeoutScheduled = false; // Capture local references to native APIs, in case a polyfill overrides them. - - var localSetTimeout = typeof setTimeout === "function" ? setTimeout : null; - var localClearTimeout = - typeof clearTimeout === "function" ? clearTimeout : null; - var localSetImmediate = - typeof setImmediate !== "undefined" ? setImmediate : null; // IE and Node.js + jsdom - - function advanceTimers(currentTime) { - // Check for tasks that are no longer delayed and add them to the queue. - var timer = peek(timerQueue); - - while (timer !== null) { - if (timer.callback === null) { - // Timer was cancelled. - pop(timerQueue); - } else if (timer.startTime <= currentTime) { - // Timer fired. Transfer to the task queue. - pop(timerQueue); - timer.sortIndex = timer.expirationTime; - push(taskQueue, timer); - } else { - // Remaining timers are pending. - return; - } + var firstTimer = peek(timerQueue); - timer = peek(timerQueue); - } - } - - function handleTimeout(currentTime) { - isHostTimeoutScheduled = false; - advanceTimers(currentTime); - - if (!isHostCallbackScheduled) { - if (peek(taskQueue) !== null) { - isHostCallbackScheduled = true; - requestHostCallback(); - } else { - var firstTimer = peek(timerQueue); - - if (firstTimer !== null) { - requestHostTimeout( - handleTimeout, - firstTimer.startTime - currentTime - ); - } - } + if (firstTimer !== null) { + requestHostTimeout(handleTimeout, firstTimer.startTime - currentTime); } } + } +} - function flushWork(initialTime) { - isHostCallbackScheduled = false; +function flushWork(initialTime) { - if (isHostTimeoutScheduled) { - // We scheduled a timeout but it's no longer needed. Cancel it. - isHostTimeoutScheduled = false; - cancelHostTimeout(); - } - isPerformingWork = true; - var previousPriorityLevel = currentPriorityLevel; + isHostCallbackScheduled = false; - try { - var currentTime; - if (enableProfiling); - else { - // No catch in prod code path. - return workLoop(initialTime); - } - } finally { - currentTask = null; - currentPriorityLevel = previousPriorityLevel; - isPerformingWork = false; - } - } + if (isHostTimeoutScheduled) { + // We scheduled a timeout but it's no longer needed. Cancel it. + isHostTimeoutScheduled = false; + cancelHostTimeout(); + } - function workLoop(initialTime) { - var currentTime = initialTime; - advanceTimers(currentTime); - currentTask = peek(taskQueue); + isPerformingWork = true; + var previousPriorityLevel = currentPriorityLevel; - while (currentTask !== null && !enableSchedulerDebugging) { - if (currentTask.expirationTime > currentTime && shouldYieldToHost()) { - // This currentTask hasn't expired, and we've reached the deadline. - break; - } // $FlowFixMe[incompatible-use] found when upgrading Flow + try { + var currentTime; if (enableProfiling) ; else { + // No catch in prod code path. + return workLoop(initialTime); + } + } finally { + currentTask = null; + currentPriorityLevel = previousPriorityLevel; + isPerformingWork = false; + } +} - var callback = currentTask.callback; +function workLoop(initialTime) { + var currentTime = initialTime; + advanceTimers(currentTime); + currentTask = peek(taskQueue); - if (typeof callback === "function") { - // $FlowFixMe[incompatible-use] found when upgrading Flow - currentTask.callback = null; // $FlowFixMe[incompatible-use] found when upgrading Flow + while (currentTask !== null && !(enableSchedulerDebugging )) { + if (currentTask.expirationTime > currentTime && shouldYieldToHost()) { + // This currentTask hasn't expired, and we've reached the deadline. + break; + } // $FlowFixMe[incompatible-use] found when upgrading Flow - currentPriorityLevel = currentTask.priorityLevel; // $FlowFixMe[incompatible-use] found when upgrading Flow - var didUserCallbackTimeout = - currentTask.expirationTime <= currentTime; + var callback = currentTask.callback; - var continuationCallback = callback(didUserCallbackTimeout); - currentTime = exports.unstable_now(); + if (typeof callback === 'function') { + // $FlowFixMe[incompatible-use] found when upgrading Flow + currentTask.callback = null; // $FlowFixMe[incompatible-use] found when upgrading Flow - if (typeof continuationCallback === "function") { - // If a continuation is returned, immediately yield to the main thread - // regardless of how much time is left in the current time slice. - // $FlowFixMe[incompatible-use] found when upgrading Flow - currentTask.callback = continuationCallback; + currentPriorityLevel = currentTask.priorityLevel; // $FlowFixMe[incompatible-use] found when upgrading Flow - advanceTimers(currentTime); - return true; - } else { - if (currentTask === peek(taskQueue)) { - pop(taskQueue); - } + var didUserCallbackTimeout = currentTask.expirationTime <= currentTime; - advanceTimers(currentTime); - } - } else { - pop(taskQueue); - } + var continuationCallback = callback(didUserCallbackTimeout); + currentTime = exports.unstable_now(); - currentTask = peek(taskQueue); - } // Return whether there's additional work + if (typeof continuationCallback === 'function') { + // If a continuation is returned, immediately yield to the main thread + // regardless of how much time is left in the current time slice. + // $FlowFixMe[incompatible-use] found when upgrading Flow + currentTask.callback = continuationCallback; - if (currentTask !== null) { + advanceTimers(currentTime); return true; } else { - var firstTimer = peek(timerQueue); - if (firstTimer !== null) { - requestHostTimeout(handleTimeout, firstTimer.startTime - currentTime); + if (currentTask === peek(taskQueue)) { + pop(taskQueue); } - return false; + advanceTimers(currentTime); } + } else { + pop(taskQueue); } - function unstable_runWithPriority(priorityLevel, eventHandler) { - switch (priorityLevel) { - case ImmediatePriority: - case UserBlockingPriority: - case NormalPriority: - case LowPriority: - case IdlePriority: - break; - - default: - priorityLevel = NormalPriority; - } + currentTask = peek(taskQueue); + } // Return whether there's additional work - var previousPriorityLevel = currentPriorityLevel; - currentPriorityLevel = priorityLevel; - try { - return eventHandler(); - } finally { - currentPriorityLevel = previousPriorityLevel; - } + if (currentTask !== null) { + return true; + } else { + var firstTimer = peek(timerQueue); + + if (firstTimer !== null) { + requestHostTimeout(handleTimeout, firstTimer.startTime - currentTime); } - function unstable_next(eventHandler) { - var priorityLevel; - - switch (currentPriorityLevel) { - case ImmediatePriority: - case UserBlockingPriority: - case NormalPriority: - // Shift down to normal priority - priorityLevel = NormalPriority; - break; - - default: - // Anything lower than normal priority should remain at the current level. - priorityLevel = currentPriorityLevel; - break; - } + return false; + } +} - var previousPriorityLevel = currentPriorityLevel; - currentPriorityLevel = priorityLevel; +function unstable_runWithPriority(priorityLevel, eventHandler) { + switch (priorityLevel) { + case ImmediatePriority: + case UserBlockingPriority: + case NormalPriority: + case LowPriority: + case IdlePriority: + break; + + default: + priorityLevel = NormalPriority; + } + + var previousPriorityLevel = currentPriorityLevel; + currentPriorityLevel = priorityLevel; + + try { + return eventHandler(); + } finally { + currentPriorityLevel = previousPriorityLevel; + } +} - try { - return eventHandler(); - } finally { - currentPriorityLevel = previousPriorityLevel; - } - } +function unstable_next(eventHandler) { + var priorityLevel; + + switch (currentPriorityLevel) { + case ImmediatePriority: + case UserBlockingPriority: + case NormalPriority: + // Shift down to normal priority + priorityLevel = NormalPriority; + break; + + default: + // Anything lower than normal priority should remain at the current level. + priorityLevel = currentPriorityLevel; + break; + } + + var previousPriorityLevel = currentPriorityLevel; + currentPriorityLevel = priorityLevel; + + try { + return eventHandler(); + } finally { + currentPriorityLevel = previousPriorityLevel; + } +} - function unstable_wrapCallback(callback) { - var parentPriorityLevel = currentPriorityLevel; // $FlowFixMe[incompatible-return] - // $FlowFixMe[missing-this-annot] +function unstable_wrapCallback(callback) { + var parentPriorityLevel = currentPriorityLevel; // $FlowFixMe[incompatible-return] + // $FlowFixMe[missing-this-annot] - return function () { - // This is a fork of runWithPriority, inlined for performance. - var previousPriorityLevel = currentPriorityLevel; - currentPriorityLevel = parentPriorityLevel; + return function () { + // This is a fork of runWithPriority, inlined for performance. + var previousPriorityLevel = currentPriorityLevel; + currentPriorityLevel = parentPriorityLevel; - try { - return callback.apply(this, arguments); - } finally { - currentPriorityLevel = previousPriorityLevel; - } - }; + try { + return callback.apply(this, arguments); + } finally { + currentPriorityLevel = previousPriorityLevel; } + }; +} - function unstable_scheduleCallback(priorityLevel, callback, options) { - var currentTime = exports.unstable_now(); - var startTime; +function unstable_scheduleCallback(priorityLevel, callback, options) { + var currentTime = exports.unstable_now(); + var startTime; - if (typeof options === "object" && options !== null) { - var delay = options.delay; + if (typeof options === 'object' && options !== null) { + var delay = options.delay; - if (typeof delay === "number" && delay > 0) { - startTime = currentTime + delay; - } else { - startTime = currentTime; - } + if (typeof delay === 'number' && delay > 0) { + startTime = currentTime + delay; + } else { + startTime = currentTime; + } + } else { + startTime = currentTime; + } + + var timeout; + + switch (priorityLevel) { + case ImmediatePriority: + // Times out immediately + timeout = -1; + break; + + case UserBlockingPriority: + // Eventually times out + timeout = userBlockingPriorityTimeout; + break; + + case IdlePriority: + // Never times out + timeout = maxSigned31BitInt; + break; + + case LowPriority: + // Eventually times out + timeout = lowPriorityTimeout; + break; + + case NormalPriority: + default: + // Eventually times out + timeout = normalPriorityTimeout; + break; + } + + var expirationTime = startTime + timeout; + var newTask = { + id: taskIdCounter++, + callback: callback, + priorityLevel: priorityLevel, + startTime: startTime, + expirationTime: expirationTime, + sortIndex: -1 + }; + + if (startTime > currentTime) { + // This is a delayed task. + newTask.sortIndex = startTime; + push(timerQueue, newTask); + + if (peek(taskQueue) === null && newTask === peek(timerQueue)) { + // All tasks are delayed, and this is the task with the earliest delay. + if (isHostTimeoutScheduled) { + // Cancel an existing timeout. + cancelHostTimeout(); } else { - startTime = currentTime; - } + isHostTimeoutScheduled = true; + } // Schedule a timeout. - var timeout; - - switch (priorityLevel) { - case ImmediatePriority: - // Times out immediately - timeout = -1; - break; - - case UserBlockingPriority: - // Eventually times out - timeout = userBlockingPriorityTimeout; - break; - - case IdlePriority: - // Never times out - timeout = maxSigned31BitInt; - break; - - case LowPriority: - // Eventually times out - timeout = lowPriorityTimeout; - break; - - case NormalPriority: - default: - // Eventually times out - timeout = normalPriorityTimeout; - break; - } - var expirationTime = startTime + timeout; - var newTask = { - id: taskIdCounter++, - callback: callback, - priorityLevel: priorityLevel, - startTime: startTime, - expirationTime: expirationTime, - sortIndex: -1 - }; - - if (startTime > currentTime) { - // This is a delayed task. - newTask.sortIndex = startTime; - push(timerQueue, newTask); - - if (peek(taskQueue) === null && newTask === peek(timerQueue)) { - // All tasks are delayed, and this is the task with the earliest delay. - if (isHostTimeoutScheduled) { - // Cancel an existing timeout. - cancelHostTimeout(); - } else { - isHostTimeoutScheduled = true; - } // Schedule a timeout. - - requestHostTimeout(handleTimeout, startTime - currentTime); - } - } else { - newTask.sortIndex = expirationTime; - push(taskQueue, newTask); - // wait until the next time we yield. + requestHostTimeout(handleTimeout, startTime - currentTime); + } + } else { + newTask.sortIndex = expirationTime; + push(taskQueue, newTask); + // wait until the next time we yield. - if (!isHostCallbackScheduled && !isPerformingWork) { - isHostCallbackScheduled = true; - requestHostCallback(); - } - } - return newTask; + if (!isHostCallbackScheduled && !isPerformingWork) { + isHostCallbackScheduled = true; + requestHostCallback(); } + } - function unstable_pauseExecution() {} + return newTask; +} - function unstable_continueExecution() { - if (!isHostCallbackScheduled && !isPerformingWork) { - isHostCallbackScheduled = true; - requestHostCallback(); - } - } +function unstable_pauseExecution() { +} - function unstable_getFirstCallbackNode() { - return peek(taskQueue); - } +function unstable_continueExecution() { - function unstable_cancelCallback(task) { - // remove from the queue because you can't remove arbitrary nodes from an - // array based heap, only the first one.) + if (!isHostCallbackScheduled && !isPerformingWork) { + isHostCallbackScheduled = true; + requestHostCallback(); + } +} - task.callback = null; - } +function unstable_getFirstCallbackNode() { + return peek(taskQueue); +} - function unstable_getCurrentPriorityLevel() { - return currentPriorityLevel; - } +function unstable_cancelCallback(task) { + // remove from the queue because you can't remove arbitrary nodes from an + // array based heap, only the first one.) - var isMessageLoopRunning = false; - var taskTimeoutID = -1; // Scheduler periodically yields in case there is other work on the main - // thread, like user events. By default, it yields multiple times per frame. - // It does not attempt to align with frame boundaries, since most tasks don't - // need to be frame aligned; for those that do, use requestAnimationFrame. - var frameInterval = frameYieldMs; - var startTime = -1; + task.callback = null; +} - function shouldYieldToHost() { - var timeElapsed = exports.unstable_now() - startTime; +function unstable_getCurrentPriorityLevel() { + return currentPriorityLevel; +} - if (timeElapsed < frameInterval) { - // The main thread has only been blocked for a really short amount of time; - // smaller than a single frame. Don't yield yet. - return false; - } // Yield now. +var isMessageLoopRunning = false; +var taskTimeoutID = -1; // Scheduler periodically yields in case there is other work on the main +// thread, like user events. By default, it yields multiple times per frame. +// It does not attempt to align with frame boundaries, since most tasks don't +// need to be frame aligned; for those that do, use requestAnimationFrame. - return true; - } +var frameInterval = frameYieldMs; +var startTime = -1; - function requestPaint() {} +function shouldYieldToHost() { + var timeElapsed = exports.unstable_now() - startTime; - function forceFrameRate(fps) { - if (fps < 0 || fps > 125) { - // Using console['error'] to evade Babel and ESLint - console["error"]( - "forceFrameRate takes a positive int between 0 and 125, " + - "forcing frame rates higher than 125 fps is not supported" - ); - return; - } + if (timeElapsed < frameInterval) { + // The main thread has only been blocked for a really short amount of time; + // smaller than a single frame. Don't yield yet. + return false; + } // Yield now. - if (fps > 0) { - frameInterval = Math.floor(1000 / fps); - } else { - // reset the framerate - frameInterval = frameYieldMs; - } - } - var performWorkUntilDeadline = function () { - if (isMessageLoopRunning) { - var currentTime = exports.unstable_now(); // Keep track of the start time so we can measure how long the main thread - // has been blocked. - - startTime = currentTime; // If a scheduler task throws, exit the current browser task so the - // error can be observed. - // - // Intentionally not using a try-catch, since that makes some debugging - // techniques harder. Instead, if `flushWork` errors, then `hasMoreWork` will - // remain true, and we'll continue the work loop. - - var hasMoreWork = true; - - try { - hasMoreWork = flushWork(currentTime); - } finally { - if (hasMoreWork) { - // If there's more work, schedule the next message event at the end - // of the preceding one. - schedulePerformWorkUntilDeadline(); - } else { - isMessageLoopRunning = false; - } - } - } - }; - - var schedulePerformWorkUntilDeadline; - - if (typeof localSetImmediate === "function") { - // Node.js and old IE. - // There's a few reasons for why we prefer setImmediate. - // - // Unlike MessageChannel, it doesn't prevent a Node.js process from exiting. - // (Even though this is a DOM fork of the Scheduler, you could get here - // with a mix of Node.js 15+, which has a MessageChannel, and jsdom.) - // https://github.com/facebook/react/issues/20756 - // - // But also, it runs earlier which is the semantic we want. - // If other browsers ever implement it, it's better to use it. - // Although both of these would be inferior to native scheduling. - schedulePerformWorkUntilDeadline = function () { - localSetImmediate(performWorkUntilDeadline); - }; - } else if (typeof MessageChannel !== "undefined") { - // DOM and Worker environments. - // We prefer MessageChannel because of the 4ms setTimeout clamping. - var channel = new MessageChannel(); - var port = channel.port2; - channel.port1.onmessage = performWorkUntilDeadline; - - schedulePerformWorkUntilDeadline = function () { - port.postMessage(null); - }; - } else { - // We should only fallback here in non-browser environments. - schedulePerformWorkUntilDeadline = function () { - // $FlowFixMe[not-a-function] nullable value - localSetTimeout(performWorkUntilDeadline, 0); - }; - } + return true; +} - function requestHostCallback() { - if (!isMessageLoopRunning) { - isMessageLoopRunning = true; +function requestPaint() {} + +function forceFrameRate(fps) { + if (fps < 0 || fps > 125) { + // Using console['error'] to evade Babel and ESLint + console['error']('forceFrameRate takes a positive int between 0 and 125, ' + 'forcing frame rates higher than 125 fps is not supported'); + return; + } + + if (fps > 0) { + frameInterval = Math.floor(1000 / fps); + } else { + // reset the framerate + frameInterval = frameYieldMs; + } +} + +var performWorkUntilDeadline = function () { + if (isMessageLoopRunning) { + var currentTime = exports.unstable_now(); // Keep track of the start time so we can measure how long the main thread + // has been blocked. + + startTime = currentTime; // If a scheduler task throws, exit the current browser task so the + // error can be observed. + // + // Intentionally not using a try-catch, since that makes some debugging + // techniques harder. Instead, if `flushWork` errors, then `hasMoreWork` will + // remain true, and we'll continue the work loop. + + var hasMoreWork = true; + + try { + hasMoreWork = flushWork(currentTime); + } finally { + if (hasMoreWork) { + // If there's more work, schedule the next message event at the end + // of the preceding one. schedulePerformWorkUntilDeadline(); + } else { + isMessageLoopRunning = false; } } + } +}; + +var schedulePerformWorkUntilDeadline; + +if (typeof localSetImmediate === 'function') { + // Node.js and old IE. + // There's a few reasons for why we prefer setImmediate. + // + // Unlike MessageChannel, it doesn't prevent a Node.js process from exiting. + // (Even though this is a DOM fork of the Scheduler, you could get here + // with a mix of Node.js 15+, which has a MessageChannel, and jsdom.) + // https://github.com/facebook/react/issues/20756 + // + // But also, it runs earlier which is the semantic we want. + // If other browsers ever implement it, it's better to use it. + // Although both of these would be inferior to native scheduling. + schedulePerformWorkUntilDeadline = function () { + localSetImmediate(performWorkUntilDeadline); + }; +} else if (typeof MessageChannel !== 'undefined') { + // DOM and Worker environments. + // We prefer MessageChannel because of the 4ms setTimeout clamping. + var channel = new MessageChannel(); + var port = channel.port2; + channel.port1.onmessage = performWorkUntilDeadline; + + schedulePerformWorkUntilDeadline = function () { + port.postMessage(null); + }; +} else { + // We should only fallback here in non-browser environments. + schedulePerformWorkUntilDeadline = function () { + // $FlowFixMe[not-a-function] nullable value + localSetTimeout(performWorkUntilDeadline, 0); + }; +} - function requestHostTimeout(callback, ms) { - // $FlowFixMe[not-a-function] nullable value - taskTimeoutID = localSetTimeout(function () { - callback(exports.unstable_now()); - }, ms); - } +function requestHostCallback() { + if (!isMessageLoopRunning) { + isMessageLoopRunning = true; + schedulePerformWorkUntilDeadline(); + } +} - function cancelHostTimeout() { - // $FlowFixMe[not-a-function] nullable value - localClearTimeout(taskTimeoutID); - taskTimeoutID = -1; - } - var unstable_Profiling = null; - - exports.unstable_IdlePriority = IdlePriority; - exports.unstable_ImmediatePriority = ImmediatePriority; - exports.unstable_LowPriority = LowPriority; - exports.unstable_NormalPriority = NormalPriority; - exports.unstable_Profiling = unstable_Profiling; - exports.unstable_UserBlockingPriority = UserBlockingPriority; - exports.unstable_cancelCallback = unstable_cancelCallback; - exports.unstable_continueExecution = unstable_continueExecution; - exports.unstable_forceFrameRate = forceFrameRate; - exports.unstable_getCurrentPriorityLevel = unstable_getCurrentPriorityLevel; - exports.unstable_getFirstCallbackNode = unstable_getFirstCallbackNode; - exports.unstable_next = unstable_next; - exports.unstable_pauseExecution = unstable_pauseExecution; - exports.unstable_requestPaint = requestPaint; - exports.unstable_runWithPriority = unstable_runWithPriority; - exports.unstable_scheduleCallback = unstable_scheduleCallback; - exports.unstable_shouldYield = shouldYieldToHost; - exports.unstable_wrapCallback = unstable_wrapCallback; - /* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */ - if ( - typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== "undefined" && - typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop === - "function" - ) { - __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(new Error()); - } +function requestHostTimeout(callback, ms) { + // $FlowFixMe[not-a-function] nullable value + taskTimeoutID = localSetTimeout(function () { + callback(exports.unstable_now()); + }, ms); +} + +function cancelHostTimeout() { + // $FlowFixMe[not-a-function] nullable value + localClearTimeout(taskTimeoutID); + taskTimeoutID = -1; +} +var unstable_Profiling = null; + +exports.unstable_IdlePriority = IdlePriority; +exports.unstable_ImmediatePriority = ImmediatePriority; +exports.unstable_LowPriority = LowPriority; +exports.unstable_NormalPriority = NormalPriority; +exports.unstable_Profiling = unstable_Profiling; +exports.unstable_UserBlockingPriority = UserBlockingPriority; +exports.unstable_cancelCallback = unstable_cancelCallback; +exports.unstable_continueExecution = unstable_continueExecution; +exports.unstable_forceFrameRate = forceFrameRate; +exports.unstable_getCurrentPriorityLevel = unstable_getCurrentPriorityLevel; +exports.unstable_getFirstCallbackNode = unstable_getFirstCallbackNode; +exports.unstable_next = unstable_next; +exports.unstable_pauseExecution = unstable_pauseExecution; +exports.unstable_requestPaint = requestPaint; +exports.unstable_runWithPriority = unstable_runWithPriority; +exports.unstable_scheduleCallback = unstable_scheduleCallback; +exports.unstable_shouldYield = shouldYieldToHost; +exports.unstable_wrapCallback = unstable_wrapCallback; + /* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */ +if ( + typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' && + typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop === + 'function' +) { + __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(new Error()); +} + })(); } diff --git a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/scheduler/cjs/SchedulerMock-dev.js b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/scheduler/cjs/SchedulerMock-dev.js index ee132a7ae5b60..85105a6597576 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/scheduler/cjs/SchedulerMock-dev.js +++ b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/scheduler/cjs/SchedulerMock-dev.js @@ -7,719 +7,707 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<<95b4127da8c85ba368ae54253ebfb7c6>> + * @generated SignedSource<> */ -"use strict"; +'use strict'; if (__DEV__) { - (function () { - "use strict"; + (function() { +'use strict'; - var enableSchedulerDebugging = false; - var enableProfiling = false; +var enableSchedulerDebugging = false; +var enableProfiling = false; - function push(heap, node) { - var index = heap.length; - heap.push(node); - siftUp(heap, node, index); - } - function peek(heap) { - return heap.length === 0 ? null : heap[0]; - } - function pop(heap) { - if (heap.length === 0) { - return null; - } +function push(heap, node) { + var index = heap.length; + heap.push(node); + siftUp(heap, node, index); +} +function peek(heap) { + return heap.length === 0 ? null : heap[0]; +} +function pop(heap) { + if (heap.length === 0) { + return null; + } - var first = heap[0]; - var last = heap.pop(); + var first = heap[0]; + var last = heap.pop(); - if (last !== first) { - heap[0] = last; - siftDown(heap, last, 0); - } + if (last !== first) { + heap[0] = last; + siftDown(heap, last, 0); + } - return first; - } + return first; +} - function siftUp(heap, node, i) { - var index = i; - - while (index > 0) { - var parentIndex = (index - 1) >>> 1; - var parent = heap[parentIndex]; - - if (compare(parent, node) > 0) { - // The parent is larger. Swap positions. - heap[parentIndex] = node; - heap[index] = parent; - index = parentIndex; - } else { - // The parent is smaller. Exit. - return; - } - } - } +function siftUp(heap, node, i) { + var index = i; - function siftDown(heap, node, i) { - var index = i; - var length = heap.length; - var halfLength = length >>> 1; - - while (index < halfLength) { - var leftIndex = (index + 1) * 2 - 1; - var left = heap[leftIndex]; - var rightIndex = leftIndex + 1; - var right = heap[rightIndex]; // If the left or right node is smaller, swap with the smaller of those. - - if (compare(left, node) < 0) { - if (rightIndex < length && compare(right, left) < 0) { - heap[index] = right; - heap[rightIndex] = node; - index = rightIndex; - } else { - heap[index] = left; - heap[leftIndex] = node; - index = leftIndex; - } - } else if (rightIndex < length && compare(right, node) < 0) { - heap[index] = right; - heap[rightIndex] = node; - index = rightIndex; - } else { - // Neither child is smaller. Exit. - return; - } - } - } + while (index > 0) { + var parentIndex = index - 1 >>> 1; + var parent = heap[parentIndex]; - function compare(a, b) { - // Compare sort index first, then task id. - var diff = a.sortIndex - b.sortIndex; - return diff !== 0 ? diff : a.id - b.id; + if (compare(parent, node) > 0) { + // The parent is larger. Swap positions. + heap[parentIndex] = node; + heap[index] = parent; + index = parentIndex; + } else { + // The parent is smaller. Exit. + return; } + } +} - // TODO: Use symbols? - var ImmediatePriority = 1; - var UserBlockingPriority = 2; - var NormalPriority = 3; - var LowPriority = 4; - var IdlePriority = 5; - - function markTaskErrored(task, ms) {} - - /* eslint-disable no-var */ - // Math.pow(2, 30) - 1 - // 0b111111111111111111111111111111 - - var maxSigned31BitInt = 1073741823; // Times out immediately - - var IMMEDIATE_PRIORITY_TIMEOUT = -1; // Eventually times out - - var USER_BLOCKING_PRIORITY_TIMEOUT = 250; - var NORMAL_PRIORITY_TIMEOUT = 5000; - var LOW_PRIORITY_TIMEOUT = 10000; // Never times out - - var IDLE_PRIORITY_TIMEOUT = maxSigned31BitInt; // Tasks are stored on a min heap - - var taskQueue = []; - var timerQueue = []; // Incrementing id counter. Used to maintain insertion order. - - var taskIdCounter = 1; // Pausing the scheduler is useful for debugging. - var currentTask = null; - var currentPriorityLevel = NormalPriority; // This is set while performing work, to prevent re-entrance. - - var isPerformingWork = false; - var isHostCallbackScheduled = false; - var isHostTimeoutScheduled = false; - var currentMockTime = 0; - var scheduledCallback = null; - var scheduledTimeout = null; - var timeoutTime = -1; - var yieldedValues = null; - var expectedNumberOfYields = -1; - var didStop = false; - var isFlushing = false; - var needsPaint = false; - var shouldYieldForPaint = false; - var disableYieldValue = false; - - function setDisableYieldValue(newValue) { - disableYieldValue = newValue; - } +function siftDown(heap, node, i) { + var index = i; + var length = heap.length; + var halfLength = length >>> 1; + + while (index < halfLength) { + var leftIndex = (index + 1) * 2 - 1; + var left = heap[leftIndex]; + var rightIndex = leftIndex + 1; + var right = heap[rightIndex]; // If the left or right node is smaller, swap with the smaller of those. + + if (compare(left, node) < 0) { + if (rightIndex < length && compare(right, left) < 0) { + heap[index] = right; + heap[rightIndex] = node; + index = rightIndex; + } else { + heap[index] = left; + heap[leftIndex] = node; + index = leftIndex; + } + } else if (rightIndex < length && compare(right, node) < 0) { + heap[index] = right; + heap[rightIndex] = node; + index = rightIndex; + } else { + // Neither child is smaller. Exit. + return; + } + } +} - function advanceTimers(currentTime) { - // Check for tasks that are no longer delayed and add them to the queue. - var timer = peek(timerQueue); - - while (timer !== null) { - if (timer.callback === null) { - // Timer was cancelled. - pop(timerQueue); - } else if (timer.startTime <= currentTime) { - // Timer fired. Transfer to the task queue. - pop(timerQueue); - timer.sortIndex = timer.expirationTime; - push(taskQueue, timer); - } else { - // Remaining timers are pending. - return; - } +function compare(a, b) { + // Compare sort index first, then task id. + var diff = a.sortIndex - b.sortIndex; + return diff !== 0 ? diff : a.id - b.id; +} - timer = peek(timerQueue); - } - } +// TODO: Use symbols? +var ImmediatePriority = 1; +var UserBlockingPriority = 2; +var NormalPriority = 3; +var LowPriority = 4; +var IdlePriority = 5; - function handleTimeout(currentTime) { - isHostTimeoutScheduled = false; - advanceTimers(currentTime); - - if (!isHostCallbackScheduled) { - if (peek(taskQueue) !== null) { - isHostCallbackScheduled = true; - requestHostCallback(flushWork); - } else { - var firstTimer = peek(timerQueue); - - if (firstTimer !== null) { - requestHostTimeout( - handleTimeout, - firstTimer.startTime - currentTime - ); - } - } - } - } +function markTaskErrored(task, ms) { +} - function flushWork(hasTimeRemaining, initialTime) { - isHostCallbackScheduled = false; +/* eslint-disable no-var */ +// Math.pow(2, 30) - 1 +// 0b111111111111111111111111111111 - if (isHostTimeoutScheduled) { - // We scheduled a timeout but it's no longer needed. Cancel it. - isHostTimeoutScheduled = false; - cancelHostTimeout(); - } +var maxSigned31BitInt = 1073741823; // Times out immediately - isPerformingWork = true; - var previousPriorityLevel = currentPriorityLevel; +var IMMEDIATE_PRIORITY_TIMEOUT = -1; // Eventually times out - try { - var currentTime; - if (enableProfiling); - else { - // No catch in prod code path. - return workLoop(hasTimeRemaining, initialTime); - } - } finally { - currentTask = null; - currentPriorityLevel = previousPriorityLevel; - isPerformingWork = false; - } - } +var USER_BLOCKING_PRIORITY_TIMEOUT = 250; +var NORMAL_PRIORITY_TIMEOUT = 5000; +var LOW_PRIORITY_TIMEOUT = 10000; // Never times out - function workLoop(hasTimeRemaining, initialTime) { - var currentTime = initialTime; - advanceTimers(currentTime); - currentTask = peek(taskQueue); - - while (currentTask !== null && !enableSchedulerDebugging) { - if ( - currentTask.expirationTime > currentTime && - (!hasTimeRemaining || shouldYieldToHost()) - ) { - // This currentTask hasn't expired, and we've reached the deadline. - break; - } // $FlowFixMe[incompatible-use] found when upgrading Flow - - var callback = currentTask.callback; - - if (typeof callback === "function") { - // $FlowFixMe[incompatible-use] found when upgrading Flow - currentTask.callback = null; // $FlowFixMe[incompatible-use] found when upgrading Flow - - currentPriorityLevel = currentTask.priorityLevel; // $FlowFixMe[incompatible-use] found when upgrading Flow - - var didUserCallbackTimeout = - currentTask.expirationTime <= currentTime; - - var continuationCallback = callback(didUserCallbackTimeout); - currentTime = getCurrentTime(); - - if (typeof continuationCallback === "function") { - // If a continuation is returned, immediately yield to the main thread - // regardless of how much time is left in the current time slice. - // $FlowFixMe[incompatible-use] found when upgrading Flow - currentTask.callback = continuationCallback; - - advanceTimers(currentTime); - - if (shouldYieldForPaint) { - needsPaint = true; - return true; - } - } else { - if (currentTask === peek(taskQueue)) { - pop(taskQueue); - } - - advanceTimers(currentTime); - } - } else { - pop(taskQueue); - } +var IDLE_PRIORITY_TIMEOUT = maxSigned31BitInt; // Tasks are stored on a min heap - currentTask = peek(taskQueue); - } // Return whether there's additional work +var taskQueue = []; +var timerQueue = []; // Incrementing id counter. Used to maintain insertion order. - if (currentTask !== null) { - return true; - } else { - var firstTimer = peek(timerQueue); +var taskIdCounter = 1; // Pausing the scheduler is useful for debugging. +var currentTask = null; +var currentPriorityLevel = NormalPriority; // This is set while performing work, to prevent re-entrance. - if (firstTimer !== null) { - requestHostTimeout(handleTimeout, firstTimer.startTime - currentTime); - } +var isPerformingWork = false; +var isHostCallbackScheduled = false; +var isHostTimeoutScheduled = false; +var currentMockTime = 0; +var scheduledCallback = null; +var scheduledTimeout = null; +var timeoutTime = -1; +var yieldedValues = null; +var expectedNumberOfYields = -1; +var didStop = false; +var isFlushing = false; +var needsPaint = false; +var shouldYieldForPaint = false; +var disableYieldValue = false; - return false; - } - } +function setDisableYieldValue(newValue) { + disableYieldValue = newValue; +} - function unstable_runWithPriority(priorityLevel, eventHandler) { - switch (priorityLevel) { - case ImmediatePriority: - case UserBlockingPriority: - case NormalPriority: - case LowPriority: - case IdlePriority: - break; - - default: - priorityLevel = NormalPriority; - } +function advanceTimers(currentTime) { + // Check for tasks that are no longer delayed and add them to the queue. + var timer = peek(timerQueue); + + while (timer !== null) { + if (timer.callback === null) { + // Timer was cancelled. + pop(timerQueue); + } else if (timer.startTime <= currentTime) { + // Timer fired. Transfer to the task queue. + pop(timerQueue); + timer.sortIndex = timer.expirationTime; + push(taskQueue, timer); + } else { + // Remaining timers are pending. + return; + } + + timer = peek(timerQueue); + } +} - var previousPriorityLevel = currentPriorityLevel; - currentPriorityLevel = priorityLevel; +function handleTimeout(currentTime) { + isHostTimeoutScheduled = false; + advanceTimers(currentTime); - try { - return eventHandler(); - } finally { - currentPriorityLevel = previousPriorityLevel; + if (!isHostCallbackScheduled) { + if (peek(taskQueue) !== null) { + isHostCallbackScheduled = true; + requestHostCallback(flushWork); + } else { + var firstTimer = peek(timerQueue); + + if (firstTimer !== null) { + requestHostTimeout(handleTimeout, firstTimer.startTime - currentTime); } } + } +} - function unstable_next(eventHandler) { - var priorityLevel; - - switch (currentPriorityLevel) { - case ImmediatePriority: - case UserBlockingPriority: - case NormalPriority: - // Shift down to normal priority - priorityLevel = NormalPriority; - break; - - default: - // Anything lower than normal priority should remain at the current level. - priorityLevel = currentPriorityLevel; - break; - } +function flushWork(hasTimeRemaining, initialTime) { - var previousPriorityLevel = currentPriorityLevel; - currentPriorityLevel = priorityLevel; - try { - return eventHandler(); - } finally { - currentPriorityLevel = previousPriorityLevel; - } - } + isHostCallbackScheduled = false; - function unstable_wrapCallback(callback) { - var parentPriorityLevel = currentPriorityLevel; // $FlowFixMe[incompatible-return] - // $FlowFixMe[missing-this-annot] + if (isHostTimeoutScheduled) { + // We scheduled a timeout but it's no longer needed. Cancel it. + isHostTimeoutScheduled = false; + cancelHostTimeout(); + } - return function () { - // This is a fork of runWithPriority, inlined for performance. - var previousPriorityLevel = currentPriorityLevel; - currentPriorityLevel = parentPriorityLevel; + isPerformingWork = true; + var previousPriorityLevel = currentPriorityLevel; - try { - return callback.apply(this, arguments); - } finally { - currentPriorityLevel = previousPriorityLevel; - } - }; + try { + var currentTime; if (enableProfiling) ; else { + // No catch in prod code path. + return workLoop(hasTimeRemaining, initialTime); } + } finally { + currentTask = null; + currentPriorityLevel = previousPriorityLevel; + isPerformingWork = false; + } +} - function unstable_scheduleCallback(priorityLevel, callback, options) { - var currentTime = getCurrentTime(); - var startTime; +function workLoop(hasTimeRemaining, initialTime) { + var currentTime = initialTime; + advanceTimers(currentTime); + currentTask = peek(taskQueue); - if (typeof options === "object" && options !== null) { - var delay = options.delay; + while (currentTask !== null && !(enableSchedulerDebugging )) { + if (currentTask.expirationTime > currentTime && (!hasTimeRemaining || shouldYieldToHost())) { + // This currentTask hasn't expired, and we've reached the deadline. + break; + } // $FlowFixMe[incompatible-use] found when upgrading Flow - if (typeof delay === "number" && delay > 0) { - startTime = currentTime + delay; - } else { - startTime = currentTime; - } - } else { - startTime = currentTime; - } - var timeout; + var callback = currentTask.callback; - switch (priorityLevel) { - case ImmediatePriority: - timeout = IMMEDIATE_PRIORITY_TIMEOUT; - break; + if (typeof callback === 'function') { + // $FlowFixMe[incompatible-use] found when upgrading Flow + currentTask.callback = null; // $FlowFixMe[incompatible-use] found when upgrading Flow - case UserBlockingPriority: - timeout = USER_BLOCKING_PRIORITY_TIMEOUT; - break; + currentPriorityLevel = currentTask.priorityLevel; // $FlowFixMe[incompatible-use] found when upgrading Flow - case IdlePriority: - timeout = IDLE_PRIORITY_TIMEOUT; - break; + var didUserCallbackTimeout = currentTask.expirationTime <= currentTime; - case LowPriority: - timeout = LOW_PRIORITY_TIMEOUT; - break; + var continuationCallback = callback(didUserCallbackTimeout); + currentTime = getCurrentTime(); - case NormalPriority: - default: - timeout = NORMAL_PRIORITY_TIMEOUT; - break; - } + if (typeof continuationCallback === 'function') { + // If a continuation is returned, immediately yield to the main thread + // regardless of how much time is left in the current time slice. + // $FlowFixMe[incompatible-use] found when upgrading Flow + currentTask.callback = continuationCallback; + + advanceTimers(currentTime); - var expirationTime = startTime + timeout; - var newTask = { - id: taskIdCounter++, - callback: callback, - priorityLevel: priorityLevel, - startTime: startTime, - expirationTime: expirationTime, - sortIndex: -1 - }; - - if (startTime > currentTime) { - // This is a delayed task. - newTask.sortIndex = startTime; - push(timerQueue, newTask); - - if (peek(taskQueue) === null && newTask === peek(timerQueue)) { - // All tasks are delayed, and this is the task with the earliest delay. - if (isHostTimeoutScheduled) { - // Cancel an existing timeout. - cancelHostTimeout(); - } else { - isHostTimeoutScheduled = true; - } // Schedule a timeout. - - requestHostTimeout(handleTimeout, startTime - currentTime); + if (shouldYieldForPaint) { + needsPaint = true; + return true; } } else { - newTask.sortIndex = expirationTime; - push(taskQueue, newTask); - // wait until the next time we yield. - if (!isHostCallbackScheduled && !isPerformingWork) { - isHostCallbackScheduled = true; - requestHostCallback(flushWork); + if (currentTask === peek(taskQueue)) { + pop(taskQueue); } - } - return newTask; + advanceTimers(currentTime); + } + } else { + pop(taskQueue); } - function unstable_pauseExecution() {} + currentTask = peek(taskQueue); + } // Return whether there's additional work - function unstable_continueExecution() { - if (!isHostCallbackScheduled && !isPerformingWork) { - isHostCallbackScheduled = true; - requestHostCallback(flushWork); - } - } - function unstable_getFirstCallbackNode() { - return peek(taskQueue); + if (currentTask !== null) { + return true; + } else { + var firstTimer = peek(timerQueue); + + if (firstTimer !== null) { + requestHostTimeout(handleTimeout, firstTimer.startTime - currentTime); } - function unstable_cancelCallback(task) { - // remove from the queue because you can't remove arbitrary nodes from an - // array based heap, only the first one.) + return false; + } +} - task.callback = null; - } +function unstable_runWithPriority(priorityLevel, eventHandler) { + switch (priorityLevel) { + case ImmediatePriority: + case UserBlockingPriority: + case NormalPriority: + case LowPriority: + case IdlePriority: + break; + + default: + priorityLevel = NormalPriority; + } + + var previousPriorityLevel = currentPriorityLevel; + currentPriorityLevel = priorityLevel; + + try { + return eventHandler(); + } finally { + currentPriorityLevel = previousPriorityLevel; + } +} - function unstable_getCurrentPriorityLevel() { - return currentPriorityLevel; - } +function unstable_next(eventHandler) { + var priorityLevel; + + switch (currentPriorityLevel) { + case ImmediatePriority: + case UserBlockingPriority: + case NormalPriority: + // Shift down to normal priority + priorityLevel = NormalPriority; + break; + + default: + // Anything lower than normal priority should remain at the current level. + priorityLevel = currentPriorityLevel; + break; + } + + var previousPriorityLevel = currentPriorityLevel; + currentPriorityLevel = priorityLevel; + + try { + return eventHandler(); + } finally { + currentPriorityLevel = previousPriorityLevel; + } +} - function requestHostCallback(callback) { - scheduledCallback = callback; - } +function unstable_wrapCallback(callback) { + var parentPriorityLevel = currentPriorityLevel; // $FlowFixMe[incompatible-return] + // $FlowFixMe[missing-this-annot] - function requestHostTimeout(callback, ms) { - scheduledTimeout = callback; - timeoutTime = currentMockTime + ms; - } + return function () { + // This is a fork of runWithPriority, inlined for performance. + var previousPriorityLevel = currentPriorityLevel; + currentPriorityLevel = parentPriorityLevel; - function cancelHostTimeout() { - scheduledTimeout = null; - timeoutTime = -1; + try { + return callback.apply(this, arguments); + } finally { + currentPriorityLevel = previousPriorityLevel; } + }; +} - function shouldYieldToHost() { - if ( - (expectedNumberOfYields === 0 && yieldedValues === null) || - (expectedNumberOfYields !== -1 && - yieldedValues !== null && - yieldedValues.length >= expectedNumberOfYields) || - (shouldYieldForPaint && needsPaint) - ) { - // We yielded at least as many values as expected. Stop flushing. - didStop = true; - return true; - } +function unstable_scheduleCallback(priorityLevel, callback, options) { + var currentTime = getCurrentTime(); + var startTime; + + if (typeof options === 'object' && options !== null) { + var delay = options.delay; + + if (typeof delay === 'number' && delay > 0) { + startTime = currentTime + delay; + } else { + startTime = currentTime; + } + } else { + startTime = currentTime; + } + + var timeout; + + switch (priorityLevel) { + case ImmediatePriority: + timeout = IMMEDIATE_PRIORITY_TIMEOUT; + break; + + case UserBlockingPriority: + timeout = USER_BLOCKING_PRIORITY_TIMEOUT; + break; + + case IdlePriority: + timeout = IDLE_PRIORITY_TIMEOUT; + break; + + case LowPriority: + timeout = LOW_PRIORITY_TIMEOUT; + break; + + case NormalPriority: + default: + timeout = NORMAL_PRIORITY_TIMEOUT; + break; + } + + var expirationTime = startTime + timeout; + var newTask = { + id: taskIdCounter++, + callback: callback, + priorityLevel: priorityLevel, + startTime: startTime, + expirationTime: expirationTime, + sortIndex: -1 + }; + + if (startTime > currentTime) { + // This is a delayed task. + newTask.sortIndex = startTime; + push(timerQueue, newTask); + + if (peek(taskQueue) === null && newTask === peek(timerQueue)) { + // All tasks are delayed, and this is the task with the earliest delay. + if (isHostTimeoutScheduled) { + // Cancel an existing timeout. + cancelHostTimeout(); + } else { + isHostTimeoutScheduled = true; + } // Schedule a timeout. - return false; - } - function getCurrentTime() { - return currentMockTime; + requestHostTimeout(handleTimeout, startTime - currentTime); } + } else { + newTask.sortIndex = expirationTime; + push(taskQueue, newTask); + // wait until the next time we yield. + - function forceFrameRate() { - // No-op + if (!isHostCallbackScheduled && !isPerformingWork) { + isHostCallbackScheduled = true; + requestHostCallback(flushWork); } + } - function reset() { - if (isFlushing) { - throw new Error("Cannot reset while already flushing work."); - } + return newTask; +} - currentMockTime = 0; - scheduledCallback = null; - scheduledTimeout = null; - timeoutTime = -1; - yieldedValues = null; - expectedNumberOfYields = -1; - didStop = false; - isFlushing = false; - needsPaint = false; - } // Should only be used via an assertion helper that inspects the yielded values. +function unstable_pauseExecution() { +} - function unstable_flushNumberOfYields(count) { - if (isFlushing) { - throw new Error("Already flushing work."); - } +function unstable_continueExecution() { - if (scheduledCallback !== null) { - var cb = scheduledCallback; - expectedNumberOfYields = count; - isFlushing = true; - - try { - var hasMoreWork = true; - - do { - hasMoreWork = cb(true, currentMockTime); - } while (hasMoreWork && !didStop); - - if (!hasMoreWork) { - scheduledCallback = null; - } - } finally { - expectedNumberOfYields = -1; - didStop = false; - isFlushing = false; - } - } - } + if (!isHostCallbackScheduled && !isPerformingWork) { + isHostCallbackScheduled = true; + requestHostCallback(flushWork); + } +} - function unstable_flushUntilNextPaint() { - if (isFlushing) { - throw new Error("Already flushing work."); - } +function unstable_getFirstCallbackNode() { + return peek(taskQueue); +} - if (scheduledCallback !== null) { - var cb = scheduledCallback; - shouldYieldForPaint = true; - needsPaint = false; - isFlushing = true; - - try { - var hasMoreWork = true; - - do { - hasMoreWork = cb(true, currentMockTime); - } while (hasMoreWork && !didStop); - - if (!hasMoreWork) { - scheduledCallback = null; - } - } finally { - shouldYieldForPaint = false; - didStop = false; - isFlushing = false; - } - } +function unstable_cancelCallback(task) { + // remove from the queue because you can't remove arbitrary nodes from an + // array based heap, only the first one.) - return false; - } - function unstable_hasPendingWork() { - return scheduledCallback !== null; - } + task.callback = null; +} - function unstable_flushExpired() { - if (isFlushing) { - throw new Error("Already flushing work."); - } +function unstable_getCurrentPriorityLevel() { + return currentPriorityLevel; +} + +function requestHostCallback(callback) { + scheduledCallback = callback; +} - if (scheduledCallback !== null) { - isFlushing = true; +function requestHostTimeout(callback, ms) { + scheduledTimeout = callback; + timeoutTime = currentMockTime + ms; +} - try { - var hasMoreWork = scheduledCallback(false, currentMockTime); +function cancelHostTimeout() { + scheduledTimeout = null; + timeoutTime = -1; +} - if (!hasMoreWork) { - scheduledCallback = null; - } - } finally { - isFlushing = false; - } - } - } +function shouldYieldToHost() { + if (expectedNumberOfYields === 0 && yieldedValues === null || expectedNumberOfYields !== -1 && yieldedValues !== null && yieldedValues.length >= expectedNumberOfYields || shouldYieldForPaint && needsPaint) { + // We yielded at least as many values as expected. Stop flushing. + didStop = true; + return true; + } - function unstable_flushAllWithoutAsserting() { - // Returns false if no work was flushed. - if (isFlushing) { - throw new Error("Already flushing work."); - } + return false; +} - if (scheduledCallback !== null) { - var cb = scheduledCallback; - isFlushing = true; +function getCurrentTime() { + return currentMockTime; +} - try { - var hasMoreWork = true; +function forceFrameRate() {// No-op +} - do { - hasMoreWork = cb(true, currentMockTime); - } while (hasMoreWork); +function reset() { + if (isFlushing) { + throw new Error('Cannot reset while already flushing work.'); + } - if (!hasMoreWork) { - scheduledCallback = null; - } + currentMockTime = 0; + scheduledCallback = null; + scheduledTimeout = null; + timeoutTime = -1; + yieldedValues = null; + expectedNumberOfYields = -1; + didStop = false; + isFlushing = false; + needsPaint = false; +} // Should only be used via an assertion helper that inspects the yielded values. - return true; - } finally { - isFlushing = false; - } - } else { - return false; + +function unstable_flushNumberOfYields(count) { + if (isFlushing) { + throw new Error('Already flushing work.'); + } + + if (scheduledCallback !== null) { + var cb = scheduledCallback; + expectedNumberOfYields = count; + isFlushing = true; + + try { + var hasMoreWork = true; + + do { + hasMoreWork = cb(true, currentMockTime); + } while (hasMoreWork && !didStop); + + if (!hasMoreWork) { + scheduledCallback = null; } + } finally { + expectedNumberOfYields = -1; + didStop = false; + isFlushing = false; } + } +} - function unstable_clearLog() { - if (yieldedValues === null) { - return []; - } +function unstable_flushUntilNextPaint() { + if (isFlushing) { + throw new Error('Already flushing work.'); + } - var values = yieldedValues; - yieldedValues = null; - return values; - } + if (scheduledCallback !== null) { + var cb = scheduledCallback; + shouldYieldForPaint = true; + needsPaint = false; + isFlushing = true; - function unstable_flushAll() { - if (yieldedValues !== null) { - throw new Error( - "Log is not empty. Assert on the log of yielded values before " + - "flushing additional work." - ); - } + try { + var hasMoreWork = true; - unstable_flushAllWithoutAsserting(); + do { + hasMoreWork = cb(true, currentMockTime); + } while (hasMoreWork && !didStop); - if (yieldedValues !== null) { - throw new Error( - "While flushing work, something yielded a value. Use an " + - "assertion helper to assert on the log of yielded values, e.g. " + - "expect(Scheduler).toFlushAndYield([...])" - ); + if (!hasMoreWork) { + scheduledCallback = null; } + } finally { + shouldYieldForPaint = false; + didStop = false; + isFlushing = false; } + } - function log(value) { - // eslint-disable-next-line react-internal/no-production-logging - if (console.log.name === "disabledLog" || disableYieldValue) { - // If console.log has been patched, we assume we're in render - // replaying and we ignore any values yielding in the second pass. - return; - } + return false; +} - if (yieldedValues === null) { - yieldedValues = [value]; - } else { - yieldedValues.push(value); +function unstable_hasPendingWork() { + return scheduledCallback !== null; +} + +function unstable_flushExpired() { + if (isFlushing) { + throw new Error('Already flushing work.'); + } + + if (scheduledCallback !== null) { + isFlushing = true; + + try { + var hasMoreWork = scheduledCallback(false, currentMockTime); + + if (!hasMoreWork) { + scheduledCallback = null; } + } finally { + isFlushing = false; } + } +} - function unstable_advanceTime(ms) { - // eslint-disable-next-line react-internal/no-production-logging - if (console.log.name === "disabledLog" || disableYieldValue) { - // If console.log has been patched, we assume we're in render - // replaying and we ignore any time advancing in the second pass. - return; - } +function unstable_flushAllWithoutAsserting() { + // Returns false if no work was flushed. + if (isFlushing) { + throw new Error('Already flushing work.'); + } - currentMockTime += ms; + if (scheduledCallback !== null) { + var cb = scheduledCallback; + isFlushing = true; - if (scheduledTimeout !== null && timeoutTime <= currentMockTime) { - scheduledTimeout(currentMockTime); - timeoutTime = -1; - scheduledTimeout = null; + try { + var hasMoreWork = true; + + do { + hasMoreWork = cb(true, currentMockTime); + } while (hasMoreWork); + + if (!hasMoreWork) { + scheduledCallback = null; } - } - function requestPaint() { - needsPaint = true; + return true; + } finally { + isFlushing = false; } - var unstable_Profiling = null; - - exports.log = log; - exports.reset = reset; - exports.unstable_IdlePriority = IdlePriority; - exports.unstable_ImmediatePriority = ImmediatePriority; - exports.unstable_LowPriority = LowPriority; - exports.unstable_NormalPriority = NormalPriority; - exports.unstable_Profiling = unstable_Profiling; - exports.unstable_UserBlockingPriority = UserBlockingPriority; - exports.unstable_advanceTime = unstable_advanceTime; - exports.unstable_cancelCallback = unstable_cancelCallback; - exports.unstable_clearLog = unstable_clearLog; - exports.unstable_continueExecution = unstable_continueExecution; - exports.unstable_flushAll = unstable_flushAll; - exports.unstable_flushAllWithoutAsserting = - unstable_flushAllWithoutAsserting; - exports.unstable_flushExpired = unstable_flushExpired; - exports.unstable_flushNumberOfYields = unstable_flushNumberOfYields; - exports.unstable_flushUntilNextPaint = unstable_flushUntilNextPaint; - exports.unstable_forceFrameRate = forceFrameRate; - exports.unstable_getCurrentPriorityLevel = unstable_getCurrentPriorityLevel; - exports.unstable_getFirstCallbackNode = unstable_getFirstCallbackNode; - exports.unstable_hasPendingWork = unstable_hasPendingWork; - exports.unstable_next = unstable_next; - exports.unstable_now = getCurrentTime; - exports.unstable_pauseExecution = unstable_pauseExecution; - exports.unstable_requestPaint = requestPaint; - exports.unstable_runWithPriority = unstable_runWithPriority; - exports.unstable_scheduleCallback = unstable_scheduleCallback; - exports.unstable_setDisableYieldValue = setDisableYieldValue; - exports.unstable_shouldYield = shouldYieldToHost; - exports.unstable_wrapCallback = unstable_wrapCallback; + } else { + return false; + } +} + +function unstable_clearLog() { + if (yieldedValues === null) { + return []; + } + + var values = yieldedValues; + yieldedValues = null; + return values; +} + +function unstable_flushAll() { + if (yieldedValues !== null) { + throw new Error('Log is not empty. Assert on the log of yielded values before ' + 'flushing additional work.'); + } + + unstable_flushAllWithoutAsserting(); + + if (yieldedValues !== null) { + throw new Error('While flushing work, something yielded a value. Use an ' + 'assertion helper to assert on the log of yielded values, e.g. ' + 'expect(Scheduler).toFlushAndYield([...])'); + } +} + +function log(value) { + // eslint-disable-next-line react-internal/no-production-logging + if (console.log.name === 'disabledLog' || disableYieldValue) { + // If console.log has been patched, we assume we're in render + // replaying and we ignore any values yielding in the second pass. + return; + } + + if (yieldedValues === null) { + yieldedValues = [value]; + } else { + yieldedValues.push(value); + } +} + +function unstable_advanceTime(ms) { + // eslint-disable-next-line react-internal/no-production-logging + if (console.log.name === 'disabledLog' || disableYieldValue) { + // If console.log has been patched, we assume we're in render + // replaying and we ignore any time advancing in the second pass. + return; + } + + currentMockTime += ms; + + if (scheduledTimeout !== null && timeoutTime <= currentMockTime) { + scheduledTimeout(currentMockTime); + timeoutTime = -1; + scheduledTimeout = null; + } +} + +function requestPaint() { + needsPaint = true; +} +var unstable_Profiling = null; + +exports.log = log; +exports.reset = reset; +exports.unstable_IdlePriority = IdlePriority; +exports.unstable_ImmediatePriority = ImmediatePriority; +exports.unstable_LowPriority = LowPriority; +exports.unstable_NormalPriority = NormalPriority; +exports.unstable_Profiling = unstable_Profiling; +exports.unstable_UserBlockingPriority = UserBlockingPriority; +exports.unstable_advanceTime = unstable_advanceTime; +exports.unstable_cancelCallback = unstable_cancelCallback; +exports.unstable_clearLog = unstable_clearLog; +exports.unstable_continueExecution = unstable_continueExecution; +exports.unstable_flushAll = unstable_flushAll; +exports.unstable_flushAllWithoutAsserting = unstable_flushAllWithoutAsserting; +exports.unstable_flushExpired = unstable_flushExpired; +exports.unstable_flushNumberOfYields = unstable_flushNumberOfYields; +exports.unstable_flushUntilNextPaint = unstable_flushUntilNextPaint; +exports.unstable_forceFrameRate = forceFrameRate; +exports.unstable_getCurrentPriorityLevel = unstable_getCurrentPriorityLevel; +exports.unstable_getFirstCallbackNode = unstable_getFirstCallbackNode; +exports.unstable_hasPendingWork = unstable_hasPendingWork; +exports.unstable_next = unstable_next; +exports.unstable_now = getCurrentTime; +exports.unstable_pauseExecution = unstable_pauseExecution; +exports.unstable_requestPaint = requestPaint; +exports.unstable_runWithPriority = unstable_runWithPriority; +exports.unstable_scheduleCallback = unstable_scheduleCallback; +exports.unstable_setDisableYieldValue = setDisableYieldValue; +exports.unstable_shouldYield = shouldYieldToHost; +exports.unstable_wrapCallback = unstable_wrapCallback; })(); } 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 334e9bbfa3444..35fd39d997422 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 @@ -f5ce642deed7c74c5ae5df54ec4340a8d028eac9 +0e0b69321a6fcfe8a3eaae3b1016beb110437b38 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 59246472fea1c..51237bb013871 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 @@ -7,1411 +7,1273 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<<84d884f07a1d5851f53652012b257860>> + * @generated SignedSource<> */ -"use strict"; +'use strict'; if (__DEV__) { - (function () { - "use strict"; - - /* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */ - if ( - typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== "undefined" && - typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart === - "function" - ) { - __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error()); - } - require("react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore"); - var React = require("react"); - var ReactNativePrivateInterface = require("react-native/Libraries/ReactPrivate/ReactNativePrivateInterface"); - var dynamicFlagsUntyped = require("ReactNativeInternalFeatureFlags"); - var Scheduler = require("scheduler"); - - var ReactSharedInternals = - React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE; - - var suppressWarning = false; - function setSuppressWarning(newSuppressWarning) { - { - suppressWarning = newSuppressWarning; - } - } // In DEV, calls to console.warn and console.error get replaced - // by calls to these methods by a Babel plugin. - // - // In PROD (or in packages without access to React internals), - // they are left as they are instead. + (function() { - function warn(format) { - { - if (!suppressWarning) { - for ( - var _len = arguments.length, - args = new Array(_len > 1 ? _len - 1 : 0), - _key = 1; - _key < _len; - _key++ - ) { - args[_key - 1] = arguments[_key]; - } + 'use strict'; - printWarning("warn", format, args); - } +/* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */ +if ( + typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' && + typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart === + 'function' +) { + __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error()); +} + require('react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore'); +var React = require('react'); +var ReactNativePrivateInterface = require('react-native/Libraries/ReactPrivate/ReactNativePrivateInterface'); +var dynamicFlagsUntyped = require('ReactNativeInternalFeatureFlags'); +var Scheduler = require('scheduler'); + +var ReactSharedInternals = React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE; + +var suppressWarning = false; +function setSuppressWarning(newSuppressWarning) { + { + suppressWarning = newSuppressWarning; + } +} // In DEV, calls to console.warn and console.error get replaced +// by calls to these methods by a Babel plugin. +// +// In PROD (or in packages without access to React internals), +// they are left as they are instead. + +function warn(format) { + { + if (!suppressWarning) { + for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + + printWarning('warn', format, args); + } + } +} +function error(format) { + { + if (!suppressWarning) { + for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { + args[_key2 - 1] = arguments[_key2]; } - } - function error(format) { - { - if (!suppressWarning) { - for ( - var _len2 = arguments.length, - args = new Array(_len2 > 1 ? _len2 - 1 : 0), - _key2 = 1; - _key2 < _len2; - _key2++ - ) { - args[_key2 - 1] = arguments[_key2]; - } - printWarning("error", format, args); - } - } + printWarning('error', format, args); } + } +} - function printWarning(level, format, args) { - // When changing this logic, you might want to also - // update consoleWithStackDev.www.js as well. - { - var stack = ReactSharedInternals.getStackAddendum(); +function printWarning(level, format, args) { + // When changing this logic, you might want to also + // update consoleWithStackDev.www.js as well. + { + var stack = ReactSharedInternals.getStackAddendum(); - if (stack !== "") { - format += "%s"; - args = args.concat([stack]); - } // eslint-disable-next-line react-internal/safe-string-coercion + if (stack !== '') { + format += '%s'; + args = args.concat([stack]); + } // eslint-disable-next-line react-internal/safe-string-coercion - var argsWithFormat = args.map(function (item) { - return String(item); - }); // Careful: RN currently depends on this prefix - argsWithFormat.unshift("Warning: " + format); // We intentionally don't use spread (or .apply) directly because it - // breaks IE9: https://github.com/facebook/react/issues/13610 - // eslint-disable-next-line react-internal/no-production-logging + var argsWithFormat = args.map(function (item) { + return String(item); + }); // Careful: RN currently depends on this prefix - Function.prototype.apply.call(console[level], console, argsWithFormat); - } - } + argsWithFormat.unshift('Warning: ' + format); // We intentionally don't use spread (or .apply) directly because it + // breaks IE9: https://github.com/facebook/react/issues/13610 + // eslint-disable-next-line react-internal/no-production-logging - var isArrayImpl = Array.isArray; // eslint-disable-next-line no-redeclare + Function.prototype.apply.call(console[level], console, argsWithFormat); + } +} - function isArray(a) { - return isArrayImpl(a); - } +var isArrayImpl = Array.isArray; // eslint-disable-next-line no-redeclare - var hasError = false; - var caughtError = null; - var getFiberCurrentPropsFromNode$1 = null; - var getInstanceFromNode$1 = null; - var getNodeFromInstance$1 = null; - function setComponentTree( - getFiberCurrentPropsFromNodeImpl, - getInstanceFromNodeImpl, - getNodeFromInstanceImpl - ) { - getFiberCurrentPropsFromNode$1 = getFiberCurrentPropsFromNodeImpl; - getInstanceFromNode$1 = getInstanceFromNodeImpl; - getNodeFromInstance$1 = getNodeFromInstanceImpl; +function isArray(a) { + return isArrayImpl(a); +} - { - if (!getNodeFromInstance$1 || !getInstanceFromNode$1) { - error( - "Injected " + - "module is missing getNodeFromInstance or getInstanceFromNode." - ); - } - } - } +var hasError = false; +var caughtError = null; +var getFiberCurrentPropsFromNode$1 = null; +var getInstanceFromNode$1 = null; +var getNodeFromInstance$1 = null; +function setComponentTree(getFiberCurrentPropsFromNodeImpl, getInstanceFromNodeImpl, getNodeFromInstanceImpl) { + getFiberCurrentPropsFromNode$1 = getFiberCurrentPropsFromNodeImpl; + getInstanceFromNode$1 = getInstanceFromNodeImpl; + getNodeFromInstance$1 = getNodeFromInstanceImpl; + + { + if (!getNodeFromInstance$1 || !getInstanceFromNode$1) { + error('Injected ' + 'module is missing getNodeFromInstance or getInstanceFromNode.'); + } + } +} - function validateEventDispatches(event) { - { - var dispatchListeners = event._dispatchListeners; - var dispatchInstances = event._dispatchInstances; - var listenersIsArr = isArray(dispatchListeners); - var listenersLen = listenersIsArr - ? dispatchListeners.length - : dispatchListeners - ? 1 - : 0; - var instancesIsArr = isArray(dispatchInstances); - var instancesLen = instancesIsArr - ? dispatchInstances.length - : dispatchInstances - ? 1 - : 0; - - if ( - instancesIsArr !== listenersIsArr || - instancesLen !== listenersLen - ) { - error("EventPluginUtils: Invalid `event`."); - } - } +function validateEventDispatches(event) { + { + var dispatchListeners = event._dispatchListeners; + var dispatchInstances = event._dispatchInstances; + var listenersIsArr = isArray(dispatchListeners); + var listenersLen = listenersIsArr ? dispatchListeners.length : dispatchListeners ? 1 : 0; + var instancesIsArr = isArray(dispatchInstances); + var instancesLen = instancesIsArr ? dispatchInstances.length : dispatchInstances ? 1 : 0; + + if (instancesIsArr !== listenersIsArr || instancesLen !== listenersLen) { + error('EventPluginUtils: Invalid `event`.'); } - /** - * Dispatch the event to the listener. - * @param {SyntheticEvent} event SyntheticEvent to handle - * @param {function} listener Application-level callback - * @param {*} inst Internal component instance - */ + } +} +/** + * Dispatch the event to the listener. + * @param {SyntheticEvent} event SyntheticEvent to handle + * @param {function} listener Application-level callback + * @param {*} inst Internal component instance + */ - function executeDispatch(event, listener, inst) { - event.currentTarget = getNodeFromInstance$1(inst); - try { - listener(event); - } catch (error) { - if (!hasError) { - hasError = true; - caughtError = error; - } - } +function executeDispatch(event, listener, inst) { + event.currentTarget = getNodeFromInstance$1(inst); - event.currentTarget = null; + try { + listener(event); + } catch (error) { + if (!hasError) { + hasError = true; + caughtError = error; } - /** - * Standard/simple iteration through an event's collected dispatches. - */ + } - function executeDispatchesInOrder(event) { - var dispatchListeners = event._dispatchListeners; - var dispatchInstances = event._dispatchInstances; + event.currentTarget = null; +} +/** + * Standard/simple iteration through an event's collected dispatches. + */ - { - validateEventDispatches(event); - } +function executeDispatchesInOrder(event) { + var dispatchListeners = event._dispatchListeners; + var dispatchInstances = event._dispatchInstances; - if (isArray(dispatchListeners)) { - for (var i = 0; i < dispatchListeners.length; i++) { - if (event.isPropagationStopped()) { - break; - } // Listeners and Instances are two parallel arrays that are always in sync. + { + validateEventDispatches(event); + } - executeDispatch(event, dispatchListeners[i], dispatchInstances[i]); - } - } else if (dispatchListeners) { - executeDispatch(event, dispatchListeners, dispatchInstances); - } + if (isArray(dispatchListeners)) { + for (var i = 0; i < dispatchListeners.length; i++) { + if (event.isPropagationStopped()) { + break; + } // Listeners and Instances are two parallel arrays that are always in sync. - event._dispatchListeners = null; - event._dispatchInstances = null; - } - /** - * Standard/simple iteration through an event's collected dispatches, but stops - * at the first dispatch execution returning true, and returns that id. - * - * @return {?string} id of the first dispatch execution who's listener returns - * true, or null if no listener returned true. - */ - function executeDispatchesInOrderStopAtTrueImpl(event) { - var dispatchListeners = event._dispatchListeners; - var dispatchInstances = event._dispatchInstances; + executeDispatch(event, dispatchListeners[i], dispatchInstances[i]); + } + } else if (dispatchListeners) { + executeDispatch(event, dispatchListeners, dispatchInstances); + } - { - validateEventDispatches(event); - } + event._dispatchListeners = null; + event._dispatchInstances = null; +} +/** + * Standard/simple iteration through an event's collected dispatches, but stops + * at the first dispatch execution returning true, and returns that id. + * + * @return {?string} id of the first dispatch execution who's listener returns + * true, or null if no listener returned true. + */ - if (isArray(dispatchListeners)) { - for (var i = 0; i < dispatchListeners.length; i++) { - if (event.isPropagationStopped()) { - break; - } // Listeners and Instances are two parallel arrays that are always in sync. +function executeDispatchesInOrderStopAtTrueImpl(event) { + var dispatchListeners = event._dispatchListeners; + var dispatchInstances = event._dispatchInstances; - if (dispatchListeners[i](event, dispatchInstances[i])) { - return dispatchInstances[i]; - } - } - } else if (dispatchListeners) { - if (dispatchListeners(event, dispatchInstances)) { - return dispatchInstances; - } - } + { + validateEventDispatches(event); + } - return null; - } - /** - * @see executeDispatchesInOrderStopAtTrueImpl - */ + if (isArray(dispatchListeners)) { + for (var i = 0; i < dispatchListeners.length; i++) { + if (event.isPropagationStopped()) { + break; + } // Listeners and Instances are two parallel arrays that are always in sync. - function executeDispatchesInOrderStopAtTrue(event) { - var ret = executeDispatchesInOrderStopAtTrueImpl(event); - event._dispatchInstances = null; - event._dispatchListeners = null; - return ret; - } - /** - * Execution of a "direct" dispatch - there must be at most one dispatch - * accumulated on the event or it is considered an error. It doesn't really make - * sense for an event with multiple dispatches (bubbled) to keep track of the - * return values at each dispatch execution, but it does tend to make sense when - * dealing with "direct" dispatches. - * - * @return {*} The return value of executing the single dispatch. - */ - function executeDirectDispatch(event) { - { - validateEventDispatches(event); + if (dispatchListeners[i](event, dispatchInstances[i])) { + return dispatchInstances[i]; } + } + } else if (dispatchListeners) { + if (dispatchListeners(event, dispatchInstances)) { + return dispatchInstances; + } + } - var dispatchListener = event._dispatchListeners; - var dispatchInstance = event._dispatchInstances; + return null; +} +/** + * @see executeDispatchesInOrderStopAtTrueImpl + */ - if (isArray(dispatchListener)) { - throw new Error("Invalid `event`."); - } - event.currentTarget = dispatchListener - ? getNodeFromInstance$1(dispatchInstance) - : null; - var res = dispatchListener ? dispatchListener(event) : null; - event.currentTarget = null; - event._dispatchListeners = null; - event._dispatchInstances = null; - return res; - } - /** - * @param {SyntheticEvent} event - * @return {boolean} True iff number of dispatches accumulated is greater than 0. - */ +function executeDispatchesInOrderStopAtTrue(event) { + var ret = executeDispatchesInOrderStopAtTrueImpl(event); + event._dispatchInstances = null; + event._dispatchListeners = null; + return ret; +} +/** + * Execution of a "direct" dispatch - there must be at most one dispatch + * accumulated on the event or it is considered an error. It doesn't really make + * sense for an event with multiple dispatches (bubbled) to keep track of the + * return values at each dispatch execution, but it does tend to make sense when + * dealing with "direct" dispatches. + * + * @return {*} The return value of executing the single dispatch. + */ - function hasDispatches(event) { - return !!event._dispatchListeners; - } - function rethrowCaughtError() { - if (hasError) { - var error = caughtError; - hasError = false; - caughtError = null; - throw error; - } - } +function executeDirectDispatch(event) { + { + validateEventDispatches(event); + } - var assign = Object.assign; + var dispatchListener = event._dispatchListeners; + var dispatchInstance = event._dispatchInstances; - var EVENT_POOL_SIZE = 10; - /** - * @interface Event - * @see http://www.w3.org/TR/DOM-Level-3-Events/ - */ + if (isArray(dispatchListener)) { + throw new Error('Invalid `event`.'); + } - var EventInterface = { - type: null, - target: null, - // currentTarget is set when dispatching; no use in copying it here - currentTarget: function () { - return null; - }, - eventPhase: null, - bubbles: null, - cancelable: null, - timeStamp: function (event) { - return event.timeStamp || Date.now(); - }, - defaultPrevented: null, - isTrusted: null - }; + event.currentTarget = dispatchListener ? getNodeFromInstance$1(dispatchInstance) : null; + var res = dispatchListener ? dispatchListener(event) : null; + event.currentTarget = null; + event._dispatchListeners = null; + event._dispatchInstances = null; + return res; +} +/** + * @param {SyntheticEvent} event + * @return {boolean} True iff number of dispatches accumulated is greater than 0. + */ - function functionThatReturnsTrue() { - return true; - } +function hasDispatches(event) { + return !!event._dispatchListeners; +} +function rethrowCaughtError() { + if (hasError) { + var error = caughtError; + hasError = false; + caughtError = null; + throw error; + } +} - function functionThatReturnsFalse() { - return false; - } - /** - * Synthetic events are dispatched by event plugins, typically in response to a - * top-level event delegation handler. - * - * These systems should generally use pooling to reduce the frequency of garbage - * collection. The system should check `isPersistent` to determine whether the - * event should be released into the pool after being dispatched. Users that - * need a persisted event should invoke `persist`. - * - * Synthetic events (and subclasses) implement the DOM Level 3 Events API by - * normalizing browser quirks. Subclasses do not necessarily have to implement a - * DOM interface; custom application-specific events can also subclass this. - * - * @param {object} dispatchConfig Configuration used to dispatch this event. - * @param {*} targetInst Marker identifying the event target. - * @param {object} nativeEvent Native browser event. - * @param {DOMEventTarget} nativeEventTarget Target node. - */ +var assign = Object.assign; - function SyntheticEvent( - dispatchConfig, - targetInst, - nativeEvent, - nativeEventTarget - ) { - { - // these have a getter/setter for warnings - delete this.nativeEvent; - delete this.preventDefault; - delete this.stopPropagation; - delete this.isDefaultPrevented; - delete this.isPropagationStopped; - } - - this.dispatchConfig = dispatchConfig; - this._targetInst = targetInst; - this.nativeEvent = nativeEvent; - this._dispatchListeners = null; - this._dispatchInstances = null; - var Interface = this.constructor.Interface; - - for (var propName in Interface) { - if (!Interface.hasOwnProperty(propName)) { - continue; - } +var EVENT_POOL_SIZE = 10; +/** + * @interface Event + * @see http://www.w3.org/TR/DOM-Level-3-Events/ + */ - { - delete this[propName]; // this has a getter/setter for warnings - } +var EventInterface = { + type: null, + target: null, + // currentTarget is set when dispatching; no use in copying it here + currentTarget: function () { + return null; + }, + eventPhase: null, + bubbles: null, + cancelable: null, + timeStamp: function (event) { + return event.timeStamp || Date.now(); + }, + defaultPrevented: null, + isTrusted: null +}; + +function functionThatReturnsTrue() { + return true; +} - var normalize = Interface[propName]; +function functionThatReturnsFalse() { + return false; +} +/** + * Synthetic events are dispatched by event plugins, typically in response to a + * top-level event delegation handler. + * + * These systems should generally use pooling to reduce the frequency of garbage + * collection. The system should check `isPersistent` to determine whether the + * event should be released into the pool after being dispatched. Users that + * need a persisted event should invoke `persist`. + * + * Synthetic events (and subclasses) implement the DOM Level 3 Events API by + * normalizing browser quirks. Subclasses do not necessarily have to implement a + * DOM interface; custom application-specific events can also subclass this. + * + * @param {object} dispatchConfig Configuration used to dispatch this event. + * @param {*} targetInst Marker identifying the event target. + * @param {object} nativeEvent Native browser event. + * @param {DOMEventTarget} nativeEventTarget Target node. + */ - if (normalize) { - this[propName] = normalize(nativeEvent); - } else { - if (propName === "target") { - this.target = nativeEventTarget; - } else { - this[propName] = nativeEvent[propName]; - } - } - } - var defaultPrevented = - nativeEvent.defaultPrevented != null - ? nativeEvent.defaultPrevented - : nativeEvent.returnValue === false; +function SyntheticEvent(dispatchConfig, targetInst, nativeEvent, nativeEventTarget) { + { + // these have a getter/setter for warnings + delete this.nativeEvent; + delete this.preventDefault; + delete this.stopPropagation; + delete this.isDefaultPrevented; + delete this.isPropagationStopped; + } - if (defaultPrevented) { - this.isDefaultPrevented = functionThatReturnsTrue; - } else { - this.isDefaultPrevented = functionThatReturnsFalse; - } + this.dispatchConfig = dispatchConfig; + this._targetInst = targetInst; + this.nativeEvent = nativeEvent; + this._dispatchListeners = null; + this._dispatchInstances = null; + var Interface = this.constructor.Interface; - this.isPropagationStopped = functionThatReturnsFalse; - return this; + for (var propName in Interface) { + if (!Interface.hasOwnProperty(propName)) { + continue; } - assign(SyntheticEvent.prototype, { - preventDefault: function () { - this.defaultPrevented = true; - var event = this.nativeEvent; + { + delete this[propName]; // this has a getter/setter for warnings + } - if (!event) { - return; - } + var normalize = Interface[propName]; - if (event.preventDefault) { - event.preventDefault(); - } else if (typeof event.returnValue !== "unknown") { - event.returnValue = false; - } + if (normalize) { + this[propName] = normalize(nativeEvent); + } else { + if (propName === 'target') { + this.target = nativeEventTarget; + } else { + this[propName] = nativeEvent[propName]; + } + } + } - this.isDefaultPrevented = functionThatReturnsTrue; - }, - stopPropagation: function () { - var event = this.nativeEvent; + var defaultPrevented = nativeEvent.defaultPrevented != null ? nativeEvent.defaultPrevented : nativeEvent.returnValue === false; - if (!event) { - return; - } + if (defaultPrevented) { + this.isDefaultPrevented = functionThatReturnsTrue; + } else { + this.isDefaultPrevented = functionThatReturnsFalse; + } - if (event.stopPropagation) { - event.stopPropagation(); - } else if (typeof event.cancelBubble !== "unknown") { - // The ChangeEventPlugin registers a "propertychange" event for - // IE. This event does not support bubbling or cancelling, and - // any references to cancelBubble throw "Member not found". A - // typeof check of "unknown" circumvents this issue (and is also - // IE specific). - event.cancelBubble = true; - } - - this.isPropagationStopped = functionThatReturnsTrue; - }, - - /** - * We release all dispatched `SyntheticEvent`s after each event loop, adding - * them back into the pool. This allows a way to hold onto a reference that - * won't be added back into the pool. - */ - persist: function () { - this.isPersistent = functionThatReturnsTrue; - }, - - /** - * Checks if this event should be released back into the pool. - * - * @return {boolean} True if this should not be released, false otherwise. - */ - isPersistent: functionThatReturnsFalse, - - /** - * `PooledClass` looks for `destructor` on each instance it releases. - */ - destructor: function () { - var Interface = this.constructor.Interface; - - for (var propName in Interface) { - { - Object.defineProperty( - this, - propName, - getPooledWarningPropertyDefinition(propName, Interface[propName]) - ); - } - } + this.isPropagationStopped = functionThatReturnsFalse; + return this; +} - this.dispatchConfig = null; - this._targetInst = null; - this.nativeEvent = null; - this.isDefaultPrevented = functionThatReturnsFalse; - this.isPropagationStopped = functionThatReturnsFalse; - this._dispatchListeners = null; - this._dispatchInstances = null; +assign(SyntheticEvent.prototype, { + preventDefault: function () { + this.defaultPrevented = true; + var event = this.nativeEvent; - { - Object.defineProperty( - this, - "nativeEvent", - getPooledWarningPropertyDefinition("nativeEvent", null) - ); - Object.defineProperty( - this, - "isDefaultPrevented", - getPooledWarningPropertyDefinition( - "isDefaultPrevented", - functionThatReturnsFalse - ) - ); - Object.defineProperty( - this, - "isPropagationStopped", - getPooledWarningPropertyDefinition( - "isPropagationStopped", - functionThatReturnsFalse - ) - ); - Object.defineProperty( - this, - "preventDefault", - getPooledWarningPropertyDefinition("preventDefault", function () {}) - ); - Object.defineProperty( - this, - "stopPropagation", - getPooledWarningPropertyDefinition( - "stopPropagation", - function () {} - ) - ); - } - } - }); - SyntheticEvent.Interface = EventInterface; - /** - * Helper to reduce boilerplate when creating subclasses. - */ + if (!event) { + return; + } - SyntheticEvent.extend = function (Interface) { - var Super = this; + if (event.preventDefault) { + event.preventDefault(); + } else if (typeof event.returnValue !== 'unknown') { + event.returnValue = false; + } - var E = function () {}; + this.isDefaultPrevented = functionThatReturnsTrue; + }, + stopPropagation: function () { + var event = this.nativeEvent; - E.prototype = Super.prototype; - var prototype = new E(); + if (!event) { + return; + } - function Class() { - return Super.apply(this, arguments); - } + if (event.stopPropagation) { + event.stopPropagation(); + } else if (typeof event.cancelBubble !== 'unknown') { + // The ChangeEventPlugin registers a "propertychange" event for + // IE. This event does not support bubbling or cancelling, and + // any references to cancelBubble throw "Member not found". A + // typeof check of "unknown" circumvents this issue (and is also + // IE specific). + event.cancelBubble = true; + } - assign(prototype, Class.prototype); - Class.prototype = prototype; - Class.prototype.constructor = Class; - Class.Interface = assign({}, Super.Interface, Interface); - Class.extend = Super.extend; - addEventPoolingTo(Class); - return Class; - }; + this.isPropagationStopped = functionThatReturnsTrue; + }, - addEventPoolingTo(SyntheticEvent); - /** - * Helper to nullify syntheticEvent instance properties when destructing - * - * @param {String} propName - * @param {?object} getVal - * @return {object} defineProperty object - */ + /** + * We release all dispatched `SyntheticEvent`s after each event loop, adding + * them back into the pool. This allows a way to hold onto a reference that + * won't be added back into the pool. + */ + persist: function () { + this.isPersistent = functionThatReturnsTrue; + }, - function getPooledWarningPropertyDefinition(propName, getVal) { - function set(val) { - var action = isFunction ? "setting the method" : "setting the property"; - warn(action, "This is effectively a no-op"); - return val; - } + /** + * Checks if this event should be released back into the pool. + * + * @return {boolean} True if this should not be released, false otherwise. + */ + isPersistent: functionThatReturnsFalse, - function get() { - var action = isFunction - ? "accessing the method" - : "accessing the property"; - var result = isFunction - ? "This is a no-op function" - : "This is set to null"; - warn(action, result); - return getVal; - } + /** + * `PooledClass` looks for `destructor` on each instance it releases. + */ + destructor: function () { + var Interface = this.constructor.Interface; - function warn(action, result) { - { - error( - "This synthetic event is reused for performance reasons. If you're seeing this, " + - "you're %s `%s` on a released/nullified synthetic event. %s. " + - "If you must keep the original synthetic event around, use event.persist(). " + - "See https://react.dev/link/event-pooling for more information.", - action, - propName, - result - ); - } + for (var propName in Interface) { + { + Object.defineProperty(this, propName, getPooledWarningPropertyDefinition(propName, Interface[propName])); } - - var isFunction = typeof getVal === "function"; - return { - configurable: true, - set: set, - get: get - }; } - function createOrGetPooledEvent( - dispatchConfig, - targetInst, - nativeEvent, - nativeInst - ) { - var EventConstructor = this; + this.dispatchConfig = null; + this._targetInst = null; + this.nativeEvent = null; + this.isDefaultPrevented = functionThatReturnsFalse; + this.isPropagationStopped = functionThatReturnsFalse; + this._dispatchListeners = null; + this._dispatchInstances = null; - if (EventConstructor.eventPool.length) { - var instance = EventConstructor.eventPool.pop(); - EventConstructor.call( - instance, - dispatchConfig, - targetInst, - nativeEvent, - nativeInst - ); - return instance; - } + { + Object.defineProperty(this, 'nativeEvent', getPooledWarningPropertyDefinition('nativeEvent', null)); + Object.defineProperty(this, 'isDefaultPrevented', getPooledWarningPropertyDefinition('isDefaultPrevented', functionThatReturnsFalse)); + Object.defineProperty(this, 'isPropagationStopped', getPooledWarningPropertyDefinition('isPropagationStopped', functionThatReturnsFalse)); + Object.defineProperty(this, 'preventDefault', getPooledWarningPropertyDefinition('preventDefault', function () {})); + Object.defineProperty(this, 'stopPropagation', getPooledWarningPropertyDefinition('stopPropagation', function () {})); + } + } +}); +SyntheticEvent.Interface = EventInterface; +/** + * Helper to reduce boilerplate when creating subclasses. + */ - return new EventConstructor( - dispatchConfig, - targetInst, - nativeEvent, - nativeInst - ); - } +SyntheticEvent.extend = function (Interface) { + var Super = this; - function releasePooledEvent(event) { - var EventConstructor = this; + var E = function () {}; - if (!(event instanceof EventConstructor)) { - throw new Error( - "Trying to release an event instance into a pool of a different type." - ); - } + E.prototype = Super.prototype; + var prototype = new E(); - event.destructor(); + function Class() { + return Super.apply(this, arguments); + } - if (EventConstructor.eventPool.length < EVENT_POOL_SIZE) { - EventConstructor.eventPool.push(event); - } - } + assign(prototype, Class.prototype); + Class.prototype = prototype; + Class.prototype.constructor = Class; + Class.Interface = assign({}, Super.Interface, Interface); + Class.extend = Super.extend; + addEventPoolingTo(Class); + return Class; +}; + +addEventPoolingTo(SyntheticEvent); +/** + * Helper to nullify syntheticEvent instance properties when destructing + * + * @param {String} propName + * @param {?object} getVal + * @return {object} defineProperty object + */ - function addEventPoolingTo(EventConstructor) { - EventConstructor.getPooled = createOrGetPooledEvent; - EventConstructor.eventPool = []; - EventConstructor.release = releasePooledEvent; +function getPooledWarningPropertyDefinition(propName, getVal) { + function set(val) { + var action = isFunction ? 'setting the method' : 'setting the property'; + warn(action, 'This is effectively a no-op'); + return val; + } + + function get() { + var action = isFunction ? 'accessing the method' : 'accessing the property'; + var result = isFunction ? 'This is a no-op function' : 'This is set to null'; + warn(action, result); + return getVal; + } + + function warn(action, result) { + { + error("This synthetic event is reused for performance reasons. If you're seeing this, " + "you're %s `%s` on a released/nullified synthetic event. %s. " + 'If you must keep the original synthetic event around, use event.persist(). ' + 'See https://react.dev/link/event-pooling for more information.', action, propName, result); } + } - /** - * `touchHistory` isn't actually on the native event, but putting it in the - * interface will ensure that it is cleaned up when pooled/destroyed. The - * `ResponderEventPlugin` will populate it appropriately. - */ + var isFunction = typeof getVal === 'function'; + return { + configurable: true, + set: set, + get: get + }; +} - var ResponderSyntheticEvent = SyntheticEvent.extend({ - touchHistory: function (nativeEvent) { - return null; // Actually doesn't even look at the native event. - } - }); +function createOrGetPooledEvent(dispatchConfig, targetInst, nativeEvent, nativeInst) { + var EventConstructor = this; - var TOP_TOUCH_START = "topTouchStart"; - var TOP_TOUCH_MOVE = "topTouchMove"; - var TOP_TOUCH_END = "topTouchEnd"; - var TOP_TOUCH_CANCEL = "topTouchCancel"; - var TOP_SCROLL = "topScroll"; - var TOP_SELECTION_CHANGE = "topSelectionChange"; - function isStartish(topLevelType) { - return topLevelType === TOP_TOUCH_START; - } - function isMoveish(topLevelType) { - return topLevelType === TOP_TOUCH_MOVE; - } - function isEndish(topLevelType) { - return ( - topLevelType === TOP_TOUCH_END || topLevelType === TOP_TOUCH_CANCEL - ); - } - var startDependencies = [TOP_TOUCH_START]; - var moveDependencies = [TOP_TOUCH_MOVE]; - var endDependencies = [TOP_TOUCH_CANCEL, TOP_TOUCH_END]; + if (EventConstructor.eventPool.length) { + var instance = EventConstructor.eventPool.pop(); + EventConstructor.call(instance, dispatchConfig, targetInst, nativeEvent, nativeInst); + return instance; + } - /** - * Tracks the position and time of each active touch by `touch.identifier`. We - * should typically only see IDs in the range of 1-20 because IDs get recycled - * when touches end and start again. - */ + return new EventConstructor(dispatchConfig, targetInst, nativeEvent, nativeInst); +} - var MAX_TOUCH_BANK = 20; - var touchBank = []; - var touchHistory = { - touchBank: touchBank, - numberActiveTouches: 0, - // If there is only one active touch, we remember its location. This prevents - // us having to loop through all of the touches all the time in the most - // common case. - indexOfSingleActiveTouch: -1, - mostRecentTimeStamp: 0 - }; +function releasePooledEvent(event) { + var EventConstructor = this; - function timestampForTouch(touch) { - // The legacy internal implementation provides "timeStamp", which has been - // renamed to "timestamp". Let both work for now while we iron it out - // TODO (evv): rename timeStamp to timestamp in internal code - return touch.timeStamp || touch.timestamp; - } - /** - * TODO: Instead of making gestures recompute filtered velocity, we could - * include a built in velocity computation that can be reused globally. - */ + if (!(event instanceof EventConstructor)) { + throw new Error('Trying to release an event instance into a pool of a different type.'); + } - function createTouchRecord(touch) { - return { - touchActive: true, - startPageX: touch.pageX, - startPageY: touch.pageY, - startTimeStamp: timestampForTouch(touch), - currentPageX: touch.pageX, - currentPageY: touch.pageY, - currentTimeStamp: timestampForTouch(touch), - previousPageX: touch.pageX, - previousPageY: touch.pageY, - previousTimeStamp: timestampForTouch(touch) - }; - } + event.destructor(); - function resetTouchRecord(touchRecord, touch) { - touchRecord.touchActive = true; - touchRecord.startPageX = touch.pageX; - touchRecord.startPageY = touch.pageY; - touchRecord.startTimeStamp = timestampForTouch(touch); - touchRecord.currentPageX = touch.pageX; - touchRecord.currentPageY = touch.pageY; - touchRecord.currentTimeStamp = timestampForTouch(touch); - touchRecord.previousPageX = touch.pageX; - touchRecord.previousPageY = touch.pageY; - touchRecord.previousTimeStamp = timestampForTouch(touch); - } + if (EventConstructor.eventPool.length < EVENT_POOL_SIZE) { + EventConstructor.eventPool.push(event); + } +} - function getTouchIdentifier(_ref) { - var identifier = _ref.identifier; +function addEventPoolingTo(EventConstructor) { + EventConstructor.getPooled = createOrGetPooledEvent; + EventConstructor.eventPool = []; + EventConstructor.release = releasePooledEvent; +} - if (identifier == null) { - throw new Error("Touch object is missing identifier."); - } +/** + * `touchHistory` isn't actually on the native event, but putting it in the + * interface will ensure that it is cleaned up when pooled/destroyed. The + * `ResponderEventPlugin` will populate it appropriately. + */ - { - if (identifier > MAX_TOUCH_BANK) { - error( - "Touch identifier %s is greater than maximum supported %s which causes " + - "performance issues backfilling array locations for all of the indices.", - identifier, - MAX_TOUCH_BANK - ); - } - } +var ResponderSyntheticEvent = SyntheticEvent.extend({ + touchHistory: function (nativeEvent) { + return null; // Actually doesn't even look at the native event. + } +}); + +var TOP_TOUCH_START = 'topTouchStart'; +var TOP_TOUCH_MOVE = 'topTouchMove'; +var TOP_TOUCH_END = 'topTouchEnd'; +var TOP_TOUCH_CANCEL = 'topTouchCancel'; +var TOP_SCROLL = 'topScroll'; +var TOP_SELECTION_CHANGE = 'topSelectionChange'; +function isStartish(topLevelType) { + return topLevelType === TOP_TOUCH_START; +} +function isMoveish(topLevelType) { + return topLevelType === TOP_TOUCH_MOVE; +} +function isEndish(topLevelType) { + return topLevelType === TOP_TOUCH_END || topLevelType === TOP_TOUCH_CANCEL; +} +var startDependencies = [TOP_TOUCH_START]; +var moveDependencies = [TOP_TOUCH_MOVE]; +var endDependencies = [TOP_TOUCH_CANCEL, TOP_TOUCH_END]; - return identifier; - } +/** + * Tracks the position and time of each active touch by `touch.identifier`. We + * should typically only see IDs in the range of 1-20 because IDs get recycled + * when touches end and start again. + */ - function recordTouchStart(touch) { - var identifier = getTouchIdentifier(touch); - var touchRecord = touchBank[identifier]; +var MAX_TOUCH_BANK = 20; +var touchBank = []; +var touchHistory = { + touchBank: touchBank, + numberActiveTouches: 0, + // If there is only one active touch, we remember its location. This prevents + // us having to loop through all of the touches all the time in the most + // common case. + indexOfSingleActiveTouch: -1, + mostRecentTimeStamp: 0 +}; + +function timestampForTouch(touch) { + // The legacy internal implementation provides "timeStamp", which has been + // renamed to "timestamp". Let both work for now while we iron it out + // TODO (evv): rename timeStamp to timestamp in internal code + return touch.timeStamp || touch.timestamp; +} +/** + * TODO: Instead of making gestures recompute filtered velocity, we could + * include a built in velocity computation that can be reused globally. + */ - if (touchRecord) { - resetTouchRecord(touchRecord, touch); - } else { - touchBank[identifier] = createTouchRecord(touch); - } - touchHistory.mostRecentTimeStamp = timestampForTouch(touch); - } +function createTouchRecord(touch) { + return { + touchActive: true, + startPageX: touch.pageX, + startPageY: touch.pageY, + startTimeStamp: timestampForTouch(touch), + currentPageX: touch.pageX, + currentPageY: touch.pageY, + currentTimeStamp: timestampForTouch(touch), + previousPageX: touch.pageX, + previousPageY: touch.pageY, + previousTimeStamp: timestampForTouch(touch) + }; +} - function recordTouchMove(touch) { - var touchRecord = touchBank[getTouchIdentifier(touch)]; +function resetTouchRecord(touchRecord, touch) { + touchRecord.touchActive = true; + touchRecord.startPageX = touch.pageX; + touchRecord.startPageY = touch.pageY; + touchRecord.startTimeStamp = timestampForTouch(touch); + touchRecord.currentPageX = touch.pageX; + touchRecord.currentPageY = touch.pageY; + touchRecord.currentTimeStamp = timestampForTouch(touch); + touchRecord.previousPageX = touch.pageX; + touchRecord.previousPageY = touch.pageY; + touchRecord.previousTimeStamp = timestampForTouch(touch); +} - if (touchRecord) { - touchRecord.touchActive = true; - touchRecord.previousPageX = touchRecord.currentPageX; - touchRecord.previousPageY = touchRecord.currentPageY; - touchRecord.previousTimeStamp = touchRecord.currentTimeStamp; - touchRecord.currentPageX = touch.pageX; - touchRecord.currentPageY = touch.pageY; - touchRecord.currentTimeStamp = timestampForTouch(touch); - touchHistory.mostRecentTimeStamp = timestampForTouch(touch); - } else { - { - warn( - "Cannot record touch move without a touch start.\n" + - "Touch Move: %s\n" + - "Touch Bank: %s", - printTouch(touch), - printTouchBank() - ); - } - } - } +function getTouchIdentifier(_ref) { + var identifier = _ref.identifier; - function recordTouchEnd(touch) { - var touchRecord = touchBank[getTouchIdentifier(touch)]; + if (identifier == null) { + throw new Error('Touch object is missing identifier.'); + } - if (touchRecord) { - touchRecord.touchActive = false; - touchRecord.previousPageX = touchRecord.currentPageX; - touchRecord.previousPageY = touchRecord.currentPageY; - touchRecord.previousTimeStamp = touchRecord.currentTimeStamp; - touchRecord.currentPageX = touch.pageX; - touchRecord.currentPageY = touch.pageY; - touchRecord.currentTimeStamp = timestampForTouch(touch); - touchHistory.mostRecentTimeStamp = timestampForTouch(touch); - } else { - { - warn( - "Cannot record touch end without a touch start.\n" + - "Touch End: %s\n" + - "Touch Bank: %s", - printTouch(touch), - printTouchBank() - ); - } - } + { + if (identifier > MAX_TOUCH_BANK) { + error('Touch identifier %s is greater than maximum supported %s which causes ' + 'performance issues backfilling array locations for all of the indices.', identifier, MAX_TOUCH_BANK); } + } - function printTouch(touch) { - return JSON.stringify({ - identifier: touch.identifier, - pageX: touch.pageX, - pageY: touch.pageY, - timestamp: timestampForTouch(touch) - }); - } + return identifier; +} - function printTouchBank() { - var printed = JSON.stringify(touchBank.slice(0, MAX_TOUCH_BANK)); +function recordTouchStart(touch) { + var identifier = getTouchIdentifier(touch); + var touchRecord = touchBank[identifier]; - if (touchBank.length > MAX_TOUCH_BANK) { - printed += " (original size: " + touchBank.length + ")"; - } + if (touchRecord) { + resetTouchRecord(touchRecord, touch); + } else { + touchBank[identifier] = createTouchRecord(touch); + } - return printed; - } + touchHistory.mostRecentTimeStamp = timestampForTouch(touch); +} - var instrumentationCallback; - var ResponderTouchHistoryStore = { - /** - * Registers a listener which can be used to instrument every touch event. - */ - instrument: function (callback) { - instrumentationCallback = callback; - }, - recordTouchTrack: function (topLevelType, nativeEvent) { - if (instrumentationCallback != null) { - instrumentationCallback(topLevelType, nativeEvent); - } +function recordTouchMove(touch) { + var touchRecord = touchBank[getTouchIdentifier(touch)]; + + if (touchRecord) { + touchRecord.touchActive = true; + touchRecord.previousPageX = touchRecord.currentPageX; + touchRecord.previousPageY = touchRecord.currentPageY; + touchRecord.previousTimeStamp = touchRecord.currentTimeStamp; + touchRecord.currentPageX = touch.pageX; + touchRecord.currentPageY = touch.pageY; + touchRecord.currentTimeStamp = timestampForTouch(touch); + touchHistory.mostRecentTimeStamp = timestampForTouch(touch); + } else { + { + warn('Cannot record touch move without a touch start.\n' + 'Touch Move: %s\n' + 'Touch Bank: %s', printTouch(touch), printTouchBank()); + } + } +} - if (isMoveish(topLevelType)) { - nativeEvent.changedTouches.forEach(recordTouchMove); - } else if (isStartish(topLevelType)) { - nativeEvent.changedTouches.forEach(recordTouchStart); - touchHistory.numberActiveTouches = nativeEvent.touches.length; +function recordTouchEnd(touch) { + var touchRecord = touchBank[getTouchIdentifier(touch)]; + + if (touchRecord) { + touchRecord.touchActive = false; + touchRecord.previousPageX = touchRecord.currentPageX; + touchRecord.previousPageY = touchRecord.currentPageY; + touchRecord.previousTimeStamp = touchRecord.currentTimeStamp; + touchRecord.currentPageX = touch.pageX; + touchRecord.currentPageY = touch.pageY; + touchRecord.currentTimeStamp = timestampForTouch(touch); + touchHistory.mostRecentTimeStamp = timestampForTouch(touch); + } else { + { + warn('Cannot record touch end without a touch start.\n' + 'Touch End: %s\n' + 'Touch Bank: %s', printTouch(touch), printTouchBank()); + } + } +} - if (touchHistory.numberActiveTouches === 1) { - touchHistory.indexOfSingleActiveTouch = - nativeEvent.touches[0].identifier; - } - } else if (isEndish(topLevelType)) { - nativeEvent.changedTouches.forEach(recordTouchEnd); - touchHistory.numberActiveTouches = nativeEvent.touches.length; +function printTouch(touch) { + return JSON.stringify({ + identifier: touch.identifier, + pageX: touch.pageX, + pageY: touch.pageY, + timestamp: timestampForTouch(touch) + }); +} - if (touchHistory.numberActiveTouches === 1) { - for (var i = 0; i < touchBank.length; i++) { - var touchTrackToCheck = touchBank[i]; +function printTouchBank() { + var printed = JSON.stringify(touchBank.slice(0, MAX_TOUCH_BANK)); - if (touchTrackToCheck != null && touchTrackToCheck.touchActive) { - touchHistory.indexOfSingleActiveTouch = i; - break; - } - } + if (touchBank.length > MAX_TOUCH_BANK) { + printed += ' (original size: ' + touchBank.length + ')'; + } - { - var activeRecord = - touchBank[touchHistory.indexOfSingleActiveTouch]; + return printed; +} - if (activeRecord == null || !activeRecord.touchActive) { - error("Cannot find single active touch."); - } - } +var instrumentationCallback; +var ResponderTouchHistoryStore = { + /** + * Registers a listener which can be used to instrument every touch event. + */ + instrument: function (callback) { + instrumentationCallback = callback; + }, + recordTouchTrack: function (topLevelType, nativeEvent) { + if (instrumentationCallback != null) { + instrumentationCallback(topLevelType, nativeEvent); + } + + if (isMoveish(topLevelType)) { + nativeEvent.changedTouches.forEach(recordTouchMove); + } else if (isStartish(topLevelType)) { + nativeEvent.changedTouches.forEach(recordTouchStart); + touchHistory.numberActiveTouches = nativeEvent.touches.length; + + if (touchHistory.numberActiveTouches === 1) { + touchHistory.indexOfSingleActiveTouch = nativeEvent.touches[0].identifier; + } + } else if (isEndish(topLevelType)) { + nativeEvent.changedTouches.forEach(recordTouchEnd); + touchHistory.numberActiveTouches = nativeEvent.touches.length; + + if (touchHistory.numberActiveTouches === 1) { + for (var i = 0; i < touchBank.length; i++) { + var touchTrackToCheck = touchBank[i]; + + if (touchTrackToCheck != null && touchTrackToCheck.touchActive) { + touchHistory.indexOfSingleActiveTouch = i; + break; } } - }, - touchHistory: touchHistory - }; - /** - * Accumulates items that must not be null or undefined. - * - * This is used to conserve memory by avoiding array allocations. - * - * @return {*|array<*>} An accumulation of items. - */ + { + var activeRecord = touchBank[touchHistory.indexOfSingleActiveTouch]; - function accumulate(current, next) { - if (next == null) { - throw new Error("Accumulated items must not be null or undefined."); + if (activeRecord == null || !activeRecord.touchActive) { + error('Cannot find single active touch.'); + } + } } + } + }, + touchHistory: touchHistory +}; - if (current == null) { - return next; - } // Both are not empty. Warning: Never call x.concat(y) when you are not - // certain that x is an Array (x could be a string with concat method). - - if (isArray(current)) { - /* $FlowFixMe[incompatible-return] if `current` is `T` and `T` an array, - * `isArray` might refine to the array element type of `T` */ - return current.concat(next); - } +/** + * Accumulates items that must not be null or undefined. + * + * This is used to conserve memory by avoiding array allocations. + * + * @return {*|array<*>} An accumulation of items. + */ - if (isArray(next)) { - /* $FlowFixMe[incompatible-return] unsound if `next` is `T` and `T` an array, - * `isArray` might refine to the array element type of `T` */ - return [current].concat(next); - } +function accumulate(current, next) { + if (next == null) { + throw new Error('Accumulated items must not be null or undefined.'); + } - return [current, next]; - } + if (current == null) { + return next; + } // Both are not empty. Warning: Never call x.concat(y) when you are not + // certain that x is an Array (x could be a string with concat method). - /** - * Accumulates items that must not be null or undefined into the first one. This - * is used to conserve memory by avoiding array allocations, and thus sacrifices - * API cleanness. Since `current` can be null before being passed in and not - * null after this function, make sure to assign it back to `current`: - * - * `a = accumulateInto(a, b);` - * - * This API should be sparingly used. Try `accumulate` for something cleaner. - * - * @return {*|array<*>} An accumulation of items. - */ - function accumulateInto(current, next) { - if (next == null) { - throw new Error("Accumulated items must not be null or undefined."); - } + if (isArray(current)) { + /* $FlowFixMe[incompatible-return] if `current` is `T` and `T` an array, + * `isArray` might refine to the array element type of `T` */ + return current.concat(next); + } - if (current == null) { - return next; - } // Both are not empty. Warning: Never call x.concat(y) when you are not - // certain that x is an Array (x could be a string with concat method). + if (isArray(next)) { + /* $FlowFixMe[incompatible-return] unsound if `next` is `T` and `T` an array, + * `isArray` might refine to the array element type of `T` */ + return [current].concat(next); + } - if (isArray(current)) { - if (isArray(next)) { - // $FlowFixMe[prop-missing] `isArray` does not ensure array is mutable - // $FlowFixMe[method-unbinding] - current.push.apply(current, next); - return current; - } // $FlowFixMe[prop-missing] `isArray` does not ensure array is mutable + return [current, next]; +} - current.push(next); - return current; - } +/** + * Accumulates items that must not be null or undefined into the first one. This + * is used to conserve memory by avoiding array allocations, and thus sacrifices + * API cleanness. Since `current` can be null before being passed in and not + * null after this function, make sure to assign it back to `current`: + * + * `a = accumulateInto(a, b);` + * + * This API should be sparingly used. Try `accumulate` for something cleaner. + * + * @return {*|array<*>} An accumulation of items. + */ - if (isArray(next)) { - // A bit too dangerous to mutate `next`. +function accumulateInto(current, next) { + if (next == null) { + throw new Error('Accumulated items must not be null or undefined.'); + } - /* $FlowFixMe[incompatible-return] unsound if `next` is `T` and `T` an array, - * `isArray` might refine to the array element type of `T` */ - return [current].concat(next); - } + if (current == null) { + return next; + } // Both are not empty. Warning: Never call x.concat(y) when you are not + // certain that x is an Array (x could be a string with concat method). - return [current, next]; - } - /** - * @param {array} arr an "accumulation" of items which is either an Array or - * a single item. Useful when paired with the `accumulate` module. This is a - * simple utility that allows us to reason about a collection of items, but - * handling the case when there is exactly one item (and we do not need to - * allocate an array). - * @param {function} cb Callback invoked with each element or a collection. - * @param {?} [scope] Scope used as `this` in a callback. - */ - function forEachAccumulated(arr, cb, scope) { - if (Array.isArray(arr)) { - // $FlowFixMe[incompatible-call] if `T` is an array, `cb` cannot be called - arr.forEach(cb, scope); - } else if (arr) { - cb.call(scope, arr); - } - } - - var FunctionComponent = 0; - var ClassComponent = 1; - var HostRoot = 3; // Root of a host tree. Could be nested inside another node. - - var HostPortal = 4; // A subtree. Could be an entry point to a different renderer. - - var HostComponent = 5; - var HostText = 6; - var Fragment = 7; - var Mode = 8; - var ContextConsumer = 9; - var ContextProvider = 10; - var ForwardRef = 11; - var Profiler = 12; - var SuspenseComponent = 13; - var MemoComponent = 14; - var SimpleMemoComponent = 15; - var LazyComponent = 16; - var IncompleteClassComponent = 17; - var DehydratedFragment = 18; - var SuspenseListComponent = 19; - var ScopeComponent = 21; - var OffscreenComponent = 22; - var LegacyHiddenComponent = 23; - var CacheComponent = 24; - var TracingMarkerComponent = 25; - var HostHoistable = 26; - var HostSingleton = 27; - var IncompleteFunctionComponent = 28; + if (isArray(current)) { + if (isArray(next)) { + // $FlowFixMe[prop-missing] `isArray` does not ensure array is mutable + // $FlowFixMe[method-unbinding] + current.push.apply(current, next); + return current; + } // $FlowFixMe[prop-missing] `isArray` does not ensure array is mutable - /** - * Instance of element that should respond to touch/move types of interactions, - * as indicated explicitly by relevant callbacks. - */ - var responderInst = null; - /** - * Count of current touches. A textInput should become responder iff the - * selection changes while there is a touch on the screen. - */ + current.push(next); + return current; + } - var trackedTouchCount = 0; - - function changeResponder(nextResponderInst, blockHostResponder) { - var oldResponderInst = responderInst; - responderInst = nextResponderInst; - - if (ResponderEventPlugin.GlobalResponderHandler !== null) { - ResponderEventPlugin.GlobalResponderHandler.onChange( - oldResponderInst, - nextResponderInst, - blockHostResponder - ); - } - } - - var eventTypes = { - /** - * On a `touchStart`/`mouseDown`, is it desired that this element become the - * responder? - */ - startShouldSetResponder: { - phasedRegistrationNames: { - bubbled: "onStartShouldSetResponder", - captured: "onStartShouldSetResponderCapture" - }, - dependencies: startDependencies - }, - - /** - * On a `scroll`, is it desired that this element become the responder? This - * is usually not needed, but should be used to retroactively infer that a - * `touchStart` had occurred during momentum scroll. During a momentum scroll, - * a touch start will be immediately followed by a scroll event if the view is - * currently scrolling. - * - * TODO: This shouldn't bubble. - */ - scrollShouldSetResponder: { - phasedRegistrationNames: { - bubbled: "onScrollShouldSetResponder", - captured: "onScrollShouldSetResponderCapture" - }, - dependencies: [TOP_SCROLL] - }, - - /** - * On text selection change, should this element become the responder? This - * is needed for text inputs or other views with native selection, so the - * JS view can claim the responder. - * - * TODO: This shouldn't bubble. - */ - selectionChangeShouldSetResponder: { - phasedRegistrationNames: { - bubbled: "onSelectionChangeShouldSetResponder", - captured: "onSelectionChangeShouldSetResponderCapture" - }, - dependencies: [TOP_SELECTION_CHANGE] - }, - - /** - * On a `touchMove`/`mouseMove`, is it desired that this element become the - * responder? - */ - moveShouldSetResponder: { - phasedRegistrationNames: { - bubbled: "onMoveShouldSetResponder", - captured: "onMoveShouldSetResponderCapture" - }, - dependencies: moveDependencies - }, - - /** - * Direct responder events dispatched directly to responder. Do not bubble. - */ - responderStart: { - registrationName: "onResponderStart", - dependencies: startDependencies - }, - responderMove: { - registrationName: "onResponderMove", - dependencies: moveDependencies - }, - responderEnd: { - registrationName: "onResponderEnd", - dependencies: endDependencies - }, - responderRelease: { - registrationName: "onResponderRelease", - dependencies: endDependencies - }, - responderTerminationRequest: { - registrationName: "onResponderTerminationRequest", - dependencies: [] - }, - responderGrant: { - registrationName: "onResponderGrant", - dependencies: [] - }, - responderReject: { - registrationName: "onResponderReject", - dependencies: [] - }, - responderTerminate: { - registrationName: "onResponderTerminate", - dependencies: [] - } - }; // Start of inline: the below functions were inlined from - // EventPropagator.js, as they deviated from ReactDOM's newer - // implementations. - - function getParent$1(inst) { - do { - inst = inst.return; // TODO: If this is a HostRoot we might want to bail out. - // That is depending on if we want nested subtrees (layers) to bubble - // events to their parent. We could also go through parentNode on the - // host node but that wouldn't work for React Native and doesn't let us - // do the portal feature. - } while (inst && inst.tag !== HostComponent); + if (isArray(next)) { + // A bit too dangerous to mutate `next`. - if (inst) { - return inst; - } + /* $FlowFixMe[incompatible-return] unsound if `next` is `T` and `T` an array, + * `isArray` might refine to the array element type of `T` */ + return [current].concat(next); + } - return null; - } - /** - * Return the lowest common ancestor of A and B, or null if they are in - * different trees. - */ + return [current, next]; +} - function getLowestCommonAncestor(instA, instB) { - var depthA = 0; +/** + * @param {array} arr an "accumulation" of items which is either an Array or + * a single item. Useful when paired with the `accumulate` module. This is a + * simple utility that allows us to reason about a collection of items, but + * handling the case when there is exactly one item (and we do not need to + * allocate an array). + * @param {function} cb Callback invoked with each element or a collection. + * @param {?} [scope] Scope used as `this` in a callback. + */ +function forEachAccumulated(arr, cb, scope) { + if (Array.isArray(arr)) { + // $FlowFixMe[incompatible-call] if `T` is an array, `cb` cannot be called + arr.forEach(cb, scope); + } else if (arr) { + cb.call(scope, arr); + } +} - for (var tempA = instA; tempA; tempA = getParent$1(tempA)) { - depthA++; - } +var FunctionComponent = 0; +var ClassComponent = 1; +var HostRoot = 3; // Root of a host tree. Could be nested inside another node. + +var HostPortal = 4; // A subtree. Could be an entry point to a different renderer. + +var HostComponent = 5; +var HostText = 6; +var Fragment = 7; +var Mode = 8; +var ContextConsumer = 9; +var ContextProvider = 10; +var ForwardRef = 11; +var Profiler = 12; +var SuspenseComponent = 13; +var MemoComponent = 14; +var SimpleMemoComponent = 15; +var LazyComponent = 16; +var IncompleteClassComponent = 17; +var DehydratedFragment = 18; +var SuspenseListComponent = 19; +var ScopeComponent = 21; +var OffscreenComponent = 22; +var LegacyHiddenComponent = 23; +var CacheComponent = 24; +var TracingMarkerComponent = 25; +var HostHoistable = 26; +var HostSingleton = 27; +var IncompleteFunctionComponent = 28; - var depthB = 0; +/** + * Instance of element that should respond to touch/move types of interactions, + * as indicated explicitly by relevant callbacks. + */ - for (var tempB = instB; tempB; tempB = getParent$1(tempB)) { - depthB++; - } // If A is deeper, crawl up. +var responderInst = null; +/** + * Count of current touches. A textInput should become responder iff the + * selection changes while there is a touch on the screen. + */ - while (depthA - depthB > 0) { - instA = getParent$1(instA); - depthA--; - } // If B is deeper, crawl up. +var trackedTouchCount = 0; - while (depthB - depthA > 0) { - instB = getParent$1(instB); - depthB--; - } // Walk in lockstep until we find a match. +function changeResponder(nextResponderInst, blockHostResponder) { + var oldResponderInst = responderInst; + responderInst = nextResponderInst; - var depth = depthA; + if (ResponderEventPlugin.GlobalResponderHandler !== null) { + ResponderEventPlugin.GlobalResponderHandler.onChange(oldResponderInst, nextResponderInst, blockHostResponder); + } +} - while (depth--) { - if (instA === instB || instA === instB.alternate) { - return instA; - } +var eventTypes = { + /** + * On a `touchStart`/`mouseDown`, is it desired that this element become the + * responder? + */ + startShouldSetResponder: { + phasedRegistrationNames: { + bubbled: 'onStartShouldSetResponder', + captured: 'onStartShouldSetResponderCapture' + }, + dependencies: startDependencies + }, + + /** + * On a `scroll`, is it desired that this element become the responder? This + * is usually not needed, but should be used to retroactively infer that a + * `touchStart` had occurred during momentum scroll. During a momentum scroll, + * a touch start will be immediately followed by a scroll event if the view is + * currently scrolling. + * + * TODO: This shouldn't bubble. + */ + scrollShouldSetResponder: { + phasedRegistrationNames: { + bubbled: 'onScrollShouldSetResponder', + captured: 'onScrollShouldSetResponderCapture' + }, + dependencies: [TOP_SCROLL] + }, + + /** + * On text selection change, should this element become the responder? This + * is needed for text inputs or other views with native selection, so the + * JS view can claim the responder. + * + * TODO: This shouldn't bubble. + */ + selectionChangeShouldSetResponder: { + phasedRegistrationNames: { + bubbled: 'onSelectionChangeShouldSetResponder', + captured: 'onSelectionChangeShouldSetResponderCapture' + }, + dependencies: [TOP_SELECTION_CHANGE] + }, + + /** + * On a `touchMove`/`mouseMove`, is it desired that this element become the + * responder? + */ + moveShouldSetResponder: { + phasedRegistrationNames: { + bubbled: 'onMoveShouldSetResponder', + captured: 'onMoveShouldSetResponderCapture' + }, + dependencies: moveDependencies + }, + + /** + * Direct responder events dispatched directly to responder. Do not bubble. + */ + responderStart: { + registrationName: 'onResponderStart', + dependencies: startDependencies + }, + responderMove: { + registrationName: 'onResponderMove', + dependencies: moveDependencies + }, + responderEnd: { + registrationName: 'onResponderEnd', + dependencies: endDependencies + }, + responderRelease: { + registrationName: 'onResponderRelease', + dependencies: endDependencies + }, + responderTerminationRequest: { + registrationName: 'onResponderTerminationRequest', + dependencies: [] + }, + responderGrant: { + registrationName: 'onResponderGrant', + dependencies: [] + }, + responderReject: { + registrationName: 'onResponderReject', + dependencies: [] + }, + responderTerminate: { + registrationName: 'onResponderTerminate', + dependencies: [] + } +}; // Start of inline: the below functions were inlined from +// EventPropagator.js, as they deviated from ReactDOM's newer +// implementations. + +function getParent$1(inst) { + do { + inst = inst.return; // TODO: If this is a HostRoot we might want to bail out. + // That is depending on if we want nested subtrees (layers) to bubble + // events to their parent. We could also go through parentNode on the + // host node but that wouldn't work for React Native and doesn't let us + // do the portal feature. + } while (inst && inst.tag !== HostComponent); + + if (inst) { + return inst; + } + + return null; +} +/** + * Return the lowest common ancestor of A and B, or null if they are in + * different trees. + */ - instA = getParent$1(instA); - instB = getParent$1(instB); - } - return null; +function getLowestCommonAncestor(instA, instB) { + var depthA = 0; + + for (var tempA = instA; tempA; tempA = getParent$1(tempA)) { + depthA++; + } + + var depthB = 0; + + for (var tempB = instB; tempB; tempB = getParent$1(tempB)) { + depthB++; + } // If A is deeper, crawl up. + + + while (depthA - depthB > 0) { + instA = getParent$1(instA); + depthA--; + } // If B is deeper, crawl up. + + + while (depthB - depthA > 0) { + instB = getParent$1(instB); + depthB--; + } // Walk in lockstep until we find a match. + + + var depth = depthA; + + while (depth--) { + if (instA === instB || instA === instB.alternate) { + return instA; } - /** - * Return if A is an ancestor of B. - */ - function isAncestor(instA, instB) { - while (instB) { - if (instA === instB || instA === instB.alternate) { - return true; - } + instA = getParent$1(instA); + instB = getParent$1(instB); + } - instB = getParent$1(instB); - } + return null; +} +/** + * Return if A is an ancestor of B. + */ - return false; +function isAncestor(instA, instB) { + while (instB) { + if (instA === instB || instA === instB.alternate) { + return true; } - /** - * Simulates the traversal of a two-phase, capture/bubble event dispatch. - */ - function traverseTwoPhase$1(inst, fn, arg) { - var path = []; + instB = getParent$1(instB); + } - while (inst) { - path.push(inst); - inst = getParent$1(inst); - } + return false; +} +/** + * Simulates the traversal of a two-phase, capture/bubble event dispatch. + */ - var i; - for (i = path.length; i-- > 0; ) { - fn(path[i], "captured", arg); - } +function traverseTwoPhase$1(inst, fn, arg) { + var path = []; - for (i = 0; i < path.length; i++) { - fn(path[i], "bubbled", arg); - } - } + while (inst) { + path.push(inst); + inst = getParent$1(inst); + } - function getListener$1(inst, registrationName) { - var stateNode = inst.stateNode; + var i; - if (stateNode === null) { - // Work in progress (ex: onload events in incremental mode). - return null; - } + for (i = path.length; i-- > 0;) { + fn(path[i], 'captured', arg); + } - var props = getFiberCurrentPropsFromNode$1(stateNode); + for (i = 0; i < path.length; i++) { + fn(path[i], 'bubbled', arg); + } +} - if (props === null) { - // Work in progress. - return null; - } +function getListener$1(inst, registrationName) { + var stateNode = inst.stateNode; - var listener = props[registrationName]; + if (stateNode === null) { + // Work in progress (ex: onload events in incremental mode). + return null; + } - if (listener && typeof listener !== "function") { - throw new Error( - "Expected `" + - registrationName + - "` listener to be a function, instead got a value of `" + - typeof listener + - "` type." - ); - } + var props = getFiberCurrentPropsFromNode$1(stateNode); - return listener; - } + if (props === null) { + // Work in progress. + return null; + } - function listenerAtPhase$1(inst, event, propagationPhase) { - var registrationName = - event.dispatchConfig.phasedRegistrationNames[propagationPhase]; - return getListener$1(inst, registrationName); - } + var listener = props[registrationName]; - function accumulateDirectionalDispatches$1(inst, phase, event) { - { - if (!inst) { - error("Dispatching inst must not be null"); - } - } + if (listener && typeof listener !== 'function') { + throw new Error("Expected `" + registrationName + "` listener to be a function, instead got a value of `" + typeof listener + "` type."); + } + + return listener; +} - var listener = listenerAtPhase$1(inst, event, phase); +function listenerAtPhase$1(inst, event, propagationPhase) { + var registrationName = event.dispatchConfig.phasedRegistrationNames[propagationPhase]; + return getListener$1(inst, registrationName); +} - if (listener) { - event._dispatchListeners = accumulateInto( - event._dispatchListeners, - listener - ); - event._dispatchInstances = accumulateInto( - event._dispatchInstances, - inst - ); - } +function accumulateDirectionalDispatches$1(inst, phase, event) { + { + if (!inst) { + error('Dispatching inst must not be null'); } - /** - * Accumulates without regard to direction, does not look for phased - * registration names. Same as `accumulateDirectDispatchesSingle` but without - * requiring that the `dispatchMarker` be the same as the dispatched ID. - */ + } - function accumulateDispatches$1(inst, ignoredDirection, event) { - if (inst && event && event.dispatchConfig.registrationName) { - var registrationName = event.dispatchConfig.registrationName; - var listener = getListener$1(inst, registrationName); + var listener = listenerAtPhase$1(inst, event, phase); - if (listener) { - event._dispatchListeners = accumulateInto( - event._dispatchListeners, - listener - ); - event._dispatchInstances = accumulateInto( - event._dispatchInstances, - inst - ); - } - } - } - /** - * Accumulates dispatches on an `SyntheticEvent`, but only for the - * `dispatchMarker`. - * @param {SyntheticEvent} event - */ + if (listener) { + event._dispatchListeners = accumulateInto(event._dispatchListeners, listener); + event._dispatchInstances = accumulateInto(event._dispatchInstances, inst); + } +} +/** + * Accumulates without regard to direction, does not look for phased + * registration names. Same as `accumulateDirectDispatchesSingle` but without + * requiring that the `dispatchMarker` be the same as the dispatched ID. + */ - function accumulateDirectDispatchesSingle$1(event) { - if (event && event.dispatchConfig.registrationName) { - accumulateDispatches$1(event._targetInst, null, event); - } - } - function accumulateDirectDispatches$1(events) { - forEachAccumulated(events, accumulateDirectDispatchesSingle$1); - } +function accumulateDispatches$1(inst, ignoredDirection, event) { + if (inst && event && event.dispatchConfig.registrationName) { + var registrationName = event.dispatchConfig.registrationName; + var listener = getListener$1(inst, registrationName); - function accumulateTwoPhaseDispatchesSingleSkipTarget(event) { - if (event && event.dispatchConfig.phasedRegistrationNames) { - var targetInst = event._targetInst; - var parentInst = targetInst ? getParent$1(targetInst) : null; - traverseTwoPhase$1( - parentInst, - accumulateDirectionalDispatches$1, - event - ); - } + if (listener) { + event._dispatchListeners = accumulateInto(event._dispatchListeners, listener); + event._dispatchInstances = accumulateInto(event._dispatchInstances, inst); } + } +} +/** + * Accumulates dispatches on an `SyntheticEvent`, but only for the + * `dispatchMarker`. + * @param {SyntheticEvent} event + */ - function accumulateTwoPhaseDispatchesSkipTarget(events) { - forEachAccumulated(events, accumulateTwoPhaseDispatchesSingleSkipTarget); - } - function accumulateTwoPhaseDispatchesSingle$1(event) { - if (event && event.dispatchConfig.phasedRegistrationNames) { - traverseTwoPhase$1( - event._targetInst, - accumulateDirectionalDispatches$1, - event - ); - } - } +function accumulateDirectDispatchesSingle$1(event) { + if (event && event.dispatchConfig.registrationName) { + accumulateDispatches$1(event._targetInst, null, event); + } +} - function accumulateTwoPhaseDispatches$1(events) { - forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle$1); - } // End of inline +function accumulateDirectDispatches$1(events) { + forEachAccumulated(events, accumulateDirectDispatchesSingle$1); +} - /** - * - * Responder System: - * ---------------- - * - * - A global, solitary "interaction lock" on a view. - * - If a node becomes the responder, it should convey visual feedback - * immediately to indicate so, either by highlighting or moving accordingly. - * - To be the responder means, that touches are exclusively important to that - * responder view, and no other view. - * - While touches are still occurring, the responder lock can be transferred to - * a new view, but only to increasingly "higher" views (meaning ancestors of - * the current responder). - * - * Responder being granted: - * ------------------------ - * - * - Touch starts, moves, and scrolls can cause an ID to become the responder. - * - We capture/bubble `startShouldSetResponder`/`moveShouldSetResponder` to - * the "appropriate place". - * - If nothing is currently the responder, the "appropriate place" is the - * initiating event's `targetID`. - * - If something *is* already the responder, the "appropriate place" is the - * first common ancestor of the event target and the current `responderInst`. - * - Some negotiation happens: See the timing diagram below. - * - Scrolled views automatically become responder. The reasoning is that a - * platform scroll view that isn't built on top of the responder system has - * began scrolling, and the active responder must now be notified that the - * interaction is no longer locked to it - the system has taken over. - * - * - Responder being released: - * As soon as no more touches that *started* inside of descendants of the - * *current* responderInst, an `onResponderRelease` event is dispatched to the - * current responder, and the responder lock is released. - * - * TODO: - * - on "end", a callback hook for `onResponderEndShouldRemainResponder` that - * determines if the responder lock should remain. - * - If a view shouldn't "remain" the responder, any active touches should by - * default be considered "dead" and do not influence future negotiations or - * bubble paths. It should be as if those touches do not exist. - * -- For multitouch: Usually a translate-z will choose to "remain" responder - * after one out of many touches ended. For translate-y, usually the view - * doesn't wish to "remain" responder after one of many touches end. - * - Consider building this on top of a `stopPropagation` model similar to - * `W3C` events. - * - Ensure that `onResponderTerminate` is called on touch cancels, whether or - * not `onResponderTerminationRequest` returns `true` or `false`. - * - */ +function accumulateTwoPhaseDispatchesSingleSkipTarget(event) { + if (event && event.dispatchConfig.phasedRegistrationNames) { + var targetInst = event._targetInst; + var parentInst = targetInst ? getParent$1(targetInst) : null; + traverseTwoPhase$1(parentInst, accumulateDirectionalDispatches$1, event); + } +} + +function accumulateTwoPhaseDispatchesSkipTarget(events) { + forEachAccumulated(events, accumulateTwoPhaseDispatchesSingleSkipTarget); +} + +function accumulateTwoPhaseDispatchesSingle$1(event) { + if (event && event.dispatchConfig.phasedRegistrationNames) { + traverseTwoPhase$1(event._targetInst, accumulateDirectionalDispatches$1, event); + } +} + +function accumulateTwoPhaseDispatches$1(events) { + forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle$1); +} // End of inline + +/** + * + * Responder System: + * ---------------- + * + * - A global, solitary "interaction lock" on a view. + * - If a node becomes the responder, it should convey visual feedback + * immediately to indicate so, either by highlighting or moving accordingly. + * - To be the responder means, that touches are exclusively important to that + * responder view, and no other view. + * - While touches are still occurring, the responder lock can be transferred to + * a new view, but only to increasingly "higher" views (meaning ancestors of + * the current responder). + * + * Responder being granted: + * ------------------------ + * + * - Touch starts, moves, and scrolls can cause an ID to become the responder. + * - We capture/bubble `startShouldSetResponder`/`moveShouldSetResponder` to + * the "appropriate place". + * - If nothing is currently the responder, the "appropriate place" is the + * initiating event's `targetID`. + * - If something *is* already the responder, the "appropriate place" is the + * first common ancestor of the event target and the current `responderInst`. + * - Some negotiation happens: See the timing diagram below. + * - Scrolled views automatically become responder. The reasoning is that a + * platform scroll view that isn't built on top of the responder system has + * began scrolling, and the active responder must now be notified that the + * interaction is no longer locked to it - the system has taken over. + * + * - Responder being released: + * As soon as no more touches that *started* inside of descendants of the + * *current* responderInst, an `onResponderRelease` event is dispatched to the + * current responder, and the responder lock is released. + * + * TODO: + * - on "end", a callback hook for `onResponderEndShouldRemainResponder` that + * determines if the responder lock should remain. + * - If a view shouldn't "remain" the responder, any active touches should by + * default be considered "dead" and do not influence future negotiations or + * bubble paths. It should be as if those touches do not exist. + * -- For multitouch: Usually a translate-z will choose to "remain" responder + * after one out of many touches ended. For translate-y, usually the view + * doesn't wish to "remain" responder after one of many touches end. + * - Consider building this on top of a `stopPropagation` model similar to + * `W3C` events. + * - Ensure that `onResponderTerminate` is called on touch cancels, whether or + * not `onResponderTerminationRequest` returns `true` or `false`. + * + */ - /* Negotiation Performed +/* Negotiation Performed +-----------------------+ / \ Process low level events to + Current Responder + wantsResponderID @@ -1490,25919 +1352,22142 @@ to return true:wantsResponderID| | | | + + */ - /** - * A note about event ordering in the `EventPluginRegistry`. - * - * Suppose plugins are injected in the following order: - * - * `[R, S, C]` - * - * To help illustrate the example, assume `S` is `SimpleEventPlugin` (for - * `onClick` etc) and `R` is `ResponderEventPlugin`. - * - * "Deferred-Dispatched Events": - * - * - The current event plugin system will traverse the list of injected plugins, - * in order, and extract events by collecting the plugin's return value of - * `extractEvents()`. - * - These events that are returned from `extractEvents` are "deferred - * dispatched events". - * - When returned from `extractEvents`, deferred-dispatched events contain an - * "accumulation" of deferred dispatches. - * - These deferred dispatches are accumulated/collected before they are - * returned, but processed at a later time by the `EventPluginRegistry` (hence the - * name deferred). - * - * In the process of returning their deferred-dispatched events, event plugins - * themselves can dispatch events on-demand without returning them from - * `extractEvents`. Plugins might want to do this, so that they can use event - * dispatching as a tool that helps them decide which events should be extracted - * in the first place. - * - * "On-Demand-Dispatched Events": - * - * - On-demand-dispatched events are not returned from `extractEvents`. - * - On-demand-dispatched events are dispatched during the process of returning - * the deferred-dispatched events. - * - They should not have side effects. - * - They should be avoided, and/or eventually be replaced with another - * abstraction that allows event plugins to perform multiple "rounds" of event - * extraction. - * - * Therefore, the sequence of event dispatches becomes: - * - * - `R`s on-demand events (if any) (dispatched by `R` on-demand) - * - `S`s on-demand events (if any) (dispatched by `S` on-demand) - * - `C`s on-demand events (if any) (dispatched by `C` on-demand) - * - `R`s extracted events (if any) (dispatched by `EventPluginRegistry`) - * - `S`s extracted events (if any) (dispatched by `EventPluginRegistry`) - * - `C`s extracted events (if any) (dispatched by `EventPluginRegistry`) - * - * In the case of `ResponderEventPlugin`: If the `startShouldSetResponder` - * on-demand dispatch returns `true` (and some other details are satisfied) the - * `onResponderGrant` deferred dispatched event is returned from - * `extractEvents`. The sequence of dispatch executions in this case - * will appear as follows: - * - * - `startShouldSetResponder` (`ResponderEventPlugin` dispatches on-demand) - * - `touchStartCapture` (`EventPluginRegistry` dispatches as usual) - * - `touchStart` (`EventPluginRegistry` dispatches as usual) - * - `responderGrant/Reject` (`EventPluginRegistry` dispatches as usual) - */ - - function setResponderAndExtractTransfer( - topLevelType, - targetInst, - nativeEvent, - nativeEventTarget - ) { - var shouldSetEventType = isStartish(topLevelType) - ? eventTypes.startShouldSetResponder - : isMoveish(topLevelType) - ? eventTypes.moveShouldSetResponder - : topLevelType === TOP_SELECTION_CHANGE - ? eventTypes.selectionChangeShouldSetResponder - : eventTypes.scrollShouldSetResponder; // TODO: stop one short of the current responder. - - var bubbleShouldSetFrom = !responderInst - ? targetInst - : getLowestCommonAncestor(responderInst, targetInst); // When capturing/bubbling the "shouldSet" event, we want to skip the target - // (deepest ID) if it happens to be the current responder. The reasoning: - // It's strange to get an `onMoveShouldSetResponder` when you're *already* - // the responder. - - var skipOverBubbleShouldSetFrom = bubbleShouldSetFrom === responderInst; - var shouldSetEvent = ResponderSyntheticEvent.getPooled( - shouldSetEventType, - bubbleShouldSetFrom, - nativeEvent, - nativeEventTarget - ); - shouldSetEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; - - if (skipOverBubbleShouldSetFrom) { - accumulateTwoPhaseDispatchesSkipTarget(shouldSetEvent); - } else { - accumulateTwoPhaseDispatches$1(shouldSetEvent); - } - - var wantsResponderInst = - executeDispatchesInOrderStopAtTrue(shouldSetEvent); +/** + * A note about event ordering in the `EventPluginRegistry`. + * + * Suppose plugins are injected in the following order: + * + * `[R, S, C]` + * + * To help illustrate the example, assume `S` is `SimpleEventPlugin` (for + * `onClick` etc) and `R` is `ResponderEventPlugin`. + * + * "Deferred-Dispatched Events": + * + * - The current event plugin system will traverse the list of injected plugins, + * in order, and extract events by collecting the plugin's return value of + * `extractEvents()`. + * - These events that are returned from `extractEvents` are "deferred + * dispatched events". + * - When returned from `extractEvents`, deferred-dispatched events contain an + * "accumulation" of deferred dispatches. + * - These deferred dispatches are accumulated/collected before they are + * returned, but processed at a later time by the `EventPluginRegistry` (hence the + * name deferred). + * + * In the process of returning their deferred-dispatched events, event plugins + * themselves can dispatch events on-demand without returning them from + * `extractEvents`. Plugins might want to do this, so that they can use event + * dispatching as a tool that helps them decide which events should be extracted + * in the first place. + * + * "On-Demand-Dispatched Events": + * + * - On-demand-dispatched events are not returned from `extractEvents`. + * - On-demand-dispatched events are dispatched during the process of returning + * the deferred-dispatched events. + * - They should not have side effects. + * - They should be avoided, and/or eventually be replaced with another + * abstraction that allows event plugins to perform multiple "rounds" of event + * extraction. + * + * Therefore, the sequence of event dispatches becomes: + * + * - `R`s on-demand events (if any) (dispatched by `R` on-demand) + * - `S`s on-demand events (if any) (dispatched by `S` on-demand) + * - `C`s on-demand events (if any) (dispatched by `C` on-demand) + * - `R`s extracted events (if any) (dispatched by `EventPluginRegistry`) + * - `S`s extracted events (if any) (dispatched by `EventPluginRegistry`) + * - `C`s extracted events (if any) (dispatched by `EventPluginRegistry`) + * + * In the case of `ResponderEventPlugin`: If the `startShouldSetResponder` + * on-demand dispatch returns `true` (and some other details are satisfied) the + * `onResponderGrant` deferred dispatched event is returned from + * `extractEvents`. The sequence of dispatch executions in this case + * will appear as follows: + * + * - `startShouldSetResponder` (`ResponderEventPlugin` dispatches on-demand) + * - `touchStartCapture` (`EventPluginRegistry` dispatches as usual) + * - `touchStart` (`EventPluginRegistry` dispatches as usual) + * - `responderGrant/Reject` (`EventPluginRegistry` dispatches as usual) + */ - if (!shouldSetEvent.isPersistent()) { - shouldSetEvent.constructor.release(shouldSetEvent); - } - if (!wantsResponderInst || wantsResponderInst === responderInst) { - return null; - } +function setResponderAndExtractTransfer(topLevelType, targetInst, nativeEvent, nativeEventTarget) { + var shouldSetEventType = isStartish(topLevelType) ? eventTypes.startShouldSetResponder : isMoveish(topLevelType) ? eventTypes.moveShouldSetResponder : topLevelType === TOP_SELECTION_CHANGE ? eventTypes.selectionChangeShouldSetResponder : eventTypes.scrollShouldSetResponder; // TODO: stop one short of the current responder. + + var bubbleShouldSetFrom = !responderInst ? targetInst : getLowestCommonAncestor(responderInst, targetInst); // When capturing/bubbling the "shouldSet" event, we want to skip the target + // (deepest ID) if it happens to be the current responder. The reasoning: + // It's strange to get an `onMoveShouldSetResponder` when you're *already* + // the responder. + + var skipOverBubbleShouldSetFrom = bubbleShouldSetFrom === responderInst; + var shouldSetEvent = ResponderSyntheticEvent.getPooled(shouldSetEventType, bubbleShouldSetFrom, nativeEvent, nativeEventTarget); + shouldSetEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + + if (skipOverBubbleShouldSetFrom) { + accumulateTwoPhaseDispatchesSkipTarget(shouldSetEvent); + } else { + accumulateTwoPhaseDispatches$1(shouldSetEvent); + } + + var wantsResponderInst = executeDispatchesInOrderStopAtTrue(shouldSetEvent); + + if (!shouldSetEvent.isPersistent()) { + shouldSetEvent.constructor.release(shouldSetEvent); + } + + if (!wantsResponderInst || wantsResponderInst === responderInst) { + return null; + } + + var extracted; + var grantEvent = ResponderSyntheticEvent.getPooled(eventTypes.responderGrant, wantsResponderInst, nativeEvent, nativeEventTarget); + grantEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches$1(grantEvent); + var blockHostResponder = executeDirectDispatch(grantEvent) === true; + + if (responderInst) { + var terminationRequestEvent = ResponderSyntheticEvent.getPooled(eventTypes.responderTerminationRequest, responderInst, nativeEvent, nativeEventTarget); + terminationRequestEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches$1(terminationRequestEvent); + var shouldSwitch = !hasDispatches(terminationRequestEvent) || executeDirectDispatch(terminationRequestEvent); + + if (!terminationRequestEvent.isPersistent()) { + terminationRequestEvent.constructor.release(terminationRequestEvent); + } + + if (shouldSwitch) { + var terminateEvent = ResponderSyntheticEvent.getPooled(eventTypes.responderTerminate, responderInst, nativeEvent, nativeEventTarget); + terminateEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches$1(terminateEvent); + extracted = accumulate(extracted, [grantEvent, terminateEvent]); + changeResponder(wantsResponderInst, blockHostResponder); + } else { + var rejectEvent = ResponderSyntheticEvent.getPooled(eventTypes.responderReject, wantsResponderInst, nativeEvent, nativeEventTarget); + rejectEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches$1(rejectEvent); + extracted = accumulate(extracted, rejectEvent); + } + } else { + extracted = accumulate(extracted, grantEvent); + changeResponder(wantsResponderInst, blockHostResponder); + } + + return extracted; +} +/** + * A transfer is a negotiation between a currently set responder and the next + * element to claim responder status. Any start event could trigger a transfer + * of responderInst. Any move event could trigger a transfer. + * + * @param {string} topLevelType Record from `BrowserEventConstants`. + * @return {boolean} True if a transfer of responder could possibly occur. + */ - var extracted; - var grantEvent = ResponderSyntheticEvent.getPooled( - eventTypes.responderGrant, - wantsResponderInst, - nativeEvent, - nativeEventTarget - ); - grantEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; - accumulateDirectDispatches$1(grantEvent); - var blockHostResponder = executeDirectDispatch(grantEvent) === true; - - if (responderInst) { - var terminationRequestEvent = ResponderSyntheticEvent.getPooled( - eventTypes.responderTerminationRequest, - responderInst, - nativeEvent, - nativeEventTarget - ); - terminationRequestEvent.touchHistory = - ResponderTouchHistoryStore.touchHistory; - accumulateDirectDispatches$1(terminationRequestEvent); - var shouldSwitch = - !hasDispatches(terminationRequestEvent) || - executeDirectDispatch(terminationRequestEvent); - - if (!terminationRequestEvent.isPersistent()) { - terminationRequestEvent.constructor.release(terminationRequestEvent); - } - - if (shouldSwitch) { - var terminateEvent = ResponderSyntheticEvent.getPooled( - eventTypes.responderTerminate, - responderInst, - nativeEvent, - nativeEventTarget - ); - terminateEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; - accumulateDirectDispatches$1(terminateEvent); - extracted = accumulate(extracted, [grantEvent, terminateEvent]); - changeResponder(wantsResponderInst, blockHostResponder); - } else { - var rejectEvent = ResponderSyntheticEvent.getPooled( - eventTypes.responderReject, - wantsResponderInst, - nativeEvent, - nativeEventTarget - ); - rejectEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; - accumulateDirectDispatches$1(rejectEvent); - extracted = accumulate(extracted, rejectEvent); - } - } else { - extracted = accumulate(extracted, grantEvent); - changeResponder(wantsResponderInst, blockHostResponder); - } - return extracted; - } - /** - * A transfer is a negotiation between a currently set responder and the next - * element to claim responder status. Any start event could trigger a transfer - * of responderInst. Any move event could trigger a transfer. - * - * @param {string} topLevelType Record from `BrowserEventConstants`. - * @return {boolean} True if a transfer of responder could possibly occur. - */ +function canTriggerTransfer(topLevelType, topLevelInst, nativeEvent) { + return topLevelInst && ( // responderIgnoreScroll: We are trying to migrate away from specifically + // tracking native scroll events here and responderIgnoreScroll indicates we + // will send topTouchCancel to handle canceling touch events instead + topLevelType === TOP_SCROLL && !nativeEvent.responderIgnoreScroll || trackedTouchCount > 0 && topLevelType === TOP_SELECTION_CHANGE || isStartish(topLevelType) || isMoveish(topLevelType)); +} +/** + * Returns whether or not this touch end event makes it such that there are no + * longer any touches that started inside of the current `responderInst`. + * + * @param {NativeEvent} nativeEvent Native touch end event. + * @return {boolean} Whether or not this touch end event ends the responder. + */ - function canTriggerTransfer(topLevelType, topLevelInst, nativeEvent) { - return ( - topLevelInst && // responderIgnoreScroll: We are trying to migrate away from specifically - // tracking native scroll events here and responderIgnoreScroll indicates we - // will send topTouchCancel to handle canceling touch events instead - ((topLevelType === TOP_SCROLL && !nativeEvent.responderIgnoreScroll) || - (trackedTouchCount > 0 && topLevelType === TOP_SELECTION_CHANGE) || - isStartish(topLevelType) || - isMoveish(topLevelType)) - ); - } - /** - * Returns whether or not this touch end event makes it such that there are no - * longer any touches that started inside of the current `responderInst`. - * - * @param {NativeEvent} nativeEvent Native touch end event. - * @return {boolean} Whether or not this touch end event ends the responder. - */ - function noResponderTouches(nativeEvent) { - var touches = nativeEvent.touches; +function noResponderTouches(nativeEvent) { + var touches = nativeEvent.touches; - if (!touches || touches.length === 0) { - return true; - } + if (!touches || touches.length === 0) { + return true; + } - for (var i = 0; i < touches.length; i++) { - var activeTouch = touches[i]; - var target = activeTouch.target; + for (var i = 0; i < touches.length; i++) { + var activeTouch = touches[i]; + var target = activeTouch.target; - if (target !== null && target !== undefined && target !== 0) { - // Is the original touch location inside of the current responder? - var targetInst = getInstanceFromNode$1(target); + if (target !== null && target !== undefined && target !== 0) { + // Is the original touch location inside of the current responder? + var targetInst = getInstanceFromNode$1(target); - if (isAncestor(responderInst, targetInst)) { - return false; - } - } + if (isAncestor(responderInst, targetInst)) { + return false; } - - return true; } + } - var ResponderEventPlugin = { - /* For unit testing only */ - _getResponder: function () { - return responderInst; - }, - eventTypes: eventTypes, - - /** - * We must be resilient to `targetInst` being `null` on `touchMove` or - * `touchEnd`. On certain platforms, this means that a native scroll has - * assumed control and the original touch targets are destroyed. - */ - extractEvents: function ( - topLevelType, - targetInst, - nativeEvent, - nativeEventTarget, - eventSystemFlags - ) { - if (isStartish(topLevelType)) { - trackedTouchCount += 1; - } else if (isEndish(topLevelType)) { - if (trackedTouchCount >= 0) { - trackedTouchCount -= 1; - } else { - { - warn( - "Ended a touch event which was not counted in `trackedTouchCount`." - ); - } + return true; +} - return null; - } +var ResponderEventPlugin = { + /* For unit testing only */ + _getResponder: function () { + return responderInst; + }, + eventTypes: eventTypes, + + /** + * We must be resilient to `targetInst` being `null` on `touchMove` or + * `touchEnd`. On certain platforms, this means that a native scroll has + * assumed control and the original touch targets are destroyed. + */ + extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget, eventSystemFlags) { + if (isStartish(topLevelType)) { + trackedTouchCount += 1; + } else if (isEndish(topLevelType)) { + if (trackedTouchCount >= 0) { + trackedTouchCount -= 1; + } else { + { + warn('Ended a touch event which was not counted in `trackedTouchCount`.'); } - ResponderTouchHistoryStore.recordTouchTrack(topLevelType, nativeEvent); - var extracted = canTriggerTransfer( - topLevelType, - targetInst, - nativeEvent - ) - ? setResponderAndExtractTransfer( - topLevelType, - targetInst, - nativeEvent, - nativeEventTarget - ) - : null; // Responder may or may not have transferred on a new touch start/move. - // Regardless, whoever is the responder after any potential transfer, we - // direct all touch start/move/ends to them in the form of - // `onResponderMove/Start/End`. These will be called for *every* additional - // finger that move/start/end, dispatched directly to whoever is the - // current responder at that moment, until the responder is "released". - // - // These multiple individual change touch events are are always bookended - // by `onResponderGrant`, and one of - // (`onResponderRelease/onResponderTerminate`). - - var isResponderTouchStart = responderInst && isStartish(topLevelType); - var isResponderTouchMove = responderInst && isMoveish(topLevelType); - var isResponderTouchEnd = responderInst && isEndish(topLevelType); - var incrementalTouch = isResponderTouchStart - ? eventTypes.responderStart - : isResponderTouchMove - ? eventTypes.responderMove - : isResponderTouchEnd - ? eventTypes.responderEnd - : null; - - if (incrementalTouch) { - var gesture = ResponderSyntheticEvent.getPooled( - incrementalTouch, - responderInst, - nativeEvent, - nativeEventTarget - ); - gesture.touchHistory = ResponderTouchHistoryStore.touchHistory; - accumulateDirectDispatches$1(gesture); - extracted = accumulate(extracted, gesture); - } - - var isResponderTerminate = - responderInst && topLevelType === TOP_TOUCH_CANCEL; - var isResponderRelease = - responderInst && - !isResponderTerminate && - isEndish(topLevelType) && - noResponderTouches(nativeEvent); - var finalTouch = isResponderTerminate - ? eventTypes.responderTerminate - : isResponderRelease - ? eventTypes.responderRelease - : null; - - if (finalTouch) { - var finalEvent = ResponderSyntheticEvent.getPooled( - finalTouch, - responderInst, - nativeEvent, - nativeEventTarget - ); - finalEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; - accumulateDirectDispatches$1(finalEvent); - extracted = accumulate(extracted, finalEvent); - changeResponder(null); - } - - return extracted; - }, - GlobalResponderHandler: null, - injection: { - /** - * @param {{onChange: (ReactID, ReactID) => void} GlobalResponderHandler - * Object that handles any change in responder. Use this to inject - * integration with an existing touch handling system etc. - */ - injectGlobalResponderHandler: function (GlobalResponderHandler) { - ResponderEventPlugin.GlobalResponderHandler = GlobalResponderHandler; - } + return null; } - }; - - /** - * Injectable ordering of event plugins. - */ - var eventPluginOrder = null; - /** - * Injectable mapping from names to event plugin modules. - */ + } - var namesToPlugins = {}; + ResponderTouchHistoryStore.recordTouchTrack(topLevelType, nativeEvent); + var extracted = canTriggerTransfer(topLevelType, targetInst, nativeEvent) ? setResponderAndExtractTransfer(topLevelType, targetInst, nativeEvent, nativeEventTarget) : null; // Responder may or may not have transferred on a new touch start/move. + // Regardless, whoever is the responder after any potential transfer, we + // direct all touch start/move/ends to them in the form of + // `onResponderMove/Start/End`. These will be called for *every* additional + // finger that move/start/end, dispatched directly to whoever is the + // current responder at that moment, until the responder is "released". + // + // These multiple individual change touch events are are always bookended + // by `onResponderGrant`, and one of + // (`onResponderRelease/onResponderTerminate`). + + var isResponderTouchStart = responderInst && isStartish(topLevelType); + var isResponderTouchMove = responderInst && isMoveish(topLevelType); + var isResponderTouchEnd = responderInst && isEndish(topLevelType); + var incrementalTouch = isResponderTouchStart ? eventTypes.responderStart : isResponderTouchMove ? eventTypes.responderMove : isResponderTouchEnd ? eventTypes.responderEnd : null; + + if (incrementalTouch) { + var gesture = ResponderSyntheticEvent.getPooled(incrementalTouch, responderInst, nativeEvent, nativeEventTarget); + gesture.touchHistory = ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches$1(gesture); + extracted = accumulate(extracted, gesture); + } + + var isResponderTerminate = responderInst && topLevelType === TOP_TOUCH_CANCEL; + var isResponderRelease = responderInst && !isResponderTerminate && isEndish(topLevelType) && noResponderTouches(nativeEvent); + var finalTouch = isResponderTerminate ? eventTypes.responderTerminate : isResponderRelease ? eventTypes.responderRelease : null; + + if (finalTouch) { + var finalEvent = ResponderSyntheticEvent.getPooled(finalTouch, responderInst, nativeEvent, nativeEventTarget); + finalEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches$1(finalEvent); + extracted = accumulate(extracted, finalEvent); + changeResponder(null); + } + + return extracted; + }, + GlobalResponderHandler: null, + injection: { /** - * Recomputes the plugin list using the injected plugins and plugin ordering. - * - * @private + * @param {{onChange: (ReactID, ReactID) => void} GlobalResponderHandler + * Object that handles any change in responder. Use this to inject + * integration with an existing touch handling system etc. */ + injectGlobalResponderHandler: function (GlobalResponderHandler) { + ResponderEventPlugin.GlobalResponderHandler = GlobalResponderHandler; + } + } +}; - function recomputePluginOrdering() { - if (!eventPluginOrder) { - // Wait until an `eventPluginOrder` is injected. - return; - } +/** + * Injectable ordering of event plugins. + */ +var eventPluginOrder = null; +/** + * Injectable mapping from names to event plugin modules. + */ - for (var pluginName in namesToPlugins) { - var pluginModule = namesToPlugins[pluginName]; // $FlowFixMe[incompatible-use] found when upgrading Flow +var namesToPlugins = {}; +/** + * Recomputes the plugin list using the injected plugins and plugin ordering. + * + * @private + */ - var pluginIndex = eventPluginOrder.indexOf(pluginName); +function recomputePluginOrdering() { + if (!eventPluginOrder) { + // Wait until an `eventPluginOrder` is injected. + return; + } - if (pluginIndex <= -1) { - throw new Error( - "EventPluginRegistry: Cannot inject event plugins that do not exist in " + - ("the plugin ordering, `" + pluginName + "`.") - ); - } + for (var pluginName in namesToPlugins) { + var pluginModule = namesToPlugins[pluginName]; // $FlowFixMe[incompatible-use] found when upgrading Flow - if (plugins[pluginIndex]) { - continue; - } + var pluginIndex = eventPluginOrder.indexOf(pluginName); - if (!pluginModule.extractEvents) { - throw new Error( - "EventPluginRegistry: Event plugins must implement an `extractEvents` " + - ("method, but `" + pluginName + "` does not.") - ); - } - - plugins[pluginIndex] = pluginModule; - var publishedEvents = pluginModule.eventTypes; - - for (var eventName in publishedEvents) { - if ( - !publishEventForPlugin( - publishedEvents[eventName], - pluginModule, - eventName - ) - ) { - throw new Error( - "EventPluginRegistry: Failed to publish event `" + - eventName + - "` for plugin `" + - pluginName + - "`." - ); - } - } - } + if (pluginIndex <= -1) { + throw new Error('EventPluginRegistry: Cannot inject event plugins that do not exist in ' + ("the plugin ordering, `" + pluginName + "`.")); } - /** - * Publishes an event so that it can be dispatched by the supplied plugin. - * - * @param {object} dispatchConfig Dispatch configuration for the event. - * @param {object} PluginModule Plugin publishing the event. - * @return {boolean} True if the event was successfully published. - * @private - */ - function publishEventForPlugin(dispatchConfig, pluginModule, eventName) { - if (eventNameDispatchConfigs.hasOwnProperty(eventName)) { - throw new Error( - "EventPluginRegistry: More than one plugin attempted to publish the same " + - ("event name, `" + eventName + "`.") - ); - } + if (plugins[pluginIndex]) { + continue; + } - eventNameDispatchConfigs[eventName] = dispatchConfig; - var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames; + if (!pluginModule.extractEvents) { + throw new Error('EventPluginRegistry: Event plugins must implement an `extractEvents` ' + ("method, but `" + pluginName + "` does not.")); + } - if (phasedRegistrationNames) { - for (var phaseName in phasedRegistrationNames) { - if (phasedRegistrationNames.hasOwnProperty(phaseName)) { - var phasedRegistrationName = phasedRegistrationNames[phaseName]; - publishRegistrationName(phasedRegistrationName, pluginModule); - } - } + plugins[pluginIndex] = pluginModule; + var publishedEvents = pluginModule.eventTypes; - return true; - } else if (dispatchConfig.registrationName) { - publishRegistrationName(dispatchConfig.registrationName, pluginModule); - return true; + for (var eventName in publishedEvents) { + if (!publishEventForPlugin(publishedEvents[eventName], pluginModule, eventName)) { + throw new Error("EventPluginRegistry: Failed to publish event `" + eventName + "` for plugin `" + pluginName + "`."); } - - return false; } - /** - * Publishes a registration name that is used to identify dispatched events. - * - * @param {string} registrationName Registration name to add. - * @param {object} PluginModule Plugin publishing the event. - * @private - */ + } +} +/** + * Publishes an event so that it can be dispatched by the supplied plugin. + * + * @param {object} dispatchConfig Dispatch configuration for the event. + * @param {object} PluginModule Plugin publishing the event. + * @return {boolean} True if the event was successfully published. + * @private + */ - function publishRegistrationName( - registrationName, - pluginModule, - eventName - ) { - if (registrationNameModules[registrationName]) { - throw new Error( - "EventPluginRegistry: More than one plugin attempted to publish the same " + - ("registration name, `" + registrationName + "`.") - ); - } - registrationNameModules[registrationName] = pluginModule; +function publishEventForPlugin(dispatchConfig, pluginModule, eventName) { + if (eventNameDispatchConfigs.hasOwnProperty(eventName)) { + throw new Error('EventPluginRegistry: More than one plugin attempted to publish the same ' + ("event name, `" + eventName + "`.")); + } - { - registrationName.toLowerCase(); + eventNameDispatchConfigs[eventName] = dispatchConfig; + var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames; + + if (phasedRegistrationNames) { + for (var phaseName in phasedRegistrationNames) { + if (phasedRegistrationNames.hasOwnProperty(phaseName)) { + var phasedRegistrationName = phasedRegistrationNames[phaseName]; + publishRegistrationName(phasedRegistrationName, pluginModule); } } - /** - * Registers plugins so that they can extract and dispatch events. - */ - - /** - * Ordered list of injected plugins. - */ - var plugins = []; - /** - * Mapping from event name to dispatch config - */ + return true; + } else if (dispatchConfig.registrationName) { + publishRegistrationName(dispatchConfig.registrationName, pluginModule); + return true; + } - var eventNameDispatchConfigs = {}; - /** - * Mapping from registration name to plugin module - */ + return false; +} +/** + * Publishes a registration name that is used to identify dispatched events. + * + * @param {string} registrationName Registration name to add. + * @param {object} PluginModule Plugin publishing the event. + * @private + */ - var registrationNameModules = {}; - /** - * Injects an ordering of plugins (by plugin name). This allows the ordering - * to be decoupled from injection of the actual plugins so that ordering is - * always deterministic regardless of packaging, on-the-fly injection, etc. - * - * @param {array} InjectedEventPluginOrder - * @internal - */ +function publishRegistrationName(registrationName, pluginModule, eventName) { + if (registrationNameModules[registrationName]) { + throw new Error('EventPluginRegistry: More than one plugin attempted to publish the same ' + ("registration name, `" + registrationName + "`.")); + } - function injectEventPluginOrder(injectedEventPluginOrder) { - if (eventPluginOrder) { - throw new Error( - "EventPluginRegistry: Cannot inject event plugin ordering more than " + - "once. You are likely trying to load more than one copy of React." - ); - } // Clone the ordering so it cannot be dynamically mutated. - // $FlowFixMe[method-unbinding] found when upgrading Flow + registrationNameModules[registrationName] = pluginModule; - eventPluginOrder = Array.prototype.slice.call(injectedEventPluginOrder); - recomputePluginOrdering(); - } - /** - * Injects plugins to be used by plugin event system. The plugin names must be - * in the ordering injected by `injectEventPluginOrder`. - * - * Plugins can be injected as part of page initialization or on-the-fly. - * - * @param {object} injectedNamesToPlugins Map from names to plugin modules. - * @internal - */ + { + registrationName.toLowerCase(); + } +} +/** + * Registers plugins so that they can extract and dispatch events. + */ - function injectEventPluginsByName(injectedNamesToPlugins) { - var isOrderingDirty = false; +/** + * Ordered list of injected plugins. + */ - for (var pluginName in injectedNamesToPlugins) { - if (!injectedNamesToPlugins.hasOwnProperty(pluginName)) { - continue; - } - var pluginModule = injectedNamesToPlugins[pluginName]; +var plugins = []; +/** + * Mapping from event name to dispatch config + */ - if ( - !namesToPlugins.hasOwnProperty(pluginName) || - namesToPlugins[pluginName] !== pluginModule - ) { - if (namesToPlugins[pluginName]) { - throw new Error( - "EventPluginRegistry: Cannot inject two different event plugins " + - ("using the same name, `" + pluginName + "`.") - ); - } +var eventNameDispatchConfigs = {}; +/** + * Mapping from registration name to plugin module + */ - namesToPlugins[pluginName] = pluginModule; - isOrderingDirty = true; - } - } +var registrationNameModules = {}; - if (isOrderingDirty) { - recomputePluginOrdering(); - } - } +/** + * Injects an ordering of plugins (by plugin name). This allows the ordering + * to be decoupled from injection of the actual plugins so that ordering is + * always deterministic regardless of packaging, on-the-fly injection, etc. + * + * @param {array} InjectedEventPluginOrder + * @internal + */ - function getListener(inst, registrationName) { - var stateNode = inst.stateNode; +function injectEventPluginOrder(injectedEventPluginOrder) { + if (eventPluginOrder) { + throw new Error('EventPluginRegistry: Cannot inject event plugin ordering more than ' + 'once. You are likely trying to load more than one copy of React.'); + } // Clone the ordering so it cannot be dynamically mutated. + // $FlowFixMe[method-unbinding] found when upgrading Flow - if (stateNode === null) { - // Work in progress (ex: onload events in incremental mode). - return null; - } - var props = getFiberCurrentPropsFromNode$1(stateNode); + eventPluginOrder = Array.prototype.slice.call(injectedEventPluginOrder); + recomputePluginOrdering(); +} +/** + * Injects plugins to be used by plugin event system. The plugin names must be + * in the ordering injected by `injectEventPluginOrder`. + * + * Plugins can be injected as part of page initialization or on-the-fly. + * + * @param {object} injectedNamesToPlugins Map from names to plugin modules. + * @internal + */ + +function injectEventPluginsByName(injectedNamesToPlugins) { + var isOrderingDirty = false; - if (props === null) { - // Work in progress. - return null; - } + for (var pluginName in injectedNamesToPlugins) { + if (!injectedNamesToPlugins.hasOwnProperty(pluginName)) { + continue; + } - var listener = props[registrationName]; + var pluginModule = injectedNamesToPlugins[pluginName]; - if (listener && typeof listener !== "function") { - throw new Error( - "Expected `" + - registrationName + - "` listener to be a function, instead got a value of `" + - typeof listener + - "` type." - ); + if (!namesToPlugins.hasOwnProperty(pluginName) || namesToPlugins[pluginName] !== pluginModule) { + if (namesToPlugins[pluginName]) { + throw new Error('EventPluginRegistry: Cannot inject two different event plugins ' + ("using the same name, `" + pluginName + "`.")); } - return listener; + namesToPlugins[pluginName] = pluginModule; + isOrderingDirty = true; } + } - var customBubblingEventTypes = - ReactNativePrivateInterface.ReactNativeViewConfigRegistry - .customBubblingEventTypes, - customDirectEventTypes = - ReactNativePrivateInterface.ReactNativeViewConfigRegistry - .customDirectEventTypes; // Start of inline: the below functions were inlined from - // EventPropagator.js, as they deviated from ReactDOM's newer - // implementations. - // $FlowFixMe[missing-local-annot] + if (isOrderingDirty) { + recomputePluginOrdering(); + } +} - function listenerAtPhase(inst, event, propagationPhase) { - var registrationName = - event.dispatchConfig.phasedRegistrationNames[propagationPhase]; - return getListener(inst, registrationName); - } // $FlowFixMe[missing-local-annot] +function getListener(inst, registrationName) { + var stateNode = inst.stateNode; - function accumulateDirectionalDispatches(inst, phase, event) { - { - if (!inst) { - error("Dispatching inst must not be null"); - } - } + if (stateNode === null) { + // Work in progress (ex: onload events in incremental mode). + return null; + } - var listener = listenerAtPhase(inst, event, phase); + var props = getFiberCurrentPropsFromNode$1(stateNode); - if (listener) { - event._dispatchListeners = accumulateInto( - event._dispatchListeners, - listener - ); - event._dispatchInstances = accumulateInto( - event._dispatchInstances, - inst - ); - } - } // $FlowFixMe[missing-local-annot] + if (props === null) { + // Work in progress. + return null; + } - function getParent(inst) { - do { - inst = inst.return; // TODO: If this is a HostRoot we might want to bail out. - // That is depending on if we want nested subtrees (layers) to bubble - // events to their parent. We could also go through parentNode on the - // host node but that wouldn't work for React Native and doesn't let us - // do the portal feature. - } while (inst && inst.tag !== HostComponent); + var listener = props[registrationName]; - if (inst) { - return inst; - } + if (listener && typeof listener !== 'function') { + throw new Error("Expected `" + registrationName + "` listener to be a function, instead got a value of `" + typeof listener + "` type."); + } - return null; + return listener; +} + +var customBubblingEventTypes = ReactNativePrivateInterface.ReactNativeViewConfigRegistry.customBubblingEventTypes, + customDirectEventTypes = ReactNativePrivateInterface.ReactNativeViewConfigRegistry.customDirectEventTypes; // Start of inline: the below functions were inlined from +// EventPropagator.js, as they deviated from ReactDOM's newer +// implementations. +// $FlowFixMe[missing-local-annot] + +function listenerAtPhase(inst, event, propagationPhase) { + var registrationName = event.dispatchConfig.phasedRegistrationNames[propagationPhase]; + return getListener(inst, registrationName); +} // $FlowFixMe[missing-local-annot] + + +function accumulateDirectionalDispatches(inst, phase, event) { + { + if (!inst) { + error('Dispatching inst must not be null'); } - /** - * Simulates the traversal of a two-phase, capture/bubble event dispatch. - */ + } - function traverseTwoPhase(inst, fn, arg, skipBubbling) { - var path = []; + var listener = listenerAtPhase(inst, event, phase); - while (inst) { - path.push(inst); - inst = getParent(inst); - } + if (listener) { + event._dispatchListeners = accumulateInto(event._dispatchListeners, listener); + event._dispatchInstances = accumulateInto(event._dispatchInstances, inst); + } +} // $FlowFixMe[missing-local-annot] - var i; - for (i = path.length; i-- > 0; ) { - fn(path[i], "captured", arg); - } +function getParent(inst) { + do { + inst = inst.return; // TODO: If this is a HostRoot we might want to bail out. + // That is depending on if we want nested subtrees (layers) to bubble + // events to their parent. We could also go through parentNode on the + // host node but that wouldn't work for React Native and doesn't let us + // do the portal feature. + } while (inst && inst.tag !== HostComponent); - if (skipBubbling) { - // Dispatch on target only - fn(path[0], "bubbled", arg); - } else { - for (i = 0; i < path.length; i++) { - fn(path[i], "bubbled", arg); - } - } - } // $FlowFixMe[missing-local-annot] + if (inst) { + return inst; + } - function accumulateTwoPhaseDispatchesSingle(event) { - if (event && event.dispatchConfig.phasedRegistrationNames) { - traverseTwoPhase( - event._targetInst, - accumulateDirectionalDispatches, - event, - false - ); - } - } // $FlowFixMe[missing-local-annot] + return null; +} +/** + * Simulates the traversal of a two-phase, capture/bubble event dispatch. + */ - function accumulateTwoPhaseDispatches(events) { - forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle); - } // $FlowFixMe[missing-local-annot] - function accumulateCapturePhaseDispatches(event) { - if (event && event.dispatchConfig.phasedRegistrationNames) { - traverseTwoPhase( - event._targetInst, - accumulateDirectionalDispatches, - event, - true - ); - } - } - /** - * Accumulates without regard to direction, does not look for phased - * registration names. Same as `accumulateDirectDispatchesSingle` but without - * requiring that the `dispatchMarker` be the same as the dispatched ID. - */ +function traverseTwoPhase(inst, fn, arg, skipBubbling) { + var path = []; - function accumulateDispatches(inst, ignoredDirection, event) { - if (inst && event && event.dispatchConfig.registrationName) { - var registrationName = event.dispatchConfig.registrationName; - var listener = getListener(inst, registrationName); + while (inst) { + path.push(inst); + inst = getParent(inst); + } - if (listener) { - event._dispatchListeners = accumulateInto( - event._dispatchListeners, - listener - ); - event._dispatchInstances = accumulateInto( - event._dispatchInstances, - inst - ); - } - } - } - /** - * Accumulates dispatches on an `SyntheticEvent`, but only for the - * `dispatchMarker`. - * @param {SyntheticEvent} event - */ + var i; - function accumulateDirectDispatchesSingle(event) { - if (event && event.dispatchConfig.registrationName) { - accumulateDispatches(event._targetInst, null, event); - } + for (i = path.length; i-- > 0;) { + fn(path[i], 'captured', arg); + } + + if (skipBubbling) { + // Dispatch on target only + fn(path[0], 'bubbled', arg); + } else { + for (i = 0; i < path.length; i++) { + fn(path[i], 'bubbled', arg); } + } +} // $FlowFixMe[missing-local-annot] - function accumulateDirectDispatches(events) { - forEachAccumulated(events, accumulateDirectDispatchesSingle); - } // End of inline +function accumulateTwoPhaseDispatchesSingle(event) { + if (event && event.dispatchConfig.phasedRegistrationNames) { + traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event, false); + } +} // $FlowFixMe[missing-local-annot] - var ReactNativeBridgeEventPlugin = { - eventTypes: {}, - extractEvents: function ( - topLevelType, - targetInst, - nativeEvent, - nativeEventTarget - ) { - if (targetInst == null) { - // Probably a node belonging to another renderer's tree. - return null; - } - var bubbleDispatchConfig = customBubblingEventTypes[topLevelType]; - var directDispatchConfig = customDirectEventTypes[topLevelType]; +function accumulateTwoPhaseDispatches(events) { + forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle); +} // $FlowFixMe[missing-local-annot] - if (!bubbleDispatchConfig && !directDispatchConfig) { - throw new Error( // $FlowFixMe[incompatible-type] - Flow doesn't like this string coercion because DOMTopLevelEventType is opaque - 'Unsupported top level event type "' + topLevelType + '" dispatched' - ); - } - var event = SyntheticEvent.getPooled( - bubbleDispatchConfig || directDispatchConfig, - targetInst, - nativeEvent, - nativeEventTarget - ); +function accumulateCapturePhaseDispatches(event) { + if (event && event.dispatchConfig.phasedRegistrationNames) { + traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event, true); + } +} +/** + * Accumulates without regard to direction, does not look for phased + * registration names. Same as `accumulateDirectDispatchesSingle` but without + * requiring that the `dispatchMarker` be the same as the dispatched ID. + */ - if (bubbleDispatchConfig) { - var skipBubbling = - event != null && - event.dispatchConfig.phasedRegistrationNames != null && - event.dispatchConfig.phasedRegistrationNames.skipBubbling; - if (skipBubbling) { - accumulateCapturePhaseDispatches(event); - } else { - accumulateTwoPhaseDispatches(event); - } - } else if (directDispatchConfig) { - accumulateDirectDispatches(event); - } else { - return null; - } +function accumulateDispatches(inst, ignoredDirection, event) { + if (inst && event && event.dispatchConfig.registrationName) { + var registrationName = event.dispatchConfig.registrationName; + var listener = getListener(inst, registrationName); - return event; - } - }; + if (listener) { + event._dispatchListeners = accumulateInto(event._dispatchListeners, listener); + event._dispatchInstances = accumulateInto(event._dispatchInstances, inst); + } + } +} +/** + * Accumulates dispatches on an `SyntheticEvent`, but only for the + * `dispatchMarker`. + * @param {SyntheticEvent} event + */ - var ReactNativeEventPluginOrder = [ - "ResponderEventPlugin", - "ReactNativeBridgeEventPlugin" - ]; - /** - * Make sure essential globals are available and are patched correctly. Please don't remove this - * line. Bundles created by react-packager `require` it before executing any application code. This - * ensures it exists in the dependency graph and can be `require`d. - * TODO: require this in packager, not in React #10932517 - */ - /** - * Inject module for resolving DOM hierarchy and plugin ordering. - */ +function accumulateDirectDispatchesSingle(event) { + if (event && event.dispatchConfig.registrationName) { + accumulateDispatches(event._targetInst, null, event); + } +} - injectEventPluginOrder(ReactNativeEventPluginOrder); - /** - * Some important event plugins included by default (without having to require - * them). - */ +function accumulateDirectDispatches(events) { + forEachAccumulated(events, accumulateDirectDispatchesSingle); +} // End of inline - injectEventPluginsByName({ - ResponderEventPlugin: ResponderEventPlugin, - ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin - }); - // Re-export dynamic flags from the internal module. - var dynamicFlags = dynamicFlagsUntyped; // We destructure each value before re-exporting to avoid a dynamic look-up on - // the exports object every time a flag is read. - - var alwaysThrottleRetries = dynamicFlags.alwaysThrottleRetries, - consoleManagedByDevToolsDuringStrictMode = - dynamicFlags.consoleManagedByDevToolsDuringStrictMode, - enableAsyncActions = dynamicFlags.enableAsyncActions, - enableEarlyReturnForPropDiffing = - dynamicFlags.enableEarlyReturnForPropDiffing, - enableComponentStackLocations = - dynamicFlags.enableComponentStackLocations, - enableDeferRootSchedulingToMicrotask = - dynamicFlags.enableDeferRootSchedulingToMicrotask, - enableInfiniteRenderLoopDetection = - dynamicFlags.enableInfiniteRenderLoopDetection, - enableRenderableContext = dynamicFlags.enableRenderableContext, - enableUnifiedSyncLane = dynamicFlags.enableUnifiedSyncLane, - passChildrenWhenCloningPersistedNodes = - dynamicFlags.passChildrenWhenCloningPersistedNodes, - useModernStrictMode = dynamicFlags.useModernStrictMode, - disableDefaultPropsExceptForClasses = - dynamicFlags.disableDefaultPropsExceptForClasses; // 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 syncLaneExpirationMs = 250; - var transitionLaneExpirationMs = 5000; - var enableLazyContextPropagation = false; - var enableLegacyHidden = false; - var disableLegacyMode = false; - - // Modules provided by RN: - var emptyObject$1 = {}; - /** - * Create a payload that contains all the updates between two sets of props. - * - * These helpers are all encapsulated into a single module, because they use - * mutation as a performance optimization which leads to subtle shared - * dependencies between the code paths. To avoid this mutable state leaking - * across modules, I've kept them isolated to this module. - */ - // Tracks removed keys +var ReactNativeBridgeEventPlugin = { + eventTypes: {}, + extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { + if (targetInst == null) { + // Probably a node belonging to another renderer's tree. + return null; + } - var removedKeys = null; - var removedKeyCount = 0; - var deepDifferOptions = { - unsafelyIgnoreFunctions: true - }; + var bubbleDispatchConfig = customBubblingEventTypes[topLevelType]; + var directDispatchConfig = customDirectEventTypes[topLevelType]; - function defaultDiffer(prevProp, nextProp) { - if (typeof nextProp !== "object" || nextProp === null) { - // Scalars have already been checked for equality - return true; - } else { - // For objects and arrays, the default diffing algorithm is a deep compare - return ReactNativePrivateInterface.deepDiffer( - prevProp, - nextProp, - deepDifferOptions - ); - } - } - - function restoreDeletedValuesInNestedArray( - updatePayload, - node, - validAttributes - ) { - if (isArray(node)) { - var i = node.length; - - while (i-- && removedKeyCount > 0) { - restoreDeletedValuesInNestedArray( - updatePayload, - node[i], - validAttributes - ); - } - } else if (node && removedKeyCount > 0) { - var obj = node; - - for (var propKey in removedKeys) { - // $FlowFixMe[incompatible-use] found when upgrading Flow - if (!removedKeys[propKey]) { - continue; - } + if (!bubbleDispatchConfig && !directDispatchConfig) { + throw new Error( // $FlowFixMe[incompatible-type] - Flow doesn't like this string coercion because DOMTopLevelEventType is opaque + "Unsupported top level event type \"" + topLevelType + "\" dispatched"); + } - var nextProp = obj[propKey]; + var event = SyntheticEvent.getPooled(bubbleDispatchConfig || directDispatchConfig, targetInst, nativeEvent, nativeEventTarget); - if (nextProp === undefined) { - continue; - } + if (bubbleDispatchConfig) { + var skipBubbling = event != null && event.dispatchConfig.phasedRegistrationNames != null && event.dispatchConfig.phasedRegistrationNames.skipBubbling; - var attributeConfig = validAttributes[propKey]; + if (skipBubbling) { + accumulateCapturePhaseDispatches(event); + } else { + accumulateTwoPhaseDispatches(event); + } + } else if (directDispatchConfig) { + accumulateDirectDispatches(event); + } else { + return null; + } - if (!attributeConfig) { - continue; // not a valid native prop - } + return event; + } +}; - if (typeof nextProp === "function") { - // $FlowFixMe[incompatible-type] found when upgrading Flow - nextProp = true; - } +var ReactNativeEventPluginOrder = ['ResponderEventPlugin', 'ReactNativeBridgeEventPlugin']; - if (typeof nextProp === "undefined") { - // $FlowFixMe[incompatible-type] found when upgrading Flow - nextProp = null; - } +/** + * Make sure essential globals are available and are patched correctly. Please don't remove this + * line. Bundles created by react-packager `require` it before executing any application code. This + * ensures it exists in the dependency graph and can be `require`d. + * TODO: require this in packager, not in React #10932517 + */ +/** + * Inject module for resolving DOM hierarchy and plugin ordering. + */ - if (typeof attributeConfig !== "object") { - // case: !Object is the default case - updatePayload[propKey] = nextProp; - } else if ( - typeof attributeConfig.diff === "function" || - typeof attributeConfig.process === "function" - ) { - // case: CustomAttributeConfiguration - var nextValue = - typeof attributeConfig.process === "function" - ? attributeConfig.process(nextProp) - : nextProp; - updatePayload[propKey] = nextValue; - } // $FlowFixMe[incompatible-use] found when upgrading Flow - - removedKeys[propKey] = false; - removedKeyCount--; - } - } - } - - function diffNestedArrayProperty( - updatePayload, - prevArray, - nextArray, - validAttributes - ) { - var minLength = - prevArray.length < nextArray.length - ? prevArray.length - : nextArray.length; - var i; - - for (i = 0; i < minLength; i++) { - // Diff any items in the array in the forward direction. Repeated keys - // will be overwritten by later values. - updatePayload = diffNestedProperty( - updatePayload, - prevArray[i], - nextArray[i], - validAttributes - ); - } - - for (; i < prevArray.length; i++) { - // Clear out all remaining properties. - updatePayload = clearNestedProperty( - updatePayload, - prevArray[i], - validAttributes - ); - } - - for (; i < nextArray.length; i++) { - // Add all remaining properties. - updatePayload = addNestedProperty( - updatePayload, - nextArray[i], - validAttributes - ); - } - - return updatePayload; - } - - function diffNestedProperty( - updatePayload, - prevProp, - nextProp, - validAttributes - ) { - if (!updatePayload && prevProp === nextProp) { - // If no properties have been added, then we can bail out quickly on object - // equality. - return updatePayload; - } - - if (!prevProp || !nextProp) { - if (nextProp) { - return addNestedProperty(updatePayload, nextProp, validAttributes); - } - - if (prevProp) { - return clearNestedProperty(updatePayload, prevProp, validAttributes); - } - - return updatePayload; - } - - if (!isArray(prevProp) && !isArray(nextProp)) { - // Both are leaves, we can diff the leaves. - return diffProperties( - updatePayload, - prevProp, - nextProp, - validAttributes - ); - } - - if (isArray(prevProp) && isArray(nextProp)) { - // Both are arrays, we can diff the arrays. - return diffNestedArrayProperty( - updatePayload, - prevProp, - nextProp, - validAttributes - ); - } +injectEventPluginOrder(ReactNativeEventPluginOrder); +/** + * Some important event plugins included by default (without having to require + * them). + */ - if (isArray(prevProp)) { - return diffProperties( - updatePayload, - ReactNativePrivateInterface.flattenStyle(prevProp), - nextProp, - validAttributes - ); - } +injectEventPluginsByName({ + ResponderEventPlugin: ResponderEventPlugin, + ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin +}); + +// Re-export dynamic flags from the internal module. +var dynamicFlags = dynamicFlagsUntyped; // We destructure each value before re-exporting to avoid a dynamic look-up on +// the exports object every time a flag is read. + +var alwaysThrottleRetries = dynamicFlags.alwaysThrottleRetries, + consoleManagedByDevToolsDuringStrictMode = dynamicFlags.consoleManagedByDevToolsDuringStrictMode, + enableAsyncActions = dynamicFlags.enableAsyncActions, + enableEarlyReturnForPropDiffing = dynamicFlags.enableEarlyReturnForPropDiffing, + enableComponentStackLocations = dynamicFlags.enableComponentStackLocations, + enableDeferRootSchedulingToMicrotask = dynamicFlags.enableDeferRootSchedulingToMicrotask, + enableInfiniteRenderLoopDetection = dynamicFlags.enableInfiniteRenderLoopDetection, + enableRenderableContext = dynamicFlags.enableRenderableContext, + enableUnifiedSyncLane = dynamicFlags.enableUnifiedSyncLane, + passChildrenWhenCloningPersistedNodes = dynamicFlags.passChildrenWhenCloningPersistedNodes, + useModernStrictMode = dynamicFlags.useModernStrictMode, + disableDefaultPropsExceptForClasses = dynamicFlags.disableDefaultPropsExceptForClasses; // 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 syncLaneExpirationMs = 250; +var transitionLaneExpirationMs = 5000; +var enableLazyContextPropagation = false; +var enableLegacyHidden = false; +var disableLegacyMode = false; + +// Modules provided by RN: +var emptyObject$1 = {}; +/** + * Create a payload that contains all the updates between two sets of props. + * + * These helpers are all encapsulated into a single module, because they use + * mutation as a performance optimization which leads to subtle shared + * dependencies between the code paths. To avoid this mutable state leaking + * across modules, I've kept them isolated to this module. + */ +// Tracks removed keys + +var removedKeys = null; +var removedKeyCount = 0; +var deepDifferOptions = { + unsafelyIgnoreFunctions: true +}; + +function defaultDiffer(prevProp, nextProp) { + if (typeof nextProp !== 'object' || nextProp === null) { + // Scalars have already been checked for equality + return true; + } else { + // For objects and arrays, the default diffing algorithm is a deep compare + return ReactNativePrivateInterface.deepDiffer(prevProp, nextProp, deepDifferOptions); + } +} - return diffProperties( - updatePayload, - prevProp, - ReactNativePrivateInterface.flattenStyle(nextProp), - validAttributes - ); +function restoreDeletedValuesInNestedArray(updatePayload, node, validAttributes) { + if (isArray(node)) { + var i = node.length; + + while (i-- && removedKeyCount > 0) { + restoreDeletedValuesInNestedArray(updatePayload, node[i], validAttributes); } - /** - * addNestedProperty takes a single set of props and valid attribute - * attribute configurations. It processes each prop and adds it to the - * updatePayload. - */ + } else if (node && removedKeyCount > 0) { + var obj = node; - function addNestedProperty(updatePayload, nextProp, validAttributes) { - if (!nextProp) { - return updatePayload; + for (var propKey in removedKeys) { + // $FlowFixMe[incompatible-use] found when upgrading Flow + if (!removedKeys[propKey]) { + continue; } - if (!isArray(nextProp)) { - // Add each property of the leaf. - return addProperties(updatePayload, nextProp, validAttributes); - } + var nextProp = obj[propKey]; - for (var i = 0; i < nextProp.length; i++) { - // Add all the properties of the array. - updatePayload = addNestedProperty( - updatePayload, - nextProp[i], - validAttributes - ); + if (nextProp === undefined) { + continue; } - return updatePayload; - } - /** - * clearNestedProperty takes a single set of props and valid attributes. It - * adds a null sentinel to the updatePayload, for each prop key. - */ + var attributeConfig = validAttributes[propKey]; - function clearNestedProperty(updatePayload, prevProp, validAttributes) { - if (!prevProp) { - return updatePayload; + if (!attributeConfig) { + continue; // not a valid native prop } - if (!isArray(prevProp)) { - // Add each property of the leaf. - return clearProperties(updatePayload, prevProp, validAttributes); + if (typeof nextProp === 'function') { + // $FlowFixMe[incompatible-type] found when upgrading Flow + nextProp = true; } - for (var i = 0; i < prevProp.length; i++) { - // Add all the properties of the array. - updatePayload = clearNestedProperty( - updatePayload, - prevProp[i], - validAttributes - ); + if (typeof nextProp === 'undefined') { + // $FlowFixMe[incompatible-type] found when upgrading Flow + nextProp = null; } - return updatePayload; - } - /** - * diffProperties takes two sets of props and a set of valid attributes - * and write to updatePayload the values that changed or were deleted. - * If no updatePayload is provided, a new one is created and returned if - * anything changed. - */ - - function diffProperties( - updatePayload, - prevProps, - nextProps, - validAttributes - ) { - var attributeConfig; - var nextProp; - var prevProp; - - for (var propKey in nextProps) { - attributeConfig = validAttributes[propKey]; - - if (!attributeConfig) { - continue; // not a valid native prop - } + if (typeof attributeConfig !== 'object') { + // case: !Object is the default case + updatePayload[propKey] = nextProp; + } else if (typeof attributeConfig.diff === 'function' || typeof attributeConfig.process === 'function') { + // case: CustomAttributeConfiguration + var nextValue = typeof attributeConfig.process === 'function' ? attributeConfig.process(nextProp) : nextProp; + updatePayload[propKey] = nextValue; + } // $FlowFixMe[incompatible-use] found when upgrading Flow - prevProp = prevProps[propKey]; - nextProp = nextProps[propKey]; // functions are converted to booleans as markers that the associated - // events should be sent from native. - if (typeof nextProp === "function") { - nextProp = true; // If nextProp is not a function, then don't bother changing prevProp - // since nextProp will win and go into the updatePayload regardless. + removedKeys[propKey] = false; + removedKeyCount--; + } + } +} - if (typeof prevProp === "function") { - prevProp = true; - } - } // An explicit value of undefined is treated as a null because it overrides - // any other preceding value. +function diffNestedArrayProperty(updatePayload, prevArray, nextArray, validAttributes) { + var minLength = prevArray.length < nextArray.length ? prevArray.length : nextArray.length; + var i; - if (typeof nextProp === "undefined") { - nextProp = null; + for (i = 0; i < minLength; i++) { + // Diff any items in the array in the forward direction. Repeated keys + // will be overwritten by later values. + updatePayload = diffNestedProperty(updatePayload, prevArray[i], nextArray[i], validAttributes); + } - if (typeof prevProp === "undefined") { - prevProp = null; - } - } + for (; i < prevArray.length; i++) { + // Clear out all remaining properties. + updatePayload = clearNestedProperty(updatePayload, prevArray[i], validAttributes); + } - if (removedKeys) { - removedKeys[propKey] = false; - } - - if (updatePayload && updatePayload[propKey] !== undefined) { - // Something else already triggered an update to this key because another - // value diffed. Since we're now later in the nested arrays our value is - // more important so we need to calculate it and override the existing - // value. It doesn't matter if nothing changed, we'll set it anyway. - // Pattern match on: attributeConfig - if (typeof attributeConfig !== "object") { - // case: !Object is the default case - updatePayload[propKey] = nextProp; - } else if ( - typeof attributeConfig.diff === "function" || - typeof attributeConfig.process === "function" - ) { - // case: CustomAttributeConfiguration - var nextValue = - typeof attributeConfig.process === "function" - ? attributeConfig.process(nextProp) - : nextProp; - updatePayload[propKey] = nextValue; - } + for (; i < nextArray.length; i++) { + // Add all remaining properties. + updatePayload = addNestedProperty(updatePayload, nextArray[i], validAttributes); + } - continue; - } + return updatePayload; +} - if (prevProp === nextProp) { - continue; // nothing changed - } // Pattern match on: attributeConfig +function diffNestedProperty(updatePayload, prevProp, nextProp, validAttributes) { + if (!updatePayload && prevProp === nextProp) { + // If no properties have been added, then we can bail out quickly on object + // equality. + return updatePayload; + } - if (typeof attributeConfig !== "object") { - // case: !Object is the default case - if (defaultDiffer(prevProp, nextProp)) { - // a normal leaf has changed - (updatePayload || (updatePayload = {}))[propKey] = nextProp; - } - } else if ( - typeof attributeConfig.diff === "function" || - typeof attributeConfig.process === "function" - ) { - // case: CustomAttributeConfiguration - var shouldUpdate = - prevProp === undefined || - (typeof attributeConfig.diff === "function" - ? attributeConfig.diff(prevProp, nextProp) - : defaultDiffer(prevProp, nextProp)); - - if (shouldUpdate) { - var _nextValue = - typeof attributeConfig.process === "function" // $FlowFixMe[incompatible-use] found when upgrading Flow - ? attributeConfig.process(nextProp) - : nextProp; - - (updatePayload || (updatePayload = {}))[propKey] = _nextValue; - } - } else { - // default: fallthrough case when nested properties are defined - removedKeys = null; - removedKeyCount = 0; // We think that attributeConfig is not CustomAttributeConfiguration at - // this point so we assume it must be AttributeConfiguration. - - updatePayload = diffNestedProperty( - updatePayload, - prevProp, - nextProp, - attributeConfig - ); - - if (removedKeyCount > 0 && updatePayload) { - restoreDeletedValuesInNestedArray( - updatePayload, - nextProp, - attributeConfig - ); - removedKeys = null; - } - } - } // Also iterate through all the previous props to catch any that have been - // removed and make sure native gets the signal so it can reset them to the - // default. + if (!prevProp || !nextProp) { + if (nextProp) { + return addNestedProperty(updatePayload, nextProp, validAttributes); + } - for (var _propKey in prevProps) { - if (nextProps[_propKey] !== undefined) { - continue; // we've already covered this key in the previous pass - } + if (prevProp) { + return clearNestedProperty(updatePayload, prevProp, validAttributes); + } - attributeConfig = validAttributes[_propKey]; + return updatePayload; + } - if (!attributeConfig) { - continue; // not a valid native prop - } + if (!isArray(prevProp) && !isArray(nextProp)) { + // Both are leaves, we can diff the leaves. + return diffProperties(updatePayload, prevProp, nextProp, validAttributes); + } - if (updatePayload && updatePayload[_propKey] !== undefined) { - // This was already updated to a diff result earlier. - continue; - } + if (isArray(prevProp) && isArray(nextProp)) { + // Both are arrays, we can diff the arrays. + return diffNestedArrayProperty(updatePayload, prevProp, nextProp, validAttributes); + } - prevProp = prevProps[_propKey]; + if (isArray(prevProp)) { + return diffProperties(updatePayload, ReactNativePrivateInterface.flattenStyle(prevProp), nextProp, validAttributes); + } - if (prevProp === undefined) { - continue; // was already empty anyway - } // Pattern match on: attributeConfig + return diffProperties(updatePayload, prevProp, ReactNativePrivateInterface.flattenStyle(nextProp), validAttributes); +} +/** + * addNestedProperty takes a single set of props and valid attribute + * attribute configurations. It processes each prop and adds it to the + * updatePayload. + */ - if ( - typeof attributeConfig !== "object" || - typeof attributeConfig.diff === "function" || - typeof attributeConfig.process === "function" - ) { - // case: CustomAttributeConfiguration | !Object - // Flag the leaf property for removal by sending a sentinel. - (updatePayload || (updatePayload = {}))[_propKey] = null; - if (!removedKeys) { - removedKeys = {}; - } +function addNestedProperty(updatePayload, nextProp, validAttributes) { + if (!nextProp) { + return updatePayload; + } - if (!removedKeys[_propKey]) { - removedKeys[_propKey] = true; - removedKeyCount++; - } - } else { - // default: - // This is a nested attribute configuration where all the properties - // were removed so we need to go through and clear out all of them. - updatePayload = clearNestedProperty( - updatePayload, - prevProp, - attributeConfig - ); - } - } + if (!isArray(nextProp)) { + // Add each property of the leaf. + return addProperties(updatePayload, nextProp, validAttributes); + } - return updatePayload; - } - /** - * addProperties adds all the valid props to the payload after being processed. - */ + for (var i = 0; i < nextProp.length; i++) { + // Add all the properties of the array. + updatePayload = addNestedProperty(updatePayload, nextProp[i], validAttributes); + } - function addProperties(updatePayload, props, validAttributes) { - // TODO: Fast path - return diffProperties( - updatePayload, - emptyObject$1, - props, - validAttributes - ); - } - /** - * clearProperties clears all the previous props by adding a null sentinel - * to the payload for each valid key. - */ + return updatePayload; +} +/** + * clearNestedProperty takes a single set of props and valid attributes. It + * adds a null sentinel to the updatePayload, for each prop key. + */ - function clearProperties(updatePayload, prevProps, validAttributes) { - // TODO: Fast path - return diffProperties( - updatePayload, - prevProps, - emptyObject$1, - validAttributes - ); - } - - function create(props, validAttributes) { - return addProperties( - null, // updatePayload - props, - validAttributes - ); - } - function diff(prevProps, nextProps, validAttributes) { - if (enableEarlyReturnForPropDiffing) { - if (prevProps === nextProps) { - return null; // no change - } - } - - return diffProperties( - null, // updatePayload - prevProps, - nextProps, - validAttributes - ); - } - - // 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$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); - } +function clearNestedProperty(updatePayload, prevProp, validAttributes) { + if (!prevProp) { + return updatePayload; + } - isInsideEventHandler = true; + if (!isArray(prevProp)) { + // Add each property of the leaf. + return clearProperties(updatePayload, prevProp, validAttributes); + } - try { - return batchedUpdatesImpl(fn, bookkeeping); - } finally { - isInsideEventHandler = false; - } - } - function setBatchingImplementation( - _batchedUpdatesImpl, - _discreteUpdatesImpl - ) { - batchedUpdatesImpl = _batchedUpdatesImpl; - } + for (var i = 0; i < prevProp.length; i++) { + // Add all the properties of the array. + updatePayload = clearNestedProperty(updatePayload, prevProp[i], validAttributes); + } - /** - * Internal queue of events that have accumulated their dispatches and are - * waiting to have their dispatches executed. - */ + return updatePayload; +} +/** + * diffProperties takes two sets of props and a set of valid attributes + * and write to updatePayload the values that changed or were deleted. + * If no updatePayload is provided, a new one is created and returned if + * anything changed. + */ - 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 executeDispatchesAndRelease(event) { - if (event) { - executeDispatchesInOrder(event); +function diffProperties(updatePayload, prevProps, nextProps, validAttributes) { + var attributeConfig; + var nextProp; + var prevProp; - if (!event.isPersistent()) { - event.constructor.release(event); - } - } - } // $FlowFixMe[missing-local-annot] + for (var propKey in nextProps) { + attributeConfig = validAttributes[propKey]; - function executeDispatchesAndReleaseTopLevel(e) { - return executeDispatchesAndRelease(e); + if (!attributeConfig) { + continue; // not a valid native prop } - 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. + prevProp = prevProps[propKey]; + nextProp = nextProps[propKey]; // functions are converted to booleans as markers that the associated + // events should be sent from native. - var processingEventQueue = eventQueue; - eventQueue = null; + if (typeof nextProp === 'function') { + nextProp = true; // If nextProp is not a function, then don't bother changing prevProp + // since nextProp will win and go into the updatePayload regardless. - if (!processingEventQueue) { - return; + if (typeof prevProp === 'function') { + prevProp = true; } + } // An explicit value of undefined is treated as a null because it overrides + // any other preceding value. - forEachAccumulated( - processingEventQueue, - executeDispatchesAndReleaseTopLevel - ); - 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 (typeof nextProp === 'undefined') { + nextProp = null; - rethrowCaughtError(); + if (typeof prevProp === 'undefined') { + prevProp = null; + } } - /** - * Allows registered plugins an opportunity to extract events from top-level - * native browser events. - * - * @return {*} An accumulation of synthetic events. - * @internal - */ + if (removedKeys) { + removedKeys[propKey] = false; + } - function extractPluginEvents( - topLevelType, - targetInst, - nativeEvent, - nativeEventTarget - ) { - var events = null; - var legacyPlugins = plugins; - - for (var i = 0; i < legacyPlugins.length; i++) { - // Not every plugin in the ordering may be loaded at runtime. - var possiblePlugin = legacyPlugins[i]; - - if (possiblePlugin) { - var extractedEvents = possiblePlugin.extractEvents( - topLevelType, - targetInst, - nativeEvent, - nativeEventTarget - ); - - if (extractedEvents) { - events = accumulateInto(events, extractedEvents); - } - } + if (updatePayload && updatePayload[propKey] !== undefined) { + // Something else already triggered an update to this key because another + // value diffed. Since we're now later in the nested arrays our value is + // more important so we need to calculate it and override the existing + // value. It doesn't matter if nothing changed, we'll set it anyway. + // Pattern match on: attributeConfig + if (typeof attributeConfig !== 'object') { + // case: !Object is the default case + updatePayload[propKey] = nextProp; + } else if (typeof attributeConfig.diff === 'function' || typeof attributeConfig.process === 'function') { + // case: CustomAttributeConfiguration + var nextValue = typeof attributeConfig.process === 'function' ? attributeConfig.process(nextProp) : nextProp; + updatePayload[propKey] = nextValue; } - return events; + continue; } - function runExtractedPluginEventsInBatch( - topLevelType, - targetInst, - nativeEvent, - nativeEventTarget - ) { - var events = extractPluginEvents( - topLevelType, - targetInst, - nativeEvent, - nativeEventTarget - ); - runEventsInBatch(events); - } + if (prevProp === nextProp) { + continue; // nothing changed + } // Pattern match on: attributeConfig + - function dispatchEvent(target, topLevelType, nativeEvent) { - var targetFiber = target; - var eventTarget = null; + if (typeof attributeConfig !== 'object') { + // case: !Object is the default case + if (defaultDiffer(prevProp, nextProp)) { + // a normal leaf has changed + (updatePayload || (updatePayload = {}))[propKey] = nextProp; + } + } else if (typeof attributeConfig.diff === 'function' || typeof attributeConfig.process === 'function') { + // case: CustomAttributeConfiguration + var shouldUpdate = prevProp === undefined || (typeof attributeConfig.diff === 'function' ? attributeConfig.diff(prevProp, nextProp) : defaultDiffer(prevProp, nextProp)); - if (targetFiber != null) { - var stateNode = targetFiber.stateNode; // Guard against Fiber being unmounted + if (shouldUpdate) { + var _nextValue = typeof attributeConfig.process === 'function' ? // $FlowFixMe[incompatible-use] found when upgrading Flow + attributeConfig.process(nextProp) : nextProp; - if (stateNode != null) { - // $FlowExpectedError[incompatible-cast] public instances in Fabric do not implement `EventTarget` yet. - eventTarget = getPublicInstance(stateNode); - } + (updatePayload || (updatePayload = {}))[propKey] = _nextValue; } + } else { + // default: fallthrough case when nested properties are defined + removedKeys = null; + removedKeyCount = 0; // We think that attributeConfig is not CustomAttributeConfiguration at + // this point so we assume it must be AttributeConfiguration. - 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 - - ReactNativePrivateInterface.RawEventEmitter.emit(topLevelType, event); // $FlowFixMe[class-object-subtyping] found when upgrading Flow - - ReactNativePrivateInterface.RawEventEmitter.emit("*", event); // Heritage plugin event system - - runExtractedPluginEventsInBatch( - topLevelType, - targetFiber, - nativeEvent, - eventTarget - ); - }); // React Native doesn't use ReactControlledComponent but if it did, here's - // where it would do it. - } - - var NoFlags$1 = - /* */ - 0; - var PerformedWork = - /* */ - 1; - var Placement = - /* */ - 2; - var DidCapture = - /* */ - 128; - var Hydrating = - /* */ - 4096; // You can change the rest (and add more). - - var Update = - /* */ - 4; - /* Skipped value: 0b0000000000000000000000001000; */ - - var ChildDeletion = - /* */ - 16; - var ContentReset = - /* */ - 32; - var Callback = - /* */ - 64; - /* Used by DidCapture: 0b0000000000000000000010000000; */ - - var ForceClientRender = - /* */ - 256; - var Ref = - /* */ - 512; - var Snapshot = - /* */ - 1024; - var Passive$1 = - /* */ - 2048; - /* Used by Hydrating: 0b0000000000000001000000000000; */ - - var Visibility = - /* */ - 8192; - var StoreConsistency = - /* */ - 16384; // It's OK to reuse these bits because these flags are mutually exclusive for - // different fiber types. We should really be doing this for as many flags as - // possible, because we're about to run out of bits. - - var ScheduleRetry = StoreConsistency; - var ShouldSuspendCommit = Visibility; - var DidDefer = ContentReset; - var FormReset = Snapshot; - var LifecycleEffectMask = - Passive$1 | Update | Callback | Ref | Snapshot | StoreConsistency; // Union of all commit flags (flags with the lifetime of a particular commit) - - var HostEffectMask = - /* */ - 32767; // These are not really side effects, but we still reuse this field. - - var Incomplete = - /* */ - 32768; - var ShouldCapture = - /* */ - 65536; - var ForceUpdateForLegacySuspense = - /* */ - 131072; - var Forked = - /* */ - 1048576; // Static tags describe aspects of a fiber that are not specific to a render, - // e.g. a fiber uses a passive effect (even if there are no updates on this particular render). - // This enables us to defer more work in the unmount case, - // since we can defer traversing the tree during layout to look for Passive effects, - // and instead rely on the static flag as a signal that there may be cleanup work. - - var RefStatic = - /* */ - 2097152; - var LayoutStatic = - /* */ - 4194304; - var PassiveStatic = - /* */ - 8388608; - var MaySuspendCommit = - /* */ - 16777216; // Flag used to identify newly inserted fibers. It isn't reset after commit unlike `Placement`. - - var PlacementDEV = - /* */ - 33554432; - var MountLayoutDev = - /* */ - 67108864; - var MountPassiveDev = - /* */ - 134217728; // Groups of flags that are used in the commit phase to skip over trees that - // don't contain effects, by checking subtreeFlags. - - var BeforeMutationMask = // TODO: Remove Update flag from before mutation phase by re-landing Visibility - // flag logic (see #20043) - Update | Snapshot | 0; - var MutationMask = - Placement | - Update | - ChildDeletion | - ContentReset | - Ref | - Hydrating | - Visibility | - FormReset; - var LayoutMask = Update | Callback | Ref | Visibility; // TODO: Split into PassiveMountMask and PassiveUnmountMask - - var PassiveMask = Passive$1 | Visibility | ChildDeletion; // Union of tags that don't get reset on clones. - // This allows certain concepts to persist without recalculating them, - // e.g. whether a subtree contains passive effects or portals. - - var StaticMask = - LayoutStatic | PassiveStatic | RefStatic | MaySuspendCommit; - - // This module only exists as an ESM wrapper around the external CommonJS - var scheduleCallback$3 = 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$1 = Scheduler.unstable_NormalPriority; - var IdlePriority = Scheduler.unstable_IdlePriority; // this doesn't actually exist on the scheduler, but it *does* - // on scheduler/unstable_mock, which we'll need for internal testing - - var log$1 = Scheduler.log; - var unstable_setDisableYieldValue = Scheduler.unstable_setDisableYieldValue; - - // 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[cannot-write] 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 */ - } + updatePayload = diffNestedProperty(updatePayload, prevProp, nextProp, attributeConfig); - disabledDepth++; + if (removedKeyCount > 0 && updatePayload) { + restoreDeletedValuesInNestedArray(updatePayload, nextProp, attributeConfig); + removedKeys = null; } } - function reenableLogs() { - { - disabledDepth--; - - if (disabledDepth === 0) { - /* eslint-disable react-internal/no-production-logging */ - var props = { - configurable: true, - enumerable: true, - writable: true - }; // $FlowFixMe[cannot-write] 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 */ - } + } // Also iterate through all the previous props to catch any that have been + // removed and make sure native gets the signal so it can reset them to the + // default. - if (disabledDepth < 0) { - error( - "disabledDepth fell below zero. " + - "This is a bug in React. Please file an issue." - ); - } - } + + for (var _propKey in prevProps) { + if (nextProps[_propKey] !== undefined) { + continue; // we've already covered this key in the previous pass } - 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; - } + attributeConfig = validAttributes[_propKey]; - var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__; + if (!attributeConfig) { + continue; // not a valid native prop + } - 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; - } + if (updatePayload && updatePayload[_propKey] !== undefined) { + // This was already updated to a diff result earlier. + continue; + } - 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://react.dev/link/react-devtools" - ); - } // DevTools exists, even though it doesn't support Fiber. + prevProp = prevProps[_propKey]; - return true; - } + if (prevProp === undefined) { + continue; // was already empty anyway + } // Pattern match on: attributeConfig - 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. + if (typeof attributeConfig !== 'object' || typeof attributeConfig.diff === 'function' || typeof attributeConfig.process === 'function') { + // case: CustomAttributeConfiguration | !Object + // Flag the leaf property for removal by sending a sentinel. + (updatePayload || (updatePayload = {}))[_propKey] = null; - injectedHook = hook; - } catch (err) { - // Catch all errors because it is unsafe to throw during initialization. - { - error("React instrumentation encountered an error: %s.", err); - } + if (!removedKeys) { + removedKeys = {}; } - if (hook.checkDCE) { - // This is the real DevTools. - return true; - } else { - // This is likely a hook installed by Fast Refresh runtime. - return false; + if (!removedKeys[_propKey]) { + removedKeys[_propKey] = true; + removedKeyCount++; } + } else { + // default: + // This is a nested attribute configuration where all the properties + // were removed so we need to go through and clear out all of them. + updatePayload = clearNestedProperty(updatePayload, prevProp, attributeConfig); } - function onScheduleRoot(root, children) { - { - 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); - } - } - } - } - } - function onCommitRoot(root, eventPriority) { - if ( - injectedHook && - typeof injectedHook.onCommitFiberRoot === "function" - ) { - try { - var didError = (root.current.flags & DidCapture) === DidCapture; + return updatePayload; +} +/** + * addProperties adds all the valid props to the payload after being processed. + */ - if (enableProfilerTimer) { - var schedulerPriority; - switch (eventPriority) { - case DiscreteEventPriority: - schedulerPriority = ImmediatePriority; - break; +function addProperties(updatePayload, props, validAttributes) { + // TODO: Fast path + return diffProperties(updatePayload, emptyObject$1, props, validAttributes); +} +/** + * clearProperties clears all the previous props by adding a null sentinel + * to the payload for each valid key. + */ - case ContinuousEventPriority: - schedulerPriority = UserBlockingPriority; - break; - case DefaultEventPriority: - schedulerPriority = NormalPriority$1; - break; +function clearProperties(updatePayload, prevProps, validAttributes) { + // TODO: Fast path + return diffProperties(updatePayload, prevProps, emptyObject$1, validAttributes); +} - case IdleEventPriority: - schedulerPriority = IdlePriority; - break; +function create(props, validAttributes) { + return addProperties(null, // updatePayload + props, validAttributes); +} +function diff(prevProps, nextProps, validAttributes) { + if (enableEarlyReturnForPropDiffing) { + if (prevProps === nextProps) { + return null; // no change + } + } - default: - schedulerPriority = NormalPriority$1; - break; - } + return diffProperties(null, // updatePayload + prevProps, nextProps, validAttributes); +} - injectedHook.onCommitFiberRoot( - rendererID, - root, - schedulerPriority, - didError - ); +// 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$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); + } + + isInsideEventHandler = true; + + try { + return batchedUpdatesImpl(fn, bookkeeping); + } finally { + isInsideEventHandler = false; + } +} +function setBatchingImplementation(_batchedUpdatesImpl, _discreteUpdatesImpl) { + batchedUpdatesImpl = _batchedUpdatesImpl; +} + +/** + * Internal queue of events that have accumulated their dispatches and are + * waiting to have their dispatches executed. + */ + +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 executeDispatchesAndRelease(event) { + if (event) { + executeDispatchesInOrder(event); + + if (!event.isPersistent()) { + event.constructor.release(event); + } + } +} // $FlowFixMe[missing-local-annot] + + +function executeDispatchesAndReleaseTopLevel(e) { + return executeDispatchesAndRelease(e); +} + +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 processingEventQueue = eventQueue; + eventQueue = null; + + if (!processingEventQueue) { + return; + } + + forEachAccumulated(processingEventQueue, executeDispatchesAndReleaseTopLevel); + + 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. + + + rethrowCaughtError(); +} + +/** + * Allows registered plugins an opportunity to extract events from top-level + * native browser events. + * + * @return {*} An accumulation of synthetic events. + * @internal + */ + +function extractPluginEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget) { + var events = null; + var legacyPlugins = plugins; + + for (var i = 0; i < legacyPlugins.length; i++) { + // Not every plugin in the ordering may be loaded at runtime. + var possiblePlugin = legacyPlugins[i]; + + if (possiblePlugin) { + var extractedEvents = possiblePlugin.extractEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget); + + if (extractedEvents) { + events = accumulateInto(events, extractedEvents); + } + } + } + + return events; +} + +function runExtractedPluginEventsInBatch(topLevelType, targetInst, nativeEvent, nativeEventTarget) { + var events = extractPluginEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget); + runEventsInBatch(events); +} + +function dispatchEvent(target, topLevelType, nativeEvent) { + var targetFiber = target; + var eventTarget = null; + + if (targetFiber != null) { + var stateNode = targetFiber.stateNode; // Guard against Fiber being unmounted + + if (stateNode != null) { + // $FlowExpectedError[incompatible-cast] public instances in Fabric do not implement `EventTarget` yet. + eventTarget = getPublicInstance(stateNode); + } + } + + 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 + + ReactNativePrivateInterface.RawEventEmitter.emit(topLevelType, event); // $FlowFixMe[class-object-subtyping] found when upgrading Flow + + ReactNativePrivateInterface.RawEventEmitter.emit('*', event); // Heritage plugin event system + + runExtractedPluginEventsInBatch(topLevelType, targetFiber, nativeEvent, eventTarget); + }); // React Native doesn't use ReactControlledComponent but if it did, here's + // where it would do it. +} + +var NoFlags$1 = +/* */ +0; +var PerformedWork = +/* */ +1; +var Placement = +/* */ +2; +var DidCapture = +/* */ +128; +var Hydrating = +/* */ +4096; // You can change the rest (and add more). + +var Update = +/* */ +4; +/* Skipped value: 0b0000000000000000000000001000; */ + +var ChildDeletion = +/* */ +16; +var ContentReset = +/* */ +32; +var Callback = +/* */ +64; +/* Used by DidCapture: 0b0000000000000000000010000000; */ + +var ForceClientRender = +/* */ +256; +var Ref = +/* */ +512; +var Snapshot = +/* */ +1024; +var Passive$1 = +/* */ +2048; +/* Used by Hydrating: 0b0000000000000001000000000000; */ + +var Visibility = +/* */ +8192; +var StoreConsistency = +/* */ +16384; // It's OK to reuse these bits because these flags are mutually exclusive for +// different fiber types. We should really be doing this for as many flags as +// possible, because we're about to run out of bits. + +var ScheduleRetry = StoreConsistency; +var ShouldSuspendCommit = Visibility; +var DidDefer = ContentReset; +var FormReset = Snapshot; +var LifecycleEffectMask = Passive$1 | Update | Callback | Ref | Snapshot | StoreConsistency; // Union of all commit flags (flags with the lifetime of a particular commit) + +var HostEffectMask = +/* */ +32767; // These are not really side effects, but we still reuse this field. + +var Incomplete = +/* */ +32768; +var ShouldCapture = +/* */ +65536; +var ForceUpdateForLegacySuspense = +/* */ +131072; +var Forked = +/* */ +1048576; // Static tags describe aspects of a fiber that are not specific to a render, +// e.g. a fiber uses a passive effect (even if there are no updates on this particular render). +// This enables us to defer more work in the unmount case, +// since we can defer traversing the tree during layout to look for Passive effects, +// and instead rely on the static flag as a signal that there may be cleanup work. + +var RefStatic = +/* */ +2097152; +var LayoutStatic = +/* */ +4194304; +var PassiveStatic = +/* */ +8388608; +var MaySuspendCommit = +/* */ +16777216; // Flag used to identify newly inserted fibers. It isn't reset after commit unlike `Placement`. + +var PlacementDEV = +/* */ +33554432; +var MountLayoutDev = +/* */ +67108864; +var MountPassiveDev = +/* */ +134217728; // Groups of flags that are used in the commit phase to skip over trees that +// don't contain effects, by checking subtreeFlags. + +var BeforeMutationMask = // TODO: Remove Update flag from before mutation phase by re-landing Visibility +// flag logic (see #20043) +Update | Snapshot | (0); +var MutationMask = Placement | Update | ChildDeletion | ContentReset | Ref | Hydrating | Visibility | FormReset; +var LayoutMask = Update | Callback | Ref | Visibility; // TODO: Split into PassiveMountMask and PassiveUnmountMask + +var PassiveMask = Passive$1 | Visibility | ChildDeletion; // Union of tags that don't get reset on clones. +// This allows certain concepts to persist without recalculating them, +// e.g. whether a subtree contains passive effects or portals. + +var StaticMask = LayoutStatic | PassiveStatic | RefStatic | MaySuspendCommit; + +// This module only exists as an ESM wrapper around the external CommonJS +var scheduleCallback$3 = 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$1 = Scheduler.unstable_NormalPriority; +var IdlePriority = Scheduler.unstable_IdlePriority; // this doesn't actually exist on the scheduler, but it *does* +// on scheduler/unstable_mock, which we'll need for internal testing + +var log$1 = Scheduler.log; +var unstable_setDisableYieldValue = Scheduler.unstable_setDisableYieldValue; + +// 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[cannot-write] 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 */ + } + + disabledDepth++; + } +} +function reenableLogs() { + { + disabledDepth--; + + if (disabledDepth === 0) { + /* eslint-disable react-internal/no-production-logging */ + var props = { + configurable: true, + enumerable: true, + writable: true + }; // $FlowFixMe[cannot-write] 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.'); + } + } +} + +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; + } + + var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__; + + 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; + } + + 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://react.dev/link/react-devtools'); + } // DevTools exists, even though it doesn't support Fiber. + + + return true; + } + + 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); + } + } + + 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; + + error('React instrumentation encountered an error: %s', err); + } + } + } + } +} +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; + + case ContinuousEventPriority: + schedulerPriority = UserBlockingPriority; + break; + + case DefaultEventPriority: + schedulerPriority = NormalPriority$1; + break; + + case IdleEventPriority: + schedulerPriority = IdlePriority; + break; + + default: + schedulerPriority = NormalPriority$1; + break; + } + + injectedHook.onCommitFiberRoot(rendererID, root, schedulerPriority, didError); + } + } catch (err) { + { + if (!hasLoggedError) { + hasLoggedError = true; + + error('React instrumentation encountered an error: %s', err); + } + } + } + } +} +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; + + error('React instrumentation encountered an error: %s', err); + } + } + } + } +} +function setIsStrictModeForDevtools(newIsStrictMode) { + if (consoleManagedByDevToolsDuringStrictMode) { + if (typeof log$1 === 'function') { + // We're in a test because Scheduler.log only exists + // in SchedulerMock. To reduce the noise in strict mode tests, + // suppress warnings and disable scheduler yielding during the double render + unstable_setDisableYieldValue(newIsStrictMode); + setSuppressWarning(newIsStrictMode); + } + + if (injectedHook && typeof injectedHook.setStrictMode === 'function') { + try { + injectedHook.setStrictMode(rendererID, newIsStrictMode); + } catch (err) { + { + if (!hasLoggedError) { + hasLoggedError = true; + + error('React instrumentation encountered an error: %s', err); } - } catch (err) { - { - if (!hasLoggedError) { - hasLoggedError = true; + } + } + } + } else { + if (newIsStrictMode) { + disableLogs(); + } else { + reenableLogs(); + } + } +} // Profiler API hooks + +function injectProfilingHooks(profilingHooks) { + injectedProfilingHooks = profilingHooks; +} + +function getLaneLabelMap() { + { + var map = new Map(); + var lane = 1; + + for (var index = 0; index < TotalLanes; index++) { + var label = getLabelForLane(lane); + map.set(lane, label); + lane *= 2; + } + + return map; + } +} + +function markCommitStarted(lanes) { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markCommitStarted === 'function') { + injectedProfilingHooks.markCommitStarted(lanes); + } + } +} +function markCommitStopped() { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markCommitStopped === 'function') { + injectedProfilingHooks.markCommitStopped(); + } + } +} +function markComponentRenderStarted(fiber) { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentRenderStarted === 'function') { + injectedProfilingHooks.markComponentRenderStarted(fiber); + } + } +} +function markComponentRenderStopped() { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentRenderStopped === 'function') { + injectedProfilingHooks.markComponentRenderStopped(); + } + } +} +function markComponentPassiveEffectMountStarted(fiber) { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentPassiveEffectMountStarted === 'function') { + injectedProfilingHooks.markComponentPassiveEffectMountStarted(fiber); + } + } +} +function markComponentPassiveEffectMountStopped() { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentPassiveEffectMountStopped === 'function') { + injectedProfilingHooks.markComponentPassiveEffectMountStopped(); + } + } +} +function markComponentPassiveEffectUnmountStarted(fiber) { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentPassiveEffectUnmountStarted === 'function') { + injectedProfilingHooks.markComponentPassiveEffectUnmountStarted(fiber); + } + } +} +function markComponentPassiveEffectUnmountStopped() { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentPassiveEffectUnmountStopped === 'function') { + injectedProfilingHooks.markComponentPassiveEffectUnmountStopped(); + } + } +} +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(); + } + } +} +function markRenderScheduled(lane) { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markRenderScheduled === 'function') { + injectedProfilingHooks.markRenderScheduled(lane); + } + } +} +function markForceUpdateScheduled(fiber, lane) { + { + 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); + } + } +} + +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 NoStrictPassiveEffectsMode = +/* */ +64; + +// 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. + +var TotalLanes = 31; +var NoLanes = +/* */ +0; +var NoLane = +/* */ +0; +var SyncHydrationLane = +/* */ +1; +var SyncLane = +/* */ +2; +var SyncLaneIndex = 1; +var InputContinuousHydrationLane = +/* */ +4; +var InputContinuousLane = +/* */ +8; +var DefaultHydrationLane = +/* */ +16; +var DefaultLane = +/* */ +32; +var SyncUpdateLanes = enableUnifiedSyncLane ? SyncLane | InputContinuousLane | DefaultLane : SyncLane; +var TransitionHydrationLane = +/* */ +64; +var TransitionLanes = +/* */ +4194176; +var TransitionLane1 = +/* */ +128; +var TransitionLane2 = +/* */ +256; +var TransitionLane3 = +/* */ +512; +var TransitionLane4 = +/* */ +1024; +var TransitionLane5 = +/* */ +2048; +var TransitionLane6 = +/* */ +4096; +var TransitionLane7 = +/* */ +8192; +var TransitionLane8 = +/* */ +16384; +var TransitionLane9 = +/* */ +32768; +var TransitionLane10 = +/* */ +65536; +var TransitionLane11 = +/* */ +131072; +var TransitionLane12 = +/* */ +262144; +var TransitionLane13 = +/* */ +524288; +var TransitionLane14 = +/* */ +1048576; +var TransitionLane15 = +/* */ +2097152; +var RetryLanes = +/* */ +62914560; +var RetryLane1 = +/* */ +4194304; +var RetryLane2 = +/* */ +8388608; +var RetryLane3 = +/* */ +16777216; +var RetryLane4 = +/* */ +33554432; +var SomeRetryLane = RetryLane1; +var SelectiveHydrationLane = +/* */ +67108864; +var NonIdleLanes = +/* */ +134217727; +var IdleHydrationLane = +/* */ +134217728; +var IdleLane = +/* */ +268435456; +var OffscreenLane = +/* */ +536870912; +var DeferredLane = +/* */ +1073741824; // Any lane that might schedule an update. This is used to detect infinite +// update loops, so it doesn't include hydration lanes or retries. + +var UpdateLanes = SyncLane | InputContinuousLane | DefaultLane | TransitionLanes; // This function is used for the experimental timeline (react-devtools-timeline) +// It should be kept in sync with the Lanes values above. + +function getLabelForLane(lane) { + { + if (lane & SyncHydrationLane) { + return 'SyncHydrationLane'; + } + + if (lane & SyncLane) { + return 'Sync'; + } + + if (lane & InputContinuousHydrationLane) { + return 'InputContinuousHydration'; + } + + if (lane & InputContinuousLane) { + return 'InputContinuous'; + } + + if (lane & DefaultHydrationLane) { + return 'DefaultHydration'; + } + + if (lane & DefaultLane) { + return 'Default'; + } + + if (lane & TransitionHydrationLane) { + return 'TransitionHydration'; + } + + if (lane & TransitionLanes) { + return 'Transition'; + } + + if (lane & RetryLanes) { + return 'Retry'; + } + + if (lane & SelectiveHydrationLane) { + return 'SelectiveHydration'; + } + + if (lane & IdleHydrationLane) { + return 'IdleHydration'; + } + + if (lane & IdleLane) { + return 'Idle'; + } + + if (lane & OffscreenLane) { + return 'Offscreen'; + } + + if (lane & DeferredLane) { + return 'Deferred'; + } + } +} +var NoTimestamp = -1; +var nextTransitionLane = TransitionLane1; +var nextRetryLane = RetryLane1; + +function getHighestPriorityLanes(lanes) { + if (enableUnifiedSyncLane) { + var pendingSyncLanes = lanes & SyncUpdateLanes; + + if (pendingSyncLanes !== 0) { + return pendingSyncLanes; + } + } + + switch (getHighestPriorityLane(lanes)) { + case SyncHydrationLane: + return SyncHydrationLane; + + case SyncLane: + return SyncLane; + + case InputContinuousHydrationLane: + return InputContinuousHydrationLane; + + case InputContinuousLane: + return InputContinuousLane; + + case DefaultHydrationLane: + return DefaultHydrationLane; + + case DefaultLane: + return DefaultLane; + + case TransitionHydrationLane: + return TransitionHydrationLane; + + case TransitionLane1: + case TransitionLane2: + case TransitionLane3: + case TransitionLane4: + case TransitionLane5: + case TransitionLane6: + case TransitionLane7: + case TransitionLane8: + case TransitionLane9: + case TransitionLane10: + case TransitionLane11: + case TransitionLane12: + case TransitionLane13: + case TransitionLane14: + case TransitionLane15: + return lanes & TransitionLanes; + + case RetryLane1: + case RetryLane2: + case RetryLane3: + case RetryLane4: + return lanes & RetryLanes; + + case SelectiveHydrationLane: + return SelectiveHydrationLane; + + case IdleHydrationLane: + return IdleHydrationLane; + + case IdleLane: + return IdleLane; + + case OffscreenLane: + return OffscreenLane; + + case DeferredLane: + // This shouldn't be reachable because deferred work is always entangled + // with something else. + return NoLanes; + + default: + { + error('Should have found matching lanes. This is a bug in React.'); + } // This shouldn't be reachable, but as a fallback, return the entire bitmask. + + + return lanes; + } +} + +function getNextLanes(root, wipLanes) { + // Early bailout if there's no pending work left. + var pendingLanes = root.pendingLanes; + + if (pendingLanes === NoLanes) { + return NoLanes; + } + + var nextLanes = NoLanes; + var suspendedLanes = root.suspendedLanes; + var pingedLanes = root.pingedLanes; // Do not work on any idle work until all the non-idle work has finished, + // even if the work is suspended. + + var nonIdlePendingLanes = pendingLanes & NonIdleLanes; + + if (nonIdlePendingLanes !== NoLanes) { + var nonIdleUnblockedLanes = nonIdlePendingLanes & ~suspendedLanes; + + if (nonIdleUnblockedLanes !== NoLanes) { + nextLanes = getHighestPriorityLanes(nonIdleUnblockedLanes); + } else { + var nonIdlePingedLanes = nonIdlePendingLanes & pingedLanes; + + if (nonIdlePingedLanes !== NoLanes) { + nextLanes = getHighestPriorityLanes(nonIdlePingedLanes); + } + } + } else { + // The only remaining work is Idle. + var unblockedLanes = pendingLanes & ~suspendedLanes; + + if (unblockedLanes !== NoLanes) { + nextLanes = getHighestPriorityLanes(unblockedLanes); + } else { + if (pingedLanes !== NoLanes) { + nextLanes = getHighestPriorityLanes(pingedLanes); + } + } + } + + if (nextLanes === NoLanes) { + // This should only be reachable if we're suspended + // TODO: Consider warning in this path if a fallback timer is not scheduled. + return NoLanes; + } // If we're already in the middle of a render, switching lanes will interrupt + // it and we'll lose our progress. We should only do this if the new lanes are + // higher priority. + + + if (wipLanes !== NoLanes && wipLanes !== nextLanes && // If we already suspended with a delay, then interrupting is fine. Don't + // bother waiting until the root is complete. + (wipLanes & suspendedLanes) === NoLanes) { + var nextLane = getHighestPriorityLane(nextLanes); + var wipLane = getHighestPriorityLane(wipLanes); + + if ( // Tests whether the next lane is equal or lower priority than the wip + // one. This works because the bits decrease in priority as you go left. + nextLane >= wipLane || // Default priority updates should not interrupt transition updates. The + // only difference between default updates and transition updates is that + // default updates do not support refresh transitions. + nextLane === DefaultLane && (wipLane & TransitionLanes) !== NoLanes) { + // Keep working on the existing in-progress tree. Do not interrupt. + return wipLanes; + } + } + + return nextLanes; +} +function getEntangledLanes(root, renderLanes) { + var entangledLanes = renderLanes; + + if ((entangledLanes & InputContinuousLane) !== NoLanes) { + // When updates are sync by default, we entangle continuous priority updates + // and default updates, so they render in the same batch. The only reason + // they use separate lanes is because continuous updates should interrupt + // transitions, but default updates should not. + entangledLanes |= entangledLanes & DefaultLane; + } // Check for entangled lanes and add them to the batch. + // + // A lane is said to be entangled with another when it's not allowed to render + // in a batch that does not also include the other lane. Typically we do this + // when multiple updates have the same source, and we only want to respond to + // the most recent event from that source. + // + // Note that we apply entanglements *after* checking for partial work above. + // This means that if a lane is entangled during an interleaved event while + // it's already rendering, we won't interrupt it. This is intentional, since + // entanglement is usually "best effort": we'll try our best to render the + // lanes in the same batch, but it's not worth throwing out partially + // completed work in order to do it. + // TODO: Reconsider this. The counter-argument is that the partial work + // represents an intermediate state, which we don't want to show to the user. + // And by spending extra time finishing it, we're increasing the amount of + // time it takes to show the final state, which is what they are actually + // waiting for. + // + // For those exceptions where entanglement is semantically important, + // we should ensure that there is no partial work at the + // time we apply the entanglement. + + + var allEntangledLanes = root.entangledLanes; + + if (allEntangledLanes !== NoLanes) { + var entanglements = root.entanglements; + var lanes = entangledLanes & allEntangledLanes; + + while (lanes > 0) { + var index = pickArbitraryLaneIndex(lanes); + var lane = 1 << index; + entangledLanes |= entanglements[index]; + lanes &= ~lane; + } + } + + return entangledLanes; +} + +function computeExpirationTime(lane, currentTime) { + switch (lane) { + case SyncHydrationLane: + case SyncLane: + case InputContinuousHydrationLane: + case InputContinuousLane: + // User interactions should expire slightly more quickly. + // + // NOTE: This is set to the corresponding constant as in Scheduler.js. + // When we made it larger, a product metric in www regressed, suggesting + // there's a user interaction that's being starved by a series of + // synchronous updates. If that theory is correct, the proper solution is + // to fix the starvation. However, this scenario supports the idea that + // expiration times are an important safeguard when starvation + // does happen. + return currentTime + syncLaneExpirationMs; + + case DefaultHydrationLane: + case DefaultLane: + case TransitionHydrationLane: + case TransitionLane1: + case TransitionLane2: + case TransitionLane3: + case TransitionLane4: + case TransitionLane5: + case TransitionLane6: + case TransitionLane7: + case TransitionLane8: + case TransitionLane9: + case TransitionLane10: + case TransitionLane11: + case TransitionLane12: + case TransitionLane13: + case TransitionLane14: + case TransitionLane15: + return currentTime + transitionLaneExpirationMs; + + case RetryLane1: + case RetryLane2: + case RetryLane3: + case RetryLane4: + // TODO: Retries should be allowed to expire if they are CPU bound for + // too long, but when I made this change it caused a spike in browser + // crashes. There must be some other underlying bug; not super urgent but + // ideally should figure out why and fix it. Unfortunately we don't have + // a repro for the crashes, only detected via production metrics. + return NoTimestamp; + + case SelectiveHydrationLane: + case IdleHydrationLane: + case IdleLane: + case OffscreenLane: + case DeferredLane: + // Anything idle priority or lower should never expire. + return NoTimestamp; + + default: + { + error('Should have found matching lanes. This is a bug in React.'); + } + + return NoTimestamp; + } +} + +function markStarvedLanesAsExpired(root, currentTime) { + // TODO: This gets called every time we yield. We can optimize by storing + // the earliest expiration time on the root. Then use that to quickly bail out + // of this function. + var pendingLanes = root.pendingLanes; + var suspendedLanes = root.suspendedLanes; + var pingedLanes = root.pingedLanes; + var expirationTimes = root.expirationTimes; // Iterate through the pending lanes and check if we've reached their + // expiration time. If so, we'll assume the update is being starved and mark + // it as expired to force it to finish. + // TODO: We should be able to replace this with upgradePendingLanesToSync + // + // We exclude retry lanes because those must always be time sliced, in order + // to unwrap uncached promises. + // TODO: Write a test for this + + var lanes = pendingLanes & ~RetryLanes; + + while (lanes > 0) { + var index = pickArbitraryLaneIndex(lanes); + var lane = 1 << index; + var expirationTime = expirationTimes[index]; + + if (expirationTime === NoTimestamp) { + // Found a pending lane with no expiration time. If it's not suspended, or + // if it's pinged, assume it's CPU-bound. Compute a new expiration time + // using the current time. + if ((lane & suspendedLanes) === NoLanes || (lane & pingedLanes) !== NoLanes) { + // Assumes timestamps are monotonically increasing. + expirationTimes[index] = computeExpirationTime(lane, currentTime); + } + } else if (expirationTime <= currentTime) { + // This lane expired + root.expiredLanes |= lane; + } + + lanes &= ~lane; + } +} // This returns the highest priority pending lanes regardless of whether they +function getLanesToRetrySynchronouslyOnError(root, originallyAttemptedLanes) { + if (root.errorRecoveryDisabledLanes & originallyAttemptedLanes) { + // The error recovery mechanism is disabled until these lanes are cleared. + return NoLanes; + } + + var everythingButOffscreen = root.pendingLanes & ~OffscreenLane; + + if (everythingButOffscreen !== NoLanes) { + return everythingButOffscreen; + } + + if (everythingButOffscreen & OffscreenLane) { + return OffscreenLane; + } + + return NoLanes; +} +function includesSyncLane(lanes) { + return (lanes & (SyncLane | SyncHydrationLane)) !== NoLanes; +} +function includesNonIdleWork(lanes) { + return (lanes & NonIdleLanes) !== NoLanes; +} +function includesOnlyRetries(lanes) { + return (lanes & RetryLanes) === lanes; +} +function includesOnlyNonUrgentLanes(lanes) { + // TODO: Should hydration lanes be included here? This function is only + // used in `updateDeferredValueImpl`. + var UrgentLanes = SyncLane | InputContinuousLane | DefaultLane; + return (lanes & UrgentLanes) === NoLanes; +} +function includesOnlyTransitions(lanes) { + return (lanes & TransitionLanes) === lanes; +} +function includesBlockingLane(root, lanes) { + + var SyncDefaultLanes = InputContinuousHydrationLane | InputContinuousLane | DefaultHydrationLane | DefaultLane; + return (lanes & SyncDefaultLanes) !== NoLanes; +} +function includesExpiredLane(root, lanes) { + // This is a separate check from includesBlockingLane because a lane can + // expire after a render has already started. + return (lanes & root.expiredLanes) !== NoLanes; +} +function isTransitionLane(lane) { + return (lane & TransitionLanes) !== NoLanes; +} +function claimNextTransitionLane() { + // Cycle through the lanes, assigning each new transition to the next lane. + // In most cases, this means every transition gets its own lane, until we + // run out of lanes and cycle back to the beginning. + var lane = nextTransitionLane; + nextTransitionLane <<= 1; + + if ((nextTransitionLane & TransitionLanes) === NoLanes) { + nextTransitionLane = TransitionLane1; + } + + return lane; +} +function claimNextRetryLane() { + var lane = nextRetryLane; + nextRetryLane <<= 1; + + if ((nextRetryLane & RetryLanes) === NoLanes) { + nextRetryLane = RetryLane1; + } + + return lane; +} +function getHighestPriorityLane(lanes) { + return lanes & -lanes; +} +function pickArbitraryLane(lanes) { + // This wrapper function gets inlined. Only exists so to communicate that it + // doesn't matter which bit is selected; you can pick any bit without + // affecting the algorithms where its used. Here I'm using + // getHighestPriorityLane because it requires the fewest operations. + return getHighestPriorityLane(lanes); +} + +function pickArbitraryLaneIndex(lanes) { + return 31 - clz32(lanes); +} + +function laneToIndex(lane) { + return pickArbitraryLaneIndex(lane); +} + +function includesSomeLane(a, b) { + return (a & b) !== NoLanes; +} +function isSubsetOfLanes(set, subset) { + return (set & subset) === subset; +} +function mergeLanes(a, b) { + return a | b; +} +function removeLanes(set, subset) { + return set & ~subset; +} +function intersectLanes(a, b) { + return a & b; +} // Seems redundant, but it changes the type from a single lane (used for +// updates) to a group of lanes (used for flushing work). + +function laneToLanes(lane) { + return lane; +} +function createLaneMap(initial) { + // Intentionally pushing one by one. + // https://v8.dev/blog/elements-kinds#avoid-creating-holes + var laneMap = []; + + for (var i = 0; i < TotalLanes; i++) { + laneMap.push(initial); + } + + return laneMap; +} +function markRootUpdated$1(root, updateLane) { + root.pendingLanes |= updateLane; // If there are any suspended transitions, it's possible this new update + // could unblock them. Clear the suspended lanes so that we can try rendering + // them again. + // + // TODO: We really only need to unsuspend only lanes that are in the + // `subtreeLanes` of the updated fiber, or the update lanes of the return + // path. This would exclude suspended updates in an unrelated sibling tree, + // since there's no way for this update to unblock it. + // + // We don't do this if the incoming update is idle, because we never process + // idle updates until after all the regular updates have finished; there's no + // way it could unblock a transition. + + if (updateLane !== IdleLane) { + root.suspendedLanes = NoLanes; + root.pingedLanes = NoLanes; + } +} +function markRootSuspended$1(root, suspendedLanes, spawnedLane) { + root.suspendedLanes |= suspendedLanes; + root.pingedLanes &= ~suspendedLanes; // The suspended lanes are no longer CPU-bound. Clear their expiration times. + + var expirationTimes = root.expirationTimes; + var lanes = suspendedLanes; + + while (lanes > 0) { + var index = pickArbitraryLaneIndex(lanes); + var lane = 1 << index; + expirationTimes[index] = NoTimestamp; + lanes &= ~lane; + } + + if (spawnedLane !== NoLane) { + markSpawnedDeferredLane(root, spawnedLane, suspendedLanes); + } +} +function markRootPinged$1(root, pingedLanes) { + root.pingedLanes |= root.suspendedLanes & pingedLanes; +} +function markRootFinished(root, remainingLanes, spawnedLane) { + var noLongerPendingLanes = root.pendingLanes & ~remainingLanes; + root.pendingLanes = remainingLanes; // Let's try everything again + + root.suspendedLanes = NoLanes; + root.pingedLanes = NoLanes; + root.expiredLanes &= remainingLanes; + root.entangledLanes &= remainingLanes; + root.errorRecoveryDisabledLanes &= remainingLanes; + root.shellSuspendCounter = 0; + var entanglements = root.entanglements; + var expirationTimes = root.expirationTimes; + var hiddenUpdates = root.hiddenUpdates; // Clear the lanes that no longer have pending work + + var lanes = noLongerPendingLanes; + + while (lanes > 0) { + var index = pickArbitraryLaneIndex(lanes); + var lane = 1 << index; + entanglements[index] = NoLanes; + expirationTimes[index] = NoTimestamp; + var hiddenUpdatesForLane = hiddenUpdates[index]; + + if (hiddenUpdatesForLane !== null) { + hiddenUpdates[index] = null; // "Hidden" updates are updates that were made to a hidden component. They + // have special logic associated with them because they may be entangled + // with updates that occur outside that tree. But once the outer tree + // commits, they behave like regular updates. + + for (var i = 0; i < hiddenUpdatesForLane.length; i++) { + var update = hiddenUpdatesForLane[i]; + + if (update !== null) { + update.lane &= ~OffscreenLane; + } + } + } + + lanes &= ~lane; + } + + if (spawnedLane !== NoLane) { + markSpawnedDeferredLane(root, spawnedLane, // This render finished successfully without suspending, so we don't need + // to entangle the spawned task with the parent task. + NoLanes); + } +} + +function markSpawnedDeferredLane(root, spawnedLane, entangledLanes) { + // This render spawned a deferred task. Mark it as pending. + root.pendingLanes |= spawnedLane; + root.suspendedLanes &= ~spawnedLane; // Entangle the spawned lane with the DeferredLane bit so that we know it + // was the result of another render. This lets us avoid a useDeferredValue + // waterfall — only the first level will defer. + + var spawnedLaneIndex = laneToIndex(spawnedLane); + root.entangledLanes |= spawnedLane; + root.entanglements[spawnedLaneIndex] |= DeferredLane | // If the parent render task suspended, we must also entangle those lanes + // with the spawned task, so that the deferred task includes all the same + // updates that the parent task did. We can exclude any lane that is not + // used for updates (e.g. Offscreen). + entangledLanes & UpdateLanes; +} + +function markRootEntangled(root, entangledLanes) { + // In addition to entangling each of the given lanes with each other, we also + // have to consider _transitive_ entanglements. For each lane that is already + // entangled with *any* of the given lanes, that lane is now transitively + // entangled with *all* the given lanes. + // + // Translated: If C is entangled with A, then entangling A with B also + // entangles C with B. + // + // If this is hard to grasp, it might help to intentionally break this + // function and look at the tests that fail in ReactTransition-test.js. Try + // commenting out one of the conditions below. + var rootEntangledLanes = root.entangledLanes |= entangledLanes; + var entanglements = root.entanglements; + var lanes = rootEntangledLanes; + + while (lanes) { + var index = pickArbitraryLaneIndex(lanes); + var lane = 1 << index; + + if ( // Is this one of the newly entangled lanes? + lane & entangledLanes | // Is this lane transitively entangled with the newly entangled lanes? + entanglements[index] & entangledLanes) { + entanglements[index] |= entangledLanes; + } + + lanes &= ~lane; + } +} +function upgradePendingLaneToSync(root, lane) { + // Since we're upgrading the priority of the given lane, there is now pending + // sync work. + root.pendingLanes |= SyncLane; // Entangle the sync lane with the lane we're upgrading. This means SyncLane + // will not be allowed to finish without also finishing the given lane. + + root.entangledLanes |= SyncLane; + root.entanglements[SyncLaneIndex] |= lane; +} +function markHiddenUpdate(root, update, lane) { + var index = laneToIndex(lane); + var hiddenUpdates = root.hiddenUpdates; + var hiddenUpdatesForLane = hiddenUpdates[index]; + + if (hiddenUpdatesForLane === null) { + hiddenUpdates[index] = [update]; + } else { + hiddenUpdatesForLane.push(update); + } + + update.lane = lane | OffscreenLane; +} +function getBumpedLaneForHydration(root, renderLanes) { + var renderLane = getHighestPriorityLane(renderLanes); + var lane; + + if (enableUnifiedSyncLane && (renderLane & SyncUpdateLanes) !== NoLane) { + lane = SyncHydrationLane; + } else { + switch (renderLane) { + case SyncLane: + lane = SyncHydrationLane; + break; + + case InputContinuousLane: + lane = InputContinuousHydrationLane; + break; + + case DefaultLane: + lane = DefaultHydrationLane; + break; + + case TransitionLane1: + case TransitionLane2: + case TransitionLane3: + case TransitionLane4: + case TransitionLane5: + case TransitionLane6: + case TransitionLane7: + case TransitionLane8: + case TransitionLane9: + case TransitionLane10: + case TransitionLane11: + case TransitionLane12: + case TransitionLane13: + case TransitionLane14: + case TransitionLane15: + case RetryLane1: + case RetryLane2: + case RetryLane3: + case RetryLane4: + lane = TransitionHydrationLane; + break; + + case IdleLane: + lane = IdleHydrationLane; + break; + + default: + // Everything else is already either a hydration lane, or shouldn't + // be retried at a hydration lane. + lane = NoLane; + break; + } + } // Check if the lane we chose is suspended. If so, that indicates that we + // already attempted and failed to hydrate at that level. Also check if we're + // already rendering that lane, which is rare but could happen. + + + if ((lane & (root.suspendedLanes | renderLanes)) !== NoLane) { + // Give up trying to hydrate and fall back to client render. + return NoLane; + } + + return lane; +} +function addFiberToLanesMap(root, fiber, lanes) { + + if (!isDevToolsPresent) { + return; + } + + var pendingUpdatersLaneMap = root.pendingUpdatersLaneMap; + + while (lanes > 0) { + var index = laneToIndex(lanes); + var lane = 1 << index; + var updaters = pendingUpdatersLaneMap[index]; + updaters.add(fiber); + lanes &= ~lane; + } +} +function movePendingFibersToMemoized(root, lanes) { + + if (!isDevToolsPresent) { + return; + } + + var pendingUpdatersLaneMap = root.pendingUpdatersLaneMap; + var memoizedUpdaters = root.memoizedUpdaters; + + while (lanes > 0) { + var index = laneToIndex(lanes); + var lane = 1 << index; + var updaters = pendingUpdatersLaneMap[index]; + + if (updaters.size > 0) { + updaters.forEach(function (fiber) { + var alternate = fiber.alternate; + + if (alternate === null || !memoizedUpdaters.has(alternate)) { + memoizedUpdaters.add(fiber); + } + }); + updaters.clear(); + } + + lanes &= ~lane; + } +} +function getTransitionsForLanes(root, lanes) { + { + return null; + } +} + +var NoEventPriority = NoLane; +var DiscreteEventPriority = SyncLane; +var ContinuousEventPriority = InputContinuousLane; +var DefaultEventPriority = DefaultLane; +var IdleEventPriority = IdleLane; +function higherEventPriority(a, b) { + return a !== 0 && a < b ? a : b; +} +function lowerEventPriority(a, b) { + return a === 0 || a > b ? a : b; +} +function isHigherEventPriority(a, b) { + return a !== 0 && a < b; +} +function eventPriorityToLane(updatePriority) { + return updatePriority; +} +function lanesToEventPriority(lanes) { + var lane = getHighestPriorityLane(lanes); + + if (!isHigherEventPriority(DiscreteEventPriority, lane)) { + return DiscreteEventPriority; + } + + if (!isHigherEventPriority(ContinuousEventPriority, lane)) { + return ContinuousEventPriority; + } + + if (includesNonIdleWork(lane)) { + return DefaultEventPriority; + } + + return IdleEventPriority; +} + +// Renderers that don't support mutation +// can re-export everything from this module. +function shim$2() { + 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$2; + +// Renderers that don't support hydration +// can re-export everything from this module. +function shim$1() { + 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 supportsHydration = false; +var isSuspenseInstancePending = shim$1; +var isSuspenseInstanceFallback = shim$1; +var getSuspenseInstanceFallbackErrorDetails = shim$1; +var registerSuspenseInstanceRetry = shim$1; + +// Renderers that don't support hydration +// can re-export everything from this module. +function shim() { + throw new Error('The current renderer does not support Resources. ' + 'This error is likely caused by a bug in React. ' + 'Please file an issue.'); +} // Resources (when unsupported) +var suspendResource = shim; + +var _nativeFabricUIManage = nativeFabricUIManager, + createNode = _nativeFabricUIManage.createNode, + 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 nextReactTag = 2; // TODO: Remove this conditional once all changes have propagated. + +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); + + { + for (var key in viewConfig.validAttributes) { + if (props.hasOwnProperty(key)) { + ReactNativePrivateInterface.deepFreezeAndThrowOnMutationInDev(props[key]); + } + } + } + + 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 createTextInstance(text, rootContainerInstance, hostContext, internalInstanceHandle) { + { + if (!hostContext.isInAParentText) { + error('Text strings must be rendered within a component.'); + } + } + + 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. + + 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] + + + if (instance._nativeTag != null) { + // $FlowExpectedError[incompatible-return] + return instance; + } + + return null; +} + +function getPublicTextInstance(textInstance, internalInstanceHandle) { + if (textInstance.publicInstance == null) { + textInstance.publicInstance = ReactNativePrivateInterface.createPublicTextInstance(internalInstanceHandle); + } + + return textInstance.publicInstance; +} + +function getPublicInstanceFromInternalInstanceHandle(internalInstanceHandle) { + var instance = internalInstanceHandle.stateNode; // React resets all the fields in the fiber when the component is unmounted + // to prevent memory leaks. + + if (instance == null) { + return null; + } + + if (internalInstanceHandle.tag === HostText) { + var textInstance = instance; + return getPublicTextInstance(textInstance, internalInstanceHandle); + } + + var elementInstance = internalInstanceHandle.stateNode; + return getPublicInstance(elementInstance); +} +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 currentUpdatePriority = NoEventPriority; +function setCurrentUpdatePriority(newPriority) { + currentUpdatePriority = newPriority; +} +function getCurrentUpdatePriority() { + return currentUpdatePriority; +} +function resolveUpdatePriority() { + if (currentUpdatePriority !== NoEventPriority) { + return currentUpdatePriority; + } + + var currentEventPriority = fabricGetCurrentEventPriority ? fabricGetCurrentEventPriority() : null; + + if (currentEventPriority != null) { + switch (currentEventPriority) { + case FabricDiscretePriority: + return DiscreteEventPriority; + + case FabricDefaultPriority: + default: + return DefaultEventPriority; + } + } + + return DefaultEventPriority; +} +function shouldAttemptEagerTransition() { + return false; +} // The Fabric renderer is secondary to the existing React Native renderer. + +var warnsIfNotActing = false; +var scheduleTimeout = setTimeout; +var cancelTimeout = clearTimeout; +var noTimeout = -1; // ------------------- +function cloneInstance(instance, type, oldProps, newProps, keepChildren, newChildSet) { + 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; + var node = instance.node; + var clone; + + if (keepChildren) { + if (updatePayload !== null) { + clone = cloneNodeWithNewProps(node, updatePayload); + } else { + // No changes + return instance; + } + } else { + // If passChildrenWhenCloningPersistedNodes is enabled, children will be non-null + if (newChildSet != null) { + if (updatePayload !== null) { + clone = cloneNodeWithNewChildrenAndProps(node, newChildSet, updatePayload); + } else { + clone = cloneNodeWithNewChildren(node, newChildSet); + } + } else { + if (updatePayload !== null) { + clone = cloneNodeWithNewChildrenAndProps(node, updatePayload); + } else { + clone = cloneNodeWithNewChildren(node); + } + } + } + + return { + node: clone, + canonical: instance.canonical + }; +} +function cloneHiddenInstance(instance, type, props) { + 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) { + throw new Error('Not yet implemented.'); +} +function createContainerChildSet() { + if (passChildrenWhenCloningPersistedNodes) { + return []; + } else { + return createChildNodeSet(); + } +} +function appendChildToContainerChildSet(childSet, child) { + if (passChildrenWhenCloningPersistedNodes) { + childSet.push(child.node); + } else { + appendChildNodeToSet(childSet, child.node); + } +} +function finalizeContainerChildren(container, newChildren) { + completeRoot(container, newChildren); +} +function replaceContainerChildren(container, newChildren) {// Noop - children will be replaced in finalizeContainerChildren +} +function preloadInstance(type, props) { + return true; +} +function waitForCommitToBeReady() { + return null; +} +var NotPendingTransition = null; +// Microtasks +// ------------------- + +var supportsMicrotasks = typeof RN$enableMicrotasksInReact !== 'undefined' && !!RN$enableMicrotasksInReact; +var scheduleMicrotask = typeof queueMicrotask === 'function' ? queueMicrotask : scheduleTimeout; + +// This is ok in DOM because they types are interchangeable, but in React Native +// they aren't. + +function getInstanceFromNode(node) { + var instance = node; // In React Native, node is never a text instance + + 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 getNodeFromInstance(fiber) { + var publicInstance = getPublicInstance(fiber.stateNode); + + if (publicInstance == null) { + throw new Error('Could not find host instance from fiber'); + } + + return publicInstance; +} + +function getFiberCurrentPropsFromNode(instance) { + return instance.canonical.currentProps; +} + +var ReactFabricGlobalResponderHandler = { + onChange: function (from, to, blockNativeResponder) { + if (from && from.stateNode) { + // equivalent to clearJSResponder + nativeFabricUIManager.setIsJSResponder(from.stateNode.node, false, blockNativeResponder || false); + } + + if (to && to.stateNode) { + // equivalent to setJSResponder + nativeFabricUIManager.setIsJSResponder(to.stateNode.node, true, blockNativeResponder || false); + } + } +}; + +setComponentTree(getFiberCurrentPropsFromNode, getInstanceFromNode, getNodeFromInstance); +ResponderEventPlugin.injection.injectGlobalResponderHandler(ReactFabricGlobalResponderHandler); + +var LegacyRoot = 0; +var ConcurrentRoot = 1; + +/** + * `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; +} + +// 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'); // TODO: Delete with enableRenderableContext + +var REACT_CONSUMER_TYPE = Symbol.for('react.consumer'); +var REACT_CONTEXT_TYPE = Symbol.for('react.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_TRACING_MARKER_TYPE = Symbol.for('react.tracing_marker'); +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 maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]; + + if (typeof maybeIterator === 'function') { + return maybeIterator; + } + + return null; +} + +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'; +} + +var REACT_CLIENT_REFERENCE = Symbol.for('react.client.reference'); // 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 (typeof type === 'function') { + if (type.$$typeof === REACT_CLIENT_REFERENCE) { + // TODO: Create a convention for naming client references with debug info. + return null; + } + + 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'; + + case REACT_STRICT_MODE_TYPE: + return 'StrictMode'; + + case REACT_SUSPENSE_TYPE: + return 'Suspense'; - error("React instrumentation encountered an error: %s", err); - } - } - } - } - } - function onPostCommitRoot(root) { - if ( - injectedHook && - typeof injectedHook.onPostCommitFiberRoot === "function" - ) { - try { - injectedHook.onPostCommitFiberRoot(rendererID, root); - } catch (err) { - { - if (!hasLoggedError) { - hasLoggedError = true; + case REACT_SUSPENSE_LIST_TYPE: + return 'SuspenseList'; - 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; + } - error("React instrumentation encountered an error: %s", err); - } - } - } + if (typeof type === 'object') { + { + if (typeof type.tag === 'number') { + error('Received an unexpected object in getComponentNameFromType(). ' + 'This is likely a bug in React. Please file an issue.'); } } - function setIsStrictModeForDevtools(newIsStrictMode) { - if (consoleManagedByDevToolsDuringStrictMode) { - if (typeof log$1 === "function") { - // We're in a test because Scheduler.log only exists - // in SchedulerMock. To reduce the noise in strict mode tests, - // suppress warnings and disable scheduler yielding during the double render - unstable_setDisableYieldValue(newIsStrictMode); - setSuppressWarning(newIsStrictMode); + + switch (type.$$typeof) { + case REACT_PROVIDER_TYPE: + if (enableRenderableContext) { + return null; + } else { + var provider = type; + return getContextName$1(provider._context) + '.Provider'; } - if (injectedHook && typeof injectedHook.setStrictMode === "function") { - try { - injectedHook.setStrictMode(rendererID, newIsStrictMode); - } catch (err) { - { - if (!hasLoggedError) { - hasLoggedError = true; + case REACT_CONTEXT_TYPE: + var context = type; - error("React instrumentation encountered an error: %s", err); - } - } - } + if (enableRenderableContext) { + return getContextName$1(context) + '.Provider'; + } else { + return getContextName$1(context) + '.Consumer'; } - } else { - if (newIsStrictMode) { - disableLogs(); + + case REACT_CONSUMER_TYPE: + if (enableRenderableContext) { + var consumer = type; + return getContextName$1(consumer._context) + '.Consumer'; } else { - reenableLogs(); + return null; } - } - } // Profiler API hooks - function injectProfilingHooks(profilingHooks) { - injectedProfilingHooks = profilingHooks; - } + case REACT_FORWARD_REF_TYPE: + return getWrappedName$1(type, type.render, 'ForwardRef'); - function getLaneLabelMap() { - { - var map = new Map(); - var lane = 1; + case REACT_MEMO_TYPE: + var outerName = type.displayName || null; - for (var index = 0; index < TotalLanes; index++) { - var label = getLabelForLane(lane); - map.set(lane, label); - lane *= 2; + if (outerName !== null) { + return outerName; } - return map; - } - } + return getComponentNameFromType(type.type) || 'Memo'; - function markCommitStarted(lanes) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markCommitStarted === "function" - ) { - injectedProfilingHooks.markCommitStarted(lanes); - } - } - } - function markCommitStopped() { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markCommitStopped === "function" - ) { - injectedProfilingHooks.markCommitStopped(); - } - } - } - function markComponentRenderStarted(fiber) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentRenderStarted === - "function" - ) { - injectedProfilingHooks.markComponentRenderStarted(fiber); - } - } - } - function markComponentRenderStopped() { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentRenderStopped === - "function" - ) { - injectedProfilingHooks.markComponentRenderStopped(); - } - } - } - function markComponentPassiveEffectMountStarted(fiber) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentPassiveEffectMountStarted === - "function" - ) { - injectedProfilingHooks.markComponentPassiveEffectMountStarted(fiber); - } - } - } - function markComponentPassiveEffectMountStopped() { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentPassiveEffectMountStopped === - "function" - ) { - injectedProfilingHooks.markComponentPassiveEffectMountStopped(); - } - } - } - function markComponentPassiveEffectUnmountStarted(fiber) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentPassiveEffectUnmountStarted === - "function" - ) { - injectedProfilingHooks.markComponentPassiveEffectUnmountStarted( - fiber - ); - } - } - } - function markComponentPassiveEffectUnmountStopped() { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentPassiveEffectUnmountStopped === - "function" - ) { - injectedProfilingHooks.markComponentPassiveEffectUnmountStopped(); - } - } - } - 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(); + case REACT_LAZY_TYPE: + { + var lazyComponent = type; + var payload = lazyComponent._payload; + var init = lazyComponent._init; + + try { + return getComponentNameFromType(init(payload)); + } catch (x) { + return null; + } } - } } - function markRenderStarted(lanes) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markRenderStarted === "function" - ) { - injectedProfilingHooks.markRenderStarted(lanes); - } + } + + 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'; +} + +function getComponentNameFromOwner(owner) { + if (typeof owner.tag === 'number') { + return getComponentNameFromFiber(owner); + } + + if (typeof owner.name === 'string') { + return owner.name; + } + + return null; +} +function getComponentNameFromFiber(fiber) { + var tag = fiber.tag, + type = fiber.type; + + switch (tag) { + case CacheComponent: + return 'Cache'; + + case ContextConsumer: + if (enableRenderableContext) { + var consumer = type; + return getContextName(consumer._context) + '.Consumer'; + } else { + var context = type; + return getContextName(context) + '.Consumer'; } - } - function markRenderYielded() { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markRenderYielded === "function" - ) { - injectedProfilingHooks.markRenderYielded(); - } + + case ContextProvider: + if (enableRenderableContext) { + var _context = type; + return getContextName(_context) + '.Provider'; + } else { + var provider = type; + return getContextName(provider._context) + '.Provider'; } - } - function markRenderStopped() { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markRenderStopped === "function" - ) { - injectedProfilingHooks.markRenderStopped(); - } + + 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'; } - } - function markRenderScheduled(lane) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markRenderScheduled === "function" - ) { - injectedProfilingHooks.markRenderScheduled(lane); - } + + return 'Mode'; + + case OffscreenComponent: + return 'Offscreen'; + + case Profiler: + return 'Profiler'; + + case ScopeComponent: + return 'Scope'; + + case SuspenseComponent: + return 'Suspense'; + + case SuspenseListComponent: + return 'SuspenseList'; + + case TracingMarkerComponent: + return 'TracingMarker'; + // The display name for these tags come from the user-provided type: + + case IncompleteClassComponent: + case IncompleteFunctionComponent: + + // Fallthrough + + case ClassComponent: + case FunctionComponent: + case MemoComponent: + case SimpleMemoComponent: + if (typeof type === 'function') { + return type.displayName || type.name || null; } - } - function markForceUpdateScheduled(fiber, lane) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markForceUpdateScheduled === "function" - ) { - injectedProfilingHooks.markForceUpdateScheduled(fiber, lane); - } + + if (typeof type === 'string') { + return type; } - } - function markStateUpdateScheduled(fiber, lane) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markStateUpdateScheduled === "function" - ) { - injectedProfilingHooks.markStateUpdateScheduled(fiber, lane); - } - } - } - - 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 NoStrictPassiveEffectsMode = - /* */ - 64; - - // 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. - - var TotalLanes = 31; - var NoLanes = - /* */ - 0; - var NoLane = - /* */ - 0; - var SyncHydrationLane = - /* */ - 1; - var SyncLane = - /* */ - 2; - var SyncLaneIndex = 1; - var InputContinuousHydrationLane = - /* */ - 4; - var InputContinuousLane = - /* */ - 8; - var DefaultHydrationLane = - /* */ - 16; - var DefaultLane = - /* */ - 32; - var SyncUpdateLanes = enableUnifiedSyncLane - ? SyncLane | InputContinuousLane | DefaultLane - : SyncLane; - var TransitionHydrationLane = - /* */ - 64; - var TransitionLanes = - /* */ - 4194176; - var TransitionLane1 = - /* */ - 128; - var TransitionLane2 = - /* */ - 256; - var TransitionLane3 = - /* */ - 512; - var TransitionLane4 = - /* */ - 1024; - var TransitionLane5 = - /* */ - 2048; - var TransitionLane6 = - /* */ - 4096; - var TransitionLane7 = - /* */ - 8192; - var TransitionLane8 = - /* */ - 16384; - var TransitionLane9 = - /* */ - 32768; - var TransitionLane10 = - /* */ - 65536; - var TransitionLane11 = - /* */ - 131072; - var TransitionLane12 = - /* */ - 262144; - var TransitionLane13 = - /* */ - 524288; - var TransitionLane14 = - /* */ - 1048576; - var TransitionLane15 = - /* */ - 2097152; - var RetryLanes = - /* */ - 62914560; - var RetryLane1 = - /* */ - 4194304; - var RetryLane2 = - /* */ - 8388608; - var RetryLane3 = - /* */ - 16777216; - var RetryLane4 = - /* */ - 33554432; - var SomeRetryLane = RetryLane1; - var SelectiveHydrationLane = - /* */ - 67108864; - var NonIdleLanes = - /* */ - 134217727; - var IdleHydrationLane = - /* */ - 134217728; - var IdleLane = - /* */ - 268435456; - var OffscreenLane = - /* */ - 536870912; - var DeferredLane = - /* */ - 1073741824; // Any lane that might schedule an update. This is used to detect infinite - // update loops, so it doesn't include hydration lanes or retries. - - var UpdateLanes = - SyncLane | InputContinuousLane | DefaultLane | TransitionLanes; // This function is used for the experimental timeline (react-devtools-timeline) - // It should be kept in sync with the Lanes values above. - - function getLabelForLane(lane) { - { - if (lane & SyncHydrationLane) { - return "SyncHydrationLane"; - } - if (lane & SyncLane) { - return "Sync"; - } + break; - if (lane & InputContinuousHydrationLane) { - return "InputContinuousHydration"; - } + } - if (lane & InputContinuousLane) { - return "InputContinuous"; - } + return null; +} - if (lane & DefaultHydrationLane) { - return "DefaultHydration"; - } +function getNearestMountedFiber(fiber) { + var node = fiber; + var nearestMounted = fiber; - if (lane & DefaultLane) { - return "Default"; - } + 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; - if (lane & TransitionHydrationLane) { - return "TransitionHydration"; - } + do { + node = nextNode; - if (lane & TransitionLanes) { - return "Transition"; - } + 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 - if (lane & RetryLanes) { - return "Retry"; - } - if (lane & SelectiveHydrationLane) { - return "SelectiveHydration"; - } + nextNode = node.return; + } while (nextNode); + } else { + while (node.return) { + node = node.return; + } + } - if (lane & IdleHydrationLane) { - return "IdleHydration"; - } + 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. - if (lane & IdleLane) { - return "Idle"; - } - if (lane & OffscreenLane) { - return "Offscreen"; - } + return null; +} +function isFiberMounted(fiber) { + return getNearestMountedFiber(fiber) === fiber; +} +function isMounted(component) { + { + var owner = ReactSharedInternals.owner; - if (lane & DeferredLane) { - return "Deferred"; - } + if (owner !== null && owner.tag === ClassComponent) { + var ownerFiber = owner; + var instance = ownerFiber.stateNode; + + 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'); } + + instance._warnedAboutRefsInRender = true; } - var NoTimestamp = -1; - var nextTransitionLane = TransitionLane1; - var nextRetryLane = RetryLane1; + } - function getHighestPriorityLanes(lanes) { - if (enableUnifiedSyncLane) { - var pendingSyncLanes = lanes & SyncUpdateLanes; + var fiber = get(component); - if (pendingSyncLanes !== 0) { - return pendingSyncLanes; - } - } + if (!fiber) { + return false; + } + + return getNearestMountedFiber(fiber) === fiber; +} + +function assertIsMounted(fiber) { + if (getNearestMountedFiber(fiber) !== fiber) { + throw new Error('Unable to find node on an unmounted component.'); + } +} - switch (getHighestPriorityLane(lanes)) { - case SyncHydrationLane: - return SyncHydrationLane; +function findCurrentFiberUsingSlowPath(fiber) { + var alternate = fiber.alternate; - case SyncLane: - return SyncLane; + if (!alternate) { + // If there is no alternate, then we only need to check if it is mounted. + var nearestMounted = getNearestMountedFiber(fiber); - case InputContinuousHydrationLane: - return InputContinuousHydrationLane; + if (nearestMounted === null) { + throw new Error('Unable to find node on an unmounted component.'); + } - case InputContinuousLane: - return InputContinuousLane; + if (nearestMounted !== fiber) { + return null; + } - case DefaultHydrationLane: - return DefaultHydrationLane; + 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. - case DefaultLane: - return DefaultLane; - case TransitionHydrationLane: - return TransitionHydrationLane; + var a = fiber; + var b = alternate; - case TransitionLane1: - case TransitionLane2: - case TransitionLane3: - case TransitionLane4: - case TransitionLane5: - case TransitionLane6: - case TransitionLane7: - case TransitionLane8: - case TransitionLane9: - case TransitionLane10: - case TransitionLane11: - case TransitionLane12: - case TransitionLane13: - case TransitionLane14: - case TransitionLane15: - return lanes & TransitionLanes; + while (true) { + var parentA = a.return; - case RetryLane1: - case RetryLane2: - case RetryLane3: - case RetryLane4: - return lanes & RetryLanes; + if (parentA === null) { + // We're at the root. + break; + } - case SelectiveHydrationLane: - return SelectiveHydrationLane; + var parentB = parentA.alternate; - case IdleHydrationLane: - return IdleHydrationLane; + 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; - case IdleLane: - return IdleLane; + if (nextParent !== null) { + a = b = nextParent; + continue; + } // If there's no parent, we're at the root. - case OffscreenLane: - return OffscreenLane; - case DeferredLane: - // This shouldn't be reachable because deferred work is always entangled - // with something else. - return NoLanes; + 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. - default: - { - error("Should have found matching lanes. This is a bug in React."); - } // This shouldn't be reachable, but as a fallback, return the entire bitmask. - return lanes; - } - } + if (parentA.child === parentB.child) { + var child = parentA.child; - function getNextLanes(root, wipLanes) { - // Early bailout if there's no pending work left. - var pendingLanes = root.pendingLanes; + while (child) { + if (child === a) { + // We've determined that A is the current branch. + assertIsMounted(parentA); + return fiber; + } - if (pendingLanes === NoLanes) { - return NoLanes; - } + if (child === b) { + // We've determined that B is the current branch. + assertIsMounted(parentA); + return alternate; + } - var nextLanes = NoLanes; - var suspendedLanes = root.suspendedLanes; - var pingedLanes = root.pingedLanes; // Do not work on any idle work until all the non-idle work has finished, - // even if the work is suspended. + 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 nonIdlePendingLanes = pendingLanes & NonIdleLanes; - if (nonIdlePendingLanes !== NoLanes) { - var nonIdleUnblockedLanes = nonIdlePendingLanes & ~suspendedLanes; + throw new Error('Unable to find node on an unmounted component.'); + } - if (nonIdleUnblockedLanes !== NoLanes) { - nextLanes = getHighestPriorityLanes(nonIdleUnblockedLanes); - } else { - var nonIdlePingedLanes = nonIdlePendingLanes & pingedLanes; + 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 (nonIdlePingedLanes !== NoLanes) { - nextLanes = getHighestPriorityLanes(nonIdlePingedLanes); - } + while (_child) { + if (_child === a) { + didFindChild = true; + a = parentA; + b = parentB; + break; } - } else { - // The only remaining work is Idle. - var unblockedLanes = pendingLanes & ~suspendedLanes; - if (unblockedLanes !== NoLanes) { - nextLanes = getHighestPriorityLanes(unblockedLanes); - } else { - if (pingedLanes !== NoLanes) { - nextLanes = getHighestPriorityLanes(pingedLanes); - } + if (_child === b) { + didFindChild = true; + b = parentA; + a = parentB; + break; } + + _child = _child.sibling; } - if (nextLanes === NoLanes) { - // This should only be reachable if we're suspended - // TODO: Consider warning in this path if a fallback timer is not scheduled. - return NoLanes; - } // If we're already in the middle of a render, switching lanes will interrupt - // it and we'll lose our progress. We should only do this if the new lanes are - // higher priority. - - if ( - wipLanes !== NoLanes && - wipLanes !== nextLanes && // If we already suspended with a delay, then interrupting is fine. Don't - // bother waiting until the root is complete. - (wipLanes & suspendedLanes) === NoLanes - ) { - var nextLane = getHighestPriorityLane(nextLanes); - var wipLane = getHighestPriorityLane(wipLanes); - - if ( - // Tests whether the next lane is equal or lower priority than the wip - // one. This works because the bits decrease in priority as you go left. - nextLane >= wipLane || // Default priority updates should not interrupt transition updates. The - // only difference between default updates and transition updates is that - // default updates do not support refresh transitions. - (nextLane === DefaultLane && (wipLane & TransitionLanes) !== NoLanes) - ) { - // Keep working on the existing in-progress tree. Do not interrupt. - return wipLanes; - } - } - - return nextLanes; - } - function getEntangledLanes(root, renderLanes) { - var entangledLanes = renderLanes; - - if ((entangledLanes & InputContinuousLane) !== NoLanes) { - // When updates are sync by default, we entangle continuous priority updates - // and default updates, so they render in the same batch. The only reason - // they use separate lanes is because continuous updates should interrupt - // transitions, but default updates should not. - entangledLanes |= entangledLanes & DefaultLane; - } // Check for entangled lanes and add them to the batch. - // - // A lane is said to be entangled with another when it's not allowed to render - // in a batch that does not also include the other lane. Typically we do this - // when multiple updates have the same source, and we only want to respond to - // the most recent event from that source. - // - // Note that we apply entanglements *after* checking for partial work above. - // This means that if a lane is entangled during an interleaved event while - // it's already rendering, we won't interrupt it. This is intentional, since - // entanglement is usually "best effort": we'll try our best to render the - // lanes in the same batch, but it's not worth throwing out partially - // completed work in order to do it. - // TODO: Reconsider this. The counter-argument is that the partial work - // represents an intermediate state, which we don't want to show to the user. - // And by spending extra time finishing it, we're increasing the amount of - // time it takes to show the final state, which is what they are actually - // waiting for. - // - // For those exceptions where entanglement is semantically important, - // we should ensure that there is no partial work at the - // time we apply the entanglement. + if (!didFindChild) { + // Search parent B's child set + _child = parentB.child; - var allEntangledLanes = root.entangledLanes; + while (_child) { + if (_child === a) { + didFindChild = true; + a = parentB; + b = parentA; + break; + } + + if (_child === b) { + didFindChild = true; + b = parentB; + a = parentA; + break; + } - if (allEntangledLanes !== NoLanes) { - var entanglements = root.entanglements; - var lanes = entangledLanes & allEntangledLanes; + _child = _child.sibling; + } - while (lanes > 0) { - var index = pickArbitraryLaneIndex(lanes); - var lane = 1 << index; - entangledLanes |= entanglements[index]; - lanes &= ~lane; + 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.'); } } + } - return entangledLanes; + 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. - function computeExpirationTime(lane, currentTime) { - switch (lane) { - case SyncHydrationLane: - case SyncLane: - case InputContinuousHydrationLane: - case InputContinuousLane: - // User interactions should expire slightly more quickly. - // - // NOTE: This is set to the corresponding constant as in Scheduler.js. - // When we made it larger, a product metric in www regressed, suggesting - // there's a user interaction that's being starved by a series of - // synchronous updates. If that theory is correct, the proper solution is - // to fix the starvation. However, this scenario supports the idea that - // expiration times are an important safeguard when starvation - // does happen. - return currentTime + syncLaneExpirationMs; - - case DefaultHydrationLane: - case DefaultLane: - case TransitionHydrationLane: - case TransitionLane1: - case TransitionLane2: - case TransitionLane3: - case TransitionLane4: - case TransitionLane5: - case TransitionLane6: - case TransitionLane7: - case TransitionLane8: - case TransitionLane9: - case TransitionLane10: - case TransitionLane11: - case TransitionLane12: - case TransitionLane13: - case TransitionLane14: - case TransitionLane15: - return currentTime + transitionLaneExpirationMs; - - case RetryLane1: - case RetryLane2: - case RetryLane3: - case RetryLane4: - // TODO: Retries should be allowed to expire if they are CPU bound for - // too long, but when I made this change it caused a spike in browser - // crashes. There must be some other underlying bug; not super urgent but - // ideally should figure out why and fix it. Unfortunately we don't have - // a repro for the crashes, only detected via production metrics. - return NoTimestamp; - - case SelectiveHydrationLane: - case IdleHydrationLane: - case IdleLane: - case OffscreenLane: - case DeferredLane: - // Anything idle priority or lower should never expire. - return NoTimestamp; - - default: - { - error("Should have found matching lanes. This is a bug in React."); - } - return NoTimestamp; - } - } + if (a.tag !== HostRoot) { + throw new Error('Unable to find node on an unmounted component.'); + } - function markStarvedLanesAsExpired(root, currentTime) { - // TODO: This gets called every time we yield. We can optimize by storing - // the earliest expiration time on the root. Then use that to quickly bail out - // of this function. - var pendingLanes = root.pendingLanes; - var suspendedLanes = root.suspendedLanes; - var pingedLanes = root.pingedLanes; - var expirationTimes = root.expirationTimes; // Iterate through the pending lanes and check if we've reached their - // expiration time. If so, we'll assume the update is being starved and mark - // it as expired to force it to finish. - // TODO: We should be able to replace this with upgradePendingLanesToSync - // - // We exclude retry lanes because those must always be time sliced, in order - // to unwrap uncached promises. - // TODO: Write a test for this - - var lanes = pendingLanes & ~RetryLanes; - - while (lanes > 0) { - var index = pickArbitraryLaneIndex(lanes); - var lane = 1 << index; - var expirationTime = expirationTimes[index]; - - if (expirationTime === NoTimestamp) { - // Found a pending lane with no expiration time. If it's not suspended, or - // if it's pinged, assume it's CPU-bound. Compute a new expiration time - // using the current time. - if ( - (lane & suspendedLanes) === NoLanes || - (lane & pingedLanes) !== NoLanes - ) { - // Assumes timestamps are monotonically increasing. - expirationTimes[index] = computeExpirationTime(lane, currentTime); - } - } else if (expirationTime <= currentTime) { - // This lane expired - root.expiredLanes |= lane; - } + if (a.stateNode.current === a) { + // We've determined that A is the current branch. + return fiber; + } // Otherwise B has to be current branch. - lanes &= ~lane; - } - } // This returns the highest priority pending lanes regardless of whether they - function getLanesToRetrySynchronouslyOnError( - root, - originallyAttemptedLanes - ) { - if (root.errorRecoveryDisabledLanes & originallyAttemptedLanes) { - // The error recovery mechanism is disabled until these lanes are cleared. - return NoLanes; - } - var everythingButOffscreen = root.pendingLanes & ~OffscreenLane; + return alternate; +} +function findCurrentHostFiber(parent) { + var currentParent = findCurrentFiberUsingSlowPath(parent); + return currentParent !== null ? findCurrentHostFiberImpl(currentParent) : null; +} - if (everythingButOffscreen !== NoLanes) { - return everythingButOffscreen; - } +function findCurrentHostFiberImpl(node) { + // Next we'll drill down this component to find the first HostComponent/Text. + var tag = node.tag; - if (everythingButOffscreen & OffscreenLane) { - return OffscreenLane; - } + if (tag === HostComponent || tag === HostHoistable || tag === HostSingleton || tag === HostText) { + return node; + } - return NoLanes; - } - function includesSyncLane(lanes) { - return (lanes & (SyncLane | SyncHydrationLane)) !== NoLanes; - } - function includesNonIdleWork(lanes) { - return (lanes & NonIdleLanes) !== NoLanes; - } - function includesOnlyRetries(lanes) { - return (lanes & RetryLanes) === lanes; - } - function includesOnlyNonUrgentLanes(lanes) { - // TODO: Should hydration lanes be included here? This function is only - // used in `updateDeferredValueImpl`. - var UrgentLanes = SyncLane | InputContinuousLane | DefaultLane; - return (lanes & UrgentLanes) === NoLanes; - } - function includesOnlyTransitions(lanes) { - return (lanes & TransitionLanes) === lanes; - } - function includesBlockingLane(root, lanes) { - var SyncDefaultLanes = - InputContinuousHydrationLane | - InputContinuousLane | - DefaultHydrationLane | - DefaultLane; - return (lanes & SyncDefaultLanes) !== NoLanes; - } - function includesExpiredLane(root, lanes) { - // This is a separate check from includesBlockingLane because a lane can - // expire after a render has already started. - return (lanes & root.expiredLanes) !== NoLanes; + var child = node.child; + + while (child !== null) { + var match = findCurrentHostFiberImpl(child); + + if (match !== null) { + return match; } - function isTransitionLane(lane) { - return (lane & TransitionLanes) !== NoLanes; + + child = child.sibling; + } + + return null; +} +function doesFiberContain(parentFiber, childFiber) { + var node = childFiber; + var parentFiberAlternate = parentFiber.alternate; + + while (node !== null) { + if (node === parentFiber || node === parentFiberAlternate) { + return true; } - function claimNextTransitionLane() { - // Cycle through the lanes, assigning each new transition to the next lane. - // In most cases, this means every transition gets its own lane, until we - // run out of lanes and cycle back to the beginning. - var lane = nextTransitionLane; - nextTransitionLane <<= 1; - if ((nextTransitionLane & TransitionLanes) === NoLanes) { - nextTransitionLane = TransitionLane1; - } + node = node.return; + } - return lane; - } - function claimNextRetryLane() { - var lane = nextRetryLane; - nextRetryLane <<= 1; + return false; +} - if ((nextRetryLane & RetryLanes) === NoLanes) { - nextRetryLane = RetryLane1; - } +var valueStack = []; +var fiberStack; - return lane; - } - function getHighestPriorityLane(lanes) { - return lanes & -lanes; - } - function pickArbitraryLane(lanes) { - // This wrapper function gets inlined. Only exists so to communicate that it - // doesn't matter which bit is selected; you can pick any bit without - // affecting the algorithms where its used. Here I'm using - // getHighestPriorityLane because it requires the fewest operations. - return getHighestPriorityLane(lanes); - } +{ + fiberStack = []; +} - function pickArbitraryLaneIndex(lanes) { - return 31 - clz32(lanes); - } +var index = -1; - function laneToIndex(lane) { - return pickArbitraryLaneIndex(lane); - } +function createCursor(defaultValue) { + return { + current: defaultValue + }; +} - function includesSomeLane(a, b) { - return (a & b) !== NoLanes; - } - function isSubsetOfLanes(set, subset) { - return (set & subset) === subset; - } - function mergeLanes(a, b) { - return a | b; - } - function removeLanes(set, subset) { - return set & ~subset; +function pop(cursor, fiber) { + if (index < 0) { + { + error('Unexpected pop.'); } - function intersectLanes(a, b) { - return a & b; - } // Seems redundant, but it changes the type from a single lane (used for - // updates) to a group of lanes (used for flushing work). - function laneToLanes(lane) { - return lane; + return; + } + + { + if (fiber !== fiberStack[index]) { + error('Unexpected Fiber popped.'); } - function createLaneMap(initial) { - // Intentionally pushing one by one. - // https://v8.dev/blog/elements-kinds#avoid-creating-holes - var laneMap = []; + } - for (var i = 0; i < TotalLanes; i++) { - laneMap.push(initial); - } + cursor.current = valueStack[index]; + valueStack[index] = null; - return laneMap; - } - function markRootUpdated$1(root, updateLane) { - root.pendingLanes |= updateLane; // If there are any suspended transitions, it's possible this new update - // could unblock them. Clear the suspended lanes so that we can try rendering - // them again. - // - // TODO: We really only need to unsuspend only lanes that are in the - // `subtreeLanes` of the updated fiber, or the update lanes of the return - // path. This would exclude suspended updates in an unrelated sibling tree, - // since there's no way for this update to unblock it. - // - // We don't do this if the incoming update is idle, because we never process - // idle updates until after all the regular updates have finished; there's no - // way it could unblock a transition. + { + fiberStack[index] = null; + } - if (updateLane !== IdleLane) { - root.suspendedLanes = NoLanes; - root.pingedLanes = NoLanes; - } - } - function markRootSuspended$1(root, suspendedLanes, spawnedLane) { - root.suspendedLanes |= suspendedLanes; - root.pingedLanes &= ~suspendedLanes; // The suspended lanes are no longer CPU-bound. Clear their expiration times. + index--; +} - var expirationTimes = root.expirationTimes; - var lanes = suspendedLanes; +function push(cursor, value, fiber) { + index++; + valueStack[index] = cursor.current; - while (lanes > 0) { - var index = pickArbitraryLaneIndex(lanes); - var lane = 1 << index; - expirationTimes[index] = NoTimestamp; - lanes &= ~lane; - } + { + fiberStack[index] = fiber; + } - if (spawnedLane !== NoLane) { - markSpawnedDeferredLane(root, spawnedLane, suspendedLanes); - } - } - function markRootPinged$1(root, pingedLanes) { - root.pingedLanes |= root.suspendedLanes & pingedLanes; - } - function markRootFinished(root, remainingLanes, spawnedLane) { - var noLongerPendingLanes = root.pendingLanes & ~remainingLanes; - root.pendingLanes = remainingLanes; // Let's try everything again + cursor.current = value; +} - root.suspendedLanes = NoLanes; - root.pingedLanes = NoLanes; - root.expiredLanes &= remainingLanes; - root.entangledLanes &= remainingLanes; - root.errorRecoveryDisabledLanes &= remainingLanes; - root.shellSuspendCounter = 0; - var entanglements = root.entanglements; - var expirationTimes = root.expirationTimes; - var hiddenUpdates = root.hiddenUpdates; // Clear the lanes that no longer have pending work +var warnedAboutMissingGetChildContext; - var lanes = noLongerPendingLanes; +{ + warnedAboutMissingGetChildContext = {}; +} - while (lanes > 0) { - var index = pickArbitraryLaneIndex(lanes); - var lane = 1 << index; - entanglements[index] = NoLanes; - expirationTimes[index] = NoTimestamp; - var hiddenUpdatesForLane = hiddenUpdates[index]; +var emptyContextObject = {}; - if (hiddenUpdatesForLane !== null) { - hiddenUpdates[index] = null; // "Hidden" updates are updates that were made to a hidden component. They - // have special logic associated with them because they may be entangled - // with updates that occur outside that tree. But once the outer tree - // commits, they behave like regular updates. +{ + Object.freeze(emptyContextObject); +} // A cursor to the current merged context object on the stack. - for (var i = 0; i < hiddenUpdatesForLane.length; i++) { - var update = hiddenUpdatesForLane[i]; - if (update !== null) { - update.lane &= ~OffscreenLane; - } - } - } +var contextStackCursor$1 = createCursor(emptyContextObject); // A cursor to a boolean indicating whether the context has changed. - lanes &= ~lane; - } +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. - if (spawnedLane !== NoLane) { - markSpawnedDeferredLane( - root, - spawnedLane, // This render finished successfully without suspending, so we don't need - // to entangle the spawned task with the parent task. - NoLanes - ); - } +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; } - function markSpawnedDeferredLane(root, spawnedLane, entangledLanes) { - // This render spawned a deferred task. Mark it as pending. - root.pendingLanes |= spawnedLane; - root.suspendedLanes &= ~spawnedLane; // Entangle the spawned lane with the DeferredLane bit so that we know it - // was the result of another render. This lets us avoid a useDeferredValue - // waterfall — only the first level will defer. + return contextStackCursor$1.current; + } +} - var spawnedLaneIndex = laneToIndex(spawnedLane); - root.entangledLanes |= spawnedLane; - root.entanglements[spawnedLaneIndex] |= - DeferredLane | // If the parent render task suspended, we must also entangle those lanes - // with the spawned task, so that the deferred task includes all the same - // updates that the parent task did. We can exclude any lane that is not - // used for updates (e.g. Offscreen). - (entangledLanes & UpdateLanes); - } +function cacheContext(workInProgress, unmaskedContext, maskedContext) { + { + var instance = workInProgress.stateNode; + instance.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext; + instance.__reactInternalMemoizedMaskedChildContext = maskedContext; + } +} - function markRootEntangled(root, entangledLanes) { - // In addition to entangling each of the given lanes with each other, we also - // have to consider _transitive_ entanglements. For each lane that is already - // entangled with *any* of the given lanes, that lane is now transitively - // entangled with *all* the given lanes. - // - // Translated: If C is entangled with A, then entangling A with B also - // entangles C with B. - // - // If this is hard to grasp, it might help to intentionally break this - // function and look at the tests that fail in ReactTransition-test.js. Try - // commenting out one of the conditions below. - var rootEntangledLanes = (root.entangledLanes |= entangledLanes); - var entanglements = root.entanglements; - var lanes = rootEntangledLanes; +function getMaskedContext(workInProgress, unmaskedContext) { + { + var type = workInProgress.type; + var contextTypes = type.contextTypes; - while (lanes) { - var index = pickArbitraryLaneIndex(lanes); - var lane = 1 << index; + 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. - if ( - // Is this one of the newly entangled lanes? - (lane & entangledLanes) | // Is this lane transitively entangled with the newly entangled lanes? - (entanglements[index] & entangledLanes) - ) { - entanglements[index] |= entangledLanes; - } - lanes &= ~lane; - } - } - function upgradePendingLaneToSync(root, lane) { - // Since we're upgrading the priority of the given lane, there is now pending - // sync work. - root.pendingLanes |= SyncLane; // Entangle the sync lane with the lane we're upgrading. This means SyncLane - // will not be allowed to finish without also finishing the given lane. + var instance = workInProgress.stateNode; - root.entangledLanes |= SyncLane; - root.entanglements[SyncLaneIndex] |= lane; + if (instance && instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext) { + return instance.__reactInternalMemoizedMaskedChildContext; } - function markHiddenUpdate(root, update, lane) { - var index = laneToIndex(lane); - var hiddenUpdates = root.hiddenUpdates; - var hiddenUpdatesForLane = hiddenUpdates[index]; - if (hiddenUpdatesForLane === null) { - hiddenUpdates[index] = [update]; - } else { - hiddenUpdatesForLane.push(update); - } + var context = {}; + + for (var key in contextTypes) { + context[key] = unmaskedContext[key]; + } // 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. - update.lane = lane | OffscreenLane; + + if (instance) { + cacheContext(workInProgress, unmaskedContext, context); } - function getBumpedLaneForHydration(root, renderLanes) { - var renderLane = getHighestPriorityLane(renderLanes); - var lane; - if (enableUnifiedSyncLane && (renderLane & SyncUpdateLanes) !== NoLane) { - lane = SyncHydrationLane; - } else { - switch (renderLane) { - case SyncLane: - lane = SyncHydrationLane; - break; + return context; + } +} - case InputContinuousLane: - lane = InputContinuousHydrationLane; - break; +function hasContextChanged() { + { + return didPerformWorkStackCursor.current; + } +} - case DefaultLane: - lane = DefaultHydrationLane; - break; +function isContextProvider(type) { + { + var childContextTypes = type.childContextTypes; + return childContextTypes !== null && childContextTypes !== undefined; + } +} - case TransitionLane1: - case TransitionLane2: - case TransitionLane3: - case TransitionLane4: - case TransitionLane5: - case TransitionLane6: - case TransitionLane7: - case TransitionLane8: - case TransitionLane9: - case TransitionLane10: - case TransitionLane11: - case TransitionLane12: - case TransitionLane13: - case TransitionLane14: - case TransitionLane15: - case RetryLane1: - case RetryLane2: - case RetryLane3: - case RetryLane4: - lane = TransitionHydrationLane; - break; +function popContext(fiber) { + { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor$1, fiber); + } +} - case IdleLane: - lane = IdleHydrationLane; - break; +function popTopLevelContextObject(fiber) { + { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor$1, fiber); + } +} - default: - // Everything else is already either a hydration lane, or shouldn't - // be retried at a hydration lane. - lane = NoLane; - break; - } - } // Check if the lane we chose is suspended. If so, that indicates that we - // already attempted and failed to hydrate at that level. Also check if we're - // already rendering that lane, which is rare but could happen. +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.'); + } + + push(contextStackCursor$1, context, fiber); + push(didPerformWorkStackCursor, didChange, fiber); + } +} + +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 (typeof instance.getChildContext !== 'function') { + { + var componentName = getComponentNameFromFiber(fiber) || 'Unknown'; - if ((lane & (root.suspendedLanes | renderLanes)) !== NoLane) { - // Give up trying to hydrate and fall back to client render. - return NoLane; + if (!warnedAboutMissingGetChildContext[componentName]) { + warnedAboutMissingGetChildContext[componentName] = true; + + 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 lane; + return parentContext; } - function addFiberToLanesMap(root, fiber, lanes) { - if (!isDevToolsPresent) { - return; - } - var pendingUpdatersLaneMap = root.pendingUpdatersLaneMap; + var childContext = instance.getChildContext(); - while (lanes > 0) { - var index = laneToIndex(lanes); - var lane = 1 << index; - var updaters = pendingUpdatersLaneMap[index]; - updaters.add(fiber); - lanes &= ~lane; + for (var contextKey in childContext) { + if (!(contextKey in childContextTypes)) { + throw new Error((getComponentNameFromFiber(fiber) || 'Unknown') + ".getChildContext(): key \"" + contextKey + "\" is not defined in childContextTypes."); } } - function movePendingFibersToMemoized(root, lanes) { - if (!isDevToolsPresent) { - return; - } - var pendingUpdatersLaneMap = root.pendingUpdatersLaneMap; - var memoizedUpdaters = root.memoizedUpdaters; + return assign({}, parentContext, childContext); + } +} - while (lanes > 0) { - var index = laneToIndex(lanes); - var lane = 1 << index; - var updaters = pendingUpdatersLaneMap[index]; +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. - if (updaters.size > 0) { - updaters.forEach(function (fiber) { - var alternate = fiber.alternate; + 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 (alternate === null || !memoizedUpdaters.has(alternate)) { - memoizedUpdaters.add(fiber); - } - }); - updaters.clear(); - } + previousContext = contextStackCursor$1.current; + push(contextStackCursor$1, memoizedMergedChildContext, workInProgress); + push(didPerformWorkStackCursor, didPerformWorkStackCursor.current, workInProgress); + return true; + } +} - lanes &= ~lane; - } - } - function getTransitionsForLanes(root, lanes) { - { - return null; - } - } +function invalidateContextProvider(workInProgress, type, didChange) { + { + var instance = workInProgress.stateNode; - var NoEventPriority = NoLane; - var DiscreteEventPriority = SyncLane; - var ContinuousEventPriority = InputContinuousLane; - var DefaultEventPriority = DefaultLane; - var IdleEventPriority = IdleLane; - function higherEventPriority(a, b) { - return a !== 0 && a < b ? a : b; - } - function lowerEventPriority(a, b) { - return a === 0 || a > b ? a : b; + 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.'); } - function isHigherEventPriority(a, b) { - return a !== 0 && a < b; + + 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 eventPriorityToLane(updatePriority) { - return updatePriority; + } +} + +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.'); } - function lanesToEventPriority(lanes) { - var lane = getHighestPriorityLane(lanes); - if (!isHigherEventPriority(DiscreteEventPriority, lane)) { - return DiscreteEventPriority; - } + var node = fiber; - if (!isHigherEventPriority(ContinuousEventPriority, lane)) { - return ContinuousEventPriority; - } + do { + switch (node.tag) { + case HostRoot: + return node.stateNode.context; - if (includesNonIdleWork(lane)) { - return DefaultEventPriority; - } + case ClassComponent: + { + var Component = node.type; - return IdleEventPriority; - } - - // Renderers that don't support mutation - // can re-export everything from this module. - function shim$2() { - 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$2; - - // Renderers that don't support hydration - // can re-export everything from this module. - function shim$1() { - 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 supportsHydration = false; - var isSuspenseInstancePending = shim$1; - var isSuspenseInstanceFallback = shim$1; - var getSuspenseInstanceFallbackErrorDetails = shim$1; - var registerSuspenseInstanceRetry = shim$1; - - // Renderers that don't support hydration - // can re-export everything from this module. - function shim() { - throw new Error( - "The current renderer does not support Resources. " + - "This error is likely caused by a bug in React. " + - "Please file an issue." - ); - } // Resources (when unsupported) - var suspendResource = shim; - - var _nativeFabricUIManage = nativeFabricUIManager, - createNode = _nativeFabricUIManage.createNode, - 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 nextReactTag = 2; // TODO: Remove this conditional once all changes have propagated. - - 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); + if (isContextProvider(Component)) { + return node.stateNode.__reactInternalMemoizedMergedChildContext; + } - { - for (var key in viewConfig.validAttributes) { - if (props.hasOwnProperty(key)) { - ReactNativePrivateInterface.deepFreezeAndThrowOnMutationInDev( - props[key] - ); + break; } - } - } - - 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 createTextInstance( - text, - rootContainerInstance, - hostContext, - internalInstanceHandle - ) { - { - if (!hostContext.isInAParentText) { - error("Text strings must be rendered within a component."); - } - } + } // $FlowFixMe[incompatible-type] we bail out when we get a null - 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. - - 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] - if (instance._nativeTag != null) { - // $FlowExpectedError[incompatible-return] - return instance; - } + node = node.return; + } while (node !== null); - return null; - } + throw new Error('Found unexpected detached subtree parent. ' + 'This error is likely caused by a bug in React. Please file an issue.'); + } +} - function getPublicTextInstance(textInstance, internalInstanceHandle) { - if (textInstance.publicInstance == null) { - textInstance.publicInstance = - ReactNativePrivateInterface.createPublicTextInstance( - internalInstanceHandle - ); - } +// 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'; +} - return textInstance.publicInstance; - } +/** + * 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 getPublicInstanceFromInternalInstanceHandle( - internalInstanceHandle - ) { - var instance = internalInstanceHandle.stateNode; // React resets all the fields in the fiber when the component is unmounted - // to prevent memory leaks. +var objectIs = // $FlowFixMe[method-unbinding] +typeof Object.is === 'function' ? Object.is : is; - if (instance == null) { - return null; +var prefix; +function describeBuiltInComponentFrame(name) { + if (enableComponentStackLocations) { + if (prefix === undefined) { + // Extract the VM specific prefix used by each line. + try { + throw Error(); + } catch (x) { + var match = x.stack.trim().match(/\n( *(at )?)/); + prefix = match && match[1] || ''; } + } // We use the prefix to ensure our stacks line up with native stack frames. - if (internalInstanceHandle.tag === HostText) { - var textInstance = instance; - return getPublicTextInstance(textInstance, internalInstanceHandle); - } - var elementInstance = internalInstanceHandle.stateNode; - return getPublicInstance(elementInstance); - } - 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 currentUpdatePriority = NoEventPriority; - function setCurrentUpdatePriority(newPriority) { - currentUpdatePriority = newPriority; - } - function getCurrentUpdatePriority() { - return currentUpdatePriority; - } - function resolveUpdatePriority() { - if (currentUpdatePriority !== NoEventPriority) { - return currentUpdatePriority; - } + return '\n' + prefix + name; + } else { + return describeComponentFrame(name); + } +} +function describeDebugInfoFrame(name, env) { + return describeBuiltInComponentFrame(name + (env ? ' (' + env + ')' : '')); +} +var reentry = false; +var componentFrameCache; - var currentEventPriority = fabricGetCurrentEventPriority - ? fabricGetCurrentEventPriority() - : null; +{ + var PossiblyWeakMap$1 = typeof WeakMap === 'function' ? WeakMap : Map; + componentFrameCache = new PossiblyWeakMap$1(); +} +/** + * Leverages native browser/VM stack frames to get proper details (e.g. + * filename, line + col number) for a single component in a component stack. We + * do this by: + * (1) throwing and catching an error in the function - this will be our + * control error. + * (2) calling the component which will eventually throw an error that we'll + * catch - this will be our sample error. + * (3) diffing the control and sample error stacks to find the stack frame + * which represents our component. + */ - if (currentEventPriority != null) { - switch (currentEventPriority) { - case FabricDiscretePriority: - return DiscreteEventPriority; - case FabricDefaultPriority: - default: - return DefaultEventPriority; - } - } +function describeNativeComponentFrame(fn, construct) { + // If something asked for a stack inside a fake render, it should get ignored. + if (!fn || reentry) { + return ''; + } - return DefaultEventPriority; - } - function shouldAttemptEagerTransition() { - return false; - } // The Fabric renderer is secondary to the existing React Native renderer. - - var warnsIfNotActing = false; - var scheduleTimeout = setTimeout; - var cancelTimeout = clearTimeout; - var noTimeout = -1; // ------------------- - function cloneInstance( - instance, - type, - oldProps, - newProps, - keepChildren, - newChildSet - ) { - 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; - var node = instance.node; - var clone; - - if (keepChildren) { - if (updatePayload !== null) { - clone = cloneNodeWithNewProps(node, updatePayload); - } else { - // No changes - return instance; - } - } else { - // If passChildrenWhenCloningPersistedNodes is enabled, children will be non-null - if (newChildSet != null) { - if (updatePayload !== null) { - clone = cloneNodeWithNewChildrenAndProps( - node, - newChildSet, - updatePayload - ); - } else { - clone = cloneNodeWithNewChildren(node, newChildSet); - } - } else { - if (updatePayload !== null) { - clone = cloneNodeWithNewChildrenAndProps(node, updatePayload); - } else { - clone = cloneNodeWithNewChildren(node); - } - } - } + { + var frame = componentFrameCache.get(fn); - return { - node: clone, - canonical: instance.canonical - }; - } - function cloneHiddenInstance(instance, type, props) { - 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) { - throw new Error("Not yet implemented."); + if (frame !== undefined) { + return frame; } - function createContainerChildSet() { - if (passChildrenWhenCloningPersistedNodes) { - return []; - } else { - return createChildNodeSet(); - } - } - function appendChildToContainerChildSet(childSet, child) { - if (passChildrenWhenCloningPersistedNodes) { - childSet.push(child.node); - } else { - appendChildNodeToSet(childSet, child.node); - } - } - function finalizeContainerChildren(container, newChildren) { - completeRoot(container, newChildren); - } - function replaceContainerChildren(container, newChildren) { - // Noop - children will be replaced in finalizeContainerChildren - } - function preloadInstance(type, props) { - return true; - } - function waitForCommitToBeReady() { - return null; - } - var NotPendingTransition = null; - // Microtasks - // ------------------- + } - var supportsMicrotasks = - typeof RN$enableMicrotasksInReact !== "undefined" && - !!RN$enableMicrotasksInReact; - var scheduleMicrotask = - typeof queueMicrotask === "function" ? queueMicrotask : scheduleTimeout; + reentry = true; + var previousPrepareStackTrace = Error.prepareStackTrace; // $FlowFixMe[incompatible-type] It does accept undefined. - // This is ok in DOM because they types are interchangeable, but in React Native - // they aren't. + Error.prepareStackTrace = undefined; + var previousDispatcher = null; - function getInstanceFromNode(node) { - var instance = node; // In React Native, node is never a text instance + { + previousDispatcher = ReactSharedInternals.H; // Set the dispatcher in DEV because this might be call in the render function + // for warnings. - if ( - instance.canonical != null && - instance.canonical.internalInstanceHandle != null - ) { - return instance.canonical.internalInstanceHandle; - } // $FlowFixMe[incompatible-return] DevTools incorrectly passes a fiber in React Native. + ReactSharedInternals.H = null; + disableLogs(); + } + /** + * Finding a common stack frame between sample and control errors can be + * tricky given the different types and levels of stack trace truncation from + * different JS VMs. So instead we'll attempt to control what that common + * frame should be through this object method: + * Having both the sample and control errors be in the function under the + * `DescribeNativeComponentFrameRoot` property, + setting the `name` and + * `displayName` properties of the function ensures that a stack + * frame exists that has the method name `DescribeNativeComponentFrameRoot` in + * it for both control and sample stacks. + */ - return node; - } - function getNodeFromInstance(fiber) { - var publicInstance = getPublicInstance(fiber.stateNode); + var RunInRootFrame = { + DetermineComponentFrameRoot: function () { + var control; - if (publicInstance == null) { - throw new Error("Could not find host instance from fiber"); - } + try { + // This should throw. + if (construct) { + // Something should be setting the props in the constructor. + var Fake = function () { + throw Error(); + }; // $FlowFixMe[prop-missing] - return publicInstance; - } - function getFiberCurrentPropsFromNode(instance) { - return instance.canonical.currentProps; - } + Object.defineProperty(Fake.prototype, 'props', { + set: function () { + // We use a throwing setter instead of frozen or non-writable props + // because that won't throw in a non-strict mode function. + throw Error(); + } + }); - var ReactFabricGlobalResponderHandler = { - onChange: function (from, to, blockNativeResponder) { - if (from && from.stateNode) { - // equivalent to clearJSResponder - nativeFabricUIManager.setIsJSResponder( - from.stateNode.node, - false, - blockNativeResponder || false - ); - } + if (typeof Reflect === 'object' && Reflect.construct) { + // We construct a different control for this case to include any extra + // frames added by the construct call. + try { + Reflect.construct(Fake, []); + } catch (x) { + control = x; + } - if (to && to.stateNode) { - // equivalent to setJSResponder - nativeFabricUIManager.setIsJSResponder( - to.stateNode.node, - true, - blockNativeResponder || false - ); - } - } - }; + Reflect.construct(fn, [], Fake); + } else { + try { + Fake.call(); + } catch (x) { + control = x; + } // $FlowFixMe[prop-missing] found when upgrading Flow - setComponentTree( - getFiberCurrentPropsFromNode, - getInstanceFromNode, - getNodeFromInstance - ); - ResponderEventPlugin.injection.injectGlobalResponderHandler( - ReactFabricGlobalResponderHandler - ); - var LegacyRoot = 0; - var ConcurrentRoot = 1; + fn.call(Fake.prototype); + } + } else { + try { + throw Error(); + } catch (x) { + control = x; + } // TODO(luna): This will currently only throw if the function component + // tries to access React/ReactDOM/props. We should probably make this throw + // in simple components too - /** - * `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; - } - - // 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"); // TODO: Delete with enableRenderableContext - - var REACT_CONSUMER_TYPE = Symbol.for("react.consumer"); - var REACT_CONTEXT_TYPE = Symbol.for("react.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_TRACING_MARKER_TYPE = Symbol.for("react.tracing_marker"); - 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 maybeIterator = - (MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL]) || - maybeIterable[FAUX_ITERATOR_SYMBOL]; + var maybePromise = fn(); // If the function component returns a promise, it's likely an async + // component, which we don't yet support. Attach a noop catch handler to + // silence the error. + // TODO: Implement component stacks for async client components? - if (typeof maybeIterator === "function") { - return maybeIterator; + if (maybePromise && typeof maybePromise.catch === 'function') { + maybePromise.catch(function () {}); + } + } + } catch (sample) { + // This is inlined manually because closure doesn't do it for us. + if (sample && control && typeof sample.stack === 'string') { + return [sample.stack, control.stack]; + } } - return null; + return [null, null]; } + }; // $FlowFixMe[prop-missing] - function getWrappedName$1(outerType, innerType, wrapperName) { - var displayName = outerType.displayName; + RunInRootFrame.DetermineComponentFrameRoot.displayName = 'DetermineComponentFrameRoot'; + var namePropDescriptor = Object.getOwnPropertyDescriptor(RunInRootFrame.DetermineComponentFrameRoot, 'name'); // Before ES6, the `name` property was not configurable. - if (displayName) { - return displayName; - } + if (namePropDescriptor && namePropDescriptor.configurable) { + // V8 utilizes a function's `name` property when generating a stack trace. + Object.defineProperty(RunInRootFrame.DetermineComponentFrameRoot, // Configurable properties can be updated even if its writable descriptor + // is set to `false`. + // $FlowFixMe[cannot-write] + 'name', { + value: 'DetermineComponentFrameRoot' + }); + } + + try { + var _RunInRootFrame$Deter = RunInRootFrame.DetermineComponentFrameRoot(), + sampleStack = _RunInRootFrame$Deter[0], + controlStack = _RunInRootFrame$Deter[1]; + + if (sampleStack && controlStack) { + // This extracts the first frame from the sample that isn't also in the control. + // Skipping one frame that we assume is the frame that calls the two. + var sampleLines = sampleStack.split('\n'); + var controlLines = controlStack.split('\n'); + var s = 0; + var c = 0; + + while (s < sampleLines.length && !sampleLines[s].includes('DetermineComponentFrameRoot')) { + s++; + } + + while (c < controlLines.length && !controlLines[c].includes('DetermineComponentFrameRoot')) { + c++; + } // We couldn't find our intentionally injected common root frame, attempt + // to find another common root frame by search from the bottom of the + // control stack... + + + if (s === sampleLines.length || c === controlLines.length) { + s = sampleLines.length - 1; + c = controlLines.length - 1; + + while (s >= 1 && c >= 0 && sampleLines[s] !== controlLines[c]) { + // We expect at least one stack frame to be shared. + // Typically this will be the root most one. However, stack frames may be + // cut off due to maximum stack limits. In this case, one maybe cut off + // earlier than the other. We assume that the sample is longer or the same + // and there for cut off earlier. So we should find the root most frame in + // the sample somewhere in the control. + c--; + } + } + + for (; s >= 1 && c >= 0; s--, c--) { + // Next we find the first one that isn't the same which should be the + // frame that called our sample function and the control. + if (sampleLines[s] !== controlLines[c]) { + // In V8, the first line is describing the message but other VMs don't. + // If we're about to return the first line, and the control is also on the same + // line, that's a pretty good indicator that our sample threw at same line as + // the control. I.e. before we entered the sample frame. So we ignore this result. + // This can happen if you passed a class to function component, or non-function. + if (s !== 1 || c !== 1) { + do { + s--; + c--; // We may still have similar intermediate frames from the construct call. + // The next one that isn't the same should be our match though. - var functionName = innerType.displayName || innerType.name || ""; - return functionName !== "" - ? wrapperName + "(" + functionName + ")" - : wrapperName; - } // Keep in sync with react-reconciler/getComponentNameFromFiber + if (c < 0 || sampleLines[s] !== controlLines[c]) { + // V8 adds a "new" prefix for native classes. Let's remove it to make it prettier. + var _frame = '\n' + sampleLines[s].replace(' at new ', ' at '); // If our component frame is labeled "" + // but we have a user-provided "displayName" + // splice it in to make the stack more readable. - function getContextName$1(type) { - return type.displayName || "Context"; - } - var REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference"); // Note that the reconciler package should generally prefer to use getComponentNameFromFiber() instead. + if (fn.displayName && _frame.includes('')) { + _frame = _frame.replace('', fn.displayName); + } - function getComponentNameFromType(type) { - if (type == null) { - // Host root, text node or just invalid type. - return null; - } + if (true) { + if (typeof fn === 'function') { + componentFrameCache.set(fn, _frame); + } + } // Return the line we found. - if (typeof type === "function") { - if (type.$$typeof === REACT_CLIENT_REFERENCE) { - // TODO: Create a convention for naming client references with debug info. - return null; - } - return type.displayName || type.name || null; - } + return _frame; + } + } while (s >= 1 && c >= 0); + } - if (typeof type === "string") { - return type; + break; + } } + } + } finally { + reentry = false; + + { + ReactSharedInternals.H = previousDispatcher; + reenableLogs(); + } - switch (type) { - case REACT_FRAGMENT_TYPE: - return "Fragment"; + Error.prepareStackTrace = previousPrepareStackTrace; + } // Fallback to just using the name if we couldn't make it throw. - case REACT_PORTAL_TYPE: - return "Portal"; - case REACT_PROFILER_TYPE: - return "Profiler"; + var name = fn ? fn.displayName || fn.name : ''; + var syntheticFrame = name ? describeBuiltInComponentFrame(name) : ''; - case REACT_STRICT_MODE_TYPE: - return "StrictMode"; + { + if (typeof fn === 'function') { + componentFrameCache.set(fn, syntheticFrame); + } + } - case REACT_SUSPENSE_TYPE: - return "Suspense"; + return syntheticFrame; +} - case REACT_SUSPENSE_LIST_TYPE: - return "SuspenseList"; - } +function describeComponentFrame(name) { + return '\n in ' + (name || 'Unknown'); +} - if (typeof type === "object") { - { - if (typeof type.tag === "number") { - error( - "Received an unexpected object in getComponentNameFromType(). " + - "This is likely a bug in React. Please file an issue." - ); - } - } +function describeClassComponentFrame(ctor) { + if (enableComponentStackLocations) { + return describeNativeComponentFrame(ctor, true); + } else { + return describeFunctionComponentFrame(ctor); + } +} +function describeFunctionComponentFrame(fn) { + if (enableComponentStackLocations) { + return describeNativeComponentFrame(fn, false); + } else { + if (!fn) { + return ''; + } + + var name = fn.displayName || fn.name || null; + return describeComponentFrame(name); + } +} + +function describeFiber(fiber) { + switch (fiber.tag) { + case HostHoistable: + case HostSingleton: + case HostComponent: + return describeBuiltInComponentFrame(fiber.type); - switch (type.$$typeof) { - case REACT_PROVIDER_TYPE: - if (enableRenderableContext) { - return null; - } else { - var provider = type; - return getContextName$1(provider._context) + ".Provider"; - } + case LazyComponent: + return describeBuiltInComponentFrame('Lazy'); - case REACT_CONTEXT_TYPE: - var context = type; + case SuspenseComponent: + return describeBuiltInComponentFrame('Suspense'); - if (enableRenderableContext) { - return getContextName$1(context) + ".Provider"; - } else { - return getContextName$1(context) + ".Consumer"; - } + case SuspenseListComponent: + return describeBuiltInComponentFrame('SuspenseList'); - case REACT_CONSUMER_TYPE: - if (enableRenderableContext) { - var consumer = type; - return getContextName$1(consumer._context) + ".Consumer"; - } else { - return null; - } + case FunctionComponent: + case SimpleMemoComponent: + return describeFunctionComponentFrame(fiber.type); - case REACT_FORWARD_REF_TYPE: - return getWrappedName$1(type, type.render, "ForwardRef"); + case ForwardRef: + return describeFunctionComponentFrame(fiber.type.render); - case REACT_MEMO_TYPE: - var outerName = type.displayName || null; + case ClassComponent: + return describeClassComponentFrame(fiber.type); - if (outerName !== null) { - return outerName; - } + default: + return ''; + } +} - return getComponentNameFromType(type.type) || "Memo"; +function getStackByFiberInDevAndProd(workInProgress) { + try { + var info = ''; + var node = workInProgress; - case REACT_LAZY_TYPE: { - var lazyComponent = type; - var payload = lazyComponent._payload; - var init = lazyComponent._init; + do { + info += describeFiber(node); - try { - return getComponentNameFromType(init(payload)); - } catch (x) { - return null; + if (true) { + // Add any Server Component stack frames in reverse order. + var debugInfo = node._debugInfo; + + if (debugInfo) { + for (var i = debugInfo.length - 1; i >= 0; i--) { + var entry = debugInfo[i]; + + if (typeof entry.name === 'string') { + info += describeDebugInfoFrame(entry.name, entry.env); } } } - } + } // $FlowFixMe[incompatible-type] we bail out when we get a null - 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 + node = node.return; + } while (node); - function getContextName(type) { - return type.displayName || "Context"; - } + return info; + } catch (x) { + return '\nError generating stack: ' + x.message + '\n' + x.stack; + } +} - function getComponentNameFromOwner(owner) { - if (typeof owner.tag === "number") { - return getComponentNameFromFiber(owner); - } +var CapturedStacks = new WeakMap(); +function createCapturedValueAtFiber(value, source) { + // If the value is an error, call this function immediately after it is thrown + // so the stack is accurate. + var stack; + + if (typeof value === 'object' && value !== null) { + var capturedStack = CapturedStacks.get(value); + + if (typeof capturedStack === 'string') { + stack = capturedStack; + } else { + stack = getStackByFiberInDevAndProd(source); + CapturedStacks.set(value, stack); + } + } else { + stack = getStackByFiberInDevAndProd(source); + } + + return { + value: value, + source: source, + stack: stack + }; +} +function createCapturedValueFromError(value, stack) { + if (typeof stack === 'string') { + CapturedStacks.set(value, stack); + } + + return { + value: value, + source: null, + stack: stack + }; +} - if (typeof owner.name === "string") { - return owner.name; - } +var contextStackCursor = createCursor(null); +var contextFiberStackCursor = createCursor(null); +var rootInstanceStackCursor = createCursor(null); // Represents the nearest host transition provider (in React DOM, a ) +// NOTE: Since forms cannot be nested, and this feature is only implemented by +// React DOM, we don't technically need this to be a stack. It could be a single +// module variable instead. + +var hostTransitionProviderCursor = createCursor(null); // TODO: This should initialize to NotPendingTransition, a constant +// imported from the fiber config. However, because of a cycle in the module +// graph, that value isn't defined during this module's initialization. I can't +// think of a way to work around this without moving that value out of the +// fiber config. For now, the "no provider" case is handled when reading, +// inside useHostTransitionStatus. + +var HostTransitionContext = { + $$typeof: REACT_CONTEXT_TYPE, + Provider: null, + Consumer: null, + _currentValue: null, + _currentValue2: null, + _threadCount: 0 +}; + +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 c; +} - return null; - } - function getComponentNameFromFiber(fiber) { - var tag = fiber.tag, - type = fiber.type; +function getRootHostContainer() { + var rootInstance = requiredContext(rootInstanceStackCursor.current); + return rootInstance; +} - switch (tag) { - case CacheComponent: - return "Cache"; +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 ContextConsumer: - if (enableRenderableContext) { - var consumer = type; - return getContextName(consumer._context) + ".Consumer"; - } else { - var context = type; - return getContextName(context) + ".Consumer"; - } + 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 ContextProvider: - if (enableRenderableContext) { - var _context = type; - return getContextName(_context) + ".Provider"; - } else { - var provider = type; - return getContextName(provider._context) + ".Provider"; - } + push(contextStackCursor, null, fiber); + var nextRootContext = getRootHostContext(); // Now that we know this function doesn't throw, replace it. - case DehydratedFragment: - return "DehydratedFragment"; + pop(contextStackCursor, fiber); + push(contextStackCursor, nextRootContext, fiber); +} - case ForwardRef: - return getWrappedName(type, type.render, "ForwardRef"); +function popHostContainer(fiber) { + pop(contextStackCursor, fiber); + pop(contextFiberStackCursor, fiber); + pop(rootInstanceStackCursor, fiber); +} - case Fragment: - return "Fragment"; +function getHostContext() { + var context = requiredContext(contextStackCursor.current); + return context; +} - case HostHoistable: - case HostSingleton: - case HostComponent: - // Host component type is the display name (e.g. "div", "View") - return type; +function pushHostContext(fiber) { + if (enableAsyncActions) { + var stateHook = fiber.memoizedState; - case HostPortal: - return "Portal"; + if (stateHook !== null) { + // Only provide context if this fiber has been upgraded by a host + // transition. We use the same optimization for regular host context below. + push(hostTransitionProviderCursor, fiber, fiber); + } + } - case HostRoot: - return "Root"; + var context = requiredContext(contextStackCursor.current); + var nextContext = getChildHostContext(context, fiber.type); // Don't push this Fiber's context unless it's unique. - case HostText: - return "Text"; + if (context !== nextContext) { + // 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); + } +} - case LazyComponent: - // Name comes from the type in this case; we don't have a tag. - return getComponentNameFromType(type); +function popHostContext(fiber) { + if (contextFiberStackCursor.current === fiber) { + // Do not pop unless this Fiber provided the current context. + // pushHostContext() only pushes Fibers that provide unique contexts. + pop(contextStackCursor, fiber); + pop(contextFiberStackCursor, fiber); + } - case Mode: - if (type === REACT_STRICT_MODE_TYPE) { - // Don't be less specific than shared/getComponentNameFromType - return "StrictMode"; - } + if (enableAsyncActions) { + if (hostTransitionProviderCursor.current === fiber) { + // Do not pop unless this Fiber provided the current context. This is mostly + // a performance optimization, but conveniently it also prevents a potential + // data race where a host provider is upgraded (i.e. memoizedState becomes + // non-null) during a concurrent event. This is a bit of a flaw in the way + // we upgrade host components, but because we're accounting for it here, it + // should be fine. + pop(hostTransitionProviderCursor, fiber); // When popping the transition provider, we reset the context value back + // to `null`. We can do this because you're not allowd to nest forms. If + // we allowed for multiple nested host transition providers, then we'd + // need to reset this to the parent provider's status. - return "Mode"; + { + HostTransitionContext._currentValue2 = null; + } + } + } +} - case OffscreenComponent: - return "Offscreen"; +var maxRowLength = 120; +var idealDepth = 15; - case Profiler: - return "Profiler"; +function findNotableNode(node, indent) { + if (node.serverProps === undefined && node.serverTail.length === 0 && node.children.length === 1 && node.distanceFromLeaf > 3 && node.distanceFromLeaf > idealDepth - indent) { + // This is not an interesting node for contextual purposes so we can skip it. + var child = node.children[0]; + return findNotableNode(child, indent); + } - case ScopeComponent: - return "Scope"; + return node; +} - case SuspenseComponent: - return "Suspense"; +function indentation(indent) { + return ' ' + ' '.repeat(indent); +} - case SuspenseListComponent: - return "SuspenseList"; +function added(indent) { + return '+ ' + ' '.repeat(indent); +} - case TracingMarkerComponent: - return "TracingMarker"; - // The display name for these tags come from the user-provided type: +function removed(indent) { + return '- ' + ' '.repeat(indent); +} - case IncompleteClassComponent: - case IncompleteFunctionComponent: +function describeFiberType(fiber) { + switch (fiber.tag) { + case HostHoistable: + case HostSingleton: + case HostComponent: + return fiber.type; - // Fallthrough + case LazyComponent: + return 'Lazy'; - case ClassComponent: - case FunctionComponent: - case MemoComponent: - case SimpleMemoComponent: - if (typeof type === "function") { - return type.displayName || type.name || null; - } + case SuspenseComponent: + return 'Suspense'; - if (typeof type === "string") { - return type; - } + case SuspenseListComponent: + return 'SuspenseList'; - break; - } + case FunctionComponent: + case SimpleMemoComponent: + var fn = fiber.type; + return fn.displayName || fn.name || null; - return null; - } + case ForwardRef: + var render = fiber.type.render; + return render.displayName || render.name || null; - function getNearestMountedFiber(fiber) { - var node = fiber; - var nearestMounted = fiber; + case ClassComponent: + var ctr = fiber.type; + return ctr.displayName || ctr.name || null; - 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; + default: + // Skip + return null; + } +} - do { - node = nextNode; +var needsEscaping = /["'&<>\n\t]/; - 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 +function describeTextNode(content, maxLength) { + if (needsEscaping.test(content)) { + var encoded = JSON.stringify(content); - nextNode = node.return; - } while (nextNode); - } else { - while (node.return) { - node = node.return; - } + if (encoded.length > maxLength - 2) { + if (maxLength < 8) { + return '{"..."}'; } - 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. - - return null; - } - function isFiberMounted(fiber) { - return getNearestMountedFiber(fiber) === fiber; + return '{' + encoded.slice(0, maxLength - 7) + '..."}'; } - function isMounted(component) { - { - var owner = ReactSharedInternals.owner; - - if (owner !== null && owner.tag === ClassComponent) { - var ownerFiber = owner; - var instance = ownerFiber.stateNode; - - 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" - ); - } - instance._warnedAboutRefsInRender = true; - } + return '{' + encoded + '}'; + } else { + if (content.length > maxLength) { + if (maxLength < 5) { + return '{"..."}'; } - var fiber = get(component); + return content.slice(0, maxLength - 3) + '...'; + } - if (!fiber) { - return false; - } + return content; + } +} - return getNearestMountedFiber(fiber) === fiber; - } +function describeTextDiff(clientText, serverProps, indent) { + var maxLength = maxRowLength - indent * 2; + + if (serverProps === null) { + return added(indent) + describeTextNode(clientText, maxLength) + '\n'; + } else if (typeof serverProps === 'string') { + var serverText = serverProps; + var firstDiff = 0; - function assertIsMounted(fiber) { - if (getNearestMountedFiber(fiber) !== fiber) { - throw new Error("Unable to find node on an unmounted component."); + for (; firstDiff < serverText.length && firstDiff < clientText.length; firstDiff++) { + if (serverText.charCodeAt(firstDiff) !== clientText.charCodeAt(firstDiff)) { + break; } } - function findCurrentFiberUsingSlowPath(fiber) { - var alternate = fiber.alternate; + if (firstDiff > maxLength - 8 && firstDiff > 10) { + // The first difference between the two strings would be cut off, so cut off in + // the beginning instead. + clientText = '...' + clientText.slice(firstDiff - 8); + serverText = '...' + serverText.slice(firstDiff - 8); + } - if (!alternate) { - // If there is no alternate, then we only need to check if it is mounted. - var nearestMounted = getNearestMountedFiber(fiber); + return added(indent) + describeTextNode(clientText, maxLength) + '\n' + removed(indent) + describeTextNode(serverText, maxLength) + '\n'; + } else { + return indentation(indent) + describeTextNode(clientText, maxLength) + '\n'; + } +} - if (nearestMounted === null) { - throw new Error("Unable to find node on an unmounted component."); - } +function objectName(object) { + // $FlowFixMe[method-unbinding] + var name = Object.prototype.toString.call(object); + return name.replace(/^\[object (.*)\]$/, function (m, p0) { + return p0; + }); +} - if (nearestMounted !== fiber) { - return null; - } +function describeValue(value, maxLength) { + switch (typeof value) { + case 'string': + { + var encoded = JSON.stringify(value); - 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. + if (encoded.length > maxLength) { + if (maxLength < 5) { + return '"..."'; + } - var a = fiber; - var b = alternate; + return encoded.slice(0, maxLength - 4) + '..."'; + } - while (true) { - var parentA = a.return; + return encoded; + } - if (parentA === null) { - // We're at the root. - break; + case 'object': + { + if (value === null) { + return 'null'; } - var parentB = parentA.alternate; + if (isArray(value)) { + return '[...]'; + } - 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 (value.$$typeof === REACT_ELEMENT_TYPE) { + var type = getComponentNameFromType(value.type); + return type ? '<' + type + '>' : '<...>'; + } - if (nextParent !== null) { - a = b = nextParent; - continue; - } // If there's no parent, we're at the root. + var name = objectName(value); - 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 (name === 'Object') { + var properties = ''; + maxLength -= 2; - if (child === b) { - // We've determined that B is the current branch. - assertIsMounted(parentA); - return alternate; + for (var propName in value) { + if (!value.hasOwnProperty(propName)) { + continue; } - 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."); - } - - 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; - } + var jsonPropName = JSON.stringify(propName); - if (_child === b) { - didFindChild = true; - b = parentA; - a = parentB; - break; + if (jsonPropName !== '"' + propName + '"') { + propName = jsonPropName; } - _child = _child.sibling; - } - - 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; - } + maxLength -= propName.length - 2; + var propValue = describeValue(value[propName], maxLength < 15 ? maxLength : 15); + maxLength -= propValue.length; - _child = _child.sibling; + if (maxLength < 0) { + properties += properties === '' ? '...' : ', ...'; + 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." - ); - } + properties += (properties === '' ? '' : ',') + propName + ':' + propValue; } - } - 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." - ); + return '{' + properties + '}'; } - } // If the root is not a host container, we're in a disconnected tree. I.e. - // unmounted. - if (a.tag !== HostRoot) { - throw new Error("Unable to find node on an unmounted component."); + return name; } - 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; + case 'function': + { + var _name = value.displayName || value.name; - if ( - tag === HostComponent || - tag === HostHoistable || - tag === HostSingleton || - tag === HostText - ) { - return node; + return _name ? 'function ' + _name : 'function'; } - var child = node.child; - - while (child !== null) { - var match = findCurrentHostFiberImpl(child); - - if (match !== null) { - return match; - } + default: + // eslint-disable-next-line react-internal/safe-string-coercion + return String(value); + } +} - child = child.sibling; +function describePropValue(value, maxLength) { + if (typeof value === 'string' && !needsEscaping.test(value)) { + if (value.length > maxLength - 2) { + if (maxLength < 5) { + return '"..."'; } - return null; + return '"' + value.slice(0, maxLength - 5) + '..."'; } - function doesFiberContain(parentFiber, childFiber) { - var node = childFiber; - var parentFiberAlternate = parentFiber.alternate; - while (node !== null) { - if (node === parentFiber || node === parentFiberAlternate) { - return true; - } + return '"' + value + '"'; + } - node = node.return; - } + return '{' + describeValue(value, maxLength - 2) + '}'; +} - return false; - } +function describeCollapsedElement(type, props, indent) { + // This function tries to fit the props into a single line for non-essential elements. + // We also ignore children because we're not going deeper. + var maxLength = maxRowLength - indent * 2 - type.length - 2; + var content = ''; - var valueStack = []; - var fiberStack; + for (var propName in props) { + if (!props.hasOwnProperty(propName)) { + continue; + } - { - fiberStack = []; + if (propName === 'children') { + // Ignored. + continue; } - var index = -1; + var propValue = describePropValue(props[propName], 15); + maxLength -= propName.length + propValue.length + 2; - function createCursor(defaultValue) { - return { - current: defaultValue - }; + if (maxLength < 0) { + content += ' ...'; + break; } - function pop(cursor, fiber) { - if (index < 0) { - { - error("Unexpected pop."); - } + content += ' ' + propName + '=' + propValue; + } - return; - } + return indentation(indent) + '<' + type + content + '>\n'; +} - { - if (fiber !== fiberStack[index]) { - error("Unexpected Fiber popped."); - } - } +function describeExpandedElement(type, props, rowPrefix) { + // This function tries to fit the props into a single line for non-essential elements. + // We also ignore children because we're not going deeper. + var remainingRowLength = maxRowLength - rowPrefix.length - type.length; // We add the properties to a set so we can choose later whether we'll put it on one + // line or multiple lines. - cursor.current = valueStack[index]; - valueStack[index] = null; + var properties = []; - { - fiberStack[index] = null; - } + for (var propName in props) { + if (!props.hasOwnProperty(propName)) { + continue; + } - index--; + if (propName === 'children') { + // Ignored. + continue; } - function push(cursor, value, fiber) { - index++; - valueStack[index] = cursor.current; + var maxLength = maxRowLength - rowPrefix.length - propName.length - 1; + var propValue = describePropValue(props[propName], maxLength); + remainingRowLength -= propName.length + propValue.length + 2; + properties.push(propName + '=' + propValue); + } - { - fiberStack[index] = fiber; - } + if (properties.length === 0) { + return rowPrefix + '<' + type + '>\n'; + } else if (remainingRowLength > 0) { + // We can fit all on one row. + return rowPrefix + '<' + type + ' ' + properties.join(' ') + '>\n'; + } else { + // Split into one row per property: + return rowPrefix + '<' + type + '\n' + rowPrefix + ' ' + properties.join('\n' + rowPrefix + ' ') + '\n' + rowPrefix + '>\n'; + } +} + +function describePropertiesDiff(clientObject, serverObject, indent) { + var properties = ''; + var remainingServerProperties = assign({}, serverObject); - cursor.current = value; + for (var propName in clientObject) { + if (!clientObject.hasOwnProperty(propName)) { + continue; } - var warnedAboutMissingGetChildContext; + delete remainingServerProperties[propName]; + var maxLength = maxRowLength - indent * 2 - propName.length - 2; + var clientValue = clientObject[propName]; + var clientPropValue = describeValue(clientValue, maxLength); - { - warnedAboutMissingGetChildContext = {}; + if (serverObject.hasOwnProperty(propName)) { + var serverValue = serverObject[propName]; + var serverPropValue = describeValue(serverValue, maxLength); + properties += added(indent) + propName + ': ' + clientPropValue + '\n'; + properties += removed(indent) + propName + ': ' + serverPropValue + '\n'; + } else { + properties += added(indent) + propName + ': ' + clientPropValue + '\n'; } + } - var emptyContextObject = {}; + for (var _propName in remainingServerProperties) { + if (!remainingServerProperties.hasOwnProperty(_propName)) { + continue; + } - { - Object.freeze(emptyContextObject); - } // A cursor to the current merged context object on the stack. + var _maxLength = maxRowLength - indent * 2 - _propName.length - 2; - var contextStackCursor$1 = createCursor(emptyContextObject); // A cursor to a boolean indicating whether the context has changed. + var _serverValue = remainingServerProperties[_propName]; - 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 _serverPropValue = describeValue(_serverValue, _maxLength); - var previousContext = emptyContextObject; + properties += removed(indent) + _propName + ': ' + _serverPropValue + '\n'; + } - 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; - } + return properties; +} - return contextStackCursor$1.current; - } - } +function describeElementDiff(type, clientProps, serverProps, indent) { + var content = ''; // Maps any previously unmatched lower case server prop name to its full prop name - function cacheContext(workInProgress, unmaskedContext, maskedContext) { - { - var instance = workInProgress.stateNode; - instance.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext; - instance.__reactInternalMemoizedMaskedChildContext = maskedContext; - } + var serverPropNames = new Map(); + + for (var propName in serverProps) { + if (!serverProps.hasOwnProperty(propName)) { + continue; } - function getMaskedContext(workInProgress, unmaskedContext) { - { - var type = workInProgress.type; - var contextTypes = type.contextTypes; + serverPropNames.set(propName.toLowerCase(), propName); + } - 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. + if (serverPropNames.size === 1 && serverPropNames.has('children')) { + content += describeExpandedElement(type, clientProps, indentation(indent)); + } else { + for (var _propName2 in clientProps) { + if (!clientProps.hasOwnProperty(_propName2)) { + continue; + } - var instance = workInProgress.stateNode; + if (_propName2 === 'children') { + // Handled below. + continue; + } - if ( - instance && - instance.__reactInternalMemoizedUnmaskedChildContext === - unmaskedContext - ) { - return instance.__reactInternalMemoizedMaskedChildContext; - } + var maxLength = maxRowLength - (indent + 1) * 2 - _propName2.length - 1; + var serverPropName = serverPropNames.get(_propName2.toLowerCase()); - var context = {}; + if (serverPropName !== undefined) { + serverPropNames.delete(_propName2.toLowerCase()); // There's a diff here. - for (var key in contextTypes) { - context[key] = unmaskedContext[key]; - } // 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. + var clientValue = clientProps[_propName2]; + var serverValue = serverProps[serverPropName]; + var clientPropValue = describePropValue(clientValue, maxLength); + var serverPropValue = describePropValue(serverValue, maxLength); - if (instance) { - cacheContext(workInProgress, unmaskedContext, context); + if (typeof clientValue === 'object' && clientValue !== null && typeof serverValue === 'object' && serverValue !== null && objectName(clientValue) === 'Object' && objectName(serverValue) === 'Object' && ( // Only do the diff if the object has a lot of keys or was shortened. + Object.keys(clientValue).length > 2 || Object.keys(serverValue).length > 2 || clientPropValue.indexOf('...') > -1 || serverPropValue.indexOf('...') > -1)) { + // We're comparing two plain objects. We can diff the nested objects instead. + content += indentation(indent + 1) + _propName2 + '={{\n' + describePropertiesDiff(clientValue, serverValue, indent + 2) + indentation(indent + 1) + '}}\n'; + } else { + content += added(indent + 1) + _propName2 + '=' + clientPropValue + '\n'; + content += removed(indent + 1) + _propName2 + '=' + serverPropValue + '\n'; } - - return context; + } else { + // Considered equal. + content += indentation(indent + 1) + _propName2 + '=' + describePropValue(clientProps[_propName2], maxLength) + '\n'; } } - function hasContextChanged() { - { - return didPerformWorkStackCursor.current; + serverPropNames.forEach(function (propName) { + if (propName === 'children') { + // Handled below. + return; } - } - function isContextProvider(type) { - { - var childContextTypes = type.childContextTypes; - return childContextTypes !== null && childContextTypes !== undefined; - } - } + var maxLength = maxRowLength - (indent + 1) * 2 - propName.length - 1; + content += removed(indent + 1) + propName + '=' + describePropValue(serverProps[propName], maxLength) + '\n'; + }); - function popContext(fiber) { - { - pop(didPerformWorkStackCursor, fiber); - pop(contextStackCursor$1, fiber); - } + if (content === '') { + // No properties + content = indentation(indent) + '<' + type + '>\n'; + } else { + // Had properties + content = indentation(indent) + '<' + type + '\n' + content + indentation(indent) + '>\n'; } + } - function popTopLevelContextObject(fiber) { - { - pop(didPerformWorkStackCursor, fiber); - pop(contextStackCursor$1, fiber); - } - } + var serverChildren = serverProps.children; + var clientChildren = clientProps.children; - 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." - ); - } + if (typeof serverChildren === 'string' || typeof serverChildren === 'number' || typeof serverChildren === 'bigint') { + // There's a diff of the children. + // $FlowFixMe[unsafe-addition] + var serverText = '' + serverChildren; + var clientText = ''; - push(contextStackCursor$1, context, fiber); - push(didPerformWorkStackCursor, didChange, fiber); - } + if (typeof clientChildren === 'string' || typeof clientChildren === 'number' || typeof clientChildren === 'bigint') { + // $FlowFixMe[unsafe-addition] + clientText = '' + clientChildren; } - 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 (typeof instance.getChildContext !== "function") { - { - var componentName = getComponentNameFromFiber(fiber) || "Unknown"; - - if (!warnedAboutMissingGetChildContext[componentName]) { - warnedAboutMissingGetChildContext[componentName] = true; - - 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; - } - - var childContext = instance.getChildContext(); - - for (var contextKey in childContext) { - if (!(contextKey in childContextTypes)) { - throw new Error( - (getComponentNameFromFiber(fiber) || "Unknown") + - '.getChildContext(): key "' + - contextKey + - '" is not defined in childContextTypes.' - ); - } - } + content += describeTextDiff(clientText, serverText, indent + 1); + } else if (typeof clientChildren === 'string' || typeof clientChildren === 'number' || typeof clientChildren === 'bigint') { + // The client has children but it's not considered a difference from the server. + // $FlowFixMe[unsafe-addition] + content += describeTextDiff('' + clientChildren, undefined, indent + 1); + } - return assign({}, parentContext, childContext); - } - } + return content; +} - 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 describeSiblingFiber(fiber, indent) { + var type = describeFiberType(fiber); - function invalidateContextProvider(workInProgress, type, didChange) { - { - var instance = workInProgress.stateNode; + if (type === null) { + // Skip this type of fiber. We currently treat this as a fragment + // so it's just part of the parent's children. + var flatContent = ''; + var childFiber = fiber.child; - 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); - } - } + while (childFiber) { + flatContent += describeSiblingFiber(childFiber, indent); + childFiber = childFiber.sibling; } - 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." - ); - } + return flatContent; + } - var node = fiber; + return indentation(indent) + '<' + type + '>' + '\n'; +} - do { - switch (node.tag) { - case HostRoot: - return node.stateNode.context; +function describeNode(node, indent) { + var skipToNode = findNotableNode(node, indent); - case ClassComponent: { - var Component = node.type; + if (skipToNode !== node && (node.children.length !== 1 || node.children[0] !== skipToNode)) { + return indentation(indent) + '...\n' + describeNode(skipToNode, indent + 1); + } // Prefix with any server components for context - if (isContextProvider(Component)) { - return node.stateNode.__reactInternalMemoizedMergedChildContext; - } - break; - } - } // $FlowFixMe[incompatible-type] we bail out when we get a null + var parentContent = ''; + var debugInfo = node.fiber._debugInfo; - node = node.return; - } while (node !== null); + if (debugInfo) { + for (var i = 0; i < debugInfo.length; i++) { + var serverComponentName = debugInfo[i].name; - throw new Error( - "Found unexpected detached subtree parent. " + - "This error is likely caused by a bug in React. Please file an issue." - ); + if (typeof serverComponentName === 'string') { + parentContent += indentation(indent) + '<' + serverComponentName + '>' + '\n'; + indent++; } } + } // Self - // 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" - ); - } - /** - * 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 - ); - } + var selfContent = ''; // We use the pending props since we might be generating a diff before the complete phase + // when something throws. - var objectIs = typeof Object.is === "function" ? Object.is : is; // $FlowFixMe[method-unbinding] + var clientProps = node.fiber.pendingProps; - var prefix; - function describeBuiltInComponentFrame(name) { - if (enableComponentStackLocations) { - if (prefix === undefined) { - // Extract the VM specific prefix used by each line. - try { - throw Error(); - } catch (x) { - var match = x.stack.trim().match(/\n( *(at )?)/); - prefix = (match && match[1]) || ""; - } - } // We use the prefix to ensure our stacks line up with native stack frames. + if (node.fiber.tag === HostText) { + // Text Node + selfContent = describeTextDiff(clientProps, node.serverProps, indent); + } else { + var type = describeFiberType(node.fiber); - return "\n" + prefix + name; + if (type !== null) { + // Element Node + if (node.serverProps === undefined) { + // Just a reference node for context. + selfContent = describeCollapsedElement(type, clientProps, indent); + indent++; + } else if (node.serverProps === null) { + selfContent = describeExpandedElement(type, clientProps, added(indent)); // If this was an insertion we won't step down further. Any tail + // are considered siblings so we don't indent. + // TODO: Model this a little better. + } else if (typeof node.serverProps === 'string') { + { + error('Should not have matched a non HostText fiber to a Text node. This is a bug in React.'); + } } else { - return describeComponentFrame(name); + selfContent = describeElementDiff(type, clientProps, node.serverProps, indent); + indent++; } } - function describeDebugInfoFrame(name, env) { - return describeBuiltInComponentFrame( - name + (env ? " (" + env + ")" : "") - ); - } - var reentry = false; - var componentFrameCache; - - { - var PossiblyWeakMap$1 = typeof WeakMap === "function" ? WeakMap : Map; - componentFrameCache = new PossiblyWeakMap$1(); - } - /** - * Leverages native browser/VM stack frames to get proper details (e.g. - * filename, line + col number) for a single component in a component stack. We - * do this by: - * (1) throwing and catching an error in the function - this will be our - * control error. - * (2) calling the component which will eventually throw an error that we'll - * catch - this will be our sample error. - * (3) diffing the control and sample error stacks to find the stack frame - * which represents our component. - */ + } // Compute children - function describeNativeComponentFrame(fn, construct) { - // If something asked for a stack inside a fake render, it should get ignored. - if (!fn || reentry) { - return ""; - } - { - var frame = componentFrameCache.get(fn); + var childContent = ''; + var childFiber = node.fiber.child; + var diffIdx = 0; - if (frame !== undefined) { - return frame; - } - } + while (childFiber && diffIdx < node.children.length) { + var childNode = node.children[diffIdx]; - reentry = true; - var previousPrepareStackTrace = Error.prepareStackTrace; // $FlowFixMe[incompatible-type] It does accept undefined. + if (childNode.fiber === childFiber) { + // This was a match in the diff. + childContent += describeNode(childNode, indent); + diffIdx++; + } else { + // This is an unrelated previous sibling. + childContent += describeSiblingFiber(childFiber, indent); + } - Error.prepareStackTrace = undefined; - var previousDispatcher = null; + childFiber = childFiber.sibling; + } - { - previousDispatcher = ReactSharedInternals.H; // Set the dispatcher in DEV because this might be call in the render function - // for warnings. - - ReactSharedInternals.H = null; - disableLogs(); - } - /** - * Finding a common stack frame between sample and control errors can be - * tricky given the different types and levels of stack trace truncation from - * different JS VMs. So instead we'll attempt to control what that common - * frame should be through this object method: - * Having both the sample and control errors be in the function under the - * `DescribeNativeComponentFrameRoot` property, + setting the `name` and - * `displayName` properties of the function ensures that a stack - * frame exists that has the method name `DescribeNativeComponentFrameRoot` in - * it for both control and sample stacks. - */ - - var RunInRootFrame = { - DetermineComponentFrameRoot: function () { - var control; + if (childFiber && node.children.length > 0) { + // If we had any further siblings after the last mismatch, we can't be sure if it's + // actually a valid match since it might not have found a match. So we exclude next + // siblings to avoid confusion. + childContent += indentation(indent) + '...' + '\n'; + } // Deleted tail nodes - try { - // This should throw. - if (construct) { - // Something should be setting the props in the constructor. - var Fake = function () { - throw Error(); - }; // $FlowFixMe[prop-missing] - - Object.defineProperty(Fake.prototype, "props", { - set: function () { - // We use a throwing setter instead of frozen or non-writable props - // because that won't throw in a non-strict mode function. - throw Error(); - } - }); - - if (typeof Reflect === "object" && Reflect.construct) { - // We construct a different control for this case to include any extra - // frames added by the construct call. - try { - Reflect.construct(Fake, []); - } catch (x) { - control = x; - } - Reflect.construct(fn, [], Fake); - } else { - try { - Fake.call(); - } catch (x) { - control = x; - } // $FlowFixMe[prop-missing] found when upgrading Flow + var serverTail = node.serverTail; - fn.call(Fake.prototype); - } - } else { - try { - throw Error(); - } catch (x) { - control = x; - } // TODO(luna): This will currently only throw if the function component - // tries to access React/ReactDOM/props. We should probably make this throw - // in simple components too - - var maybePromise = fn(); // If the function component returns a promise, it's likely an async - // component, which we don't yet support. Attach a noop catch handler to - // silence the error. - // TODO: Implement component stacks for async client components? - - if (maybePromise && typeof maybePromise.catch === "function") { - maybePromise.catch(function () {}); - } - } - } catch (sample) { - // This is inlined manually because closure doesn't do it for us. - if (sample && control && typeof sample.stack === "string") { - return [sample.stack, control.stack]; - } - } + for (var _i = 0; _i < serverTail.length; _i++) { + var tailNode = serverTail[_i]; - return [null, null]; - } - }; // $FlowFixMe[prop-missing] + if (typeof tailNode === 'string') { + // Removed text node + childContent += removed(indent) + describeTextNode(tailNode, maxRowLength - indent * 2) + '\n'; + } else { + // Removed element + childContent += describeExpandedElement(tailNode.type, tailNode.props, removed(indent)); + } + } - RunInRootFrame.DetermineComponentFrameRoot.displayName = - "DetermineComponentFrameRoot"; - var namePropDescriptor = Object.getOwnPropertyDescriptor( - RunInRootFrame.DetermineComponentFrameRoot, - "name" - ); // Before ES6, the `name` property was not configurable. + return parentContent + selfContent + childContent; +} - if (namePropDescriptor && namePropDescriptor.configurable) { - // V8 utilizes a function's `name` property when generating a stack trace. - Object.defineProperty( - RunInRootFrame.DetermineComponentFrameRoot, // Configurable properties can be updated even if its writable descriptor - // is set to `false`. - // $FlowFixMe[cannot-write] - "name", - { - value: "DetermineComponentFrameRoot" - } - ); - } +function describeDiff(rootNode) { + try { + return '\n\n' + describeNode(rootNode, 0); + } catch (x) { + return ''; + } +} - try { - var _RunInRootFrame$Deter = - RunInRootFrame.DetermineComponentFrameRoot(), - sampleStack = _RunInRootFrame$Deter[0], - controlStack = _RunInRootFrame$Deter[1]; - - if (sampleStack && controlStack) { - // This extracts the first frame from the sample that isn't also in the control. - // Skipping one frame that we assume is the frame that calls the two. - var sampleLines = sampleStack.split("\n"); - var controlLines = controlStack.split("\n"); - var s = 0; - var c = 0; - - while ( - s < sampleLines.length && - !sampleLines[s].includes("DetermineComponentFrameRoot") - ) { - s++; - } +var isHydrating = false; // This flag allows for warning supression when we expect there to be mismatches - while ( - c < controlLines.length && - !controlLines[c].includes("DetermineComponentFrameRoot") - ) { - c++; - } // We couldn't find our intentionally injected common root frame, attempt - // to find another common root frame by search from the bottom of the - // control stack... - - if (s === sampleLines.length || c === controlLines.length) { - s = sampleLines.length - 1; - c = controlLines.length - 1; - - while (s >= 1 && c >= 0 && sampleLines[s] !== controlLines[c]) { - // We expect at least one stack frame to be shared. - // Typically this will be the root most one. However, stack frames may be - // cut off due to maximum stack limits. In this case, one maybe cut off - // earlier than the other. We assume that the sample is longer or the same - // and there for cut off earlier. So we should find the root most frame in - // the sample somewhere in the control. - c--; - } - } +var hydrationDiffRootDEV = null; // Hydration errors that were thrown inside this boundary - for (; s >= 1 && c >= 0; s--, c--) { - // Next we find the first one that isn't the same which should be the - // frame that called our sample function and the control. - if (sampleLines[s] !== controlLines[c]) { - // In V8, the first line is describing the message but other VMs don't. - // If we're about to return the first line, and the control is also on the same - // line, that's a pretty good indicator that our sample threw at same line as - // the control. I.e. before we entered the sample frame. So we ignore this result. - // This can happen if you passed a class to function component, or non-function. - if (s !== 1 || c !== 1) { - do { - s--; - c--; // We may still have similar intermediate frames from the construct call. - // The next one that isn't the same should be our match though. - - if (c < 0 || sampleLines[s] !== controlLines[c]) { - // V8 adds a "new" prefix for native classes. Let's remove it to make it prettier. - var _frame = - "\n" + sampleLines[s].replace(" at new ", " at "); // If our component frame is labeled "" - // but we have a user-provided "displayName" - // splice it in to make the stack more readable. - - if (fn.displayName && _frame.includes("")) { - _frame = _frame.replace("", fn.displayName); - } +var hydrationErrors = null; - if (true) { - if (typeof fn === "function") { - componentFrameCache.set(fn, _frame); - } - } // Return the line we found. +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.'); + } +} - return _frame; - } - } while (s >= 1 && c >= 0); - } +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.'); + } +} - break; - } - } - } - } finally { - reentry = false; +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.'); + } +} - { - ReactSharedInternals.H = previousDispatcher; - reenableLogs(); - } +function popHydrationState(fiber) { + { + return false; + } +} - Error.prepareStackTrace = previousPrepareStackTrace; - } // Fallback to just using the name if we couldn't make it throw. +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; + } +} - var name = fn ? fn.displayName || fn.name : ""; - var syntheticFrame = name ? describeBuiltInComponentFrame(name) : ""; +function getIsHydrating() { + return isHydrating; +} - { - if (typeof fn === "function") { - componentFrameCache.set(fn, syntheticFrame); - } - } +function queueHydrationError(error) { + if (hydrationErrors === null) { + hydrationErrors = [error]; + } else { + hydrationErrors.push(error); + } +} +function emitPendingHydrationWarnings() { + { + // If we haven't yet thrown any hydration errors by the time we reach the end we've successfully + // hydrated, however, we might still have DEV-only mismatches that we log now. + var diffRoot = hydrationDiffRootDEV; - return syntheticFrame; - } + if (diffRoot !== null) { + hydrationDiffRootDEV = null; + var diff = describeDiff(diffRoot); - function describeComponentFrame(name) { - return "\n in " + (name || "Unknown"); + error("A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. " + 'This can happen if a SSR-ed Client Component used:\n' + '\n' + "- A server/client branch `if (typeof window !== 'undefined')`.\n" + "- Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.\n" + "- Date formatting in a user's locale which doesn't match the server.\n" + '- External changing data without sending a snapshot of it along with the HTML.\n' + '- Invalid HTML tag nesting.\n' + '\n' + 'It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.\n' + '\n' + '%s%s', 'https://react.dev/link/hydration-mismatch', diff); } + } +} + +// 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 concurrentQueues = []; +var concurrentQueuesIndex = 0; +var concurrentlyUpdatedLanes = NoLanes; +function finishQueueingConcurrentUpdates() { + var endIndex = concurrentQueuesIndex; + concurrentQueuesIndex = 0; + concurrentlyUpdatedLanes = NoLanes; + var i = 0; + + 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; - function describeClassComponentFrame(ctor) { - if (enableComponentStackLocations) { - return describeNativeComponentFrame(ctor, true); + if (pending === null) { + // This is the first update. Create a circular list. + update.next = update; } else { - return describeFunctionComponentFrame(ctor); + update.next = pending.next; + pending.next = update; } + + queue.pending = update; } - function describeFunctionComponentFrame(fn) { - if (enableComponentStackLocations) { - return describeNativeComponentFrame(fn, false); - } else { - if (!fn) { - return ""; - } - var name = fn.displayName || fn.name || null; - return describeComponentFrame(name); - } + if (lane !== NoLane) { + markUpdateLaneFromFiberToRoot(fiber, update, lane); } + } +} +function getConcurrentlyUpdatedLanes() { + return concurrentlyUpdatedLanes; +} - function describeFiber(fiber) { - switch (fiber.tag) { - case HostHoistable: - case HostSingleton: - case HostComponent: - return describeBuiltInComponentFrame(fiber.type); +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. + + fiber.lanes = mergeLanes(fiber.lanes, lane); + var alternate = fiber.alternate; + + if (alternate !== null) { + alternate.lanes = mergeLanes(alternate.lanes, lane); + } +} - case LazyComponent: - return describeBuiltInComponentFrame("Lazy"); +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; + + 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. + +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; +} - case SuspenseComponent: - return describeBuiltInComponentFrame("Suspense"); +function markUpdateLaneFromFiberToRoot(sourceFiber, update, lane) { + // Update the source fiber's lanes + sourceFiber.lanes = mergeLanes(sourceFiber.lanes, lane); + var alternate = sourceFiber.alternate; - case SuspenseListComponent: - return describeBuiltInComponentFrame("SuspenseList"); + if (alternate !== null) { + alternate.lanes = mergeLanes(alternate.lanes, lane); + } // Walk the parent path to the root and update the child lanes. - case FunctionComponent: - case SimpleMemoComponent: - return describeFunctionComponentFrame(fiber.type); - case ForwardRef: - return describeFunctionComponentFrame(fiber.type.render); + var isHidden = false; + var parent = sourceFiber.return; + var node = sourceFiber; - case ClassComponent: - return describeClassComponentFrame(fiber.type); + while (parent !== null) { + parent.childLanes = mergeLanes(parent.childLanes, lane); + alternate = parent.alternate; - default: - return ""; - } + if (alternate !== null) { + alternate.childLanes = mergeLanes(alternate.childLanes, lane); } - function getStackByFiberInDevAndProd(workInProgress) { - try { - var info = ""; - var node = workInProgress; + 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; - do { - info += describeFiber(node); + if (offscreenInstance !== null && !(offscreenInstance._visibility & OffscreenVisible)) { + isHidden = true; + } + } - if (true) { - // Add any Server Component stack frames in reverse order. - var debugInfo = node._debugInfo; + node = parent; + parent = parent.return; + } - if (debugInfo) { - for (var i = debugInfo.length - 1; i >= 0; i--) { - var entry = debugInfo[i]; + if (isHidden && update !== null && node.tag === HostRoot) { + var root = node.stateNode; + markHiddenUpdate(root, update, lane); + } +} - if (typeof entry.name === "string") { - info += describeDebugInfoFrame(entry.name, entry.env); - } - } - } - } // $FlowFixMe[incompatible-type] we bail out when we get a null +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. + + detectUpdateOnUnmountedFiber(sourceFiber, sourceFiber); + var node = sourceFiber; + var parent = node.return; + + while (parent !== null) { + detectUpdateOnUnmountedFiber(sourceFiber, node); + node = parent; + parent = node.return; + } + + return node.tag === HostRoot ? node.stateNode : null; +} - node = node.return; - } while (node); +function detectUpdateOnUnmountedFiber(sourceFiber, parent) { + { + var alternate = parent.alternate; - return info; - } catch (x) { - return "\nError generating stack: " + x.message + "\n" + x.stack; - } + if (alternate === null && (parent.flags & (Placement | Hydrating)) !== NoFlags$1) { + warnAboutUpdateOnNotYetMountedFiberInDEV(sourceFiber); } + } +} - var CapturedStacks = new WeakMap(); - function createCapturedValueAtFiber(value, source) { - // If the value is an error, call this function immediately after it is thrown - // so the stack is accurate. - var stack; +// there's only a single root, but we do support multi root apps, hence this +// extra complexity. But this module is optimized for the single root case. + +var firstScheduledRoot = null; +var lastScheduledRoot = null; // Used to prevent redundant mircotasks from being scheduled. + +var didScheduleMicrotask = false; // `act` "microtasks" are scheduled on the `act` queue instead of an actual +// microtask, so we have to dedupe those separately. This wouldn't be an issue +// if we required all `act` calls to be awaited, which we might in the future. + +var didScheduleMicrotask_act = false; // Used to quickly bail out of flushSync if there's no sync work to do. + +var mightHavePendingSyncWork = false; +var isFlushingWork = false; +var currentEventTransitionLane = NoLane; +function ensureRootIsScheduled(root) { + // This function is called whenever a root receives an update. It does two + // things 1) it ensures the root is in the root schedule, and 2) it ensures + // there's a pending microtask to process the root schedule. + // + // Most of the actual scheduling logic does not happen until + // `scheduleTaskForRootDuringMicrotask` runs. + // Add the root to the schedule + if (root === lastScheduledRoot || root.next !== null) ; else { + if (lastScheduledRoot === null) { + firstScheduledRoot = lastScheduledRoot = root; + } else { + lastScheduledRoot.next = root; + lastScheduledRoot = root; + } + } // Any time a root received an update, we set this to true until the next time + // we process the schedule. If it's false, then we can quickly exit flushSync + // without consulting the schedule. + + + mightHavePendingSyncWork = true; // At the end of the current event, go through each of the roots and ensure + // there's a task scheduled for each one at the correct priority. + + if (ReactSharedInternals.actQueue !== null) { + // We're inside an `act` scope. + if (!didScheduleMicrotask_act) { + didScheduleMicrotask_act = true; + scheduleImmediateTask(processRootScheduleInMicrotask); + } + } else { + if (!didScheduleMicrotask) { + didScheduleMicrotask = true; + scheduleImmediateTask(processRootScheduleInMicrotask); + } + } + + if (!enableDeferRootSchedulingToMicrotask) { + // While this flag is disabled, we schedule the render task immediately + // instead of waiting a microtask. + // TODO: We need to land enableDeferRootSchedulingToMicrotask ASAP to + // unblock additional features we have planned. + scheduleTaskForRootDuringMicrotask(root, now$1()); + } + + if (ReactSharedInternals.isBatchingLegacy && root.tag === LegacyRoot) { + // Special `act` case: Record whenever a legacy update is scheduled. + ReactSharedInternals.didScheduleLegacyUpdate = true; + } +} +function flushSyncWorkOnAllRoots() { + // This is allowed to be called synchronously, but the caller should check + // the execution context first. + flushSyncWorkAcrossRoots_impl(false); +} +function flushSyncWorkOnLegacyRootsOnly() { + // This is allowed to be called synchronously, but the caller should check + // the execution context first. + { + flushSyncWorkAcrossRoots_impl(true); + } +} - if (typeof value === "object" && value !== null) { - var capturedStack = CapturedStacks.get(value); +function flushSyncWorkAcrossRoots_impl(onlyLegacy) { + if (isFlushingWork) { + // Prevent reentrancy. + // TODO: Is this overly defensive? The callers must check the execution + // context first regardless. + return; + } - if (typeof capturedStack === "string") { - stack = capturedStack; - } else { - stack = getStackByFiberInDevAndProd(source); - CapturedStacks.set(value, stack); - } - } else { - stack = getStackByFiberInDevAndProd(source); - } + if (!mightHavePendingSyncWork) { + // Fast path. There's no sync work to do. + return; + } // There may or may not be synchronous work scheduled. Let's check. - return { - value: value, - source: source, - stack: stack - }; - } - function createCapturedValueFromError(value, stack) { - if (typeof stack === "string") { - CapturedStacks.set(value, stack); - } - return { - value: value, - source: null, - stack: stack - }; - } + var didPerformSomeWork; + isFlushingWork = true; - var contextStackCursor = createCursor(null); - var contextFiberStackCursor = createCursor(null); - var rootInstanceStackCursor = createCursor(null); // Represents the nearest host transition provider (in React DOM, a ) - // NOTE: Since forms cannot be nested, and this feature is only implemented by - // React DOM, we don't technically need this to be a stack. It could be a single - // module variable instead. - - var hostTransitionProviderCursor = createCursor(null); // TODO: This should initialize to NotPendingTransition, a constant - // imported from the fiber config. However, because of a cycle in the module - // graph, that value isn't defined during this module's initialization. I can't - // think of a way to work around this without moving that value out of the - // fiber config. For now, the "no provider" case is handled when reading, - // inside useHostTransitionStatus. - - var HostTransitionContext = { - $$typeof: REACT_CONTEXT_TYPE, - Provider: null, - Consumer: null, - _currentValue: null, - _currentValue2: null, - _threadCount: 0 - }; + do { + didPerformSomeWork = false; + var root = firstScheduledRoot; - 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." - ); + while (root !== null) { + if (onlyLegacy && (root.tag !== LegacyRoot)) ; else { + var workInProgressRoot = getWorkInProgressRoot(); + var workInProgressRootRenderLanes = getWorkInProgressRootRenderLanes(); + var nextLanes = getNextLanes(root, root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes); + + if (includesSyncLane(nextLanes)) { + // This root has pending sync work. Flush it now. + didPerformSomeWork = true; + performSyncWorkOnRoot(root, nextLanes); } } - return c; + root = root.next; } + } while (didPerformSomeWork); - function getRootHostContainer() { - var rootInstance = requiredContext(rootInstanceStackCursor.current); - return rootInstance; - } + isFlushingWork = false; +} - 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. +function processRootScheduleInMicrotask() { + // This function is always called inside a microtask. It should never be + // called synchronously. + didScheduleMicrotask = false; - 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. + { + didScheduleMicrotask_act = false; + } // We'll recompute this as we iterate through all the roots and schedule them. - push(contextStackCursor, null, fiber); - var nextRootContext = getRootHostContext(); // Now that we know this function doesn't throw, replace it. - pop(contextStackCursor, fiber); - push(contextStackCursor, nextRootContext, fiber); - } + mightHavePendingSyncWork = false; + var currentTime = now$1(); + var prev = null; + var root = firstScheduledRoot; - function popHostContainer(fiber) { - pop(contextStackCursor, fiber); - pop(contextFiberStackCursor, fiber); - pop(rootInstanceStackCursor, fiber); - } + while (root !== null) { + var next = root.next; - function getHostContext() { - var context = requiredContext(contextStackCursor.current); - return context; + if (currentEventTransitionLane !== NoLane && shouldAttemptEagerTransition()) { + // A transition was scheduled during an event, but we're going to try to + // render it synchronously anyway. We do this during a popstate event to + // preserve the scroll position of the previous page. + upgradePendingLaneToSync(root, currentEventTransitionLane); } - function pushHostContext(fiber) { - if (enableAsyncActions) { - var stateHook = fiber.memoizedState; - - if (stateHook !== null) { - // Only provide context if this fiber has been upgraded by a host - // transition. We use the same optimization for regular host context below. - push(hostTransitionProviderCursor, fiber, fiber); - } - } + var nextLanes = scheduleTaskForRootDuringMicrotask(root, currentTime); - var context = requiredContext(contextStackCursor.current); - var nextContext = getChildHostContext(context, fiber.type); // Don't push this Fiber's context unless it's unique. + if (nextLanes === NoLane) { + // This root has no more pending work. Remove it from the schedule. To + // guard against subtle reentrancy bugs, this microtask is the only place + // we do this — you can add roots to the schedule whenever, but you can + // only remove them here. + // Null this out so we know it's been removed from the schedule. + root.next = null; - if (context !== nextContext) { - // 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); + if (prev === null) { + // This is the new head of the list + firstScheduledRoot = next; + } else { + prev.next = next; } - } - function popHostContext(fiber) { - if (contextFiberStackCursor.current === fiber) { - // Do not pop unless this Fiber provided the current context. - // pushHostContext() only pushes Fibers that provide unique contexts. - pop(contextStackCursor, fiber); - pop(contextFiberStackCursor, fiber); + if (next === null) { + // This is the new tail of the list + lastScheduledRoot = prev; } + } else { + // This root still has work. Keep it in the list. + prev = root; - if (enableAsyncActions) { - if (hostTransitionProviderCursor.current === fiber) { - // Do not pop unless this Fiber provided the current context. This is mostly - // a performance optimization, but conveniently it also prevents a potential - // data race where a host provider is upgraded (i.e. memoizedState becomes - // non-null) during a concurrent event. This is a bit of a flaw in the way - // we upgrade host components, but because we're accounting for it here, it - // should be fine. - pop(hostTransitionProviderCursor, fiber); // When popping the transition provider, we reset the context value back - // to `null`. We can do this because you're not allowd to nest forms. If - // we allowed for multiple nested host transition providers, then we'd - // need to reset this to the parent provider's status. - - { - HostTransitionContext._currentValue2 = null; - } - } + if (includesSyncLane(nextLanes)) { + mightHavePendingSyncWork = true; } } - var maxRowLength = 120; - var idealDepth = 15; - - function findNotableNode(node, indent) { - if ( - node.serverProps === undefined && - node.serverTail.length === 0 && - node.children.length === 1 && - node.distanceFromLeaf > 3 && - node.distanceFromLeaf > idealDepth - indent - ) { - // This is not an interesting node for contextual purposes so we can skip it. - var child = node.children[0]; - return findNotableNode(child, indent); - } + root = next; + } - return node; - } + currentEventTransitionLane = NoLane; // At the end of the microtask, flush any pending synchronous work. This has + // to come at the end, because it does actual rendering work that might throw. - function indentation(indent) { - return " " + " ".repeat(indent); - } + flushSyncWorkOnAllRoots(); +} - function added(indent) { - return "+ " + " ".repeat(indent); - } +function scheduleTaskForRootDuringMicrotask(root, currentTime) { + // This function is always called inside a microtask, or at the very end of a + // rendering task right before we yield to the main thread. It should never be + // called synchronously. + // + // TODO: Unless enableDeferRootSchedulingToMicrotask is off. We need to land + // that ASAP to unblock additional features we have planned. + // + // This function also never performs React work synchronously; it should + // only schedule work to be performed later, in a separate task or microtask. + // Check if any lanes are being starved by other work. If so, mark them as + // expired so we know to work on those next. + markStarvedLanesAsExpired(root, currentTime); // Determine the next lanes to work on, and their priority. + + var workInProgressRoot = getWorkInProgressRoot(); + var workInProgressRootRenderLanes = getWorkInProgressRootRenderLanes(); + var nextLanes = getNextLanes(root, root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes); + var existingCallbackNode = root.callbackNode; + + if ( // Check if there's nothing to work on + nextLanes === NoLanes || // 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. + // + // Suspended render phase + root === workInProgressRoot && isWorkLoopSuspendedOnData() || // Suspended commit phase + root.cancelPendingCommit !== null) { + // Fast path: There's nothing to work on. + if (existingCallbackNode !== null) { + cancelCallback(existingCallbackNode); + } + + root.callbackNode = null; + root.callbackPriority = NoLane; + return NoLane; + } // Schedule a new callback in the host environment. + + + if (includesSyncLane(nextLanes)) { + // Synchronous work is always flushed at the end of the microtask, so we + // don't need to schedule an additional task. + if (existingCallbackNode !== null) { + cancelCallback(existingCallbackNode); + } + + root.callbackPriority = SyncLane; + root.callbackNode = null; + return SyncLane; + } else { + // We use the highest priority lane to represent the priority of the callback. + var existingCallbackPriority = root.callbackPriority; + var newCallbackPriority = getHighestPriorityLane(nextLanes); + + if (newCallbackPriority === existingCallbackPriority && // Special case related to `act`. If the currently scheduled task is a + // Scheduler task, rather than an `act` task, cancel it and re-schedule + // on the `act` queue. + !(ReactSharedInternals.actQueue !== null && existingCallbackNode !== fakeActCallbackNode$1)) { + // The priority hasn't changed. We can reuse the existing task. + return newCallbackPriority; + } else { + // Cancel the existing callback. We'll schedule a new one below. + cancelCallback(existingCallbackNode); + } + + var schedulerPriorityLevel; + + switch (lanesToEventPriority(nextLanes)) { + case DiscreteEventPriority: + schedulerPriorityLevel = ImmediatePriority; + break; + + case ContinuousEventPriority: + schedulerPriorityLevel = UserBlockingPriority; + break; + + case DefaultEventPriority: + schedulerPriorityLevel = NormalPriority$1; + break; + + case IdleEventPriority: + schedulerPriorityLevel = IdlePriority; + break; + + default: + schedulerPriorityLevel = NormalPriority$1; + break; + } + + var newCallbackNode = scheduleCallback$2(schedulerPriorityLevel, performConcurrentWorkOnRoot.bind(null, root)); + root.callbackPriority = newCallbackPriority; + root.callbackNode = newCallbackNode; + return newCallbackPriority; + } +} - function removed(indent) { - return "- " + " ".repeat(indent); - } +function getContinuationForRoot(root, originalCallbackNode) { + // This is called at the end of `performConcurrentWorkOnRoot` to determine + // if we need to schedule a continuation task. + // + // Usually `scheduleTaskForRootDuringMicrotask` only runs inside a microtask; + // however, since most of the logic for determining if we need a continuation + // versus a new task is the same, we cheat a bit and call it here. This is + // only safe to do because we know we're at the end of the browser task. + // So although it's not an actual microtask, it might as well be. + scheduleTaskForRootDuringMicrotask(root, now$1()); + + 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); + } + + return null; +} +var fakeActCallbackNode$1 = {}; + +function scheduleCallback$2(priorityLevel, callback) { + if (ReactSharedInternals.actQueue !== null) { + // Special case: We're inside an `act` scope (a testing utility). + // Instead of scheduling work in the host environment, add it to a + // fake internal queue that's managed by the `act` implementation. + ReactSharedInternals.actQueue.push(callback); + return fakeActCallbackNode$1; + } else { + return scheduleCallback$3(priorityLevel, callback); + } +} - function describeFiberType(fiber) { - switch (fiber.tag) { - case HostHoistable: - case HostSingleton: - case HostComponent: - return fiber.type; +function cancelCallback(callbackNode) { + if (callbackNode === fakeActCallbackNode$1) ; else if (callbackNode !== null) { + cancelCallback$1(callbackNode); + } +} - case LazyComponent: - return "Lazy"; +function scheduleImmediateTask(cb) { + if (ReactSharedInternals.actQueue !== null) { + // Special case: Inside an `act` scope, we push microtasks to the fake `act` + // callback queue. This is because we currently support calling `act` + // without awaiting the result. The plan is to deprecate that, and require + // that you always await the result so that the microtasks have a chance to + // run. But it hasn't happened yet. + ReactSharedInternals.actQueue.push(function () { + cb(); + return null; + }); + } // TODO: Can we land supportsMicrotasks? Which environments don't support it? + // Alternatively, can we move this check to the host config? - case SuspenseComponent: - return "Suspense"; - case SuspenseListComponent: - return "SuspenseList"; + if (supportsMicrotasks) { + scheduleMicrotask(function () { + // In Safari, appending an iframe forces microtasks to run. + // https://github.com/facebook/react/issues/22459 + // We don't support running callbacks in the middle of render + // or commit so we need to check against that. + var executionContext = getExecutionContext(); - case FunctionComponent: - case SimpleMemoComponent: - var fn = fiber.type; - return fn.displayName || fn.name || null; + if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { + // Note that this would still prematurely flush the callbacks + // if this happens outside render or commit phase (e.g. in an event). + // Intentionally using a macrotask instead of a microtask here. This is + // wrong semantically but it prevents an infinite loop. The bug is + // Safari's, not ours, so we just do our best to not crash even though + // the behavior isn't completely correct. + scheduleCallback$3(ImmediatePriority, cb); + return; + } - case ForwardRef: - var render = fiber.type.render; - return render.displayName || render.name || null; + cb(); + }); + } else { + // If microtasks are not supported, use Scheduler. + scheduleCallback$3(ImmediatePriority, cb); + } +} - case ClassComponent: - var ctr = fiber.type; - return ctr.displayName || ctr.name || null; +function requestTransitionLane( // This argument isn't used, it's only here to encourage the caller to +// check that it's inside a transition before calling this function. +// TODO: Make this non-nullable. Requires a tweak to useOptimistic. +transition) { + // 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(); + } + + return currentEventTransitionLane; +} - default: - // Skip - return null; +// transition updates that occur while the async action is still in progress +// are treated as part of the action. +// +// The ideal behavior would be to treat each async function as an independent +// action. However, without a mechanism like AsyncContext, we can't tell which +// action an update corresponds to. So instead, we entangle them all into one. +// The listeners to notify once the entangled scope completes. + +var currentEntangledListeners = null; // The number of pending async actions in the entangled scope. + +var currentEntangledPendingCount = 0; // The transition lane shared by all updates in the entangled scope. + +var currentEntangledLane = NoLane; // A thenable that resolves when the entangled scope completes. It does not +// resolve to a particular value because it's only used for suspending the UI +// until the async action scope has completed. + +var currentEntangledActionThenable = null; +function entangleAsyncAction(transition, thenable) { + // `thenable` is the return value of the async action scope function. Create + // a combined thenable that resolves once every entangled scope function + // has finished. + if (currentEntangledListeners === null) { + // There's no outer async action scope. Create a new one. + var entangledListeners = currentEntangledListeners = []; + currentEntangledPendingCount = 0; + currentEntangledLane = requestTransitionLane(); + var entangledThenable = { + status: 'pending', + value: undefined, + then: function (resolve) { + entangledListeners.push(resolve); } - } - - var needsEscaping = /["'&<>\n\t]/; + }; + currentEntangledActionThenable = entangledThenable; + } - function describeTextNode(content, maxLength) { - if (needsEscaping.test(content)) { - var encoded = JSON.stringify(content); + currentEntangledPendingCount++; + thenable.then(pingEngtangledActionScope, pingEngtangledActionScope); + return thenable; +} - if (encoded.length > maxLength - 2) { - if (maxLength < 8) { - return '{"..."}'; - } +function pingEngtangledActionScope() { + if (currentEntangledListeners !== null && --currentEntangledPendingCount === 0) { + // All the actions have finished. Close the entangled async action scope + // and notify all the listeners. + if (currentEntangledActionThenable !== null) { + var fulfilledThenable = currentEntangledActionThenable; + fulfilledThenable.status = 'fulfilled'; + } - return "{" + encoded.slice(0, maxLength - 7) + '..."}'; - } + var listeners = currentEntangledListeners; + currentEntangledListeners = null; + currentEntangledLane = NoLane; + currentEntangledActionThenable = null; - return "{" + encoded + "}"; - } else { - if (content.length > maxLength) { - if (maxLength < 5) { - return '{"..."}'; - } + for (var i = 0; i < listeners.length; i++) { + var listener = listeners[i]; + listener(); + } + } +} - return content.slice(0, maxLength - 3) + "..."; - } +function chainThenableValue(thenable, result) { + // Equivalent to: Promise.resolve(thenable).then(() => result), except we can + // cheat a bit since we know that that this thenable is only ever consumed + // by React. + // + // We don't technically require promise support on the client yet, hence this + // extra code. + var listeners = []; + var thenableWithOverride = { + status: 'pending', + value: null, + reason: null, + then: function (resolve) { + listeners.push(resolve); + } + }; + thenable.then(function (value) { + var fulfilledThenable = thenableWithOverride; + fulfilledThenable.status = 'fulfilled'; + fulfilledThenable.value = result; + + for (var i = 0; i < listeners.length; i++) { + var listener = listeners[i]; + listener(result); + } + }, function (error) { + var rejectedThenable = thenableWithOverride; + rejectedThenable.status = 'rejected'; + rejectedThenable.reason = error; + + for (var i = 0; i < listeners.length; i++) { + var listener = listeners[i]; // This is a perf hack where we call the `onFulfill` ping function + // instead of `onReject`, because we know that React is the only + // consumer of these promises, and it passes the same listener to both. + // We also know that it will read the error directly off the + // `.reason` field. + + listener(undefined); + } + }); + return thenableWithOverride; +} +function peekEntangledActionLane() { + return currentEntangledLane; +} +function peekEntangledActionThenable() { + return currentEntangledActionThenable; +} - return content; - } - } +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`. - function describeTextDiff(clientText, serverProps, indent) { - var maxLength = maxRowLength - indent * 2; +var hasForceUpdate = false; +var didWarnUpdateInsideUpdate; +var currentlyProcessingQueue; - if (serverProps === null) { - return added(indent) + describeTextNode(clientText, maxLength) + "\n"; - } else if (typeof serverProps === "string") { - var serverText = serverProps; - var firstDiff = 0; +{ + didWarnUpdateInsideUpdate = false; + currentlyProcessingQueue = null; +} - for ( - ; - firstDiff < serverText.length && firstDiff < clientText.length; - firstDiff++ - ) { - if ( - serverText.charCodeAt(firstDiff) !== - clientText.charCodeAt(firstDiff) - ) { - break; - } - } +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 (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; - if (firstDiff > maxLength - 8 && firstDiff > 10) { - // The first difference between the two strings would be cut off, so cut off in - // the beginning instead. - clientText = "..." + clientText.slice(firstDiff - 8); - serverText = "..." + serverText.slice(firstDiff - 8); - } + if (updateQueue === null) { + // Only occurs if the fiber has been unmounted. + return null; + } - return ( - added(indent) + - describeTextNode(clientText, maxLength) + - "\n" + - removed(indent) + - describeTextNode(serverText, maxLength) + - "\n" - ); - } else { - return ( - indentation(indent) + describeTextNode(clientText, maxLength) + "\n" - ); - } - } + var sharedQueue = updateQueue.shared; - function objectName(object) { - // $FlowFixMe[method-unbinding] - var name = Object.prototype.toString.call(object); - return name.replace(/^\[object (.*)\]$/, function (m, p0) { - return p0; - }); - } + { + if (currentlyProcessingQueue === sharedQueue && !didWarnUpdateInsideUpdate) { + var componentName = getComponentNameFromFiber(fiber); - function describeValue(value, maxLength) { - switch (typeof value) { - case "string": { - var encoded = JSON.stringify(value); + 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 (encoded.length > maxLength) { - if (maxLength < 5) { - return '"..."'; - } + didWarnUpdateInsideUpdate = true; + } + } - return encoded.slice(0, maxLength - 4) + '..."'; - } + 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 encoded; - } + if (pending === null) { + // This is the first update. Create a circular list. + update.next = update; + } else { + update.next = pending.next; + pending.next = update; + } - case "object": { - if (value === null) { - return "null"; - } + 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). - if (isArray(value)) { - return "[...]"; - } + return unsafe_markUpdateLaneFromFiberToRoot(fiber, lane); + } else { + return enqueueConcurrentClassUpdate(fiber, sharedQueue, update, lane); + } +} +function entangleTransitions(root, fiber, lane) { + var updateQueue = fiber.updateQueue; - if (value.$$typeof === REACT_ELEMENT_TYPE) { - var type = getComponentNameFromType(value.type); - return type ? "<" + type + ">" : "<...>"; - } + if (updateQueue === null) { + // Only occurs if the fiber has been unmounted. + return; + } - var name = objectName(value); + var sharedQueue = updateQueue.shared; - if (name === "Object") { - var properties = ""; - maxLength -= 2; + 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. - for (var propName in value) { - if (!value.hasOwnProperty(propName)) { - continue; - } + queueLanes = intersectLanes(queueLanes, root.pendingLanes); // Entangle the new transition lane with the other transition lanes. - var jsonPropName = JSON.stringify(propName); + 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 (jsonPropName !== '"' + propName + '"') { - propName = jsonPropName; - } + 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 current = workInProgress.alternate; + + if (current !== null) { + var currentQueue = current.updateQueue; + + 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; - maxLength -= propName.length - 2; - var propValue = describeValue( - value[propName], - maxLength < 15 ? maxLength : 15 - ); - maxLength -= propValue.length; + if (firstBaseUpdate !== null) { + // Loop through the updates and clone them. + var update = firstBaseUpdate; - if (maxLength < 0) { - properties += properties === "" ? "..." : ", ..."; - break; - } + 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 + }; - properties += - (properties === "" ? "" : ",") + propName + ":" + propValue; - } + if (newLast === null) { + newFirst = newLast = clone; + } else { + newLast.next = clone; + newLast = clone; + } // $FlowFixMe[incompatible-type] we bail out when we get a null - return "{" + properties + "}"; - } - return name; - } + update = update.next; + } while (update !== null); // Append the captured update the end of the cloned list. - case "function": { - var _name = value.displayName || value.name; - return _name ? "function " + _name : "function"; + if (newLast === null) { + newFirst = newLast = capturedUpdate; + } else { + newLast.next = capturedUpdate; + newLast = capturedUpdate; } - - default: - // eslint-disable-next-line react-internal/safe-string-coercion - return String(value); + } else { + // There are no base updates. + newFirst = newLast = capturedUpdate; } + + 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. - function describePropValue(value, maxLength) { - if (typeof value === "string" && !needsEscaping.test(value)) { - if (value.length > maxLength - 2) { - if (maxLength < 5) { - return '"..."'; - } - return '"' + value.slice(0, maxLength - 5) + '..."'; - } + var lastBaseUpdate = queue.lastBaseUpdate; - return '"' + value + '"'; - } + if (lastBaseUpdate === null) { + queue.firstBaseUpdate = capturedUpdate; + } else { + lastBaseUpdate.next = capturedUpdate; + } - return "{" + describeValue(value, maxLength - 2) + "}"; - } + queue.lastBaseUpdate = capturedUpdate; +} - function describeCollapsedElement(type, props, indent) { - // This function tries to fit the props into a single line for non-essential elements. - // We also ignore children because we're not going deeper. - var maxLength = maxRowLength - indent * 2 - type.length - 2; - var content = ""; +function getStateFromUpdate(workInProgress, queue, update, prevState, nextProps, instance) { + switch (update.tag) { + case ReplaceState: + { + var payload = update.payload; - for (var propName in props) { - if (!props.hasOwnProperty(propName)) { - continue; - } + if (typeof payload === 'function') { + // Updater function + { + enterDisallowedContextReadInDEV(); + } - if (propName === "children") { - // Ignored. - continue; - } + var nextState = payload.call(instance, prevState, nextProps); - var propValue = describePropValue(props[propName], 15); - maxLength -= propName.length + propValue.length + 2; + { + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); - if (maxLength < 0) { - content += " ..."; - break; - } + try { + payload.call(instance, prevState, nextProps); + } finally { + setIsStrictModeForDevtools(false); + } + } - content += " " + propName + "=" + propValue; - } + exitDisallowedContextReadInDEV(); + } - return indentation(indent) + "<" + type + content + ">\n"; - } + return nextState; + } // State object - function describeExpandedElement(type, props, rowPrefix) { - // This function tries to fit the props into a single line for non-essential elements. - // We also ignore children because we're not going deeper. - var remainingRowLength = maxRowLength - rowPrefix.length - type.length; // We add the properties to a set so we can choose later whether we'll put it on one - // line or multiple lines. - var properties = []; + return payload; + } - for (var propName in props) { - if (!props.hasOwnProperty(propName)) { - continue; - } + case CaptureUpdate: + { + workInProgress.flags = workInProgress.flags & ~ShouldCapture | DidCapture; + } + // Intentional fallthrough - if (propName === "children") { - // Ignored. - continue; - } + case UpdateState: + { + var _payload = update.payload; + var partialState; - var maxLength = maxRowLength - rowPrefix.length - propName.length - 1; - var propValue = describePropValue(props[propName], maxLength); - remainingRowLength -= propName.length + propValue.length + 2; - properties.push(propName + "=" + propValue); - } + if (typeof _payload === 'function') { + // Updater function + { + enterDisallowedContextReadInDEV(); + } - if (properties.length === 0) { - return rowPrefix + "<" + type + ">\n"; - } else if (remainingRowLength > 0) { - // We can fit all on one row. - return rowPrefix + "<" + type + " " + properties.join(" ") + ">\n"; - } else { - // Split into one row per property: - return ( - rowPrefix + - "<" + - type + - "\n" + - rowPrefix + - " " + - properties.join("\n" + rowPrefix + " ") + - "\n" + - rowPrefix + - ">\n" - ); - } - } - - function describePropertiesDiff(clientObject, serverObject, indent) { - var properties = ""; - var remainingServerProperties = assign({}, serverObject); - - for (var propName in clientObject) { - if (!clientObject.hasOwnProperty(propName)) { - continue; - } + partialState = _payload.call(instance, prevState, nextProps); - delete remainingServerProperties[propName]; - var maxLength = maxRowLength - indent * 2 - propName.length - 2; - var clientValue = clientObject[propName]; - var clientPropValue = describeValue(clientValue, maxLength); + { + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); - if (serverObject.hasOwnProperty(propName)) { - var serverValue = serverObject[propName]; - var serverPropValue = describeValue(serverValue, maxLength); - properties += - added(indent) + propName + ": " + clientPropValue + "\n"; - properties += - removed(indent) + propName + ": " + serverPropValue + "\n"; - } else { - properties += - added(indent) + propName + ": " + clientPropValue + "\n"; - } - } + try { + _payload.call(instance, prevState, nextProps); + } finally { + setIsStrictModeForDevtools(false); + } + } - for (var _propName in remainingServerProperties) { - if (!remainingServerProperties.hasOwnProperty(_propName)) { - continue; + exitDisallowedContextReadInDEV(); + } + } else { + // Partial state object + partialState = _payload; } - var _maxLength = maxRowLength - indent * 2 - _propName.length - 2; - - var _serverValue = remainingServerProperties[_propName]; + if (partialState === null || partialState === undefined) { + // Null and undefined are treated as no-ops. + return prevState; + } // Merge the partial state and the previous state. - var _serverPropValue = describeValue(_serverValue, _maxLength); - properties += - removed(indent) + _propName + ": " + _serverPropValue + "\n"; + return assign({}, prevState, partialState); } - return properties; - } + case ForceUpdate: + { + hasForceUpdate = true; + return prevState; + } + } - function describeElementDiff(type, clientProps, serverProps, indent) { - var content = ""; // Maps any previously unmatched lower case server prop name to its full prop name + return prevState; +} - var serverPropNames = new Map(); +var didReadFromEntangledAsyncAction = false; // Each call to processUpdateQueue should be accompanied by a call to this. It's +// only in a separate function because in updateHostRoot, it must happen after +// all the context stacks have been pushed to, to prevent a stack mismatch. A +// bit unfortunate. + +function suspendIfUpdateReadFromEntangledAsyncAction() { + // Check if this update is part of a pending async action. If so, we'll + // need to suspend until the action has finished, so that it's batched + // together with future updates in the same action. + // TODO: Once we support hooks inside useMemo (or an equivalent + // memoization boundary like Forget), hoist this logic so that it only + // suspends if the memo boundary produces a new value. + if (didReadFromEntangledAsyncAction) { + var entangledActionThenable = peekEntangledActionThenable(); + + if (entangledActionThenable !== null) { + // TODO: Instead of the throwing the thenable directly, throw a + // special object like `use` does so we can detect if it's captured + // by userspace. + throw entangledActionThenable; + } + } +} +function processUpdateQueue(workInProgress, props, instance, renderLanes) { + didReadFromEntangledAsyncAction = false; // This is always non-null on a ClassComponent or HostRoot - for (var propName in serverProps) { - if (!serverProps.hasOwnProperty(propName)) { - continue; - } + var queue = workInProgress.updateQueue; + hasForceUpdate = false; - serverPropNames.set(propName.toLowerCase(), propName); - } + { + currentlyProcessingQueue = queue.shared; + } - if (serverPropNames.size === 1 && serverPropNames.has("children")) { - content += describeExpandedElement( - type, - clientProps, - indentation(indent) - ); - } else { - for (var _propName2 in clientProps) { - if (!clientProps.hasOwnProperty(_propName2)) { - continue; - } + var firstBaseUpdate = queue.firstBaseUpdate; + var lastBaseUpdate = queue.lastBaseUpdate; // Check if there are pending updates. If so, transfer them to the base queue. - if (_propName2 === "children") { - // Handled below. - continue; - } + var pendingQueue = queue.shared.pending; - var maxLength = - maxRowLength - (indent + 1) * 2 - _propName2.length - 1; - var serverPropName = serverPropNames.get(_propName2.toLowerCase()); - - if (serverPropName !== undefined) { - serverPropNames.delete(_propName2.toLowerCase()); // There's a diff here. - - var clientValue = clientProps[_propName2]; - var serverValue = serverProps[serverPropName]; - var clientPropValue = describePropValue(clientValue, maxLength); - var serverPropValue = describePropValue(serverValue, maxLength); - - if ( - typeof clientValue === "object" && - clientValue !== null && - typeof serverValue === "object" && - serverValue !== null && - objectName(clientValue) === "Object" && - objectName(serverValue) === "Object" && // Only do the diff if the object has a lot of keys or was shortened. - (Object.keys(clientValue).length > 2 || - Object.keys(serverValue).length > 2 || - clientPropValue.indexOf("...") > -1 || - serverPropValue.indexOf("...") > -1) - ) { - // We're comparing two plain objects. We can diff the nested objects instead. - content += - indentation(indent + 1) + - _propName2 + - "={{\n" + - describePropertiesDiff(clientValue, serverValue, indent + 2) + - indentation(indent + 1) + - "}}\n"; - } else { - content += - added(indent + 1) + _propName2 + "=" + clientPropValue + "\n"; - content += - removed(indent + 1) + _propName2 + "=" + serverPropValue + "\n"; - } - } else { - // Considered equal. - content += - indentation(indent + 1) + - _propName2 + - "=" + - describePropValue(clientProps[_propName2], maxLength) + - "\n"; - } - } + 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. - serverPropNames.forEach(function (propName) { - if (propName === "children") { - // Handled below. - return; - } + var lastPendingUpdate = pendingQueue; + var firstPendingUpdate = lastPendingUpdate.next; + lastPendingUpdate.next = null; // Append pending updates to base queue - var maxLength = maxRowLength - (indent + 1) * 2 - propName.length - 1; - content += - removed(indent + 1) + - propName + - "=" + - describePropValue(serverProps[propName], maxLength) + - "\n"; - }); + if (lastBaseUpdate === null) { + firstBaseUpdate = firstPendingUpdate; + } else { + lastBaseUpdate.next = firstPendingUpdate; + } - if (content === "") { - // No properties - content = indentation(indent) + "<" + type + ">\n"; - } else { - // Had properties - content = - indentation(indent) + - "<" + - type + - "\n" + - content + - indentation(indent) + - ">\n"; - } - } + 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 - var serverChildren = serverProps.children; - var clientChildren = clientProps.children; + var current = workInProgress.alternate; - if ( - typeof serverChildren === "string" || - typeof serverChildren === "number" || - typeof serverChildren === "bigint" - ) { - // There's a diff of the children. - // $FlowFixMe[unsafe-addition] - var serverText = "" + serverChildren; - var clientText = ""; + if (current !== null) { + // This is always non-null on a ClassComponent or HostRoot + var currentQueue = current.updateQueue; + var currentLastBaseUpdate = currentQueue.lastBaseUpdate; - if ( - typeof clientChildren === "string" || - typeof clientChildren === "number" || - typeof clientChildren === "bigint" - ) { - // $FlowFixMe[unsafe-addition] - clientText = "" + clientChildren; + if (currentLastBaseUpdate !== lastBaseUpdate) { + if (currentLastBaseUpdate === null) { + currentQueue.firstBaseUpdate = firstPendingUpdate; + } else { + currentLastBaseUpdate.next = firstPendingUpdate; } - content += describeTextDiff(clientText, serverText, indent + 1); - } else if ( - typeof clientChildren === "string" || - typeof clientChildren === "number" || - typeof clientChildren === "bigint" - ) { - // The client has children but it's not considered a difference from the server. - // $FlowFixMe[unsafe-addition] - content += describeTextDiff("" + clientChildren, undefined, indent + 1); + currentQueue.lastBaseUpdate = lastPendingUpdate; } - - return content; } + } // These values may change as we process the queue. - function describeSiblingFiber(fiber, indent) { - var type = describeFiberType(fiber); - if (type === null) { - // Skip this type of fiber. We currently treat this as a fragment - // so it's just part of the parent's children. - var flatContent = ""; - var childFiber = fiber.child; + 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. - while (childFiber) { - flatContent += describeSiblingFiber(childFiber, indent); - childFiber = childFiber.sibling; - } + var newLanes = NoLanes; + var newBaseState = null; + var newFirstBaseUpdate = null; + var newLastBaseUpdate = null; + var update = firstBaseUpdate; - return flatContent; - } + 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. - return indentation(indent) + "<" + type + ">" + "\n"; - } + var shouldSkipUpdate = isHiddenUpdate ? !isSubsetOfLanes(getWorkInProgressRootRenderLanes(), updateLane) : !isSubsetOfLanes(renderLanes, updateLane); - function describeNode(node, indent) { - var skipToNode = findNotableNode(node, indent); + 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 + }; - if ( - skipToNode !== node && - (node.children.length !== 1 || node.children[0] !== skipToNode) - ) { - return ( - indentation(indent) + "...\n" + describeNode(skipToNode, indent + 1) - ); - } // Prefix with any server components for context + if (newLastBaseUpdate === null) { + newFirstBaseUpdate = newLastBaseUpdate = clone; + newBaseState = newState; + } else { + newLastBaseUpdate = newLastBaseUpdate.next = clone; + } // Update the remaining priority in the queue. - var parentContent = ""; - var debugInfo = node.fiber._debugInfo; - if (debugInfo) { - for (var i = 0; i < debugInfo.length; i++) { - var serverComponentName = debugInfo[i].name; + newLanes = mergeLanes(newLanes, updateLane); + } else { + // This update does have sufficient priority. + // Check if this update is part of a pending async action. If so, + // we'll need to suspend until the action has finished, so that it's + // batched together with future updates in the same action. + if (updateLane !== NoLane && updateLane === peekEntangledActionLane()) { + didReadFromEntangledAsyncAction = true; + } + + 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 (typeof serverComponentName === "string") { - parentContent += - indentation(indent) + "<" + serverComponentName + ">" + "\n"; - indent++; - } - } - } // Self - var selfContent = ""; // We use the pending props since we might be generating a diff before the complete phase - // when something throws. + newState = getStateFromUpdate(workInProgress, queue, update, newState, props, instance); + var callback = update.callback; - var clientProps = node.fiber.pendingProps; + if (callback !== null) { + workInProgress.flags |= Callback; - if (node.fiber.tag === HostText) { - // Text Node - selfContent = describeTextDiff(clientProps, node.serverProps, indent); - } else { - var type = describeFiberType(node.fiber); - - if (type !== null) { - // Element Node - if (node.serverProps === undefined) { - // Just a reference node for context. - selfContent = describeCollapsedElement(type, clientProps, indent); - indent++; - } else if (node.serverProps === null) { - selfContent = describeExpandedElement( - type, - clientProps, - added(indent) - ); // If this was an insertion we won't step down further. Any tail - // are considered siblings so we don't indent. - // TODO: Model this a little better. - } else if (typeof node.serverProps === "string") { - { - error( - "Should not have matched a non HostText fiber to a Text node. This is a bug in React." - ); - } - } else { - selfContent = describeElementDiff( - type, - clientProps, - node.serverProps, - indent - ); - indent++; + if (isHiddenUpdate) { + workInProgress.flags |= Visibility; } - } - } // Compute children - var childContent = ""; - var childFiber = node.fiber.child; - var diffIdx = 0; + var callbacks = queue.callbacks; - while (childFiber && diffIdx < node.children.length) { - var childNode = node.children[diffIdx]; - - if (childNode.fiber === childFiber) { - // This was a match in the diff. - childContent += describeNode(childNode, indent); - diffIdx++; - } else { - // This is an unrelated previous sibling. - childContent += describeSiblingFiber(childFiber, indent); + if (callbacks === null) { + queue.callbacks = [callback]; + } else { + callbacks.push(callback); + } } + } // $FlowFixMe[incompatible-type] we bail out when we get a null - childFiber = childFiber.sibling; - } - - if (childFiber && node.children.length > 0) { - // If we had any further siblings after the last mismatch, we can't be sure if it's - // actually a valid match since it might not have found a match. So we exclude next - // siblings to avoid confusion. - childContent += indentation(indent) + "..." + "\n"; - } // Deleted tail nodes - var serverTail = node.serverTail; + update = update.next; - for (var _i = 0; _i < serverTail.length; _i++) { - var tailNode = serverTail[_i]; + if (update === null) { + pendingQueue = queue.shared.pending; - if (typeof tailNode === "string") { - // Removed text node - childContent += - removed(indent) + - describeTextNode(tailNode, maxRowLength - indent * 2) + - "\n"; + if (pendingQueue === null) { + break; } else { - // Removed element - childContent += describeExpandedElement( - tailNode.type, - tailNode.props, - removed(indent) - ); + // 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. + + var _firstPendingUpdate = _lastPendingUpdate.next; + _lastPendingUpdate.next = null; + update = _firstPendingUpdate; + queue.lastBaseUpdate = _lastPendingUpdate; + queue.shared.pending = null; } } + } while (true); - return parentContent + selfContent + childContent; + if (newLastBaseUpdate === null) { + newBaseState = newState; } - function describeDiff(rootNode) { - try { - return "\n\n" + describeNode(rootNode, 0); - } catch (x) { - return ""; - } - } + queue.baseState = newBaseState; + queue.firstBaseUpdate = newFirstBaseUpdate; + queue.lastBaseUpdate = newLastBaseUpdate; - var isHydrating = false; // This flag allows for warning supression when we expect there to be mismatches + 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. - var hydrationDiffRootDEV = null; // Hydration errors that were thrown inside this boundary - var hydrationErrors = null; + markSkippedUpdateLanes(newLanes); + workInProgress.lanes = newLanes; + workInProgress.memoizedState = newState; + } - 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." - ); - } - } + { + currentlyProcessingQueue = null; + } +} - 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." - ); - } - } +function callCallback(callback, context) { + if (typeof callback !== 'function') { + throw new Error('Invalid argument passed as callback. Expected a function. Instead ' + ("received: " + callback)); + } - 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." - ); - } - } + callback.call(context); +} - function popHydrationState(fiber) { - { - return false; - } - } +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; - 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 (newHiddenCallbacks !== null) { + var existingHiddenCallbacks = updateQueue.shared.hiddenCallbacks; - function getIsHydrating() { - return isHydrating; + 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 queueHydrationError(error) { - if (hydrationErrors === null) { - hydrationErrors = [error]; - } else { - hydrationErrors.push(error); - } + if (hiddenCallbacks !== null) { + updateQueue.shared.hiddenCallbacks = null; + + for (var i = 0; i < hiddenCallbacks.length; i++) { + var callback = hiddenCallbacks[i]; + callCallback(callback, context); } - function emitPendingHydrationWarnings() { - { - // If we haven't yet thrown any hydration errors by the time we reach the end we've successfully - // hydrated, however, we might still have DEV-only mismatches that we log now. - var diffRoot = hydrationDiffRootDEV; - - if (diffRoot !== null) { - hydrationDiffRootDEV = null; - var diff = describeDiff(diffRoot); - - error( - "A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. " + - "This can happen if a SSR-ed Client Component used:\n" + - "\n" + - "- A server/client branch `if (typeof window !== 'undefined')`.\n" + - "- Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.\n" + - "- Date formatting in a user's locale which doesn't match the server.\n" + - "- External changing data without sending a snapshot of it along with the HTML.\n" + - "- Invalid HTML tag nesting.\n" + - "\n" + - "It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.\n" + - "\n" + - "%s%s", - "https://react.dev/link/hydration-mismatch", - diff - ); - } - } - } - - // 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 concurrentQueues = []; - var concurrentQueuesIndex = 0; - var concurrentlyUpdatedLanes = NoLanes; - function finishQueueingConcurrentUpdates() { - var endIndex = concurrentQueuesIndex; - concurrentQueuesIndex = 0; - concurrentlyUpdatedLanes = NoLanes; - var i = 0; - - 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; - } + } +} +function commitCallbacks(updateQueue, context) { + var callbacks = updateQueue.callbacks; - queue.pending = update; - } + if (callbacks !== null) { + updateQueue.callbacks = null; - if (lane !== NoLane) { - markUpdateLaneFromFiberToRoot(fiber, update, lane); - } - } + for (var i = 0; i < callbacks.length; i++) { + var callback = callbacks[i]; + callCallback(callback, context); } - function getConcurrentlyUpdatedLanes() { - return concurrentlyUpdatedLanes; - } - - 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. + } +} - fiber.lanes = mergeLanes(fiber.lanes, lane); - var alternate = fiber.alternate; +// $FlowFixMe[method-unbinding] +var hasOwnProperty = Object.prototype.hasOwnProperty; - if (alternate !== null) { - alternate.lanes = mergeLanes(alternate.lanes, lane); - } - } - - 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. +/** + * 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. + */ - var isConcurrentlyRendering = getWorkInProgressRoot() !== null; +function shallowEqual(objA, objB) { + if (objectIs(objA, objB)) { + return true; + } - 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 (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) { + return false; + } - 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; - } + var keysA = Object.keys(objA); + var keysB = Object.keys(objB); - function markUpdateLaneFromFiberToRoot(sourceFiber, update, lane) { - // Update the source fiber's lanes - sourceFiber.lanes = mergeLanes(sourceFiber.lanes, lane); - var alternate = sourceFiber.alternate; + if (keysA.length !== keysB.length) { + return false; + } // Test for A's keys different from B. - if (alternate !== null) { - alternate.lanes = mergeLanes(alternate.lanes, lane); - } // Walk the parent path to the root and update the child lanes. - var isHidden = false; - var parent = sourceFiber.return; - var node = sourceFiber; + for (var i = 0; i < keysA.length; i++) { + var currentKey = keysA[i]; - while (parent !== null) { - parent.childLanes = mergeLanes(parent.childLanes, lane); - alternate = parent.alternate; + if (!hasOwnProperty.call(objB, currentKey) || // $FlowFixMe[incompatible-use] lost refinement of `objB` + !objectIs(objA[currentKey], objB[currentKey])) { + return false; + } + } - if (alternate !== null) { - alternate.childLanes = mergeLanes(alternate.childLanes, lane); - } + return true; +} - 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 ( - offscreenInstance !== null && - !(offscreenInstance._visibility & OffscreenVisible) - ) { - isHidden = true; - } - } +var current = null; +var isRendering = false; +function getCurrentFiberOwnerNameInDevOrNull() { + { + if (current === null) { + return null; + } - node = parent; - parent = parent.return; - } + var owner = current._debugOwner; - if (isHidden && update !== null && node.tag === HostRoot) { - var root = node.stateNode; - markHiddenUpdate(root, update, lane); - } + if (owner != null) { + return getComponentNameFromOwner(owner); } + } - 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. + return null; +} - detectUpdateOnUnmountedFiber(sourceFiber, sourceFiber); - var node = sourceFiber; - var parent = node.return; +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. - while (parent !== null) { - detectUpdateOnUnmountedFiber(sourceFiber, node); - node = parent; - parent = node.return; - } - return node.tag === HostRoot ? node.stateNode : null; - } + return getStackByFiberInDevAndProd(current); + } +} - function detectUpdateOnUnmountedFiber(sourceFiber, parent) { - { - var alternate = parent.alternate; +function resetCurrentFiber() { + { + ReactSharedInternals.getCurrentStack = null; + current = null; + isRendering = false; + } +} +function setCurrentFiber(fiber) { + { + ReactSharedInternals.getCurrentStack = fiber === null ? null : getCurrentFiberStackInDev; + current = fiber; + isRendering = false; + } +} +function getCurrentFiber() { + { + return current; + } +} +function setIsRendering(rendering) { + { + isRendering = rendering; + } +} - if ( - alternate === null && - (parent.flags & (Placement | Hydrating)) !== NoFlags$1 - ) { - warnAboutUpdateOnNotYetMountedFiberInDEV(sourceFiber); - } +var ReactStrictModeWarnings = { + recordUnsafeLifecycleWarnings: function (fiber, instance) {}, + flushPendingUnsafeLifecycleWarnings: function () {}, + recordLegacyContextWarning: function (fiber, instance) {}, + flushLegacyContextWarning: function () {}, + discardPendingWarnings: function () {} +}; + +{ + var findStrictRoot = function (fiber) { + var maybeStrictRoot = null; + var node = fiber; + + while (node !== null) { + if (node.mode & StrictLegacyMode) { + maybeStrictRoot = node; } + + node = node.return; } - // there's only a single root, but we do support multi root apps, hence this - // extra complexity. But this module is optimized for the single root case. + return maybeStrictRoot; + }; - var firstScheduledRoot = null; - var lastScheduledRoot = null; // Used to prevent redundant mircotasks from being scheduled. + var setToSortedString = function (set) { + var array = []; + set.forEach(function (value) { + array.push(value); + }); + return array.sort().join(', '); + }; - var didScheduleMicrotask = false; // `act` "microtasks" are scheduled on the `act` queue instead of an actual - // microtask, so we have to dedupe those separately. This wouldn't be an issue - // if we required all `act` calls to be awaited, which we might in the future. + var pendingComponentWillMountWarnings = []; + var pendingUNSAFE_ComponentWillMountWarnings = []; + var pendingComponentWillReceivePropsWarnings = []; + var pendingUNSAFE_ComponentWillReceivePropsWarnings = []; + var pendingComponentWillUpdateWarnings = []; + var pendingUNSAFE_ComponentWillUpdateWarnings = []; // Tracks components we have already warned about. - var didScheduleMicrotask_act = false; // Used to quickly bail out of flushSync if there's no sync work to do. + var didWarnAboutUnsafeLifecycles = new Set(); - var mightHavePendingSyncWork = false; - var isFlushingWork = false; - var currentEventTransitionLane = NoLane; - function ensureRootIsScheduled(root) { - // This function is called whenever a root receives an update. It does two - // things 1) it ensures the root is in the root schedule, and 2) it ensures - // there's a pending microtask to process the root schedule. - // - // Most of the actual scheduling logic does not happen until - // `scheduleTaskForRootDuringMicrotask` runs. - // Add the root to the schedule - if (root === lastScheduledRoot || root.next !== null); - else { - if (lastScheduledRoot === null) { - firstScheduledRoot = lastScheduledRoot = root; - } else { - lastScheduledRoot.next = root; - lastScheduledRoot = root; - } - } // Any time a root received an update, we set this to true until the next time - // we process the schedule. If it's false, then we can quickly exit flushSync - // without consulting the schedule. + ReactStrictModeWarnings.recordUnsafeLifecycleWarnings = function (fiber, instance) { + // Dedupe strategy: Warn once per component. + if (didWarnAboutUnsafeLifecycles.has(fiber.type)) { + return; + } - mightHavePendingSyncWork = true; // At the end of the current event, go through each of the roots and ensure - // there's a task scheduled for each one at the correct priority. + if (typeof instance.componentWillMount === 'function' && // Don't warn about react-lifecycles-compat polyfilled components. + instance.componentWillMount.__suppressDeprecationWarning !== true) { + pendingComponentWillMountWarnings.push(fiber); + } - if (ReactSharedInternals.actQueue !== null) { - // We're inside an `act` scope. - if (!didScheduleMicrotask_act) { - didScheduleMicrotask_act = true; - scheduleImmediateTask(processRootScheduleInMicrotask); - } - } else { - if (!didScheduleMicrotask) { - didScheduleMicrotask = true; - scheduleImmediateTask(processRootScheduleInMicrotask); - } - } + if (fiber.mode & StrictLegacyMode && typeof instance.UNSAFE_componentWillMount === 'function') { + pendingUNSAFE_ComponentWillMountWarnings.push(fiber); + } - if (!enableDeferRootSchedulingToMicrotask) { - // While this flag is disabled, we schedule the render task immediately - // instead of waiting a microtask. - // TODO: We need to land enableDeferRootSchedulingToMicrotask ASAP to - // unblock additional features we have planned. - scheduleTaskForRootDuringMicrotask(root, now$1()); - } + if (typeof instance.componentWillReceiveProps === 'function' && instance.componentWillReceiveProps.__suppressDeprecationWarning !== true) { + pendingComponentWillReceivePropsWarnings.push(fiber); + } - if (ReactSharedInternals.isBatchingLegacy && root.tag === LegacyRoot) { - // Special `act` case: Record whenever a legacy update is scheduled. - ReactSharedInternals.didScheduleLegacyUpdate = true; - } + if (fiber.mode & StrictLegacyMode && typeof instance.UNSAFE_componentWillReceiveProps === 'function') { + pendingUNSAFE_ComponentWillReceivePropsWarnings.push(fiber); } - function flushSyncWorkOnAllRoots() { - // This is allowed to be called synchronously, but the caller should check - // the execution context first. - flushSyncWorkAcrossRoots_impl(false); + + if (typeof instance.componentWillUpdate === 'function' && instance.componentWillUpdate.__suppressDeprecationWarning !== true) { + pendingComponentWillUpdateWarnings.push(fiber); } - function flushSyncWorkOnLegacyRootsOnly() { - // This is allowed to be called synchronously, but the caller should check - // the execution context first. - { - flushSyncWorkAcrossRoots_impl(true); - } + + if (fiber.mode & StrictLegacyMode && typeof instance.UNSAFE_componentWillUpdate === 'function') { + pendingUNSAFE_ComponentWillUpdateWarnings.push(fiber); } + }; - function flushSyncWorkAcrossRoots_impl(onlyLegacy) { - if (isFlushingWork) { - // Prevent reentrancy. - // TODO: Is this overly defensive? The callers must check the execution - // context first regardless. - return; - } + ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = function () { + // We do an initial pass to gather component names + var componentWillMountUniqueNames = new Set(); - if (!mightHavePendingSyncWork) { - // Fast path. There's no sync work to do. - return; - } // There may or may not be synchronous work scheduled. Let's check. + if (pendingComponentWillMountWarnings.length > 0) { + pendingComponentWillMountWarnings.forEach(function (fiber) { + componentWillMountUniqueNames.add(getComponentNameFromFiber(fiber) || 'Component'); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingComponentWillMountWarnings = []; + } - var didPerformSomeWork; - isFlushingWork = true; + var UNSAFE_componentWillMountUniqueNames = new Set(); - do { - didPerformSomeWork = false; - var root = firstScheduledRoot; - - while (root !== null) { - if (onlyLegacy && root.tag !== LegacyRoot); - else { - var workInProgressRoot = getWorkInProgressRoot(); - var workInProgressRootRenderLanes = - getWorkInProgressRootRenderLanes(); - var nextLanes = getNextLanes( - root, - root === workInProgressRoot - ? workInProgressRootRenderLanes - : NoLanes - ); + if (pendingUNSAFE_ComponentWillMountWarnings.length > 0) { + pendingUNSAFE_ComponentWillMountWarnings.forEach(function (fiber) { + UNSAFE_componentWillMountUniqueNames.add(getComponentNameFromFiber(fiber) || 'Component'); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingUNSAFE_ComponentWillMountWarnings = []; + } - if (includesSyncLane(nextLanes)) { - // This root has pending sync work. Flush it now. - didPerformSomeWork = true; - performSyncWorkOnRoot(root, nextLanes); - } - } + var componentWillReceivePropsUniqueNames = new Set(); - root = root.next; - } - } while (didPerformSomeWork); + if (pendingComponentWillReceivePropsWarnings.length > 0) { + pendingComponentWillReceivePropsWarnings.forEach(function (fiber) { + componentWillReceivePropsUniqueNames.add(getComponentNameFromFiber(fiber) || 'Component'); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingComponentWillReceivePropsWarnings = []; + } + + var UNSAFE_componentWillReceivePropsUniqueNames = new Set(); - isFlushingWork = false; + if (pendingUNSAFE_ComponentWillReceivePropsWarnings.length > 0) { + pendingUNSAFE_ComponentWillReceivePropsWarnings.forEach(function (fiber) { + UNSAFE_componentWillReceivePropsUniqueNames.add(getComponentNameFromFiber(fiber) || 'Component'); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingUNSAFE_ComponentWillReceivePropsWarnings = []; } - function processRootScheduleInMicrotask() { - // This function is always called inside a microtask. It should never be - // called synchronously. - didScheduleMicrotask = false; + var componentWillUpdateUniqueNames = new Set(); - { - didScheduleMicrotask_act = false; - } // We'll recompute this as we iterate through all the roots and schedule them. - - mightHavePendingSyncWork = false; - var currentTime = now$1(); - var prev = null; - var root = firstScheduledRoot; - - while (root !== null) { - var next = root.next; - - if ( - currentEventTransitionLane !== NoLane && - shouldAttemptEagerTransition() - ) { - // A transition was scheduled during an event, but we're going to try to - // render it synchronously anyway. We do this during a popstate event to - // preserve the scroll position of the previous page. - upgradePendingLaneToSync(root, currentEventTransitionLane); - } - - var nextLanes = scheduleTaskForRootDuringMicrotask(root, currentTime); - - if (nextLanes === NoLane) { - // This root has no more pending work. Remove it from the schedule. To - // guard against subtle reentrancy bugs, this microtask is the only place - // we do this — you can add roots to the schedule whenever, but you can - // only remove them here. - // Null this out so we know it's been removed from the schedule. - root.next = null; - - if (prev === null) { - // This is the new head of the list - firstScheduledRoot = next; - } else { - prev.next = next; - } + if (pendingComponentWillUpdateWarnings.length > 0) { + pendingComponentWillUpdateWarnings.forEach(function (fiber) { + componentWillUpdateUniqueNames.add(getComponentNameFromFiber(fiber) || 'Component'); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingComponentWillUpdateWarnings = []; + } - if (next === null) { - // This is the new tail of the list - lastScheduledRoot = prev; - } - } else { - // This root still has work. Keep it in the list. - prev = root; + var UNSAFE_componentWillUpdateUniqueNames = new Set(); - if (includesSyncLane(nextLanes)) { - mightHavePendingSyncWork = true; - } - } + 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' - root = next; - } - currentEventTransitionLane = NoLane; // At the end of the microtask, flush any pending synchronous work. This has - // to come at the end, because it does actual rendering work that might throw. + if (UNSAFE_componentWillMountUniqueNames.size > 0) { + var sortedNames = setToSortedString(UNSAFE_componentWillMountUniqueNames); - flushSyncWorkOnAllRoots(); + error('Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code. ' + 'See https://react.dev/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 scheduleTaskForRootDuringMicrotask(root, currentTime) { - // This function is always called inside a microtask, or at the very end of a - // rendering task right before we yield to the main thread. It should never be - // called synchronously. - // - // TODO: Unless enableDeferRootSchedulingToMicrotask is off. We need to land - // that ASAP to unblock additional features we have planned. - // - // This function also never performs React work synchronously; it should - // only schedule work to be performed later, in a separate task or microtask. - // Check if any lanes are being starved by other work. If so, mark them as - // expired so we know to work on those next. - markStarvedLanesAsExpired(root, currentTime); // Determine the next lanes to work on, and their priority. - - var workInProgressRoot = getWorkInProgressRoot(); - var workInProgressRootRenderLanes = getWorkInProgressRootRenderLanes(); - var nextLanes = getNextLanes( - root, - root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes - ); - var existingCallbackNode = root.callbackNode; - - if ( - // Check if there's nothing to work on - nextLanes === NoLanes || // 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. - // - // Suspended render phase - (root === workInProgressRoot && isWorkLoopSuspendedOnData()) || // Suspended commit phase - root.cancelPendingCommit !== null - ) { - // Fast path: There's nothing to work on. - if (existingCallbackNode !== null) { - cancelCallback(existingCallbackNode); - } - - root.callbackNode = null; - root.callbackPriority = NoLane; - return NoLane; - } // Schedule a new callback in the host environment. + if (UNSAFE_componentWillReceivePropsUniqueNames.size > 0) { + var _sortedNames = setToSortedString(UNSAFE_componentWillReceivePropsUniqueNames); - if (includesSyncLane(nextLanes)) { - // Synchronous work is always flushed at the end of the microtask, so we - // don't need to schedule an additional task. - if (existingCallbackNode !== null) { - cancelCallback(existingCallbackNode); - } + error('Using UNSAFE_componentWillReceiveProps in strict mode is not recommended ' + 'and may indicate bugs in your code. ' + 'See https://react.dev/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://react.dev/link/derived-state\n' + '\nPlease update the following components: %s', _sortedNames); + } - root.callbackPriority = SyncLane; - root.callbackNode = null; - return SyncLane; - } else { - // We use the highest priority lane to represent the priority of the callback. - var existingCallbackPriority = root.callbackPriority; - var newCallbackPriority = getHighestPriorityLane(nextLanes); - - if ( - newCallbackPriority === existingCallbackPriority && // Special case related to `act`. If the currently scheduled task is a - // Scheduler task, rather than an `act` task, cancel it and re-schedule - // on the `act` queue. - !( - ReactSharedInternals.actQueue !== null && - existingCallbackNode !== fakeActCallbackNode$1 - ) - ) { - // The priority hasn't changed. We can reuse the existing task. - return newCallbackPriority; - } else { - // Cancel the existing callback. We'll schedule a new one below. - cancelCallback(existingCallbackNode); - } + if (UNSAFE_componentWillUpdateUniqueNames.size > 0) { + var _sortedNames2 = setToSortedString(UNSAFE_componentWillUpdateUniqueNames); - var schedulerPriorityLevel; + error('Using UNSAFE_componentWillUpdate in strict mode is not recommended ' + 'and may indicate bugs in your code. ' + 'See https://react.dev/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); + } - switch (lanesToEventPriority(nextLanes)) { - case DiscreteEventPriority: - schedulerPriorityLevel = ImmediatePriority; - break; + if (componentWillMountUniqueNames.size > 0) { + var _sortedNames3 = setToSortedString(componentWillMountUniqueNames); - case ContinuousEventPriority: - schedulerPriorityLevel = UserBlockingPriority; - break; + warn('componentWillMount has been renamed, and is not recommended for use. ' + 'See https://react.dev/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); + } - case DefaultEventPriority: - schedulerPriorityLevel = NormalPriority$1; - break; + if (componentWillReceivePropsUniqueNames.size > 0) { + var _sortedNames4 = setToSortedString(componentWillReceivePropsUniqueNames); - case IdleEventPriority: - schedulerPriorityLevel = IdlePriority; - break; + warn('componentWillReceiveProps has been renamed, and is not recommended for use. ' + 'See https://react.dev/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://react.dev/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); + } - default: - schedulerPriorityLevel = NormalPriority$1; - break; - } + if (componentWillUpdateUniqueNames.size > 0) { + var _sortedNames5 = setToSortedString(componentWillUpdateUniqueNames); - var newCallbackNode = scheduleCallback$2( - schedulerPriorityLevel, - performConcurrentWorkOnRoot.bind(null, root) - ); - root.callbackPriority = newCallbackPriority; - root.callbackNode = newCallbackNode; - return newCallbackPriority; - } + warn('componentWillUpdate has been renamed, and is not recommended for use. ' + 'See https://react.dev/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); } + }; - function getContinuationForRoot(root, originalCallbackNode) { - // This is called at the end of `performConcurrentWorkOnRoot` to determine - // if we need to schedule a continuation task. - // - // Usually `scheduleTaskForRootDuringMicrotask` only runs inside a microtask; - // however, since most of the logic for determining if we need a continuation - // versus a new task is the same, we cheat a bit and call it here. This is - // only safe to do because we know we're at the end of the browser task. - // So although it's not an actual microtask, it might as well be. - scheduleTaskForRootDuringMicrotask(root, now$1()); + var pendingLegacyContextWarning = new Map(); // Tracks components we have already warned about. - 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); - } + var didWarnAboutLegacyContext = new Set(); - return null; - } - var fakeActCallbackNode$1 = {}; + ReactStrictModeWarnings.recordLegacyContextWarning = function (fiber, instance) { + var strictRoot = findStrictRoot(fiber); - function scheduleCallback$2(priorityLevel, callback) { - if (ReactSharedInternals.actQueue !== null) { - // Special case: We're inside an `act` scope (a testing utility). - // Instead of scheduling work in the host environment, add it to a - // fake internal queue that's managed by the `act` implementation. - ReactSharedInternals.actQueue.push(callback); - return fakeActCallbackNode$1; - } else { - return scheduleCallback$3(priorityLevel, callback); - } - } + 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.'); - function cancelCallback(callbackNode) { - if (callbackNode === fakeActCallbackNode$1); - else if (callbackNode !== null) { - cancelCallback$1(callbackNode); - } - } + return; + } // Dedup strategy: Warn once per component. - function scheduleImmediateTask(cb) { - if (ReactSharedInternals.actQueue !== null) { - // Special case: Inside an `act` scope, we push microtasks to the fake `act` - // callback queue. This is because we currently support calling `act` - // without awaiting the result. The plan is to deprecate that, and require - // that you always await the result so that the microtasks have a chance to - // run. But it hasn't happened yet. - ReactSharedInternals.actQueue.push(function () { - cb(); - return null; - }); - } // TODO: Can we land supportsMicrotasks? Which environments don't support it? - // Alternatively, can we move this check to the host config? - - if (supportsMicrotasks) { - scheduleMicrotask(function () { - // In Safari, appending an iframe forces microtasks to run. - // https://github.com/facebook/react/issues/22459 - // We don't support running callbacks in the middle of render - // or commit so we need to check against that. - var executionContext = getExecutionContext(); - - if ( - (executionContext & (RenderContext | CommitContext)) !== - NoContext - ) { - // Note that this would still prematurely flush the callbacks - // if this happens outside render or commit phase (e.g. in an event). - // Intentionally using a macrotask instead of a microtask here. This is - // wrong semantically but it prevents an infinite loop. The bug is - // Safari's, not ours, so we just do our best to not crash even though - // the behavior isn't completely correct. - scheduleCallback$3(ImmediatePriority, cb); - return; - } - cb(); - }); - } else { - // If microtasks are not supported, use Scheduler. - scheduleCallback$3(ImmediatePriority, cb); - } + if (didWarnAboutLegacyContext.has(fiber.type)) { + return; } - function requestTransitionLane( // This argument isn't used, it's only here to encourage the caller to - // check that it's inside a transition before calling this function. - // TODO: Make this non-nullable. Requires a tweak to useOptimistic. - transition - ) { - // 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(); + var warningsForRoot = pendingLegacyContextWarning.get(strictRoot); + + if (fiber.type.contextTypes != null || fiber.type.childContextTypes != null || instance !== null && typeof instance.getChildContext === 'function') { + if (warningsForRoot === undefined) { + warningsForRoot = []; + pendingLegacyContextWarning.set(strictRoot, warningsForRoot); } - return currentEventTransitionLane; + warningsForRoot.push(fiber); } + }; - // transition updates that occur while the async action is still in progress - // are treated as part of the action. - // - // The ideal behavior would be to treat each async function as an independent - // action. However, without a mechanism like AsyncContext, we can't tell which - // action an update corresponds to. So instead, we entangle them all into one. - // The listeners to notify once the entangled scope completes. - - var currentEntangledListeners = null; // The number of pending async actions in the entangled scope. - - var currentEntangledPendingCount = 0; // The transition lane shared by all updates in the entangled scope. - - var currentEntangledLane = NoLane; // A thenable that resolves when the entangled scope completes. It does not - // resolve to a particular value because it's only used for suspending the UI - // until the async action scope has completed. - - var currentEntangledActionThenable = null; - function entangleAsyncAction(transition, thenable) { - // `thenable` is the return value of the async action scope function. Create - // a combined thenable that resolves once every entangled scope function - // has finished. - if (currentEntangledListeners === null) { - // There's no outer async action scope. Create a new one. - var entangledListeners = (currentEntangledListeners = []); - currentEntangledPendingCount = 0; - currentEntangledLane = requestTransitionLane(); - var entangledThenable = { - status: "pending", - value: undefined, - then: function (resolve) { - entangledListeners.push(resolve); - } - }; - currentEntangledActionThenable = entangledThenable; + ReactStrictModeWarnings.flushLegacyContextWarning = function () { + pendingLegacyContextWarning.forEach(function (fiberArray, strictRoot) { + if (fiberArray.length === 0) { + return; } - currentEntangledPendingCount++; - thenable.then(pingEngtangledActionScope, pingEngtangledActionScope); - return thenable; - } - - function pingEngtangledActionScope() { - if ( - currentEntangledListeners !== null && - --currentEntangledPendingCount === 0 - ) { - // All the actions have finished. Close the entangled async action scope - // and notify all the listeners. - if (currentEntangledActionThenable !== null) { - var fulfilledThenable = currentEntangledActionThenable; - fulfilledThenable.status = "fulfilled"; - } + 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); - var listeners = currentEntangledListeners; - currentEntangledListeners = null; - currentEntangledLane = NoLane; - currentEntangledActionThenable = null; + try { + setCurrentFiber(firstFiber); - for (var i = 0; i < listeners.length; i++) { - var listener = listeners[i]; - listener(); - } + 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://react.dev/link/legacy-context', sortedNames); + } finally { + resetCurrentFiber(); } - } + }); + }; + + ReactStrictModeWarnings.discardPendingWarnings = function () { + pendingComponentWillMountWarnings = []; + pendingUNSAFE_ComponentWillMountWarnings = []; + pendingComponentWillReceivePropsWarnings = []; + pendingUNSAFE_ComponentWillReceivePropsWarnings = []; + pendingComponentWillUpdateWarnings = []; + pendingUNSAFE_ComponentWillUpdateWarnings = []; + pendingLegacyContextWarning = new Map(); + }; +} - function chainThenableValue(thenable, result) { - // Equivalent to: Promise.resolve(thenable).then(() => result), except we can - // cheat a bit since we know that that this thenable is only ever consumed - // by React. - // - // We don't technically require promise support on the client yet, hence this - // extra code. - var listeners = []; - var thenableWithOverride = { - status: "pending", - value: null, - reason: null, - then: function (resolve) { - listeners.push(resolve); - } - }; - thenable.then( - function (value) { - var fulfilledThenable = thenableWithOverride; - fulfilledThenable.status = "fulfilled"; - fulfilledThenable.value = result; - - for (var i = 0; i < listeners.length; i++) { - var listener = listeners[i]; - listener(result); - } - }, - function (error) { - var rejectedThenable = thenableWithOverride; - rejectedThenable.status = "rejected"; - rejectedThenable.reason = error; - - for (var i = 0; i < listeners.length; i++) { - var listener = listeners[i]; // This is a perf hack where we call the `onFulfill` ping function - // instead of `onReject`, because we know that React is the only - // consumer of these promises, and it passes the same listener to both. - // We also know that it will read the error directly off the - // `.reason` field. - - listener(undefined); - } - } - ); - return thenableWithOverride; - } - function peekEntangledActionLane() { - return currentEntangledLane; - } - function peekEntangledActionThenable() { - return currentEntangledActionThenable; - } +function getThenablesFromState(state) { + { + var devState = state; + return devState.thenables; + } +} // 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. - 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 hasForceUpdate = false; - var didWarnUpdateInsideUpdate; - var currentlyProcessingQueue; +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 noopSuspenseyCommitThenable = { + then: function () { { - didWarnUpdateInsideUpdate = false; - currentlyProcessingQueue = null; - } - - 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 (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('Internal React error: A listener was unexpectedly attached to a ' + '"noop" thenable. This is a bug in React. Please file an issue.'); + } + } +}; +function createThenableState() { + // The ThenableState is created the first time a component suspends. If it + // suspends again, we'll reuse the same state. + { + return { + didWarnAboutUncachedPromise: false, + thenables: [] + }; + } +} +function isThenableResolved(thenable) { + var status = thenable.status; + return status === 'fulfilled' || status === 'rejected'; +} - if (updateQueue === null) { - // Only occurs if the fiber has been unmounted. - return null; - } +function noop() {} - var sharedQueue = updateQueue.shared; +function trackUsedThenable(thenableState, thenable, index) { + if (ReactSharedInternals.actQueue !== null) { + ReactSharedInternals.didUsePromise = true; + } + var trackedThenables = getThenablesFromState(thenableState); + var previous = trackedThenables[index]; + + if (previous === undefined) { + trackedThenables.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. { - if ( - currentlyProcessingQueue === sharedQueue && - !didWarnUpdateInsideUpdate - ) { - var componentName = getComponentNameFromFiber(fiber); + var thenableStateDev = thenableState; - 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 (!thenableStateDev.didWarnAboutUncachedPromise) { + // We should only warn the first time an uncached thenable is + // discovered per component, because if there are multiple, the + // subsequent ones are likely derived from the first. + // + // We track this on the thenableState instead of deduping using the + // component name like we usually do, because in the case of a + // promise-as-React-node, the owner component is likely different from + // the parent that's currently being reconciled. We'd have to track + // the owner using state, which we're trying to move away from. Though + // since this is dev-only, maybe that'd be OK. + // + // However, another benefit of doing it this way is we might + // eventually have a thenableState per memo/Forget boundary instead + // of per component, so this would allow us to have more + // granular warnings. + thenableStateDev.didWarnAboutUncachedPromise = true; // TODO: This warning should link to a corresponding docs page. - didWarnUpdateInsideUpdate = true; + error('A component was suspended by an uncached promise. Creating ' + 'promises inside a Client Component or hook is not yet ' + 'supported, except via a Suspense-compatible library or framework.'); } - } + } // Avoid an unhandled rejection errors for the Promises that we'll + // intentionally ignore. - 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; - if (pending === null) { - // This is the first update. Create a circular list. - update.next = update; - } else { - update.next = pending.next; - pending.next = update; - } + thenable.then(noop, noop); + thenable = previous; + } + } // 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. - 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). - return unsafe_markUpdateLaneFromFiberToRoot(fiber, lane); - } else { - return enqueueConcurrentClassUpdate(fiber, sharedQueue, update, lane); + switch (thenable.status) { + case 'fulfilled': + { + var fulfilledValue = thenable.value; + return fulfilledValue; } - } - function entangleTransitions(root, fiber, lane) { - var updateQueue = fiber.updateQueue; - if (updateQueue === null) { - // Only occurs if the fiber has been unmounted. - return; + case 'rejected': + { + var rejectedError = thenable.reason; + checkIfUseWrappedInAsyncCatch(rejectedError); + throw rejectedError; } - var sharedQueue = updateQueue.shared; + 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 { + // This is an uncached thenable that we haven't seen before. + // Detect infinite ping loops caused by uncached promises. + var root = getWorkInProgressRoot(); - 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 (root !== null && root.shellSuspendCounter > 100) { + // This root has suspended repeatedly in the shell without making any + // progress (i.e. committing something). This is highly suggestive of + // an infinite ping loop, often caused by an accidental Async Client + // Component. + // + // During a transition, we can suspend the work loop until the promise + // to resolve, but this is a sync render, so that's not an option. We + // also can't show a fallback, because none was provided. So our last + // resort is to throw an error. + // + // TODO: Remove this error in a future release. Other ways of handling + // this case include forcing a concurrent render, or putting the whole + // root into offscreen mode. + throw new Error('async/await is not yet supported in Client Components, only ' + 'Server Components. This error is often caused by accidentally ' + "adding `'use client'` to a module that was originally written " + 'for the server.'); + } - queueLanes = intersectLanes(queueLanes, root.pendingLanes); // Entangle the new transition lane with the other transition 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. - 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. - 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. + switch (thenable.status) { + case 'fulfilled': + { + var fulfilledThenable = thenable; + return fulfilledThenable.value; + } - var current = workInProgress.alternate; + case 'rejected': + { + var rejectedThenable = thenable; + var _rejectedError = rejectedThenable.reason; + checkIfUseWrappedInAsyncCatch(_rejectedError); + throw _rejectedError; + } + } // 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. - if (current !== null) { - var currentQueue = current.updateQueue; - - 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; - - if (firstBaseUpdate !== null) { - // Loop through the updates and clone them. - var update = firstBaseUpdate; - 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 - }; + suspendedThenable = thenable; - if (newLast === null) { - newFirst = newLast = clone; - } else { - newLast.next = clone; - newLast = clone; - } // $FlowFixMe[incompatible-type] we bail out when we get a null + { + needsToResetSuspendedThenableDEV = true; + } - update = update.next; - } while (update !== null); // Append the captured update the end of the cloned list. + throw SuspenseException; + } + } +} +// 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.'); + } + + 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 (newLast === null) { - newFirst = newLast = capturedUpdate; - } else { - newLast.next = capturedUpdate; - newLast = capturedUpdate; - } - } else { - // There are no base updates. - newFirst = newLast = capturedUpdate; - } + return false; +} +function checkIfUseWrappedInAsyncCatch(rejectedReason) { + // This check runs in prod, too, because it prevents a more confusing + // downstream error, where SuspenseException is caught by a promise and + // thrown asynchronously. + // TODO: Another way to prevent SuspenseException from leaking into an async + // execution context is to check the dispatcher every time `use` is called, + // or some equivalent. That might be preferable for other reasons, too, since + // it matches how we prevent similar mistakes for other hooks. + if (rejectedReason === SuspenseException) { + throw new Error('Hooks are not supported inside an async component. This ' + "error is often caused by accidentally adding `'use client'` " + 'to a module that was originally written for the server.'); + } +} - 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. +var thenableState$1 = null; +var thenableIndexCounter$1 = 0; + +function mergeDebugInfo(outer, inner) { + + if (inner == null) { + return outer; + } else if (outer === null) { + return inner; + } else { + // If we have two debugInfo, we need to create a new one. This makes the array no longer + // live so we'll miss any future updates if we received more so ideally we should always + // do this after both have fully resolved/unsuspended. + return outer.concat(inner); + } +} - var lastBaseUpdate = queue.lastBaseUpdate; +var didWarnAboutMaps; +var didWarnAboutGenerators; +var ownerHasKeyUseWarning; +var ownerHasFunctionTypeWarning; +var ownerHasSymbolTypeWarning; - if (lastBaseUpdate === null) { - queue.firstBaseUpdate = capturedUpdate; - } else { - lastBaseUpdate.next = capturedUpdate; - } +var warnForMissingKey = function (child, returnFiber) {}; - queue.lastBaseUpdate = capturedUpdate; - } +{ + didWarnAboutMaps = false; + didWarnAboutGenerators = false; + /** + * 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. + */ - function getStateFromUpdate( - workInProgress, - queue, - update, - prevState, - nextProps, - instance - ) { - switch (update.tag) { - case ReplaceState: { - var payload = update.payload; + ownerHasKeyUseWarning = {}; + ownerHasFunctionTypeWarning = {}; + ownerHasSymbolTypeWarning = {}; - if (typeof payload === "function") { - // Updater function - { - enterDisallowedContextReadInDEV(); - } + warnForMissingKey = function (child, returnFiber) { + if (child === null || typeof child !== 'object') { + return; + } - var nextState = payload.call(instance, prevState, nextProps); + if (!child._store || child._store.validated || child.key != null) { + return; + } - { - if (workInProgress.mode & StrictLegacyMode) { - setIsStrictModeForDevtools(true); + 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[cannot-write] unable to narrow type from mixed to writable object - try { - payload.call(instance, prevState, nextProps); - } finally { - setIsStrictModeForDevtools(false); - } - } - exitDisallowedContextReadInDEV(); - } + child._store.validated = true; + var componentName = getComponentNameFromFiber(returnFiber) || 'Component'; - return nextState; - } // State object + if (ownerHasKeyUseWarning[componentName]) { + return; + } - return payload; - } + ownerHasKeyUseWarning[componentName] = true; - case CaptureUpdate: { - workInProgress.flags = - (workInProgress.flags & ~ShouldCapture) | DidCapture; - } - // Intentional fallthrough + error('Each child in a list should have a unique ' + '"key" prop. See https://react.dev/link/warning-keys for ' + 'more information.'); + }; +} - case UpdateState: { - var _payload = update.payload; - var partialState; +function unwrapThenable(thenable) { + var index = thenableIndexCounter$1; + thenableIndexCounter$1 += 1; - if (typeof _payload === "function") { - // Updater function - { - enterDisallowedContextReadInDEV(); - } + if (thenableState$1 === null) { + thenableState$1 = createThenableState(); + } - partialState = _payload.call(instance, prevState, nextProps); + return trackUsedThenable(thenableState$1, thenable, index); +} - { - if (workInProgress.mode & StrictLegacyMode) { - setIsStrictModeForDevtools(true); +function coerceRef(returnFiber, current, workInProgress, element) { + var ref; - try { - _payload.call(instance, prevState, nextProps); - } finally { - setIsStrictModeForDevtools(false); - } - } + { + // Old behavior. + ref = element.ref; + } // TODO: If enableRefAsProp is on, we shouldn't use the `ref` field. We + // should always read the ref from the prop. - exitDisallowedContextReadInDEV(); - } - } else { - // Partial state object - partialState = _payload; - } - if (partialState === null || partialState === undefined) { - // Null and undefined are treated as no-ops. - return prevState; - } // Merge the partial state and the previous state. + workInProgress.ref = ref; +} - return assign({}, prevState, partialState); - } +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.'); +} - case ForceUpdate: { - hasForceUpdate = true; - return prevState; - } - } +function warnOnFunctionType(returnFiber, invalidChild) { + { + var parentName = getComponentNameFromFiber(returnFiber) || 'Component'; - return prevState; + if (ownerHasFunctionTypeWarning[parentName]) { + return; } - var didReadFromEntangledAsyncAction = false; // Each call to processUpdateQueue should be accompanied by a call to this. It's - // only in a separate function because in updateHostRoot, it must happen after - // all the context stacks have been pushed to, to prevent a stack mismatch. A - // bit unfortunate. - - function suspendIfUpdateReadFromEntangledAsyncAction() { - // Check if this update is part of a pending async action. If so, we'll - // need to suspend until the action has finished, so that it's batched - // together with future updates in the same action. - // TODO: Once we support hooks inside useMemo (or an equivalent - // memoization boundary like Forget), hoist this logic so that it only - // suspends if the memo boundary produces a new value. - if (didReadFromEntangledAsyncAction) { - var entangledActionThenable = peekEntangledActionThenable(); + ownerHasFunctionTypeWarning[parentName] = true; + var name = invalidChild.displayName || invalidChild.name || 'Component'; - if (entangledActionThenable !== null) { - // TODO: Instead of the throwing the thenable directly, throw a - // special object like `use` does so we can detect if it's captured - // by userspace. - throw entangledActionThenable; - } - } + if (returnFiber.tag === HostRoot) { + error('Functions are not valid as a React child. This may happen if ' + 'you return %s instead of <%s /> from render. ' + 'Or maybe you meant to call this function rather than return it.\n' + ' root.render(%s)', name, name, name); + } else { + error('Functions are not valid as a React child. This may happen if ' + 'you return %s instead of <%s /> from render. ' + 'Or maybe you meant to call this function rather than return it.\n' + ' <%s>{%s}', name, name, parentName, name, parentName); } - function processUpdateQueue(workInProgress, props, instance, renderLanes) { - didReadFromEntangledAsyncAction = false; // This is always non-null on a ClassComponent or HostRoot + } +} - var queue = workInProgress.updateQueue; - hasForceUpdate = false; +function warnOnSymbolType(returnFiber, invalidChild) { + { + var parentName = getComponentNameFromFiber(returnFiber) || 'Component'; - { - currentlyProcessingQueue = queue.shared; - } + if (ownerHasSymbolTypeWarning[parentName]) { + return; + } - var firstBaseUpdate = queue.firstBaseUpdate; - var lastBaseUpdate = queue.lastBaseUpdate; // Check if there are pending updates. If so, transfer them to the base queue. + ownerHasSymbolTypeWarning[parentName] = true; // eslint-disable-next-line react-internal/safe-string-coercion - var pendingQueue = queue.shared.pending; + var name = String(invalidChild); - 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. + if (returnFiber.tag === HostRoot) { + error('Symbols are not valid as a React child.\n' + ' root.render(%s)', name); + } else { + error('Symbols are not valid as a React child.\n' + ' <%s>%s', parentName, name, parentName); + } + } +} - var lastPendingUpdate = pendingQueue; - var firstPendingUpdate = lastPendingUpdate.next; - lastPendingUpdate.next = null; // Append pending updates to base queue +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 (lastBaseUpdate === null) { - firstBaseUpdate = firstPendingUpdate; - } else { - lastBaseUpdate.next = firstPendingUpdate; - } - 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 +function createChildReconciler(shouldTrackSideEffects) { + function deleteChild(returnFiber, childToDelete) { + if (!shouldTrackSideEffects) { + // Noop. + return; + } - var current = workInProgress.alternate; + var deletions = returnFiber.deletions; - if (current !== null) { - // This is always non-null on a ClassComponent or HostRoot - var currentQueue = current.updateQueue; - var currentLastBaseUpdate = currentQueue.lastBaseUpdate; + if (deletions === null) { + returnFiber.deletions = [childToDelete]; + returnFiber.flags |= ChildDeletion; + } else { + deletions.push(childToDelete); + } + } - if (currentLastBaseUpdate !== lastBaseUpdate) { - if (currentLastBaseUpdate === null) { - currentQueue.firstBaseUpdate = firstPendingUpdate; - } else { - currentLastBaseUpdate.next = firstPendingUpdate; - } + 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. - currentQueue.lastBaseUpdate = lastPendingUpdate; - } - } - } // 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 newLanes = NoLanes; - var newBaseState = null; - var newFirstBaseUpdate = null; - var newLastBaseUpdate = null; - var update = firstBaseUpdate; + var childToDelete = currentFirstChild; - 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); - - 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 - }; + while (childToDelete !== null) { + deleteChild(returnFiber, childToDelete); + childToDelete = childToDelete.sibling; + } - if (newLastBaseUpdate === null) { - newFirstBaseUpdate = newLastBaseUpdate = clone; - newBaseState = newState; - } else { - newLastBaseUpdate = newLastBaseUpdate.next = clone; - } // Update the remaining priority in the queue. + return null; + } - newLanes = mergeLanes(newLanes, updateLane); - } else { - // This update does have sufficient priority. - // Check if this update is part of a pending async action. If so, - // we'll need to suspend until the action has finished, so that it's - // batched together with future updates in the same action. - if ( - updateLane !== NoLane && - updateLane === peekEntangledActionLane() - ) { - didReadFromEntangledAsyncAction = true; - } + function mapRemainingChildren(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; - 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. - - newState = getStateFromUpdate( - workInProgress, - queue, - update, - newState, - props, - instance - ); - var callback = update.callback; + while (existingChild !== null) { + if (existingChild.key !== null) { + existingChildren.set(existingChild.key, existingChild); + } else { + existingChildren.set(existingChild.index, existingChild); + } - if (callback !== null) { - workInProgress.flags |= Callback; + existingChild = existingChild.sibling; + } - if (isHiddenUpdate) { - workInProgress.flags |= Visibility; - } + return existingChildren; + } - var callbacks = queue.callbacks; + 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; + } - if (callbacks === null) { - queue.callbacks = [callback]; - } else { - callbacks.push(callback); - } - } - } // $FlowFixMe[incompatible-type] we bail out when we get a null + function placeChild(newFiber, lastPlacedIndex, newIndex) { + newFiber.index = newIndex; - update = update.next; + 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 (update === null) { - pendingQueue = queue.shared.pending; + var current = newFiber.alternate; - 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. - - var _firstPendingUpdate = _lastPendingUpdate.next; - _lastPendingUpdate.next = null; - update = _firstPendingUpdate; - queue.lastBaseUpdate = _lastPendingUpdate; - queue.shared.pending = null; - } - } - } while (true); + if (current !== null) { + var oldIndex = current.index; - if (newLastBaseUpdate === null) { - newBaseState = newState; - } + 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; + } + } - queue.baseState = newBaseState; - queue.firstBaseUpdate = newFirstBaseUpdate; - queue.lastBaseUpdate = newLastBaseUpdate; + 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; + } - 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. + return newFiber; + } - markSkippedUpdateLanes(newLanes); - workInProgress.lanes = newLanes; - workInProgress.memoizedState = newState; - } + function updateTextNode(returnFiber, current, textContent, lanes, debugInfo) { + if (current === null || current.tag !== HostText) { + // Insert + var created = createFiberFromText(textContent, returnFiber.mode, lanes); + created.return = returnFiber; { - currentlyProcessingQueue = null; + created._debugInfo = debugInfo; } - } - function callCallback(callback, context) { - if (typeof callback !== "function") { - throw new Error( - "Invalid argument passed as callback. Expected a function. Instead " + - ("received: " + callback) - ); + return created; + } else { + // Update + var existing = useFiber(current, textContent); + existing.return = returnFiber; + + { + existing._debugInfo = debugInfo; } - callback.call(context); + return existing; } + } - function resetHasForceUpdateBeforeProcessing() { - hasForceUpdate = false; - } - function checkHasForceUpdateAfterProcessing() { - return hasForceUpdate; + function updateElement(returnFiber, current, element, lanes, debugInfo) { + var elementType = element.type; + + if (elementType === REACT_FRAGMENT_TYPE) { + return updateFragment(returnFiber, current, element.props.children, lanes, element.key, debugInfo); } - 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; + 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); + coerceRef(returnFiber, current, existing, element); + existing.return = returnFiber; - if (existingHiddenCallbacks === null) { - updateQueue.shared.hiddenCallbacks = newHiddenCallbacks; - } else { - updateQueue.shared.hiddenCallbacks = - existingHiddenCallbacks.concat(newHiddenCallbacks); + { + existing._debugOwner = element._owner; + existing._debugInfo = debugInfo; } + + return existing; } + } // Insert + + + var created = createFiberFromElement(element, returnFiber.mode, lanes); + coerceRef(returnFiber, current, created, element); + created.return = returnFiber; + + { + created._debugInfo = debugInfo; } - 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; + return created; + } - for (var i = 0; i < hiddenCallbacks.length; i++) { - var callback = hiddenCallbacks[i]; - callCallback(callback, context); - } + function updatePortal(returnFiber, current, portal, lanes, debugInfo) { + 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; + + { + created._debugInfo = debugInfo; } - } - function commitCallbacks(updateQueue, context) { - var callbacks = updateQueue.callbacks; - if (callbacks !== null) { - updateQueue.callbacks = null; + return created; + } else { + // Update + var existing = useFiber(current, portal.children || []); + existing.return = returnFiber; - for (var i = 0; i < callbacks.length; i++) { - var callback = callbacks[i]; - callCallback(callback, context); - } + { + existing._debugInfo = debugInfo; } - } - // $FlowFixMe[method-unbinding] - var hasOwnProperty = Object.prototype.hasOwnProperty; + return existing; + } + } - /** - * 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. - */ + function updateFragment(returnFiber, current, fragment, lanes, key, debugInfo) { + if (current === null || current.tag !== Fragment) { + // Insert + var created = createFiberFromFragment(fragment, returnFiber.mode, lanes, key); + created.return = returnFiber; - function shallowEqual(objA, objB) { - if (objectIs(objA, objB)) { - return true; + { + created._debugInfo = debugInfo; } - if ( - typeof objA !== "object" || - objA === null || - typeof objB !== "object" || - objB === null - ) { - return false; - } + return created; + } else { + // Update + var existing = useFiber(current, fragment); + existing.return = returnFiber; - var keysA = Object.keys(objA); - var keysB = Object.keys(objB); + { + existing._debugInfo = debugInfo; + } - if (keysA.length !== keysB.length) { - return false; - } // Test for A's keys different from B. + return existing; + } + } - for (var i = 0; i < keysA.length; i++) { - var currentKey = keysA[i]; + function createChild(returnFiber, newChild, lanes, debugInfo) { + if (typeof newChild === 'string' && newChild !== '' || typeof newChild === 'number' || typeof newChild === 'bigint') { + // 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( // $FlowFixMe[unsafe-addition] Flow doesn't want us to use `+` operator with string and bigint + '' + newChild, returnFiber.mode, lanes); + created.return = returnFiber; - if ( - !hasOwnProperty.call(objB, currentKey) || // $FlowFixMe[incompatible-use] lost refinement of `objB` - !objectIs(objA[currentKey], objB[currentKey]) - ) { - return false; - } + { + created._debugInfo = debugInfo; } - return true; + return created; } - var current = null; - var isRendering = false; - function getCurrentFiberOwnerNameInDevOrNull() { - { - if (current === null) { - return null; - } + if (typeof newChild === 'object' && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + { + var _created = createFiberFromElement(newChild, returnFiber.mode, lanes); - var owner = current._debugOwner; + coerceRef(returnFiber, null, _created, newChild); + _created.return = returnFiber; - if (owner != null) { - return getComponentNameFromOwner(owner); - } + { + _created._debugInfo = mergeDebugInfo(debugInfo, newChild._debugInfo); + } + + return _created; + } + + case REACT_PORTAL_TYPE: + { + var _created2 = createFiberFromPortal(newChild, returnFiber.mode, lanes); + + _created2.return = returnFiber; + + { + _created2._debugInfo = debugInfo; + } + + return _created2; + } + + case REACT_LAZY_TYPE: + { + var payload = newChild._payload; + var init = newChild._init; + return createChild(returnFiber, init(payload), lanes, mergeDebugInfo(debugInfo, newChild._debugInfo) // call merge after init + ); + } } - return null; - } + if (isArray(newChild) || getIteratorFn(newChild)) { + var _created3 = createFiberFromFragment(newChild, returnFiber.mode, lanes, null); + + _created3.return = returnFiber; + + { + _created3._debugInfo = mergeDebugInfo(debugInfo, newChild._debugInfo); + } + + return _created3; + } // Usable node types + // + // Unwrap the inner value and recursively call this function again. - 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. - return getStackByFiberInDevAndProd(current); + if (typeof newChild.then === 'function') { + var thenable = newChild; + return createChild(returnFiber, unwrapThenable(thenable), lanes, mergeDebugInfo(debugInfo, newChild._debugInfo)); } - } - function resetCurrentFiber() { - { - ReactSharedInternals.getCurrentStack = null; - current = null; - isRendering = false; + if (newChild.$$typeof === REACT_CONTEXT_TYPE) { + var context = newChild; + return createChild(returnFiber, readContextDuringReconciliation(returnFiber, context, lanes), lanes, debugInfo); } + + throwOnInvalidObjectType(returnFiber, newChild); } - function setCurrentFiber(fiber) { - { - ReactSharedInternals.getCurrentStack = - fiber === null ? null : getCurrentFiberStackInDev; - current = fiber; - isRendering = false; + + { + if (typeof newChild === 'function') { + warnOnFunctionType(returnFiber, newChild); } - } - function getCurrentFiber() { - { - return current; + + if (typeof newChild === 'symbol') { + warnOnSymbolType(returnFiber, newChild); } } - function setIsRendering(rendering) { - { - isRendering = rendering; + + return null; + } + + function updateSlot(returnFiber, oldFiber, newChild, lanes, debugInfo) { + // 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' || typeof newChild === 'bigint') { + // 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; } + + return updateTextNode(returnFiber, oldFiber, // $FlowFixMe[unsafe-addition] Flow doesn't want us to use `+` operator with string and bigint + '' + newChild, lanes, debugInfo); } - var ReactStrictModeWarnings = { - recordUnsafeLifecycleWarnings: function (fiber, instance) {}, - flushPendingUnsafeLifecycleWarnings: function () {}, - recordLegacyContextWarning: function (fiber, instance) {}, - flushLegacyContextWarning: function () {}, - discardPendingWarnings: function () {} - }; + if (typeof newChild === 'object' && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + { + if (newChild.key === key) { + return updateElement(returnFiber, oldFiber, newChild, lanes, mergeDebugInfo(debugInfo, newChild._debugInfo)); + } else { + return null; + } + } - { - var findStrictRoot = function (fiber) { - var maybeStrictRoot = null; - var node = fiber; + case REACT_PORTAL_TYPE: + { + if (newChild.key === key) { + return updatePortal(returnFiber, oldFiber, newChild, lanes, debugInfo); + } else { + return null; + } + } - while (node !== null) { - if (node.mode & StrictLegacyMode) { - maybeStrictRoot = node; + case REACT_LAZY_TYPE: + { + var payload = newChild._payload; + var init = newChild._init; + return updateSlot(returnFiber, oldFiber, init(payload), lanes, mergeDebugInfo(debugInfo, newChild._debugInfo)); } + } - node = node.return; + if (isArray(newChild) || getIteratorFn(newChild)) { + if (key !== null) { + return null; } - return maybeStrictRoot; - }; - - var setToSortedString = function (set) { - var array = []; - set.forEach(function (value) { - array.push(value); - }); - return array.sort().join(", "); - }; + return updateFragment(returnFiber, oldFiber, newChild, lanes, null, mergeDebugInfo(debugInfo, newChild._debugInfo)); + } // Usable node types + // + // Unwrap the inner value and recursively call this function again. - var pendingComponentWillMountWarnings = []; - var pendingUNSAFE_ComponentWillMountWarnings = []; - var pendingComponentWillReceivePropsWarnings = []; - var pendingUNSAFE_ComponentWillReceivePropsWarnings = []; - var pendingComponentWillUpdateWarnings = []; - var pendingUNSAFE_ComponentWillUpdateWarnings = []; // Tracks components we have already warned about. - - var didWarnAboutUnsafeLifecycles = new Set(); - - ReactStrictModeWarnings.recordUnsafeLifecycleWarnings = function ( - fiber, - instance - ) { - // Dedupe strategy: Warn once per component. - if (didWarnAboutUnsafeLifecycles.has(fiber.type)) { - return; - } - if ( - typeof instance.componentWillMount === "function" && // Don't warn about react-lifecycles-compat polyfilled components. - instance.componentWillMount.__suppressDeprecationWarning !== true - ) { - pendingComponentWillMountWarnings.push(fiber); - } + if (typeof newChild.then === 'function') { + var thenable = newChild; + return updateSlot(returnFiber, oldFiber, unwrapThenable(thenable), lanes, debugInfo); + } - if ( - fiber.mode & StrictLegacyMode && - typeof instance.UNSAFE_componentWillMount === "function" - ) { - pendingUNSAFE_ComponentWillMountWarnings.push(fiber); - } + if (newChild.$$typeof === REACT_CONTEXT_TYPE) { + var context = newChild; + return updateSlot(returnFiber, oldFiber, readContextDuringReconciliation(returnFiber, context, lanes), lanes, debugInfo); + } - if ( - typeof instance.componentWillReceiveProps === "function" && - instance.componentWillReceiveProps.__suppressDeprecationWarning !== - true - ) { - pendingComponentWillReceivePropsWarnings.push(fiber); - } + throwOnInvalidObjectType(returnFiber, newChild); + } - if ( - fiber.mode & StrictLegacyMode && - typeof instance.UNSAFE_componentWillReceiveProps === "function" - ) { - pendingUNSAFE_ComponentWillReceivePropsWarnings.push(fiber); - } + { + if (typeof newChild === 'function') { + warnOnFunctionType(returnFiber, newChild); + } - if ( - typeof instance.componentWillUpdate === "function" && - instance.componentWillUpdate.__suppressDeprecationWarning !== true - ) { - pendingComponentWillUpdateWarnings.push(fiber); - } + if (typeof newChild === 'symbol') { + warnOnSymbolType(returnFiber, newChild); + } + } - if ( - fiber.mode & StrictLegacyMode && - typeof instance.UNSAFE_componentWillUpdate === "function" - ) { - pendingUNSAFE_ComponentWillUpdateWarnings.push(fiber); - } - }; + return null; + } - ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = - function () { - // We do an initial pass to gather component names - var componentWillMountUniqueNames = new Set(); - - if (pendingComponentWillMountWarnings.length > 0) { - pendingComponentWillMountWarnings.forEach(function (fiber) { - componentWillMountUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingComponentWillMountWarnings = []; - } + function updateFromMap(existingChildren, returnFiber, newIdx, newChild, lanes, debugInfo) { + if (typeof newChild === 'string' && newChild !== '' || typeof newChild === 'number' || typeof newChild === 'bigint') { + // 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, // $FlowFixMe[unsafe-addition] Flow doesn't want us to use `+` operator with string and bigint + '' + newChild, lanes, debugInfo); + } - var UNSAFE_componentWillMountUniqueNames = new Set(); + 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 (pendingUNSAFE_ComponentWillMountWarnings.length > 0) { - pendingUNSAFE_ComponentWillMountWarnings.forEach(function (fiber) { - UNSAFE_componentWillMountUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingUNSAFE_ComponentWillMountWarnings = []; + return updateElement(returnFiber, _matchedFiber, newChild, lanes, mergeDebugInfo(debugInfo, newChild._debugInfo)); } - var componentWillReceivePropsUniqueNames = new Set(); + case REACT_PORTAL_TYPE: + { + var _matchedFiber2 = existingChildren.get(newChild.key === null ? newIdx : newChild.key) || null; - if (pendingComponentWillReceivePropsWarnings.length > 0) { - pendingComponentWillReceivePropsWarnings.forEach(function (fiber) { - componentWillReceivePropsUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingComponentWillReceivePropsWarnings = []; + return updatePortal(returnFiber, _matchedFiber2, newChild, lanes, debugInfo); } - var UNSAFE_componentWillReceivePropsUniqueNames = new Set(); + case REACT_LAZY_TYPE: + var payload = newChild._payload; + var init = newChild._init; + return updateFromMap(existingChildren, returnFiber, newIdx, init(payload), lanes, mergeDebugInfo(debugInfo, newChild._debugInfo)); + } - if (pendingUNSAFE_ComponentWillReceivePropsWarnings.length > 0) { - pendingUNSAFE_ComponentWillReceivePropsWarnings.forEach( - function (fiber) { - UNSAFE_componentWillReceivePropsUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - } - ); - pendingUNSAFE_ComponentWillReceivePropsWarnings = []; - } + if (isArray(newChild) || getIteratorFn(newChild)) { + var _matchedFiber3 = existingChildren.get(newIdx) || null; - var componentWillUpdateUniqueNames = new Set(); + return updateFragment(returnFiber, _matchedFiber3, newChild, lanes, null, mergeDebugInfo(debugInfo, newChild._debugInfo)); + } // Usable node types + // + // Unwrap the inner value and recursively call this function again. - if (pendingComponentWillUpdateWarnings.length > 0) { - pendingComponentWillUpdateWarnings.forEach(function (fiber) { - componentWillUpdateUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingComponentWillUpdateWarnings = []; - } - var UNSAFE_componentWillUpdateUniqueNames = new Set(); - - 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 (UNSAFE_componentWillMountUniqueNames.size > 0) { - var sortedNames = setToSortedString( - UNSAFE_componentWillMountUniqueNames - ); + if (typeof newChild.then === 'function') { + var thenable = newChild; + return updateFromMap(existingChildren, returnFiber, newIdx, unwrapThenable(thenable), lanes, debugInfo); + } - error( - "Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code. " + - "See https://react.dev/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 (newChild.$$typeof === REACT_CONTEXT_TYPE) { + var context = newChild; + return updateFromMap(existingChildren, returnFiber, newIdx, readContextDuringReconciliation(returnFiber, context, lanes), lanes, debugInfo); + } - if (UNSAFE_componentWillReceivePropsUniqueNames.size > 0) { - var _sortedNames = setToSortedString( - UNSAFE_componentWillReceivePropsUniqueNames - ); + throwOnInvalidObjectType(returnFiber, newChild); + } - error( - "Using UNSAFE_componentWillReceiveProps in strict mode is not recommended " + - "and may indicate bugs in your code. " + - "See https://react.dev/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://react.dev/link/derived-state\n" + - "\nPlease update the following components: %s", - _sortedNames - ); - } + { + if (typeof newChild === 'function') { + warnOnFunctionType(returnFiber, newChild); + } - if (UNSAFE_componentWillUpdateUniqueNames.size > 0) { - var _sortedNames2 = setToSortedString( - UNSAFE_componentWillUpdateUniqueNames - ); + if (typeof newChild === 'symbol') { + warnOnSymbolType(returnFiber, newChild); + } + } - error( - "Using UNSAFE_componentWillUpdate in strict mode is not recommended " + - "and may indicate bugs in your code. " + - "See https://react.dev/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 null; + } + /** + * Warns if there is a duplicate or missing key + */ - if (componentWillMountUniqueNames.size > 0) { - var _sortedNames3 = setToSortedString( - componentWillMountUniqueNames - ); - warn( - "componentWillMount has been renamed, and is not recommended for use. " + - "See https://react.dev/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 - ); - } + function warnOnInvalidKey(child, knownKeys, returnFiber) { + { + if (typeof child !== 'object' || child === null) { + return knownKeys; + } - if (componentWillReceivePropsUniqueNames.size > 0) { - var _sortedNames4 = setToSortedString( - componentWillReceivePropsUniqueNames - ); + switch (child.$$typeof) { + case REACT_ELEMENT_TYPE: + case REACT_PORTAL_TYPE: + warnForMissingKey(child, returnFiber); + var key = child.key; - warn( - "componentWillReceiveProps has been renamed, and is not recommended for use. " + - "See https://react.dev/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://react.dev/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 (typeof key !== 'string') { + break; } - if (componentWillUpdateUniqueNames.size > 0) { - var _sortedNames5 = setToSortedString( - componentWillUpdateUniqueNames - ); + if (knownKeys === null) { + knownKeys = new Set(); + knownKeys.add(key); + break; + } - warn( - "componentWillUpdate has been renamed, and is not recommended for use. " + - "See https://react.dev/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 (!knownKeys.has(key)) { + knownKeys.add(key); + break; } - }; - var pendingLegacyContextWarning = new Map(); // Tracks components we have already warned about. + 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); - var didWarnAboutLegacyContext = new Set(); + break; - ReactStrictModeWarnings.recordLegacyContextWarning = function ( - fiber, - instance - ) { - var strictRoot = findStrictRoot(fiber); + case REACT_LAZY_TYPE: + var payload = child._payload; + var init = child._init; + warnOnInvalidKey(init(payload), knownKeys, returnFiber); + break; + } + } - 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." - ); + return knownKeys; + } + + function reconcileChildrenArray(returnFiber, currentFirstChild, newChildren, lanes, debugInfo) { + // 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; - return; - } // Dedup strategy: Warn once per component. + for (var i = 0; i < newChildren.length; i++) { + var child = newChildren[i]; + knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber); + } + } - if (didWarnAboutLegacyContext.has(fiber.type)) { - return; - } + var resultingFirstChild = null; + var previousNewFiber = null; + var oldFiber = currentFirstChild; + var lastPlacedIndex = 0; + var newIdx = 0; + var nextOldFiber = null; - var warningsForRoot = pendingLegacyContextWarning.get(strictRoot); + for (; oldFiber !== null && newIdx < newChildren.length; newIdx++) { + if (oldFiber.index > newIdx) { + nextOldFiber = oldFiber; + oldFiber = null; + } else { + nextOldFiber = oldFiber.sibling; + } - if ( - fiber.type.contextTypes != null || - fiber.type.childContextTypes != null || - (instance !== null && typeof instance.getChildContext === "function") - ) { - if (warningsForRoot === undefined) { - warningsForRoot = []; - pendingLegacyContextWarning.set(strictRoot, warningsForRoot); - } + var newFiber = updateSlot(returnFiber, oldFiber, newChildren[newIdx], lanes, debugInfo); - warningsForRoot.push(fiber); + 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; } - }; - - ReactStrictModeWarnings.flushLegacyContextWarning = function () { - pendingLegacyContextWarning.forEach(function (fiberArray, strictRoot) { - if (fiberArray.length === 0) { - return; - } - - 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); - - try { - setCurrentFiber(firstFiber); - - 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://react.dev/link/legacy-context", - sortedNames - ); - } finally { - resetCurrentFiber(); - } - }); - }; - ReactStrictModeWarnings.discardPendingWarnings = function () { - pendingComponentWillMountWarnings = []; - pendingUNSAFE_ComponentWillMountWarnings = []; - pendingComponentWillReceivePropsWarnings = []; - pendingUNSAFE_ComponentWillReceivePropsWarnings = []; - pendingComponentWillUpdateWarnings = []; - pendingUNSAFE_ComponentWillUpdateWarnings = []; - pendingLegacyContextWarning = new Map(); - }; - } + break; + } - function getThenablesFromState(state) { - { - var devState = state; - return devState.thenables; - } - } // 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. - - 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 noopSuspenseyCommitThenable = { - then: function () { - { - error( - "Internal React error: A listener was unexpectedly attached to a " + - '"noop" thenable. This is a bug in React. Please file an issue.' - ); + 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 createThenableState() { - // The ThenableState is created the first time a component suspends. If it - // suspends again, we'll reuse the same state. - { - return { - didWarnAboutUncachedPromise: false, - thenables: [] - }; - } - } - function isThenableResolved(thenable) { - var status = thenable.status; - return status === "fulfilled" || status === "rejected"; - } - function noop() {} + lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); - function trackUsedThenable(thenableState, thenable, index) { - if (ReactSharedInternals.actQueue !== null) { - ReactSharedInternals.didUsePromise = true; + 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; } - var trackedThenables = getThenablesFromState(thenableState); - var previous = trackedThenables[index]; + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } - if (previous === undefined) { - trackedThenables.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. - { - var thenableStateDev = thenableState; + if (newIdx === newChildren.length) { + // We've reached the end of the new children. We can delete the rest. + deleteRemainingChildren(returnFiber, oldFiber); - if (!thenableStateDev.didWarnAboutUncachedPromise) { - // We should only warn the first time an uncached thenable is - // discovered per component, because if there are multiple, the - // subsequent ones are likely derived from the first. - // - // We track this on the thenableState instead of deduping using the - // component name like we usually do, because in the case of a - // promise-as-React-node, the owner component is likely different from - // the parent that's currently being reconciled. We'd have to track - // the owner using state, which we're trying to move away from. Though - // since this is dev-only, maybe that'd be OK. - // - // However, another benefit of doing it this way is we might - // eventually have a thenableState per memo/Forget boundary instead - // of per component, so this would allow us to have more - // granular warnings. - thenableStateDev.didWarnAboutUncachedPromise = true; // TODO: This warning should link to a corresponding docs page. - - error( - "A component was suspended by an uncached promise. Creating " + - "promises inside a Client Component or hook is not yet " + - "supported, except via a Suspense-compatible library or framework." - ); - } - } // Avoid an unhandled rejection errors for the Promises that we'll - // intentionally ignore. + return resultingFirstChild; + } - thenable.then(noop, noop); - thenable = previous; - } - } // 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. + 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, debugInfo); - switch (thenable.status) { - case "fulfilled": { - var fulfilledValue = thenable.value; - return fulfilledValue; + if (_newFiber === null) { + continue; } - case "rejected": { - var rejectedError = thenable.reason; - checkIfUseWrappedInAsyncCatch(rejectedError); - throw rejectedError; + 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; } - 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 { - // This is an uncached thenable that we haven't seen before. - // Detect infinite ping loops caused by uncached promises. - var root = getWorkInProgressRoot(); - - if (root !== null && root.shellSuspendCounter > 100) { - // This root has suspended repeatedly in the shell without making any - // progress (i.e. committing something). This is highly suggestive of - // an infinite ping loop, often caused by an accidental Async Client - // Component. - // - // During a transition, we can suspend the work loop until the promise - // to resolve, but this is a sync render, so that's not an option. We - // also can't show a fallback, because none was provided. So our last - // resort is to throw an error. - // - // TODO: Remove this error in a future release. Other ways of handling - // this case include forcing a concurrent render, or putting the whole - // root into offscreen mode. - throw new Error( - "async/await is not yet supported in Client Components, only " + - "Server Components. This error is often caused by accidentally " + - "adding `'use client'` to a module that was originally written " + - "for the server." - ); - } + previousNewFiber = _newFiber; + } - 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. + return resultingFirstChild; + } // Add all children to a key map for quick lookups. - switch (thenable.status) { - case "fulfilled": { - var fulfilledThenable = thenable; - return fulfilledThenable.value; - } - case "rejected": { - var rejectedThenable = thenable; - var _rejectedError = rejectedThenable.reason; - checkIfUseWrappedInAsyncCatch(_rejectedError); - throw _rejectedError; - } - } // 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. + var existingChildren = mapRemainingChildren(oldFiber); // Keep scanning and use the map to restore deleted items as moves. - suspendedThenable = thenable; + for (; newIdx < newChildren.length; newIdx++) { + var _newFiber2 = updateFromMap(existingChildren, returnFiber, newIdx, newChildren[newIdx], lanes, debugInfo); - { - needsToResetSuspendedThenableDEV = true; + 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); } - - throw SuspenseException; } - } - } - // 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." - ); - } + lastPlacedIndex = placeChild(_newFiber2, lastPlacedIndex, newIdx); - var thenable = suspendedThenable; - suspendedThenable = null; + if (previousNewFiber === null) { + resultingFirstChild = _newFiber2; + } else { + previousNewFiber.sibling = _newFiber2; + } - { - needsToResetSuspendedThenableDEV = false; + previousNewFiber = _newFiber2; } - - 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; - } - } - return false; - } - function checkIfUseWrappedInAsyncCatch(rejectedReason) { - // This check runs in prod, too, because it prevents a more confusing - // downstream error, where SuspenseException is caught by a promise and - // thrown asynchronously. - // TODO: Another way to prevent SuspenseException from leaking into an async - // execution context is to check the dispatcher every time `use` is called, - // or some equivalent. That might be preferable for other reasons, too, since - // it matches how we prevent similar mistakes for other hooks. - if (rejectedReason === SuspenseException) { - throw new Error( - "Hooks are not supported inside an async component. This " + - "error is often caused by accidentally adding `'use client'` " + - "to a module that was originally written for the server." - ); - } - } - - var thenableState$1 = null; - var thenableIndexCounter$1 = 0; - - function mergeDebugInfo(outer, inner) { - if (inner == null) { - return outer; - } else if (outer === null) { - return inner; - } else { - // If we have two debugInfo, we need to create a new one. This makes the array no longer - // live so we'll miss any future updates if we received more so ideally we should always - // do this after both have fully resolved/unsuspended. - return outer.concat(inner); - } + 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); + }); } - var didWarnAboutMaps; - var didWarnAboutGenerators; - var ownerHasKeyUseWarning; - var ownerHasFunctionTypeWarning; - var ownerHasSymbolTypeWarning; + return resultingFirstChild; + } - var warnForMissingKey = function (child, returnFiber) {}; + function reconcileChildrenIterator(returnFiber, currentFirstChild, newChildrenIterable, lanes, debugInfo) { + // This is the same implementation as reconcileChildrenArray(), + // but using the iterator instead. + var iteratorFn = getIteratorFn(newChildrenIterable); - { - didWarnAboutMaps = false; - didWarnAboutGenerators = false; - /** - * 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 = {}; - ownerHasSymbolTypeWarning = {}; - - warnForMissingKey = function (child, returnFiber) { - if (child === null || typeof child !== "object") { - return; - } + 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.'); + } - if (!child._store || child._store.validated || child.key != null) { - return; + { + // We don't support rendering Generators because it's a mutation. + // See https://github.com/facebook/react/issues/12995 + if (typeof Symbol === 'function' && // $FlowFixMe[prop-missing] 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.'); } - 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[cannot-write] unable to narrow type from mixed to writable object + didWarnAboutGenerators = true; + } // Warn about using Maps as children - child._store.validated = true; - var componentName = - getComponentNameFromFiber(returnFiber) || "Component"; - if (ownerHasKeyUseWarning[componentName]) { - return; + if (newChildrenIterable.entries === iteratorFn) { + if (!didWarnAboutMaps) { + error('Using Maps as children is not supported. ' + 'Use an array of keyed ReactElements instead.'); } - ownerHasKeyUseWarning[componentName] = true; + didWarnAboutMaps = true; + } // First, validate keys. + // We'll get a different iterator later for the main pass. - error( - "Each child in a list should have a unique " + - '"key" prop. See https://react.dev/link/warning-keys for ' + - "more information." - ); - }; - } - function unwrapThenable(thenable) { - var index = thenableIndexCounter$1; - thenableIndexCounter$1 += 1; + var _newChildren = iteratorFn.call(newChildrenIterable); - if (thenableState$1 === null) { - thenableState$1 = createThenableState(); - } + if (_newChildren) { + var knownKeys = null; - return trackUsedThenable(thenableState$1, thenable, index); - } + var _step = _newChildren.next(); - function coerceRef(returnFiber, current, workInProgress, element) { - var ref; + for (; !_step.done; _step = _newChildren.next()) { + var child = _step.value; + knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber); + } + } + } - { - // Old behavior. - ref = element.ref; - } // TODO: If enableRefAsProp is on, we shouldn't use the `ref` field. We - // should always read the ref from the prop. + var newChildren = iteratorFn.call(newChildrenIterable); - workInProgress.ref = ref; + if (newChildren == null) { + throw new Error('An iterable object provided no iterator.'); } - 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 warnOnFunctionType(returnFiber, invalidChild) { - { - var parentName = getComponentNameFromFiber(returnFiber) || "Component"; + var resultingFirstChild = null; + var previousNewFiber = null; + var oldFiber = currentFirstChild; + var lastPlacedIndex = 0; + var newIdx = 0; + var nextOldFiber = null; + var step = newChildren.next(); - if (ownerHasFunctionTypeWarning[parentName]) { - return; + for (; oldFiber !== null && !step.done; newIdx++, step = newChildren.next()) { + if (oldFiber.index > newIdx) { + nextOldFiber = oldFiber; + oldFiber = null; + } else { + nextOldFiber = oldFiber.sibling; + } + + var newFiber = updateSlot(returnFiber, oldFiber, step.value, lanes, debugInfo); + + 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; } - ownerHasFunctionTypeWarning[parentName] = true; - var name = invalidChild.displayName || invalidChild.name || "Component"; + break; + } - if (returnFiber.tag === HostRoot) { - error( - "Functions are not valid as a React child. This may happen if " + - "you return %s instead of <%s /> from render. " + - "Or maybe you meant to call this function rather than return it.\n" + - " root.render(%s)", - name, - name, - name - ); - } else { - error( - "Functions are not valid as a React child. This may happen if " + - "you return %s instead of <%s /> from render. " + - "Or maybe you meant to call this function rather than return it.\n" + - " <%s>{%s}", - name, - name, - parentName, - name, - parentName - ); + 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 warnOnSymbolType(returnFiber, invalidChild) { - { - var parentName = getComponentNameFromFiber(returnFiber) || "Component"; + lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); - if (ownerHasSymbolTypeWarning[parentName]) { - return; - } + 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; + } - ownerHasSymbolTypeWarning[parentName] = true; // eslint-disable-next-line react-internal/safe-string-coercion + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } - var name = String(invalidChild); + if (step.done) { + // We've reached the end of the new children. We can delete the rest. + deleteRemainingChildren(returnFiber, oldFiber); - if (returnFiber.tag === HostRoot) { - error( - "Symbols are not valid as a React child.\n" + " root.render(%s)", - name - ); - } else { - error( - "Symbols are not valid as a React child.\n" + " <%s>%s", - parentName, - name, - parentName - ); - } - } + return resultingFirstChild; } - 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 (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, debugInfo); - function createChildReconciler(shouldTrackSideEffects) { - function deleteChild(returnFiber, childToDelete) { - if (!shouldTrackSideEffects) { - // Noop. - return; + if (_newFiber3 === null) { + continue; } - var deletions = returnFiber.deletions; + lastPlacedIndex = placeChild(_newFiber3, lastPlacedIndex, newIdx); - if (deletions === null) { - returnFiber.deletions = [childToDelete]; - returnFiber.flags |= ChildDeletion; + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = _newFiber3; } else { - deletions.push(childToDelete); + previousNewFiber.sibling = _newFiber3; } - } - 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. + previousNewFiber = _newFiber3; + } - var childToDelete = currentFirstChild; + return resultingFirstChild; + } // Add all children to a key map for quick lookups. - while (childToDelete !== null) { - deleteChild(returnFiber, childToDelete); - childToDelete = childToDelete.sibling; - } - return null; - } + var existingChildren = mapRemainingChildren(oldFiber); // Keep scanning and use the map to restore deleted items as moves. - function mapRemainingChildren(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; + for (; !step.done; newIdx++, step = newChildren.next()) { + var _newFiber4 = updateFromMap(existingChildren, returnFiber, newIdx, step.value, lanes, debugInfo); - while (existingChild !== null) { - if (existingChild.key !== null) { - existingChildren.set(existingChild.key, existingChild); - } else { - existingChildren.set(existingChild.index, existingChild); + 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); } - - existingChild = existingChild.sibling; } - return existingChildren; - } + lastPlacedIndex = placeChild(_newFiber4, lastPlacedIndex, newIdx); + + if (previousNewFiber === null) { + resultingFirstChild = _newFiber4; + } else { + previousNewFiber.sibling = _newFiber4; + } - 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; + previousNewFiber = _newFiber4; } + } - function placeChild(newFiber, lastPlacedIndex, newIndex) { - newFiber.index = newIndex; + 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); + }); + } - 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; - } + return resultingFirstChild; + } + + 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; + } + + function reconcileSingleElement(returnFiber, currentFirstChild, element, lanes, debugInfo) { + var key = element.key; + var child = currentFirstChild; + + 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; - var current = newFiber.alternate; + if (elementType === REACT_FRAGMENT_TYPE) { + if (child.tag === Fragment) { + deleteRemainingChildren(returnFiber, child.sibling); + var existing = useFiber(child, element.props.children); + existing.return = returnFiber; - if (current !== null) { - var oldIndex = current.index; + { + existing._debugOwner = element._owner; + existing._debugInfo = debugInfo; + } - if (oldIndex < lastPlacedIndex) { - // This is a move. - newFiber.flags |= Placement | PlacementDEV; - return lastPlacedIndex; - } else { - // This item can stay in place. - return oldIndex; + return existing; } } else { - // This is an insertion. - newFiber.flags |= Placement | PlacementDEV; - return lastPlacedIndex; - } + 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); + + var _existing = useFiber(child, element.props); + + coerceRef(returnFiber, child, _existing, element); + _existing.return = returnFiber; + + { + _existing._debugOwner = element._owner; + _existing._debugInfo = debugInfo; + } + + return _existing; + } + } // Didn't match. + + + deleteRemainingChildren(returnFiber, child); + break; + } else { + deleteChild(returnFiber, 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; - } + child = child.sibling; + } + + if (element.type === REACT_FRAGMENT_TYPE) { + var created = createFiberFromFragment(element.props.children, returnFiber.mode, lanes, element.key); + created.return = returnFiber; - return newFiber; + { + created._debugInfo = debugInfo; } - function updateTextNode( - returnFiber, - current, - textContent, - lanes, - debugInfo - ) { - if (current === null || current.tag !== HostText) { - // Insert - var created = createFiberFromText( - textContent, - returnFiber.mode, - lanes - ); - created.return = returnFiber; + return created; + } else { + var _created4 = createFiberFromElement(element, returnFiber.mode, lanes); - { - created._debugInfo = debugInfo; - } + coerceRef(returnFiber, currentFirstChild, _created4, element); + _created4.return = returnFiber; - return created; - } else { - // Update - var existing = useFiber(current, textContent); - existing.return = returnFiber; + { + _created4._debugInfo = debugInfo; + } - { - existing._debugInfo = debugInfo; - } + return _created4; + } + } + function reconcileSinglePortal(returnFiber, currentFirstChild, portal, lanes, debugInfo) { + var key = portal.key; + var child = currentFirstChild; + + 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 updateElement(returnFiber, current, element, lanes, debugInfo) { - var elementType = element.type; + child = child.sibling; + } + + 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. - if (elementType === REACT_FRAGMENT_TYPE) { - return updateFragment( - returnFiber, - current, - element.props.children, - lanes, - element.key, - debugInfo - ); - } - 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); - coerceRef(returnFiber, current, existing, element); - existing.return = returnFiber; + function reconcileChildFibersImpl(returnFiber, currentFirstChild, newChild, lanes, debugInfo) { + // This function is only recursive for Usables/Lazy and not nested arrays. + // That's so that using a Lazy wrapper is unobservable to the Fragment + // convention. + // 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. + // We don't use recursion here because a fragment inside a fragment + // is no longer considered "top level" for these purposes. + var isUnkeyedTopLevelFragment = typeof newChild === 'object' && newChild !== null && newChild.type === REACT_FRAGMENT_TYPE && newChild.key === null; - { - existing._debugOwner = element._owner; - existing._debugInfo = debugInfo; - } + if (isUnkeyedTopLevelFragment) { + newChild = newChild.props.children; + } // Handle object types - return existing; - } - } // Insert - var created = createFiberFromElement(element, returnFiber.mode, lanes); - coerceRef(returnFiber, current, created, element); - created.return = returnFiber; + if (typeof newChild === 'object' && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return placeSingleChild(reconcileSingleElement(returnFiber, currentFirstChild, newChild, lanes, mergeDebugInfo(debugInfo, newChild._debugInfo))); - { - created._debugInfo = debugInfo; - } + case REACT_PORTAL_TYPE: + return placeSingleChild(reconcileSinglePortal(returnFiber, currentFirstChild, newChild, lanes)); - return created; + case REACT_LAZY_TYPE: + var payload = newChild._payload; + var init = newChild._init; + return reconcileChildFibersImpl(returnFiber, currentFirstChild, init(payload), lanes, mergeDebugInfo(debugInfo, newChild._debugInfo)); } - function updatePortal(returnFiber, current, portal, lanes, debugInfo) { - 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; - - { - created._debugInfo = debugInfo; - } + if (isArray(newChild)) { + return reconcileChildrenArray(returnFiber, currentFirstChild, newChild, lanes, mergeDebugInfo(debugInfo, newChild._debugInfo)); + } - return created; - } else { - // Update - var existing = useFiber(current, portal.children || []); - existing.return = returnFiber; + if (getIteratorFn(newChild)) { + return reconcileChildrenIterator(returnFiber, currentFirstChild, newChild, lanes, mergeDebugInfo(debugInfo, newChild._debugInfo)); + } // 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. - { - existing._debugInfo = debugInfo; - } - return existing; - } + if (typeof newChild.then === 'function') { + var thenable = newChild; + return reconcileChildFibersImpl(returnFiber, currentFirstChild, unwrapThenable(thenable), lanes, mergeDebugInfo(debugInfo, thenable._debugInfo)); } - function updateFragment( - returnFiber, - current, - fragment, - lanes, - key, - debugInfo - ) { - if (current === null || current.tag !== Fragment) { - // Insert - var created = createFiberFromFragment( - fragment, - returnFiber.mode, - lanes, - key - ); - created.return = returnFiber; - - { - created._debugInfo = debugInfo; - } + if (newChild.$$typeof === REACT_CONTEXT_TYPE) { + var context = newChild; + return reconcileChildFibersImpl(returnFiber, currentFirstChild, readContextDuringReconciliation(returnFiber, context, lanes), lanes, debugInfo); + } - return created; - } else { - // Update - var existing = useFiber(current, fragment); - existing.return = returnFiber; + throwOnInvalidObjectType(returnFiber, newChild); + } - { - existing._debugInfo = debugInfo; - } + if (typeof newChild === 'string' && newChild !== '' || typeof newChild === 'number' || typeof newChild === 'bigint') { + return placeSingleChild(reconcileSingleTextNode(returnFiber, currentFirstChild, // $FlowFixMe[unsafe-addition] Flow doesn't want us to use `+` operator with string and bigint + '' + newChild, lanes)); + } - return existing; - } + { + if (typeof newChild === 'function') { + warnOnFunctionType(returnFiber, newChild); } - function createChild(returnFiber, newChild, lanes, debugInfo) { - if ( - (typeof newChild === "string" && newChild !== "") || - typeof newChild === "number" || - typeof newChild === "bigint" - ) { - // 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( - // $FlowFixMe[unsafe-addition] Flow doesn't want us to use `+` operator with string and bigint - "" + newChild, - returnFiber.mode, - lanes - ); - created.return = returnFiber; + if (typeof newChild === 'symbol') { + warnOnSymbolType(returnFiber, newChild); + } + } // Remaining cases are all treated as empty. - { - created._debugInfo = debugInfo; - } - return created; - } + return deleteRemainingChildren(returnFiber, currentFirstChild); + } - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: { - var _created = createFiberFromElement( - newChild, - returnFiber.mode, - lanes - ); + 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, null // debugInfo + ); + thenableState$1 = null; // Don't bother to reset `thenableIndexCounter` to 0 because it always gets + // set at the beginning. - coerceRef(returnFiber, null, _created, newChild); - _created.return = returnFiber; + return firstChildFiber; + } - { - _created._debugInfo = mergeDebugInfo( - debugInfo, - newChild._debugInfo - ); - } + return reconcileChildFibers; +} - return _created; - } +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 (workInProgress.child === null) { + return; + } + + var currentChild = workInProgress.child; + var newChild = createWorkInProgress(currentChild, currentChild.pendingProps); + workInProgress.child = newChild; + newChild.return = workInProgress; + + while (currentChild.sibling !== null) { + currentChild = currentChild.sibling; + newChild = newChild.sibling = createWorkInProgress(currentChild, currentChild.pendingProps); + newChild.return = workInProgress; + } + + newChild.sibling = null; +} // Reset a workInProgress child set to prepare it for a second pass. + +function resetChildFibers(workInProgress, lanes) { + var child = workInProgress.child; + + while (child !== null) { + resetWorkInProgress(child, lanes); + child = child.sibling; + } +} - case REACT_PORTAL_TYPE: { - var _created2 = createFiberFromPortal( - newChild, - returnFiber.mode, - lanes - ); +// TODO: This isn't being used yet, but it's intended to replace the +// InvisibleParentContext that is currently managed by SuspenseContext. - _created2.return = returnFiber; +var currentTreeHiddenStackCursor = createCursor(null); +var prevEntangledRenderLanesCursor = createCursor(NoLanes); +function pushHiddenContext(fiber, context) { + var prevEntangledRenderLanes = getEntangledRenderLanes(); + push(prevEntangledRenderLanesCursor, prevEntangledRenderLanes, 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. - { - _created2._debugInfo = debugInfo; - } + setEntangledRenderLanes(mergeLanes(prevEntangledRenderLanes, 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(prevEntangledRenderLanesCursor, getEntangledRenderLanes(), fiber); + push(currentTreeHiddenStackCursor, currentTreeHiddenStackCursor.current, fiber); +} +function popHiddenContext(fiber) { + // Restore the previous render lanes from the stack + setEntangledRenderLanes(prevEntangledRenderLanesCursor.current); + pop(currentTreeHiddenStackCursor, fiber); + pop(prevEntangledRenderLanesCursor, fiber); +} +function isCurrentTreeHidden() { + return currentTreeHiddenStackCursor.current !== null; +} - return _created2; - } +// suspends, i.e. it's the nearest `catch` block on the stack. + +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. - case REACT_LAZY_TYPE: { - var payload = newChild._payload; - var init = newChild._init; - return createChild( - returnFiber, - init(payload), - lanes, - mergeDebugInfo(debugInfo, newChild._debugInfo) // call merge after init - ); - } - } + 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. - if (isArray(newChild) || getIteratorFn(newChild)) { - var _created3 = createFiberFromFragment( - newChild, - returnFiber.mode, - lanes, - null - ); - _created3.return = returnFiber; + push(suspenseHandlerStackCursor, handler, handler); - { - _created3._debugInfo = mergeDebugInfo( - debugInfo, - newChild._debugInfo - ); - } + if (shellBoundary === null) { + if (current === null || isCurrentTreeHidden()) { + // This boundary is not visible in the current UI. + shellBoundary = handler; + } else { + var prevState = current.memoizedState; - return _created3; - } // Usable node types - // - // Unwrap the inner value and recursively call this function again. - - if (typeof newChild.then === "function") { - var thenable = newChild; - return createChild( - returnFiber, - unwrapThenable(thenable), - lanes, - mergeDebugInfo(debugInfo, newChild._debugInfo) - ); - } + 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 (shellBoundary !== null) ; else { + var current = fiber.alternate; - if (newChild.$$typeof === REACT_CONTEXT_TYPE) { - var context = newChild; - return createChild( - returnFiber, - readContextDuringReconciliation(returnFiber, context, lanes), - lanes, - debugInfo - ); - } + if (current !== null) { + var prevState = current.memoizedState; - throwOnInvalidObjectType(returnFiber, newChild); + 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; } + } + } + } 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. + +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 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); +} - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber, newChild); - } +// 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. - if (typeof newChild === "symbol") { - warnOnSymbolType(returnFiber, newChild); - } +function findFirstSuspended(row) { + var node = row; + + while (node !== null) { + if (node.tag === SuspenseComponent) { + var state = node.memoizedState; + + if (state !== null) { + var dehydrated = state.dehydrated; + + if (dehydrated === null || isSuspenseInstancePending() || isSuspenseInstanceFallback()) { + return node; } + } + } 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; + } + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } + + if (node === row) { + return null; + } + while (node.sibling === null) { + if (node.return === null || node.return === row) { return null; } - function updateSlot(returnFiber, oldFiber, newChild, lanes, debugInfo) { - // Update the fiber if the keys match, otherwise return null. - var key = oldFiber !== null ? oldFiber.key : null; + node = node.return; + } - if ( - (typeof newChild === "string" && newChild !== "") || - typeof newChild === "number" || - typeof newChild === "bigint" - ) { - // 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.sibling.return = node.return; + node = node.sibling; + } - return updateTextNode( - returnFiber, - oldFiber, // $FlowFixMe[unsafe-addition] Flow doesn't want us to use `+` operator with string and bigint - "" + newChild, - lanes, - debugInfo - ); - } - - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: { - if (newChild.key === key) { - return updateElement( - returnFiber, - oldFiber, - newChild, - lanes, - mergeDebugInfo(debugInfo, newChild._debugInfo) - ); - } else { - return null; - } - } + return null; +} - case REACT_PORTAL_TYPE: { - if (newChild.key === key) { - return updatePortal( - returnFiber, - oldFiber, - newChild, - lanes, - debugInfo - ); - } else { - return null; - } - } +var NoFlags = +/* */ +0; // Represents whether effect should fire. + +var HasEffect = +/* */ +1; // Represents the phase in which the effect (not the clean-up) fires. + +var Insertion = +/* */ +2; +var Layout = +/* */ +4; +var Passive = +/* */ +8; + +var didWarnAboutMismatchedHooksForComponent; +var didWarnUncachedGetSnapshot; +var didWarnAboutUseWrappedInTryCatch; +var didWarnAboutAsyncClientComponent; +var didWarnAboutUseFormState; + +{ + didWarnAboutMismatchedHooksForComponent = new Set(); + didWarnAboutUseWrappedInTryCatch = new Set(); + didWarnAboutAsyncClientComponent = new Set(); + didWarnAboutUseFormState = new Set(); +} // The effect "instance" is a shared object that remains the same for the entire +// lifetime of an effect. In Rust terms, a RefCell. We use it to store the +// "destroy" function that is returned from an effect, because that is stateful. +// The field is `undefined` if the effect is unmounted, or if the effect ran +// but is not stateful. We don't explicitly track whether the effect is mounted +// or unmounted because that can be inferred by the hiddenness of the fiber in +// the tree, i.e. whether there is a hidden Offscreen fiber above it. +// +// It's unfortunate that this is stored on a separate object, because it adds +// more memory per effect instance, but it's conceptually sound. I think there's +// likely a better data structure we could use for effects; perhaps just one +// array of effect instances per fiber. But I think this is OK for now despite +// the additional memory and we can follow up with performance +// optimizations later. +// These are set right before calling the component. + + +var renderLanes = 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`. + +var didScheduleRenderPhaseUpdateDuringThisPass = false; +var shouldDoubleInvokeUserFnsInHooksDEV = false; // Counts the number of useId hooks in this component. + +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. + +var globalClientIdCounter = 0; +var RE_RENDER_LIMIT = 25; // In DEV, this is the name of the currently executing primitive hook + +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. + +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 { + hookTypesDev.push(hookName); + } + } +} - case REACT_LAZY_TYPE: { - var payload = newChild._payload; - var init = newChild._init; - return updateSlot( - returnFiber, - oldFiber, - init(payload), - lanes, - mergeDebugInfo(debugInfo, newChild._debugInfo) - ); - } - } +function updateHookTypesDev() { + { + var hookName = currentHookNameInDev; - if (isArray(newChild) || getIteratorFn(newChild)) { - if (key !== null) { - return null; - } + if (hookTypesDev !== null) { + hookTypesUpdateIndexDev++; - return updateFragment( - returnFiber, - oldFiber, - newChild, - lanes, - null, - mergeDebugInfo(debugInfo, newChild._debugInfo) - ); - } // 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, - debugInfo - ); - } + if (hookTypesDev[hookTypesUpdateIndexDev] !== hookName) { + warnOnHookMismatchInDev(hookName); + } + } + } +} - if (newChild.$$typeof === REACT_CONTEXT_TYPE) { - var context = newChild; - return updateSlot( - returnFiber, - oldFiber, - readContextDuringReconciliation(returnFiber, context, lanes), - lanes, - debugInfo - ); - } +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); + } + } +} - throwOnInvalidObjectType(returnFiber, newChild); - } +function warnOnHookMismatchInDev(currentHookName) { + { + var componentName = getComponentNameFromFiber(currentlyRenderingFiber$1); - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber, newChild); - } + if (!didWarnAboutMismatchedHooksForComponent.has(componentName)) { + didWarnAboutMismatchedHooksForComponent.add(componentName); + + if (hookTypesDev !== null) { + var table = ''; + var secondColumnStart = 30; + + 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 (typeof newChild === "symbol") { - warnOnSymbolType(returnFiber, newChild); + while (row.length < secondColumnStart) { + row += ' '; } + + row += newHookName + '\n'; + table += row; } - return null; + 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://react.dev/link/rules-of-hooks\n\n' + ' Previous render Next render\n' + ' ------------------------------------------------------\n' + '%s' + ' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n', componentName, table); } + } + } +} - function updateFromMap( - existingChildren, - returnFiber, - newIdx, - newChild, - lanes, - debugInfo - ) { - if ( - (typeof newChild === "string" && newChild !== "") || - typeof newChild === "number" || - typeof newChild === "bigint" - ) { - // 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, // $FlowFixMe[unsafe-addition] Flow doesn't want us to use `+` operator with string and bigint - "" + newChild, - lanes, - debugInfo - ); - } - - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: { - var _matchedFiber = - existingChildren.get( - newChild.key === null ? newIdx : newChild.key - ) || null; - - return updateElement( - returnFiber, - _matchedFiber, - newChild, - lanes, - mergeDebugInfo(debugInfo, newChild._debugInfo) - ); - } +function warnOnUseFormStateInDev() { + { + var componentName = getComponentNameFromFiber(currentlyRenderingFiber$1); - case REACT_PORTAL_TYPE: { - var _matchedFiber2 = - existingChildren.get( - newChild.key === null ? newIdx : newChild.key - ) || null; - - return updatePortal( - returnFiber, - _matchedFiber2, - newChild, - lanes, - debugInfo - ); - } + if (!didWarnAboutUseFormState.has(componentName)) { + didWarnAboutUseFormState.add(componentName); - case REACT_LAZY_TYPE: - var payload = newChild._payload; - var init = newChild._init; - return updateFromMap( - existingChildren, - returnFiber, - newIdx, - init(payload), - lanes, - mergeDebugInfo(debugInfo, newChild._debugInfo) - ); - } + error('ReactDOM.useFormState has been renamed to React.useActionState. ' + 'Please update %s to use React.useActionState.', componentName); + } + } +} - if (isArray(newChild) || getIteratorFn(newChild)) { - var _matchedFiber3 = existingChildren.get(newIdx) || null; +function warnIfAsyncClientComponent(Component) { + { + // This dev-only check only works for detecting native async functions, + // not transpiled ones. There's also a prod check that we use to prevent + // async client components from crashing the app; the prod one works even + // for transpiled async functions. Neither mechanism is completely + // bulletproof but together they cover the most common cases. + var isAsyncFunction = // $FlowIgnore[method-unbinding] + Object.prototype.toString.call(Component) === '[object AsyncFunction]'; - return updateFragment( - returnFiber, - _matchedFiber3, - newChild, - lanes, - null, - mergeDebugInfo(debugInfo, newChild._debugInfo) - ); - } // Usable node types - // - // Unwrap the inner value and recursively call this function again. - - if (typeof newChild.then === "function") { - var thenable = newChild; - return updateFromMap( - existingChildren, - returnFiber, - newIdx, - unwrapThenable(thenable), - lanes, - debugInfo - ); - } + if (isAsyncFunction) { + // Encountered an async Client Component. This is not yet supported. + var componentName = getComponentNameFromFiber(currentlyRenderingFiber$1); - if (newChild.$$typeof === REACT_CONTEXT_TYPE) { - var context = newChild; - return updateFromMap( - existingChildren, - returnFiber, - newIdx, - readContextDuringReconciliation(returnFiber, context, lanes), - lanes, - debugInfo - ); - } + if (!didWarnAboutAsyncClientComponent.has(componentName)) { + didWarnAboutAsyncClientComponent.add(componentName); - throwOnInvalidObjectType(returnFiber, newChild); - } + error('async/await is not yet supported in Client Components, only ' + 'Server Components. This error is often caused by accidentally ' + "adding `'use client'` to a module that was originally written " + 'for the server.'); + } + } + } +} - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber, newChild); - } +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://react.dev/link/invalid-hook-call for tips about how to debug and fix this problem.'); +} - if (typeof newChild === "symbol") { - warnOnSymbolType(returnFiber, newChild); - } - } +function areHookInputsEqual(nextDeps, prevDeps) { + { + if (ignorePreviousDependencies) { + // Only true when this component is being hot reloaded. + return false; + } + } - return null; - } - /** - * Warns if there is a duplicate or missing key - */ + if (prevDeps === null) { + { + 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); + } - function warnOnInvalidKey(child, knownKeys, returnFiber) { - { - if (typeof child !== "object" || child === null) { - return knownKeys; - } + return false; + } - switch (child.$$typeof) { - case REACT_ELEMENT_TYPE: - case REACT_PORTAL_TYPE: - warnForMissingKey(child, returnFiber); - var key = child.key; + { + // 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 - if (typeof key !== "string") { - break; - } - if (knownKeys === null) { - knownKeys = new Set(); - knownKeys.add(key); - break; - } + 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; + } - if (!knownKeys.has(key)) { - knownKeys.add(key); - break; - } + return false; + } - 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 - ); + return true; +} - break; +function renderWithHooks(current, workInProgress, Component, props, secondArg, nextRenderLanes) { + renderLanes = nextRenderLanes; + currentlyRenderingFiber$1 = workInProgress; + + { + hookTypesDev = current !== null ? current._debugHookTypes : null; + hookTypesUpdateIndexDev = -1; // Used for hot reloading: + + ignorePreviousDependencies = current !== null && current.type !== workInProgress.type; + warnIfAsyncClientComponent(Component); + } + + 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 (current !== null && current.memoizedState !== null) { + ReactSharedInternals.H = 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. + ReactSharedInternals.H = HooksDispatcherOnMountWithHookTypesInDEV; + } else { + ReactSharedInternals.H = 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. + + + var shouldDoubleRenderDEV = (workInProgress.mode & StrictLegacyMode) !== NoMode; + shouldDoubleInvokeUserFnsInHooksDEV = shouldDoubleRenderDEV; + var children = Component(props, secondArg); + shouldDoubleInvokeUserFnsInHooksDEV = false; // Check if there was a render phase update + + if (didScheduleRenderPhaseUpdateDuringThisPass) { + // Keep rendering until the component stabilizes (there are no more render + // phase updates). + children = renderWithHooksAgain(workInProgress, Component, props, secondArg); + } + + if (shouldDoubleRenderDEV) { + // In development, components are invoked twice to help detect side effects. + setIsStrictModeForDevtools(true); + + try { + children = renderWithHooksAgain(workInProgress, Component, props, secondArg); + } finally { + setIsStrictModeForDevtools(false); + } + } + + finishRenderingHooks(current, workInProgress); + return children; +} - case REACT_LAZY_TYPE: - var payload = child._payload; - var init = child._init; - warnOnInvalidKey(init(payload), knownKeys, returnFiber); - break; - } - } +function finishRenderingHooks(current, workInProgress, Component) { + { + workInProgress._debugHookTypes = hookTypesDev; + } // 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. - return knownKeys; - } - function reconcileChildrenArray( - returnFiber, - currentFirstChild, - newChildren, - lanes, - debugInfo - ) { - // 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; + ReactSharedInternals.H = ContextOnlyDispatcher; // 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. - for (var i = 0; i < newChildren.length; i++) { - var child = newChildren[i]; - knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber); - } - } + var didRenderTooFewHooks = currentHook !== null && currentHook.next !== null; + renderLanes = NoLanes; + currentlyRenderingFiber$1 = null; + currentHook = null; + workInProgressHook = null; - var resultingFirstChild = null; - var previousNewFiber = null; - var oldFiber = currentFirstChild; - var lastPlacedIndex = 0; - var newIdx = 0; - var nextOldFiber = null; + { + 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. - for (; oldFiber !== null && newIdx < newChildren.length; newIdx++) { - if (oldFiber.index > newIdx) { - nextOldFiber = oldFiber; - oldFiber = null; - } else { - nextOldFiber = oldFiber.sibling; - } + 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.'); + } + } - var newFiber = updateSlot( - returnFiber, - oldFiber, - newChildren[newIdx], - lanes, - debugInfo - ); - - 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; - } + didScheduleRenderPhaseUpdate = false; // This is reset by checkDidRenderIdHook + // localIdCounter = 0; - break; - } + thenableIndexCounter = 0; + thenableState = null; - 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); - } - } + if (didRenderTooFewHooks) { + throw new Error('Rendered fewer hooks than expected. This may be caused by an accidental ' + 'early return statement.'); + } - lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); + { + if (checkIfUseWrappedInTryCatch()) { + var componentName = getComponentNameFromFiber(workInProgress) || 'Unknown'; - 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 (!didWarnAboutUseWrappedInTryCatch.has(componentName) && // This warning also fires if you suspend with `use` inside an + // async component. Since we warn for that above, we'll silence this + // second warning by checking here. + !didWarnAboutAsyncClientComponent.has(componentName)) { + didWarnAboutUseWrappedInTryCatch.add(componentName); - previousNewFiber = newFiber; - oldFiber = nextOldFiber; - } + 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.'); + } + } + } +} - if (newIdx === newChildren.length) { - // We've reached the end of the new children. We can delete the rest. - deleteRemainingChildren(returnFiber, oldFiber); +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: + + ignorePreviousDependencies = current !== null && current.type !== workInProgress.type; + } + + var children = renderWithHooksAgain(workInProgress, Component, props, secondArg); + finishRenderingHooks(current, workInProgress); + return children; +} - return resultingFirstChild; - } +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. + currentlyRenderingFiber$1 = workInProgress; + 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; + } - 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, - debugInfo - ); + thenableIndexCounter = 0; + didScheduleRenderPhaseUpdateDuringThisPass = false; - if (_newFiber === null) { - continue; - } + if (numberOfReRenders >= RE_RENDER_LIMIT) { + throw new Error('Too many re-renders. React limits the number of renders to prevent ' + 'an infinite loop.'); + } - lastPlacedIndex = placeChild(_newFiber, lastPlacedIndex, newIdx); + numberOfReRenders += 1; - if (previousNewFiber === null) { - // TODO: Move out of the loop. This only happens for the first run. - resultingFirstChild = _newFiber; - } else { - previousNewFiber.sibling = _newFiber; - } + { + // 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 - previousNewFiber = _newFiber; - } - return resultingFirstChild; - } // Add all children to a key map for quick lookups. - - var existingChildren = mapRemainingChildren(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, - debugInfo - ); - - 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 - ); - } - } + currentHook = null; + workInProgressHook = null; + workInProgress.updateQueue = null; - lastPlacedIndex = placeChild(_newFiber2, lastPlacedIndex, newIdx); + { + // Also validate hook order for cascading updates. + hookTypesUpdateIndexDev = -1; + } - if (previousNewFiber === null) { - resultingFirstChild = _newFiber2; - } else { - previousNewFiber.sibling = _newFiber2; - } + ReactSharedInternals.H = HooksDispatcherOnRerenderInDEV ; + children = Component(props, secondArg); + } while (didScheduleRenderPhaseUpdateDuringThisPass); - previousNewFiber = _newFiber2; - } - } + return children; +} - 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 renderTransitionAwareHostComponentWithHooks(current, workInProgress, lanes) { + if (!enableAsyncActions) { + throw new Error('Not implemented.'); + } - return resultingFirstChild; - } + return renderWithHooks(current, workInProgress, TransitionAwareHostComponent, null, null, lanes); +} +function TransitionAwareHostComponent() { + if (!enableAsyncActions) { + throw new Error('Not implemented.'); + } - function reconcileChildrenIterator( - returnFiber, - currentFirstChild, - newChildrenIterable, - lanes, - debugInfo - ) { - // This is the same implementation as reconcileChildrenArray(), - // but using the iterator instead. - var iteratorFn = getIteratorFn(newChildrenIterable); + var dispatcher = ReactSharedInternals.H; - 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." - ); - } + var _dispatcher$useState = dispatcher.useState(), + maybeThenable = _dispatcher$useState[0]; - { - // We don't support rendering Generators because it's a mutation. - // See https://github.com/facebook/react/issues/12995 - if ( - typeof Symbol === "function" && // $FlowFixMe[prop-missing] 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." - ); - } + var nextState; - didWarnAboutGenerators = true; - } // Warn about using Maps as children + if (typeof maybeThenable.then === 'function') { + var thenable = maybeThenable; + nextState = useThenable(thenable); + } else { + var status = maybeThenable; + nextState = status; + } // The "reset state" is an object. If it changes, that means something + // requested that we reset the form. - if (newChildrenIterable.entries === iteratorFn) { - if (!didWarnAboutMaps) { - error( - "Using Maps as children is not supported. " + - "Use an array of keyed ReactElements instead." - ); - } - didWarnAboutMaps = true; - } // First, validate keys. - // We'll get a different iterator later for the main pass. + var _dispatcher$useState2 = dispatcher.useState(), + nextResetState = _dispatcher$useState2[0]; - var _newChildren = iteratorFn.call(newChildrenIterable); + var prevResetState = currentHook !== null ? currentHook.memoizedState : null; - if (_newChildren) { - var knownKeys = null; + if (prevResetState !== nextResetState) { + // Schedule a form reset + currentlyRenderingFiber$1.flags |= FormReset; + } - var _step = _newChildren.next(); + return nextState; +} +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). - for (; !_step.done; _step = _newChildren.next()) { - var child = _step.value; - knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber); - } - } - } + 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. + currentlyRenderingFiber$1 = null; // 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. + + ReactSharedInternals.H = ContextOnlyDispatcher; +} +function resetHooksOnUnwind(workInProgress) { + 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 = workInProgress.memoizedState; - if (newChildren == null) { - throw new Error("An iterable object provided no iterator."); - } + while (hook !== null) { + var queue = hook.queue; - var resultingFirstChild = null; - var previousNewFiber = null; - var oldFiber = currentFirstChild; - var lastPlacedIndex = 0; - var newIdx = 0; - var nextOldFiber = null; - var step = newChildren.next(); + if (queue !== null) { + queue.pending = null; + } - for ( - ; - oldFiber !== null && !step.done; - newIdx++, step = newChildren.next() - ) { - if (oldFiber.index > newIdx) { - nextOldFiber = oldFiber; - oldFiber = null; - } else { - nextOldFiber = oldFiber.sibling; - } + hook = hook.next; + } - var newFiber = updateSlot( - returnFiber, - oldFiber, - step.value, - lanes, - debugInfo - ); - - 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; - } + didScheduleRenderPhaseUpdate = false; + } - break; - } + renderLanes = NoLanes; + currentlyRenderingFiber$1 = null; + currentHook = null; + workInProgressHook = null; - 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); - } - } + { + hookTypesDev = null; + hookTypesUpdateIndexDev = -1; + currentHookNameInDev = null; + } - lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); + didScheduleRenderPhaseUpdateDuringThisPass = false; + thenableIndexCounter = 0; + thenableState = null; +} - 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; - } +function mountWorkInProgressHook() { + var hook = { + memoizedState: null, + baseState: null, + baseQueue: null, + queue: null, + next: null + }; + + 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; +} - previousNewFiber = newFiber; - oldFiber = nextOldFiber; - } +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; + + if (currentHook === null) { + var current = currentlyRenderingFiber$1.alternate; + + if (current !== null) { + nextCurrentHook = current.memoizedState; + } else { + nextCurrentHook = null; + } + } 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 (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.'); + } + } - if (step.done) { - // We've reached the end of the new children. We can delete the rest. - deleteRemainingChildren(returnFiber, oldFiber); + currentHook = nextCurrentHook; + var newHook = { + memoizedState: currentHook.memoizedState, + baseState: currentHook.baseState, + baseQueue: currentHook.baseQueue, + queue: currentHook.queue, + next: null + }; - return resultingFirstChild; - } + 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 (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, - debugInfo - ); + 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 (_newFiber3 === null) { - continue; - } - 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 useThenable(thenable) { + // Track the position of the thenable within this fiber. + var index = thenableIndexCounter; + thenableIndexCounter += 1; - return resultingFirstChild; - } // Add all children to a key map for quick lookups. - - var existingChildren = mapRemainingChildren(oldFiber); // Keep scanning and use the map to restore deleted items as moves. - - for (; !step.done; newIdx++, step = newChildren.next()) { - var _newFiber4 = updateFromMap( - existingChildren, - returnFiber, - newIdx, - step.value, - lanes, - debugInfo - ); - - 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 (thenableState === null) { + thenableState = createThenableState(); + } - lastPlacedIndex = placeChild(_newFiber4, lastPlacedIndex, newIdx); + var result = trackUsedThenable(thenableState, thenable, index); - if (previousNewFiber === null) { - resultingFirstChild = _newFiber4; - } else { - previousNewFiber.sibling = _newFiber4; - } + 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. + { + ReactSharedInternals.H = HooksDispatcherOnMountInDEV; + } + } - previousNewFiber = _newFiber4; - } - } + return result; +} - 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 use(usable) { + if (usable !== null && typeof usable === 'object') { + // $FlowFixMe[method-unbinding] + if (typeof usable.then === 'function') { + // This is a thenable. + var thenable = usable; + return useThenable(thenable); + } else if (usable.$$typeof === REACT_CONTEXT_TYPE) { + var context = usable; + return readContext(context); + } + } // eslint-disable-next-line react-internal/safe-string-coercion - return resultingFirstChild; - } - 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; - } - - function reconcileSingleElement( - returnFiber, - currentFirstChild, - element, - lanes, - debugInfo - ) { - var key = element.key; - var child = currentFirstChild; - - 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 (elementType === REACT_FRAGMENT_TYPE) { - if (child.tag === Fragment) { - deleteRemainingChildren(returnFiber, child.sibling); - var existing = useFiber(child, element.props.children); - existing.return = returnFiber; + throw new Error('An unsupported type was passed to use(): ' + String(usable)); +} - { - existing._debugOwner = element._owner; - existing._debugInfo = debugInfo; - } +function useMemoCache(size) { + var memoCache = null; // Fast-path, load memo cache from wip fiber if already prepared - 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); + var updateQueue = currentlyRenderingFiber$1.updateQueue; - var _existing = useFiber(child, element.props); + if (updateQueue !== null) { + memoCache = updateQueue.memoCache; + } // Otherwise clone from the current fiber - coerceRef(returnFiber, child, _existing, element); - _existing.return = returnFiber; - { - _existing._debugOwner = element._owner; - _existing._debugInfo = debugInfo; - } + if (memoCache == null) { + var current = currentlyRenderingFiber$1.alternate; - return _existing; - } - } // Didn't match. + if (current !== null) { + var currentUpdateQueue = current.updateQueue; - deleteRemainingChildren(returnFiber, child); - break; - } else { - deleteChild(returnFiber, child); - } + if (currentUpdateQueue !== null) { + var currentMemoCache = currentUpdateQueue.memoCache; - child = child.sibling; + 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 - if (element.type === REACT_FRAGMENT_TYPE) { - var created = createFiberFromFragment( - element.props.children, - returnFiber.mode, - lanes, - element.key - ); - created.return = returnFiber; - { - created._debugInfo = debugInfo; - } + if (memoCache == null) { + memoCache = { + data: [], + index: 0 + }; + } - return created; - } else { - var _created4 = createFiberFromElement( - element, - returnFiber.mode, - lanes - ); + if (updateQueue === null) { + updateQueue = createFunctionComponentUpdateQueue(); + currentlyRenderingFiber$1.updateQueue = updateQueue; + } - coerceRef(returnFiber, currentFirstChild, _created4, element); - _created4.return = returnFiber; + updateQueue.memoCache = memoCache; + var data = memoCache.data[memoCache.index]; - { - _created4._debugInfo = debugInfo; - } + if (data === undefined) { + data = memoCache.data[memoCache.index] = new Array(size); - return _created4; - } - } - - function reconcileSinglePortal( - returnFiber, - currentFirstChild, - portal, - lanes, - debugInfo - ) { - var key = portal.key; - var child = currentFirstChild; - - 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); - } + 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); + } + } - child = child.sibling; - } - - 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 reconcileChildFibersImpl( - returnFiber, - currentFirstChild, - newChild, - lanes, - debugInfo - ) { - // This function is only recursive for Usables/Lazy and not nested arrays. - // That's so that using a Lazy wrapper is unobservable to the Fragment - // convention. - // 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. - // We don't use recursion here because a fragment inside a fragment - // is no longer considered "top level" for these purposes. - var isUnkeyedTopLevelFragment = - typeof newChild === "object" && - newChild !== null && - newChild.type === REACT_FRAGMENT_TYPE && - newChild.key === null; - - if (isUnkeyedTopLevelFragment) { - newChild = newChild.props.children; - } // Handle object types - - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: - return placeSingleChild( - reconcileSingleElement( - returnFiber, - currentFirstChild, - newChild, - lanes, - mergeDebugInfo(debugInfo, newChild._debugInfo) - ) - ); - - case REACT_PORTAL_TYPE: - return placeSingleChild( - reconcileSinglePortal( - returnFiber, - currentFirstChild, - newChild, - lanes - ) - ); - - case REACT_LAZY_TYPE: - var payload = newChild._payload; - var init = newChild._init; - return reconcileChildFibersImpl( - returnFiber, - currentFirstChild, - init(payload), - lanes, - mergeDebugInfo(debugInfo, newChild._debugInfo) - ); - } + memoCache.index++; + return data; +} - if (isArray(newChild)) { - return reconcileChildrenArray( - returnFiber, - currentFirstChild, - newChild, - lanes, - mergeDebugInfo(debugInfo, newChild._debugInfo) - ); - } +function basicStateReducer(state, action) { + // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types + return typeof action === 'function' ? action(state) : action; +} - if (getIteratorFn(newChild)) { - return reconcileChildrenIterator( - returnFiber, - currentFirstChild, - newChild, - lanes, - mergeDebugInfo(debugInfo, newChild._debugInfo) - ); - } // 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 (typeof newChild.then === "function") { - var thenable = newChild; - return reconcileChildFibersImpl( - returnFiber, - currentFirstChild, - unwrapThenable(thenable), - lanes, - mergeDebugInfo(debugInfo, thenable._debugInfo) - ); - } +function mountReducer(reducer, initialArg, init) { + var hook = mountWorkInProgressHook(); + var initialState; + + if (init !== undefined) { + initialState = init(initialArg); + + if (shouldDoubleInvokeUserFnsInHooksDEV) { + setIsStrictModeForDevtools(true); + init(initialArg); + setIsStrictModeForDevtools(false); + } + } 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]; +} - if (newChild.$$typeof === REACT_CONTEXT_TYPE) { - var context = newChild; - return reconcileChildFibersImpl( - returnFiber, - currentFirstChild, - readContextDuringReconciliation(returnFiber, context, lanes), - lanes, - debugInfo - ); - } +function updateReducer(reducer, initialArg, init) { + var hook = updateWorkInProgressHook(); + return updateReducerImpl(hook, currentHook, reducer); +} - throwOnInvalidObjectType(returnFiber, newChild); - } +function updateReducerImpl(hook, current, reducer) { + var queue = hook.queue; - if ( - (typeof newChild === "string" && newChild !== "") || - typeof newChild === "number" || - typeof newChild === "bigint" - ) { - return placeSingleChild( - reconcileSingleTextNode( - returnFiber, - currentFirstChild, // $FlowFixMe[unsafe-addition] Flow doesn't want us to use `+` operator with string and bigint - "" + newChild, - lanes - ) - ); - } + if (queue === null) { + throw new Error('Should have a queue. This is likely a bug in React. Please file an issue.'); + } - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber, newChild); - } + queue.lastRenderedReducer = reducer; // The last rebase update that is NOT part of the base state. - if (typeof newChild === "symbol") { - warnOnSymbolType(returnFiber, newChild); - } - } // Remaining cases are all treated as empty. + var baseQueue = hook.baseQueue; // The last pending update that hasn't been processed yet. - return deleteRemainingChildren(returnFiber, currentFirstChild); - } + var pendingQueue = queue.pending; - 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, - null // debugInfo - ); - thenableState$1 = null; // Don't bother to reset `thenableIndexCounter` to 0 because it always gets - // set at the beginning. + 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 firstChildFiber; - } + { + 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.'); + } + } + + current.baseQueue = baseQueue = pendingQueue; + queue.pending = null; + } + + var baseState = hook.baseState; + + if (baseQueue === null) { + // If there are no pending updates, then the memoized state should be the + // same as the base state. Currently these only diverge in the case of + // useOptimistic, because useOptimistic accepts a new baseState on + // every render. + hook.memoizedState = baseState; // We don't need to call markWorkInProgressReceivedUpdate because + // baseState is derived from other reactive values. + } else { + // We have a queue to process. + var first = baseQueue.next; + var newState = baseState; + var newBaseState = null; + var newBaseQueueFirst = null; + var newBaseQueueLast = null; + var update = first; + var didReadFromEntangledAsyncAction = false; + + 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); + + 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, + revertLane: update.revertLane, + action: update.action, + hasEagerState: update.hasEagerState, + eagerState: update.eagerState, + next: null + }; - return reconcileChildFibers; - } + 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. - 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 (workInProgress.child === null) { - return; - } + currentlyRenderingFiber$1.lanes = mergeLanes(currentlyRenderingFiber$1.lanes, updateLane); + markSkippedUpdateLanes(updateLane); + } else { + // This update does have sufficient priority. + // Check if this is an optimistic update. + var revertLane = update.revertLane; + + if (!enableAsyncActions || revertLane === NoLane) { + // This is not an optimistic update, and we're going to apply it now. + // But, if there were earlier updates that were skipped, we need to + // leave this update in the queue so it can be rebased later. + 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, + revertLane: NoLane, + action: update.action, + hasEagerState: update.hasEagerState, + eagerState: update.eagerState, + next: null + }; + newBaseQueueLast = newBaseQueueLast.next = _clone; + } // Check if this update is part of a pending async action. If so, + // we'll need to suspend until the action has finished, so that it's + // batched together with future updates in the same action. - var currentChild = workInProgress.child; - var newChild = createWorkInProgress( - currentChild, - currentChild.pendingProps - ); - workInProgress.child = newChild; - newChild.return = workInProgress; - while (currentChild.sibling !== null) { - currentChild = currentChild.sibling; - newChild = newChild.sibling = createWorkInProgress( - currentChild, - currentChild.pendingProps - ); - newChild.return = workInProgress; - } + if (updateLane === peekEntangledActionLane()) { + didReadFromEntangledAsyncAction = true; + } + } else { + // This is an optimistic update. If the "revert" priority is + // sufficient, don't apply the update. Otherwise, apply the update, + // but leave it in the queue so it can be either reverted or + // rebased in a subsequent render. + if (isSubsetOfLanes(renderLanes, revertLane)) { + // The transition that this optimistic update is associated with + // has finished. Pretend the update doesn't exist by skipping + // over it. + update = update.next; // Check if this update is part of a pending async action. If so, + // we'll need to suspend until the action has finished, so that it's + // batched together with future updates in the same action. - newChild.sibling = null; - } // Reset a workInProgress child set to prepare it for a second pass. + if (revertLane === peekEntangledActionLane()) { + didReadFromEntangledAsyncAction = true; + } - function resetChildFibers(workInProgress, lanes) { - var child = workInProgress.child; + continue; + } else { + var _clone2 = { + // Once we commit an optimistic update, we shouldn't uncommit it + // until the transition it is associated with has finished + // (represented by revertLane). Using NoLane here works because 0 + // is a subset of all bitmasks, so this will never be skipped by + // the check above. + lane: NoLane, + // Reuse the same revertLane so we know when the transition + // has finished. + revertLane: update.revertLane, + action: update.action, + hasEagerState: update.hasEagerState, + eagerState: update.eagerState, + next: null + }; - while (child !== null) { - resetWorkInProgress(child, lanes); - child = child.sibling; - } - } + if (newBaseQueueLast === null) { + newBaseQueueFirst = newBaseQueueLast = _clone2; + newBaseState = newState; + } else { + newBaseQueueLast = newBaseQueueLast.next = _clone2; + } // Update the remaining priority in the queue. + // TODO: Don't need to accumulate this. Instead, we can remove + // renderLanes from the original lanes. - // 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 prevEntangledRenderLanesCursor = createCursor(NoLanes); - function pushHiddenContext(fiber, context) { - var prevEntangledRenderLanes = getEntangledRenderLanes(); - push(prevEntangledRenderLanesCursor, prevEntangledRenderLanes, 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. + currentlyRenderingFiber$1.lanes = mergeLanes(currentlyRenderingFiber$1.lanes, revertLane); + markSkippedUpdateLanes(revertLane); + } + } // Process this update. - setEntangledRenderLanes( - mergeLanes(prevEntangledRenderLanes, 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(prevEntangledRenderLanesCursor, getEntangledRenderLanes(), fiber); - push( - currentTreeHiddenStackCursor, - currentTreeHiddenStackCursor.current, - fiber - ); - } - function popHiddenContext(fiber) { - // Restore the previous render lanes from the stack - setEntangledRenderLanes(prevEntangledRenderLanesCursor.current); - pop(currentTreeHiddenStackCursor, fiber); - pop(prevEntangledRenderLanesCursor, fiber); - } - function isCurrentTreeHidden() { - return currentTreeHiddenStackCursor.current !== null; - } - // suspends, i.e. it's the nearest `catch` block on the stack. + var action = update.action; - 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 (shouldDoubleInvokeUserFnsInHooksDEV) { + reducer(newState, action); + } - if (prevState !== null) { - // This boundary is showing a fallback in the current UI. - shellBoundary = handler; - } + 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); } } - } - 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; + update = update.next; + } while (update !== null && update !== first); - if (current !== null) { - var prevState = current.memoizedState; + 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 (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; - } - } + + if (!objectIs(newState, hook.memoizedState)) { + markWorkInProgressReceivedUpdate(); // Check if this update is part of a pending async action. If so, we'll + // need to suspend until the action has finished, so that it's batched + // together with future updates in the same action. + // TODO: Once we support hooks inside useMemo (or an equivalent + // memoization boundary like Forget), hoist this logic so that it only + // suspends if the memo boundary produces a new value. + + if (didReadFromEntangledAsyncAction) { + var entangledActionThenable = peekEntangledActionThenable(); + + if (entangledActionThenable !== null) { + // TODO: Instead of the throwing the thenable directly, throw a + // special object like `use` does so we can detect if it's captured + // by userspace. + throw entangledActionThenable; } - } 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. + hook.memoizedState = newState; + hook.baseState = newBaseState; + hook.baseQueue = newBaseQueueLast; + queue.lastRenderedState = newState; + } - 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. + 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; + } - 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); - } + var dispatch = queue.dispatch; + return [hook.memoizedState, dispatch]; +} - // 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 rerenderReducer(reducer, initialArg, init) { + var hook = updateWorkInProgressHook(); + var queue = hook.queue; - function findFirstSuspended(row) { - var node = row; + if (queue === null) { + throw new Error('Should have a queue. This is likely a bug in React. Please file an issue.'); + } - while (node !== null) { - if (node.tag === SuspenseComponent) { - var state = node.memoizedState; + queue.lastRenderedReducer = reducer; // This is a re-render. Apply the new render phase updates to the previous + // work-in-progress hook. - if (state !== null) { - var dehydrated = state.dehydrated; + var dispatch = queue.dispatch; + var lastRenderPhaseUpdate = queue.pending; + var newState = hook.memoizedState; - if ( - dehydrated === null || - isSuspenseInstancePending() || - isSuspenseInstanceFallback() - ) { - return node; - } - } - } 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; - } - } else if (node.child !== null) { - node.child.return = node; - node = node.child; - continue; - } + if (lastRenderPhaseUpdate !== null) { + // The queue doesn't persist past this render pass. + queue.pending = null; + var firstRenderPhaseUpdate = lastRenderPhaseUpdate.next; + var update = firstRenderPhaseUpdate; - if (node === row) { - return null; - } + 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. - while (node.sibling === null) { - if (node.return === null || node.return === row) { - return null; - } - node = node.return; - } + if (!objectIs(newState, hook.memoizedState)) { + markWorkInProgressReceivedUpdate(); + } - node.sibling.return = node.return; - node = node.sibling; - } + 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. - return null; + if (hook.baseQueue === null) { + hook.baseState = newState; } - var NoFlags = - /* */ - 0; // Represents whether effect should fire. + queue.lastRenderedState = newState; + } - var HasEffect = - /* */ - 1; // Represents the phase in which the effect (not the clean-up) fires. + return [newState, dispatch]; +} - var Insertion = - /* */ - 2; - var Layout = - /* */ - 4; - var Passive = - /* */ - 8; +function mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) { + var fiber = currentlyRenderingFiber$1; + var hook = mountWorkInProgressHook(); + var nextSnapshot; - var didWarnAboutMismatchedHooksForComponent; - var didWarnUncachedGetSnapshot; - var didWarnAboutUseWrappedInTryCatch; - var didWarnAboutAsyncClientComponent; - var didWarnAboutUseFormState; + { + nextSnapshot = getSnapshot(); { - didWarnAboutMismatchedHooksForComponent = new Set(); - didWarnAboutUseWrappedInTryCatch = new Set(); - didWarnAboutAsyncClientComponent = new Set(); - didWarnAboutUseFormState = new Set(); - } // The effect "instance" is a shared object that remains the same for the entire - // lifetime of an effect. In Rust terms, a RefCell. We use it to store the - // "destroy" function that is returned from an effect, because that is stateful. - // The field is `undefined` if the effect is unmounted, or if the effect ran - // but is not stateful. We don't explicitly track whether the effect is mounted - // or unmounted because that can be inferred by the hiddenness of the fiber in - // the tree, i.e. whether there is a hidden Offscreen fiber above it. - // - // It's unfortunate that this is stored on a separate object, because it adds - // more memory per effect instance, but it's conceptually sound. I think there's - // likely a better data structure we could use for effects; perhaps just one - // array of effect instances per fiber. But I think this is OK for now despite - // the additional memory and we can follow up with performance - // optimizations later. - // These are set right before calling the component. - - var renderLanes = 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`. - - var didScheduleRenderPhaseUpdateDuringThisPass = false; - var shouldDoubleInvokeUserFnsInHooksDEV = false; // Counts the number of useId hooks in this component. - - 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. - - var globalClientIdCounter = 0; - var RE_RENDER_LIMIT = 25; // In DEV, this is the name of the currently executing primitive hook - - 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. - - 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 (!didWarnUncachedGetSnapshot) { + var cachedSnapshot = getSnapshot(); - if (hookTypesDev === null) { - hookTypesDev = [hookName]; - } else { - hookTypesDev.push(hookName); + if (!objectIs(nextSnapshot, cachedSnapshot)) { + error('The result of getSnapshot should be cached to avoid an infinite loop'); + + 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. - function updateHookTypesDev() { - { - var hookName = currentHookNameInDev; - if (hookTypesDev !== null) { - hookTypesUpdateIndexDev++; + var root = getWorkInProgressRoot(); - if (hookTypesDev[hookTypesUpdateIndexDev] !== hookName) { - warnOnHookMismatchInDev(hookName); - } - } - } + if (root === null) { + throw new Error('Expected a work-in-progress root. This is a bug in React. Please file an issue.'); } - 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 - ); - } - } + var rootRenderLanes = getWorkInProgressRootRenderLanes(); + + if (!includesBlockingLane(root, rootRenderLanes)) { + 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. - function warnOnHookMismatchInDev(currentHookName) { - { - var componentName = getComponentNameFromFiber( - currentlyRenderingFiber$1 - ); - - if (!didWarnAboutMismatchedHooksForComponent.has(componentName)) { - didWarnAboutMismatchedHooksForComponent.add(componentName); - - if (hookTypesDev !== null) { - var table = ""; - var secondColumnStart = 30; - - 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 - - while (row.length < secondColumnStart) { - row += " "; - } - row += newHookName + "\n"; - table += row; - } + hook.memoizedState = nextSnapshot; + var inst = { + value: nextSnapshot, + getSnapshot: getSnapshot + }; + hook.queue = inst; // Schedule an effect to subscribe to the store. - 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://react.dev/link/rules-of-hooks\n\n" + - " Previous render Next render\n" + - " ------------------------------------------------------\n" + - "%s" + - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - componentName, - table - ); - } - } - } - } + 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. - function warnOnUseFormStateInDev() { - { - var componentName = getComponentNameFromFiber( - currentlyRenderingFiber$1 - ); + fiber.flags |= Passive$1; + pushEffect(HasEffect | Passive, updateStoreInstance.bind(null, fiber, inst, nextSnapshot, getSnapshot), createEffectInstance(), null); + return nextSnapshot; +} - if (!didWarnAboutUseFormState.has(componentName)) { - didWarnAboutUseFormState.add(componentName); +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. - error( - "ReactDOM.useFormState has been renamed to React.useActionState. " + - "Please update %s to use React.useActionState.", - componentName - ); - } - } - } + var nextSnapshot; - function warnIfAsyncClientComponent(Component) { - { - // This dev-only check only works for detecting native async functions, - // not transpiled ones. There's also a prod check that we use to prevent - // async client components from crashing the app; the prod one works even - // for transpiled async functions. Neither mechanism is completely - // bulletproof but together they cover the most common cases. - var isAsyncFunction = // $FlowIgnore[method-unbinding] - Object.prototype.toString.call(Component) === - "[object AsyncFunction]"; - - if (isAsyncFunction) { - // Encountered an async Client Component. This is not yet supported. - var componentName = getComponentNameFromFiber( - currentlyRenderingFiber$1 - ); - - if (!didWarnAboutAsyncClientComponent.has(componentName)) { - didWarnAboutAsyncClientComponent.add(componentName); - - error( - "async/await is not yet supported in Client Components, only " + - "Server Components. This error is often caused by accidentally " + - "adding `'use client'` to a module that was originally written " + - "for the server." - ); - } - } - } - } + { + nextSnapshot = getSnapshot(); - 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://react.dev/link/invalid-hook-call for tips about how to debug and fix this problem." - ); - } + { + if (!didWarnUncachedGetSnapshot) { + var cachedSnapshot = getSnapshot(); - function areHookInputsEqual(nextDeps, prevDeps) { - { - if (ignorePreviousDependencies) { - // Only true when this component is being hot reloaded. - return false; - } - } + if (!objectIs(nextSnapshot, cachedSnapshot)) { + error('The result of getSnapshot should be cached to avoid an infinite loop'); - if (prevDeps === null) { - { - 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 - ); + didWarnUncachedGetSnapshot = true; } - - return false; } + } + } - { - // 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 - - 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; - } + var prevSnapshot = (currentHook || hook).memoizedState; + var snapshotChanged = !objectIs(prevSnapshot, nextSnapshot); - return false; - } + if (snapshotChanged) { + hook.memoizedState = nextSnapshot; + markWorkInProgressReceivedUpdate(); + } - return true; - } + 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. - function renderWithHooks( - current, - workInProgress, - Component, - props, - secondArg, - nextRenderLanes - ) { - renderLanes = nextRenderLanes; - currentlyRenderingFiber$1 = workInProgress; + if (inst.getSnapshot !== getSnapshot || snapshotChanged || // Check if the subscribe 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), createEffectInstance(), 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. - { - hookTypesDev = current !== null ? current._debugHookTypes : null; - hookTypesUpdateIndexDev = -1; // Used for hot reloading: + var root = getWorkInProgressRoot(); - ignorePreviousDependencies = - current !== null && current.type !== workInProgress.type; - warnIfAsyncClientComponent(Component); - } + if (root === null) { + throw new Error('Expected a work-in-progress root. This is a bug in React. Please file an issue.'); + } - 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 (!includesBlockingLane(root, renderLanes)) { + pushStoreConsistencyCheck(fiber, getSnapshot, nextSnapshot); + } + } - { - if (current !== null && current.memoizedState !== null) { - ReactSharedInternals.H = 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. - ReactSharedInternals.H = HooksDispatcherOnMountWithHookTypesInDEV; - } else { - ReactSharedInternals.H = 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. - - var shouldDoubleRenderDEV = - (workInProgress.mode & StrictLegacyMode) !== NoMode; - shouldDoubleInvokeUserFnsInHooksDEV = shouldDoubleRenderDEV; - var children = Component(props, secondArg); - shouldDoubleInvokeUserFnsInHooksDEV = false; // Check if there was a render phase update - - if (didScheduleRenderPhaseUpdateDuringThisPass) { - // Keep rendering until the component stabilizes (there are no more render - // phase updates). - children = renderWithHooksAgain( - workInProgress, - Component, - props, - secondArg - ); - } - - if (shouldDoubleRenderDEV) { - // In development, components are invoked twice to help detect side effects. - setIsStrictModeForDevtools(true); + return nextSnapshot; +} - try { - children = renderWithHooksAgain( - workInProgress, - Component, - props, - secondArg - ); - } finally { - setIsStrictModeForDevtools(false); - } - } +function pushStoreConsistencyCheck(fiber, getSnapshot, renderedSnapshot) { + fiber.flags |= StoreConsistency; + var check = { + getSnapshot: getSnapshot, + value: renderedSnapshot + }; + var componentUpdateQueue = currentlyRenderingFiber$1.updateQueue; + + if (componentUpdateQueue === null) { + componentUpdateQueue = createFunctionComponentUpdateQueue(); + currentlyRenderingFiber$1.updateQueue = componentUpdateQueue; + componentUpdateQueue.stores = [check]; + } else { + var stores = componentUpdateQueue.stores; + + if (stores === null) { + componentUpdateQueue.stores = [check]; + } else { + stores.push(check); + } + } +} - finishRenderingHooks(current, workInProgress); - return children; +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. + + if (checkIfSnapshotChanged(inst)) { + // Force a re-render. + forceStoreRerender(fiber); + } +} + +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 finishRenderingHooks(current, workInProgress, Component) { - { - workInProgress._debugHookTypes = hookTypesDev; - } // 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. - ReactSharedInternals.H = ContextOnlyDispatcher; // 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. + return subscribe(handleStoreChange); +} - var didRenderTooFewHooks = - currentHook !== null && currentHook.next !== null; - renderLanes = NoLanes; - currentlyRenderingFiber$1 = null; - currentHook = null; - workInProgressHook = null; +function checkIfSnapshotChanged(inst) { + var latestGetSnapshot = inst.getSnapshot; + var prevValue = inst.value; - { - 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( - "Internal React error: Expected static flag was missing. Please " + - "notify the React team." - ); - } - } - - didScheduleRenderPhaseUpdate = false; // This is reset by checkDidRenderIdHook - // localIdCounter = 0; - - thenableIndexCounter = 0; - thenableState = null; + try { + var nextValue = latestGetSnapshot(); + return !objectIs(prevValue, nextValue); + } catch (error) { + return true; + } +} - if (didRenderTooFewHooks) { - throw new Error( - "Rendered fewer hooks than expected. This may be caused by an accidental " + - "early return statement." - ); - } +function forceStoreRerender(fiber) { + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - { - if (checkIfUseWrappedInTryCatch()) { - var componentName = - getComponentNameFromFiber(workInProgress) || "Unknown"; - - if ( - !didWarnAboutUseWrappedInTryCatch.has(componentName) && // This warning also fires if you suspend with `use` inside an - // async component. Since we warn for that above, we'll silence this - // second warning by checking here. - !didWarnAboutAsyncClientComponent.has(componentName) - ) { - didWarnAboutUseWrappedInTryCatch.add(componentName); - - 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." - ); - } - } - } - } + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane); + } +} - 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: +function mountStateImpl(initialState) { + var hook = mountWorkInProgressHook(); - ignorePreviousDependencies = - current !== null && current.type !== workInProgress.type; - } + if (typeof initialState === 'function') { + var initialStateInitializer = initialState; // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types + + initialState = initialStateInitializer(); + + if (shouldDoubleInvokeUserFnsInHooksDEV) { + setIsStrictModeForDevtools(true); // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types - var children = renderWithHooksAgain( - workInProgress, - Component, - props, - secondArg - ); - finishRenderingHooks(current, workInProgress); - return children; + initialStateInitializer(); + setIsStrictModeForDevtools(false); } + } - 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. - currentlyRenderingFiber$1 = workInProgress; - var numberOfReRenders = 0; - var children; + hook.memoizedState = hook.baseState = initialState; + var queue = { + pending: null, + lanes: NoLanes, + dispatch: null, + lastRenderedReducer: basicStateReducer, + lastRenderedState: initialState + }; + hook.queue = queue; + return hook; +} - 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; - } +function mountState(initialState) { + var hook = mountStateImpl(initialState); + var queue = hook.queue; + var dispatch = dispatchSetState.bind(null, currentlyRenderingFiber$1, queue); + queue.dispatch = dispatch; + return [hook.memoizedState, dispatch]; +} - thenableIndexCounter = 0; - didScheduleRenderPhaseUpdateDuringThisPass = false; +function updateState(initialState) { + return updateReducer(basicStateReducer); +} - if (numberOfReRenders >= RE_RENDER_LIMIT) { - throw new Error( - "Too many re-renders. React limits the number of renders to prevent " + - "an infinite loop." - ); - } +function rerenderState(initialState) { + return rerenderReducer(basicStateReducer); +} - numberOfReRenders += 1; +function mountOptimistic(passthrough, reducer) { + var hook = mountWorkInProgressHook(); + hook.memoizedState = hook.baseState = passthrough; + var queue = { + pending: null, + lanes: NoLanes, + dispatch: null, + // Optimistic state does not use the eager update optimization. + lastRenderedReducer: null, + lastRenderedState: null + }; + hook.queue = queue; // This is different than the normal setState function. + + var dispatch = dispatchOptimisticSetState.bind(null, currentlyRenderingFiber$1, true, queue); + queue.dispatch = dispatch; + return [passthrough, dispatch]; +} - { - // 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 updateOptimistic(passthrough, reducer) { + var hook = updateWorkInProgressHook(); + return updateOptimisticImpl(hook, currentHook, passthrough, reducer); +} - currentHook = null; - workInProgressHook = null; - workInProgress.updateQueue = null; +function updateOptimisticImpl(hook, current, passthrough, reducer) { + // Optimistic updates are always rebased on top of the latest value passed in + // as an argument. It's called a passthrough because if there are no pending + // updates, it will be returned as-is. + // + // Reset the base state to the passthrough. Future updates will be applied + // on top of this. + hook.baseState = passthrough; // If a reducer is not provided, default to the same one used by useState. + + var resolvedReducer = typeof reducer === 'function' ? reducer : basicStateReducer; + return updateReducerImpl(hook, currentHook, resolvedReducer); +} - { - // Also validate hook order for cascading updates. - hookTypesUpdateIndexDev = -1; - } +function rerenderOptimistic(passthrough, reducer) { + // Unlike useState, useOptimistic doesn't support render phase updates. + // Also unlike useState, we need to replay all pending updates again in case + // the passthrough value changed. + // + // So instead of a forked re-render implementation that knows how to handle + // render phase udpates, we can use the same implementation as during a + // regular mount or update. + var hook = updateWorkInProgressHook(); + + if (currentHook !== null) { + // This is an update. Process the update queue. + return updateOptimisticImpl(hook, currentHook, passthrough, reducer); + } // This is a mount. No updates to process. + // Reset the base state to the passthrough. Future updates will be applied + // on top of this. + + + hook.baseState = passthrough; + var dispatch = hook.queue.dispatch; + return [passthrough, dispatch]; +} // useActionState actions run sequentially, because each action receives the +// previous state as an argument. We store pending actions on a queue. + + +function dispatchActionState(fiber, actionQueue, setPendingState, setState, payload) { + if (isRenderPhaseUpdate(fiber)) { + throw new Error('Cannot update form state while rendering.'); + } + + var last = actionQueue.pending; + + if (last === null) { + // There are no pending actions; this is the first one. We can run + // it immediately. + var newLast = { + payload: payload, + next: null // circular - ReactSharedInternals.H = HooksDispatcherOnRerenderInDEV; - children = Component(props, secondArg); - } while (didScheduleRenderPhaseUpdateDuringThisPass); + }; + newLast.next = actionQueue.pending = newLast; + runActionStateAction(actionQueue, setPendingState, setState, payload); + } else { + // There's already an action running. Add to the queue. + var first = last.next; + var _newLast = { + payload: payload, + next: first + }; + actionQueue.pending = last.next = _newLast; + } +} - return children; - } +function runActionStateAction(actionQueue, setPendingState, setState, payload) { + var action = actionQueue.action; + var prevState = actionQueue.state; // This is a fork of startTransition - function renderTransitionAwareHostComponentWithHooks( - current, - workInProgress, - lanes - ) { - if (!enableAsyncActions) { - throw new Error("Not implemented."); - } + var prevTransition = ReactSharedInternals.T; + var currentTransition = { + _callbacks: new Set() + }; + ReactSharedInternals.T = currentTransition; - return renderWithHooks( - current, - workInProgress, - TransitionAwareHostComponent, - null, - null, - lanes - ); - } - function TransitionAwareHostComponent() { - if (!enableAsyncActions) { - throw new Error("Not implemented."); - } + { + ReactSharedInternals.T._updatedFibers = new Set(); + } // Optimistically update the pending state, similar to useTransition. + // This will be reverted automatically when all actions are finished. - var dispatcher = ReactSharedInternals.H; - var _dispatcher$useState = dispatcher.useState(), - maybeThenable = _dispatcher$useState[0]; + setPendingState(true); - var nextState; + try { + var returnValue = action(prevState, payload); - if (typeof maybeThenable.then === "function") { - var thenable = maybeThenable; - nextState = useThenable(thenable); - } else { - var status = maybeThenable; - nextState = status; - } // The "reset state" is an object. If it changes, that means something - // requested that we reset the form. + if (returnValue !== null && typeof returnValue === 'object' && // $FlowFixMe[method-unbinding] + typeof returnValue.then === 'function') { + var thenable = returnValue; + notifyTransitionCallbacks(currentTransition, thenable); // Attach a listener to read the return state of the action. As soon as + // this resolves, we can run the next action in the sequence. - var _dispatcher$useState2 = dispatcher.useState(), - nextResetState = _dispatcher$useState2[0]; + thenable.then(function (nextState) { + actionQueue.state = nextState; + finishRunningActionStateAction(actionQueue, setPendingState, setState); + }, function () { + return finishRunningActionStateAction(actionQueue, setPendingState, setState); + }); + setState(thenable); + } else { + setState(returnValue); + var nextState = returnValue; + actionQueue.state = nextState; + finishRunningActionStateAction(actionQueue, setPendingState, setState); + } + } catch (error) { + // This is a trick to get the `useActionState` hook to rethrow the error. + // When it unwraps the thenable with the `use` algorithm, the error + // will be thrown. + var rejectedThenable = { + then: function () {}, + status: 'rejected', + reason: error // $FlowFixMe: Not sure why this doesn't work - var prevResetState = - currentHook !== null ? currentHook.memoizedState : null; + }; + setState(rejectedThenable); + finishRunningActionStateAction(actionQueue, setPendingState, setState); + } finally { + ReactSharedInternals.T = prevTransition; - if (prevResetState !== nextResetState) { - // Schedule a form reset - currentlyRenderingFiber$1.flags |= FormReset; - } + { + if (prevTransition === null && currentTransition._updatedFibers) { + var updatedFibersCount = currentTransition._updatedFibers.size; - return nextState; - } - 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). + currentTransition._updatedFibers.clear(); - if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { - workInProgress.flags &= ~( - MountPassiveDev | - MountLayoutDev | - Passive$1 | - Update - ); - } else { - workInProgress.flags &= ~(Passive$1 | Update); + 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.'); + } } + } + } +} + +function finishRunningActionStateAction(actionQueue, setPendingState, setState) { + // The action finished running. Pop it from the queue and run the next pending + // action, if there are any. + var last = actionQueue.pending; + + if (last !== null) { + var first = last.next; + + if (first === last) { + // This was the last action in the queue. + actionQueue.pending = null; + } else { + // Remove the first node from the circular queue. + var next = first.next; + last.next = next; // Run the next action. - current.lanes = removeLanes(current.lanes, lanes); + runActionStateAction(actionQueue, setPendingState, setState, next.payload); } - 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. - currentlyRenderingFiber$1 = null; // 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. - - ReactSharedInternals.H = ContextOnlyDispatcher; - } - function resetHooksOnUnwind(workInProgress) { - 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 = workInProgress.memoizedState; + } +} - while (hook !== null) { - var queue = hook.queue; +function actionStateReducer(oldState, newState) { + return newState; +} - if (queue !== null) { - queue.pending = null; - } +function mountActionState(action, initialStateProp, permalink) { + var initialState = initialStateProp; + // the `use` algorithm during render. + + + var stateHook = mountWorkInProgressHook(); + stateHook.memoizedState = stateHook.baseState = initialState; // TODO: Typing this "correctly" results in recursion limit errors + // const stateQueue: UpdateQueue, S | Awaited> = { + + var stateQueue = { + pending: null, + lanes: NoLanes, + dispatch: null, + lastRenderedReducer: actionStateReducer, + lastRenderedState: initialState + }; + stateHook.queue = stateQueue; + var setState = dispatchSetState.bind(null, currentlyRenderingFiber$1, stateQueue); + stateQueue.dispatch = setState; // Pending state. This is used to store the pending state of the action. + // Tracked optimistically, like a transition pending state. + + var pendingStateHook = mountStateImpl(false); + var setPendingState = dispatchOptimisticSetState.bind(null, currentlyRenderingFiber$1, false, pendingStateHook.queue); // Action queue hook. This is used to queue pending actions. The queue is + // shared between all instances of the hook. Similar to a regular state queue, + // but different because the actions are run sequentially, and they run in + // an event instead of during render. + + var actionQueueHook = mountWorkInProgressHook(); + var actionQueue = { + state: initialState, + dispatch: null, + // circular + action: action, + pending: null + }; + actionQueueHook.queue = actionQueue; + var dispatch = dispatchActionState.bind(null, currentlyRenderingFiber$1, actionQueue, setPendingState, setState); + actionQueue.dispatch = dispatch; // Stash the action function on the memoized state of the hook. We'll use this + // to detect when the action function changes so we can update it in + // an effect. + + actionQueueHook.memoizedState = action; + return [initialState, dispatch, false]; +} - hook = hook.next; - } +function updateActionState(action, initialState, permalink) { + var stateHook = updateWorkInProgressHook(); + var currentStateHook = currentHook; + return updateActionStateImpl(stateHook, currentStateHook, action); +} - didScheduleRenderPhaseUpdate = false; - } +function updateActionStateImpl(stateHook, currentStateHook, action, initialState, permalink) { + var _updateReducerImpl = updateReducerImpl(stateHook, currentStateHook, actionStateReducer), + actionResult = _updateReducerImpl[0]; - renderLanes = NoLanes; - currentlyRenderingFiber$1 = null; - currentHook = null; - workInProgressHook = null; + var _updateState = updateState(), + isPending = _updateState[0]; // This will suspend until the action finishes. - { - hookTypesDev = null; - hookTypesUpdateIndexDev = -1; - currentHookNameInDev = null; - } - didScheduleRenderPhaseUpdateDuringThisPass = false; - thenableIndexCounter = 0; - thenableState = null; - } + var state = typeof actionResult === 'object' && actionResult !== null && // $FlowFixMe[method-unbinding] + typeof actionResult.then === 'function' ? useThenable(actionResult) : actionResult; + var actionQueueHook = updateWorkInProgressHook(); + var actionQueue = actionQueueHook.queue; + var dispatch = actionQueue.dispatch; // Check if a new action was passed. If so, update it in an effect. - function mountWorkInProgressHook() { - var hook = { - memoizedState: null, - baseState: null, - baseQueue: null, - queue: null, - next: null - }; + var prevAction = actionQueueHook.memoizedState; - 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; - } + if (action !== prevAction) { + currentlyRenderingFiber$1.flags |= Passive$1; + pushEffect(HasEffect | Passive, actionStateActionEffect.bind(null, actionQueue, action), createEffectInstance(), null); + } - return workInProgressHook; - } + return [state, dispatch, isPending]; +} - 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 actionStateActionEffect(actionQueue, action) { + actionQueue.action = action; +} - if (currentHook === null) { - var current = currentlyRenderingFiber$1.alternate; +function rerenderActionState(action, initialState, permalink) { + // Unlike useState, useActionState doesn't support render phase updates. + // Also unlike useState, we need to replay all pending updates again in case + // the passthrough value changed. + // + // So instead of a forked re-render implementation that knows how to handle + // render phase udpates, we can use the same implementation as during a + // regular mount or update. + var stateHook = updateWorkInProgressHook(); + var currentStateHook = currentHook; + + if (currentStateHook !== null) { + // This is an update. Process the update queue. + return updateActionStateImpl(stateHook, currentStateHook, action); + } + + updateWorkInProgressHook(); // State + // This is a mount. No updates to process. + + var state = stateHook.memoizedState; + var actionQueueHook = updateWorkInProgressHook(); + var actionQueue = actionQueueHook.queue; + var dispatch = actionQueue.dispatch; // This may have changed during the rerender. + + actionQueueHook.memoizedState = action; // For mount, pending is always false. + + return [state, dispatch, false]; +} - if (current !== null) { - nextCurrentHook = current.memoizedState; - } else { - nextCurrentHook = null; - } - } else { - nextCurrentHook = currentHook.next; - } +function pushEffect(tag, create, inst, deps) { + var effect = { + tag: tag, + create: create, + inst: inst, + 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; +} - var nextWorkInProgressHook; +function createEffectInstance() { + return { + destroy: undefined + }; +} - if (workInProgressHook === null) { - nextWorkInProgressHook = currentlyRenderingFiber$1.memoizedState; - } else { - nextWorkInProgressHook = workInProgressHook.next; - } +function mountRef(initialValue) { + var hook = mountWorkInProgressHook(); + var ref = { + current: initialValue + }; + hook.memoizedState = ref; + return ref; +} - 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 (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." - ); - } - } +function updateRef(initialValue) { + var hook = updateWorkInProgressHook(); + return hook.memoizedState; +} - currentHook = nextCurrentHook; - var newHook = { - memoizedState: currentHook.memoizedState, - baseState: currentHook.baseState, - baseQueue: currentHook.baseQueue, - queue: currentHook.queue, - next: null - }; +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, createEffectInstance(), nextDeps); +} - 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; - } +function updateEffectImpl(fiberFlags, hookFlags, create, deps) { + var hook = updateWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + var effect = hook.memoizedState; + var inst = effect.inst; // currentHook is null on initial mount when rerendering after a render phase + // state update or for strict mode. + + if (currentHook !== null) { + if (nextDeps !== null) { + var prevEffect = currentHook.memoizedState; + var prevDeps = prevEffect.deps; + + if (areHookInputsEqual(nextDeps, prevDeps)) { + hook.memoizedState = pushEffect(hookFlags, create, inst, nextDeps); + return; } + } + } - 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. + currentlyRenderingFiber$1.flags |= fiberFlags; + hook.memoizedState = pushEffect(HasEffect | hookFlags, create, inst, nextDeps); +} - var createFunctionComponentUpdateQueue; +function mountEffect(create, deps) { + if ((currentlyRenderingFiber$1.mode & StrictEffectsMode) !== NoMode && (currentlyRenderingFiber$1.mode & NoStrictPassiveEffectsMode) === NoMode) { + mountEffectImpl(MountPassiveDev | Passive$1 | PassiveStatic, Passive, create, deps); + } else { + mountEffectImpl(Passive$1 | PassiveStatic, Passive, create, deps); + } +} - { - createFunctionComponentUpdateQueue = function () { - return { - lastEffect: null, - events: null, - stores: null, - memoCache: null - }; - }; - } +function updateEffect(create, deps) { + updateEffectImpl(Passive$1, Passive, create, deps); +} - function useThenable(thenable) { - // Track the position of the thenable within this fiber. - var index = thenableIndexCounter; - thenableIndexCounter += 1; +function mountInsertionEffect(create, deps) { + mountEffectImpl(Update, Insertion, create, deps); +} - if (thenableState === null) { - thenableState = createThenableState(); - } +function updateInsertionEffect(create, deps) { + return updateEffectImpl(Update, Insertion, create, deps); +} - var result = trackUsedThenable(thenableState, thenable, index); +function mountLayoutEffect(create, deps) { + var fiberFlags = Update | LayoutStatic; - 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. - { - ReactSharedInternals.H = HooksDispatcherOnMountInDEV; - } - } + if ((currentlyRenderingFiber$1.mode & StrictEffectsMode) !== NoMode) { + fiberFlags |= MountLayoutDev; + } + + return mountEffectImpl(fiberFlags, Layout, create, deps); +} + +function updateLayoutEffect(create, deps) { + return updateEffectImpl(Update, Layout, create, deps); +} - return result; +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(', ') + '}'); + } } - function use(usable) { - if (usable !== null && typeof usable === "object") { - // $FlowFixMe[method-unbinding] - if (typeof usable.then === "function") { - // This is a thenable. - var thenable = usable; - return useThenable(thenable); - } else if (usable.$$typeof === REACT_CONTEXT_TYPE) { - var context = usable; - return readContext(context); - } - } // eslint-disable-next-line react-internal/safe-string-coercion + var _inst = create(); + + refObject.current = _inst; + return function () { + refObject.current = null; + }; + } +} - throw new Error( - "An unsupported type was passed to use(): " + String(usable) - ); +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? - function useMemoCache(size) { - var memoCache = null; // Fast-path, load memo cache from wip fiber if already prepared - var updateQueue = currentlyRenderingFiber$1.updateQueue; + var effectDeps = deps !== null && deps !== undefined ? deps.concat([ref]) : null; + var fiberFlags = Update | LayoutStatic; - if (updateQueue !== null) { - memoCache = updateQueue.memoCache; - } // Otherwise clone from the current fiber + if ((currentlyRenderingFiber$1.mode & StrictEffectsMode) !== NoMode) { + fiberFlags |= MountLayoutDev; + } - if (memoCache == null) { - var current = currentlyRenderingFiber$1.alternate; + mountEffectImpl(fiberFlags, Layout, imperativeHandleEffect.bind(null, create, ref), effectDeps); +} - if (current !== null) { - var currentUpdateQueue = current.updateQueue; +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 (currentUpdateQueue !== null) { - var currentMemoCache = currentUpdateQueue.memoCache; - 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 + var effectDeps = deps !== null && deps !== undefined ? deps.concat([ref]) : null; + updateEffectImpl(Update, Layout, imperativeHandleEffect.bind(null, create, ref), effectDeps); +} - if (memoCache == null) { - memoCache = { - data: [], - index: 0 - }; - } +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. +} - if (updateQueue === null) { - updateQueue = createFunctionComponentUpdateQueue(); - currentlyRenderingFiber$1.updateQueue = updateQueue; - } +var updateDebugValue = mountDebugValue; - updateQueue.memoCache = memoCache; - var data = memoCache.data[memoCache.index]; +function mountCallback(callback, deps) { + var hook = mountWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + hook.memoizedState = [callback, nextDeps]; + return callback; +} - if (data === undefined) { - data = memoCache.data[memoCache.index] = new Array(size); +function updateCallback(callback, deps) { + var hook = updateWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + var prevState = hook.memoizedState; - 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 - ); - } - } + if (nextDeps !== null) { + var prevDeps = prevState[1]; - memoCache.index++; - return data; + if (areHookInputsEqual(nextDeps, prevDeps)) { + return prevState[0]; } + } - function basicStateReducer(state, action) { - // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types - return typeof action === "function" ? action(state) : action; - } + hook.memoizedState = [callback, nextDeps]; + return callback; +} - function mountReducer(reducer, initialArg, init) { - var hook = mountWorkInProgressHook(); - var initialState; +function mountMemo(nextCreate, deps) { + var hook = mountWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + var nextValue = nextCreate(); - if (init !== undefined) { - initialState = init(initialArg); + if (shouldDoubleInvokeUserFnsInHooksDEV) { + setIsStrictModeForDevtools(true); + nextCreate(); + setIsStrictModeForDevtools(false); + } - if (shouldDoubleInvokeUserFnsInHooksDEV) { - setIsStrictModeForDevtools(true); - init(initialArg); - setIsStrictModeForDevtools(false); - } - } else { - initialState = initialArg; - } + hook.memoizedState = [nextValue, nextDeps]; + return nextValue; +} - 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]; - } +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. + + if (nextDeps !== null) { + var prevDeps = prevState[1]; - function updateReducer(reducer, initialArg, init) { - var hook = updateWorkInProgressHook(); - return updateReducerImpl(hook, currentHook, reducer); + if (areHookInputsEqual(nextDeps, prevDeps)) { + return prevState[0]; } + } - function updateReducerImpl(hook, current, reducer) { - var queue = hook.queue; + var nextValue = nextCreate(); - if (queue === null) { - throw new Error( - "Should have a queue. This is likely a bug in React. Please file an issue." - ); - } + if (shouldDoubleInvokeUserFnsInHooksDEV) { + setIsStrictModeForDevtools(true); + nextCreate(); + setIsStrictModeForDevtools(false); + } - queue.lastRenderedReducer = reducer; // The last rebase update that is NOT part of the base state. + hook.memoizedState = [nextValue, nextDeps]; + return nextValue; +} - var baseQueue = hook.baseQueue; // The last pending update that hasn't been processed yet. +function mountDeferredValue(value, initialValue) { + var hook = mountWorkInProgressHook(); + return mountDeferredValueImpl(hook, value, initialValue); +} - var pendingQueue = queue.pending; +function updateDeferredValue(value, initialValue) { + var hook = updateWorkInProgressHook(); + var resolvedCurrentHook = currentHook; + var prevValue = resolvedCurrentHook.memoizedState; + return updateDeferredValueImpl(hook, prevValue, value, initialValue); +} - 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; - } +function rerenderDeferredValue(value, initialValue) { + var hook = updateWorkInProgressHook(); + + if (currentHook === null) { + // This is a rerender during a mount. + return mountDeferredValueImpl(hook, value, initialValue); + } else { + // This is a rerender during an update. + var prevValue = currentHook.memoizedState; + return updateDeferredValueImpl(hook, prevValue, value, initialValue); + } +} - { - 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." - ); - } - } +function mountDeferredValueImpl(hook, value, initialValue) { + if (// When `initialValue` is provided, we defer the initial render even if the + // current render is not synchronous. + initialValue !== undefined && // However, to avoid waterfalls, we do not defer if this render + // was itself spawned by an earlier useDeferredValue. Check if DeferredLane + // is part of the render lanes. + !includesSomeLane(renderLanes, DeferredLane)) { + // Render with the initial value + hook.memoizedState = initialValue; // Schedule a deferred render to switch to the final value. + + var deferredLane = requestDeferredLane(); + currentlyRenderingFiber$1.lanes = mergeLanes(currentlyRenderingFiber$1.lanes, deferredLane); + markSkippedUpdateLanes(deferredLane); + return initialValue; + } else { + hook.memoizedState = value; + return value; + } +} - current.baseQueue = baseQueue = pendingQueue; - queue.pending = null; +function updateDeferredValueImpl(hook, prevValue, value, initialValue) { + if (objectIs(value, prevValue)) { + // The incoming value is referentially identical to the currently rendered + // value, so we can bail out quickly. + return value; + } else { + // Received a new value that's different from the current value. + // Check if we're inside a hidden tree + if (isCurrentTreeHidden()) { + // Revealing a prerendered tree is considered the same as mounting new + // one, so we reuse the "mount" path in this case. + var resultValue = mountDeferredValueImpl(hook, value, initialValue); // Unlike during an actual mount, we need to mark this as an update if + // the value changed. + + if (!objectIs(resultValue, prevValue)) { + markWorkInProgressReceivedUpdate(); } - var baseState = hook.baseState; - - if (baseQueue === null) { - // If there are no pending updates, then the memoized state should be the - // same as the base state. Currently these only diverge in the case of - // useOptimistic, because useOptimistic accepts a new baseState on - // every render. - hook.memoizedState = baseState; // We don't need to call markWorkInProgressReceivedUpdate because - // baseState is derived from other reactive values. - } else { - // We have a queue to process. - var first = baseQueue.next; - var newState = baseState; - var newBaseState = null; - var newBaseQueueFirst = null; - var newBaseQueueLast = null; - var update = first; - var didReadFromEntangledAsyncAction = false; + return resultValue; + } - 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); - - 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, - revertLane: update.revertLane, - action: update.action, - hasEagerState: update.hasEagerState, - eagerState: update.eagerState, - next: null - }; + var shouldDeferValue = !includesOnlyNonUrgentLanes(renderLanes); - 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. + if (shouldDeferValue) { + // This is an urgent update. Since the value has changed, keep using the + // previous value and spawn a deferred render to update it later. + // Schedule a deferred render + var deferredLane = requestDeferredLane(); + currentlyRenderingFiber$1.lanes = mergeLanes(currentlyRenderingFiber$1.lanes, deferredLane); + markSkippedUpdateLanes(deferredLane); // Reuse the previous value. We do not need to mark this as an update, + // because we did not render a new value. - currentlyRenderingFiber$1.lanes = mergeLanes( - currentlyRenderingFiber$1.lanes, - updateLane - ); - markSkippedUpdateLanes(updateLane); - } else { - // This update does have sufficient priority. - // Check if this is an optimistic update. - var revertLane = update.revertLane; - - if (!enableAsyncActions || revertLane === NoLane) { - // This is not an optimistic update, and we're going to apply it now. - // But, if there were earlier updates that were skipped, we need to - // leave this update in the queue so it can be rebased later. - 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, - revertLane: NoLane, - action: update.action, - hasEagerState: update.hasEagerState, - eagerState: update.eagerState, - next: null - }; - newBaseQueueLast = newBaseQueueLast.next = _clone; - } // Check if this update is part of a pending async action. If so, - // we'll need to suspend until the action has finished, so that it's - // batched together with future updates in the same action. - - if (updateLane === peekEntangledActionLane()) { - didReadFromEntangledAsyncAction = true; - } - } else { - // This is an optimistic update. If the "revert" priority is - // sufficient, don't apply the update. Otherwise, apply the update, - // but leave it in the queue so it can be either reverted or - // rebased in a subsequent render. - if (isSubsetOfLanes(renderLanes, revertLane)) { - // The transition that this optimistic update is associated with - // has finished. Pretend the update doesn't exist by skipping - // over it. - update = update.next; // Check if this update is part of a pending async action. If so, - // we'll need to suspend until the action has finished, so that it's - // batched together with future updates in the same action. - - if (revertLane === peekEntangledActionLane()) { - didReadFromEntangledAsyncAction = true; - } + 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. + // Mark this as an update to prevent the fiber from bailing out. + markWorkInProgressReceivedUpdate(); + hook.memoizedState = value; + return value; + } + } +} - continue; - } else { - var _clone2 = { - // Once we commit an optimistic update, we shouldn't uncommit it - // until the transition it is associated with has finished - // (represented by revertLane). Using NoLane here works because 0 - // is a subset of all bitmasks, so this will never be skipped by - // the check above. - lane: NoLane, - // Reuse the same revertLane so we know when the transition - // has finished. - revertLane: update.revertLane, - action: update.action, - hasEagerState: update.hasEagerState, - eagerState: update.eagerState, - next: null - }; - - if (newBaseQueueLast === null) { - newBaseQueueFirst = newBaseQueueLast = _clone2; - newBaseState = newState; - } else { - newBaseQueueLast = newBaseQueueLast.next = _clone2; - } // 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, - revertLane - ); - markSkippedUpdateLanes(revertLane); - } - } // Process this update. +function startTransition(fiber, queue, pendingState, finishedState, callback, options) { + var previousPriority = getCurrentUpdatePriority(); + setCurrentUpdatePriority(higherEventPriority(previousPriority, ContinuousEventPriority)); + var prevTransition = ReactSharedInternals.T; + var currentTransition = { + _callbacks: new Set() + }; + + if (enableAsyncActions) { + // We don't really need to use an optimistic update here, because we + // schedule a second "revert" update below (which we use to suspend the + // transition until the async action scope has finished). But we'll use an + // optimistic update anyway to make it less likely the behavior accidentally + // diverges; for example, both an optimistic update and this one should + // share the same lane. + ReactSharedInternals.T = currentTransition; + dispatchOptimisticSetState(fiber, false, queue, pendingState); + } else { + ReactSharedInternals.T = null; + dispatchSetState(fiber, queue, pendingState); + ReactSharedInternals.T = currentTransition; + } + + { + currentTransition._updatedFibers = new Set(); + } + + try { + if (enableAsyncActions) { + var returnValue = callback(); // Check if we're inside an async action scope. If so, we'll entangle + // this new action with the existing scope. + // + // If we're not already inside an async action scope, and this action is + // async, then we'll create a new async scope. + // + // In the async case, the resulting render will suspend until the async + // action scope has finished. - var action = update.action; + if (returnValue !== null && typeof returnValue === 'object' && typeof returnValue.then === 'function') { + var thenable = returnValue; + notifyTransitionCallbacks(currentTransition, thenable); // Create a thenable that resolves to `finishedState` once the async + // action has completed. - if (shouldDoubleInvokeUserFnsInHooksDEV) { - reducer(newState, action); - } + var thenableForFinishedState = chainThenableValue(thenable, finishedState); + dispatchSetState(fiber, queue, thenableForFinishedState); + } else { + dispatchSetState(fiber, queue, finishedState); + } + } else { + // Async actions are not enabled. + dispatchSetState(fiber, queue, finishedState); + callback(); + } + } catch (error) { + if (enableAsyncActions) { + // This is a trick to get the `useTransition` hook to rethrow the error. + // When it unwraps the thenable with the `use` algorithm, the error + // will be thrown. + var rejectedThenable = { + then: function () {}, + status: 'rejected', + reason: error + }; + dispatchSetState(fiber, queue, rejectedThenable); + } else { + // The error rethrowing behavior is only enabled when the async actions + // feature is on, even for sync actions. + throw error; + } + } finally { + setCurrentUpdatePriority(previousPriority); + ReactSharedInternals.T = prevTransition; - 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 (prevTransition === null && currentTransition._updatedFibers) { + var updatedFibersCount = currentTransition._updatedFibers.size; - update = update.next; - } while (update !== null && update !== first); + currentTransition._updatedFibers.clear(); - 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(); // Check if this update is part of a pending async action. If so, we'll - // need to suspend until the action has finished, so that it's batched - // together with future updates in the same action. - // TODO: Once we support hooks inside useMemo (or an equivalent - // memoization boundary like Forget), hoist this logic so that it only - // suspends if the memo boundary produces a new value. - - if (didReadFromEntangledAsyncAction) { - var entangledActionThenable = peekEntangledActionThenable(); - - if (entangledActionThenable !== null) { - // TODO: Instead of the throwing the thenable directly, throw a - // special object like `use` does so we can detect if it's captured - // by userspace. - throw entangledActionThenable; - } - } + 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.'); } - - hook.memoizedState = newState; - hook.baseState = newBaseState; - hook.baseQueue = newBaseQueueLast; - queue.lastRenderedState = newState; } + } + } +} - 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; - } +function mountTransition() { + var stateHook = mountStateImpl(false); // The `start` method never changes. - var dispatch = queue.dispatch; - return [hook.memoizedState, dispatch]; - } + var start = startTransition.bind(null, currentlyRenderingFiber$1, stateHook.queue, true, false); + var hook = mountWorkInProgressHook(); + hook.memoizedState = start; + return [false, start]; +} - function rerenderReducer(reducer, initialArg, init) { - var hook = updateWorkInProgressHook(); - var queue = hook.queue; +function updateTransition() { + var _updateState2 = updateState(), + booleanOrThenable = _updateState2[0]; - if (queue === null) { - throw new Error( - "Should have a queue. This is likely a bug in React. Please file an issue." - ); - } + var hook = updateWorkInProgressHook(); + var start = hook.memoizedState; + var isPending = typeof booleanOrThenable === 'boolean' ? booleanOrThenable : // This will suspend until the async action scope has finished. + useThenable(booleanOrThenable); + return [isPending, start]; +} - queue.lastRenderedReducer = reducer; // This is a re-render. Apply the new render phase updates to the previous - // work-in-progress hook. +function rerenderTransition() { + var _rerenderState = rerenderState(), + booleanOrThenable = _rerenderState[0]; - var dispatch = queue.dispatch; - var lastRenderPhaseUpdate = queue.pending; - var newState = hook.memoizedState; + var hook = updateWorkInProgressHook(); + var start = hook.memoizedState; + var isPending = typeof booleanOrThenable === 'boolean' ? booleanOrThenable : // This will suspend until the async action scope has finished. + useThenable(booleanOrThenable); + return [isPending, start]; +} - if (lastRenderPhaseUpdate !== null) { - // The queue doesn't persist past this render pass. - queue.pending = null; - var firstRenderPhaseUpdate = lastRenderPhaseUpdate.next; - var update = firstRenderPhaseUpdate; +function useHostTransitionStatus() { + if (!enableAsyncActions) { + throw new Error('Not implemented.'); + } - 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 status = readContext(HostTransitionContext); + return status !== null ? status : NotPendingTransition; +} - if (!objectIs(newState, hook.memoizedState)) { - markWorkInProgressReceivedUpdate(); - } +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; + + { + // Use a lowercase r prefix for client-generated ids. + var globalClientId = globalClientIdCounter++; + id = ':' + identifierPrefix + 'r' + globalClientId.toString(32) + ':'; + } + + hook.memoizedState = id; + return id; +} - 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. +function updateId() { + var hook = updateWorkInProgressHook(); + var id = hook.memoizedState; + return id; +} - if (hook.baseQueue === null) { - hook.baseState = newState; - } +function mountRefresh() { + var hook = mountWorkInProgressHook(); + var refresh = hook.memoizedState = refreshCache.bind(null, currentlyRenderingFiber$1); + return refresh; +} - queue.lastRenderedState = newState; - } +function updateRefresh() { + var hook = updateWorkInProgressHook(); + return hook.memoizedState; +} - return [newState, dispatch]; - } +function refreshCache(fiber, seedKey, seedValue) { + // TODO: Consider warning if the refresh is at discrete priority, or if we + // otherwise suspect that it wasn't batched properly. - function mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) { - var fiber = currentlyRenderingFiber$1; - var hook = mountWorkInProgressHook(); - var nextSnapshot; - { - nextSnapshot = getSnapshot(); + var provider = fiber.return; + while (provider !== null) { + switch (provider.tag) { + case CacheComponent: + case HostRoot: { - if (!didWarnUncachedGetSnapshot) { - var cachedSnapshot = getSnapshot(); + // Schedule an update on the cache boundary to trigger a refresh. + var lane = requestUpdateLane(provider); + var refreshUpdate = createUpdate(lane); + var root = enqueueUpdate(provider, refreshUpdate, lane); - if (!objectIs(nextSnapshot, cachedSnapshot)) { - error( - "The result of getSnapshot should be cached to avoid an infinite loop" - ); - - 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. + if (root !== null) { + scheduleUpdateOnFiber(root, provider, lane); + entangleTransitions(root, provider, lane); + } // TODO: If a refresh never commits, the new cache created here must be + // released. A simple case is start refreshing a cache boundary, but then + // unmount that boundary before the refresh completes. - 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." - ); - } + var seededCache = createCache(); - var rootRenderLanes = getWorkInProgressRootRenderLanes(); + if (seedKey !== null && seedKey !== undefined && root !== null) { + { + { + error('The seed argument is not enabled outside experimental channels.'); + } + } + } - if (!includesBlockingLane(root, rootRenderLanes)) { - pushStoreConsistencyCheck(fiber, getSnapshot, nextSnapshot); + var payload = { + cache: seededCache + }; + refreshUpdate.payload = payload; + return; } - } // 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. - - fiber.flags |= Passive$1; - pushEffect( - HasEffect | Passive, - updateStoreInstance.bind(null, fiber, inst, nextSnapshot, getSnapshot), - createEffectInstance(), - 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; + provider = provider.return; + } // TODO: Warn if unmounted? - { - nextSnapshot = getSnapshot(); +} - { - if (!didWarnUncachedGetSnapshot) { - var cachedSnapshot = getSnapshot(); +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 (!objectIs(nextSnapshot, cachedSnapshot)) { - error( - "The result of getSnapshot should be cached to avoid an infinite loop" - ); + var lane = requestUpdateLane(fiber); + var update = { + lane: lane, + revertLane: NoLane, + action: action, + hasEagerState: false, + eagerState: null, + next: null + }; - didWarnUncachedGetSnapshot = true; - } - } - } - } + if (isRenderPhaseUpdate(fiber)) { + enqueueRenderPhaseUpdate(queue, update); + } else { + var root = enqueueConcurrentHookUpdate(fiber, queue, update, lane); - var prevSnapshot = (currentHook || hook).memoizedState; - var snapshotChanged = !objectIs(prevSnapshot, nextSnapshot); + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, lane); + entangleTransitionUpdate(root, queue, lane); + } + } - if (snapshotChanged) { - hook.memoizedState = nextSnapshot; - markWorkInProgressReceivedUpdate(); - } + markUpdateInDevTools(fiber, lane); +} - 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. - - if ( - inst.getSnapshot !== getSnapshot || - snapshotChanged || // Check if the subscribe 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 - ), - createEffectInstance(), - 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 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)) { - pushStoreConsistencyCheck(fiber, getSnapshot, nextSnapshot); - } - } - - return nextSnapshot; - } - - function pushStoreConsistencyCheck(fiber, getSnapshot, renderedSnapshot) { - fiber.flags |= StoreConsistency; - var check = { - getSnapshot: getSnapshot, - value: renderedSnapshot - }; - var componentUpdateQueue = currentlyRenderingFiber$1.updateQueue; +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().'); + } + } + + var lane = requestUpdateLane(fiber); + var update = { + lane: lane, + revertLane: NoLane, + action: action, + hasEagerState: false, + eagerState: null, + next: null + }; + + if (isRenderPhaseUpdate(fiber)) { + enqueueRenderPhaseUpdate(queue, update); + } else { + var alternate = fiber.alternate; + + 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; + + if (lastRenderedReducer !== null) { + var prevDispatcher = null; - if (componentUpdateQueue === null) { - componentUpdateQueue = createFunctionComponentUpdateQueue(); - currentlyRenderingFiber$1.updateQueue = componentUpdateQueue; - componentUpdateQueue.stores = [check]; - } else { - var stores = componentUpdateQueue.stores; + { + prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; + } - if (stores === null) { - componentUpdateQueue.stores = [check]; - } else { - stores.push(check); + 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. + + update.hasEagerState = true; + update.eagerState = eagerState; + + 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 { + { + ReactSharedInternals.H = prevDispatcher; + } } } } - 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. + var root = enqueueConcurrentHookUpdate(fiber, queue, update, lane); - if (checkIfSnapshotChanged(inst)) { - // Force a re-render. - forceStoreRerender(fiber); - } + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, lane); + entangleTransitionUpdate(root, queue, lane); } + } - 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. + markUpdateInDevTools(fiber, lane); +} - return subscribe(handleStoreChange); - } +function dispatchOptimisticSetState(fiber, throwIfDuringRender, queue, action) { + var transition = requestCurrentTransition(); + + { + if (transition === null) { + // An optimistic update occurred, but startTransition is not on the stack. + // There are two likely scenarios. + // One possibility is that the optimistic update is triggered by a regular + // event handler (e.g. `onSubmit`) instead of an action. This is a mistake + // and we will warn. + // The other possibility is the optimistic update is inside an async + // action, but after an `await`. In this case, we can make it "just work" + // by associating the optimistic update with the pending async action. + // Technically it's possible that the optimistic update is unrelated to + // the pending action, but we don't have a way of knowing this for sure + // because browsers currently do not provide a way to track async scope. + // (The AsyncContext proposal, if it lands, will solve this in the + // future.) However, this is no different than the problem of unrelated + // transitions being grouped together — it's not wrong per se, but it's + // not ideal. + // Once AsyncContext starts landing in browsers, we will provide better + // warnings in development for these cases. + if (peekEntangledActionLane() !== NoLane) ; else { + // There's no pending async action. The most likely cause is that we're + // inside a regular event handler (e.g. onSubmit) instead of an action. + error('An optimistic state update occurred outside a transition or ' + 'action. To fix, move the update to an action, or wrap ' + 'with startTransition.'); + } + } + } + + var update = { + // An optimistic update commits synchronously. + lane: SyncLane, + // After committing, the optimistic update is "reverted" using the same + // lane as the transition it's associated with. + revertLane: requestTransitionLane(), + action: action, + hasEagerState: false, + eagerState: null, + next: null + }; + + if (isRenderPhaseUpdate(fiber)) { + // When calling startTransition during render, this warns instead of + // throwing because throwing would be a breaking change. setOptimisticState + // is a new API so it's OK to throw. + if (throwIfDuringRender) { + throw new Error('Cannot update optimistic state while rendering.'); + } else { + // startTransition was called during render. We don't need to do anything + // besides warn here because the render phase update would be overidden by + // the second update, anyway. We can remove this branch and make it throw + // in a future release. + { + error('Cannot call startTransition while rendering.'); + } + } + } else { + var root = enqueueConcurrentHookUpdate(fiber, queue, update, SyncLane); + + if (root !== null) { + // NOTE: The optimistic update implementation assumes that the transition + // will never be attempted before the optimistic update. This currently + // holds because the optimistic update is always synchronous. If we ever + // change that, we'll need to account for this. + scheduleUpdateOnFiber(root, fiber, SyncLane); // Optimistic updates are always synchronous, so we don't need to call + // entangleTransitionUpdate here. + } + } + + markUpdateInDevTools(fiber, SyncLane); +} - function checkIfSnapshotChanged(inst) { - var latestGetSnapshot = inst.getSnapshot; - var prevValue = inst.value; +function isRenderPhaseUpdate(fiber) { + var alternate = fiber.alternate; + return fiber === currentlyRenderingFiber$1 || alternate !== null && alternate === currentlyRenderingFiber$1; +} - try { - var nextValue = latestGetSnapshot(); - return !objectIs(prevValue, nextValue); - } catch (error) { - return true; - } - } +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 (pending === null) { + // This is the first update. Create a circular list. + update.next = update; + } else { + update.next = pending.next; + pending.next = update; + } + + queue.pending = update; +} // TODO: Move to ReactFiberConcurrentUpdates? + + +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. + + queueLanes = intersectLanes(queueLanes, root.pendingLanes); // Entangle the new transition lane with the other transition lanes. + + 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. + + markRootEntangled(root, newQueueLanes); + } +} - function forceStoreRerender(fiber) { - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); +function markUpdateInDevTools(fiber, lane, action) { - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane); - } - } + { + markStateUpdateScheduled(fiber, lane); + } +} + +var ContextOnlyDispatcher = { + readContext: readContext, + use: use, + useCallback: throwInvalidHookError, + useContext: throwInvalidHookError, + useEffect: throwInvalidHookError, + useImperativeHandle: throwInvalidHookError, + useLayoutEffect: throwInvalidHookError, + useInsertionEffect: throwInvalidHookError, + useMemo: throwInvalidHookError, + useReducer: throwInvalidHookError, + useRef: throwInvalidHookError, + useState: throwInvalidHookError, + useDebugValue: throwInvalidHookError, + useDeferredValue: throwInvalidHookError, + useTransition: throwInvalidHookError, + useSyncExternalStore: throwInvalidHookError, + useId: throwInvalidHookError +}; + +{ + ContextOnlyDispatcher.useCacheRefresh = throwInvalidHookError; +} - function mountStateImpl(initialState) { - var hook = mountWorkInProgressHook(); +{ + ContextOnlyDispatcher.useMemoCache = throwInvalidHookError; +} - if (typeof initialState === "function") { - var initialStateInitializer = initialState; // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types +if (enableAsyncActions) { + ContextOnlyDispatcher.useHostTransitionStatus = throwInvalidHookError; + ContextOnlyDispatcher.useFormState = throwInvalidHookError; + ContextOnlyDispatcher.useActionState = throwInvalidHookError; +} - initialState = initialStateInitializer(); +if (enableAsyncActions) { + ContextOnlyDispatcher.useOptimistic = throwInvalidHookError; +} - if (shouldDoubleInvokeUserFnsInHooksDEV) { - setIsStrictModeForDevtools(true); // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types +var HooksDispatcherOnMountInDEV = null; +var HooksDispatcherOnMountWithHookTypesInDEV = null; +var HooksDispatcherOnUpdateInDEV = null; +var HooksDispatcherOnRerenderInDEV = null; +var InvalidNestedHooksDispatcherOnMountInDEV = null; +var InvalidNestedHooksDispatcherOnUpdateInDEV = null; +var InvalidNestedHooksDispatcherOnRerenderInDEV = null; + +{ + 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().'); + }; + + 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://react.dev/link/rules-of-hooks'); + }; + + HooksDispatcherOnMountInDEV = { + readContext: function (context) { + return readContext(context); + }, + use: use, + 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 = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; - initialStateInitializer(); - setIsStrictModeForDevtools(false); - } + try { + return mountMemo(create, deps); + } finally { + ReactSharedInternals.H = prevDispatcher; } + }, + useReducer: function (reducer, initialArg, init) { + currentHookNameInDev = 'useReducer'; + mountHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; - hook.memoizedState = hook.baseState = initialState; - var queue = { - pending: null, - lanes: NoLanes, - dispatch: null, - lastRenderedReducer: basicStateReducer, - lastRenderedState: initialState - }; - hook.queue = queue; - return hook; - } + try { + return mountReducer(reducer, initialArg, init); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useRef: function (initialValue) { + currentHookNameInDev = 'useRef'; + mountHookTypesDev(); + return mountRef(initialValue); + }, + useState: function (initialState) { + currentHookNameInDev = 'useState'; + mountHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; - function mountState(initialState) { - var hook = mountStateImpl(initialState); - var queue = hook.queue; - var dispatch = dispatchSetState.bind( - null, - currentlyRenderingFiber$1, - queue - ); - queue.dispatch = dispatch; - return [hook.memoizedState, dispatch]; - } + try { + return mountState(initialState); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useDebugValue: function (value, formatterFn) { + currentHookNameInDev = 'useDebugValue'; + mountHookTypesDev(); + return mountDebugValue(); + }, + useDeferredValue: function (value, initialValue) { + currentHookNameInDev = 'useDeferredValue'; + mountHookTypesDev(); + return mountDeferredValue(value, initialValue); + }, + useTransition: function () { + currentHookNameInDev = 'useTransition'; + mountHookTypesDev(); + return mountTransition(); + }, + useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { + currentHookNameInDev = 'useSyncExternalStore'; + mountHookTypesDev(); + return mountSyncExternalStore(subscribe, getSnapshot); + }, + useId: function () { + currentHookNameInDev = 'useId'; + mountHookTypesDev(); + return mountId(); + } + }; + + { + HooksDispatcherOnMountInDEV.useCacheRefresh = function useCacheRefresh() { + currentHookNameInDev = 'useCacheRefresh'; + mountHookTypesDev(); + return mountRefresh(); + }; + } - function updateState(initialState) { - return updateReducer(basicStateReducer); - } + { + HooksDispatcherOnMountInDEV.useMemoCache = useMemoCache; + } - function rerenderState(initialState) { - return rerenderReducer(basicStateReducer); - } + if (enableAsyncActions) { + HooksDispatcherOnMountInDEV.useHostTransitionStatus = useHostTransitionStatus; - function mountOptimistic(passthrough, reducer) { - var hook = mountWorkInProgressHook(); - hook.memoizedState = hook.baseState = passthrough; - var queue = { - pending: null, - lanes: NoLanes, - dispatch: null, - // Optimistic state does not use the eager update optimization. - lastRenderedReducer: null, - lastRenderedState: null - }; - hook.queue = queue; // This is different than the normal setState function. + HooksDispatcherOnMountInDEV.useFormState = function useFormState(action, initialState, permalink) { + currentHookNameInDev = 'useFormState'; + mountHookTypesDev(); + return mountActionState(action, initialState); + }; - var dispatch = dispatchOptimisticSetState.bind( - null, - currentlyRenderingFiber$1, - true, - queue - ); - queue.dispatch = dispatch; - return [passthrough, dispatch]; - } + HooksDispatcherOnMountInDEV.useActionState = function useActionState(action, initialState, permalink) { + currentHookNameInDev = 'useActionState'; + mountHookTypesDev(); + return mountActionState(action, initialState); + }; + } - function updateOptimistic(passthrough, reducer) { - var hook = updateWorkInProgressHook(); - return updateOptimisticImpl(hook, currentHook, passthrough, reducer); - } + if (enableAsyncActions) { + HooksDispatcherOnMountInDEV.useOptimistic = function useOptimistic(passthrough, reducer) { + currentHookNameInDev = 'useOptimistic'; + mountHookTypesDev(); + return mountOptimistic(passthrough); + }; + } + + HooksDispatcherOnMountWithHookTypesInDEV = { + readContext: function (context) { + return readContext(context); + }, + use: use, + 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 = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; - function updateOptimisticImpl(hook, current, passthrough, reducer) { - // Optimistic updates are always rebased on top of the latest value passed in - // as an argument. It's called a passthrough because if there are no pending - // updates, it will be returned as-is. - // - // Reset the base state to the passthrough. Future updates will be applied - // on top of this. - hook.baseState = passthrough; // If a reducer is not provided, default to the same one used by useState. + try { + return mountMemo(create, deps); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useReducer: function (reducer, initialArg, init) { + currentHookNameInDev = 'useReducer'; + updateHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; - var resolvedReducer = - typeof reducer === "function" ? reducer : basicStateReducer; - return updateReducerImpl(hook, currentHook, resolvedReducer); - } + try { + return mountReducer(reducer, initialArg, init); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useRef: function (initialValue) { + currentHookNameInDev = 'useRef'; + updateHookTypesDev(); + return mountRef(initialValue); + }, + useState: function (initialState) { + currentHookNameInDev = 'useState'; + updateHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; - function rerenderOptimistic(passthrough, reducer) { - // Unlike useState, useOptimistic doesn't support render phase updates. - // Also unlike useState, we need to replay all pending updates again in case - // the passthrough value changed. - // - // So instead of a forked re-render implementation that knows how to handle - // render phase udpates, we can use the same implementation as during a - // regular mount or update. - var hook = updateWorkInProgressHook(); - - if (currentHook !== null) { - // This is an update. Process the update queue. - return updateOptimisticImpl(hook, currentHook, passthrough, reducer); - } // This is a mount. No updates to process. - // Reset the base state to the passthrough. Future updates will be applied - // on top of this. - - hook.baseState = passthrough; - var dispatch = hook.queue.dispatch; - return [passthrough, dispatch]; - } // useActionState actions run sequentially, because each action receives the - // previous state as an argument. We store pending actions on a queue. - - function dispatchActionState( - fiber, - actionQueue, - setPendingState, - setState, - payload - ) { - if (isRenderPhaseUpdate(fiber)) { - throw new Error("Cannot update form state while rendering."); - } - - var last = actionQueue.pending; - - if (last === null) { - // There are no pending actions; this is the first one. We can run - // it immediately. - var newLast = { - payload: payload, - next: null // circular - }; - newLast.next = actionQueue.pending = newLast; - runActionStateAction(actionQueue, setPendingState, setState, payload); - } else { - // There's already an action running. Add to the queue. - var first = last.next; - var _newLast = { - payload: payload, - next: first - }; - actionQueue.pending = last.next = _newLast; - } - } + try { + return mountState(initialState); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useDebugValue: function (value, formatterFn) { + currentHookNameInDev = 'useDebugValue'; + updateHookTypesDev(); + return mountDebugValue(); + }, + useDeferredValue: function (value, initialValue) { + currentHookNameInDev = 'useDeferredValue'; + updateHookTypesDev(); + return mountDeferredValue(value, initialValue); + }, + useTransition: function () { + currentHookNameInDev = 'useTransition'; + updateHookTypesDev(); + return mountTransition(); + }, + useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { + currentHookNameInDev = 'useSyncExternalStore'; + updateHookTypesDev(); + return mountSyncExternalStore(subscribe, getSnapshot); + }, + useId: function () { + currentHookNameInDev = 'useId'; + updateHookTypesDev(); + return mountId(); + } + }; + + { + HooksDispatcherOnMountWithHookTypesInDEV.useCacheRefresh = function useCacheRefresh() { + currentHookNameInDev = 'useCacheRefresh'; + updateHookTypesDev(); + return mountRefresh(); + }; + } - function runActionStateAction( - actionQueue, - setPendingState, - setState, - payload - ) { - var action = actionQueue.action; - var prevState = actionQueue.state; // This is a fork of startTransition + { + HooksDispatcherOnMountWithHookTypesInDEV.useMemoCache = useMemoCache; + } - var prevTransition = ReactSharedInternals.T; - var currentTransition = { - _callbacks: new Set() - }; - ReactSharedInternals.T = currentTransition; + if (enableAsyncActions) { + HooksDispatcherOnMountWithHookTypesInDEV.useHostTransitionStatus = useHostTransitionStatus; - { - ReactSharedInternals.T._updatedFibers = new Set(); - } // Optimistically update the pending state, similar to useTransition. - // This will be reverted automatically when all actions are finished. + HooksDispatcherOnMountWithHookTypesInDEV.useFormState = function useFormState(action, initialState, permalink) { + currentHookNameInDev = 'useFormState'; + updateHookTypesDev(); + warnOnUseFormStateInDev(); + return mountActionState(action, initialState); + }; + + HooksDispatcherOnMountWithHookTypesInDEV.useActionState = function useActionState(action, initialState, permalink) { + currentHookNameInDev = 'useActionState'; + updateHookTypesDev(); + return mountActionState(action, initialState); + }; + } - setPendingState(true); + if (enableAsyncActions) { + HooksDispatcherOnMountWithHookTypesInDEV.useOptimistic = function useOptimistic(passthrough, reducer) { + currentHookNameInDev = 'useOptimistic'; + updateHookTypesDev(); + return mountOptimistic(passthrough); + }; + } + + HooksDispatcherOnUpdateInDEV = { + readContext: function (context) { + return readContext(context); + }, + use: use, + 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 = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; try { - var returnValue = action(prevState, payload); - - if ( - returnValue !== null && - typeof returnValue === "object" && // $FlowFixMe[method-unbinding] - typeof returnValue.then === "function" - ) { - var thenable = returnValue; - notifyTransitionCallbacks(currentTransition, thenable); // Attach a listener to read the return state of the action. As soon as - // this resolves, we can run the next action in the sequence. - - thenable.then( - function (nextState) { - actionQueue.state = nextState; - finishRunningActionStateAction( - actionQueue, - setPendingState, - setState - ); - }, - function () { - return finishRunningActionStateAction( - actionQueue, - setPendingState, - setState - ); - } - ); - setState(thenable); - } else { - setState(returnValue); - var nextState = returnValue; - actionQueue.state = nextState; - finishRunningActionStateAction( - actionQueue, - setPendingState, - setState - ); - } - } catch (error) { - // This is a trick to get the `useActionState` hook to rethrow the error. - // When it unwraps the thenable with the `use` algorithm, the error - // will be thrown. - var rejectedThenable = { - then: function () {}, - status: "rejected", - reason: error // $FlowFixMe: Not sure why this doesn't work - }; - setState(rejectedThenable); - finishRunningActionStateAction(actionQueue, setPendingState, setState); + return updateMemo(create, deps); } finally { - ReactSharedInternals.T = prevTransition; + ReactSharedInternals.H = prevDispatcher; + } + }, + useReducer: function (reducer, initialArg, init) { + currentHookNameInDev = 'useReducer'; + updateHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; - { - if (prevTransition === null && currentTransition._updatedFibers) { - var updatedFibersCount = currentTransition._updatedFibers.size; + try { + return updateReducer(reducer, initialArg, init); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useRef: function (initialValue) { + currentHookNameInDev = 'useRef'; + updateHookTypesDev(); + return updateRef(); + }, + useState: function (initialState) { + currentHookNameInDev = 'useState'; + updateHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; - currentTransition._updatedFibers.clear(); + try { + return updateState(initialState); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useDebugValue: function (value, formatterFn) { + currentHookNameInDev = 'useDebugValue'; + updateHookTypesDev(); + return updateDebugValue(); + }, + useDeferredValue: function (value, initialValue) { + currentHookNameInDev = 'useDeferredValue'; + updateHookTypesDev(); + return updateDeferredValue(value, initialValue); + }, + useTransition: function () { + currentHookNameInDev = 'useTransition'; + updateHookTypesDev(); + return updateTransition(); + }, + useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { + currentHookNameInDev = 'useSyncExternalStore'; + updateHookTypesDev(); + return updateSyncExternalStore(subscribe, getSnapshot); + }, + useId: function () { + currentHookNameInDev = 'useId'; + updateHookTypesDev(); + return updateId(); + } + }; + + { + HooksDispatcherOnUpdateInDEV.useCacheRefresh = function useCacheRefresh() { + currentHookNameInDev = 'useCacheRefresh'; + updateHookTypesDev(); + return updateRefresh(); + }; + } - 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." - ); - } - } - } - } - } + { + HooksDispatcherOnUpdateInDEV.useMemoCache = useMemoCache; + } - function finishRunningActionStateAction( - actionQueue, - setPendingState, - setState - ) { - // The action finished running. Pop it from the queue and run the next pending - // action, if there are any. - var last = actionQueue.pending; + if (enableAsyncActions) { + HooksDispatcherOnUpdateInDEV.useHostTransitionStatus = useHostTransitionStatus; - if (last !== null) { - var first = last.next; + HooksDispatcherOnUpdateInDEV.useFormState = function useFormState(action, initialState, permalink) { + currentHookNameInDev = 'useFormState'; + updateHookTypesDev(); + warnOnUseFormStateInDev(); + return updateActionState(action); + }; - if (first === last) { - // This was the last action in the queue. - actionQueue.pending = null; - } else { - // Remove the first node from the circular queue. - var next = first.next; - last.next = next; // Run the next action. + HooksDispatcherOnUpdateInDEV.useActionState = function useActionState(action, initialState, permalink) { + currentHookNameInDev = 'useActionState'; + updateHookTypesDev(); + return updateActionState(action); + }; + } - runActionStateAction( - actionQueue, - setPendingState, - setState, - next.payload - ); - } + if (enableAsyncActions) { + HooksDispatcherOnUpdateInDEV.useOptimistic = function useOptimistic(passthrough, reducer) { + currentHookNameInDev = 'useOptimistic'; + updateHookTypesDev(); + return updateOptimistic(passthrough, reducer); + }; + } + + HooksDispatcherOnRerenderInDEV = { + readContext: function (context) { + return readContext(context); + }, + use: use, + 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 = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnRerenderInDEV; + + try { + return updateMemo(create, deps); + } finally { + ReactSharedInternals.H = prevDispatcher; } - } + }, + useReducer: function (reducer, initialArg, init) { + currentHookNameInDev = 'useReducer'; + updateHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnRerenderInDEV; - function actionStateReducer(oldState, newState) { - return newState; - } + try { + return rerenderReducer(reducer, initialArg, init); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useRef: function (initialValue) { + currentHookNameInDev = 'useRef'; + updateHookTypesDev(); + return updateRef(); + }, + useState: function (initialState) { + currentHookNameInDev = 'useState'; + updateHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnRerenderInDEV; + + try { + return rerenderState(initialState); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useDebugValue: function (value, formatterFn) { + currentHookNameInDev = 'useDebugValue'; + updateHookTypesDev(); + return updateDebugValue(); + }, + useDeferredValue: function (value, initialValue) { + currentHookNameInDev = 'useDeferredValue'; + updateHookTypesDev(); + return rerenderDeferredValue(value, initialValue); + }, + useTransition: function () { + currentHookNameInDev = 'useTransition'; + updateHookTypesDev(); + return rerenderTransition(); + }, + useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { + currentHookNameInDev = 'useSyncExternalStore'; + updateHookTypesDev(); + return updateSyncExternalStore(subscribe, getSnapshot); + }, + useId: function () { + currentHookNameInDev = 'useId'; + updateHookTypesDev(); + return updateId(); + } + }; + + { + HooksDispatcherOnRerenderInDEV.useCacheRefresh = function useCacheRefresh() { + currentHookNameInDev = 'useCacheRefresh'; + updateHookTypesDev(); + return updateRefresh(); + }; + } - function mountActionState(action, initialStateProp, permalink) { - var initialState = initialStateProp; - // the `use` algorithm during render. + { + HooksDispatcherOnRerenderInDEV.useMemoCache = useMemoCache; + } - var stateHook = mountWorkInProgressHook(); - stateHook.memoizedState = stateHook.baseState = initialState; // TODO: Typing this "correctly" results in recursion limit errors - // const stateQueue: UpdateQueue, S | Awaited> = { + if (enableAsyncActions) { + HooksDispatcherOnRerenderInDEV.useHostTransitionStatus = useHostTransitionStatus; - var stateQueue = { - pending: null, - lanes: NoLanes, - dispatch: null, - lastRenderedReducer: actionStateReducer, - lastRenderedState: initialState - }; - stateHook.queue = stateQueue; - var setState = dispatchSetState.bind( - null, - currentlyRenderingFiber$1, - stateQueue - ); - stateQueue.dispatch = setState; // Pending state. This is used to store the pending state of the action. - // Tracked optimistically, like a transition pending state. - - var pendingStateHook = mountStateImpl(false); - var setPendingState = dispatchOptimisticSetState.bind( - null, - currentlyRenderingFiber$1, - false, - pendingStateHook.queue - ); // Action queue hook. This is used to queue pending actions. The queue is - // shared between all instances of the hook. Similar to a regular state queue, - // but different because the actions are run sequentially, and they run in - // an event instead of during render. - - var actionQueueHook = mountWorkInProgressHook(); - var actionQueue = { - state: initialState, - dispatch: null, - // circular - action: action, - pending: null - }; - actionQueueHook.queue = actionQueue; - var dispatch = dispatchActionState.bind( - null, - currentlyRenderingFiber$1, - actionQueue, - setPendingState, - setState - ); - actionQueue.dispatch = dispatch; // Stash the action function on the memoized state of the hook. We'll use this - // to detect when the action function changes so we can update it in - // an effect. - - actionQueueHook.memoizedState = action; - return [initialState, dispatch, false]; - } - - function updateActionState(action, initialState, permalink) { - var stateHook = updateWorkInProgressHook(); - var currentStateHook = currentHook; - return updateActionStateImpl(stateHook, currentStateHook, action); - } - - function updateActionStateImpl( - stateHook, - currentStateHook, - action, - initialState, - permalink - ) { - var _updateReducerImpl = updateReducerImpl( - stateHook, - currentStateHook, - actionStateReducer - ), - actionResult = _updateReducerImpl[0]; - - var _updateState = updateState(), - isPending = _updateState[0]; // This will suspend until the action finishes. - - var state = - typeof actionResult === "object" && - actionResult !== null && // $FlowFixMe[method-unbinding] - typeof actionResult.then === "function" - ? useThenable(actionResult) - : actionResult; - var actionQueueHook = updateWorkInProgressHook(); - var actionQueue = actionQueueHook.queue; - var dispatch = actionQueue.dispatch; // Check if a new action was passed. If so, update it in an effect. - - var prevAction = actionQueueHook.memoizedState; - - if (action !== prevAction) { - currentlyRenderingFiber$1.flags |= Passive$1; - pushEffect( - HasEffect | Passive, - actionStateActionEffect.bind(null, actionQueue, action), - createEffectInstance(), - null - ); - } - - return [state, dispatch, isPending]; - } - - function actionStateActionEffect(actionQueue, action) { - actionQueue.action = action; - } - - function rerenderActionState(action, initialState, permalink) { - // Unlike useState, useActionState doesn't support render phase updates. - // Also unlike useState, we need to replay all pending updates again in case - // the passthrough value changed. - // - // So instead of a forked re-render implementation that knows how to handle - // render phase udpates, we can use the same implementation as during a - // regular mount or update. - var stateHook = updateWorkInProgressHook(); - var currentStateHook = currentHook; + HooksDispatcherOnRerenderInDEV.useFormState = function useFormState(action, initialState, permalink) { + currentHookNameInDev = 'useFormState'; + updateHookTypesDev(); + warnOnUseFormStateInDev(); + return rerenderActionState(action); + }; + + HooksDispatcherOnRerenderInDEV.useActionState = function useActionState(action, initialState, permalink) { + currentHookNameInDev = 'useActionState'; + updateHookTypesDev(); + return rerenderActionState(action); + }; + } - if (currentStateHook !== null) { - // This is an update. Process the update queue. - return updateActionStateImpl(stateHook, currentStateHook, action); + if (enableAsyncActions) { + HooksDispatcherOnRerenderInDEV.useOptimistic = function useOptimistic(passthrough, reducer) { + currentHookNameInDev = 'useOptimistic'; + updateHookTypesDev(); + return rerenderOptimistic(passthrough, reducer); + }; + } + + InvalidNestedHooksDispatcherOnMountInDEV = { + readContext: function (context) { + warnInvalidContextAccess(); + return readContext(context); + }, + use: function (usable) { + warnInvalidHookAccess(); + return use(usable); + }, + 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 = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; + + try { + return mountMemo(create, deps); + } finally { + ReactSharedInternals.H = prevDispatcher; } + }, + useReducer: function (reducer, initialArg, init) { + currentHookNameInDev = 'useReducer'; + warnInvalidHookAccess(); + mountHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; - updateWorkInProgressHook(); // State - // This is a mount. No updates to process. + try { + return mountReducer(reducer, initialArg, init); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useRef: function (initialValue) { + currentHookNameInDev = 'useRef'; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountRef(initialValue); + }, + useState: function (initialState) { + currentHookNameInDev = 'useState'; + warnInvalidHookAccess(); + mountHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; - var state = stateHook.memoizedState; - var actionQueueHook = updateWorkInProgressHook(); - var actionQueue = actionQueueHook.queue; - var dispatch = actionQueue.dispatch; // This may have changed during the rerender. + try { + return mountState(initialState); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useDebugValue: function (value, formatterFn) { + currentHookNameInDev = 'useDebugValue'; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountDebugValue(); + }, + useDeferredValue: function (value, initialValue) { + currentHookNameInDev = 'useDeferredValue'; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountDeferredValue(value, initialValue); + }, + useTransition: function () { + currentHookNameInDev = 'useTransition'; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountTransition(); + }, + useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { + currentHookNameInDev = 'useSyncExternalStore'; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountSyncExternalStore(subscribe, getSnapshot); + }, + useId: function () { + currentHookNameInDev = 'useId'; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountId(); + } + }; + + { + InvalidNestedHooksDispatcherOnMountInDEV.useCacheRefresh = function useCacheRefresh() { + currentHookNameInDev = 'useCacheRefresh'; + mountHookTypesDev(); + return mountRefresh(); + }; + } - actionQueueHook.memoizedState = action; // For mount, pending is always false. + { + InvalidNestedHooksDispatcherOnMountInDEV.useMemoCache = function (size) { + warnInvalidHookAccess(); + return useMemoCache(size); + }; + } - return [state, dispatch, false]; - } + if (enableAsyncActions) { + InvalidNestedHooksDispatcherOnMountInDEV.useHostTransitionStatus = useHostTransitionStatus; - function pushEffect(tag, create, inst, deps) { - var effect = { - tag: tag, - create: create, - inst: inst, - deps: deps, - // Circular - next: null - }; - var componentUpdateQueue = currentlyRenderingFiber$1.updateQueue; + InvalidNestedHooksDispatcherOnMountInDEV.useFormState = function useFormState(action, initialState, permalink) { + currentHookNameInDev = 'useFormState'; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountActionState(action, initialState); + }; - if (componentUpdateQueue === null) { - componentUpdateQueue = createFunctionComponentUpdateQueue(); - currentlyRenderingFiber$1.updateQueue = componentUpdateQueue; - componentUpdateQueue.lastEffect = effect.next = effect; - } else { - var lastEffect = componentUpdateQueue.lastEffect; + InvalidNestedHooksDispatcherOnMountInDEV.useActionState = function useActionState(action, initialState, permalink) { + currentHookNameInDev = 'useActionState'; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountActionState(action, initialState); + }; + } + + if (enableAsyncActions) { + InvalidNestedHooksDispatcherOnMountInDEV.useOptimistic = function useOptimistic(passthrough, reducer) { + currentHookNameInDev = 'useOptimistic'; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountOptimistic(passthrough); + }; + } + + InvalidNestedHooksDispatcherOnUpdateInDEV = { + readContext: function (context) { + warnInvalidContextAccess(); + return readContext(context); + }, + use: function (usable) { + warnInvalidHookAccess(); + return use(usable); + }, + 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 = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; - if (lastEffect === null) { - componentUpdateQueue.lastEffect = effect.next = effect; - } else { - var firstEffect = lastEffect.next; - lastEffect.next = effect; - effect.next = firstEffect; - componentUpdateQueue.lastEffect = effect; - } + try { + return updateMemo(create, deps); + } finally { + ReactSharedInternals.H = prevDispatcher; } + }, + useReducer: function (reducer, initialArg, init) { + currentHookNameInDev = 'useReducer'; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; - return effect; - } - - function createEffectInstance() { - return { - destroy: undefined - }; - } + try { + return updateReducer(reducer, initialArg, init); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useRef: function (initialValue) { + currentHookNameInDev = 'useRef'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateRef(); + }, + useState: function (initialState) { + currentHookNameInDev = 'useState'; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; - function mountRef(initialValue) { - var hook = mountWorkInProgressHook(); - var ref = { - current: initialValue - }; - hook.memoizedState = ref; - return ref; - } + try { + return updateState(initialState); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useDebugValue: function (value, formatterFn) { + currentHookNameInDev = 'useDebugValue'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateDebugValue(); + }, + useDeferredValue: function (value, initialValue) { + currentHookNameInDev = 'useDeferredValue'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateDeferredValue(value, initialValue); + }, + useTransition: function () { + currentHookNameInDev = 'useTransition'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateTransition(); + }, + useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { + currentHookNameInDev = 'useSyncExternalStore'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateSyncExternalStore(subscribe, getSnapshot); + }, + useId: function () { + currentHookNameInDev = 'useId'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateId(); + } + }; + + { + InvalidNestedHooksDispatcherOnUpdateInDEV.useCacheRefresh = function useCacheRefresh() { + currentHookNameInDev = 'useCacheRefresh'; + updateHookTypesDev(); + return updateRefresh(); + }; + } - function updateRef(initialValue) { - var hook = updateWorkInProgressHook(); - return hook.memoizedState; - } + { + InvalidNestedHooksDispatcherOnUpdateInDEV.useMemoCache = function (size) { + warnInvalidHookAccess(); + return useMemoCache(size); + }; + } - 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, - createEffectInstance(), - nextDeps - ); - } + if (enableAsyncActions) { + InvalidNestedHooksDispatcherOnUpdateInDEV.useHostTransitionStatus = useHostTransitionStatus; - function updateEffectImpl(fiberFlags, hookFlags, create, deps) { - var hook = updateWorkInProgressHook(); - var nextDeps = deps === undefined ? null : deps; - var effect = hook.memoizedState; - var inst = effect.inst; // currentHook is null on initial mount when rerendering after a render phase - // state update or for strict mode. + InvalidNestedHooksDispatcherOnUpdateInDEV.useFormState = function useFormState(action, initialState, permalink) { + currentHookNameInDev = 'useFormState'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateActionState(action); + }; - if (currentHook !== null) { - if (nextDeps !== null) { - var prevEffect = currentHook.memoizedState; - var prevDeps = prevEffect.deps; + InvalidNestedHooksDispatcherOnUpdateInDEV.useActionState = function useActionState(action, initialState, permalink) { + currentHookNameInDev = 'useActionState'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateActionState(action); + }; + } + + if (enableAsyncActions) { + InvalidNestedHooksDispatcherOnUpdateInDEV.useOptimistic = function useOptimistic(passthrough, reducer) { + currentHookNameInDev = 'useOptimistic'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateOptimistic(passthrough, reducer); + }; + } + + InvalidNestedHooksDispatcherOnRerenderInDEV = { + readContext: function (context) { + warnInvalidContextAccess(); + return readContext(context); + }, + use: function (usable) { + warnInvalidHookAccess(); + return use(usable); + }, + 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 = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; - if (areHookInputsEqual(nextDeps, prevDeps)) { - hook.memoizedState = pushEffect(hookFlags, create, inst, nextDeps); - return; - } - } + try { + return updateMemo(create, deps); + } finally { + ReactSharedInternals.H = prevDispatcher; } + }, + useReducer: function (reducer, initialArg, init) { + currentHookNameInDev = 'useReducer'; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; - currentlyRenderingFiber$1.flags |= fiberFlags; - hook.memoizedState = pushEffect( - HasEffect | hookFlags, - create, - inst, - nextDeps - ); - } + try { + return rerenderReducer(reducer, initialArg, init); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useRef: function (initialValue) { + currentHookNameInDev = 'useRef'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateRef(); + }, + useState: function (initialState) { + currentHookNameInDev = 'useState'; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; - function mountEffect(create, deps) { - if ( - (currentlyRenderingFiber$1.mode & StrictEffectsMode) !== NoMode && - (currentlyRenderingFiber$1.mode & NoStrictPassiveEffectsMode) === NoMode - ) { - mountEffectImpl( - MountPassiveDev | Passive$1 | PassiveStatic, - Passive, - create, - deps - ); - } else { - mountEffectImpl(Passive$1 | PassiveStatic, Passive, create, deps); - } - } + try { + return rerenderState(initialState); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useDebugValue: function (value, formatterFn) { + currentHookNameInDev = 'useDebugValue'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateDebugValue(); + }, + useDeferredValue: function (value, initialValue) { + currentHookNameInDev = 'useDeferredValue'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return rerenderDeferredValue(value, initialValue); + }, + useTransition: function () { + currentHookNameInDev = 'useTransition'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return rerenderTransition(); + }, + useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { + currentHookNameInDev = 'useSyncExternalStore'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateSyncExternalStore(subscribe, getSnapshot); + }, + useId: function () { + currentHookNameInDev = 'useId'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateId(); + } + }; + + { + InvalidNestedHooksDispatcherOnRerenderInDEV.useCacheRefresh = function useCacheRefresh() { + currentHookNameInDev = 'useCacheRefresh'; + updateHookTypesDev(); + return updateRefresh(); + }; + } - function updateEffect(create, deps) { - updateEffectImpl(Passive$1, Passive, create, deps); - } + { + InvalidNestedHooksDispatcherOnRerenderInDEV.useMemoCache = function (size) { + warnInvalidHookAccess(); + return useMemoCache(size); + }; + } - function mountInsertionEffect(create, deps) { - mountEffectImpl(Update, Insertion, create, deps); - } + if (enableAsyncActions) { + InvalidNestedHooksDispatcherOnRerenderInDEV.useHostTransitionStatus = useHostTransitionStatus; - function updateInsertionEffect(create, deps) { - return updateEffectImpl(Update, Insertion, create, deps); - } + InvalidNestedHooksDispatcherOnRerenderInDEV.useFormState = function useFormState(action, initialState, permalink) { + currentHookNameInDev = 'useFormState'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return rerenderActionState(action); + }; - function mountLayoutEffect(create, deps) { - var fiberFlags = Update | LayoutStatic; + InvalidNestedHooksDispatcherOnRerenderInDEV.useActionState = function useActionState(action, initialState, permalink) { + currentHookNameInDev = 'useActionState'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return rerenderActionState(action); + }; + } + + if (enableAsyncActions) { + InvalidNestedHooksDispatcherOnRerenderInDEV.useOptimistic = function useOptimistic(passthrough, reducer) { + currentHookNameInDev = 'useOptimistic'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return rerenderOptimistic(passthrough, reducer); + }; + } +} - if ((currentlyRenderingFiber$1.mode & StrictEffectsMode) !== NoMode) { - fiberFlags |= MountLayoutDev; - } +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. + */ - return mountEffectImpl(fiberFlags, Layout, create, deps); - } +var currentUpdateIsNested = false; +var nestedUpdateScheduled = false; - function updateLayoutEffect(create, deps) { - return updateEffectImpl(Update, Layout, create, deps); - } +function isCurrentUpdateNested() { + return currentUpdateIsNested; +} - 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; +function markNestedUpdateScheduled() { + { + nestedUpdateScheduled = true; + } +} - { - 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(", ") + "}" - ); - } - } +function resetNestedUpdateFlag() { + { + currentUpdateIsNested = false; + nestedUpdateScheduled = false; + } +} - var _inst = create(); +function syncNestedUpdateFlag() { + { + currentUpdateIsNested = nestedUpdateScheduled; + nestedUpdateScheduled = false; + } +} - refObject.current = _inst; - return function () { - refObject.current = null; - }; - } - } +function getCommitTime() { + return commitTime; +} - 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? +function recordCommitTime() { - var effectDeps = - deps !== null && deps !== undefined ? deps.concat([ref]) : null; - var fiberFlags = Update | LayoutStatic; + commitTime = now(); +} - if ((currentlyRenderingFiber$1.mode & StrictEffectsMode) !== NoMode) { - fiberFlags |= MountLayoutDev; - } +function startProfilerTimer(fiber) { - mountEffectImpl( - fiberFlags, - Layout, - imperativeHandleEffect.bind(null, create, ref), - effectDeps - ); - } + profilerStartTime = now(); - 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 (fiber.actualStartTime < 0) { + fiber.actualStartTime = now(); + } +} - var effectDeps = - deps !== null && deps !== undefined ? deps.concat([ref]) : null; - updateEffectImpl( - Update, - Layout, - imperativeHandleEffect.bind(null, create, ref), - effectDeps - ); - } +function stopProfilerTimerIfRunning(fiber) { + + profilerStartTime = -1; +} - 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. +function stopProfilerTimerIfRunningAndRecordDelta(fiber, overrideBaseTime) { + + if (profilerStartTime >= 0) { + var elapsedTime = now() - profilerStartTime; + fiber.actualDuration += elapsedTime; + + if (overrideBaseTime) { + fiber.selfBaseDuration = elapsedTime; } - var updateDebugValue = mountDebugValue; + profilerStartTime = -1; + } +} + +function recordLayoutEffectDuration(fiber) { - function mountCallback(callback, deps) { - var hook = mountWorkInProgressHook(); - var nextDeps = deps === undefined ? null : deps; - hook.memoizedState = [callback, nextDeps]; - return callback; - } + 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) - function updateCallback(callback, deps) { - var hook = updateWorkInProgressHook(); - var nextDeps = deps === undefined ? null : deps; - var prevState = hook.memoizedState; + var parentFiber = fiber.return; - if (nextDeps !== null) { - var prevDeps = prevState[1]; + while (parentFiber !== null) { + switch (parentFiber.tag) { + case HostRoot: + var root = parentFiber.stateNode; + root.effectDuration += elapsedTime; + return; - if (areHookInputsEqual(nextDeps, prevDeps)) { - return prevState[0]; - } + case Profiler: + var parentStateNode = parentFiber.stateNode; + parentStateNode.effectDuration += elapsedTime; + return; } - hook.memoizedState = [callback, nextDeps]; - return callback; + parentFiber = parentFiber.return; } + } +} - function mountMemo(nextCreate, deps) { - var hook = mountWorkInProgressHook(); - var nextDeps = deps === undefined ? null : deps; - var nextValue = nextCreate(); +function recordPassiveEffectDuration(fiber) { - if (shouldDoubleInvokeUserFnsInHooksDEV) { - setIsStrictModeForDevtools(true); - nextCreate(); - setIsStrictModeForDevtools(false); - } + 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) - hook.memoizedState = [nextValue, nextDeps]; - return nextValue; - } + var parentFiber = fiber.return; - 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. + while (parentFiber !== null) { + switch (parentFiber.tag) { + case HostRoot: + var root = parentFiber.stateNode; - if (nextDeps !== null) { - var prevDeps = prevState[1]; + if (root !== null) { + root.passiveEffectDuration += elapsedTime; + } - if (areHookInputsEqual(nextDeps, prevDeps)) { - return prevState[0]; - } - } + return; - var nextValue = nextCreate(); + case Profiler: + var parentStateNode = parentFiber.stateNode; - if (shouldDoubleInvokeUserFnsInHooksDEV) { - setIsStrictModeForDevtools(true); - nextCreate(); - setIsStrictModeForDevtools(false); - } + 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; + } - hook.memoizedState = [nextValue, nextDeps]; - return nextValue; - } + return; + } - function mountDeferredValue(value, initialValue) { - var hook = mountWorkInProgressHook(); - return mountDeferredValueImpl(hook, value, initialValue); + parentFiber = parentFiber.return; } + } +} - function updateDeferredValue(value, initialValue) { - var hook = updateWorkInProgressHook(); - var resolvedCurrentHook = currentHook; - var prevValue = resolvedCurrentHook.memoizedState; - return updateDeferredValueImpl(hook, prevValue, value, initialValue); - } +function startLayoutEffectTimer() { - function rerenderDeferredValue(value, initialValue) { - var hook = updateWorkInProgressHook(); + layoutEffectStartTime = now(); +} - if (currentHook === null) { - // This is a rerender during a mount. - return mountDeferredValueImpl(hook, value, initialValue); - } else { - // This is a rerender during an update. - var prevValue = currentHook.memoizedState; - return updateDeferredValueImpl(hook, prevValue, value, initialValue); - } - } - - function mountDeferredValueImpl(hook, value, initialValue) { - if ( - // When `initialValue` is provided, we defer the initial render even if the - // current render is not synchronous. - initialValue !== undefined && // However, to avoid waterfalls, we do not defer if this render - // was itself spawned by an earlier useDeferredValue. Check if DeferredLane - // is part of the render lanes. - !includesSomeLane(renderLanes, DeferredLane) - ) { - // Render with the initial value - hook.memoizedState = initialValue; // Schedule a deferred render to switch to the final value. - - var deferredLane = requestDeferredLane(); - currentlyRenderingFiber$1.lanes = mergeLanes( - currentlyRenderingFiber$1.lanes, - deferredLane - ); - markSkippedUpdateLanes(deferredLane); - return initialValue; - } else { - hook.memoizedState = value; - return value; - } - } +function startPassiveEffectTimer() { - function updateDeferredValueImpl(hook, prevValue, value, initialValue) { - if (objectIs(value, prevValue)) { - // The incoming value is referentially identical to the currently rendered - // value, so we can bail out quickly. - return value; - } else { - // Received a new value that's different from the current value. - // Check if we're inside a hidden tree - if (isCurrentTreeHidden()) { - // Revealing a prerendered tree is considered the same as mounting new - // one, so we reuse the "mount" path in this case. - var resultValue = mountDeferredValueImpl(hook, value, initialValue); // Unlike during an actual mount, we need to mark this as an update if - // the value changed. - - if (!objectIs(resultValue, prevValue)) { - markWorkInProgressReceivedUpdate(); - } + passiveEffectStartTime = now(); +} - return resultValue; - } +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; + + while (child) { + // $FlowFixMe[unsafe-addition] addition with possible null/undefined value + fiber.actualDuration += child.actualDuration; + child = child.sibling; + } +} - var shouldDeferValue = !includesOnlyNonUrgentLanes(renderLanes); +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); +} - if (shouldDeferValue) { - // This is an urgent update. Since the value has changed, keep using the - // previous value and spawn a deferred render to update it later. - // Schedule a deferred render - var deferredLane = requestDeferredLane(); - currentlyRenderingFiber$1.lanes = mergeLanes( - currentlyRenderingFiber$1.lanes, - deferredLane - ); - markSkippedUpdateLanes(deferredLane); // Reuse the previous value. We do not need to mark this as an update, - // because we did not render a new value. +function warnOnInvalidCallback(callback) { + { + if (callback === null || typeof callback === 'function') { + return; + } // eslint-disable-next-line react-internal/safe-string-coercion - 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. - // Mark this as an update to prevent the fiber from bailing out. - markWorkInProgressReceivedUpdate(); - hook.memoizedState = value; - return value; - } - } - } - - function startTransition( - fiber, - queue, - pendingState, - finishedState, - callback, - options - ) { - var previousPriority = getCurrentUpdatePriority(); - setCurrentUpdatePriority( - higherEventPriority(previousPriority, ContinuousEventPriority) - ); - var prevTransition = ReactSharedInternals.T; - var currentTransition = { - _callbacks: new Set() - }; - if (enableAsyncActions) { - // We don't really need to use an optimistic update here, because we - // schedule a second "revert" update below (which we use to suspend the - // transition until the async action scope has finished). But we'll use an - // optimistic update anyway to make it less likely the behavior accidentally - // diverges; for example, both an optimistic update and this one should - // share the same lane. - ReactSharedInternals.T = currentTransition; - dispatchOptimisticSetState(fiber, false, queue, pendingState); - } else { - ReactSharedInternals.T = null; - dispatchSetState(fiber, queue, pendingState); - ReactSharedInternals.T = currentTransition; - } + var key = String(callback); - { - currentTransition._updatedFibers = new Set(); - } + if (!didWarnOnInvalidCallback.has(key)) { + didWarnOnInvalidCallback.add(key); - try { - if (enableAsyncActions) { - var returnValue = callback(); // Check if we're inside an async action scope. If so, we'll entangle - // this new action with the existing scope. - // - // If we're not already inside an async action scope, and this action is - // async, then we'll create a new async scope. - // - // In the async case, the resulting render will suspend until the async - // action scope has finished. - - if ( - returnValue !== null && - typeof returnValue === "object" && - typeof returnValue.then === "function" - ) { - var thenable = returnValue; - notifyTransitionCallbacks(currentTransition, thenable); // Create a thenable that resolves to `finishedState` once the async - // action has completed. - - var thenableForFinishedState = chainThenableValue( - thenable, - finishedState - ); - dispatchSetState(fiber, queue, thenableForFinishedState); - } else { - dispatchSetState(fiber, queue, finishedState); - } - } else { - // Async actions are not enabled. - dispatchSetState(fiber, queue, finishedState); - callback(); - } - } catch (error) { - if (enableAsyncActions) { - // This is a trick to get the `useTransition` hook to rethrow the error. - // When it unwraps the thenable with the `use` algorithm, the error - // will be thrown. - var rejectedThenable = { - then: function () {}, - status: "rejected", - reason: error - }; - dispatchSetState(fiber, queue, rejectedThenable); - } else { - // The error rethrowing behavior is only enabled when the async actions - // feature is on, even for sync actions. - throw error; - } - } finally { - setCurrentUpdatePriority(previousPriority); - ReactSharedInternals.T = prevTransition; + error('Expected the last optional `callback` argument to be a ' + 'function. Instead received: %s.', callback); + } + } +} - { - if (prevTransition === null && currentTransition._updatedFibers) { - var updatedFibersCount = currentTransition._updatedFibers.size; +function warnOnUndefinedDerivedState(type, partialState) { + { + if (partialState === undefined) { + var componentName = getComponentNameFromType(type) || 'Component'; - currentTransition._updatedFibers.clear(); + if (!didWarnAboutUndefinedDerivedState.has(componentName)) { + didWarnAboutUndefinedDerivedState.add(componentName); - 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." - ); - } - } - } + error('%s.getDerivedStateFromProps(): A valid state object (or null) must be returned. ' + 'You have returned undefined.', componentName); } } + } +} - function mountTransition() { - var stateHook = mountStateImpl(false); // The `start` method never changes. - - var start = startTransition.bind( - null, - currentlyRenderingFiber$1, - stateHook.queue, - true, - false - ); - var hook = mountWorkInProgressHook(); - hook.memoizedState = start; - return [false, start]; - } +function applyDerivedStateFromProps(workInProgress, ctor, getDerivedStateFromProps, nextProps) { + var prevState = workInProgress.memoizedState; + var partialState = getDerivedStateFromProps(nextProps, prevState); - function updateTransition() { - var _updateState2 = updateState(), - booleanOrThenable = _updateState2[0]; + { + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); - var hook = updateWorkInProgressHook(); - var start = hook.memoizedState; - var isPending = - typeof booleanOrThenable === "boolean" - ? booleanOrThenable // This will suspend until the async action scope has finished. - : useThenable(booleanOrThenable); - return [isPending, start]; + try { + // Invoke the function an extra time to help detect side-effects. + partialState = getDerivedStateFromProps(nextProps, prevState); + } finally { + setIsStrictModeForDevtools(false); + } } - function rerenderTransition() { - var _rerenderState = rerenderState(), - booleanOrThenable = _rerenderState[0]; + warnOnUndefinedDerivedState(ctor, partialState); + } // Merge the partial state and the previous state. - var hook = updateWorkInProgressHook(); - var start = hook.memoizedState; - var isPending = - typeof booleanOrThenable === "boolean" - ? booleanOrThenable // This will suspend until the async action scope has finished. - : useThenable(booleanOrThenable); - return [isPending, start]; - } - - function useHostTransitionStatus() { - if (!enableAsyncActions) { - throw new Error("Not implemented."); - } - var status = readContext(HostTransitionContext); - return status !== null ? status : NotPendingTransition; - } + 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. - 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 (workInProgress.lanes === NoLanes) { + // Queue is always non-null for classes + var updateQueue = workInProgress.updateQueue; + updateQueue.baseState = memoizedState; + } +} - var identifierPrefix = root.identifierPrefix; - var id; +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) { { - // Use a lowercase r prefix for client-generated ids. - var globalClientId = globalClientIdCounter++; - id = ":" + identifierPrefix + "r" + globalClientId.toString(32) + ":"; + warnOnInvalidCallback(callback); } - hook.memoizedState = id; - return id; + update.callback = callback; } - function updateId() { - var hook = updateWorkInProgressHook(); - var id = hook.memoizedState; - return id; - } + var root = enqueueUpdate(fiber, update, lane); - function mountRefresh() { - var hook = mountWorkInProgressHook(); - var refresh = (hook.memoizedState = refreshCache.bind( - null, - currentlyRenderingFiber$1 - )); - return refresh; + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, lane); + entangleTransitions(root, fiber, lane); } - function updateRefresh() { - var hook = updateWorkInProgressHook(); - return hook.memoizedState; + { + 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 refreshCache(fiber, seedKey, seedValue) { - // TODO: Consider warning if the refresh is at discrete priority, or if we - // otherwise suspect that it wasn't batched properly. - - var provider = fiber.return; - - while (provider !== null) { - switch (provider.tag) { - case CacheComponent: - case HostRoot: { - // Schedule an update on the cache boundary to trigger a refresh. - var lane = requestUpdateLane(provider); - var refreshUpdate = createUpdate(lane); - var root = enqueueUpdate(provider, refreshUpdate, lane); - - if (root !== null) { - scheduleUpdateOnFiber(root, provider, lane); - entangleTransitions(root, provider, lane); - } // TODO: If a refresh never commits, the new cache created here must be - // released. A simple case is start refreshing a cache boundary, but then - // unmount that boundary before the refresh completes. + if (callback !== undefined && callback !== null) { + { + warnOnInvalidCallback(callback); + } - var seededCache = createCache(); + update.callback = callback; + } - if (seedKey !== null && seedKey !== undefined && root !== null) { - { - { - error( - "The seed argument is not enabled outside experimental channels." - ); - } - } - } + var root = enqueueUpdate(fiber, update, lane); - var payload = { - cache: seededCache - }; - refreshUpdate.payload = payload; - return; - } - } + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, lane); + entangleTransitions(root, fiber, lane); + } - provider = provider.return; - } // TODO: Warn if unmounted? + { + 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; - function dispatchReducerAction(fiber, queue, action) { + if (callback !== undefined && callback !== null) { { - 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()." - ); - } - } - - var lane = requestUpdateLane(fiber); - var update = { - lane: lane, - revertLane: NoLane, - action: action, - hasEagerState: false, - eagerState: null, - next: null - }; - - if (isRenderPhaseUpdate(fiber)) { - enqueueRenderPhaseUpdate(queue, update); - } else { - var root = enqueueConcurrentHookUpdate(fiber, queue, update, lane); - - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, lane); - entangleTransitionUpdate(root, queue, lane); - } + warnOnInvalidCallback(callback); } - markUpdateInDevTools(fiber, lane); + update.callback = callback; } - 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()." - ); - } - } - - var lane = requestUpdateLane(fiber); - var update = { - lane: lane, - revertLane: NoLane, - action: action, - hasEagerState: false, - eagerState: null, - next: null - }; - - if (isRenderPhaseUpdate(fiber)) { - enqueueRenderPhaseUpdate(queue, update); - } else { - var alternate = fiber.alternate; + var root = enqueueUpdate(fiber, update, lane); - 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; + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, lane); + entangleTransitions(root, fiber, lane); + } - if (lastRenderedReducer !== null) { - var prevDispatcher = null; + { + markForceUpdateScheduled(fiber, lane); + } + } +}; - { - prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = - InvalidNestedHooksDispatcherOnUpdateInDEV; - } +function checkShouldComponentUpdate(workInProgress, ctor, oldProps, newProps, oldState, newState, nextContext) { + var instance = workInProgress.stateNode; - 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. - - update.hasEagerState = true; - update.eagerState = eagerState; - - 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 { - { - ReactSharedInternals.H = prevDispatcher; - } - } - } - } + if (typeof instance.shouldComponentUpdate === 'function') { + var shouldUpdate = instance.shouldComponentUpdate(newProps, newState, nextContext); - var root = enqueueConcurrentHookUpdate(fiber, queue, update, lane); + { + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, lane); - entangleTransitionUpdate(root, queue, lane); + try { + // Invoke the function an extra time to help detect side-effects. + shouldUpdate = instance.shouldComponentUpdate(newProps, newState, nextContext); + } finally { + setIsStrictModeForDevtools(false); } } - markUpdateInDevTools(fiber, lane); + if (shouldUpdate === undefined) { + error('%s.shouldComponentUpdate(): Returned undefined instead of a ' + 'boolean value. Make sure to return true or false.', getComponentNameFromType(ctor) || 'Component'); + } } - function dispatchOptimisticSetState( - fiber, - throwIfDuringRender, - queue, - action - ) { - var transition = requestCurrentTransition(); + return shouldUpdate; + } - { - if (transition === null) { - // An optimistic update occurred, but startTransition is not on the stack. - // There are two likely scenarios. - // One possibility is that the optimistic update is triggered by a regular - // event handler (e.g. `onSubmit`) instead of an action. This is a mistake - // and we will warn. - // The other possibility is the optimistic update is inside an async - // action, but after an `await`. In this case, we can make it "just work" - // by associating the optimistic update with the pending async action. - // Technically it's possible that the optimistic update is unrelated to - // the pending action, but we don't have a way of knowing this for sure - // because browsers currently do not provide a way to track async scope. - // (The AsyncContext proposal, if it lands, will solve this in the - // future.) However, this is no different than the problem of unrelated - // transitions being grouped together — it's not wrong per se, but it's - // not ideal. - // Once AsyncContext starts landing in browsers, we will provide better - // warnings in development for these cases. - if (peekEntangledActionLane() !== NoLane); - else { - // There's no pending async action. The most likely cause is that we're - // inside a regular event handler (e.g. onSubmit) instead of an action. - error( - "An optimistic state update occurred outside a transition or " + - "action. To fix, move the update to an action, or wrap " + - "with startTransition." - ); - } - } - } + if (ctor.prototype && ctor.prototype.isPureReactComponent) { + return !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState); + } - var update = { - // An optimistic update commits synchronously. - lane: SyncLane, - // After committing, the optimistic update is "reverted" using the same - // lane as the transition it's associated with. - revertLane: requestTransitionLane(), - action: action, - hasEagerState: false, - eagerState: null, - next: null - }; + return true; +} - if (isRenderPhaseUpdate(fiber)) { - // When calling startTransition during render, this warns instead of - // throwing because throwing would be a breaking change. setOptimisticState - // is a new API so it's OK to throw. - if (throwIfDuringRender) { - throw new Error("Cannot update optimistic state while rendering."); - } else { - // startTransition was called during render. We don't need to do anything - // besides warn here because the render phase update would be overidden by - // the second update, anyway. We can remove this branch and make it throw - // in a future release. - { - error("Cannot call startTransition while rendering."); - } - } - } else { - var root = enqueueConcurrentHookUpdate(fiber, queue, update, SyncLane); +function checkClassInstance(workInProgress, ctor, newProps) { + var instance = workInProgress.stateNode; - if (root !== null) { - // NOTE: The optimistic update implementation assumes that the transition - // will never be attempted before the optimistic update. This currently - // holds because the optimistic update is always synchronous. If we ever - // change that, we'll need to account for this. - scheduleUpdateOnFiber(root, fiber, SyncLane); // Optimistic updates are always synchronous, so we don't need to call - // entangleTransitionUpdate here. - } - } + { + var name = getComponentNameFromType(ctor) || 'Component'; + var renderPresent = instance.render; - markUpdateInDevTools(fiber, SyncLane); + if (!renderPresent) { + if (ctor.prototype && typeof ctor.prototype.render === 'function') { + error('No `render` method found on the %s ' + 'instance: did you accidentally return an object from the constructor?', name); + } else { + error('No `render` method found on the %s ' + 'instance: you may have forgotten to define `render`.', name); + } } - function isRenderPhaseUpdate(fiber) { - var alternate = fiber.alternate; - return ( - fiber === currentlyRenderingFiber$1 || - (alternate !== null && alternate === currentlyRenderingFiber$1) - ); + 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); } - 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 (pending === null) { - // This is the first update. Create a circular list. - update.next = update; - } else { - update.next = pending.next; - pending.next = update; - } + 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); + } - queue.pending = update; - } // TODO: Move to ReactFiberConcurrentUpdates? + if (instance.propTypes) { + error('propTypes was defined as an instance property on %s. Use a static ' + 'property to define propTypes instead.', name); + } - 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 (instance.contextType) { + error('contextType was defined as an instance property on %s. Use a static ' + 'property to define contextType instead.', name); + } - queueLanes = intersectLanes(queueLanes, root.pendingLanes); // Entangle the new transition lane with the other transition lanes. + { + if (instance.contextTypes) { + error('contextTypes was defined as an instance property on %s. Use a static ' + 'property to define contextTypes instead.', name); + } - 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 (ctor.contextType && ctor.contextTypes && !didWarnAboutContextTypeAndContextTypes.has(ctor)) { + didWarnAboutContextTypeAndContextTypes.add(ctor); - markRootEntangled(root, newQueueLanes); + error('%s declares both contextTypes and contextType static properties. ' + 'The legacy contextTypes property will be ignored.', name); } } - function markUpdateInDevTools(fiber, lane, action) { - { - markStateUpdateScheduled(fiber, lane); - } - } - - var ContextOnlyDispatcher = { - readContext: readContext, - use: use, - useCallback: throwInvalidHookError, - useContext: throwInvalidHookError, - useEffect: throwInvalidHookError, - useImperativeHandle: throwInvalidHookError, - useLayoutEffect: throwInvalidHookError, - useInsertionEffect: throwInvalidHookError, - useMemo: throwInvalidHookError, - useReducer: throwInvalidHookError, - useRef: throwInvalidHookError, - useState: throwInvalidHookError, - useDebugValue: throwInvalidHookError, - useDeferredValue: throwInvalidHookError, - useTransition: throwInvalidHookError, - useSyncExternalStore: throwInvalidHookError, - useId: throwInvalidHookError - }; - - { - ContextOnlyDispatcher.useCacheRefresh = throwInvalidHookError; + 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); } - { - ContextOnlyDispatcher.useMemoCache = throwInvalidHookError; + 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'); } - if (enableAsyncActions) { - ContextOnlyDispatcher.useHostTransitionStatus = throwInvalidHookError; - ContextOnlyDispatcher.useFormState = throwInvalidHookError; - ContextOnlyDispatcher.useActionState = throwInvalidHookError; + 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 (enableAsyncActions) { - ContextOnlyDispatcher.useOptimistic = throwInvalidHookError; + 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); } - var HooksDispatcherOnMountInDEV = null; - var HooksDispatcherOnMountWithHookTypesInDEV = null; - var HooksDispatcherOnUpdateInDEV = null; - var HooksDispatcherOnRerenderInDEV = null; - var InvalidNestedHooksDispatcherOnMountInDEV = null; - var InvalidNestedHooksDispatcherOnUpdateInDEV = null; - var InvalidNestedHooksDispatcherOnRerenderInDEV = null; - - { - 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()." - ); - }; - - 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://react.dev/link/rules-of-hooks" - ); - }; - - HooksDispatcherOnMountInDEV = { - readContext: function (context) { - return readContext(context); - }, - use: use, - 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 = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; + if (typeof instance.componentWillRecieveProps === 'function') { + error('%s has a method called ' + 'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?', name); + } - try { - return mountMemo(create, deps); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useReducer: function (reducer, initialArg, init) { - currentHookNameInDev = "useReducer"; - mountHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; + if (typeof instance.UNSAFE_componentWillRecieveProps === 'function') { + error('%s has a method called ' + 'UNSAFE_componentWillRecieveProps(). Did you mean UNSAFE_componentWillReceiveProps()?', name); + } - try { - return mountReducer(reducer, initialArg, init); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useRef: function (initialValue) { - currentHookNameInDev = "useRef"; - mountHookTypesDev(); - return mountRef(initialValue); - }, - useState: function (initialState) { - currentHookNameInDev = "useState"; - mountHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; + var hasMutatedProps = instance.props !== newProps; - try { - return mountState(initialState); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useDebugValue: function (value, formatterFn) { - currentHookNameInDev = "useDebugValue"; - mountHookTypesDev(); - return mountDebugValue(); - }, - useDeferredValue: function (value, initialValue) { - currentHookNameInDev = "useDeferredValue"; - mountHookTypesDev(); - return mountDeferredValue(value, initialValue); - }, - useTransition: function () { - currentHookNameInDev = "useTransition"; - mountHookTypesDev(); - return mountTransition(); - }, - useSyncExternalStore: function ( - subscribe, - getSnapshot, - getServerSnapshot - ) { - currentHookNameInDev = "useSyncExternalStore"; - mountHookTypesDev(); - return mountSyncExternalStore(subscribe, getSnapshot); - }, - useId: function () { - currentHookNameInDev = "useId"; - mountHookTypesDev(); - return mountId(); - } - }; + if (instance.props !== undefined && hasMutatedProps) { + error('When calling super() in `%s`, make sure to pass ' + "up the same props that your component's constructor was passed.", name); + } - { - HooksDispatcherOnMountInDEV.useCacheRefresh = - function useCacheRefresh() { - currentHookNameInDev = "useCacheRefresh"; - mountHookTypesDev(); - return mountRefresh(); - }; - } + 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); + } - { - HooksDispatcherOnMountInDEV.useMemoCache = useMemoCache; - } + if (typeof instance.getSnapshotBeforeUpdate === 'function' && typeof instance.componentDidUpdate !== 'function' && !didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.has(ctor)) { + didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.add(ctor); - if (enableAsyncActions) { - HooksDispatcherOnMountInDEV.useHostTransitionStatus = - useHostTransitionStatus; + error('%s: getSnapshotBeforeUpdate() should be used with componentDidUpdate(). ' + 'This component defines getSnapshotBeforeUpdate() only.', getComponentNameFromType(ctor)); + } - HooksDispatcherOnMountInDEV.useFormState = function useFormState( - action, - initialState, - permalink - ) { - currentHookNameInDev = "useFormState"; - mountHookTypesDev(); - return mountActionState(action, initialState); - }; + 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); + } - HooksDispatcherOnMountInDEV.useActionState = function useActionState( - action, - initialState, - permalink - ) { - currentHookNameInDev = "useActionState"; - mountHookTypesDev(); - return mountActionState(action, initialState); - }; - } + 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 (enableAsyncActions) { - HooksDispatcherOnMountInDEV.useOptimistic = function useOptimistic( - passthrough, - reducer - ) { - currentHookNameInDev = "useOptimistic"; - mountHookTypesDev(); - return mountOptimistic(passthrough); - }; - } + 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); + } - HooksDispatcherOnMountWithHookTypesInDEV = { - readContext: function (context) { - return readContext(context); - }, - use: use, - 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 = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; + var state = instance.state; - try { - return mountMemo(create, deps); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useReducer: function (reducer, initialArg, init) { - currentHookNameInDev = "useReducer"; - updateHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; + if (state && (typeof state !== 'object' || isArray(state))) { + error('%s.state: must be set to an object or null', name); + } - try { - return mountReducer(reducer, initialArg, init); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useRef: function (initialValue) { - currentHookNameInDev = "useRef"; - updateHookTypesDev(); - return mountRef(initialValue); - }, - useState: function (initialState) { - currentHookNameInDev = "useState"; - updateHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; + if (typeof instance.getChildContext === 'function' && typeof ctor.childContextTypes !== 'object') { + error('%s.getChildContext(): childContextTypes must be defined in order to ' + 'use getChildContext().', name); + } + } +} - try { - return mountState(initialState); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useDebugValue: function (value, formatterFn) { - currentHookNameInDev = "useDebugValue"; - updateHookTypesDev(); - return mountDebugValue(); - }, - useDeferredValue: function (value, initialValue) { - currentHookNameInDev = "useDeferredValue"; - updateHookTypesDev(); - return mountDeferredValue(value, initialValue); - }, - useTransition: function () { - currentHookNameInDev = "useTransition"; - updateHookTypesDev(); - return mountTransition(); - }, - useSyncExternalStore: function ( - subscribe, - getSnapshot, - getServerSnapshot - ) { - currentHookNameInDev = "useSyncExternalStore"; - updateHookTypesDev(); - return mountSyncExternalStore(subscribe, getSnapshot); - }, - useId: function () { - currentHookNameInDev = "useId"; - updateHookTypesDev(); - return mountId(); +function constructClassInstance(workInProgress, ctor, props) { + var isLegacyContextConsumer = false; + var unmaskedContext = emptyContextObject; + var context = emptyContextObject; + var contextType = ctor.contextType; + + { + if ('contextType' in ctor) { + var isValid = // Allow null for conditional declaration + contextType === null || contextType !== undefined && contextType.$$typeof === REACT_CONTEXT_TYPE; + + if (!isValid && !didWarnAboutInvalidateContextType.has(ctor)) { + didWarnAboutInvalidateContextType.add(ctor); + var addendum = ''; + + 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_CONSUMER_TYPE) { + addendum = ' Did you accidentally pass the Context.Consumer instead?'; + } else { + addendum = ' However, it is set to an object with keys {' + Object.keys(contextType).join(', ') + '}.'; } - }; - { - HooksDispatcherOnMountWithHookTypesInDEV.useCacheRefresh = - function useCacheRefresh() { - currentHookNameInDev = "useCacheRefresh"; - updateHookTypesDev(); - return mountRefresh(); - }; + error('%s defines an invalid contextType. ' + 'contextType should point to the Context object returned by React.createContext().%s', getComponentNameFromType(ctor) || 'Component', addendum); } + } + } - { - HooksDispatcherOnMountWithHookTypesInDEV.useMemoCache = useMemoCache; - } + 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; + } - if (enableAsyncActions) { - HooksDispatcherOnMountWithHookTypesInDEV.useHostTransitionStatus = - useHostTransitionStatus; + var instance = new ctor(props, context); // Instantiate twice to help detect side-effects. - HooksDispatcherOnMountWithHookTypesInDEV.useFormState = - function useFormState(action, initialState, permalink) { - currentHookNameInDev = "useFormState"; - updateHookTypesDev(); - warnOnUseFormStateInDev(); - return mountActionState(action, initialState); - }; + { + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); - HooksDispatcherOnMountWithHookTypesInDEV.useActionState = - function useActionState(action, initialState, permalink) { - currentHookNameInDev = "useActionState"; - updateHookTypesDev(); - return mountActionState(action, initialState); - }; + try { + instance = new ctor(props, context); // eslint-disable-line no-new + } finally { + setIsStrictModeForDevtools(false); } + } + } - if (enableAsyncActions) { - HooksDispatcherOnMountWithHookTypesInDEV.useOptimistic = - function useOptimistic(passthrough, reducer) { - currentHookNameInDev = "useOptimistic"; - updateHookTypesDev(); - return mountOptimistic(passthrough); - }; - } + var state = workInProgress.memoizedState = instance.state !== null && instance.state !== undefined ? instance.state : null; + instance.updater = classComponentUpdater; + workInProgress.stateNode = instance; // The instance needs access to the fiber so that it can schedule updates - HooksDispatcherOnUpdateInDEV = { - readContext: function (context) { - return readContext(context); - }, - use: use, - 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 = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; + set(instance, workInProgress); - try { - return updateMemo(create, deps); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useReducer: function (reducer, initialArg, init) { - currentHookNameInDev = "useReducer"; - updateHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; + { + instance._reactInternalInstance = fakeInternalInstance; + } - try { - return updateReducer(reducer, initialArg, init); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useRef: function (initialValue) { - currentHookNameInDev = "useRef"; - updateHookTypesDev(); - return updateRef(); - }, - useState: function (initialState) { - currentHookNameInDev = "useState"; - updateHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; + { + if (typeof ctor.getDerivedStateFromProps === 'function' && state === null) { + var componentName = getComponentNameFromType(ctor) || 'Component'; - try { - return updateState(initialState); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useDebugValue: function (value, formatterFn) { - currentHookNameInDev = "useDebugValue"; - updateHookTypesDev(); - return updateDebugValue(); - }, - useDeferredValue: function (value, initialValue) { - currentHookNameInDev = "useDeferredValue"; - updateHookTypesDev(); - return updateDeferredValue(value, initialValue); - }, - useTransition: function () { - currentHookNameInDev = "useTransition"; - updateHookTypesDev(); - return updateTransition(); - }, - useSyncExternalStore: function ( - subscribe, - getSnapshot, - getServerSnapshot - ) { - currentHookNameInDev = "useSyncExternalStore"; - updateHookTypesDev(); - return updateSyncExternalStore(subscribe, getSnapshot); - }, - useId: function () { - currentHookNameInDev = "useId"; - updateHookTypesDev(); - return updateId(); - } - }; + if (!didWarnAboutUninitializedState.has(componentName)) { + didWarnAboutUninitializedState.add(componentName); - { - HooksDispatcherOnUpdateInDEV.useCacheRefresh = - function useCacheRefresh() { - currentHookNameInDev = "useCacheRefresh"; - updateHookTypesDev(); - return updateRefresh(); - }; + 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; - { - HooksDispatcherOnUpdateInDEV.useMemoCache = useMemoCache; - } - - if (enableAsyncActions) { - HooksDispatcherOnUpdateInDEV.useHostTransitionStatus = - useHostTransitionStatus; - - HooksDispatcherOnUpdateInDEV.useFormState = function useFormState( - action, - initialState, - permalink - ) { - currentHookNameInDev = "useFormState"; - updateHookTypesDev(); - warnOnUseFormStateInDev(); - return updateActionState(action); - }; + if (typeof instance.componentWillMount === 'function' && instance.componentWillMount.__suppressDeprecationWarning !== true) { + foundWillMountName = 'componentWillMount'; + } else if (typeof instance.UNSAFE_componentWillMount === 'function') { + foundWillMountName = 'UNSAFE_componentWillMount'; + } - HooksDispatcherOnUpdateInDEV.useActionState = function useActionState( - action, - initialState, - permalink - ) { - currentHookNameInDev = "useActionState"; - updateHookTypesDev(); - return updateActionState(action); - }; + if (typeof instance.componentWillReceiveProps === 'function' && instance.componentWillReceiveProps.__suppressDeprecationWarning !== true) { + foundWillReceivePropsName = 'componentWillReceiveProps'; + } else if (typeof instance.UNSAFE_componentWillReceiveProps === 'function') { + foundWillReceivePropsName = 'UNSAFE_componentWillReceiveProps'; } - if (enableAsyncActions) { - HooksDispatcherOnUpdateInDEV.useOptimistic = function useOptimistic( - passthrough, - reducer - ) { - currentHookNameInDev = "useOptimistic"; - updateHookTypesDev(); - return updateOptimistic(passthrough, reducer); - }; + if (typeof instance.componentWillUpdate === 'function' && instance.componentWillUpdate.__suppressDeprecationWarning !== true) { + foundWillUpdateName = 'componentWillUpdate'; + } else if (typeof instance.UNSAFE_componentWillUpdate === 'function') { + foundWillUpdateName = 'UNSAFE_componentWillUpdate'; } - HooksDispatcherOnRerenderInDEV = { - readContext: function (context) { - return readContext(context); - }, - use: use, - 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 = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnRerenderInDEV; + if (foundWillMountName !== null || foundWillReceivePropsName !== null || foundWillUpdateName !== null) { + var _componentName = getComponentNameFromType(ctor) || 'Component'; - try { - return updateMemo(create, deps); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useReducer: function (reducer, initialArg, init) { - currentHookNameInDev = "useReducer"; - updateHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnRerenderInDEV; + var newApiName = typeof ctor.getDerivedStateFromProps === 'function' ? 'getDerivedStateFromProps()' : 'getSnapshotBeforeUpdate()'; - try { - return rerenderReducer(reducer, initialArg, init); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useRef: function (initialValue) { - currentHookNameInDev = "useRef"; - updateHookTypesDev(); - return updateRef(); - }, - useState: function (initialState) { - currentHookNameInDev = "useState"; - updateHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnRerenderInDEV; + if (!didWarnAboutLegacyLifecyclesAndDerivedState.has(_componentName)) { + didWarnAboutLegacyLifecyclesAndDerivedState.add(_componentName); - try { - return rerenderState(initialState); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useDebugValue: function (value, formatterFn) { - currentHookNameInDev = "useDebugValue"; - updateHookTypesDev(); - return updateDebugValue(); - }, - useDeferredValue: function (value, initialValue) { - currentHookNameInDev = "useDeferredValue"; - updateHookTypesDev(); - return rerenderDeferredValue(value, initialValue); - }, - useTransition: function () { - currentHookNameInDev = "useTransition"; - updateHookTypesDev(); - return rerenderTransition(); - }, - useSyncExternalStore: function ( - subscribe, - getSnapshot, - getServerSnapshot - ) { - currentHookNameInDev = "useSyncExternalStore"; - updateHookTypesDev(); - return updateSyncExternalStore(subscribe, getSnapshot); - }, - useId: function () { - currentHookNameInDev = "useId"; - updateHookTypesDev(); - return updateId(); + 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://react.dev/link/unsafe-component-lifecycles', _componentName, newApiName, foundWillMountName !== null ? "\n " + foundWillMountName : '', foundWillReceivePropsName !== null ? "\n " + foundWillReceivePropsName : '', foundWillUpdateName !== null ? "\n " + foundWillUpdateName : ''); } - }; - - { - HooksDispatcherOnRerenderInDEV.useCacheRefresh = - function useCacheRefresh() { - currentHookNameInDev = "useCacheRefresh"; - updateHookTypesDev(); - return updateRefresh(); - }; } + } + } // Cache unmasked context so we can avoid recreating masked context unless necessary. + // ReactFiberContext usually updates this cache but can't for newly-created instances. - { - HooksDispatcherOnRerenderInDEV.useMemoCache = useMemoCache; - } - - if (enableAsyncActions) { - HooksDispatcherOnRerenderInDEV.useHostTransitionStatus = - useHostTransitionStatus; - - HooksDispatcherOnRerenderInDEV.useFormState = function useFormState( - action, - initialState, - permalink - ) { - currentHookNameInDev = "useFormState"; - updateHookTypesDev(); - warnOnUseFormStateInDev(); - return rerenderActionState(action); - }; - HooksDispatcherOnRerenderInDEV.useActionState = function useActionState( - action, - initialState, - permalink - ) { - currentHookNameInDev = "useActionState"; - updateHookTypesDev(); - return rerenderActionState(action); - }; - } + if (isLegacyContextConsumer) { + cacheContext(workInProgress, unmaskedContext, context); + } - if (enableAsyncActions) { - HooksDispatcherOnRerenderInDEV.useOptimistic = function useOptimistic( - passthrough, - reducer - ) { - currentHookNameInDev = "useOptimistic"; - updateHookTypesDev(); - return rerenderOptimistic(passthrough, reducer); - }; - } + return instance; +} - InvalidNestedHooksDispatcherOnMountInDEV = { - readContext: function (context) { - warnInvalidContextAccess(); - return readContext(context); - }, - use: function (usable) { - warnInvalidHookAccess(); - return use(usable); - }, - 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 = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; +function callComponentWillMount(workInProgress, instance) { + var oldState = instance.state; - try { - return mountMemo(create, deps); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useReducer: function (reducer, initialArg, init) { - currentHookNameInDev = "useReducer"; - warnInvalidHookAccess(); - mountHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; + if (typeof instance.componentWillMount === 'function') { + instance.componentWillMount(); + } - try { - return mountReducer(reducer, initialArg, init); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useRef: function (initialValue) { - currentHookNameInDev = "useRef"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountRef(initialValue); - }, - useState: function (initialState) { - currentHookNameInDev = "useState"; - warnInvalidHookAccess(); - mountHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; + if (typeof instance.UNSAFE_componentWillMount === 'function') { + instance.UNSAFE_componentWillMount(); + } - try { - return mountState(initialState); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useDebugValue: function (value, formatterFn) { - currentHookNameInDev = "useDebugValue"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountDebugValue(); - }, - useDeferredValue: function (value, initialValue) { - currentHookNameInDev = "useDeferredValue"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountDeferredValue(value, initialValue); - }, - useTransition: function () { - currentHookNameInDev = "useTransition"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountTransition(); - }, - useSyncExternalStore: function ( - subscribe, - getSnapshot, - getServerSnapshot - ) { - currentHookNameInDev = "useSyncExternalStore"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountSyncExternalStore(subscribe, getSnapshot); - }, - useId: function () { - currentHookNameInDev = "useId"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountId(); - } - }; + 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'); + } - { - InvalidNestedHooksDispatcherOnMountInDEV.useCacheRefresh = - function useCacheRefresh() { - currentHookNameInDev = "useCacheRefresh"; - mountHookTypesDev(); - return mountRefresh(); - }; - } + classComponentUpdater.enqueueReplaceState(instance, instance.state, null); + } +} - { - InvalidNestedHooksDispatcherOnMountInDEV.useMemoCache = function ( - size - ) { - warnInvalidHookAccess(); - return useMemoCache(size); - }; - } +function callComponentWillReceiveProps(workInProgress, instance, newProps, nextContext) { + var oldState = instance.state; - if (enableAsyncActions) { - InvalidNestedHooksDispatcherOnMountInDEV.useHostTransitionStatus = - useHostTransitionStatus; + if (typeof instance.componentWillReceiveProps === 'function') { + instance.componentWillReceiveProps(newProps, nextContext); + } - InvalidNestedHooksDispatcherOnMountInDEV.useFormState = - function useFormState(action, initialState, permalink) { - currentHookNameInDev = "useFormState"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountActionState(action, initialState); - }; + if (typeof instance.UNSAFE_componentWillReceiveProps === 'function') { + instance.UNSAFE_componentWillReceiveProps(newProps, nextContext); + } - InvalidNestedHooksDispatcherOnMountInDEV.useActionState = - function useActionState(action, initialState, permalink) { - currentHookNameInDev = "useActionState"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountActionState(action, initialState); - }; - } + if (instance.state !== oldState) { + { + var componentName = getComponentNameFromFiber(workInProgress) || 'Component'; - if (enableAsyncActions) { - InvalidNestedHooksDispatcherOnMountInDEV.useOptimistic = - function useOptimistic(passthrough, reducer) { - currentHookNameInDev = "useOptimistic"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountOptimistic(passthrough); - }; - } + if (!didWarnAboutStateAssignmentForComponent.has(componentName)) { + didWarnAboutStateAssignmentForComponent.add(componentName); - InvalidNestedHooksDispatcherOnUpdateInDEV = { - readContext: function (context) { - warnInvalidContextAccess(); - return readContext(context); - }, - use: function (usable) { - warnInvalidHookAccess(); - return use(usable); - }, - 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 = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; + error('%s.componentWillReceiveProps(): Assigning directly to ' + "this.state is deprecated (except inside a component's " + 'constructor). Use setState instead.', componentName); + } + } - try { - return updateMemo(create, deps); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useReducer: function (reducer, initialArg, init) { - currentHookNameInDev = "useReducer"; - warnInvalidHookAccess(); - updateHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; + classComponentUpdater.enqueueReplaceState(instance, instance.state, null); + } +} // Invokes the mount life-cycles on a previously never rendered instance. - try { - return updateReducer(reducer, initialArg, init); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useRef: function (initialValue) { - currentHookNameInDev = "useRef"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateRef(); - }, - useState: function (initialState) { - currentHookNameInDev = "useState"; - warnInvalidHookAccess(); - updateHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; - try { - return updateState(initialState); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useDebugValue: function (value, formatterFn) { - currentHookNameInDev = "useDebugValue"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateDebugValue(); - }, - useDeferredValue: function (value, initialValue) { - currentHookNameInDev = "useDeferredValue"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateDeferredValue(value, initialValue); - }, - useTransition: function () { - currentHookNameInDev = "useTransition"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateTransition(); - }, - useSyncExternalStore: function ( - subscribe, - getSnapshot, - getServerSnapshot - ) { - currentHookNameInDev = "useSyncExternalStore"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateSyncExternalStore(subscribe, getSnapshot); - }, - useId: function () { - currentHookNameInDev = "useId"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateId(); - } - }; +function mountClassInstance(workInProgress, ctor, newProps, renderLanes) { + { + checkClassInstance(workInProgress, ctor, newProps); + } - { - InvalidNestedHooksDispatcherOnUpdateInDEV.useCacheRefresh = - function useCacheRefresh() { - currentHookNameInDev = "useCacheRefresh"; - updateHookTypesDev(); - return updateRefresh(); - }; - } + var instance = workInProgress.stateNode; + instance.props = newProps; + instance.state = workInProgress.memoizedState; + instance.refs = {}; + initializeUpdateQueue(workInProgress); + var contextType = ctor.contextType; - { - InvalidNestedHooksDispatcherOnUpdateInDEV.useMemoCache = function ( - size - ) { - warnInvalidHookAccess(); - return useMemoCache(size); - }; - } + if (typeof contextType === 'object' && contextType !== null) { + instance.context = readContext(contextType); + } else { + var unmaskedContext = getUnmaskedContext(workInProgress, ctor, true); + instance.context = getMaskedContext(workInProgress, unmaskedContext); + } - if (enableAsyncActions) { - InvalidNestedHooksDispatcherOnUpdateInDEV.useHostTransitionStatus = - useHostTransitionStatus; + { + if (instance.state === newProps) { + var componentName = getComponentNameFromType(ctor) || 'Component'; - InvalidNestedHooksDispatcherOnUpdateInDEV.useFormState = - function useFormState(action, initialState, permalink) { - currentHookNameInDev = "useFormState"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateActionState(action); - }; + if (!didWarnAboutDirectlyAssigningPropsToState.has(componentName)) { + didWarnAboutDirectlyAssigningPropsToState.add(componentName); - InvalidNestedHooksDispatcherOnUpdateInDEV.useActionState = - function useActionState(action, initialState, permalink) { - currentHookNameInDev = "useActionState"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateActionState(action); - }; + 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); } + } - if (enableAsyncActions) { - InvalidNestedHooksDispatcherOnUpdateInDEV.useOptimistic = - function useOptimistic(passthrough, reducer) { - currentHookNameInDev = "useOptimistic"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateOptimistic(passthrough, reducer); - }; - } + if (workInProgress.mode & StrictLegacyMode) { + ReactStrictModeWarnings.recordLegacyContextWarning(workInProgress, instance); + } - InvalidNestedHooksDispatcherOnRerenderInDEV = { - readContext: function (context) { - warnInvalidContextAccess(); - return readContext(context); - }, - use: function (usable) { - warnInvalidHookAccess(); - return use(usable); - }, - 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 = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; + ReactStrictModeWarnings.recordUnsafeLifecycleWarnings(workInProgress, instance); + } - try { - return updateMemo(create, deps); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useReducer: function (reducer, initialArg, init) { - currentHookNameInDev = "useReducer"; - warnInvalidHookAccess(); - updateHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; + instance.state = workInProgress.memoizedState; + var getDerivedStateFromProps = ctor.getDerivedStateFromProps; - try { - return rerenderReducer(reducer, initialArg, init); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useRef: function (initialValue) { - currentHookNameInDev = "useRef"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateRef(); - }, - useState: function (initialState) { - currentHookNameInDev = "useState"; - warnInvalidHookAccess(); - updateHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; + 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. - try { - return rerenderState(initialState); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useDebugValue: function (value, formatterFn) { - currentHookNameInDev = "useDebugValue"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateDebugValue(); - }, - useDeferredValue: function (value, initialValue) { - currentHookNameInDev = "useDeferredValue"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return rerenderDeferredValue(value, initialValue); - }, - useTransition: function () { - currentHookNameInDev = "useTransition"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return rerenderTransition(); - }, - useSyncExternalStore: function ( - subscribe, - getSnapshot, - getServerSnapshot - ) { - currentHookNameInDev = "useSyncExternalStore"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateSyncExternalStore(subscribe, getSnapshot); - }, - useId: function () { - currentHookNameInDev = "useId"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateId(); - } - }; - { - InvalidNestedHooksDispatcherOnRerenderInDEV.useCacheRefresh = - function useCacheRefresh() { - currentHookNameInDev = "useCacheRefresh"; - updateHookTypesDev(); - return updateRefresh(); - }; - } + 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. - { - InvalidNestedHooksDispatcherOnRerenderInDEV.useMemoCache = function ( - size - ) { - warnInvalidHookAccess(); - return useMemoCache(size); - }; - } + processUpdateQueue(workInProgress, newProps, instance, renderLanes); + suspendIfUpdateReadFromEntangledAsyncAction(); + instance.state = workInProgress.memoizedState; + } - if (enableAsyncActions) { - InvalidNestedHooksDispatcherOnRerenderInDEV.useHostTransitionStatus = - useHostTransitionStatus; + if (typeof instance.componentDidMount === 'function') { + workInProgress.flags |= Update | LayoutStatic; + } - InvalidNestedHooksDispatcherOnRerenderInDEV.useFormState = - function useFormState(action, initialState, permalink) { - currentHookNameInDev = "useFormState"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return rerenderActionState(action); - }; + if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { + workInProgress.flags |= MountLayoutDev; + } +} - InvalidNestedHooksDispatcherOnRerenderInDEV.useActionState = - function useActionState(action, initialState, permalink) { - currentHookNameInDev = "useActionState"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return rerenderActionState(action); - }; +function resumeMountClassInstance(workInProgress, ctor, newProps, renderLanes) { + var instance = workInProgress.stateNode; + var unresolvedOldProps = workInProgress.memoizedProps; + var oldProps = resolveClassComponentProps(ctor, unresolvedOldProps, workInProgress.type === workInProgress.elementType); + 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); + } + + var getDerivedStateFromProps = ctor.getDerivedStateFromProps; + var hasNewLifecycles = typeof getDerivedStateFromProps === 'function' || typeof instance.getSnapshotBeforeUpdate === 'function'; // When comparing whether props changed, we should compare using the + // unresolved props object that is stored on the fiber, rather than the + // one that gets assigned to the instance, because that object may have been + // cloned to resolve default props and/or remove `ref`. + + var unresolvedNewProps = workInProgress.pendingProps; + var didReceiveNewProps = unresolvedNewProps !== unresolvedOldProps; // 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 (didReceiveNewProps || oldContext !== nextContext) { + callComponentWillReceiveProps(workInProgress, instance, newProps, nextContext); + } + } + + resetHasForceUpdateBeforeProcessing(); + var oldState = workInProgress.memoizedState; + var newState = instance.state = oldState; + processUpdateQueue(workInProgress, newProps, instance, renderLanes); + suspendIfUpdateReadFromEntangledAsyncAction(); + newState = workInProgress.memoizedState; + + if (!didReceiveNewProps && 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') { + workInProgress.flags |= Update | LayoutStatic; + } + + if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { + workInProgress.flags |= MountLayoutDev; + } + + return false; + } + + if (typeof getDerivedStateFromProps === 'function') { + applyDerivedStateFromProps(workInProgress, ctor, getDerivedStateFromProps, newProps); + newState = workInProgress.memoizedState; + } + + 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 (enableAsyncActions) { - InvalidNestedHooksDispatcherOnRerenderInDEV.useOptimistic = - function useOptimistic(passthrough, reducer) { - currentHookNameInDev = "useOptimistic"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return rerenderOptimistic(passthrough, reducer); - }; + if (typeof instance.UNSAFE_componentWillMount === 'function') { + instance.UNSAFE_componentWillMount(); } } - 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; + if (typeof instance.componentDidMount === 'function') { + workInProgress.flags |= Update | LayoutStatic; + } - function isCurrentUpdateNested() { - return currentUpdateIsNested; + if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { + workInProgress.flags |= MountLayoutDev; + } + } 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') { + workInProgress.flags |= Update | LayoutStatic; } - function markNestedUpdateScheduled() { - { - nestedUpdateScheduled = true; - } + if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { + workInProgress.flags |= MountLayoutDev; + } // 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 = resolveClassComponentProps(ctor, unresolvedOldProps, workInProgress.type === workInProgress.elementType); + 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); } + } - function resetNestedUpdateFlag() { - { - currentUpdateIsNested = false; - nestedUpdateScheduled = false; + resetHasForceUpdateBeforeProcessing(); + var oldState = workInProgress.memoizedState; + var newState = instance.state = oldState; + processUpdateQueue(workInProgress, newProps, instance, renderLanes); + suspendIfUpdateReadFromEntangledAsyncAction(); + 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; } } - function syncNestedUpdateFlag() { - { - currentUpdateIsNested = nestedUpdateScheduled; - nestedUpdateScheduled = false; + if (typeof instance.getSnapshotBeforeUpdate === 'function') { + if (unresolvedOldProps !== current.memoizedProps || oldState !== current.memoizedState) { + workInProgress.flags |= Snapshot; } } - function getCommitTime() { - return commitTime; - } + return false; + } - function recordCommitTime() { - commitTime = now(); - } + if (typeof getDerivedStateFromProps === 'function') { + applyDerivedStateFromProps(workInProgress, ctor, getDerivedStateFromProps, newProps); + newState = workInProgress.memoizedState; + } - function startProfilerTimer(fiber) { - profilerStartTime = now(); + 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 (fiber.actualStartTime < 0) { - fiber.actualStartTime = now(); + 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); } - } - function stopProfilerTimerIfRunning(fiber) { - profilerStartTime = -1; + if (typeof instance.UNSAFE_componentWillUpdate === 'function') { + instance.UNSAFE_componentWillUpdate(newProps, newState, nextContext); + } } - function stopProfilerTimerIfRunningAndRecordDelta(fiber, overrideBaseTime) { - if (profilerStartTime >= 0) { - var elapsedTime = now() - profilerStartTime; - fiber.actualDuration += elapsedTime; - - if (overrideBaseTime) { - fiber.selfBaseDuration = elapsedTime; - } + if (typeof instance.componentDidUpdate === 'function') { + workInProgress.flags |= Update; + } - profilerStartTime = -1; + 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 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) + 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. - var parentFiber = fiber.return; - while (parentFiber !== null) { - switch (parentFiber.tag) { - case HostRoot: - var root = parentFiber.stateNode; - root.effectDuration += elapsedTime; - return; + workInProgress.memoizedProps = newProps; + workInProgress.memoizedState = newState; + } // Update the existing instance's state, props, and context pointers even + // if shouldComponentUpdate returns false. - case Profiler: - var parentStateNode = parentFiber.stateNode; - parentStateNode.effectDuration += elapsedTime; - return; - } - parentFiber = parentFiber.return; - } - } - } + instance.props = newProps; + instance.state = newState; + instance.context = nextContext; + return shouldUpdate; +} - 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) +function resolveClassComponentProps(Component, baseProps, // Only resolve default props if this is a lazy component. Otherwise, they +// would have already been resolved by the JSX runtime. +// TODO: We're going to remove default prop resolution from the JSX runtime +// and keep it only for class components. As part of that change, we should +// remove this extra check. +alreadyResolvedDefaultProps) { + var newProps = baseProps; - var parentFiber = fiber.return; - while (parentFiber !== null) { - switch (parentFiber.tag) { - case HostRoot: - var root = parentFiber.stateNode; + var defaultProps = Component.defaultProps; - if (root !== null) { - root.passiveEffectDuration += elapsedTime; - } + if (defaultProps && ( // If disableDefaultPropsExceptForClasses is true, we always resolve + // default props here in the reconciler, rather than in the JSX runtime. + disableDefaultPropsExceptForClasses || !alreadyResolvedDefaultProps)) { + // We may have already copied the props object above to remove ref. If so, + // we can modify that. Otherwise, copy the props object with Object.assign. + if (newProps === baseProps) { + newProps = assign({}, newProps); + } // Taken from old JSX runtime, where this used to live. - return; - case Profiler: - var parentStateNode = parentFiber.stateNode; + for (var _propName in defaultProps) { + if (newProps[_propName] === undefined) { + newProps[_propName] = defaultProps[_propName]; + } + } + } - 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; - } + return newProps; +} - return; - } +function resolveDefaultPropsOnNonClassComponent(Component, baseProps) { + if (disableDefaultPropsExceptForClasses) { + // Support for defaultProps is removed in React 19 for all types + // except classes. + return baseProps; + } - parentFiber = parentFiber.return; - } + if (Component && Component.defaultProps) { + // Resolve default props. Taken from ReactElement + var props = assign({}, baseProps); + var defaultProps = Component.defaultProps; + + for (var propName in defaultProps) { + if (props[propName] === undefined) { + props[propName] = defaultProps[propName]; } } - function startLayoutEffectTimer() { - layoutEffectStartTime = now(); - } + return props; + } + + return baseProps; +} - function startPassiveEffectTimer() { - passiveEffectStartTime = now(); +var reportGlobalError = typeof reportError === 'function' ? // In modern browsers, reportError will dispatch an error event, +// emulating an uncaught JavaScript error. +reportError : function (error) { + if (typeof window === 'object' && typeof window.ErrorEvent === 'function') { + // Browser Polyfill + var message = typeof error === 'object' && error !== null && typeof error.message === 'string' ? // eslint-disable-next-line react-internal/safe-string-coercion + String(error.message) : // eslint-disable-next-line react-internal/safe-string-coercion + String(error); + var event = new window.ErrorEvent('error', { + bubbles: true, + cancelable: true, + message: message, + error: error + }); + var shouldLog = window.dispatchEvent(event); + + if (!shouldLog) { + return; + } + } else if (typeof process === 'object' && // $FlowFixMe[method-unbinding] + typeof process.emit === 'function') { + // Node Polyfill + process.emit('uncaughtException', error); + return; + } // eslint-disable-next-line react-internal/no-production-logging + + + console['error'](error); +}; + +var componentName = null; +var errorBoundaryName = null; +function defaultOnUncaughtError(error, errorInfo) { + // Overriding this can silence these warnings e.g. for tests. + // See https://github.com/facebook/react/pull/13384 + // For uncaught root errors we report them as uncaught to the browser's + // onerror callback. This won't have component stacks and the error addendum. + // So we add those into a separate console.warn. + reportGlobalError(error); + + { + var componentStack = errorInfo.componentStack != null ? errorInfo.componentStack : ''; + var componentNameMessage = componentName ? "An error occurred in the <" + componentName + "> component:" : 'An error occurred in one of your React components:'; + console['warn']('%s\n%s\n\n%s', componentNameMessage, componentStack || '', 'Consider adding an error boundary to your tree to customize error handling behavior.\n' + 'Visit https://react.dev/link/error-boundaries to learn more about error boundaries.'); + } +} +function defaultOnCaughtError(error, errorInfo) { + // Overriding this can silence these warnings e.g. for tests. + // See https://github.com/facebook/react/pull/13384 + // Caught by error boundary + { + var componentStack = errorInfo.componentStack != null ? errorInfo.componentStack : ''; + var componentNameMessage = componentName ? "The above error occurred in the <" + componentName + "> component:" : 'The above error occurred in one of your React components:'; // In development, we provide our own message which includes the component stack + // in addition to the error. + // Don't transform to our wrapper + + console['error']('%o\n\n%s\n%s\n\n%s', error, componentNameMessage, componentStack, "React will try to recreate this component tree from scratch " + ("using the error boundary you provided, " + (errorBoundaryName || 'Anonymous') + ".")); + } +} +function defaultOnRecoverableError(error, errorInfo) { + reportGlobalError(error); +} +function logUncaughtError(root, errorInfo) { + try { + if (true) { + componentName = errorInfo.source ? getComponentNameFromFiber(errorInfo.source) : null; + errorBoundaryName = null; } - 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; + var error = errorInfo.value; - while (child) { - // $FlowFixMe[unsafe-addition] addition with possible null/undefined value - fiber.actualDuration += child.actualDuration; - child = child.sibling; - } + if (true && ReactSharedInternals.actQueue !== null) { + // For uncaught errors inside act, we track them on the act and then + // rethrow them into the test. + ReactSharedInternals.thrownErrors.push(error); + return; } - var fakeInternalInstance = {}; - var didWarnAboutStateAssignmentForComponent; - var didWarnAboutUninitializedState; - var didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate; - var didWarnAboutLegacyLifecyclesAndDerivedState; - var didWarnAboutUndefinedDerivedState; - var didWarnAboutDirectlyAssigningPropsToState; - var didWarnAboutContextTypeAndContextTypes; - var didWarnAboutInvalidateContextType; - var didWarnOnInvalidCallback; + var onUncaughtError = root.onUncaughtError; + onUncaughtError(error, { + componentStack: errorInfo.stack + }); + } 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 logCaughtError(root, boundary, errorInfo) { + try { + if (true) { + componentName = errorInfo.source ? getComponentNameFromFiber(errorInfo.source) : null; + errorBoundaryName = getComponentNameFromFiber(boundary); + } + + var error = errorInfo.value; + var onCaughtError = root.onCaughtError; + onCaughtError(error, { + componentStack: errorInfo.stack, + errorBoundary: boundary.tag === ClassComponent ? boundary.stateNode // This should always be the case as long as we only have class boundaries + : null + }); + } 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; + }); + } +} - { - 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 createRootErrorUpdate(root, errorInfo, lane) { + var update = createUpdate(lane); // Unmount the root by rendering null. - function warnOnInvalidCallback(callback) { - { - if (callback === null || typeof callback === "function") { - return; - } // eslint-disable-next-line react-internal/safe-string-coercion + update.tag = CaptureUpdate; // Caution: React DevTools currently depends on this property + // being called "element". - var key = String(callback); + update.payload = { + element: null + }; - if (!didWarnOnInvalidCallback.has(key)) { - didWarnOnInvalidCallback.add(key); + update.callback = function () { + logUncaughtError(root, errorInfo); + }; - error( - "Expected the last optional `callback` argument to be a " + - "function. Instead received: %s.", - callback - ); - } + return update; +} + +function createClassErrorUpdate(lane) { + var update = createUpdate(lane); + update.tag = CaptureUpdate; + return update; +} + +function initializeClassErrorUpdate(update, root, fiber, errorInfo) { + var getDerivedStateFromError = fiber.type.getDerivedStateFromError; + + if (typeof getDerivedStateFromError === 'function') { + var error$1 = errorInfo.value; + + update.payload = function () { + return getDerivedStateFromError(error$1); + }; + + update.callback = function () { + { + markFailedErrorBoundaryForHotReloading(fiber); } - } - function warnOnUndefinedDerivedState(type, partialState) { + logCaughtError(root, fiber, errorInfo); + }; + } + + var inst = fiber.stateNode; + + if (inst !== null && typeof inst.componentDidCatch === 'function') { + // $FlowFixMe[missing-this-annot] + update.callback = function callback() { { - if (partialState === undefined) { - var componentName = getComponentNameFromType(type) || "Component"; + markFailedErrorBoundaryForHotReloading(fiber); + } - if (!didWarnAboutUndefinedDerivedState.has(componentName)) { - didWarnAboutUndefinedDerivedState.add(componentName); + logCaughtError(root, fiber, errorInfo); - error( - "%s.getDerivedStateFromProps(): A valid state object (or null) must be returned. " + - "You have returned undefined.", - componentName - ); - } - } + 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 applyDerivedStateFromProps( - workInProgress, - ctor, - getDerivedStateFromProps, - nextProps - ) { - var prevState = workInProgress.memoizedState; - var partialState = getDerivedStateFromProps(nextProps, prevState); + var error$1 = errorInfo.value; + var stack = errorInfo.stack; + this.componentDidCatch(error$1, { + componentStack: stack !== null ? stack : '' + }); { - 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 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'); } } + } + }; + } +} - warnOnUndefinedDerivedState(ctor, partialState); - } // Merge the partial state and the previous state. +function resetSuspendedComponent(sourceFiber, rootRenderLanes) { + // A legacy mode Suspense quirk, only relevant to hook components. - 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 tag = sourceFiber.tag; + + 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 { + sourceFiber.updateQueue = null; + sourceFiber.memoizedState = null; } + } +} - 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 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; + + 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); + } + } else if (sourceFiber.tag === FunctionComponent) { + var _currentSourceFiber = sourceFiber.alternate; + + if (_currentSourceFiber === null) { + // This is a new mount. Change the tag so it's not mistaken for a + // completed function component. + sourceFiber.tag = IncompleteFunctionComponent; + } + } // The source fiber did not complete. Mark it with Sync priority to + // indicate that it still has pending work. + + + sourceFiber.lanes = mergeLanes(sourceFiber.lanes, SyncLane); + } + + 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. + + + suspenseBoundary.flags |= ShouldCapture; // TODO: I think we can remove this, since we now use `DidCapture` in + // the begin phase to prevent an early bailout. + + suspenseBoundary.lanes = rootRenderLanes; + return suspenseBoundary; +} - if (callback !== undefined && callback !== null) { - { - warnOnInvalidCallback(callback); - } +function throwException(root, returnFiber, sourceFiber, value, rootRenderLanes) { + // The source fiber did not complete. + sourceFiber.flags |= Incomplete; - update.callback = callback; - } + { + if (isDevToolsPresent) { + // If we have pending work still, restore the original updaters + restorePendingUpdaters(root, rootRenderLanes); + } + } - var root = enqueueUpdate(fiber, update, lane); + if (value !== null && typeof value === 'object') { - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, lane); - entangleTransitions(root, fiber, lane); - } + if (typeof value.then === 'function') { + // This is a wakeable. The component suspended. + var wakeable = value; + resetSuspendedComponent(sourceFiber); - { - 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; - if (callback !== undefined && callback !== null) { - { - warnOnInvalidCallback(callback); - } + 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; + + if (current === null) { + renderDidSuspend(); + } + } + } + + 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. + + var isSuspenseyResource = wakeable === noopSuspenseyCommitThenable; + + if (isSuspenseyResource) { + suspenseBoundary.flags |= ScheduleRetry; + } else { + var retryQueue = suspenseBoundary.updateQueue; + + if (retryQueue === null) { + suspenseBoundary.updateQueue = new Set([wakeable]); + } else { + retryQueue.add(wakeable); + } // We only attach ping listeners in concurrent mode. Legacy + // Suspense always commits fallbacks synchronously, so there are + // no pings. + - update.callback = callback; - } + if (suspenseBoundary.mode & ConcurrentMode) { + attachPingListener(root, wakeable, rootRenderLanes); + } + } - var root = enqueueUpdate(fiber, update, lane); + return false; + } - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, lane); - entangleTransitions(root, fiber, lane); - } + case OffscreenComponent: + { + if (suspenseBoundary.mode & ConcurrentMode) { + suspenseBoundary.flags |= ShouldCapture; - { - 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 _isSuspenseyResource = wakeable === noopSuspenseyCommitThenable; - if (callback !== undefined && callback !== null) { - { - warnOnInvalidCallback(callback); - } + if (_isSuspenseyResource) { + suspenseBoundary.flags |= ScheduleRetry; + } else { + var offscreenQueue = suspenseBoundary.updateQueue; + + if (offscreenQueue === null) { + var newOffscreenQueue = { + transitions: null, + markerInstances: null, + retryQueue: new Set([wakeable]) + }; + suspenseBoundary.updateQueue = newOffscreenQueue; + } else { + var _retryQueue = offscreenQueue.retryQueue; - update.callback = callback; - } + if (_retryQueue === null) { + offscreenQueue.retryQueue = new Set([wakeable]); + } else { + _retryQueue.add(wakeable); + } + } - var root = enqueueUpdate(fiber, update, lane); + attachPingListener(root, wakeable, rootRenderLanes); + } - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, lane); - entangleTransitions(root, fiber, lane); + return false; + } + } } - { - markForceUpdateScheduled(fiber, lane); + throw new Error("Unexpected Suspense handler tag (" + suspenseBoundary.tag + "). This " + 'is a bug in React.'); + } 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 false; + } 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; } } - }; - - 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 (workInProgress.mode & StrictLegacyMode) { - setIsStrictModeForDevtools(true); + } + } // This is a regular error, not a Suspense wakeable. - try { - // Invoke the function an extra time to help detect side-effects. - shouldUpdate = instance.shouldComponentUpdate( - newProps, - newState, - nextContext - ); - } finally { - setIsStrictModeForDevtools(false); - } - } + var wrapperError = new Error('There was an error during concurrent rendering but React was able to recover by ' + 'instead synchronously rendering the entire root.', { + cause: value + }); + queueConcurrentError(createCapturedValueAtFiber(wrapperError, sourceFiber)); + renderDidError(); // 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 (shouldUpdate === undefined) { - error( - "%s.shouldComponentUpdate(): Returned undefined instead of a " + - "boolean value. Make sure to return true or false.", - getComponentNameFromType(ctor) || "Component" - ); - } - } + if (returnFiber === null) { + // There's no return fiber, which means the root errored. This should never + // happen. Return `true` to trigger a fatal error (panic). + return true; + } - return shouldUpdate; - } + var errorInfo = createCapturedValueAtFiber(value, sourceFiber); + var workInProgress = returnFiber; - if (ctor.prototype && ctor.prototype.isPureReactComponent) { - return ( - !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState) - ); - } + do { + switch (workInProgress.tag) { + case HostRoot: + { + workInProgress.flags |= ShouldCapture; - return true; - } + var _lane = pickArbitraryLane(rootRenderLanes); - function checkClassInstance(workInProgress, ctor, newProps) { - var instance = workInProgress.stateNode; + workInProgress.lanes = mergeLanes(workInProgress.lanes, _lane); - { - var name = getComponentNameFromType(ctor) || "Component"; - var renderPresent = instance.render; - - if (!renderPresent) { - if (ctor.prototype && typeof ctor.prototype.render === "function") { - error( - "No `render` method found on the %s " + - "instance: did you accidentally return an object from the constructor?", - name - ); - } else { - error( - "No `render` method found on the %s " + - "instance: you may have forgotten to define `render`.", - name - ); - } - } + var _update = createRootErrorUpdate(workInProgress.stateNode, errorInfo, _lane); - 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 - ); + enqueueCapturedUpdate(workInProgress, _update); + return false; } - 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 - ); - } + case ClassComponent: + // Capture and retry + var ctor = workInProgress.type; + var instance = workInProgress.stateNode; - if (instance.propTypes) { - error( - "propTypes was defined as an instance property on %s. Use a static " + - "property to define propTypes instead.", - name - ); - } + if ((workInProgress.flags & DidCapture) === NoFlags$1 && (typeof ctor.getDerivedStateFromError === 'function' || instance !== null && typeof instance.componentDidCatch === 'function' && !isAlreadyFailedLegacyErrorBoundary(instance))) { + workInProgress.flags |= ShouldCapture; - if (instance.contextType) { - error( - "contextType was defined as an instance property on %s. Use a static " + - "property to define contextType instead.", - name - ); - } + var _lane2 = pickArbitraryLane(rootRenderLanes); - { - if (instance.contextTypes) { - error( - "contextTypes was defined as an instance property on %s. Use a static " + - "property to define contextTypes instead.", - name - ); - } + workInProgress.lanes = mergeLanes(workInProgress.lanes, _lane2); // Schedule the error boundary to re-render using updated state - if ( - ctor.contextType && - ctor.contextTypes && - !didWarnAboutContextTypeAndContextTypes.has(ctor) - ) { - didWarnAboutContextTypeAndContextTypes.add(ctor); - - error( - "%s declares both contextTypes and contextType static properties. " + - "The legacy contextTypes property will be ignored.", - name - ); - } - } + var _update2 = createClassErrorUpdate(_lane2); - 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 - ); - } - - 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" - ); + initializeClassErrorUpdate(_update2, root, workInProgress, errorInfo); + enqueueCapturedUpdate(workInProgress, _update2); + return false; } - 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 - ); - } + break; + } // $FlowFixMe[incompatible-type] we bail out when we get a null - if (typeof instance.componentWillRecieveProps === "function") { - error( - "%s has a method called " + - "componentWillRecieveProps(). Did you mean componentWillReceiveProps()?", - name - ); - } - if (typeof instance.UNSAFE_componentWillRecieveProps === "function") { - error( - "%s has a method called " + - "UNSAFE_componentWillRecieveProps(). Did you mean UNSAFE_componentWillReceiveProps()?", - name - ); - } + workInProgress = workInProgress.return; + } while (workInProgress !== null); - var hasMutatedProps = instance.props !== newProps; + return false; +} - if (instance.props !== undefined && hasMutatedProps) { - error( - "When calling super() in `%s`, make sure to pass " + - "up the same props that your component's constructor was passed.", - name - ); - } +// into a dehydrated boundary. + +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 didWarnAboutContextTypeOnFunctionComponent; +var didWarnAboutGetDerivedStateOnFunctionComponent; +var didWarnAboutFunctionRefs; +var didWarnAboutReassigningProps; +var didWarnAboutRevealOrder; +var didWarnAboutTailOptions; +var didWarnAboutDefaultPropsOnFunctionComponent; + +{ + didWarnAboutBadClass = {}; + didWarnAboutContextTypeOnFunctionComponent = {}; + didWarnAboutGetDerivedStateOnFunctionComponent = {}; + didWarnAboutFunctionRefs = {}; + didWarnAboutReassigningProps = false; + didWarnAboutRevealOrder = {}; + didWarnAboutTailOptions = {}; + didWarnAboutDefaultPropsOnFunctionComponent = {}; +} - 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 - ); - } +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); + } +} - if ( - typeof instance.getSnapshotBeforeUpdate === "function" && - typeof instance.componentDidUpdate !== "function" && - !didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.has(ctor) - ) { - didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.add(ctor); +function forceUnmountCurrentAndReconcile(current, workInProgress, nextChildren, renderLanes) { + // 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); +} - error( - "%s: getSnapshotBeforeUpdate() should be used with componentDidUpdate(). " + - "This component defines getSnapshotBeforeUpdate() only.", - getComponentNameFromType(ctor) - ); - } +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. + var render = Component.render; + var ref = workInProgress.ref; + var propsWithoutRef; - 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 - ); - } + { + propsWithoutRef = nextProps; + } // The rest is a fork of updateFunctionComponent - 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 (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 nextChildren; + prepareToReadContext(workInProgress, renderLanes); - var state = instance.state; + { + markComponentRenderStarted(workInProgress); + } - if (state && (typeof state !== "object" || isArray(state))) { - error("%s.state: must be set to an object or null", name); - } + { + ReactSharedInternals.owner = workInProgress; + setIsRendering(true); + nextChildren = renderWithHooks(current, workInProgress, render, propsWithoutRef, ref, renderLanes); + setIsRendering(false); + } - if ( - typeof instance.getChildContext === "function" && - typeof ctor.childContextTypes !== "object" - ) { - error( - "%s.getChildContext(): childContextTypes must be defined in order to " + - "use getChildContext().", - name - ); - } - } - } + { + markComponentRenderStopped(); + } - function constructClassInstance(workInProgress, ctor, props) { - var isLegacyContextConsumer = false; - var unmaskedContext = emptyContextObject; - var context = emptyContextObject; - var contextType = ctor.contextType; + if (current !== null && !didReceiveUpdate) { + bailoutHooks(current, workInProgress, renderLanes); + return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); + } - { - if ("contextType" in ctor) { - var isValid = // Allow null for conditional declaration - contextType === null || - (contextType !== undefined && - contextType.$$typeof === REACT_CONTEXT_TYPE); - - if (!isValid && !didWarnAboutInvalidateContextType.has(ctor)) { - didWarnAboutInvalidateContextType.add(ctor); - var addendum = ""; - - 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_CONSUMER_TYPE) { - addendum = - " Did you accidentally pass the Context.Consumer instead?"; - } else { - addendum = - " However, it is set to an object with keys {" + - Object.keys(contextType).join(", ") + - "}."; - } - error( - "%s defines an invalid contextType. " + - "contextType should point to the Context object returned by React.createContext().%s", - getComponentNameFromType(ctor) || "Component", - addendum - ); - } - } - } + workInProgress.flags |= PerformedWork; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} - 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; - } +function updateMemoComponent(current, workInProgress, Component, nextProps, renderLanes) { + if (current === null) { + var type = Component.type; - var instance = new ctor(props, context); // Instantiate twice to help detect side-effects. + if (isSimpleFunctionComponent(type) && Component.compare === null && ( // SimpleMemoComponent codepath doesn't resolve outer props either. + disableDefaultPropsExceptForClasses || Component.defaultProps === undefined)) { + var resolvedType = type; { - if (workInProgress.mode & StrictLegacyMode) { - setIsStrictModeForDevtools(true); - - try { - instance = new ctor(props, context); // eslint-disable-line no-new - } finally { - setIsStrictModeForDevtools(false); - } - } - } + 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. - var state = (workInProgress.memoizedState = - instance.state !== null && instance.state !== undefined - ? instance.state - : null); - instance.updater = classComponentUpdater; - workInProgress.stateNode = instance; // The instance needs access to the fiber so that it can schedule updates - set(instance, workInProgress); + workInProgress.tag = SimpleMemoComponent; + workInProgress.type = resolvedType; { - instance._reactInternalInstance = fakeInternalInstance; + validateFunctionComponentInDev(workInProgress, type); } - { - 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; - - if ( - typeof instance.componentWillMount === "function" && - instance.componentWillMount.__suppressDeprecationWarning !== true - ) { - foundWillMountName = "componentWillMount"; - } else if (typeof instance.UNSAFE_componentWillMount === "function") { - foundWillMountName = "UNSAFE_componentWillMount"; - } + return updateSimpleMemoComponent(current, workInProgress, resolvedType, nextProps, renderLanes); + } - if ( - typeof instance.componentWillReceiveProps === "function" && - instance.componentWillReceiveProps.__suppressDeprecationWarning !== - true - ) { - foundWillReceivePropsName = "componentWillReceiveProps"; - } else if ( - typeof instance.UNSAFE_componentWillReceiveProps === "function" - ) { - foundWillReceivePropsName = "UNSAFE_componentWillReceiveProps"; - } + if (!disableDefaultPropsExceptForClasses) { + { + if (Component.defaultProps !== undefined) { + var componentName = getComponentNameFromType(type) || 'Unknown'; - if ( - typeof instance.componentWillUpdate === "function" && - instance.componentWillUpdate.__suppressDeprecationWarning !== true - ) { - foundWillUpdateName = "componentWillUpdate"; - } else if ( - typeof instance.UNSAFE_componentWillUpdate === "function" - ) { - foundWillUpdateName = "UNSAFE_componentWillUpdate"; - } + 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 ( - foundWillMountName !== null || - foundWillReceivePropsName !== null || - foundWillUpdateName !== null - ) { - var _componentName = getComponentNameFromType(ctor) || "Component"; - - var newApiName = - typeof ctor.getDerivedStateFromProps === "function" - ? "getDerivedStateFromProps()" - : "getSnapshotBeforeUpdate()"; - - if ( - !didWarnAboutLegacyLifecyclesAndDerivedState.has(_componentName) - ) { - didWarnAboutLegacyLifecyclesAndDerivedState.add(_componentName); - - 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://react.dev/link/unsafe-component-lifecycles", - _componentName, - newApiName, - foundWillMountName !== null ? "\n " + foundWillMountName : "", - foundWillReceivePropsName !== null - ? "\n " + foundWillReceivePropsName - : "", - foundWillUpdateName !== null ? "\n " + foundWillUpdateName : "" - ); - } + didWarnAboutDefaultPropsOnFunctionComponent[componentName] = true; } } - } // Cache unmasked context so we can avoid recreating masked context unless necessary. - // ReactFiberContext usually updates this cache but can't for newly-created instances. - - if (isLegacyContextConsumer) { - cacheContext(workInProgress, unmaskedContext, context); } - - return instance; } - function callComponentWillMount(workInProgress, instance) { - var oldState = instance.state; + var child = createFiberFromTypeAndProps(Component.type, null, nextProps, workInProgress, workInProgress.mode, renderLanes); + child.ref = workInProgress.ref; + child.return = workInProgress; + workInProgress.child = child; + return child; + } - if (typeof instance.componentWillMount === "function") { - instance.componentWillMount(); - } + var currentChild = current.child; // This is always exactly one child - if (typeof instance.UNSAFE_componentWillMount === "function") { - instance.UNSAFE_componentWillMount(); - } + var hasScheduledUpdateOrContext = checkScheduledUpdateOrContext(current, 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" - ); - } + 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 - classComponentUpdater.enqueueReplaceState( - instance, - instance.state, - null - ); - } + 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. - function callComponentWillReceiveProps( - workInProgress, - instance, - newProps, - nextContext - ) { - var oldState = instance.state; - if (typeof instance.componentWillReceiveProps === "function") { - instance.componentWillReceiveProps(newProps, nextContext); - } + workInProgress.flags |= PerformedWork; + var newChild = createWorkInProgress(currentChild, nextProps); + newChild.ref = workInProgress.ref; + newChild.return = workInProgress; + workInProgress.child = newChild; + return newChild; +} - if (typeof instance.UNSAFE_componentWillReceiveProps === "function") { - instance.UNSAFE_componentWillReceiveProps(newProps, nextContext); +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 (current !== null) { + var prevProps = current.memoizedProps; + + 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. + + 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; } + } + } - if (instance.state !== oldState) { - { - var componentName = - getComponentNameFromFiber(workInProgress) || "Component"; - - 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. + return updateFunctionComponent(current, workInProgress, Component, nextProps, renderLanes); +} - function mountClassInstance(workInProgress, ctor, newProps, renderLanes) { - { - checkClassInstance(workInProgress, ctor, newProps); - } +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(current, workInProgress); - var instance = workInProgress.stateNode; - instance.props = newProps; - instance.state = workInProgress.memoizedState; - instance.refs = {}; - initializeUpdateQueue(workInProgress); - var contextType = ctor.contextType; + if (nextProps.mode === 'hidden' || enableLegacyHidden || nextIsDetached) { + // Rendering a hidden tree. + var didSuspend = (workInProgress.flags & DidCapture) !== NoFlags$1; - if (typeof contextType === "object" && contextType !== null) { - instance.context = readContext(contextType); - } else { - var unmaskedContext = getUnmaskedContext(workInProgress, ctor, true); - instance.context = getMaskedContext(workInProgress, unmaskedContext); - } + 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; - { - if (instance.state === newProps) { - var componentName = getComponentNameFromType(ctor) || "Component"; + 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 (!didWarnAboutDirectlyAssigningPropsToState.has(componentName)) { - didWarnAboutDirectlyAssigningPropsToState.add(componentName); + var currentChildLanes = NoLanes; - 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 - ); - } + while (currentChild !== null) { + currentChildLanes = mergeLanes(mergeLanes(currentChildLanes, currentChild.lanes), currentChild.childLanes); + currentChild = currentChild.sibling; } - if (workInProgress.mode & StrictLegacyMode) { - ReactStrictModeWarnings.recordLegacyContextWarning( - workInProgress, - instance - ); - } - - 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); - suspendIfUpdateReadFromEntangledAsyncAction(); - instance.state = workInProgress.memoizedState; - } - - if (typeof instance.componentDidMount === "function") { - workInProgress.flags |= Update | LayoutStatic; - } - - if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { - workInProgress.flags |= MountLayoutDev; - } - } - - function resumeMountClassInstance( - workInProgress, - ctor, - newProps, - renderLanes - ) { - var instance = workInProgress.stateNode; - var unresolvedOldProps = workInProgress.memoizedProps; - var oldProps = resolveClassComponentProps( - ctor, - unresolvedOldProps, - workInProgress.type === workInProgress.elementType - ); - instance.props = oldProps; - var oldContext = instance.context; - var contextType = ctor.contextType; - var nextContext = emptyContextObject; - - if (typeof contextType === "object" && contextType !== null) { - nextContext = readContext(contextType); + var lanesWeJustAttempted = nextBaseLanes; + var remainingChildLanes = removeLanes(currentChildLanes, lanesWeJustAttempted); + workInProgress.childLanes = remainingChildLanes; } else { - var nextLegacyUnmaskedContext = getUnmaskedContext( - workInProgress, - ctor, - true - ); - nextContext = getMaskedContext( - workInProgress, - nextLegacyUnmaskedContext - ); - } - - var getDerivedStateFromProps = ctor.getDerivedStateFromProps; - var hasNewLifecycles = - typeof getDerivedStateFromProps === "function" || - typeof instance.getSnapshotBeforeUpdate === "function"; // When comparing whether props changed, we should compare using the - // unresolved props object that is stored on the fiber, rather than the - // one that gets assigned to the instance, because that object may have been - // cloned to resolve default props and/or remove `ref`. - - var unresolvedNewProps = workInProgress.pendingProps; - var didReceiveNewProps = unresolvedNewProps !== unresolvedOldProps; // 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 (didReceiveNewProps || oldContext !== nextContext) { - callComponentWillReceiveProps( - workInProgress, - instance, - newProps, - nextContext - ); - } - } - - resetHasForceUpdateBeforeProcessing(); - var oldState = workInProgress.memoizedState; - var newState = (instance.state = oldState); - processUpdateQueue(workInProgress, newProps, instance, renderLanes); - suspendIfUpdateReadFromEntangledAsyncAction(); - newState = workInProgress.memoizedState; + workInProgress.childLanes = NoLanes; + workInProgress.child = null; + } - if ( - !didReceiveNewProps && - 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") { - workInProgress.flags |= Update | LayoutStatic; - } + return deferHiddenOffscreenComponent(current, workInProgress, nextBaseLanes); + } - if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { - workInProgress.flags |= MountLayoutDev; - } + 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; - return false; + { + // push the cache pool even though we're going to bail out + // because otherwise there'd be a context mismatch + if (current !== null) { + pushTransition(workInProgress, null); + } } - if (typeof getDerivedStateFromProps === "function") { - applyDerivedStateFromProps( - workInProgress, - ctor, - getDerivedStateFromProps, - newProps - ); - newState = workInProgress.memoizedState; - } - - var shouldUpdate = - checkHasForceUpdateAfterProcessing() || - checkShouldComponentUpdate( - workInProgress, - ctor, - oldProps, - newProps, - oldState, - newState, - nextContext - ); + 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 _nextBaseLanes = prevState !== null ? mergeLanes(prevState.baseLanes, renderLanes) : renderLanes; + + 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 (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 (current !== null) { + // If the render that spawned this one accessed the cache pool, resume + // using the same cache. Unless the parent changed, since that means + // there was a refresh. + var prevCachePool = prevState !== null ? prevState.cachePool : null; // TODO: Consider if and how Offscreen pre-rendering should + // be attributed to the transition that spawned it - if (typeof instance.UNSAFE_componentWillMount === "function") { - instance.UNSAFE_componentWillMount(); - } - } + pushTransition(workInProgress, prevCachePool); + } // Push the lanes that were skipped when we bailed out. - if (typeof instance.componentDidMount === "function") { - workInProgress.flags |= Update | LayoutStatic; - } - if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { - workInProgress.flags |= MountLayoutDev; - } - } 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") { - workInProgress.flags |= Update | LayoutStatic; - } - - if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { - workInProgress.flags |= MountLayoutDev; - } // 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 = resolveClassComponentProps( - ctor, - unresolvedOldProps, - workInProgress.type === workInProgress.elementType - ); - 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); + if (prevState !== null) { + pushHiddenContext(workInProgress, prevState); } 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); - suspendIfUpdateReadFromEntangledAsyncAction(); - 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; - } - } - - return false; + reuseHiddenContextOnStack(workInProgress); } - if (typeof getDerivedStateFromProps === "function") { - applyDerivedStateFromProps( - workInProgress, - ctor, - getDerivedStateFromProps, - newProps - ); - newState = workInProgress.memoizedState; - } - - 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; + pushOffscreenSuspenseHandler(workInProgress); + } + } else { + // Rendering a visible tree. + if (prevState !== null) { + // We're going from hidden -> visible. + var _prevCachePool = 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_componentWillUpdate === "function" || - typeof instance.componentWillUpdate === "function") - ) { - if (typeof instance.componentWillUpdate === "function") { - instance.componentWillUpdate(newProps, newState, nextContext); - } + { + // If the render that spawned this one accessed the cache pool, resume + // using the same cache. Unless the parent changed, since that means + // there was a refresh. + _prevCachePool = prevState.cachePool; + } - if (typeof instance.UNSAFE_componentWillUpdate === "function") { - instance.UNSAFE_componentWillUpdate( - newProps, - newState, - nextContext - ); - } - } + pushTransition(workInProgress, _prevCachePool); // Push the lanes that were skipped when we bailed out. - if (typeof instance.componentDidUpdate === "function") { - workInProgress.flags |= Update; - } + pushHiddenContext(workInProgress, prevState); + reuseSuspenseHandlerOnStack(workInProgress); // Since we're not hidden anymore, reset the state - 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; - } + workInProgress.memoizedState = null; + } else { + // We weren't previously hidden, and we still aren't, so there's nothing + // special to do. Need to push to the stack regardless, though, to avoid + // a push/pop misalignment. + { + // If the render that spawned this one accessed the cache pool, resume + // using the same cache. Unless the parent changed, since that means + // there was a refresh. + if (current !== null) { + pushTransition(workInProgress, null); } + } // We're about to bail out, but we need to push this to the stack anyway + // to avoid a push/pop misalignment. - 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. - - 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 resolveClassComponentProps( - Component, - baseProps, // Only resolve default props if this is a lazy component. Otherwise, they - // would have already been resolved by the JSX runtime. - // TODO: We're going to remove default prop resolution from the JSX runtime - // and keep it only for class components. As part of that change, we should - // remove this extra check. - alreadyResolvedDefaultProps - ) { - var newProps = baseProps; - - var defaultProps = Component.defaultProps; - - if ( - defaultProps && // If disableDefaultPropsExceptForClasses is true, we always resolve - // default props here in the reconciler, rather than in the JSX runtime. - (disableDefaultPropsExceptForClasses || !alreadyResolvedDefaultProps) - ) { - // We may have already copied the props object above to remove ref. If so, - // we can modify that. Otherwise, copy the props object with Object.assign. - if (newProps === baseProps) { - newProps = assign({}, newProps); - } // Taken from old JSX runtime, where this used to live. - - for (var _propName in defaultProps) { - if (newProps[_propName] === undefined) { - newProps[_propName] = defaultProps[_propName]; - } - } - } - return newProps; + reuseHiddenContextOnStack(workInProgress); + reuseSuspenseHandlerOnStack(workInProgress); } + } - function resolveDefaultPropsOnNonClassComponent(Component, baseProps) { - if (disableDefaultPropsExceptForClasses) { - // Support for defaultProps is removed in React 19 for all types - // except classes. - return baseProps; - } + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} - if (Component && Component.defaultProps) { - // Resolve default props. Taken from ReactElement - var props = assign({}, baseProps); - var defaultProps = Component.defaultProps; +function deferHiddenOffscreenComponent(current, workInProgress, nextBaseLanes, renderLanes) { + var nextState = { + baseLanes: nextBaseLanes, + // Save the cache pool so we can resume later. + cachePool: getOffscreenDeferredCache() + }; + workInProgress.memoizedState = nextState; - for (var propName in defaultProps) { - if (props[propName] === undefined) { - props[propName] = defaultProps[propName]; - } - } + { + // push the cache pool even though we're going to bail out + // because otherwise there'd be a context mismatch + if (current !== null) { + pushTransition(workInProgress, null); + } + } // We're about to bail out, but we need to push this to the stack anyway + // to avoid a push/pop misalignment. - return props; - } - - return baseProps; - } - - var reportGlobalError = - typeof reportError === "function" // In modern browsers, reportError will dispatch an error event, - ? // emulating an uncaught JavaScript error. - reportError - : function (error) { - if ( - typeof window === "object" && - typeof window.ErrorEvent === "function" - ) { - // Browser Polyfill - var message = - typeof error === "object" && - error !== null && - typeof error.message === "string" // eslint-disable-next-line react-internal/safe-string-coercion - ? String(error.message) // eslint-disable-next-line react-internal/safe-string-coercion - : String(error); - var event = new window.ErrorEvent("error", { - bubbles: true, - cancelable: true, - message: message, - error: error - }); - var shouldLog = window.dispatchEvent(event); - - if (!shouldLog) { - return; - } - } else if ( - typeof process === "object" && // $FlowFixMe[method-unbinding] - typeof process.emit === "function" - ) { - // Node Polyfill - process.emit("uncaughtException", error); - return; - } // eslint-disable-next-line react-internal/no-production-logging - - console["error"](error); - }; - var componentName = null; - var errorBoundaryName = null; - function defaultOnUncaughtError(error, errorInfo) { - // Overriding this can silence these warnings e.g. for tests. - // See https://github.com/facebook/react/pull/13384 - // For uncaught root errors we report them as uncaught to the browser's - // onerror callback. This won't have component stacks and the error addendum. - // So we add those into a separate console.warn. - reportGlobalError(error); + reuseHiddenContextOnStack(workInProgress); + pushOffscreenSuspenseHandler(workInProgress); - { - var componentStack = - errorInfo.componentStack != null ? errorInfo.componentStack : ""; - var componentNameMessage = componentName - ? "An error occurred in the <" + componentName + "> component:" - : "An error occurred in one of your React components:"; - console["warn"]( - "%s\n%s\n\n%s", - componentNameMessage, - componentStack || "", - "Consider adding an error boundary to your tree to customize error handling behavior.\n" + - "Visit https://react.dev/link/error-boundaries to learn more about error boundaries." - ); - } - } - function defaultOnCaughtError(error, errorInfo) { - // Overriding this can silence these warnings e.g. for tests. - // See https://github.com/facebook/react/pull/13384 - // Caught by error boundary - { - var componentStack = - errorInfo.componentStack != null ? errorInfo.componentStack : ""; - var componentNameMessage = componentName - ? "The above error occurred in the <" + componentName + "> component:" - : "The above error occurred in one of your React components:"; // In development, we provide our own message which includes the component stack - // in addition to the error. - // Don't transform to our wrapper - - console["error"]( - "%o\n\n%s\n%s\n\n%s", - error, - componentNameMessage, - componentStack, - "React will try to recreate this component tree from scratch " + - ("using the error boundary you provided, " + - (errorBoundaryName || "Anonymous") + - ".") - ); - } - } - function defaultOnRecoverableError(error, errorInfo) { - reportGlobalError(error); - } - function logUncaughtError(root, errorInfo) { - try { - if (true) { - componentName = errorInfo.source - ? getComponentNameFromFiber(errorInfo.source) - : null; - errorBoundaryName = null; - } + return null; +} // Note: These happen to have identical begin phases, for now. We shouldn't hold - var error = errorInfo.value; +function updateCacheComponent(current, workInProgress, renderLanes) { - if (true && ReactSharedInternals.actQueue !== null) { - // For uncaught errors inside act, we track them on the act and then - // rethrow them into the test. - ReactSharedInternals.thrownErrors.push(error); - return; - } + prepareToReadContext(workInProgress, renderLanes); + var parentCache = readContext(CacheContext); - var onUncaughtError = root.onUncaughtError; - onUncaughtError(error, { - componentStack: errorInfo.stack - }); - } 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 logCaughtError(root, boundary, errorInfo) { - try { - if (true) { - componentName = errorInfo.source - ? getComponentNameFromFiber(errorInfo.source) - : null; - errorBoundaryName = getComponentNameFromFiber(boundary); - } - - var error = errorInfo.value; - var onCaughtError = root.onCaughtError; - onCaughtError(error, { - componentStack: errorInfo.stack, - errorBoundary: - boundary.tag === ClassComponent - ? boundary.stateNode // This should always be the case as long as we only have class boundaries - : null - }); - } 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; - }); - } + if (current === null) { + // Initial mount. Request a fresh cache from the pool. + var freshCache = requestCacheFromPool(renderLanes); + var initialState = { + parent: parentCache, + cache: freshCache + }; + workInProgress.memoizedState = initialState; + initializeUpdateQueue(workInProgress); + pushCacheProvider(workInProgress, freshCache); + } else { + // Check for updates + if (includesSomeLane(current.lanes, renderLanes)) { + cloneUpdateQueue(current, workInProgress); + processUpdateQueue(workInProgress, null, null, renderLanes); + suspendIfUpdateReadFromEntangledAsyncAction(); } - function createRootErrorUpdate(root, errorInfo, lane) { - var update = createUpdate(lane); // Unmount the root by rendering null. + var prevState = current.memoizedState; + var nextState = workInProgress.memoizedState; // Compare the new parent cache to the previous to see detect there was + // a refresh. - update.tag = CaptureUpdate; // Caution: React DevTools currently depends on this property - // being called "element". + if (prevState.parent !== parentCache) { + // Refresh in parent. Update the parent. + var derivedState = { + parent: parentCache, + cache: parentCache + }; // Copied from getDerivedStateFromProps implementation. Once the update + // queue is empty, persist the derived state onto the base state. - update.payload = { - element: null - }; + workInProgress.memoizedState = derivedState; - update.callback = function () { - logUncaughtError(root, errorInfo); - }; + if (workInProgress.lanes === NoLanes) { + var updateQueue = workInProgress.updateQueue; + workInProgress.memoizedState = updateQueue.baseState = derivedState; + } - return update; - } + pushCacheProvider(workInProgress, parentCache); // No need to propagate a context change because the refreshed parent + // already did. + } else { + // The parent didn't refresh. Now check if this cache did. + var nextCache = nextState.cache; + pushCacheProvider(workInProgress, nextCache); - function createClassErrorUpdate(lane) { - var update = createUpdate(lane); - update.tag = CaptureUpdate; - return update; + if (nextCache !== prevState.cache) { + // This cache refreshed. Propagate a context change. + propagateContextChange(workInProgress, CacheContext, renderLanes); + } } + } - function initializeClassErrorUpdate(update, root, fiber, errorInfo) { - var getDerivedStateFromError = fiber.type.getDerivedStateFromError; - - if (typeof getDerivedStateFromError === "function") { - var error$1 = errorInfo.value; + var nextChildren = workInProgress.pendingProps.children; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} // This should only be called if the name changes - update.payload = function () { - return getDerivedStateFromError(error$1); - }; +function updateFragment(current, workInProgress, renderLanes) { + var nextChildren = workInProgress.pendingProps; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} - update.callback = function () { - { - markFailedErrorBoundaryForHotReloading(fiber); - } +function updateMode(current, workInProgress, renderLanes) { + var nextChildren = workInProgress.pendingProps.children; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} - logCaughtError(root, fiber, errorInfo); - }; - } +function updateProfiler(current, workInProgress, renderLanes) { + { + workInProgress.flags |= Update; - var inst = fiber.stateNode; + { + // 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 nextProps = workInProgress.pendingProps; + var nextChildren = nextProps.children; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} - if (inst !== null && typeof inst.componentDidCatch === "function") { - // $FlowFixMe[missing-this-annot] - update.callback = function callback() { - { - markFailedErrorBoundaryForHotReloading(fiber); - } +function markRef(current, workInProgress) { + // TODO: Check props.ref instead of fiber.ref when enableRefAsProp is on. + var ref = workInProgress.ref; - logCaughtError(root, fiber, errorInfo); + if (ref === null) { + if (current !== null && current.ref !== null) { + // Schedule a Ref effect + workInProgress.flags |= Ref | RefStatic; + } + } else { + if (typeof ref !== 'function' && typeof ref !== 'object') { + throw new Error('Expected ref to be a function, an object returned by React.createRef(), or undefined/null.'); + } - 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 (current === null || current.ref !== ref) { + if (current !== null) { + var oldRef = current.ref; + var newRef = ref; + + if (typeof oldRef === 'function' && typeof newRef === 'function' && typeof oldRef.__stringRef === 'string' && oldRef.__stringRef === newRef.__stringRef && oldRef.__stringRefType === newRef.__stringRefType && oldRef.__stringRefOwner === newRef.__stringRefOwner) { + // Although this is a different callback, it represents the same + // string ref. To avoid breaking old Meta code that relies on string + // refs only being attached once, reuse the old ref. This will + // prevent us from detaching and reattaching the ref on each update. + workInProgress.ref = oldRef; + return; + } + } // Schedule a Ref effect - var error$1 = errorInfo.value; - var stack = errorInfo.stack; - this.componentDidCatch(error$1, { - componentStack: stack !== null ? stack : "" - }); - { - 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" - ); - } - } - } - }; - } + workInProgress.flags |= Ref | RefStatic; } + } +} - function resetSuspendedComponent(sourceFiber, rootRenderLanes) { - // A legacy mode Suspense quirk, only relevant to hook components. +function mountIncompleteFunctionComponent(_current, workInProgress, Component, nextProps, renderLanes) { + resetSuspendedCurrentOnMountInLegacyMode(_current, workInProgress); + workInProgress.tag = FunctionComponent; + return updateFunctionComponent(null, workInProgress, Component, nextProps, renderLanes); +} - var tag = sourceFiber.tag; +function updateFunctionComponent(current, workInProgress, Component, nextProps, renderLanes) { + { + if (Component.prototype && typeof Component.prototype.render === 'function') { + var componentName = getComponentNameFromType(Component) || 'Unknown'; - if ( - (sourceFiber.mode & ConcurrentMode) === NoMode && - (tag === FunctionComponent || - tag === ForwardRef || - tag === SimpleMemoComponent) - ) { - var currentSource = sourceFiber.alternate; + 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); - if (currentSource) { - sourceFiber.updateQueue = currentSource.updateQueue; - sourceFiber.memoizedState = currentSource.memoizedState; - sourceFiber.lanes = currentSource.lanes; - } else { - sourceFiber.updateQueue = null; - sourceFiber.memoizedState = null; - } + didWarnAboutBadClass[componentName] = true; } } - 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. + if (workInProgress.mode & StrictLegacyMode) { + ReactStrictModeWarnings.recordLegacyContextWarning(workInProgress, null); + } - sourceFiber.flags &= ~(LifecycleEffectMask | Incomplete); + if (current === null) { + // Some validations were previously done in mountIndeterminateComponent however and are now run + // in updateFuntionComponent but only on mount + validateFunctionComponentInDev(workInProgress, workInProgress.type); + } + } - if (sourceFiber.tag === ClassComponent) { - var currentSourceFiber = sourceFiber.alternate; + var context; - 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); - } - } else if (sourceFiber.tag === FunctionComponent) { - var _currentSourceFiber = sourceFiber.alternate; + { + var unmaskedContext = getUnmaskedContext(workInProgress, Component, true); + context = getMaskedContext(workInProgress, unmaskedContext); + } - if (_currentSourceFiber === null) { - // This is a new mount. Change the tag so it's not mistaken for a - // completed function component. - sourceFiber.tag = IncompleteFunctionComponent; - } - } // The source fiber did not complete. Mark it with Sync priority to - // indicate that it still has pending work. + var nextChildren; + prepareToReadContext(workInProgress, renderLanes); - sourceFiber.lanes = mergeLanes(sourceFiber.lanes, SyncLane); - } + { + markComponentRenderStarted(workInProgress); + } - 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. + { + ReactSharedInternals.owner = workInProgress; + setIsRendering(true); + nextChildren = renderWithHooks(current, workInProgress, Component, nextProps, context, renderLanes); + setIsRendering(false); + } - suspenseBoundary.flags |= ShouldCapture; // TODO: I think we can remove this, since we now use `DidCapture` in - // the begin phase to prevent an early bailout. + { + markComponentRenderStopped(); + } - suspenseBoundary.lanes = rootRenderLanes; - return suspenseBoundary; - } + if (current !== null && !didReceiveUpdate) { + bailoutHooks(current, workInProgress, renderLanes); + return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); + } - function throwException( - root, - returnFiber, - sourceFiber, - value, - rootRenderLanes - ) { - // The source fiber did not complete. - sourceFiber.flags |= Incomplete; - { - if (isDevToolsPresent) { - // If we have pending work still, restore the original updaters - restorePendingUpdaters(root, rootRenderLanes); - } - } - - if (value !== null && typeof value === "object") { - if (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; - - if (current === null) { - renderDidSuspend(); - } - } - } + workInProgress.flags |= PerformedWork; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} - 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. - - var isSuspenseyResource = - wakeable === noopSuspenseyCommitThenable; - - if (isSuspenseyResource) { - suspenseBoundary.flags |= ScheduleRetry; - } else { - var retryQueue = suspenseBoundary.updateQueue; +function replayFunctionComponent(current, workInProgress, nextProps, Component, secondArg, renderLanes) { + // 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. + prepareToReadContext(workInProgress, renderLanes); - if (retryQueue === null) { - suspenseBoundary.updateQueue = new Set([wakeable]); - } else { - retryQueue.add(wakeable); - } // We only attach ping listeners in concurrent mode. Legacy - // Suspense always commits fallbacks synchronously, so there are - // no pings. + { + markComponentRenderStarted(workInProgress); + } - if (suspenseBoundary.mode & ConcurrentMode) { - attachPingListener(root, wakeable, rootRenderLanes); - } - } + var nextChildren = replaySuspendedComponentWithHooks(current, workInProgress, Component, nextProps, secondArg); - return false; - } + { + markComponentRenderStopped(); + } - case OffscreenComponent: { - if (suspenseBoundary.mode & ConcurrentMode) { - suspenseBoundary.flags |= ShouldCapture; + if (current !== null && !didReceiveUpdate) { + bailoutHooks(current, workInProgress, renderLanes); + return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); + } - var _isSuspenseyResource = - wakeable === noopSuspenseyCommitThenable; - if (_isSuspenseyResource) { - suspenseBoundary.flags |= ScheduleRetry; - } else { - var offscreenQueue = suspenseBoundary.updateQueue; - - if (offscreenQueue === null) { - var newOffscreenQueue = { - transitions: null, - markerInstances: null, - retryQueue: new Set([wakeable]) - }; - suspenseBoundary.updateQueue = newOffscreenQueue; - } else { - var _retryQueue = offscreenQueue.retryQueue; + workInProgress.flags |= PerformedWork; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} - if (_retryQueue === null) { - offscreenQueue.retryQueue = new Set([wakeable]); - } else { - _retryQueue.add(wakeable); - } - } +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? - attachPingListener(root, wakeable, rootRenderLanes); - } + var tempInstance = new ctor(workInProgress.memoizedProps, _instance.context); + var state = tempInstance.state; - return false; - } - } - } + _instance.updater.enqueueSetState(_instance, state, null); - throw new Error( - "Unexpected Suspense handler tag (" + - suspenseBoundary.tag + - "). This " + - "is a bug in React." - ); - } 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 false; - } 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; - } - } + break; } - } // This is a regular error, not a Suspense wakeable. - var wrapperError = new Error( - "There was an error during concurrent rendering but React was able to recover by " + - "instead synchronously rendering the entire root.", + case true: { - cause: value - } - ); - queueConcurrentError( - createCapturedValueAtFiber(wrapperError, sourceFiber) - ); - renderDidError(); // 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 (returnFiber === null) { - // There's no return fiber, which means the root errored. This should never - // happen. Return `true` to trigger a fatal error (panic). - return true; - } - - var errorInfo = createCapturedValueAtFiber(value, sourceFiber); - var workInProgress = returnFiber; - - do { - switch (workInProgress.tag) { - case HostRoot: { - workInProgress.flags |= ShouldCapture; - - var _lane = pickArbitraryLane(rootRenderLanes); + workInProgress.flags |= DidCapture; + workInProgress.flags |= ShouldCapture; // eslint-disable-next-line react-internal/prod-error-codes - workInProgress.lanes = mergeLanes(workInProgress.lanes, _lane); + 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 - var _update = createRootErrorUpdate( - workInProgress.stateNode, - errorInfo, - _lane - ); + var root = getWorkInProgressRoot(); - enqueueCapturedUpdate(workInProgress, _update); - return false; + if (root === null) { + throw new Error('Expected a work-in-progress root. This is a bug in React. Please file an issue.'); } - case ClassComponent: - // Capture and retry - var ctor = workInProgress.type; - var instance = workInProgress.stateNode; - - if ( - (workInProgress.flags & DidCapture) === NoFlags$1 && - (typeof ctor.getDerivedStateFromError === "function" || - (instance !== null && - typeof instance.componentDidCatch === "function" && - !isAlreadyFailedLegacyErrorBoundary(instance))) - ) { - workInProgress.flags |= ShouldCapture; - - var _lane2 = pickArbitraryLane(rootRenderLanes); - - workInProgress.lanes = mergeLanes(workInProgress.lanes, _lane2); // Schedule the error boundary to re-render using updated state - - var _update2 = createClassErrorUpdate(_lane2); - - initializeClassErrorUpdate( - _update2, - root, - workInProgress, - errorInfo - ); - enqueueCapturedUpdate(workInProgress, _update2); - return false; - } + var update = createClassErrorUpdate(lane); + initializeClassErrorUpdate(update, root, workInProgress, createCapturedValueAtFiber(error$1, workInProgress)); + enqueueCapturedUpdate(workInProgress, update); + break; + } + } + } // 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. - break; - } // $FlowFixMe[incompatible-type] we bail out when we get a null - workInProgress = workInProgress.return; - } while (workInProgress !== null); + var hasContext; - return false; - } + if (isContextProvider(Component)) { + hasContext = true; + pushContextProvider(workInProgress); + } else { + hasContext = false; + } - // into a dehydrated boundary. + prepareToReadContext(workInProgress, renderLanes); + var instance = workInProgress.stateNode; + var shouldUpdate; - 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 didWarnAboutContextTypeOnFunctionComponent; - var didWarnAboutGetDerivedStateOnFunctionComponent; - var didWarnAboutFunctionRefs; - var didWarnAboutReassigningProps; - var didWarnAboutRevealOrder; - var didWarnAboutTailOptions; - var didWarnAboutDefaultPropsOnFunctionComponent; + if (instance === null) { + resetSuspendedCurrentOnMountInLegacyMode(current, workInProgress); // In the initial pass we might need to construct the instance. - { - didWarnAboutBadClass = {}; - 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 forceUnmountCurrentAndReconcile( - current, - workInProgress, - nextChildren, - renderLanes - ) { - // 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 - ); - } - - 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. - var render = Component.render; - var ref = workInProgress.ref; - var propsWithoutRef; + 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); + } - { - propsWithoutRef = nextProps; - } // The rest is a fork of updateFunctionComponent + var nextUnitOfWork = finishClassComponent(current, workInProgress, Component, shouldUpdate, hasContext, renderLanes); - var nextChildren; - prepareToReadContext(workInProgress, renderLanes); + { + var inst = workInProgress.stateNode; - { - markComponentRenderStarted(workInProgress); + 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'); } - { - ReactSharedInternals.owner = workInProgress; - setIsRendering(true); - nextChildren = renderWithHooks( - current, - workInProgress, - render, - propsWithoutRef, - ref, - renderLanes - ); - setIsRendering(false); - } + didWarnAboutReassigningProps = true; + } + } - { - markComponentRenderStopped(); - } + return nextUnitOfWork; +} - if (current !== null && !didReceiveUpdate) { - bailoutHooks(current, workInProgress, renderLanes); - return bailoutOnAlreadyFinishedWork( - current, - workInProgress, - renderLanes - ); - } +function finishClassComponent(current, workInProgress, Component, shouldUpdate, hasContext, renderLanes) { + // Refs should update even if shouldComponentUpdate returns false + markRef(current, workInProgress); + var didCaptureError = (workInProgress.flags & DidCapture) !== NoFlags$1; - workInProgress.flags |= PerformedWork; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; + if (!shouldUpdate && !didCaptureError) { + // Context providers should defer to sCU for rendering + if (hasContext) { + invalidateContextProvider(workInProgress, Component, false); } - function updateMemoComponent( - current, - workInProgress, - Component, - nextProps, - renderLanes - ) { - if (current === null) { - var type = Component.type; + return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); + } - if ( - isSimpleFunctionComponent(type) && - Component.compare === null && // SimpleMemoComponent codepath doesn't resolve outer props either. - (disableDefaultPropsExceptForClasses || - Component.defaultProps === undefined) - ) { - var resolvedType = type; + var instance = workInProgress.stateNode; // Rerender - { - 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. + { + ReactSharedInternals.owner = workInProgress; + } - workInProgress.tag = SimpleMemoComponent; - workInProgress.type = resolvedType; + var nextChildren; - { - validateFunctionComponentInDev(workInProgress, type); - } + 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; - return updateSimpleMemoComponent( - current, - workInProgress, - resolvedType, - nextProps, - renderLanes - ); - } + { + stopProfilerTimerIfRunning(); + } + } else { + { + markComponentRenderStarted(workInProgress); + } - if (!disableDefaultPropsExceptForClasses) { - { - 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; - } - } - } - } + { + setIsRendering(true); + nextChildren = instance.render(); - var child = createFiberFromTypeAndProps( - Component.type, - null, - nextProps, - workInProgress, - workInProgress.mode, - renderLanes - ); - child.ref = workInProgress.ref; - child.return = workInProgress; - workInProgress.child = child; - return child; - } - - 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 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 (current !== null) { - var prevProps = current.memoizedProps; - - 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. - - 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; - } + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); + + try { + instance.render(); + } finally { + setIsStrictModeForDevtools(false); } } - return updateFunctionComponent( - current, - workInProgress, - Component, - nextProps, - renderLanes - ); + setIsRendering(false); } - 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(current, workInProgress); + { + markComponentRenderStopped(); + } + } // React DevTools reads this flag. - if (nextProps.mode === "hidden" || enableLegacyHidden || nextIsDetached) { - // Rendering a hidden tree. - var didSuspend = (workInProgress.flags & DidCapture) !== NoFlags$1; - 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; + workInProgress.flags |= PerformedWork; - 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. - - var currentChildLanes = NoLanes; - - while (currentChild !== null) { - currentChildLanes = mergeLanes( - mergeLanes(currentChildLanes, currentChild.lanes), - currentChild.childLanes - ); - currentChild = currentChild.sibling; - } + 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. - var lanesWeJustAttempted = nextBaseLanes; - var remainingChildLanes = removeLanes( - currentChildLanes, - lanesWeJustAttempted - ); - workInProgress.childLanes = remainingChildLanes; - } else { - workInProgress.childLanes = NoLanes; - workInProgress.child = null; - } - return deferHiddenOffscreenComponent( - current, - workInProgress, - nextBaseLanes - ); - } + workInProgress.memoizedState = instance.state; // The context might have changed so we need to recalculate it. - 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; + if (hasContext) { + invalidateContextProvider(workInProgress, Component, true); + } - { - // push the cache pool even though we're going to bail out - // because otherwise there'd be a context mismatch - if (current !== null) { - pushTransition(workInProgress, null); - } - } + return workInProgress.child; +} - 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 _nextBaseLanes = - prevState !== null - ? mergeLanes(prevState.baseLanes, renderLanes) - : renderLanes; - - 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; +function pushHostRootContext(workInProgress) { + var root = workInProgress.stateNode; - if (current !== null) { - // If the render that spawned this one accessed the cache pool, resume - // using the same cache. Unless the parent changed, since that means - // there was a refresh. - var prevCachePool = prevState !== null ? prevState.cachePool : null; // TODO: Consider if and how Offscreen pre-rendering should - // be attributed to the transition that spawned it + if (root.pendingContext) { + pushTopLevelContextObject(workInProgress, root.pendingContext, root.pendingContext !== root.context); + } else if (root.context) { + // Should always be set + pushTopLevelContextObject(workInProgress, root.context, false); + } - pushTransition(workInProgress, prevCachePool); - } // Push the lanes that were skipped when we bailed out. + pushHostContainer(workInProgress, root.containerInfo); +} - if (prevState !== null) { - pushHiddenContext(workInProgress, prevState); - } else { - reuseHiddenContextOnStack(workInProgress); - } +function updateHostRoot(current, workInProgress, renderLanes) { + pushHostRootContext(workInProgress); - pushOffscreenSuspenseHandler(workInProgress); - } - } else { - // Rendering a visible tree. - if (prevState !== null) { - // We're going from hidden -> visible. - var _prevCachePool = null; + if (current === null) { + throw new Error('Should have a current fiber. This is a bug in React.'); + } - { - // If the render that spawned this one accessed the cache pool, resume - // using the same cache. Unless the parent changed, since that means - // there was a refresh. - _prevCachePool = prevState.cachePool; - } + var nextProps = workInProgress.pendingProps; + var prevState = workInProgress.memoizedState; + var prevChildren = prevState.element; + cloneUpdateQueue(current, workInProgress); + processUpdateQueue(workInProgress, nextProps, null, renderLanes); + var nextState = workInProgress.memoizedState; - pushTransition(workInProgress, _prevCachePool); // Push the lanes that were skipped when we bailed out. + { + var nextCache = nextState.cache; + pushCacheProvider(workInProgress, nextCache); - pushHiddenContext(workInProgress, prevState); - reuseSuspenseHandlerOnStack(workInProgress); // Since we're not hidden anymore, reset the state + if (nextCache !== prevState.cache) { + // The root cache refreshed. + propagateContextChange(workInProgress, CacheContext, renderLanes); + } + } // This would ideally go inside processUpdateQueue, but because it suspends, + // it needs to happen after the `pushCacheProvider` call above to avoid a + // context stack mismatch. A bit unfortunate. - workInProgress.memoizedState = null; - } else { - // We weren't previously hidden, and we still aren't, so there's nothing - // special to do. Need to push to the stack regardless, though, to avoid - // a push/pop misalignment. - { - // If the render that spawned this one accessed the cache pool, resume - // using the same cache. Unless the parent changed, since that means - // there was a refresh. - if (current !== null) { - pushTransition(workInProgress, null); - } - } // We're about to bail out, but we need to push this to the stack anyway - // to avoid a push/pop misalignment. - reuseHiddenContextOnStack(workInProgress); - reuseSuspenseHandlerOnStack(workInProgress); - } - } + suspendIfUpdateReadFromEntangledAsyncAction(); // Caution: React DevTools currently depends on this property + // being called "element". - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; + var nextChildren = nextState.element; + + { + + if (nextChildren === prevChildren) { + return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); } - function deferHiddenOffscreenComponent( - current, - workInProgress, - nextBaseLanes, - renderLanes - ) { - var nextState = { - baseLanes: nextBaseLanes, - // Save the cache pool so we can resume later. - cachePool: getOffscreenDeferredCache() - }; - workInProgress.memoizedState = nextState; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + } - { - // push the cache pool even though we're going to bail out - // because otherwise there'd be a context mismatch - if (current !== null) { - pushTransition(workInProgress, null); - } - } // We're about to bail out, but we need to push this to the stack anyway - // to avoid a push/pop misalignment. + return workInProgress.child; +} - reuseHiddenContextOnStack(workInProgress); - pushOffscreenSuspenseHandler(workInProgress); +function updateHostComponent$1(current, workInProgress, renderLanes) { - return null; - } // Note: These happen to have identical begin phases, for now. We shouldn't hold + pushHostContext(workInProgress); + var nextProps = workInProgress.pendingProps; + var prevProps = current !== null ? current.memoizedProps : null; + var nextChildren = nextProps.children; - function updateCacheComponent(current, workInProgress, renderLanes) { - prepareToReadContext(workInProgress, renderLanes); - var parentCache = readContext(CacheContext); + 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; + } - if (current === null) { - // Initial mount. Request a fresh cache from the pool. - var freshCache = requestCacheFromPool(renderLanes); - var initialState = { - parent: parentCache, - cache: freshCache - }; - workInProgress.memoizedState = initialState; - initializeUpdateQueue(workInProgress); - pushCacheProvider(workInProgress, freshCache); - } else { - // Check for updates - if (includesSomeLane(current.lanes, renderLanes)) { - cloneUpdateQueue(current, workInProgress); - processUpdateQueue(workInProgress, null, null, renderLanes); - suspendIfUpdateReadFromEntangledAsyncAction(); - } + if (enableAsyncActions) { + var memoizedState = workInProgress.memoizedState; - var prevState = current.memoizedState; - var nextState = workInProgress.memoizedState; // Compare the new parent cache to the previous to see detect there was - // a refresh. - - if (prevState.parent !== parentCache) { - // Refresh in parent. Update the parent. - var derivedState = { - parent: parentCache, - cache: parentCache - }; // Copied from getDerivedStateFromProps implementation. Once the update - // queue is empty, persist the derived state onto the base state. - - workInProgress.memoizedState = derivedState; - - if (workInProgress.lanes === NoLanes) { - var updateQueue = workInProgress.updateQueue; - workInProgress.memoizedState = updateQueue.baseState = derivedState; - } + if (memoizedState !== null) { + // This fiber has been upgraded to a stateful component. The only way + // happens currently is for form actions. We use hooks to track the + // pending and error state of the form. + // + // Once a fiber is upgraded to be stateful, it remains stateful for the + // rest of its lifetime. + var newState = renderTransitionAwareHostComponentWithHooks(current, workInProgress, renderLanes); // If the transition state changed, propagate the change to all the + // descendents. We use Context as an implementation detail for this. + // + // This is intentionally set here instead of pushHostContext because + // pushHostContext gets called before we process the state hook, to avoid + // a state mismatch in the event that something suspends. + // + // NOTE: This assumes that there cannot be nested transition providers, + // because the only renderer that implements this feature is React DOM, + // and forms cannot be nested. If we did support nested providers, then + // we would need to push a context value even for host fibers that + // haven't been upgraded yet. - pushCacheProvider(workInProgress, parentCache); // No need to propagate a context change because the refreshed parent - // already did. - } else { - // The parent didn't refresh. Now check if this cache did. - var nextCache = nextState.cache; - pushCacheProvider(workInProgress, nextCache); + { + HostTransitionContext._currentValue2 = newState; + } + + { + if (didReceiveUpdate) { + if (current !== null) { + var oldStateHook = current.memoizedState; + var oldState = oldStateHook.memoizedState; // This uses regular equality instead of Object.is because we assume + // that host transition state doesn't include NaN as a valid type. - if (nextCache !== prevState.cache) { - // This cache refreshed. Propagate a context change. - propagateContextChange(workInProgress, CacheContext, renderLanes); + if (oldState !== newState) { + propagateContextChange(workInProgress, HostTransitionContext, renderLanes); + } } } } + } + } + + markRef(current, workInProgress); + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} - var nextChildren = workInProgress.pendingProps.children; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; - } // This should only be called if the name changes +function updateHostText$1(current, workInProgress) { + // immediately after. - function updateFragment(current, workInProgress, renderLanes) { - var nextChildren = workInProgress.pendingProps; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; - } - function updateMode(current, workInProgress, renderLanes) { - var nextChildren = workInProgress.pendingProps.children; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; - } + return null; +} + +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. + + workInProgress.type = Component; + + if (typeof Component === 'function') { + if (isFunctionClassComponent(Component)) { + var resolvedProps = resolveClassComponentProps(Component, props, false); + workInProgress.tag = ClassComponent; - function updateProfiler(current, workInProgress, renderLanes) { { - workInProgress.flags |= Update; + workInProgress.type = Component = resolveClassForHotReloading(Component); + } - { - // 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; - } + return updateClassComponent(null, workInProgress, Component, resolvedProps, renderLanes); + } else { + var _resolvedProps = disableDefaultPropsExceptForClasses ? props : resolveDefaultPropsOnNonClassComponent(Component, props); + + workInProgress.tag = FunctionComponent; + + { + validateFunctionComponentInDev(workInProgress, Component); + workInProgress.type = Component = resolveFunctionForHotReloading(Component); } - var nextProps = workInProgress.pendingProps; - var nextChildren = nextProps.children; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; + return updateFunctionComponent(null, workInProgress, Component, _resolvedProps, renderLanes); } + } else if (Component !== undefined && Component !== null) { + var $$typeof = Component.$$typeof; - function markRef(current, workInProgress) { - // TODO: Check props.ref instead of fiber.ref when enableRefAsProp is on. - var ref = workInProgress.ref; + if ($$typeof === REACT_FORWARD_REF_TYPE) { + var _resolvedProps2 = disableDefaultPropsExceptForClasses ? props : resolveDefaultPropsOnNonClassComponent(Component, props); - if (ref === null) { - if (current !== null && current.ref !== null) { - // Schedule a Ref effect - workInProgress.flags |= Ref | RefStatic; - } - } else { - if (typeof ref !== "function" && typeof ref !== "object") { - throw new Error( - "Expected ref to be a function, an object returned by React.createRef(), or undefined/null." - ); - } - - if (current === null || current.ref !== ref) { - if (current !== null) { - var oldRef = current.ref; - var newRef = ref; - - if ( - typeof oldRef === "function" && - typeof newRef === "function" && - typeof oldRef.__stringRef === "string" && - oldRef.__stringRef === newRef.__stringRef && - oldRef.__stringRefType === newRef.__stringRefType && - oldRef.__stringRefOwner === newRef.__stringRefOwner - ) { - // Although this is a different callback, it represents the same - // string ref. To avoid breaking old Meta code that relies on string - // refs only being attached once, reuse the old ref. This will - // prevent us from detaching and reattaching the ref on each update. - workInProgress.ref = oldRef; - return; - } - } // Schedule a Ref effect + workInProgress.tag = ForwardRef; - workInProgress.flags |= Ref | RefStatic; - } + { + workInProgress.type = Component = resolveForwardRefForHotReloading(Component); } + + return updateForwardRef(null, workInProgress, Component, _resolvedProps2, renderLanes); + } else if ($$typeof === REACT_MEMO_TYPE) { + var _resolvedProps3 = disableDefaultPropsExceptForClasses ? props : resolveDefaultPropsOnNonClassComponent(Component, props); + + workInProgress.tag = MemoComponent; + return updateMemoComponent(null, workInProgress, Component, disableDefaultPropsExceptForClasses ? _resolvedProps3 : resolveDefaultPropsOnNonClassComponent(Component.type, _resolvedProps3), // The inner type can have defaults too + renderLanes); } + } - function mountIncompleteFunctionComponent( - _current, - workInProgress, - Component, - nextProps, - renderLanes - ) { - resetSuspendedCurrentOnMountInLegacyMode(_current, workInProgress); - workInProgress.tag = FunctionComponent; - return updateFunctionComponent( - null, - workInProgress, - Component, - nextProps, - renderLanes - ); - } - - function updateFunctionComponent( - current, - workInProgress, - Component, - nextProps, - renderLanes - ) { - { - 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 - ); + var hint = ''; - didWarnAboutBadClass[componentName] = true; - } - } + { + 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. - if (workInProgress.mode & StrictLegacyMode) { - ReactStrictModeWarnings.recordLegacyContextWarning( - workInProgress, - null - ); - } - if (current === null) { - // Some validations were previously done in mountIndeterminateComponent however and are now run - // in updateFuntionComponent but only on mount - validateFunctionComponentInDev(workInProgress, workInProgress.type); - } - } + 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 context; +function mountIncompleteClassComponent(_current, workInProgress, Component, nextProps, renderLanes) { + resetSuspendedCurrentOnMountInLegacyMode(_current, workInProgress); // Promote the fiber to a class and try rendering again. - { - var unmaskedContext = getUnmaskedContext( - workInProgress, - Component, - true - ); - context = getMaskedContext(workInProgress, unmaskedContext); - } + 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. - var nextChildren; - prepareToReadContext(workInProgress, renderLanes); + var hasContext; - { - markComponentRenderStarted(workInProgress); - } + if (isContextProvider(Component)) { + hasContext = true; + pushContextProvider(workInProgress); + } else { + hasContext = false; + } - { - ReactSharedInternals.owner = workInProgress; - setIsRendering(true); - nextChildren = renderWithHooks( - current, - workInProgress, - Component, - nextProps, - context, - renderLanes - ); - setIsRendering(false); + prepareToReadContext(workInProgress, renderLanes); + constructClassInstance(workInProgress, Component, nextProps); + mountClassInstance(workInProgress, Component, nextProps, renderLanes); + return finishClassComponent(null, workInProgress, Component, true, hasContext, renderLanes); +} + +function validateFunctionComponentInDev(workInProgress, Component) { + { + if (Component) { + if (Component.childContextTypes) { + error('childContextTypes cannot be defined on a function component.\n' + ' %s.childContextTypes = ...', Component.displayName || Component.name || 'Component'); } + } - { - markComponentRenderStopped(); + if (workInProgress.ref !== null) { + var info = ''; + var componentName = getComponentNameFromType(Component) || 'Unknown'; + var ownerName = getCurrentFiberOwnerNameInDevOrNull(); + + if (ownerName) { + info += '\n\nCheck the render method of `' + ownerName + '`.'; } - if (current !== null && !didReceiveUpdate) { - bailoutHooks(current, workInProgress, renderLanes); - return bailoutOnAlreadyFinishedWork( - current, - workInProgress, - renderLanes - ); + var warningKey = componentName + '|' + (ownerName || ''); + + if (!didWarnAboutFunctionRefs[warningKey]) { + didWarnAboutFunctionRefs[warningKey] = true; + + error('Function components cannot be given refs. ' + 'Attempts to access this ref will fail. ' + 'Did you mean to use React.forwardRef()?%s', info); } + } + + if (!disableDefaultPropsExceptForClasses && 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); - workInProgress.flags |= PerformedWork; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; + didWarnAboutDefaultPropsOnFunctionComponent[_componentName] = true; + } } - function replayFunctionComponent( - current, - workInProgress, - nextProps, - Component, - secondArg, - renderLanes - ) { - // 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. - prepareToReadContext(workInProgress, renderLanes); + if (typeof Component.getDerivedStateFromProps === 'function') { + var _componentName2 = getComponentNameFromType(Component) || 'Unknown'; - { - markComponentRenderStarted(workInProgress); + if (!didWarnAboutGetDerivedStateOnFunctionComponent[_componentName2]) { + error('%s: Function components do not support getDerivedStateFromProps.', _componentName2); + + didWarnAboutGetDerivedStateOnFunctionComponent[_componentName2] = true; } + } - var nextChildren = replaySuspendedComponentWithHooks( - current, - workInProgress, - Component, - nextProps, - secondArg - ); + if (typeof Component.contextType === 'object' && Component.contextType !== null) { + var _componentName3 = getComponentNameFromType(Component) || 'Unknown'; - { - markComponentRenderStopped(); + if (!didWarnAboutContextTypeOnFunctionComponent[_componentName3]) { + error('%s: Function components do not support contextType.', _componentName3); + + didWarnAboutContextTypeOnFunctionComponent[_componentName3] = true; } + } + } +} + +var SUSPENDED_MARKER = { + dehydrated: null, + treeContext: null, + retryLane: NoLane +}; + +function mountSuspenseOffscreenState(renderLanes) { + return { + baseLanes: renderLanes, + cachePool: getSuspendedCache() + }; +} + +function updateSuspenseOffscreenState(prevOffscreenState, renderLanes) { + var cachePool = null; + + { + var prevCachePool = prevOffscreenState.cachePool; - if (current !== null && !didReceiveUpdate) { - bailoutHooks(current, workInProgress, renderLanes); - return bailoutOnAlreadyFinishedWork( - current, - workInProgress, - renderLanes - ); - } + if (prevCachePool !== null) { + var parentCache = CacheContext._currentValue2; - workInProgress.flags |= PerformedWork; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; + if (prevCachePool.parent !== parentCache) { + // Detected a refresh in the parent. This overrides any previously + // suspended cache. + cachePool = { + parent: parentCache, + pool: parentCache + }; + } else { + // We can reuse the cache from last time. The only thing that would have + // overridden it is a parent refresh, which we checked for above. + cachePool = prevCachePool; + } + } else { + // If there's no previous cache pool, grab the current one. + cachePool = getSuspendedCache(); + } + } + + return { + baseLanes: mergeLanes(prevOffscreenState.baseLanes, renderLanes), + cachePool: cachePool + }; +} // TODO: Probably should inline this back + + +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 (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. - 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? - - var tempInstance = new ctor( - workInProgress.memoizedProps, - _instance.context - ); - var state = tempInstance.state; - - _instance.updater.enqueueSetState(_instance, state, null); - break; - } + var suspenseContext = suspenseStackCursor.current; + return hasSuspenseListContext(suspenseContext, ForceSuspenseFallback); +} - case true: { - workInProgress.flags |= DidCapture; - workInProgress.flags |= ShouldCapture; // eslint-disable-next-line react-internal/prod-error-codes +function getRemainingWorkInPrimaryTree(current, primaryTreeDidDefer, renderLanes) { + var remainingLanes = current !== null ? removeLanes(current.childLanes, renderLanes) : NoLanes; - 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 (primaryTreeDidDefer) { + // A useDeferredValue hook spawned a deferred task inside the primary tree. + // Ensure that we retry this component at the deferred priority. + // TODO: We could make this a per-subtree value instead of a global one. + // Would need to track it on the context stack somehow, similar to what + // we'd have to do for resumable contexts. + remainingLanes = mergeLanes(remainingLanes, peekDeferredLane()); + } - var root = getWorkInProgressRoot(); + return remainingLanes; +} - if (root === null) { - throw new Error( - "Expected a work-in-progress root. This is a bug in React. Please file an issue." - ); - } +function updateSuspenseComponent(current, workInProgress, renderLanes) { + var nextProps = workInProgress.pendingProps; // This is used by DevTools to force a boundary to suspend. + + { + if (shouldSuspend(workInProgress)) { + workInProgress.flags |= DidCapture; + } + } + + var showFallback = false; + var didSuspend = (workInProgress.flags & DidCapture) !== NoFlags$1; + + if (didSuspend || shouldRemainOnFallback(current)) { + // Something in this boundary's subtree already suspended. Switch to + // rendering the fallback children. + showFallback = true; + workInProgress.flags &= ~DidCapture; + } // Check if the primary children spawned a deferred task (useDeferredValue) + // during the first pass. + + + var didPrimaryChildrenDefer = (workInProgress.flags & DidDefer) !== NoFlags$1; + workInProgress.flags &= ~DidDefer; // 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. + + if (current === null) { + + var nextPrimaryChildren = nextProps.children; + var nextFallbackChildren = nextProps.fallback; + + if (showFallback) { + pushFallbackTreeSuspenseHandler(workInProgress); + var fallbackFragment = mountSuspenseFallbackChildren(workInProgress, nextPrimaryChildren, nextFallbackChildren, renderLanes); + var primaryChildFragment = workInProgress.child; + primaryChildFragment.memoizedState = mountSuspenseOffscreenState(renderLanes); + primaryChildFragment.childLanes = getRemainingWorkInPrimaryTree(current, didPrimaryChildrenDefer, renderLanes); + workInProgress.memoizedState = SUSPENDED_MARKER; + + 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); + + var _fallbackFragment = mountSuspenseFallbackChildren(workInProgress, nextPrimaryChildren, nextFallbackChildren, renderLanes); + + var _primaryChildFragment = workInProgress.child; + _primaryChildFragment.memoizedState = mountSuspenseOffscreenState(renderLanes); + _primaryChildFragment.childLanes = getRemainingWorkInPrimaryTree(current, didPrimaryChildrenDefer, 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 = SomeRetryLane; + return _fallbackFragment; + } else { + pushPrimaryTreeSuspenseHandler(workInProgress); + return mountSuspensePrimaryChildren(workInProgress, nextPrimaryChildren); + } + } else { + // This is an update. + // Special path for hydration + var prevState = current.memoizedState; + + if (prevState !== null) { + var _dehydrated = prevState.dehydrated; + + if (_dehydrated !== null) { + return updateDehydratedSuspenseComponent(current, workInProgress, didSuspend, didPrimaryChildrenDefer, nextProps, _dehydrated, prevState, renderLanes); + } + } + + 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); + + _primaryChildFragment2.childLanes = getRemainingWorkInPrimaryTree(current, didPrimaryChildrenDefer, renderLanes); + workInProgress.memoizedState = SUSPENDED_MARKER; + return fallbackChildFragment; + } else { + pushPrimaryTreeSuspenseHandler(workInProgress); + var _nextPrimaryChildren2 = nextProps.children; - var update = createClassErrorUpdate(lane); - initializeClassErrorUpdate( - update, - root, - workInProgress, - createCapturedValueAtFiber(error$1, workInProgress) - ); - enqueueCapturedUpdate(workInProgress, update); - break; - } - } - } // 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 _primaryChildFragment3 = updateSuspensePrimaryChildren(current, workInProgress, _nextPrimaryChildren2, renderLanes); - var hasContext; + workInProgress.memoizedState = null; + return _primaryChildFragment3; + } + } +} - if (isContextProvider(Component)) { - hasContext = true; - pushContextProvider(workInProgress); - } else { - hasContext = false; - } - - 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 - ); +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; +} - { - 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" - ); - } +function mountSuspenseFallbackChildren(workInProgress, primaryChildren, fallbackChildren, 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; + + 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; + } + + 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; +} - didWarnAboutReassigningProps = true; - } - } +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); +} - return nextUnitOfWork; - } +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 finishClassComponent( - current, - workInProgress, - Component, - shouldUpdate, - hasContext, - renderLanes - ) { - // Refs should update even if shouldComponentUpdate returns false - markRef(current, workInProgress); - var didCaptureError = (workInProgress.flags & DidCapture) !== NoFlags$1; +function updateSuspensePrimaryChildren(current, workInProgress, primaryChildren, renderLanes) { + var currentPrimaryChildFragment = current.child; + var currentFallbackChildFragment = currentPrimaryChildFragment.sibling; + var primaryChildFragment = updateWorkInProgressOffscreenFiber(currentPrimaryChildFragment, { + mode: 'visible', + children: primaryChildren + }); - if (!shouldUpdate && !didCaptureError) { - // Context providers should defer to sCU for rendering - if (hasContext) { - invalidateContextProvider(workInProgress, Component, false); - } + if ((workInProgress.mode & ConcurrentMode) === NoMode) { + primaryChildFragment.lanes = renderLanes; + } - return bailoutOnAlreadyFinishedWork( - current, - workInProgress, - renderLanes - ); - } + primaryChildFragment.return = workInProgress; + primaryChildFragment.sibling = null; - var instance = workInProgress.stateNode; // Rerender + if (currentFallbackChildFragment !== null) { + // Delete the fallback child fragment + var deletions = workInProgress.deletions; - { - ReactSharedInternals.owner = workInProgress; - } + if (deletions === null) { + workInProgress.deletions = [currentFallbackChildFragment]; + workInProgress.flags |= ChildDeletion; + } else { + deletions.push(currentFallbackChildFragment); + } + } - var nextChildren; + workInProgress.child = primaryChildFragment; + return primaryChildFragment; +} - 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; +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 ( // 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 (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 { + 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.) + + primaryChildFragment.subtreeFlags = currentPrimaryChildFragment.subtreeFlags & StaticMask; + } + + var fallbackChildFragment; + + 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. + + fallbackChildFragment.flags |= Placement; + } + + fallbackChildFragment.return = workInProgress; + primaryChildFragment.return = workInProgress; + primaryChildFragment.sibling = fallbackChildFragment; + workInProgress.child = primaryChildFragment; + return fallbackChildFragment; +} - { - stopProfilerTimerIfRunning(); - } - } else { - { - markComponentRenderStarted(workInProgress); - } +function retrySuspenseComponentWithoutHydrating(current, workInProgress, renderLanes) { + // 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. + // 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; +} - { - setIsRendering(true); - nextChildren = instance.render(); +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; + + 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); + } + + return fallbackChildFragment; +} - if (workInProgress.mode & StrictLegacyMode) { - setIsStrictModeForDevtools(true); +function updateDehydratedSuspenseComponent(current, workInProgress, didSuspend, didPrimaryChildrenDefer, 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, - try { - instance.render(); - } finally { - setIsStrictModeForDevtools(false); - } - } + 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; + var message; + var stack = null; + var componentStack = null; - setIsRendering(false); - } + { + var _getSuspenseInstanceF = getSuspenseInstanceFallbackErrorDetails(); - { - markComponentRenderStopped(); - } - } // React DevTools reads this flag. - - workInProgress.flags |= PerformedWork; - - 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. + digest = _getSuspenseInstanceF.digest; + message = _getSuspenseInstanceF.message; + stack = _getSuspenseInstanceF.stack; + componentStack = _getSuspenseInstanceF.componentStack; + } // TODO: Figure out a better signal than encoding a magic digest value. - workInProgress.memoizedState = instance.state; // The context might have changed so we need to recalculate it. - if (hasContext) { - invalidateContextProvider(workInProgress, Component, true); - } + { + var error; - return workInProgress.child; - } + 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.'); + } // Replace the stack with the server stack - function pushHostRootContext(workInProgress) { - var root = workInProgress.stateNode; - if (root.pendingContext) { - pushTopLevelContextObject( - workInProgress, - root.pendingContext, - root.pendingContext !== root.context - ); - } else if (root.context) { - // Should always be set - pushTopLevelContextObject(workInProgress, root.context, false); + error.stack = stack || ''; + error.digest = digest; + var capturedValue = createCapturedValueFromError(error, componentStack === undefined ? null : componentStack); + queueHydrationError(capturedValue); } - pushHostContainer(workInProgress, root.containerInfo); + return retrySuspenseComponentWithoutHydrating(current, workInProgress, renderLanes); } + // any context has changed, we need to treat is as if the input might have changed. - function updateHostRoot(current, workInProgress, renderLanes) { - pushHostRootContext(workInProgress); - if (current === null) { - throw new Error("Should have a current fiber. This is a bug in React."); - } + var hasContextChanged = includesSomeLane(renderLanes, current.childLanes); - var nextProps = workInProgress.pendingProps; - var prevState = workInProgress.memoizedState; - var prevChildren = prevState.element; - cloneUpdateQueue(current, workInProgress); - processUpdateQueue(workInProgress, nextProps, null, renderLanes); - var nextState = workInProgress.memoizedState; + 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(); - { - var nextCache = nextState.cache; - pushCacheProvider(workInProgress, nextCache); + if (root !== null) { + var attemptHydrationAtLane = getBumpedLaneForHydration(root, renderLanes); + + 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; + enqueueConcurrentRenderForLane(current, attemptHydrationAtLane); + scheduleUpdateOnFiber(root, current, attemptHydrationAtLane); // 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 (nextCache !== prevState.cache) { - // The root cache refreshed. - propagateContextChange(workInProgress, CacheContext, renderLanes); + throw SelectiveHydrationException; } - } // This would ideally go inside processUpdateQueue, but because it suspends, - // it needs to happen after the `pushCacheProvider` call above to avoid a - // context stack mismatch. A bit unfortunate. - - suspendIfUpdateReadFromEntangledAsyncAction(); // Caution: React DevTools currently depends on this property - // being called "element". + } // 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. + + + if (isSuspenseInstancePending()) ; else { + renderDidSuspendDelayIfPossible(); + } + + return retrySuspenseComponentWithoutHydrating(current, workInProgress, renderLanes); + } 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. + + workInProgress.child = current.child; // Register a callback to retry this boundary once the server has sent the result. + + 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. + + 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. + // The error should've already been logged in throwException. + pushPrimaryTreeSuspenseHandler(workInProgress); + workInProgress.flags &= ~ForceClientRender; + return retrySuspenseComponentWithoutHydrating(current, workInProgress, renderLanes); + } 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. + + 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); + _primaryChildFragment4.childLanes = getRemainingWorkInPrimaryTree(current, didPrimaryChildrenDefer, renderLanes); + workInProgress.memoizedState = SUSPENDED_MARKER; + return fallbackChildFragment; + } + } +} - var nextChildren = nextState.element; +function scheduleSuspenseWorkOnFiber(fiber, renderLanes, propagationRoot) { + fiber.lanes = mergeLanes(fiber.lanes, renderLanes); + var alternate = fiber.alternate; - { - if (nextChildren === prevChildren) { - return bailoutOnAlreadyFinishedWork( - current, - workInProgress, - renderLanes - ); - } + if (alternate !== null) { + alternate.lanes = mergeLanes(alternate.lanes, renderLanes); + } - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - } + scheduleContextWorkOnParentPath(fiber.return, renderLanes, propagationRoot); +} - return workInProgress.child; - } +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; - function updateHostComponent$1(current, workInProgress, renderLanes) { - pushHostContext(workInProgress); - var nextProps = workInProgress.pendingProps; - var prevProps = current !== null ? current.memoizedProps : null; - var nextChildren = nextProps.children; + while (node !== null) { + if (node.tag === SuspenseComponent) { + var state = node.memoizedState; - 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; + 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 (enableAsyncActions) { - var memoizedState = workInProgress.memoizedState; - - if (memoizedState !== null) { - // This fiber has been upgraded to a stateful component. The only way - // happens currently is for form actions. We use hooks to track the - // pending and error state of the form. - // - // Once a fiber is upgraded to be stateful, it remains stateful for the - // rest of its lifetime. - var newState = renderTransitionAwareHostComponentWithHooks( - current, - workInProgress, - renderLanes - ); // If the transition state changed, propagate the change to all the - // descendents. We use Context as an implementation detail for this. - // - // This is intentionally set here instead of pushHostContext because - // pushHostContext gets called before we process the state hook, to avoid - // a state mismatch in the event that something suspends. - // - // NOTE: This assumes that there cannot be nested transition providers, - // because the only renderer that implements this feature is React DOM, - // and forms cannot be nested. If we did support nested providers, then - // we would need to push a context value even for host fibers that - // haven't been upgraded yet. + if (node === workInProgress) { + return; + } // $FlowFixMe[incompatible-use] found when upgrading Flow - { - HostTransitionContext._currentValue2 = newState; - } - { - if (didReceiveUpdate) { - if (current !== null) { - var oldStateHook = current.memoizedState; - var oldState = oldStateHook.memoizedState; // This uses regular equality instead of Object.is because we assume - // that host transition state doesn't include NaN as a valid type. - - if (oldState !== newState) { - propagateContextChange( - workInProgress, - HostTransitionContext, - renderLanes - ); - } - } - } - } - } + while (node.sibling === null) { + // $FlowFixMe[incompatible-use] found when upgrading Flow + if (node.return === null || node.return === workInProgress) { + return; } - markRef(current, workInProgress); - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; - } + node = node.return; + } // $FlowFixMe[incompatible-use] found when upgrading Flow - function updateHostText$1(current, workInProgress) { - // immediately after. - return null; - } + node.sibling.return = node.return; + node = node.sibling; + } +} - 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. - - workInProgress.type = Component; - - if (typeof Component === "function") { - if (isFunctionClassComponent(Component)) { - var resolvedProps = resolveClassComponentProps( - Component, - props, - false - ); - workInProgress.tag = ClassComponent; +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; - { - workInProgress.type = Component = - resolveClassForHotReloading(Component); - } + while (row !== null) { + var currentRow = row.alternate; // New rows can't be content rows. - return updateClassComponent( - null, - workInProgress, - Component, - resolvedProps, - renderLanes - ); - } else { - var _resolvedProps = disableDefaultPropsExceptForClasses - ? props - : resolveDefaultPropsOnNonClassComponent(Component, props); + if (currentRow !== null && findFirstSuspended(currentRow) === null) { + lastContentRow = row; + } - workInProgress.tag = FunctionComponent; + row = row.sibling; + } - { - validateFunctionComponentInDev(workInProgress, Component); - workInProgress.type = Component = - resolveFunctionForHotReloading(Component); - } + return lastContentRow; +} - return updateFunctionComponent( - null, - workInProgress, - Component, - _resolvedProps, - renderLanes - ); - } - } else if (Component !== undefined && Component !== null) { - var $$typeof = Component.$$typeof; +function validateRevealOrder(revealOrder) { + { + if (revealOrder !== undefined && revealOrder !== 'forwards' && revealOrder !== 'backwards' && revealOrder !== 'together' && !didWarnAboutRevealOrder[revealOrder]) { + didWarnAboutRevealOrder[revealOrder] = true; + + 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()); - if ($$typeof === REACT_FORWARD_REF_TYPE) { - var _resolvedProps2 = disableDefaultPropsExceptForClasses - ? props - : resolveDefaultPropsOnNonClassComponent(Component, props); + break; + } - workInProgress.tag = ForwardRef; + 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()); - { - workInProgress.type = Component = - resolveForwardRefForHotReloading(Component); - } + break; + } - return updateForwardRef( - null, - workInProgress, - Component, - _resolvedProps2, - renderLanes - ); - } else if ($$typeof === REACT_MEMO_TYPE) { - var _resolvedProps3 = disableDefaultPropsExceptForClasses - ? props - : resolveDefaultPropsOnNonClassComponent(Component, props); - - workInProgress.tag = MemoComponent; - return updateMemoComponent( - null, - workInProgress, - Component, - disableDefaultPropsExceptForClasses - ? _resolvedProps3 - : resolveDefaultPropsOnNonClassComponent( - Component.type, - _resolvedProps3 - ), // The inner type can have defaults too - renderLanes - ); - } - } - - var hint = ""; + default: + error('"%s" is not a supported revealOrder on . ' + 'Did you mean "together", "forwards" or "backwards"?', revealOrder); - { - 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) - ); - } - - function mountIncompleteClassComponent( - _current, - workInProgress, - Component, - nextProps, - renderLanes - ) { - resetSuspendedCurrentOnMountInLegacyMode(_current, workInProgress); // Promote the fiber to a class and try rendering again. - - 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. - - var hasContext; - - if (isContextProvider(Component)) { - hasContext = true; - pushContextProvider(workInProgress); + break; + } } else { - hasContext = false; + error('%s is not a supported value for revealOrder on . ' + 'Did you mean "together", "forwards" or "backwards"?', revealOrder); } - - prepareToReadContext(workInProgress, renderLanes); - constructClassInstance(workInProgress, Component, nextProps); - mountClassInstance(workInProgress, Component, nextProps, renderLanes); - return finishClassComponent( - null, - workInProgress, - Component, - true, - hasContext, - renderLanes - ); } + } +} - function validateFunctionComponentInDev(workInProgress, Component) { - { - if (Component) { - if (Component.childContextTypes) { - error( - "childContextTypes cannot be defined on a function component.\n" + - " %s.childContextTypes = ...", - Component.displayName || Component.name || "Component" - ); - } - } +function validateTailOptions(tailMode, revealOrder) { + { + if (tailMode !== undefined && !didWarnAboutTailOptions[tailMode]) { + if (tailMode !== 'collapsed' && tailMode !== 'hidden') { + didWarnAboutTailOptions[tailMode] = true; - if (workInProgress.ref !== null) { - var info = ""; - var componentName = getComponentNameFromType(Component) || "Unknown"; - var ownerName = getCurrentFiberOwnerNameInDevOrNull(); + 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 (ownerName) { - info += "\n\nCheck the render method of `" + ownerName + "`."; - } + error(' is only valid if revealOrder is ' + '"forwards" or "backwards". ' + 'Did you mean to specify revealOrder="forwards"?', tailMode); + } + } + } +} - var warningKey = componentName + "|" + (ownerName || ""); +function validateSuspenseListNestedChild(childSlot, index) { + { + var isAnArray = isArray(childSlot); + var isIterable = !isAnArray && typeof getIteratorFn(childSlot) === 'function'; - if (!didWarnAboutFunctionRefs[warningKey]) { - didWarnAboutFunctionRefs[warningKey] = true; + if (isAnArray || isIterable) { + var type = isAnArray ? 'array' : 'iterable'; - error( - "Function components cannot be given refs. " + - "Attempts to access this ref will fail. " + - "Did you mean to use React.forwardRef()?%s", - info - ); - } - } + error('A nested %s was passed to row #%s in . Wrap it in ' + 'an additional SuspenseList to configure its revealOrder: ' + ' ... ' + '{%s} ... ' + '', type, index, type); - if ( - !disableDefaultPropsExceptForClasses && - Component.defaultProps !== undefined - ) { - var _componentName = getComponentNameFromType(Component) || "Unknown"; + return false; + } + } - 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 - ); + return true; +} - didWarnAboutDefaultPropsOnFunctionComponent[_componentName] = true; +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); - if (typeof Component.getDerivedStateFromProps === "function") { - var _componentName2 = - getComponentNameFromType(Component) || "Unknown"; - - if ( - !didWarnAboutGetDerivedStateOnFunctionComponent[_componentName2] - ) { - error( - "%s: Function components do not support getDerivedStateFromProps.", - _componentName2 - ); - - didWarnAboutGetDerivedStateOnFunctionComponent[_componentName2] = - true; - } - } + if (typeof iteratorFn === 'function') { + var childrenIterator = iteratorFn.call(children); - if ( - typeof Component.contextType === "object" && - Component.contextType !== null - ) { - var _componentName3 = - getComponentNameFromType(Component) || "Unknown"; + if (childrenIterator) { + var step = childrenIterator.next(); + var _i = 0; - if (!didWarnAboutContextTypeOnFunctionComponent[_componentName3]) { - error( - "%s: Function components do not support contextType.", - _componentName3 - ); + for (; !step.done; step = childrenIterator.next()) { + if (!validateSuspenseListNestedChild(step.value, _i)) { + return; + } - didWarnAboutContextTypeOnFunctionComponent[_componentName3] = true; + _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); } } } + } +} - var SUSPENDED_MARKER = { - dehydrated: null, - treeContext: null, - retryLane: NoLane +function initSuspenseListRenderState(workInProgress, isBackwards, tail, lastContentRow, tailMode) { + var renderState = workInProgress.memoizedState; + + 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. + + +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 (shouldForceFallback) { + suspenseContext = setShallowSuspenseListContext(suspenseContext, ForceSuspenseFallback); + workInProgress.flags |= DidCapture; + } else { + var didSuspendBefore = current !== null && (current.flags & DidCapture) !== NoFlags$1; + + 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); + } + + suspenseContext = setDefaultShallowSuspenseListContext(suspenseContext); + } + + 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; - function mountSuspenseOffscreenState(renderLanes) { - return { - baseLanes: renderLanes, - cachePool: getSuspendedCache() - }; - } + 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; + } - function updateSuspenseOffscreenState(prevOffscreenState, renderLanes) { - var cachePool = null; + initSuspenseListRenderState(workInProgress, false, // isBackwards + tail, lastContentRow, tailMode); + break; + } - { - var prevCachePool = prevOffscreenState.cachePool; + 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; + + while (row !== null) { + var currentRow = row.alternate; // New rows can't be content rows. + + if (currentRow !== null && findFirstSuspended(currentRow) === null) { + // This is the beginning of the main content. + workInProgress.child = row; + break; + } - if (prevCachePool !== null) { - var parentCache = CacheContext._currentValue2; + var nextRow = row.sibling; + row.sibling = _tail; + _tail = row; + row = nextRow; + } // TODO: If workInProgress.child is null, we can continue on the tail immediately. - if (prevCachePool.parent !== parentCache) { - // Detected a refresh in the parent. This overrides any previously - // suspended cache. - cachePool = { - parent: parentCache, - pool: parentCache - }; - } else { - // We can reuse the cache from last time. The only thing that would have - // overridden it is a parent refresh, which we checked for above. - cachePool = prevCachePool; - } - } else { - // If there's no previous cache pool, grab the current one. - cachePool = getSuspendedCache(); - } - } - return { - baseLanes: mergeLanes(prevOffscreenState.baseLanes, renderLanes), - cachePool: cachePool - }; - } // TODO: Probably should inline this back - - 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; + initSuspenseListRenderState(workInProgress, true, // isBackwards + _tail, null, // last + tailMode); + 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; + case 'together': + { + initSuspenseListRenderState(workInProgress, false, // isBackwards + null, // tail + null, // last + undefined); + break; } - } // Not currently showing content. Consult the Suspense context. - var suspenseContext = suspenseStackCursor.current; - return hasSuspenseListContext(suspenseContext, ForceSuspenseFallback); + default: + { + // The default reveal order is the same as not having + // a boundary. + workInProgress.memoizedState = null; + } } + } - function getRemainingWorkInPrimaryTree( - current, - primaryTreeDidDefer, - renderLanes - ) { - var remainingLanes = - current !== null - ? removeLanes(current.childLanes, renderLanes) - : NoLanes; + return workInProgress.child; +} - if (primaryTreeDidDefer) { - // A useDeferredValue hook spawned a deferred task inside the primary tree. - // Ensure that we retry this component at the deferred priority. - // TODO: We could make this a per-subtree value instead of a global one. - // Would need to track it on the context stack somehow, similar to what - // we'd have to do for resumable contexts. - remainingLanes = mergeLanes(remainingLanes, peekDeferredLane()); - } +function updatePortalComponent(current, workInProgress, renderLanes) { + pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); + var nextChildren = workInProgress.pendingProps; + + 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); + } + + return workInProgress.child; +} - return remainingLanes; - } +var hasWarnedAboutUsingNoValuePropOnContextProvider = false; - function updateSuspenseComponent(current, workInProgress, renderLanes) { - var nextProps = workInProgress.pendingProps; // This is used by DevTools to force a boundary to suspend. +function updateContextProvider(current, workInProgress, renderLanes) { + var context; - { - if (shouldSuspend(workInProgress)) { - workInProgress.flags |= DidCapture; - } + if (enableRenderableContext) { + context = workInProgress.type; + } else { + context = workInProgress.type._context; + } + + var newProps = workInProgress.pendingProps; + var oldProps = workInProgress.memoizedProps; + var newValue = newProps.value; + + { + 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?'); } + } + } - var showFallback = false; - var didSuspend = (workInProgress.flags & DidCapture) !== NoFlags$1; + pushProvider(workInProgress, context, newValue); - if (didSuspend || shouldRemainOnFallback(current)) { - // Something in this boundary's subtree already suspended. Switch to - // rendering the fallback children. - showFallback = true; - workInProgress.flags &= ~DidCapture; - } // Check if the primary children spawned a deferred task (useDeferredValue) - // during the first pass. + { + if (oldProps !== null) { + var oldValue = oldProps.value; - var didPrimaryChildrenDefer = - (workInProgress.flags & DidDefer) !== NoFlags$1; - workInProgress.flags &= ~DidDefer; // 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. - - if (current === null) { - var nextPrimaryChildren = nextProps.children; - var nextFallbackChildren = nextProps.fallback; - - if (showFallback) { - pushFallbackTreeSuspenseHandler(workInProgress); - var fallbackFragment = mountSuspenseFallbackChildren( - workInProgress, - nextPrimaryChildren, - nextFallbackChildren, - renderLanes - ); - var primaryChildFragment = workInProgress.child; - primaryChildFragment.memoizedState = - mountSuspenseOffscreenState(renderLanes); - primaryChildFragment.childLanes = getRemainingWorkInPrimaryTree( - current, - didPrimaryChildrenDefer, - renderLanes - ); - workInProgress.memoizedState = SUSPENDED_MARKER; - - 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); - - var _fallbackFragment = mountSuspenseFallbackChildren( - workInProgress, - nextPrimaryChildren, - nextFallbackChildren, - renderLanes - ); - - var _primaryChildFragment = workInProgress.child; - _primaryChildFragment.memoizedState = - mountSuspenseOffscreenState(renderLanes); - _primaryChildFragment.childLanes = getRemainingWorkInPrimaryTree( - current, - didPrimaryChildrenDefer, - 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 = SomeRetryLane; - return _fallbackFragment; - } else { - pushPrimaryTreeSuspenseHandler(workInProgress); - return mountSuspensePrimaryChildren( - workInProgress, - nextPrimaryChildren - ); + 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 { - // This is an update. - // Special path for hydration - var prevState = current.memoizedState; + // The context value changed. Search for matching consumers and schedule + // them to update. + propagateContextChange(workInProgress, context, renderLanes); + } + } + } - if (prevState !== null) { - var _dehydrated = prevState.dehydrated; - - if (_dehydrated !== null) { - return updateDehydratedSuspenseComponent( - current, - workInProgress, - didSuspend, - didPrimaryChildrenDefer, - nextProps, - _dehydrated, - prevState, - renderLanes - ); - } - } + var newChildren = newProps.children; + reconcileChildren(current, workInProgress, newChildren, renderLanes); + return workInProgress.child; +} - 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); - - _primaryChildFragment2.childLanes = getRemainingWorkInPrimaryTree( - current, - didPrimaryChildrenDefer, - renderLanes - ); - workInProgress.memoizedState = SUSPENDED_MARKER; - return fallbackChildFragment; - } else { - pushPrimaryTreeSuspenseHandler(workInProgress); - var _nextPrimaryChildren2 = nextProps.children; +function updateContextConsumer(current, workInProgress, renderLanes) { + var context; - var _primaryChildFragment3 = updateSuspensePrimaryChildren( - current, - workInProgress, - _nextPrimaryChildren2, - renderLanes - ); + if (enableRenderableContext) { + var consumerType = workInProgress.type; + context = consumerType._context; + } else { + context = workInProgress.type; - workInProgress.memoizedState = null; - return _primaryChildFragment3; - } + { + if (context._context !== undefined) { + context = context._context; } } + } - 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; - } + var newProps = workInProgress.pendingProps; + var render = newProps.children; - function mountSuspenseFallbackChildren( - workInProgress, - primaryChildren, - fallbackChildren, - 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; - - 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; - } - - 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; + { + 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 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; - } - - primaryChildFragment.return = workInProgress; - primaryChildFragment.sibling = null; + prepareToReadContext(workInProgress, renderLanes); + var newValue = readContext(context); - if (currentFallbackChildFragment !== null) { - // Delete the fallback child fragment - var deletions = workInProgress.deletions; + { + markComponentRenderStarted(workInProgress); + } - if (deletions === null) { - workInProgress.deletions = [currentFallbackChildFragment]; - workInProgress.flags |= ChildDeletion; - } else { - deletions.push(currentFallbackChildFragment); - } - } + var newChildren; - workInProgress.child = primaryChildFragment; - return primaryChildFragment; - } + { + ReactSharedInternals.owner = workInProgress; + setIsRendering(true); + newChildren = render(newValue); + setIsRendering(false); + } - 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 ( - // 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 (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 { - 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.) + { + markComponentRenderStopped(); + } // React DevTools reads this flag. - primaryChildFragment.subtreeFlags = - currentPrimaryChildFragment.subtreeFlags & StaticMask; - } - var fallbackChildFragment; + workInProgress.flags |= PerformedWork; + reconcileChildren(current, workInProgress, newChildren, renderLanes); + return workInProgress.child; +} - 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. +function markWorkInProgressReceivedUpdate() { + didReceiveUpdate = true; +} - fallbackChildFragment.flags |= Placement; - } +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 - fallbackChildFragment.return = workInProgress; - primaryChildFragment.return = workInProgress; - primaryChildFragment.sibling = fallbackChildFragment; - workInProgress.child = primaryChildFragment; - return fallbackChildFragment; + workInProgress.flags |= Placement; } + } +} - function retrySuspenseComponentWithoutHydrating( - current, - workInProgress, - renderLanes - ) { - // 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. - // 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. +function bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes) { + if (current !== null) { + // Reuse previous dependencies + workInProgress.dependencies = current.dependencies; + } - primaryChildFragment.flags |= Placement; - workInProgress.memoizedState = null; - return primaryChildFragment; - } + { + // Don't update "base" render times for bailouts. + stopProfilerTimerIfRunning(); + } - 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; - - 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); - } + markSkippedUpdateLanes(workInProgress.lanes); // Check if the children have any pending work. - return fallbackChildFragment; + 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. - function updateDehydratedSuspenseComponent( - current, - workInProgress, - didSuspend, - didPrimaryChildrenDefer, - 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 (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; - var message; - var stack = null; - var componentStack = null; - { - var _getSuspenseInstanceF = - getSuspenseInstanceFallbackErrorDetails(); + cloneChildFibers(current, workInProgress); + return workInProgress.child; +} - digest = _getSuspenseInstanceF.digest; - message = _getSuspenseInstanceF.message; - stack = _getSuspenseInstanceF.stack; - componentStack = _getSuspenseInstanceF.componentStack; - } // TODO: Figure out a better signal than encoding a magic digest value. +function remountFiber(current, oldWorkInProgress, newWorkInProgress) { + { + var returnFiber = oldWorkInProgress.return; - { - var error; + 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 (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." - ); - } // Replace the stack with the server stack - - error.stack = stack || ""; - error.digest = digest; - var capturedValue = createCapturedValueFromError( - error, - componentStack === undefined ? null : componentStack - ); - queueHydrationError(capturedValue); - } - return retrySuspenseComponentWithoutHydrating( - current, - workInProgress, - renderLanes - ); - } - // any context has changed, we need to treat is as if the input might have changed. + current.alternate = null; + oldWorkInProgress.alternate = null; // Connect to the new tree. + + newWorkInProgress.index = oldWorkInProgress.index; + newWorkInProgress.sibling = oldWorkInProgress.sibling; + newWorkInProgress.return = oldWorkInProgress.return; + newWorkInProgress.ref = oldWorkInProgress.ref; - var hasContextChanged = includesSomeLane( - renderLanes, - current.childLanes - ); + { + newWorkInProgress._debugInfo = oldWorkInProgress._debugInfo; + } // Replace the child/sibling pointers above it. - 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(); - if (root !== null) { - var attemptHydrationAtLane = getBumpedLaneForHydration( - root, - renderLanes - ); + if (oldWorkInProgress === returnFiber.child) { + returnFiber.child = newWorkInProgress; + } else { + var prevSibling = returnFiber.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; - enqueueConcurrentRenderForLane(current, attemptHydrationAtLane); - scheduleUpdateOnFiber(root, current, attemptHydrationAtLane); // 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 (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 - 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. - - if (isSuspenseInstancePending()); - else { - renderDidSuspendDelayIfPossible(); - } - return retrySuspenseComponentWithoutHydrating( - current, - workInProgress, - renderLanes - ); - } 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. - - workInProgress.child = current.child; // Register a callback to retry this boundary once the server has sent the result. - - 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. - - 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. - // The error should've already been logged in throwException. - pushPrimaryTreeSuspenseHandler(workInProgress); - workInProgress.flags &= ~ForceClientRender; - return retrySuspenseComponentWithoutHydrating( - current, - workInProgress, - renderLanes - ); - } 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. + while (prevSibling.sibling !== oldWorkInProgress) { + // $FlowFixMe[incompatible-use] found when upgrading Flow + prevSibling = prevSibling.sibling; - 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); - _primaryChildFragment4.childLanes = getRemainingWorkInPrimaryTree( - current, - didPrimaryChildrenDefer, - renderLanes - ); - workInProgress.memoizedState = SUSPENDED_MARKER; - return fallbackChildFragment; + 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 - function scheduleSuspenseWorkOnFiber(fiber, renderLanes, propagationRoot) { - fiber.lanes = mergeLanes(fiber.lanes, renderLanes); - var alternate = fiber.alternate; - if (alternate !== null) { - alternate.lanes = mergeLanes(alternate.lanes, renderLanes); - } + 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; - scheduleContextWorkOnParentPath( - fiber.return, - renderLanes, - propagationRoot - ); + if (deletions === null) { + returnFiber.deletions = [current]; + returnFiber.flags |= ChildDeletion; + } else { + deletions.push(current); } - 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; + newWorkInProgress.flags |= Placement; // Restart work from the new fiber. - while (node !== null) { - if (node.tag === SuspenseComponent) { - var state = node.memoizedState; + return newWorkInProgress; + } +} - 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; - } +function checkScheduledUpdateOrContext(current, renderLanes) { + // Before performing an early bailout, we must check if there are pending + // updates or context. + var updateLanes = current.lanes; - if (node === workInProgress) { - return; - } // $FlowFixMe[incompatible-use] found when upgrading Flow + if (includesSomeLane(updateLanes, renderLanes)) { + return true; + } // No pending update, but because context is propagated lazily, we need - while (node.sibling === null) { - // $FlowFixMe[incompatible-use] found when upgrading Flow - if (node.return === null || node.return === workInProgress) { - return; - } + return false; +} - node = node.return; - } // $FlowFixMe[incompatible-use] found when upgrading Flow +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); - node.sibling.return = node.return; - node = node.sibling; + { + var cache = current.memoizedState.cache; + pushCacheProvider(workInProgress, cache); } - } + break; - 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; + case HostSingleton: + case HostComponent: + pushHostContext(workInProgress); + break; - while (row !== null) { - var currentRow = row.alternate; // New rows can't be content rows. + case ClassComponent: + { + var Component = workInProgress.type; - if (currentRow !== null && findFirstSuspended(currentRow) === null) { - lastContentRow = row; + if (isContextProvider(Component)) { + pushContextProvider(workInProgress); } - row = row.sibling; + break; } - return lastContentRow; - } + case HostPortal: + pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); + break; - function validateRevealOrder(revealOrder) { + case ContextProvider: { - if ( - revealOrder !== undefined && - revealOrder !== "forwards" && - revealOrder !== "backwards" && - revealOrder !== "together" && - !didWarnAboutRevealOrder[revealOrder] - ) { - didWarnAboutRevealOrder[revealOrder] = true; - - 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 newValue = workInProgress.memoizedProps.value; + var context; - 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() - ); + if (enableRenderableContext) { + context = workInProgress.type; + } else { + context = workInProgress.type._context; + } - break; - } + pushProvider(workInProgress, context, newValue); + break; + } - default: - error( - '"%s" is not a supported revealOrder on . ' + - 'Did you mean "together", "forwards" or "backwards"?', - revealOrder - ); + case Profiler: + { + // Profiler should only call onRender when one of its descendants actually rendered. + var hasChildWork = includesSomeLane(renderLanes, workInProgress.childLanes); - break; - } - } else { - error( - "%s is not a supported value for revealOrder on . " + - 'Did you mean "together", "forwards" or "backwards"?', - revealOrder - ); - } + if (hasChildWork) { + workInProgress.flags |= Update; } - } - } - function validateTailOptions(tailMode, revealOrder) { - { - 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; - - error( - ' is only valid if revealOrder is ' + - '"forwards" or "backwards". ' + - 'Did you mean to specify revealOrder="forwards"?', - tailMode - ); - } + { + // 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; } } - } - function validateSuspenseListNestedChild(childSlot, index) { + break; + + case SuspenseComponent: { - var isAnArray = isArray(childSlot); - var isIterable = - !isAnArray && typeof getIteratorFn(childSlot) === "function"; - - if (isAnArray || isIterable) { - var type = isAnArray ? "array" : "iterable"; - - error( - "A nested %s was passed to row #%s in . Wrap it in " + - "an additional SuspenseList to configure its revealOrder: " + - " ... " + - "{%s} ... " + - "", - type, - index, - type - ); + var state = workInProgress.memoizedState; - return false; - } - } + 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. - return true; - } + workInProgress.flags |= DidCapture; // We should never render the children of a dehydrated boundary until we + // upgrade it. We return null instead of bailoutOnAlreadyFinishedWork. - 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); + 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. - if (typeof iteratorFn === "function") { - var childrenIterator = iteratorFn.call(children); - if (childrenIterator) { - var step = childrenIterator.next(); - var _i = 0; + var primaryChildFragment = workInProgress.child; + var primaryChildLanes = primaryChildFragment.childLanes; - for (; !step.done; step = childrenIterator.next()) { - if (!validateSuspenseListNestedChild(step.value, _i)) { - return; - } + 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. - _i++; - } - } + var child = bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); + + if (child !== null) { + // The fallback children have pending work. Skip over the + // primary children and work on the fallback. + return child.sibling; } 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 - ); + // 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); } + + break; } - } - function initSuspenseListRenderState( - workInProgress, - isBackwards, - tail, - lastContentRow, - tailMode - ) { - var renderState = workInProgress.memoizedState; + case SuspenseListComponent: + { + var didSuspendBefore = (current.flags & DidCapture) !== NoFlags$1; - 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. - - 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 (shouldForceFallback) { - suspenseContext = setShallowSuspenseListContext( - suspenseContext, - ForceSuspenseFallback - ); - workInProgress.flags |= DidCapture; - } else { - var didSuspendBefore = - current !== null && (current.flags & DidCapture) !== NoFlags$1; + var _hasChildWork = includesSomeLane(renderLanes, workInProgress.childLanes); 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 - ); - } - - suspenseContext = setDefaultShallowSuspenseListContext(suspenseContext); - } - - 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; - } + 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. - initSuspenseListRenderState( - workInProgress, - false, // isBackwards - tail, - lastContentRow, - tailMode - ); - break; - } - 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; + 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. - while (row !== null) { - var currentRow = row.alternate; // New rows can't be content rows. - if ( - currentRow !== null && - findFirstSuspended(currentRow) === null - ) { - // This is the beginning of the main content. - workInProgress.child = row; - break; - } + var renderState = workInProgress.memoizedState; - var nextRow = row.sibling; - row.sibling = _tail; - _tail = row; - row = nextRow; - } // TODO: If workInProgress.child is null, we can continue on the tail immediately. - - initSuspenseListRenderState( - workInProgress, - true, // isBackwards - _tail, - null, // last - tailMode - ); - break; - } + 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; + } - case "together": { - initSuspenseListRenderState( - workInProgress, - false, // isBackwards - null, // tail - null, // last - undefined - ); - break; - } + pushSuspenseListContext(workInProgress, suspenseStackCursor.current); - default: { - // The default reveal order is the same as not having - // a boundary. - workInProgress.memoizedState = null; - } + 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; } } - return workInProgress.child; - } + 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); + } - function updatePortalComponent(current, workInProgress, renderLanes) { - pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); - var nextChildren = workInProgress.pendingProps; - - 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); + case CacheComponent: + { + { + var _cache = current.memoizedState.cache; + pushCacheProvider(workInProgress, _cache); + } + + break; } + } + + return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); +} - return workInProgress.child; +function beginWork(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)); } + } - var hasWarnedAboutUsingNoValuePropOnContextProvider = false; + if (current !== null) { + var oldProps = current.memoizedProps; + var newProps = workInProgress.pendingProps; - function updateContextProvider(current, workInProgress, renderLanes) { - var context; + 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); + + 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 (enableRenderableContext) { - context = workInProgress.type; + 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 { - context = workInProgress.type._context; + // 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. - var newProps = workInProgress.pendingProps; - var oldProps = workInProgress.memoizedProps; - var newValue = newProps.value; - { - if (!("value" in newProps)) { - if (!hasWarnedAboutUsingNoValuePropOnContextProvider) { - hasWarnedAboutUsingNoValuePropOnContextProvider = true; + workInProgress.lanes = NoLanes; - error( - "The `value` prop is required for the ``. Did you misspell it or forget to pass it?" - ); - } - } + switch (workInProgress.tag) { + case LazyComponent: + { + var elementType = workInProgress.elementType; + return mountLazyComponent(current, workInProgress, elementType, renderLanes); } - pushProvider(workInProgress, context, newValue); - + case FunctionComponent: { - if (oldProps !== null) { - var oldValue = oldProps.value; - - 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); - } - } + var Component = workInProgress.type; + var unresolvedProps = workInProgress.pendingProps; + var resolvedProps = disableDefaultPropsExceptForClasses || workInProgress.elementType === Component ? unresolvedProps : resolveDefaultPropsOnNonClassComponent(Component, unresolvedProps); + return updateFunctionComponent(current, workInProgress, Component, resolvedProps, renderLanes); } - var newChildren = newProps.children; - reconcileChildren(current, workInProgress, newChildren, renderLanes); - return workInProgress.child; - } - - function updateContextConsumer(current, workInProgress, renderLanes) { - var context; + case ClassComponent: + { + var _Component = workInProgress.type; + var _unresolvedProps = workInProgress.pendingProps; - if (enableRenderableContext) { - var consumerType = workInProgress.type; - context = consumerType._context; - } else { - context = workInProgress.type; + var _resolvedProps4 = resolveClassComponentProps(_Component, _unresolvedProps, workInProgress.elementType === _Component); - { - if (context._context !== undefined) { - context = context._context; - } - } + return updateClassComponent(current, workInProgress, _Component, _resolvedProps4, renderLanes); } - var newProps = workInProgress.pendingProps; - var render = newProps.children; + case HostRoot: + return updateHostRoot(current, workInProgress, renderLanes); - { - 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." - ); - } - } + case HostHoistable: - prepareToReadContext(workInProgress, renderLanes); - var newValue = readContext(context); + // Fall through - { - markComponentRenderStarted(workInProgress); - } + case HostSingleton: - var newChildren; + // Fall through - { - ReactSharedInternals.owner = workInProgress; - setIsRendering(true); - newChildren = render(newValue); - setIsRendering(false); - } + case HostComponent: + return updateHostComponent$1(current, workInProgress, renderLanes); - { - markComponentRenderStopped(); - } // React DevTools reads this flag. + case HostText: + return updateHostText$1(); - workInProgress.flags |= PerformedWork; - reconcileChildren(current, workInProgress, newChildren, renderLanes); - return workInProgress.child; - } + case SuspenseComponent: + return updateSuspenseComponent(current, workInProgress, renderLanes); - function markWorkInProgressReceivedUpdate() { - didReceiveUpdate = true; - } + case HostPortal: + return updatePortalComponent(current, workInProgress, renderLanes); - 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 + case ForwardRef: + { + var type = workInProgress.type; + var _unresolvedProps2 = workInProgress.pendingProps; - workInProgress.flags |= Placement; - } - } - } + var _resolvedProps5 = disableDefaultPropsExceptForClasses || workInProgress.elementType === type ? _unresolvedProps2 : resolveDefaultPropsOnNonClassComponent(type, _unresolvedProps2); - function bailoutOnAlreadyFinishedWork( - current, - workInProgress, - renderLanes - ) { - if (current !== null) { - // Reuse previous dependencies - workInProgress.dependencies = current.dependencies; + return updateForwardRef(current, workInProgress, type, _resolvedProps5, renderLanes); } - { - // Don't update "base" render times for bailouts. - stopProfilerTimerIfRunning(); - } + case Fragment: + return updateFragment(current, workInProgress, renderLanes); - markSkippedUpdateLanes(workInProgress.lanes); // Check if the children have any pending work. + case Mode: + return updateMode(current, workInProgress, 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; - } - } // This fiber doesn't have work, but its subtree does. Clone the child - // fibers and continue. + case Profiler: + return updateProfiler(current, workInProgress, renderLanes); - cloneChildFibers(current, workInProgress); - return workInProgress.child; - } + case ContextProvider: + return updateContextProvider(current, workInProgress, renderLanes); - function remountFiber(current, oldWorkInProgress, newWorkInProgress) { - { - var returnFiber = oldWorkInProgress.return; + case ContextConsumer: + return updateContextConsumer(current, workInProgress, renderLanes); - 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. + case MemoComponent: + { + var _type = workInProgress.type; + var _unresolvedProps3 = workInProgress.pendingProps; // Resolve outer props first, then resolve inner props. - current.alternate = null; - oldWorkInProgress.alternate = null; // Connect to the new tree. + var _resolvedProps6 = disableDefaultPropsExceptForClasses ? _unresolvedProps3 : resolveDefaultPropsOnNonClassComponent(_type, _unresolvedProps3); - newWorkInProgress.index = oldWorkInProgress.index; - newWorkInProgress.sibling = oldWorkInProgress.sibling; - newWorkInProgress.return = oldWorkInProgress.return; - newWorkInProgress.ref = oldWorkInProgress.ref; + _resolvedProps6 = disableDefaultPropsExceptForClasses ? _resolvedProps6 : resolveDefaultPropsOnNonClassComponent(_type.type, _resolvedProps6); + return updateMemoComponent(current, workInProgress, _type, _resolvedProps6, renderLanes); + } - { - newWorkInProgress._debugInfo = oldWorkInProgress._debugInfo; - } // Replace the child/sibling pointers above it. + case SimpleMemoComponent: + { + return updateSimpleMemoComponent(current, workInProgress, workInProgress.type, workInProgress.pendingProps, renderLanes); + } - if (oldWorkInProgress === returnFiber.child) { - returnFiber.child = newWorkInProgress; - } else { - var prevSibling = returnFiber.child; + case IncompleteClassComponent: + { - 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 + var _Component2 = workInProgress.type; + var _unresolvedProps4 = workInProgress.pendingProps; - while (prevSibling.sibling !== oldWorkInProgress) { - // $FlowFixMe[incompatible-use] found when upgrading Flow - prevSibling = prevSibling.sibling; + var _resolvedProps7 = resolveClassComponentProps(_Component2, _unresolvedProps4, workInProgress.elementType === _Component2); - 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 + return mountIncompleteClassComponent(current, workInProgress, _Component2, _resolvedProps7, renderLanes); + } - prevSibling.sibling = newWorkInProgress; - } // Delete the old fiber and place the new one. - // Since the old fiber is disconnected, we have to schedule it manually. + case IncompleteFunctionComponent: + { - var deletions = returnFiber.deletions; + var _Component3 = workInProgress.type; + var _unresolvedProps5 = workInProgress.pendingProps; - if (deletions === null) { - returnFiber.deletions = [current]; - returnFiber.flags |= ChildDeletion; - } else { - deletions.push(current); - } + var _resolvedProps8 = resolveClassComponentProps(_Component3, _unresolvedProps5, workInProgress.elementType === _Component3); - newWorkInProgress.flags |= Placement; // Restart work from the new fiber. + return mountIncompleteFunctionComponent(current, workInProgress, _Component3, _resolvedProps8, renderLanes); + } - return newWorkInProgress; + case SuspenseListComponent: + { + return updateSuspenseListComponent(current, workInProgress, renderLanes); } - } - function checkScheduledUpdateOrContext(current, renderLanes) { - // Before performing an early bailout, we must check if there are pending - // updates or context. - var updateLanes = current.lanes; + case ScopeComponent: + { - if (includesSomeLane(updateLanes, renderLanes)) { - return true; - } // No pending update, but because context is propagated lazily, we need + break; + } - return false; - } + case OffscreenComponent: + { + return updateOffscreenComponent(current, workInProgress, renderLanes); + } - 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); + case LegacyHiddenComponent: + { - { - var cache = current.memoizedState.cache; - pushCacheProvider(workInProgress, cache); - } - break; + break; + } - case HostSingleton: - case HostComponent: - pushHostContext(workInProgress); - break; + case CacheComponent: + { + { + return updateCacheComponent(current, workInProgress, renderLanes); + } + } + } - case ClassComponent: { - var Component = workInProgress.type; + 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 (isContextProvider(Component)) { - pushContextProvider(workInProgress); - } +var valueCursor = createCursor(null); - break; - } +var renderer2CursorDEV; - case HostPortal: - pushHostContainer( - workInProgress, - workInProgress.stateNode.containerInfo - ); - break; +{ + renderer2CursorDEV = createCursor(null); +} - case ContextProvider: { - var newValue = workInProgress.memoizedProps.value; - var context; +var rendererSigil; - if (enableRenderableContext) { - context = workInProgress.type; - } else { - context = workInProgress.type._context; - } +{ + // Use this to detect multiple renderers using the same context + rendererSigil = {}; +} - pushProvider(workInProgress, context, newValue); - break; - } +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; + + { + isDisallowedContextReadInDEV = false; + } +} +function enterDisallowedContextReadInDEV() { + { + isDisallowedContextReadInDEV = true; + } +} +function exitDisallowedContextReadInDEV() { + { + isDisallowedContextReadInDEV = false; + } +} +function pushProvider(providerFiber, context, nextValue) { + { + push(valueCursor, context._currentValue2, providerFiber); + context._currentValue2 = nextValue; - case Profiler: - { - // Profiler should only call onRender when one of its descendants actually rendered. - var hasChildWork = includesSomeLane( - renderLanes, - workInProgress.childLanes - ); + { + push(renderer2CursorDEV, context._currentRenderer2, providerFiber); - if (hasChildWork) { - workInProgress.flags |= Update; - } + if (context._currentRenderer2 !== undefined && context._currentRenderer2 !== null && context._currentRenderer2 !== rendererSigil) { + error('Detected multiple renderers concurrently rendering the ' + 'same context provider. This is currently unsupported.'); + } - { - // 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; - } - } + context._currentRenderer2 = rendererSigil; + } + } +} +function popProvider(context, providerFiber) { + var currentValue = valueCursor.current; - break; + { + context._currentValue2 = currentValue; - case SuspenseComponent: { - var state = workInProgress.memoizedState; + { + var currentRenderer2 = renderer2CursorDEV.current; + pop(renderer2CursorDEV, providerFiber); + context._currentRenderer2 = currentRenderer2; + } + } - 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. + pop(valueCursor, providerFiber); +} +function scheduleContextWorkOnParentPath(parent, renderLanes, propagationRoot) { + // Update the child lanes of all the ancestors, including the alternates. + var node = parent; - workInProgress.flags |= DidCapture; // We should never render the children of a dehydrated boundary until we - // upgrade it. We return null instead of bailoutOnAlreadyFinishedWork. + while (node !== null) { + var alternate = node.alternate; - 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. + if (!isSubsetOfLanes(node.childLanes, renderLanes)) { + node.childLanes = mergeLanes(node.childLanes, renderLanes); - var primaryChildFragment = workInProgress.child; - var primaryChildLanes = primaryChildFragment.childLanes; - - 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. - - var child = bailoutOnAlreadyFinishedWork( - current, - workInProgress, - renderLanes - ); - - 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 (alternate !== null) { + alternate.childLanes = mergeLanes(alternate.childLanes, renderLanes); + } + } else if (alternate !== null && !isSubsetOfLanes(alternate.childLanes, renderLanes)) { + alternate.childLanes = mergeLanes(alternate.childLanes, renderLanes); + } else ; - break; - } + if (node === propagationRoot) { + break; + } - case SuspenseListComponent: { - var didSuspendBefore = (current.flags & DidCapture) !== NoFlags$1; - - var _hasChildWork = includesSomeLane( - renderLanes, - workInProgress.childLanes - ); - - 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. - - 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. - - var renderState = workInProgress.memoizedState; - - 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; - } + node = node.return; + } - pushSuspenseListContext(workInProgress, suspenseStackCursor.current); + { + 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); + } +} - 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; - } - } +function propagateContextChange_eager(workInProgress, context, renderLanes) { - 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); - } + var fiber = workInProgress.child; - case CacheComponent: { - { - var _cache = current.memoizedState.cache; - pushCacheProvider(workInProgress, _cache); - } + if (fiber !== null) { + // Set the return pointer of the child to the work-in-progress fiber. + fiber.return = workInProgress; + } - break; - } - } + while (fiber !== null) { + var nextFiber = void 0; // Visit this fiber. - return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); - } + var list = fiber.dependencies; - function beginWork(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 (list !== null) { + nextFiber = fiber.child; + var dependency = list.firstContext; - if (current !== null) { - var oldProps = current.memoizedProps; - var newProps = workInProgress.pendingProps; - - 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 - ); - - 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 - ); - } + 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 + + var updateQueue = fiber.updateQueue; + + if (updateQueue === null) ; else { + var sharedQueue = updateQueue.shared; + var pending = sharedQueue.pending; + + if (pending === null) { + // This is the first update. Create a circular list. + update.next = update; + } else { + update.next = pending.next; + pending.next = update; + } - 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; + sharedQueue.pending = update; + } } - } - } 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. - - workInProgress.lanes = NoLanes; - - switch (workInProgress.tag) { - case LazyComponent: { - var elementType = workInProgress.elementType; - return mountLazyComponent( - current, - workInProgress, - elementType, - renderLanes - ); - } - - case FunctionComponent: { - var Component = workInProgress.type; - var unresolvedProps = workInProgress.pendingProps; - var resolvedProps = - disableDefaultPropsExceptForClasses || - workInProgress.elementType === Component - ? unresolvedProps - : resolveDefaultPropsOnNonClassComponent( - Component, - unresolvedProps - ); - return updateFunctionComponent( - current, - workInProgress, - Component, - resolvedProps, - renderLanes - ); - } - - case ClassComponent: { - var _Component = workInProgress.type; - var _unresolvedProps = workInProgress.pendingProps; - - var _resolvedProps4 = resolveClassComponentProps( - _Component, - _unresolvedProps, - workInProgress.elementType === _Component - ); - - return updateClassComponent( - current, - workInProgress, - _Component, - _resolvedProps4, - renderLanes - ); - } - case HostRoot: - return updateHostRoot(current, workInProgress, renderLanes); - - case HostHoistable: + fiber.lanes = mergeLanes(fiber.lanes, renderLanes); + var alternate = fiber.alternate; - // Fall through - - case HostSingleton: + if (alternate !== null) { + alternate.lanes = mergeLanes(alternate.lanes, renderLanes); + } - // Fall through + scheduleContextWorkOnParentPath(fiber.return, renderLanes, workInProgress); // Mark the updated lanes on the list, too. - case HostComponent: - return updateHostComponent$1(current, workInProgress, renderLanes); + list.lanes = mergeLanes(list.lanes, renderLanes); // Since we already found a match, we can stop traversing the + // dependency list. - case HostText: - return updateHostText$1(); + break; + } - case SuspenseComponent: - return updateSuspenseComponent(current, workInProgress, renderLanes); + 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; - case HostPortal: - return updatePortalComponent(current, workInProgress, renderLanes); + 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 ForwardRef: { - var type = workInProgress.type; - var _unresolvedProps2 = workInProgress.pendingProps; + parentSuspense.lanes = mergeLanes(parentSuspense.lanes, renderLanes); + var _alternate = parentSuspense.alternate; - var _resolvedProps5 = - disableDefaultPropsExceptForClasses || - workInProgress.elementType === type - ? _unresolvedProps2 - : resolveDefaultPropsOnNonClassComponent(type, _unresolvedProps2); + 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 updateForwardRef( - current, - workInProgress, - type, - _resolvedProps5, - renderLanes - ); - } - case Fragment: - return updateFragment(current, workInProgress, renderLanes); + scheduleContextWorkOnParentPath(parentSuspense, renderLanes, workInProgress); + nextFiber = fiber.sibling; + } else { + // Traverse down. + nextFiber = fiber.child; + } - case Mode: - return updateMode(current, workInProgress, renderLanes); + 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; - case Profiler: - return updateProfiler(current, workInProgress, renderLanes); - - case ContextProvider: - return updateContextProvider(current, workInProgress, renderLanes); - - case ContextConsumer: - return updateContextConsumer(current, workInProgress, renderLanes); - - case MemoComponent: { - var _type = workInProgress.type; - var _unresolvedProps3 = workInProgress.pendingProps; // Resolve outer props first, then resolve inner props. - - var _resolvedProps6 = disableDefaultPropsExceptForClasses - ? _unresolvedProps3 - : resolveDefaultPropsOnNonClassComponent(_type, _unresolvedProps3); - - _resolvedProps6 = disableDefaultPropsExceptForClasses - ? _resolvedProps6 - : resolveDefaultPropsOnNonClassComponent( - _type.type, - _resolvedProps6 - ); - return updateMemoComponent( - current, - workInProgress, - _type, - _resolvedProps6, - renderLanes - ); - } - - case SimpleMemoComponent: { - return updateSimpleMemoComponent( - current, - workInProgress, - workInProgress.type, - workInProgress.pendingProps, - renderLanes - ); - } - - case IncompleteClassComponent: { - var _Component2 = workInProgress.type; - var _unresolvedProps4 = workInProgress.pendingProps; - - var _resolvedProps7 = resolveClassComponentProps( - _Component2, - _unresolvedProps4, - workInProgress.elementType === _Component2 - ); - - return mountIncompleteClassComponent( - current, - workInProgress, - _Component2, - _resolvedProps7, - renderLanes - ); - } - - case IncompleteFunctionComponent: { - var _Component3 = workInProgress.type; - var _unresolvedProps5 = workInProgress.pendingProps; - - var _resolvedProps8 = resolveClassComponentProps( - _Component3, - _unresolvedProps5, - workInProgress.elementType === _Component3 - ); - - return mountIncompleteFunctionComponent( - current, - workInProgress, - _Component3, - _resolvedProps8, - renderLanes - ); - } - - case SuspenseListComponent: { - return updateSuspenseListComponent( - current, - workInProgress, - renderLanes - ); - } - - case ScopeComponent: { + while (nextFiber !== null) { + if (nextFiber === workInProgress) { + // We're back to the root of this subtree. Exit. + nextFiber = null; break; } - case OffscreenComponent: { - return updateOffscreenComponent(current, workInProgress, renderLanes); - } + var sibling = nextFiber.sibling; - case LegacyHiddenComponent: { + 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. - case CacheComponent: { - { - return updateCacheComponent(current, workInProgress, renderLanes); - } - } - } - throw new Error( - "Unknown unit of work tag (" + - workInProgress.tag + - "). This error is likely caused by a bug in " + - "React. Please file an issue." - ); + nextFiber = nextFiber.return; + } } - var valueCursor = createCursor(null); - - var renderer2CursorDEV; + fiber = nextFiber; + } +} +function prepareToReadContext(workInProgress, renderLanes) { + currentlyRenderingFiber = workInProgress; + lastContextDependency = null; + lastFullyObservedContext = null; + var dependencies = workInProgress.dependencies; + if (dependencies !== null) { { - renderer2CursorDEV = createCursor(null); - } + var firstContext = dependencies.firstContext; - var rendererSigil; - - { - // Use this to detect multiple renderers using the same context - rendererSigil = {}; - } + 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 - 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; - { - isDisallowedContextReadInDEV = false; - } - } - function enterDisallowedContextReadInDEV() { - { - isDisallowedContextReadInDEV = true; + dependencies.firstContext = null; } } - function exitDisallowedContextReadInDEV() { - { - isDisallowedContextReadInDEV = false; - } + } +} +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().'); } - function pushProvider(providerFiber, context, nextValue) { - { - push(valueCursor, context._currentValue2, providerFiber); - context._currentValue2 = nextValue; + } - { - 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 readContextForConsumer(currentlyRenderingFiber, context); +} +function readContextDuringReconciliation(consumer, context, renderLanes) { + if (currentlyRenderingFiber === null) { + prepareToReadContext(consumer, renderLanes); + } - context._currentRenderer2 = rendererSigil; - } - } - } - function popProvider(context, providerFiber) { - var currentValue = valueCursor.current; + return readContextForConsumer(consumer, context); +} - { - context._currentValue2 = currentValue; +function readContextForConsumer(consumer, context) { + var value = context._currentValue2; - { - var currentRenderer2 = renderer2CursorDEV.current; - pop(renderer2CursorDEV, providerFiber); - context._currentRenderer2 = currentRenderer2; - } - } + if (lastFullyObservedContext === context) ; else { + var contextItem = { + context: context, + memoizedValue: value, + next: null + }; - pop(valueCursor, providerFiber); - } - function scheduleContextWorkOnParentPath( - parent, - renderLanes, - propagationRoot - ) { - // Update the child lanes of all the ancestors, including the alternates. - var node = parent; + 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. - while (node !== null) { - var alternate = node.alternate; - if (!isSubsetOfLanes(node.childLanes, renderLanes)) { - node.childLanes = mergeLanes(node.childLanes, renderLanes); + lastContextDependency = contextItem; + consumer.dependencies = { + lanes: NoLanes, + firstContext: contextItem + }; + } else { + // Append a new context item. + lastContextDependency = lastContextDependency.next = contextItem; + } + } - 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 (node === propagationRoot) { - break; - } + return value; +} - node = node.return; - } +// replace it with a lightweight shim that only has the features we use. - { - 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); - } +var AbortControllerLocal = typeof AbortController !== 'undefined' ? AbortController : // $FlowFixMe[missing-this-annot] +// $FlowFixMe[prop-missing] +function AbortControllerShim() { + var listeners = []; + var signal = this.signal = { + aborted: false, + addEventListener: function (type, listener) { + listeners.push(listener); } + }; - function propagateContextChange_eager( - workInProgress, - context, - renderLanes - ) { - var fiber = workInProgress.child; + this.abort = function () { + signal.aborted = true; + listeners.forEach(function (listener) { + return listener(); + }); + }; +} ; // Intentionally not named imports because Rollup would +// use dynamic dispatch for CommonJS interop named imports. + +var scheduleCallback$1 = Scheduler.unstable_scheduleCallback, + NormalPriority = Scheduler.unstable_NormalPriority; +var CacheContext = { + $$typeof: REACT_CONTEXT_TYPE, + // We don't use Consumer/Provider for Cache components. So we'll cheat. + Consumer: null, + Provider: null, + // We'll initialize these at the root. + _currentValue: null, + _currentValue2: null, + _threadCount: 0 +} ; + +{ + CacheContext._currentRenderer = null; + CacheContext._currentRenderer2 = null; +} // Creates a new empty Cache instance with a ref-count of 0. The caller is responsible +// for retaining the cache once it is in use (retainCache), and releasing the cache +// once it is no longer needed (releaseCache). + + +function createCache() { + + var cache = { + controller: new AbortControllerLocal(), + data: new Map(), + refCount: 0 + }; + return cache; +} +function retainCache(cache) { - if (fiber !== null) { - // Set the return pointer of the child to the work-in-progress fiber. - fiber.return = workInProgress; - } + { + if (cache.controller.signal.aborted) { + warn('A cache instance was retained after it was already freed. ' + 'This likely indicates a bug in React.'); + } + } - while (fiber !== null) { - var nextFiber = void 0; // Visit this fiber. + cache.refCount++; +} // Cleanup a cache instance, potentially freeing it if there are no more references - var list = fiber.dependencies; +function releaseCache(cache) { - if (list !== null) { - nextFiber = fiber.child; - var dependency = list.firstContext; + cache.refCount--; - 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 (cache.refCount < 0) { + warn('A cache instance was released after it was already freed. ' + 'This likely indicates a bug in React.'); + } + } - var updateQueue = fiber.updateQueue; + if (cache.refCount === 0) { + scheduleCallback$1(NormalPriority, function () { + cache.controller.abort(); + }); + } +} +function pushCacheProvider(workInProgress, cache) { - if (updateQueue === null); - else { - var sharedQueue = updateQueue.shared; - var pending = sharedQueue.pending; + pushProvider(workInProgress, CacheContext, cache); +} +function popCacheProvider(workInProgress, cache) { - if (pending === null) { - // This is the first update. Create a circular list. - update.next = update; - } else { - update.next = pending.next; - pending.next = update; - } + popProvider(CacheContext, workInProgress); +} - sharedQueue.pending = update; - } - } +function requestCurrentTransition() { + var transition = ReactSharedInternals.T; - fiber.lanes = mergeLanes(fiber.lanes, renderLanes); - var alternate = fiber.alternate; + if (transition !== null) { + // Whenever a transition update is scheduled, register a callback on the + // transition object so we can get the return value of the scope function. + transition._callbacks.add(handleAsyncAction); + } - if (alternate !== null) { - alternate.lanes = mergeLanes(alternate.lanes, renderLanes); - } + return transition; +} - scheduleContextWorkOnParentPath( - fiber.return, - renderLanes, - workInProgress - ); // Mark the updated lanes on the list, too. +function handleAsyncAction(transition, thenable) { + if (enableAsyncActions) { + // This is an async action. + entangleAsyncAction(transition, thenable); + } +} - list.lanes = mergeLanes(list.lanes, renderLanes); // Since we already found a match, we can stop traversing the - // dependency list. +function notifyTransitionCallbacks(transition, returnValue) { + var callbacks = transition._callbacks; + callbacks.forEach(function (callback) { + return callback(transition, returnValue); + }); +} // When retrying a Suspense/Offscreen boundary, we restore the cache that was +// used during the previous render by placing it here, on the stack. - break; - } +var resumedCache = createCursor(null); // During the render/synchronous commit phase, we don't actually process the - 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." - ); - } +function peekCacheFromPool() { + // If we're rendering inside a Suspense boundary that is currently hidden, + // we should use the same cache that we used during the previous render, if + // one exists. - parentSuspense.lanes = mergeLanes(parentSuspense.lanes, renderLanes); - var _alternate = parentSuspense.alternate; - - 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. - - scheduleContextWorkOnParentPath( - parentSuspense, - renderLanes, - workInProgress - ); - nextFiber = fiber.sibling; - } else { - // Traverse down. - nextFiber = fiber.child; - } - 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; + var cacheResumedFromPreviousRender = resumedCache.current; - while (nextFiber !== null) { - if (nextFiber === workInProgress) { - // We're back to the root of this subtree. Exit. - nextFiber = null; - break; - } + if (cacheResumedFromPreviousRender !== null) { + return cacheResumedFromPreviousRender; + } // Otherwise, check the root's cache pool. - 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. + var root = getWorkInProgressRoot(); + var cacheFromRootCachePool = root.pooledCache; + return cacheFromRootCachePool; +} - nextFiber = nextFiber.return; - } - } +function requestCacheFromPool(renderLanes) { + // Similar to previous function, except if there's not already a cache in the + // pool, we allocate a new one. + var cacheFromPool = peekCacheFromPool(); + + if (cacheFromPool !== null) { + return cacheFromPool; + } // Create a fresh cache and add it to the root cache pool. A cache can have + // multiple owners: + // - A cache pool that lives on the FiberRoot. This is where all fresh caches + // are originally created (TODO: except during refreshes, until we implement + // this correctly). The root takes ownership immediately when the cache is + // created. Conceptually, root.pooledCache is an Option> (owned), + // and the return value of this function is a &Arc (borrowed). + // - One of several fiber types: host root, cache boundary, suspense + // component. These retain and release in the commit phase. + + + var root = getWorkInProgressRoot(); + var freshCache = createCache(); + root.pooledCache = freshCache; + retainCache(freshCache); + + if (freshCache !== null) { + root.pooledCacheLanes |= renderLanes; + } + + return freshCache; +} +function pushTransition(offscreenWorkInProgress, prevCachePool, newTransitions) { + { + if (prevCachePool === null) { + push(resumedCache, resumedCache.current, offscreenWorkInProgress); + } else { + push(resumedCache, prevCachePool.pool, offscreenWorkInProgress); + } + } +} +function popTransition(workInProgress, current) { + if (current !== null) { - fiber = nextFiber; - } + { + pop(resumedCache, workInProgress); } - function prepareToReadContext(workInProgress, renderLanes) { - currentlyRenderingFiber = workInProgress; - lastContextDependency = null; - lastFullyObservedContext = null; - var dependencies = workInProgress.dependencies; + } +} +function getSuspendedCache() { + // cache that would have been used to render fresh data during this render, + // if there was any, so that we can resume rendering with the same cache when + // we receive more data. - if (dependencies !== null) { - { - var firstContext = dependencies.firstContext; - 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 + var cacheFromPool = peekCacheFromPool(); - 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()." - ); - } - } + if (cacheFromPool === null) { + return null; + } - return readContextForConsumer(currentlyRenderingFiber, context); - } - function readContextDuringReconciliation(consumer, context, renderLanes) { - if (currentlyRenderingFiber === null) { - prepareToReadContext(consumer, renderLanes); - } + return { + // We must also save the parent, so that when we resume we can detect + // a refresh. + parent: CacheContext._currentValue2, + pool: cacheFromPool + }; +} +function getOffscreenDeferredCache() { - return readContextForConsumer(consumer, context); - } + var cacheFromPool = peekCacheFromPool(); - function readContextForConsumer(consumer, context) { - var value = context._currentValue2; + if (cacheFromPool === null) { + return null; + } - if (lastFullyObservedContext === context); - else { - var contextItem = { - context: context, - memoizedValue: value, - next: null - }; + return { + // We must also store the parent, so that when we resume we can detect + // a refresh. + parent: CacheContext._currentValue2, + pool: cacheFromPool + }; +} - 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. +/** + * Tag the fiber with an update effect. This turns a Placement into + * a PlacementAndUpdate. + */ - lastContextDependency = contextItem; - consumer.dependencies = { - lanes: NoLanes, - firstContext: contextItem - }; - } else { - // Append a new context item. - lastContextDependency = lastContextDependency.next = contextItem; - } - } +function markUpdate(workInProgress) { + workInProgress.flags |= Update; +} +/** + * In persistent mode, return whether this update needs to clone the subtree. + */ - return value; - } - // replace it with a lightweight shim that only has the features we use. +function doesRequireClone(current, completedWork) { + var didBailout = current !== null && current.child === completedWork.child; - var AbortControllerLocal = - typeof AbortController !== "undefined" - ? AbortController // $FlowFixMe[missing-this-annot] - : // $FlowFixMe[prop-missing] - function AbortControllerShim() { - var listeners = []; - var signal = (this.signal = { - aborted: false, - addEventListener: function (type, listener) { - listeners.push(listener); - } - }); + if (didBailout) { + return false; + } - this.abort = function () { - signal.aborted = true; - listeners.forEach(function (listener) { - return listener(); - }); - }; - }; // Intentionally not named imports because Rollup would - // use dynamic dispatch for CommonJS interop named imports. - - var scheduleCallback$1 = Scheduler.unstable_scheduleCallback, - NormalPriority = Scheduler.unstable_NormalPriority; - var CacheContext = { - $$typeof: REACT_CONTEXT_TYPE, - // We don't use Consumer/Provider for Cache components. So we'll cheat. - Consumer: null, - Provider: null, - // We'll initialize these at the root. - _currentValue: null, - _currentValue2: null, - _threadCount: 0 - }; + if ((completedWork.flags & ChildDeletion) !== NoFlags$1) { + return true; + } // TODO: If we move the `doesRequireClone` call after `bubbleProperties` + // then we only have to check the `completedWork.subtreeFlags`. - { - CacheContext._currentRenderer = null; - CacheContext._currentRenderer2 = null; - } // Creates a new empty Cache instance with a ref-count of 0. The caller is responsible - // for retaining the cache once it is in use (retainCache), and releasing the cache - // once it is no longer needed (releaseCache). - - function createCache() { - var cache = { - controller: new AbortControllerLocal(), - data: new Map(), - refCount: 0 - }; - return cache; + + var child = completedWork.child; + + while (child !== null) { + if ((child.flags & MutationMask) !== NoFlags$1 || (child.subtreeFlags & MutationMask) !== NoFlags$1) { + return true; } - function retainCache(cache) { - { - if (cache.controller.signal.aborted) { - warn( - "A cache instance was retained after it was already freed. " + - "This likely indicates a bug in React." - ); - } - } - cache.refCount++; - } // Cleanup a cache instance, potentially freeing it if there are no more references + child = child.sibling; + } - function releaseCache(cache) { - cache.refCount--; + return false; +} - { - if (cache.refCount < 0) { - warn( - "A cache instance was released after it was already freed. " + - "This likely indicates a bug in React." - ); +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; + + while (_node !== null) { + if (_node.tag === HostComponent) { + var instance = _node.stateNode; + + if (needsVisibilityToggle && isHidden) { + instance = cloneHiddenInstance(instance); } - } - if (cache.refCount === 0) { - scheduleCallback$1(NormalPriority, function () { - cache.controller.abort(); - }); - } - } - function pushCacheProvider(workInProgress, cache) { - pushProvider(workInProgress, CacheContext, cache); - } - function popCacheProvider(workInProgress, cache) { - popProvider(CacheContext, workInProgress); - } + appendInitialChild(parent, instance); + } else if (_node.tag === HostText) { + var _instance = _node.stateNode; - function requestCurrentTransition() { - var transition = ReactSharedInternals.T; + if (needsVisibilityToggle && isHidden) { + _instance = cloneHiddenTextInstance(); + } - if (transition !== null) { - // Whenever a transition update is scheduled, register a callback on the - // transition object so we can get the return value of the scope function. - transition._callbacks.add(handleAsyncAction); - } + 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; - return transition; - } + if (child !== null) { + child.return = _node; + } - function handleAsyncAction(transition, thenable) { - if (enableAsyncActions) { - // This is an async action. - entangleAsyncAction(transition, thenable); + appendAllChildren(parent, _node, + /* needsVisibilityToggle */ + true, + /* isHidden */ + true); + } else if (_node.child !== null) { + _node.child.return = _node; + _node = _node.child; + continue; } - } - - function notifyTransitionCallbacks(transition, returnValue) { - var callbacks = transition._callbacks; - callbacks.forEach(function (callback) { - return callback(transition, returnValue); - }); - } // When retrying a Suspense/Offscreen boundary, we restore the cache that was - // used during the previous render by placing it here, on the stack. - var resumedCache = createCursor(null); // During the render/synchronous commit phase, we don't actually process the + if (_node === workInProgress) { + return; + } // $FlowFixMe[incompatible-use] found when upgrading Flow - function peekCacheFromPool() { - // If we're rendering inside a Suspense boundary that is currently hidden, - // we should use the same cache that we used during the previous render, if - // one exists. - var cacheResumedFromPreviousRender = resumedCache.current; + while (_node.sibling === null) { + // $FlowFixMe[incompatible-use] found when upgrading Flow + if (_node.return === null || _node.return === workInProgress) { + return; + } - if (cacheResumedFromPreviousRender !== null) { - return cacheResumedFromPreviousRender; - } // Otherwise, check the root's cache pool. + _node = _node.return; + } // $FlowFixMe[incompatible-use] found when upgrading Flow - var root = getWorkInProgressRoot(); - var cacheFromRootCachePool = root.pooledCache; - return cacheFromRootCachePool; - } - - function requestCacheFromPool(renderLanes) { - // Similar to previous function, except if there's not already a cache in the - // pool, we allocate a new one. - var cacheFromPool = peekCacheFromPool(); - - if (cacheFromPool !== null) { - return cacheFromPool; - } // Create a fresh cache and add it to the root cache pool. A cache can have - // multiple owners: - // - A cache pool that lives on the FiberRoot. This is where all fresh caches - // are originally created (TODO: except during refreshes, until we implement - // this correctly). The root takes ownership immediately when the cache is - // created. Conceptually, root.pooledCache is an Option> (owned), - // and the return value of this function is a &Arc (borrowed). - // - One of several fiber types: host root, cache boundary, suspense - // component. These retain and release in the commit phase. - var root = getWorkInProgressRoot(); - var freshCache = createCache(); - root.pooledCache = freshCache; - retainCache(freshCache); + _node.sibling.return = _node.return; + _node = _node.sibling; + } + } +} // An unfortunate fork of appendAllChildren because we have two different parent types. - if (freshCache !== null) { - root.pooledCacheLanes |= renderLanes; - } - return freshCache; - } - function pushTransition( - offscreenWorkInProgress, - prevCachePool, - newTransitions - ) { - { - if (prevCachePool === null) { - push(resumedCache, resumedCache.current, offscreenWorkInProgress); - } else { - push(resumedCache, prevCachePool.pool, offscreenWorkInProgress); - } - } - } - function popTransition(workInProgress, current) { - if (current !== null) { - { - pop(resumedCache, workInProgress); - } - } - } - function getSuspendedCache() { - // cache that would have been used to render fresh data during this render, - // if there was any, so that we can resume rendering with the same cache when - // we receive more data. +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; - var cacheFromPool = peekCacheFromPool(); + while (node !== null) { + if (node.tag === HostComponent) { + var instance = node.stateNode; - if (cacheFromPool === null) { - return null; - } + if (needsVisibilityToggle && isHidden) { + instance = cloneHiddenInstance(instance); + } - return { - // We must also save the parent, so that when we resume we can detect - // a refresh. - parent: CacheContext._currentValue2, - pool: cacheFromPool - }; - } - function getOffscreenDeferredCache() { - var cacheFromPool = peekCacheFromPool(); + appendChildToContainerChildSet(containerChildSet, instance); + } else if (node.tag === HostText) { + var _instance2 = node.stateNode; - if (cacheFromPool === null) { - return null; - } + if (needsVisibilityToggle && isHidden) { + _instance2 = cloneHiddenTextInstance(); + } - return { - // We must also store the parent, so that when we resume we can detect - // a refresh. - parent: CacheContext._currentValue2, - pool: cacheFromPool - }; - } + 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; - /** - * Tag the fiber with an update effect. This turns a Placement into - * a PlacementAndUpdate. - */ + if (child !== null) { + child.return = node; + } // If Offscreen is not in manual mode, detached tree is hidden from user space. - function markUpdate(workInProgress) { - workInProgress.flags |= Update; - } - /** - * In persistent mode, return whether this update needs to clone the subtree. - */ - function doesRequireClone(current, completedWork) { - var didBailout = - current !== null && current.child === completedWork.child; + var _needsVisibilityToggle = !isOffscreenManual(node); - if (didBailout) { - return false; + appendAllChildrenToContainer(containerChildSet, node, + /* needsVisibilityToggle */ + _needsVisibilityToggle, + /* isHidden */ + true); + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; } - if ((completedWork.flags & ChildDeletion) !== NoFlags$1) { - return true; - } // TODO: If we move the `doesRequireClone` call after `bubbleProperties` - // then we only have to check the `completedWork.subtreeFlags`. + node = node; - var child = completedWork.child; + if (node === workInProgress) { + return; + } // $FlowFixMe[incompatible-use] found when upgrading Flow - while (child !== null) { - if ( - (child.flags & MutationMask) !== NoFlags$1 || - (child.subtreeFlags & MutationMask) !== NoFlags$1 - ) { - return true; + + while (node.sibling === null) { + // $FlowFixMe[incompatible-use] found when upgrading Flow + if (node.return === null || node.return === workInProgress) { + return; } - child = child.sibling; - } + node = node.return; + } // $FlowFixMe[incompatible-use] found when upgrading Flow - return false; + + node.sibling.return = node.return; + node = node.sibling; } + } +} - 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; +function updateHostContainer(current, workInProgress) { + { + if (doesRequireClone(current, workInProgress)) { + var portalOrRoot = workInProgress.stateNode; + var container = portalOrRoot.containerInfo; + var newChildSet = createContainerChildSet(); // If children might have changed, we have to add them all to the set. - while (_node !== null) { - if (_node.tag === HostComponent) { - var instance = _node.stateNode; + appendAllChildrenToContainer(newChildSet, workInProgress, + /* needsVisibilityToggle */ + false, + /* isHidden */ + false); + portalOrRoot.pendingChildren = newChildSet; // Schedule an update on the container to swap out the container. - if (needsVisibilityToggle && isHidden) { - instance = cloneHiddenInstance(instance); - } + markUpdate(workInProgress); + finalizeContainerChildren(container, newChildSet); + } + } +} - appendInitialChild(parent, instance); - } else if (_node.tag === HostText) { - var _instance = _node.stateNode; +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 requiresClone = doesRequireClone(current, workInProgress); + + if (!requiresClone && _oldProps === newProps) { + // No changes, just reuse the existing instance. + // Note that this might release a previous clone. + workInProgress.stateNode = currentInstance; + return; + } + + getHostContext(); + var newChildSet = null; + + if (requiresClone && passChildrenWhenCloningPersistedNodes) { + newChildSet = createContainerChildSet(); // If children might have changed, we have to add them all to the set. + + appendAllChildrenToContainer(newChildSet, workInProgress, + /* needsVisibilityToggle */ + false, + /* isHidden */ + false); + } + + var newInstance = cloneInstance(currentInstance, type, _oldProps, newProps, !requiresClone, newChildSet); + + if (newInstance === currentInstance) { + // No changes, just reuse the existing instance. + // Note that this might release a previous clone. + workInProgress.stateNode = currentInstance; + return; + } // Certain renderers require commit-time effects for initial mount. + + workInProgress.stateNode = newInstance; + + if (!requiresClone) { + // 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 (!passChildrenWhenCloningPersistedNodes) { + // If children might have changed, we have to add them all to the set. + appendAllChildren(newInstance, workInProgress, + /* needsVisibilityToggle */ + false, + /* isHidden */ + false); + } + } +} // This function must be called 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. +// 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. + + +function preloadInstanceAndSuspendIfNeeded(workInProgress, type, props, renderLanes) { + { + // 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 &= ~MaySuspendCommit; + return; + } // Mark this fiber with a flag. This gets set on all host instances +} - if (needsVisibilityToggle && isHidden) { - _instance = cloneHiddenTextInstance(); - } +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); + } + } +} - 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; +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. - if (child !== null) { - child.return = _node; - } + markUpdate(workInProgress); + } else { + workInProgress.stateNode = current.stateNode; + } + } +} - appendAllChildren( - parent, - _node, - /* needsVisibilityToggle */ - true, - /* isHidden */ - true - ); - } else if (_node.child !== null) { - _node.child.return = _node; - _node = _node.child; - continue; - } +function cutOffTailIfNeeded(renderState, hasRenderedATailFallback) { - if (_node === workInProgress) { - return; - } // $FlowFixMe[incompatible-use] found when upgrading Flow + 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; - while (_node.sibling === null) { - // $FlowFixMe[incompatible-use] found when upgrading Flow - if (_node.return === null || _node.return === workInProgress) { - return; - } + 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. - _node = _node.return; - } // $FlowFixMe[incompatible-use] found when upgrading Flow - _node.sibling.return = _node.return; - _node = _node.sibling; + 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; } + + break; } - } // An unfortunate fork of appendAllChildren because we have two different parent types. - function appendAllChildrenToContainer( - containerChildSet, - workInProgress, - needsVisibilityToggle, - isHidden - ) { + case 'collapsed': { - // 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; + // 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 (node !== null) { - if (node.tag === HostComponent) { - var instance = node.stateNode; - - if (needsVisibilityToggle && isHidden) { - instance = cloneHiddenInstance(instance); - } - - appendChildToContainerChildSet(containerChildSet, instance); - } else if (node.tag === HostText) { - var _instance2 = node.stateNode; + while (_tailNode !== null) { + if (_tailNode.alternate !== null) { + _lastTailNode = _tailNode; + } - if (needsVisibilityToggle && isHidden) { - _instance2 = cloneHiddenTextInstance(); - } + _tailNode = _tailNode.sibling; + } // Next we're simply going to delete all insertions after the + // last rendered item. - 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; - if (child !== null) { - child.return = node; - } // If Offscreen is not in manual mode, detached tree is hidden from user space. - - var _needsVisibilityToggle = !isOffscreenManual(node); - - appendAllChildrenToContainer( - containerChildSet, - node, - /* needsVisibilityToggle */ - _needsVisibilityToggle, - /* isHidden */ - true - ); - } else if (node.child !== null) { - node.child.return = node; - node = node.child; - continue; + 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; + } - node = node; + break; + } + } +} - if (node === workInProgress) { - return; - } // $FlowFixMe[incompatible-use] found when upgrading Flow +function bubbleProperties(completedWork) { + var didBailout = completedWork.alternate !== null && completedWork.alternate.child === completedWork.child; + var newChildLanes = NoLanes; + var subtreeFlags = NoFlags$1; + + 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; - while (node.sibling === null) { - // $FlowFixMe[incompatible-use] found when upgrading Flow - if (node.return === null || node.return === workInProgress) { - return; - } + 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 - node = node.return; - } // $FlowFixMe[incompatible-use] found when upgrading Flow + actualDuration += child.actualDuration; // $FlowFixMe[unsafe-addition] addition with possible null/undefined value - node.sibling.return = node.return; - node = node.sibling; - } + treeBaseDuration += child.treeBaseDuration; + child = child.sibling; } - } - function updateHostContainer(current, workInProgress) { - { - if (doesRequireClone(current, workInProgress)) { - var portalOrRoot = workInProgress.stateNode; - var container = portalOrRoot.containerInfo; - var newChildSet = createContainerChildSet(); // If children might have changed, we have to add them all to the set. - - appendAllChildrenToContainer( - newChildSet, - workInProgress, - /* needsVisibilityToggle */ - false, - /* isHidden */ - false - ); - portalOrRoot.pendingChildren = newChildSet; // Schedule an update on the container to swap out the container. - - markUpdate(workInProgress); - finalizeContainerChildren(container, newChildSet); - } - } - } - - 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. + completedWork.actualDuration = actualDuration; + completedWork.treeBaseDuration = treeBaseDuration; + } else { + var _child = completedWork.child; - var requiresClone = doesRequireClone(current, 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. - if (!requiresClone && _oldProps === newProps) { - // No changes, just reuse the existing instance. - // Note that this might release a previous clone. - workInProgress.stateNode = currentInstance; - return; - } + _child.return = completedWork; + _child = _child.sibling; + } + } - getHostContext(); - var newChildSet = null; + 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; - if (requiresClone && passChildrenWhenCloningPersistedNodes) { - newChildSet = createContainerChildSet(); // If children might have changed, we have to add them all to the set. + 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. - appendAllChildrenToContainer( - newChildSet, - workInProgress, - /* needsVisibilityToggle */ - false, - /* isHidden */ - false - ); - } + subtreeFlags |= _child2.subtreeFlags & StaticMask; + subtreeFlags |= _child2.flags & StaticMask; // $FlowFixMe[unsafe-addition] addition with possible null/undefined value - var newInstance = cloneInstance( - currentInstance, - type, - _oldProps, - newProps, - !requiresClone, - newChildSet - ); + _treeBaseDuration += _child2.treeBaseDuration; + _child2 = _child2.sibling; + } - if (newInstance === currentInstance) { - // No changes, just reuse the existing instance. - // Note that this might release a previous clone. - workInProgress.stateNode = currentInstance; - return; - } // Certain renderers require commit-time effects for initial mount. - - workInProgress.stateNode = newInstance; - - if (!requiresClone) { - // 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 (!passChildrenWhenCloningPersistedNodes) { - // If children might have changed, we have to add them all to the set. - appendAllChildren( - newInstance, - workInProgress, - /* needsVisibilityToggle */ - false, - /* isHidden */ - false - ); - } - } - } // This function must be called 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. - // 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. - - function preloadInstanceAndSuspendIfNeeded( - workInProgress, - type, - props, - renderLanes - ) { - { - // 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 &= ~MaySuspendCommit; - return; - } // Mark this fiber with a flag. This gets set on all host instances - } + completedWork.treeBaseDuration = _treeBaseDuration; + } else { + var _child3 = completedWork.child; - function scheduleRetryEffect(workInProgress, retryQueue) { - var wakeables = retryQueue; + 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 (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); - } - } - } - - 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; - } + 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. + + _child3.return = completedWork; + _child3 = _child3.sibling; } } - 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; + completedWork.subtreeFlags |= subtreeFlags; + } - 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. + completedWork.childLanes = newChildLanes; + return didBailout; +} - 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; - } +function completeDehydratedSuspenseBoundary(current, workInProgress, nextState) { + var wasHydrated = popHydrationState(); - break; - } + 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 "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; + prepareToHydrateHostSuspenseInstance(); + bubbleProperties(workInProgress); - while (_tailNode !== null) { - if (_tailNode.alternate !== null) { - _lastTailNode = _tailNode; - } + { + if ((workInProgress.mode & ProfileMode) !== NoMode) { + var isTimedOutSuspense = nextState !== null; - _tailNode = _tailNode.sibling; - } // Next we're simply going to delete all insertions after the - // last rendered item. + if (isTimedOutSuspense) { + // Don't count time spent in a timed out Suspense subtree as part of the base duration. + var primaryChildFragment = workInProgress.child; - 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; + if (primaryChildFragment !== null) { + // $FlowFixMe[unsafe-arithmetic] Flow doesn't support type casting in combination with the -= operator + workInProgress.treeBaseDuration -= primaryChildFragment.treeBaseDuration; } - } else { - // Detach the insertion after the last node that was already - // inserted. - _lastTailNode.sibling = null; } - - break; } } - } - function bubbleProperties(completedWork) { - var didBailout = - completedWork.alternate !== null && - completedWork.alternate.child === completedWork.child; - var newChildLanes = NoLanes; - var subtreeFlags = NoFlags$1; + return false; + } else { + emitPendingHydrationWarnings(); // We might have reentered this boundary to hydrate it. If so, we need to reset the hydration - 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; + 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. - 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 - - actualDuration += child.actualDuration; // $FlowFixMe[unsafe-addition] addition with possible null/undefined value - - treeBaseDuration += child.treeBaseDuration; - child = child.sibling; - } - completedWork.actualDuration = actualDuration; - completedWork.treeBaseDuration = treeBaseDuration; - } else { - var _child = completedWork.child; + workInProgress.flags |= Update; + bubbleProperties(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. + { + if ((workInProgress.mode & ProfileMode) !== NoMode) { + var _isTimedOutSuspense = nextState !== null; + + if (_isTimedOutSuspense) { + // Don't count time spent in a timed out Suspense subtree as part of the base duration. + var _primaryChildFragment = workInProgress.child; - _child.return = completedWork; - _child = _child.sibling; + if (_primaryChildFragment !== null) { + // $FlowFixMe[unsafe-arithmetic] Flow doesn't support type casting in combination with the -= operator + workInProgress.treeBaseDuration -= _primaryChildFragment.treeBaseDuration; + } } } + } - 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; - - 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. - - subtreeFlags |= _child2.subtreeFlags & StaticMask; - subtreeFlags |= _child2.flags & StaticMask; // $FlowFixMe[unsafe-addition] addition with possible null/undefined value - - _treeBaseDuration += _child2.treeBaseDuration; - _child2 = _child2.sibling; - } + 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 - completedWork.treeBaseDuration = _treeBaseDuration; - } else { - var _child3 = completedWork.child; - - 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. - - 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. - - _child3.return = completedWork; - _child3 = _child3.sibling; - } + return true; + } +} + +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 IncompleteFunctionComponent: + + case LazyComponent: + case SimpleMemoComponent: + case FunctionComponent: + case ForwardRef: + case Fragment: + case Mode: + case Profiler: + case ContextConsumer: + case MemoComponent: + bubbleProperties(workInProgress); + return null; + + case ClassComponent: + { + var Component = workInProgress.type; + + if (isContextProvider(Component)) { + popContext(workInProgress); } - completedWork.subtreeFlags |= subtreeFlags; + bubbleProperties(workInProgress); + return null; } - completedWork.childLanes = newChildLanes; - return didBailout; - } + case HostRoot: + { + var fiberRoot = workInProgress.stateNode; - function completeDehydratedSuspenseBoundary( - current, - workInProgress, - nextState - ) { - var wasHydrated = popHydrationState(); + { + var previousCache = null; - 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." - ); + if (current !== null) { + previousCache = current.memoizedState.cache; } - prepareToHydrateHostSuspenseInstance(); - bubbleProperties(workInProgress); - - { - if ((workInProgress.mode & ProfileMode) !== NoMode) { - var isTimedOutSuspense = nextState !== 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 cache = workInProgress.memoizedState.cache; - if (primaryChildFragment !== null) { - // $FlowFixMe[unsafe-arithmetic] Flow doesn't support type casting in combination with the -= operator - workInProgress.treeBaseDuration -= - primaryChildFragment.treeBaseDuration; - } - } - } + if (cache !== previousCache) { + // Run passive effects to retain/release the cache. + workInProgress.flags |= Passive$1; } - return false; - } else { - emitPendingHydrationWarnings(); // We might have reentered this boundary to hydrate it. If so, we need to reset the hydration + popCacheProvider(workInProgress); + } + popHostContainer(workInProgress); + popTopLevelContextObject(workInProgress); - 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. + if (fiberRoot.pendingContext) { + fiberRoot.context = fiberRoot.pendingContext; + fiberRoot.pendingContext = null; + } - workInProgress.flags |= Update; - bubbleProperties(workInProgress); + 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 ((workInProgress.mode & ProfileMode) !== NoMode) { - var _isTimedOutSuspense = nextState !== null; + if (wasHydrated) { + emitPendingHydrationWarnings(); // If we hydrated, then we'll need to schedule an update for + // the commit side-effects on the root. - if (_isTimedOutSuspense) { - // Don't count time spent in a timed out Suspense subtree as part of the base duration. - var _primaryChildFragment = workInProgress.child; + markUpdate(workInProgress); + } else { + if (current !== null) { + var prevState = current.memoizedState; - if (_primaryChildFragment !== null) { - // $FlowFixMe[unsafe-arithmetic] Flow doesn't support type casting in combination with the -= operator - workInProgress.treeBaseDuration -= - _primaryChildFragment.treeBaseDuration; - } + 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. + + upgradeHydrationErrorsToRecoverable(); } } } - - 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 - return true; + updateHostContainer(current, workInProgress); + bubbleProperties(workInProgress); + + return null; } - } - function completeWork(current, workInProgress, renderLanes) { - var newProps = workInProgress.pendingProps; // Note: This intentionally doesn't check if we're hydrating because comparing + case HostHoistable: - switch (workInProgress.tag) { - case IncompleteFunctionComponent: + case HostSingleton: - case LazyComponent: - case SimpleMemoComponent: - case FunctionComponent: - case ForwardRef: - case Fragment: - case Mode: - case Profiler: - case ContextConsumer: - case MemoComponent: - bubbleProperties(workInProgress); - return null; + case HostComponent: + { + popHostContext(workInProgress); + var _type2 = workInProgress.type; + + if (current !== null && workInProgress.stateNode != null) { + updateHostComponent(current, workInProgress, _type2, newProps); + } 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. - case ClassComponent: { - var Component = workInProgress.type; - if (isContextProvider(Component)) { - popContext(workInProgress); + bubbleProperties(workInProgress); + return null; } - bubbleProperties(workInProgress); - return null; - } + var _currentHostContext = 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. - case HostRoot: { - var fiberRoot = workInProgress.stateNode; - { - var previousCache = null; + var _wasHydrated2 = popHydrationState(); - if (current !== null) { - previousCache = current.memoizedState.cache; - } + if (_wasHydrated2) { + // TODO: Move this and createInstance step into the beginPhase + // to consolidate. + prepareToHydrateHostInstance(); + } else { + var _rootContainerInstance = getRootHostContainer(); - var cache = workInProgress.memoizedState.cache; + var _instance3 = createInstance(_type2, newProps, _rootContainerInstance, _currentHostContext, workInProgress); // TODO: For persistent renderers, we should pass children as part + // of the initial instance creation - if (cache !== previousCache) { - // Run passive effects to retain/release the cache. - workInProgress.flags |= Passive$1; - } - popCacheProvider(workInProgress); + appendAllChildren(_instance3, workInProgress, false, false); + workInProgress.stateNode = _instance3; // Certain renderers require commit-time effects for initial mount. } - popHostContainer(workInProgress); - popTopLevelContextObject(workInProgress); + } - if (fiberRoot.pendingContext) { - fiberRoot.context = fiberRoot.pendingContext; - fiberRoot.pendingContext = null; - } + 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. - 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(); + preloadInstanceAndSuspendIfNeeded(workInProgress); + return null; + } - if (wasHydrated) { - emitPendingHydrationWarnings(); // If we hydrated, then we'll need to schedule an update for - // the commit side-effects on the root. + case HostText: + { + var newText = newProps; - markUpdate(workInProgress); - } else { - if (current !== null) { - var prevState = current.memoizedState; - - 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. - - upgradeHydrationErrorsToRecoverable(); - } - } - } - } + 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. - updateHostContainer(current, workInProgress); - bubbleProperties(workInProgress); + 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. - return null; - } + } - case HostHoistable: + var _rootContainerInstance2 = getRootHostContainer(); - case HostSingleton: + var _currentHostContext2 = getHostContext(); - case HostComponent: { - popHostContext(workInProgress); - var _type2 = workInProgress.type; + var _wasHydrated3 = popHydrationState(); - if (current !== null && workInProgress.stateNode != null) { - updateHostComponent(current, workInProgress, _type2, newProps); + if (_wasHydrated3) { + prepareToHydrateHostTextInstance(); } 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. - - bubbleProperties(workInProgress); - return null; - } + workInProgress.stateNode = createTextInstance(newText, _rootContainerInstance2, _currentHostContext2, workInProgress); + } + } + + bubbleProperties(workInProgress); + return null; + } + + case SuspenseComponent: + { + 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. - var _currentHostContext = 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. + if (current === null || current.memoizedState !== null && current.memoizedState.dehydrated !== null) { + var fallthroughToNormalSuspensePath = completeDehydratedSuspenseBoundary(current, workInProgress, nextState); - var _wasHydrated2 = popHydrationState(); + if (!fallthroughToNormalSuspensePath) { + if (workInProgress.flags & ForceClientRender) { + popSuspenseHandler(workInProgress); // Special case. There were remaining unhydrated nodes. We treat + // this as a mismatch. Revert to client rendering. - if (_wasHydrated2) { - // TODO: Move this and createInstance step into the beginPhase - // to consolidate. - prepareToHydrateHostInstance(); + return workInProgress; } else { - var _rootContainerInstance = getRootHostContainer(); - - var _instance3 = createInstance( - _type2, - newProps, - _rootContainerInstance, - _currentHostContext, - workInProgress - ); // TODO: For persistent renderers, we should pass children as part - // of the initial instance creation - - appendAllChildren(_instance3, workInProgress, false, false); - workInProgress.stateNode = _instance3; // Certain renderers require commit-time effects for initial mount. - } - } + popSuspenseHandler(workInProgress); // Did not finish hydrating, either because this is the initial + // render or because something suspended. - 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. + return null; + } + } // Continue with the normal Suspense path. - preloadInstanceAndSuspendIfNeeded(workInProgress); - return null; } - case HostText: { - var newText = newProps; + popSuspenseHandler(workInProgress); - 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 ((workInProgress.flags & DidCapture) !== NoFlags$1) { + // Something suspended. Re-render with the fallback children. + workInProgress.lanes = renderLanes; // Do not reset the effect list. - 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. - } + if ((workInProgress.mode & ProfileMode) !== NoMode) { + transferActualDuration(workInProgress); + } // Don't bubble properties in this case. - var _rootContainerInstance2 = getRootHostContainer(); - var _currentHostContext2 = getHostContext(); + return workInProgress; + } - var _wasHydrated3 = popHydrationState(); + var nextDidTimeout = nextState !== null; + var prevDidTimeout = current !== null && current.memoizedState !== null; - if (_wasHydrated3) { - prepareToHydrateHostTextInstance(); - } else { - workInProgress.stateNode = createTextInstance( - newText, - _rootContainerInstance2, - _currentHostContext2, - workInProgress - ); - } - } + if (nextDidTimeout) { + var offscreenFiber = workInProgress.child; + var _previousCache = null; - bubbleProperties(workInProgress); - return null; - } + if (offscreenFiber.alternate !== null && offscreenFiber.alternate.memoizedState !== null && offscreenFiber.alternate.memoizedState.cachePool !== null) { + _previousCache = offscreenFiber.alternate.memoizedState.cachePool.pool; + } - case SuspenseComponent: { - 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. - - if ( - current === null || - (current.memoizedState !== null && - current.memoizedState.dehydrated !== null) - ) { - var fallthroughToNormalSuspensePath = - completeDehydratedSuspenseBoundary( - current, - workInProgress, - nextState - ); - - if (!fallthroughToNormalSuspensePath) { - if (workInProgress.flags & ForceClientRender) { - popSuspenseHandler(workInProgress); // Special case. There were remaining unhydrated nodes. We treat - // this as a mismatch. Revert to client rendering. - - return workInProgress; - } else { - popSuspenseHandler(workInProgress); // Did not finish hydrating, either because this is the initial - // render or because something suspended. + var _cache = null; - return null; - } - } // Continue with the normal Suspense path. + if (offscreenFiber.memoizedState !== null && offscreenFiber.memoizedState.cachePool !== null) { + _cache = offscreenFiber.memoizedState.cachePool.pool; } - popSuspenseHandler(workInProgress); - - if ((workInProgress.flags & DidCapture) !== NoFlags$1) { - // Something suspended. Re-render with the fallback children. - workInProgress.lanes = renderLanes; // Do not reset the effect list. + if (_cache !== _previousCache) { + // Run passive effects to retain/release the cache. + offscreenFiber.flags |= Passive$1; + } + } // If the suspended state of the boundary changes, we need to schedule + // a passive effect, which is when we process the transitions - if ((workInProgress.mode & ProfileMode) !== NoMode) { - transferActualDuration(workInProgress); - } // Don't bubble properties in this case. - return workInProgress; - } + 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 nextDidTimeout = nextState !== null; - var prevDidTimeout = - current !== null && current.memoizedState !== null; if (nextDidTimeout) { - var offscreenFiber = workInProgress.child; - var _previousCache = null; - - if ( - offscreenFiber.alternate !== null && - offscreenFiber.alternate.memoizedState !== null && - offscreenFiber.alternate.memoizedState.cachePool !== null - ) { - _previousCache = - offscreenFiber.alternate.memoizedState.cachePool.pool; - } - - var _cache = null; + var _offscreenFiber2 = workInProgress.child; + _offscreenFiber2.flags |= Visibility; + } + } - if ( - offscreenFiber.memoizedState !== null && - offscreenFiber.memoizedState.cachePool !== null - ) { - _cache = offscreenFiber.memoizedState.cachePool.pool; - } + var retryQueue = workInProgress.updateQueue; + scheduleRetryEffect(workInProgress, retryQueue); - if (_cache !== _previousCache) { - // Run passive effects to retain/release the cache. - offscreenFiber.flags |= Passive$1; - } - } // If the suspended state of the boundary changes, we need to schedule - // a passive effect, which is when we process the transitions - - 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. + bubbleProperties(workInProgress); + { + if ((workInProgress.mode & ProfileMode) !== NoMode) { if (nextDidTimeout) { - var _offscreenFiber2 = workInProgress.child; - _offscreenFiber2.flags |= Visibility; + // 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[unsafe-arithmetic] Flow doesn't support type casting in combination with the -= operator + workInProgress.treeBaseDuration -= primaryChildFragment.treeBaseDuration; + } } } + } - var retryQueue = workInProgress.updateQueue; - scheduleRetryEffect(workInProgress, retryQueue); + return null; + } - bubbleProperties(workInProgress); + case HostPortal: + popHostContainer(workInProgress); + updateHostContainer(current, workInProgress); - { - 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[unsafe-arithmetic] Flow doesn't support type casting in combination with the -= operator - workInProgress.treeBaseDuration -= - primaryChildFragment.treeBaseDuration; - } - } - } - } + bubbleProperties(workInProgress); + return null; - return null; - } + case ContextProvider: + // Pop provider fiber + var context; - case HostPortal: - popHostContainer(workInProgress); - updateHostContainer(current, workInProgress); + if (enableRenderableContext) { + context = workInProgress.type; + } else { + context = workInProgress.type._context; + } - bubbleProperties(workInProgress); - return null; + popProvider(context, workInProgress); + bubbleProperties(workInProgress); + return null; - case ContextProvider: - // Pop provider fiber - var context; + case IncompleteClassComponent: + { + // sequential to ensure this switch is compiled to a jump table. - if (enableRenderableContext) { - context = workInProgress.type; - } else { - context = workInProgress.type._context; - } - popProvider(context, workInProgress); - bubbleProperties(workInProgress); - return null; + var _Component = workInProgress.type; - case IncompleteClassComponent: { - // sequential to ensure this switch is compiled to a jump table. + if (isContextProvider(_Component)) { + popContext(workInProgress); + } - var _Component = workInProgress.type; + bubbleProperties(workInProgress); + return null; + } - if (isContextProvider(_Component)) { - popContext(workInProgress); - } + case SuspenseListComponent: + { + popSuspenseListContext(workInProgress); + var renderState = workInProgress.memoizedState; + if (renderState === null) { + // We're running in the default, "independent" mode. + // We don't do anything in this mode. bubbleProperties(workInProgress); return null; } - case SuspenseListComponent: { - popSuspenseListContext(workInProgress); - var renderState = workInProgress.memoizedState; + var didSuspendAlready = (workInProgress.flags & DidCapture) !== NoFlags$1; + var renderedTail = renderState.rendering; + + 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 (!cannotBeSuspended) { + var row = workInProgress.child; + + while (row !== null) { + var suspended = findFirstSuspended(row); + + 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. + + 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; + } - if (renderState === null) { - // We're running in the default, "independent" mode. - // We don't do anything in this mode. - bubbleProperties(workInProgress); - return null; - } + row = row.sibling; + } + } - var didSuspendAlready = - (workInProgress.flags & DidCapture) !== NoFlags$1; - var renderedTail = renderState.rendering; - - 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 (!cannotBeSuspended) { - var row = workInProgress.child; - - while (row !== null) { - var suspended = findFirstSuspended(row); - - 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. - - 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; - } + 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. + + workInProgress.lanes = SomeRetryLane; + } + } else { + cutOffTailIfNeeded(renderState, false); + } // Next we're going to render the tail. - row = row.sibling; - } - } + } else { + // Append the rendered row to the child list. + if (!didSuspendAlready) { + var _suspended = findFirstSuspended(renderedTail); - if ( - renderState.tail !== null && - now$1() > getRenderTargetTime() + 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 _retryQueue2 = _suspended.updateQueue; + workInProgress.updateQueue = _retryQueue2; + scheduleRetryEffect(workInProgress, _retryQueue2); + cutOffTailIfNeeded(renderState, true); // This might have been modified. + + if (renderState.tail === null && renderState.tailMode === 'hidden' && !renderedTail.alternate && !getIsHydrating() // We don't cut it if we're hydrating. ) { - // 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. - - 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 _retryQueue2 = _suspended.updateQueue; - workInProgress.updateQueue = _retryQueue2; - scheduleRetryEffect(workInProgress, _retryQueue2); - cutOffTailIfNeeded(renderState, true); // This might have been modified. - - 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. - - workInProgress.lanes = SomeRetryLane; - } - } - - 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; - - if (previousSibling !== null) { - previousSibling.sibling = renderedTail; - } else { - workInProgress.child = renderedTail; - } - - renderState.last = renderedTail; + } 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. + + workInProgress.lanes = SomeRetryLane; } } - 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. - - var suspenseContext = suspenseStackCursor.current; - - if (didSuspendAlready) { - suspenseContext = setShallowSuspenseListContext( - suspenseContext, - ForceSuspenseFallback - ); + 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; + + if (previousSibling !== null) { + previousSibling.sibling = renderedTail; } else { - suspenseContext = - setDefaultShallowSuspenseListContext(suspenseContext); + workInProgress.child = renderedTail; } - pushSuspenseListContext(workInProgress, suspenseContext); // Do a pass over the next row. - // Don't bubble properties in this case. - - return next; + renderState.last = renderedTail; } - - bubbleProperties(workInProgress); - return null; - } - - case ScopeComponent: { - break; } - 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 (current !== null) { - var _prevState = current.memoizedState; - var prevIsHidden = _prevState !== null; + 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 (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; - } - } - } + var suspenseContext = suspenseStackCursor.current; - if ( - !nextIsHidden || - (workInProgress.mode & ConcurrentMode) === NoMode - ) { - bubbleProperties(workInProgress); + if (didSuspendAlready) { + suspenseContext = setShallowSuspenseListContext(suspenseContext, ForceSuspenseFallback); } 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.subtreeFlags & (Placement | Update)) { - workInProgress.flags |= Visibility; - } - } + suspenseContext = setDefaultShallowSuspenseListContext(suspenseContext); } - var offscreenQueue = workInProgress.updateQueue; + pushSuspenseListContext(workInProgress, suspenseContext); // Do a pass over the next row. + // Don't bubble properties in this case. - if (offscreenQueue !== null) { - var _retryQueue3 = offscreenQueue.retryQueue; - scheduleRetryEffect(workInProgress, _retryQueue3); - } - - { - var _previousCache2 = null; - - if ( - current !== null && - current.memoizedState !== null && - current.memoizedState.cachePool !== null - ) { - _previousCache2 = current.memoizedState.cachePool.pool; - } + return next; + } - var _cache2 = null; + bubbleProperties(workInProgress); + return null; + } - if ( - workInProgress.memoizedState !== null && - workInProgress.memoizedState.cachePool !== null - ) { - _cache2 = workInProgress.memoizedState.cachePool.pool; - } + case ScopeComponent: + { - if (_cache2 !== _previousCache2) { - // Run passive effects to retain/release the cache. - workInProgress.flags |= Passive$1; - } - } + break; + } - popTransition(workInProgress, current); - return null; - } + 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 - case CacheComponent: { - { - var _previousCache3 = null; + { + if (current !== null) { + var _prevState = current.memoizedState; + var prevIsHidden = _prevState !== null; - if (current !== null) { - _previousCache3 = current.memoizedState.cache; + if (prevIsHidden !== nextIsHidden) { + workInProgress.flags |= Visibility; } - - var _cache3 = workInProgress.memoizedState.cache; - - if (_cache3 !== _previousCache3) { - // Run passive effects to retain/release the cache. - workInProgress.flags |= Passive$1; + } else { + // On initial mount, we only need a Visibility effect if the tree + // is hidden. + if (nextIsHidden) { + workInProgress.flags |= Visibility; } - - popCacheProvider(workInProgress); - bubbleProperties(workInProgress); } - - 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 unwindWork(current, workInProgress, renderLanes) { - switch (workInProgress.tag) { - case ClassComponent: { - var Component = workInProgress.type; - if (isContextProvider(Component)) { - popContext(workInProgress); + 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.subtreeFlags & (Placement | Update)) { + workInProgress.flags |= Visibility; + } } + } - var flags = workInProgress.flags; + var offscreenQueue = workInProgress.updateQueue; - if (flags & ShouldCapture) { - workInProgress.flags = (flags & ~ShouldCapture) | DidCapture; + if (offscreenQueue !== null) { + var _retryQueue3 = offscreenQueue.retryQueue; + scheduleRetryEffect(workInProgress, _retryQueue3); + } - if ((workInProgress.mode & ProfileMode) !== NoMode) { - transferActualDuration(workInProgress); - } + { + var _previousCache2 = null; - return workInProgress; + if (current !== null && current.memoizedState !== null && current.memoizedState.cachePool !== null) { + _previousCache2 = current.memoizedState.cachePool.pool; } - return null; - } + var _cache2 = null; - case HostRoot: { - { - popCacheProvider(workInProgress); + if (workInProgress.memoizedState !== null && workInProgress.memoizedState.cachePool !== null) { + _cache2 = workInProgress.memoizedState.cachePool.pool; } - popHostContainer(workInProgress); - popTopLevelContextObject(workInProgress); - 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. - return null; + if (_cache2 !== _previousCache2) { + // Run passive effects to retain/release the cache. + workInProgress.flags |= Passive$1; + } } - case HostHoistable: - case HostSingleton: - case HostComponent: { - // TODO: popHydrationState - popHostContext(workInProgress); - return null; - } + popTransition(workInProgress, current); + return null; + } - case SuspenseComponent: { - popSuspenseHandler(workInProgress); - var suspenseState = workInProgress.memoizedState; + case CacheComponent: + { + { + var _previousCache3 = null; - 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 (current !== null) { + _previousCache3 = current.memoizedState.cache; } - var _flags2 = workInProgress.flags; - - if (_flags2 & ShouldCapture) { - workInProgress.flags = (_flags2 & ~ShouldCapture) | DidCapture; // Captured a suspense effect. Re-render the boundary. + var _cache3 = workInProgress.memoizedState.cache; - if ((workInProgress.mode & ProfileMode) !== NoMode) { - transferActualDuration(workInProgress); - } - - return workInProgress; + if (_cache3 !== _previousCache3) { + // Run passive effects to retain/release the cache. + workInProgress.flags |= Passive$1; } - return null; + popCacheProvider(workInProgress); + bubbleProperties(workInProgress); } - 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. + return null; + } - return null; - } + case TracingMarkerComponent: + { - case HostPortal: - popHostContainer(workInProgress); - return null; + return null; + } + } - case ContextProvider: - var context; + 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 (enableRenderableContext) { - context = workInProgress.type; - } else { - context = workInProgress.type._context; - } +function unwindWork(current, workInProgress, renderLanes) { - popProvider(context, workInProgress); - return null; + switch (workInProgress.tag) { + case ClassComponent: + { + var Component = workInProgress.type; - case OffscreenComponent: - case LegacyHiddenComponent: { - popSuspenseHandler(workInProgress); - popHiddenContext(workInProgress); - popTransition(workInProgress, current); - var _flags3 = workInProgress.flags; + if (isContextProvider(Component)) { + popContext(workInProgress); + } - if (_flags3 & ShouldCapture) { - workInProgress.flags = (_flags3 & ~ShouldCapture) | DidCapture; // Captured a suspense effect. Re-render the boundary. + var flags = workInProgress.flags; - if ((workInProgress.mode & ProfileMode) !== NoMode) { - transferActualDuration(workInProgress); - } + if (flags & ShouldCapture) { + workInProgress.flags = flags & ~ShouldCapture | DidCapture; - return workInProgress; + if ((workInProgress.mode & ProfileMode) !== NoMode) { + transferActualDuration(workInProgress); } - return null; + return workInProgress; } - case CacheComponent: - { - popCacheProvider(workInProgress); - } + return null; + } - return null; + case HostRoot: + { - case TracingMarkerComponent: - return null; + { + popCacheProvider(workInProgress); + } + popHostContainer(workInProgress); + popTopLevelContextObject(workInProgress); + var _flags = workInProgress.flags; - default: - return null; + 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. + + + return null; } - } - function unwindInterruptedWork(current, interruptedWork, renderLanes) { - switch (interruptedWork.tag) { - case ClassComponent: { - var childContextTypes = interruptedWork.type.childContextTypes; + case HostHoistable: + case HostSingleton: + case HostComponent: + { + // TODO: popHydrationState + popHostContext(workInProgress); + return null; + } - if (childContextTypes !== null && childContextTypes !== undefined) { - popContext(interruptedWork); - } + case SuspenseComponent: + { + popSuspenseHandler(workInProgress); + var suspenseState = workInProgress.memoizedState; - break; + 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.'); + } } - case HostRoot: { - { - popCacheProvider(interruptedWork); + var _flags2 = workInProgress.flags; + + if (_flags2 & ShouldCapture) { + workInProgress.flags = _flags2 & ~ShouldCapture | DidCapture; // Captured a suspense effect. Re-render the boundary. + + if ((workInProgress.mode & ProfileMode) !== NoMode) { + transferActualDuration(workInProgress); } - popHostContainer(interruptedWork); - popTopLevelContextObject(interruptedWork); - break; - } - case HostHoistable: - case HostSingleton: - case HostComponent: { - popHostContext(interruptedWork); - break; + return workInProgress; } - case HostPortal: - popHostContainer(interruptedWork); - break; + return null; + } - case SuspenseComponent: - popSuspenseHandler(interruptedWork); - break; + 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. - case SuspenseListComponent: - popSuspenseListContext(interruptedWork); - break; + return null; + } - case ContextProvider: - var context; + case HostPortal: + popHostContainer(workInProgress); + return null; - if (enableRenderableContext) { - context = interruptedWork.type; - } else { - context = interruptedWork.type._context; - } + case ContextProvider: + var context; - popProvider(context, interruptedWork); - break; + if (enableRenderableContext) { + context = workInProgress.type; + } else { + context = workInProgress.type._context; + } - case OffscreenComponent: - case LegacyHiddenComponent: - popSuspenseHandler(interruptedWork); - popHiddenContext(interruptedWork); - popTransition(interruptedWork, current); - break; + popProvider(context, workInProgress); + return null; - case CacheComponent: - { - popCacheProvider(interruptedWork); - } + case OffscreenComponent: + case LegacyHiddenComponent: + { + popSuspenseHandler(workInProgress); + popHiddenContext(workInProgress); + popTransition(workInProgress, current); + var _flags3 = workInProgress.flags; - break; - } - } + if (_flags3 & ShouldCapture) { + workInProgress.flags = _flags3 & ~ShouldCapture | DidCapture; // Captured a suspense effect. Re-render the boundary. - var didWarnAboutUndefinedSnapshotBeforeUpdate = null; + if ((workInProgress.mode & ProfileMode) !== NoMode) { + transferActualDuration(workInProgress); + } - { - 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; // Used to track if a form needs to be reset at the end of the mutation phase. - var PossiblyWeakSet = typeof WeakSet === "function" ? WeakSet : Set; - var nextEffect = null; // Used for Profiling builds to track updaters. - - var inProgressLanes = null; - var inProgressRoot = null; - - function shouldProfile(current) { - return ( - (current.mode & ProfileMode) !== NoMode && - (getExecutionContext() & CommitContext) !== NoContext - ); - } - - function callComponentWillUnmountWithTimer(current, instance) { - instance.props = resolveClassComponentProps( - current.type, - current.memoizedProps, - current.elementType === current.type - ); - instance.state = current.memoizedState; - - if (shouldProfile(current)) { - try { - startLayoutEffectTimer(); - instance.componentWillUnmount(); - } finally { - recordLayoutEffectDuration(current); + return workInProgress; } - } 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); + return null; } - } // Capture errors so they don't interrupt mounting. - function safelyAttachRef(current, nearestMountedAncestor) { - try { - commitAttachRef(current); - } catch (error) { - captureCommitPhaseError(current, nearestMountedAncestor, error); + case CacheComponent: + { + popCacheProvider(workInProgress); } - } - function safelyDetachRef(current, nearestMountedAncestor) { - var ref = current.ref; - var refCleanup = current.refCleanup; + return null; - if (ref !== null) { - 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; + case TracingMarkerComponent: - if (finishedWork != null) { - finishedWork.refCleanup = null; - } - } - } else if (typeof ref === "function") { - var retVal; + return null; - try { - if (shouldProfile(current)) { - try { - startLayoutEffectTimer(); - retVal = ref(null); - } finally { - recordLayoutEffectDuration(current); - } - } else { - retVal = ref(null); - } - } catch (error) { - captureCommitPhaseError(current, nearestMountedAncestor, error); - } + default: + return null; + } +} - { - 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[incompatible-use] unable to narrow type to RefObject - ref.current = null; +function unwindInterruptedWork(current, interruptedWork, renderLanes) { + + switch (interruptedWork.tag) { + case ClassComponent: + { + var childContextTypes = interruptedWork.type.childContextTypes; + + if (childContextTypes !== null && childContextTypes !== undefined) { + popContext(interruptedWork); } + + break; } - } - function safelyCallDestroy(current, nearestMountedAncestor, destroy) { - try { - destroy(); - } catch (error) { - captureCommitPhaseError(current, nearestMountedAncestor, error); + case HostRoot: + { + + { + popCacheProvider(interruptedWork); + } + popHostContainer(interruptedWork); + popTopLevelContextObject(interruptedWork); + break; } - } - var shouldFireAfterActiveInstanceBlur = false; - function commitBeforeMutationEffects(root, firstChild) { - nextEffect = firstChild; - commitBeforeMutationEffects_begin(); // We no longer need to track the active instance fiber - var shouldFire = shouldFireAfterActiveInstanceBlur; - shouldFireAfterActiveInstanceBlur = false; - return shouldFire; - } + case HostHoistable: + case HostSingleton: + case HostComponent: + { + popHostContext(interruptedWork); + break; + } - function commitBeforeMutationEffects_begin() { - while (nextEffect !== null) { - var fiber = nextEffect; // This phase is only used for beforeActiveInstanceBlur. + case HostPortal: + popHostContainer(interruptedWork); + break; - var child = fiber.child; + case SuspenseComponent: + popSuspenseHandler(interruptedWork); + break; - if ( - (fiber.subtreeFlags & BeforeMutationMask) !== NoFlags$1 && - child !== null - ) { - child.return = fiber; - nextEffect = child; - } else { - commitBeforeMutationEffects_complete(); - } - } - } + case SuspenseListComponent: + popSuspenseListContext(interruptedWork); + break; - function commitBeforeMutationEffects_complete() { - while (nextEffect !== null) { - var fiber = nextEffect; - setCurrentFiber(fiber); + case ContextProvider: + var context; - try { - commitBeforeMutationEffectsOnFiber(fiber); - } catch (error) { - captureCommitPhaseError(fiber, fiber.return, error); - } + if (enableRenderableContext) { + context = interruptedWork.type; + } else { + context = interruptedWork.type._context; + } - resetCurrentFiber(); - var sibling = fiber.sibling; + popProvider(context, interruptedWork); + break; - if (sibling !== null) { - sibling.return = fiber.return; - nextEffect = sibling; - return; - } + case OffscreenComponent: + case LegacyHiddenComponent: + popSuspenseHandler(interruptedWork); + popHiddenContext(interruptedWork); + popTransition(interruptedWork, current); + break; - nextEffect = fiber.return; + case CacheComponent: + { + popCacheProvider(interruptedWork); } - } - function commitBeforeMutationEffectsOnFiber(finishedWork) { - var current = finishedWork.alternate; - var flags = finishedWork.flags; + break; + } +} - if ((flags & Snapshot) !== NoFlags$1) { - setCurrentFiber(finishedWork); - } +var didWarnAboutUndefinedSnapshotBeforeUpdate = null; - switch (finishedWork.tag) { - case FunctionComponent: { - break; - } +{ + 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. - case ForwardRef: - case SimpleMemoComponent: { - break; - } - 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. +var offscreenSubtreeIsHidden = false; +var offscreenSubtreeWasHidden = false; // Used to track if a form needs to be reset at the end of the mutation phase. +var PossiblyWeakSet = typeof WeakSet === 'function' ? WeakSet : Set; +var nextEffect = null; // Used for Profiling builds to track updaters. - { - if ( - !finishedWork.type.defaultProps && - !("ref" in finishedWork.memoizedProps) && - !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" - ); - } +var inProgressLanes = null; +var inProgressRoot = null; - 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" - ); - } - } - } +function shouldProfile(current) { + return (current.mode & ProfileMode) !== NoMode && (getExecutionContext() & CommitContext) !== NoContext; +} - var snapshot = instance.getSnapshotBeforeUpdate( - resolveClassComponentProps( - finishedWork.type, - prevProps, - finishedWork.elementType === finishedWork.type - ), - prevState - ); +function callComponentWillUnmountWithTimer(current, instance) { + instance.props = resolveClassComponentProps(current.type, current.memoizedProps, current.elementType === current.type); + instance.state = current.memoizedState; + + if (shouldProfile(current)) { + try { + startLayoutEffectTimer(); + instance.componentWillUnmount(); + } finally { + recordLayoutEffectDuration(current); + } + } 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. + + +function safelyAttachRef(current, nearestMountedAncestor) { + try { + commitAttachRef(current); + } catch (error) { + captureCommitPhaseError(current, nearestMountedAncestor, error); + } +} - { - var didWarnSet = didWarnAboutUndefinedSnapshotBeforeUpdate; - - 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) - ); - } - } +function safelyDetachRef(current, nearestMountedAncestor) { + var ref = current.ref; + var refCleanup = current.refCleanup; - instance.__reactInternalSnapshotBeforeUpdate = snapshot; - } + if (ref !== null) { + if (typeof refCleanup === 'function') { + try { + if (shouldProfile(current)) { + try { + startLayoutEffectTimer(); + refCleanup(); + } finally { + recordLayoutEffectDuration(current); } - - break; + } 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; - case HostRoot: { - break; + if (finishedWork != null) { + finishedWork.refCleanup = null; } + } + } else if (typeof ref === 'function') { + var retVal; - case HostComponent: - case HostHoistable: - case HostSingleton: - case HostText: - case HostPortal: - case IncompleteClassComponent: - // Nothing to do for these component types - break; - - 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." - ); + try { + if (shouldProfile(current)) { + try { + startLayoutEffectTimer(); + retVal = ref(null); + } finally { + recordLayoutEffectDuration(current); } + } else { + retVal = ref(null); } + } catch (error) { + captureCommitPhaseError(current, nearestMountedAncestor, error); } - if ((flags & Snapshot) !== NoFlags$1) { - resetCurrentFiber(); + { + 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[incompatible-use] unable to narrow type to RefObject + ref.current = null; } + } +} - function commitHookEffectListUnmount( - flags, - finishedWork, - nearestMountedAncestor - ) { - var updateQueue = finishedWork.updateQueue; - var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null; - - if (lastEffect !== null) { - var firstEffect = lastEffect.next; - var effect = firstEffect; - - do { - if ((effect.tag & flags) === flags) { - // Unmount - var inst = effect.inst; - var destroy = inst.destroy; +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 + + var shouldFire = shouldFireAfterActiveInstanceBlur; + shouldFireAfterActiveInstanceBlur = false; + return shouldFire; +} - if (destroy !== undefined) { - inst.destroy = undefined; +function commitBeforeMutationEffects_begin() { + while (nextEffect !== null) { + var fiber = nextEffect; // This phase is only used for beforeActiveInstanceBlur. - { - if ((flags & Passive) !== NoFlags) { - markComponentPassiveEffectUnmountStarted(finishedWork); - } else if ((flags & Layout) !== NoFlags) { - markComponentLayoutEffectUnmountStarted(finishedWork); - } - } + var child = fiber.child; - { - if ((flags & Insertion) !== NoFlags) { - setIsRunningInsertionEffect(true); - } - } + if ((fiber.subtreeFlags & BeforeMutationMask) !== NoFlags$1 && child !== null) { + child.return = fiber; + nextEffect = child; + } else { + commitBeforeMutationEffects_complete(); + } + } +} - safelyCallDestroy(finishedWork, nearestMountedAncestor, destroy); +function commitBeforeMutationEffects_complete() { + while (nextEffect !== null) { + var fiber = nextEffect; + setCurrentFiber(fiber); - { - if ((flags & Insertion) !== NoFlags) { - setIsRunningInsertionEffect(false); - } - } + try { + commitBeforeMutationEffectsOnFiber(fiber); + } catch (error) { + captureCommitPhaseError(fiber, fiber.return, error); + } - { - if ((flags & Passive) !== NoFlags) { - markComponentPassiveEffectUnmountStopped(); - } else if ((flags & Layout) !== NoFlags) { - markComponentLayoutEffectUnmountStopped(); - } - } - } - } + resetCurrentFiber(); + var sibling = fiber.sibling; - effect = effect.next; - } while (effect !== firstEffect); - } + if (sibling !== null) { + sibling.return = fiber.return; + nextEffect = sibling; + return; } - function commitHookEffectListMount(flags, finishedWork) { - var updateQueue = finishedWork.updateQueue; - var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null; - - if (lastEffect !== null) { - var firstEffect = lastEffect.next; - var effect = firstEffect; + nextEffect = fiber.return; + } +} - do { - if ((effect.tag & flags) === flags) { - { - if ((flags & Passive) !== NoFlags) { - markComponentPassiveEffectMountStarted(finishedWork); - } else if ((flags & Layout) !== NoFlags) { - markComponentLayoutEffectMountStarted(finishedWork); - } - } // Mount +function commitBeforeMutationEffectsOnFiber(finishedWork) { + var current = finishedWork.alternate; + var flags = finishedWork.flags; - var create = effect.create; + if ((flags & Snapshot) !== NoFlags$1) { + setCurrentFiber(finishedWork); + } - { - if ((flags & Insertion) !== NoFlags) { - setIsRunningInsertionEffect(true); - } - } + switch (finishedWork.tag) { + case FunctionComponent: + { - var inst = effect.inst; - var destroy = create(); - inst.destroy = destroy; + break; + } - { - if ((flags & Insertion) !== NoFlags) { - setIsRunningInsertionEffect(false); - } - } + case ForwardRef: + case SimpleMemoComponent: + { + break; + } - { - if ((flags & Passive) !== NoFlags) { - markComponentPassiveEffectMountStopped(); - } else if ((flags & Layout) !== NoFlags) { - markComponentLayoutEffectMountStopped(); - } - } + 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 (destroy !== undefined && typeof destroy !== "function") { - var hookName = void 0; - - if ((effect.tag & Layout) !== NoFlags$1) { - hookName = "useLayoutEffect"; - } else if ((effect.tag & Insertion) !== NoFlags$1) { - hookName = "useInsertionEffect"; - } else { - hookName = "useEffect"; + if (!finishedWork.type.defaultProps && !('ref' in finishedWork.memoizedProps) && !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'); } - var addendum = void 0; - - 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://react.dev/link/hooks-data-fetching"; - } else { - addendum = " You returned: " + destroy; + 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'); } - - error( - "%s must not return anything besides a function, " + - "which is used for clean-up.%s", - hookName, - addendum - ); } } - } - - effect = effect.next; - } while (effect !== firstEffect); - } - } - - 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. - var commitTime = getCommitTime(); - var phase = finishedWork.alternate === null ? "mount" : "update"; + var snapshot = instance.getSnapshotBeforeUpdate(resolveClassComponentProps(finishedWork.type, prevProps, finishedWork.elementType === finishedWork.type), prevState); - { - if (isCurrentUpdateNested()) { - phase = "nested-update"; - } - } + { + var didWarnSet = didWarnAboutUndefinedSnapshotBeforeUpdate; - 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; - } + if (snapshot === undefined && !didWarnSet.has(finishedWork.type)) { + didWarnSet.add(finishedWork.type); - parentFiber = parentFiber.return; + error('%s.getSnapshotBeforeUpdate(): A snapshot value (or null) ' + 'must be returned. You have returned undefined.', getComponentNameFromFiber(finishedWork)); } - - break; } + + instance.__reactInternalSnapshotBeforeUpdate = snapshot; } } + + break; } - } - 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); - } + case HostRoot: + { - recordLayoutEffectDuration(finishedWork); - } else { - try { - commitHookEffectListMount(hookFlags, finishedWork); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } + break; } - } - function commitClassLayoutLifecycles(finishedWork, current) { - var instance = finishedWork.stateNode; + case HostComponent: + case HostHoistable: + case HostSingleton: + case HostText: + case HostPortal: + case IncompleteClassComponent: + // Nothing to do for these component types + break; - 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.defaultProps && - !("ref" in finishedWork.memoizedProps) && - !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 (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" - ); - } - } + 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 (shouldProfile(finishedWork)) { - try { - startLayoutEffectTimer(); - instance.componentDidMount(); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } + if ((flags & Snapshot) !== NoFlags$1) { + resetCurrentFiber(); + } +} - recordLayoutEffectDuration(finishedWork); - } else { - try { - instance.componentDidMount(); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } - } - } else { - var prevProps = resolveClassComponentProps( - finishedWork.type, - current.memoizedProps, - finishedWork.elementType === finishedWork.type - ); - 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. +function commitHookEffectListUnmount(flags, finishedWork, nearestMountedAncestor) { + var updateQueue = finishedWork.updateQueue; + var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null; - { - if ( - !finishedWork.type.defaultProps && - !("ref" in finishedWork.memoizedProps) && - !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 (lastEffect !== null) { + var firstEffect = lastEffect.next; + var effect = firstEffect; - 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" - ); - } - } - } + do { + if ((effect.tag & flags) === flags) { + // Unmount + var inst = effect.inst; + var destroy = inst.destroy; - if (shouldProfile(finishedWork)) { - try { - startLayoutEffectTimer(); - instance.componentDidUpdate( - prevProps, - prevState, - instance.__reactInternalSnapshotBeforeUpdate - ); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } + if (destroy !== undefined) { + inst.destroy = undefined; - recordLayoutEffectDuration(finishedWork); - } else { - try { - instance.componentDidUpdate( - prevProps, - prevState, - instance.__reactInternalSnapshotBeforeUpdate - ); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); + { + if ((flags & Passive) !== NoFlags) { + markComponentPassiveEffectUnmountStarted(finishedWork); + } else if ((flags & Layout) !== NoFlags) { + markComponentLayoutEffectUnmountStarted(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 & Insertion) !== NoFlags) { + setIsRunningInsertionEffect(true); + } + } - if (updateQueue !== null) { - var instance = finishedWork.stateNode; + safelyCallDestroy(finishedWork, nearestMountedAncestor, destroy); - { - if ( - !finishedWork.type.defaultProps && - !("ref" in finishedWork.memoizedProps) && - !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 ((flags & Insertion) !== NoFlags) { + setIsRunningInsertionEffect(false); } + } - 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 & Passive) !== NoFlags) { + markComponentPassiveEffectUnmountStopped(); + } else if ((flags & Layout) !== NoFlags) { + markComponentLayoutEffectUnmountStopped(); } } - } // 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); } } - } - function commitHostComponentMount(finishedWork) { - var type = finishedWork.type; - var props = finishedWork.memoizedProps; - var instance = finishedWork.stateNode; + effect = effect.next; + } while (effect !== firstEffect); + } +} - try { - commitMount(instance, type, props, finishedWork); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } - } +function commitHookEffectListMount(flags, finishedWork) { + var updateQueue = finishedWork.updateQueue; + var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null; - 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"; - } - } + if (lastEffect !== null) { + var firstEffect = lastEffect.next; + var effect = firstEffect; - if (typeof onRender === "function") { - onRender( - finishedWork.memoizedProps.id, - phase, - finishedWork.actualDuration, - finishedWork.treeBaseDuration, - finishedWork.actualStartTime, - commitTime - ); + do { + if ((effect.tag & flags) === flags) { + { + if ((flags & Passive) !== NoFlags) { + markComponentPassiveEffectMountStarted(finishedWork); + } else if ((flags & Layout) !== NoFlags) { + markComponentLayoutEffectMountStarted(finishedWork); } + } // Mount - 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. - - 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. - - var parentFiber = finishedWork.return; - - 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; - } + var create = effect.create; - parentFiber = parentFiber.return; - } + { + if ((flags & Insertion) !== NoFlags) { + setIsRunningInsertionEffect(true); } - } 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; - switch (finishedWork.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); + var inst = effect.inst; + var destroy = create(); + inst.destroy = destroy; - if (flags & Update) { - commitHookLayoutEffects(finishedWork, Layout | HasEffect); + { + if ((flags & Insertion) !== NoFlags) { + setIsRunningInsertionEffect(false); } - - break; } - case ClassComponent: { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); - - if (flags & Update) { - commitClassLayoutLifecycles(finishedWork, current); - } - - if (flags & Callback) { - commitClassCallbacks(finishedWork); - } - - if (flags & Ref) { - safelyAttachRef(finishedWork, finishedWork.return); + { + if ((flags & Passive) !== NoFlags) { + markComponentPassiveEffectMountStopped(); + } else if ((flags & Layout) !== NoFlags) { + markComponentLayoutEffectMountStopped(); } - - 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 (destroy !== undefined && typeof destroy !== 'function') { + var hookName = void 0; - if (finishedWork.child !== null) { - switch (finishedWork.child.tag) { - case HostSingleton: - case HostComponent: - instance = getPublicInstance(finishedWork.child.stateNode); - break; + if ((effect.tag & Layout) !== NoFlags$1) { + hookName = 'useLayoutEffect'; + } else if ((effect.tag & Insertion) !== NoFlags$1) { + hookName = 'useInsertionEffect'; + } else { + hookName = 'useEffect'; + } - case ClassComponent: - instance = finishedWork.child.stateNode; - break; - } - } + var addendum = void 0; - try { - commitCallbacks(updateQueue, instance); - } catch (error) { - captureCommitPhaseError( - finishedWork, - finishedWork.return, - error - ); - } + 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://react.dev/link/hooks-data-fetching'; + } else { + addendum = ' You returned: ' + destroy; } - } - break; + error('%s must not return anything besides a function, ' + 'which is used for clean-up.%s', hookName, addendum); + } } + } - case HostHoistable: - - 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); - } + effect = effect.next; + } while (effect !== firstEffect); + } +} - if (flags & Ref) { - safelyAttachRef(finishedWork, finishedWork.return); - } +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. - break; - } + var commitTime = getCommitTime(); + var phase = finishedWork.alternate === null ? 'mount' : 'update'; - 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 (isCurrentUpdateNested()) { + phase = 'nested-update'; + } + } - if (flags & Update) { - commitProfilerUpdate(finishedWork, current); - } + 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. - break; - } - case SuspenseComponent: { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); + var parentFiber = finishedWork.return; - break; - } + outer: while (parentFiber !== null) { + switch (parentFiber.tag) { + case HostRoot: + var root = parentFiber.stateNode; + root.passiveEffectDuration += passiveEffectDuration; + break outer; - case OffscreenComponent: { - var isModernRoot = (finishedWork.mode & ConcurrentMode) !== NoMode; - - if (isModernRoot) { - var isHidden = finishedWork.memoizedState !== null; - var newOffscreenSubtreeIsHidden = - isHidden || offscreenSubtreeIsHidden; - - 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 (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); + case Profiler: + var parentStateNode = parentFiber.stateNode; + parentStateNode.passiveEffectDuration += passiveEffectDuration; + break outer; } - offscreenSubtreeIsHidden = prevOffscreenSubtreeIsHidden; - offscreenSubtreeWasHidden = prevOffscreenSubtreeWasHidden; + parentFiber = parentFiber.return; } - } else { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); + + break; } + } + } + } +} - if (flags & Ref) { - var props = finishedWork.memoizedProps; +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 (props.mode === "manual") { - safelyAttachRef(finishedWork, finishedWork.return); - } else { - safelyDetachRef(finishedWork, finishedWork.return); - } - } +function commitClassLayoutLifecycles(finishedWork, current) { + var instance = finishedWork.stateNode; - break; + 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.defaultProps && !('ref' in finishedWork.memoizedProps) && !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'); } - default: { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); - break; + 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'); } } } - function commitAttachRef(finishedWork) { - var ref = finishedWork.ref; - - if (ref !== null) { - var instance = finishedWork.stateNode; - var instanceToUse; - - switch (finishedWork.tag) { - case HostHoistable: - case HostSingleton: - case HostComponent: - instanceToUse = getPublicInstance(instance); - break; + if (shouldProfile(finishedWork)) { + try { + startLayoutEffectTimer(); + instance.componentDidMount(); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } - default: - instanceToUse = instance; - } // Moved outside to ensure DCE works with this flag + recordLayoutEffectDuration(finishedWork); + } else { + try { + instance.componentDidMount(); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } + } + } else { + var prevProps = resolveClassComponentProps(finishedWork.type, current.memoizedProps, finishedWork.elementType === finishedWork.type); + 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 (typeof ref === "function") { - if (shouldProfile(finishedWork)) { - try { - startLayoutEffectTimer(); - finishedWork.refCleanup = ref(instanceToUse); - } finally { - recordLayoutEffectDuration(finishedWork); - } - } else { - finishedWork.refCleanup = ref(instanceToUse); - } - } else { - { - // TODO: We should move these warnings to happen during the render - // phase (markRef). - if (!ref.hasOwnProperty("current")) { - error( - "Unexpected ref object provided for %s. " + - "Use either a ref-setter function or React.createRef().", - getComponentNameFromFiber(finishedWork) - ); - } - } // $FlowFixMe[incompatible-use] unable to narrow type to the non-function case + { + if (!finishedWork.type.defaultProps && !('ref' in finishedWork.memoizedProps) && !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'); + } - ref.current = instanceToUse; + 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'); } } } - 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; + if (shouldProfile(finishedWork)) { + try { + startLayoutEffectTimer(); + instance.componentDidUpdate(prevProps, prevState, instance.__reactInternalSnapshotBeforeUpdate); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); } - fiber.return = null; + recordLayoutEffectDuration(finishedWork); + } else { + try { + instance.componentDidUpdate(prevProps, prevState, instance.__reactInternalSnapshotBeforeUpdate); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } } + } +} - 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. +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; - fiber.child = null; - fiber.deletions = null; - fiber.sibling = null; // The `stateNode` is cyclical because on host nodes it points to the host + if (updateQueue !== null) { + var instance = finishedWork.stateNode; - fiber.stateNode = null; + { + if (!finishedWork.type.defaultProps && !('ref' in finishedWork.memoizedProps) && !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'); + } - { - 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. + 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. - 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; + try { + commitCallbacks(updateQueue, instance); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); } + } +} - function emptyPortalContainer(current) { - createContainerChildSet(); - } +function commitHostComponentMount(finishedWork) { + var type = finishedWork.type; + var props = finishedWork.memoizedProps; + var instance = finishedWork.stateNode; - function commitPlacement(finishedWork) { - { - return; + try { + commitMount(instance, type, props, finishedWork); + } 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'; + } } - } - function commitDeletionEffects(root, returnFiber, deletedFiber) { - { - // Detach refs and call componentWillUnmount() on the whole subtree. - commitDeletionEffectsOnFiber(root, returnFiber, deletedFiber); + if (typeof onRender === 'function') { + onRender(finishedWork.memoizedProps.id, phase, finishedWork.actualDuration, finishedWork.treeBaseDuration, finishedWork.actualStartTime, commitTime); } - detachFiberMutation(deletedFiber); - } + 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. - 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) { - commitDeletionEffectsOnFiber( - finishedRoot, - nearestMountedAncestor, - child - ); - child = child.sibling; - } - } + 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. - 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. + var parentFiber = finishedWork.return; - switch (deletedFiber.tag) { - case HostHoistable: + outer: while (parentFiber !== null) { + switch (parentFiber.tag) { + case HostRoot: + var root = parentFiber.stateNode; + root.effectDuration += effectDuration; + break outer; - case HostSingleton: + case Profiler: + var parentStateNode = parentFiber.stateNode; + parentStateNode.effectDuration += effectDuration; + break outer; + } - case HostComponent: { - if (!offscreenSubtreeWasHidden) { - safelyDetachRef(deletedFiber, nearestMountedAncestor); - } // Intentional fallthrough to next branch + parentFiber = parentFiber.return; } + } + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } + } +} - 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 - ); - } +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; - return; - } + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: + { + recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); - case DehydratedFragment: { - return; + if (flags & Update) { + commitHookLayoutEffects(finishedWork, Layout | HasEffect); } - case HostPortal: { - { - emptyPortalContainer(); - recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - deletedFiber - ); - } + break; + } - return; + case ClassComponent: + { + recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); + + if (flags & Update) { + commitClassLayoutLifecycles(finishedWork, current); } - case FunctionComponent: - case ForwardRef: - case MemoComponent: - case SimpleMemoComponent: { - if (!offscreenSubtreeWasHidden) { - var updateQueue = deletedFiber.updateQueue; + if (flags & Callback) { + commitClassCallbacks(finishedWork); + } - if (updateQueue !== null) { - var lastEffect = updateQueue.lastEffect; + if (flags & Ref) { + safelyAttachRef(finishedWork, finishedWork.return); + } - if (lastEffect !== null) { - var firstEffect = lastEffect.next; - var effect = firstEffect; + break; + } - do { - var tag = effect.tag; - var inst = effect.inst; - var destroy = inst.destroy; + case HostRoot: + { + recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); - if (destroy !== undefined) { - if ((tag & Insertion) !== NoFlags) { - inst.destroy = undefined; - safelyCallDestroy( - deletedFiber, - nearestMountedAncestor, - destroy - ); - } else if ((tag & Layout) !== NoFlags) { - { - markComponentLayoutEffectUnmountStarted(deletedFiber); - } + 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 (shouldProfile(deletedFiber)) { - startLayoutEffectTimer(); - inst.destroy = undefined; - safelyCallDestroy( - deletedFiber, - nearestMountedAncestor, - destroy - ); - recordLayoutEffectDuration(deletedFiber); - } else { - inst.destroy = undefined; - safelyCallDestroy( - deletedFiber, - nearestMountedAncestor, - destroy - ); - } + if (updateQueue !== null) { + var instance = null; - { - markComponentLayoutEffectUnmountStopped(); - } - } - } + if (finishedWork.child !== null) { + switch (finishedWork.child.tag) { + case HostSingleton: + case HostComponent: + instance = getPublicInstance(finishedWork.child.stateNode); + break; - effect = effect.next; - } while (effect !== firstEffect); + case ClassComponent: + instance = finishedWork.child.stateNode; + break; } } - } - recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - deletedFiber - ); - return; + try { + commitCallbacks(updateQueue, instance); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } + } } - case ClassComponent: { - if (!offscreenSubtreeWasHidden) { - safelyDetachRef(deletedFiber, nearestMountedAncestor); - var instance = deletedFiber.stateNode; + break; + } - if (typeof instance.componentWillUnmount === "function") { - safelyCallComponentWillUnmount( - deletedFiber, - nearestMountedAncestor, - instance - ); - } - } + case HostHoistable: - recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - deletedFiber - ); - return; + 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); } - case ScopeComponent: { - recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - deletedFiber - ); - return; + if (flags & Ref) { + safelyAttachRef(finishedWork, finishedWork.return); } - case OffscreenComponent: { - safelyDetachRef(deletedFiber, nearestMountedAncestor); + 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 - ); - } + 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. - break; + if (flags & Update) { + commitProfilerUpdate(finishedWork, current); } - default: { - recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - deletedFiber - ); - return; - } + break; } - } - function commitSuspenseCallback(finishedWork) {} + case SuspenseComponent: + { + recursivelyTraverseLayoutEffects(finishedRoot, 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 SuspenseComponent: - case SuspenseListComponent: { - var retryCache = finishedWork.stateNode; + break; + } - if (retryCache === null) { - retryCache = finishedWork.stateNode = new PossiblyWeakSet(); - } + case OffscreenComponent: + { + var isModernRoot = (finishedWork.mode & ConcurrentMode) !== NoMode; - return retryCache; - } + if (isModernRoot) { + var isHidden = finishedWork.memoizedState !== null; + var newOffscreenSubtreeIsHidden = isHidden || offscreenSubtreeIsHidden; - case OffscreenComponent: { - var instance = finishedWork.stateNode; - var _retryCache = instance._retryCache; + 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 (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); + } - if (_retryCache === null) { - _retryCache = instance._retryCache = new PossiblyWeakSet(); + offscreenSubtreeIsHidden = prevOffscreenSubtreeIsHidden; + offscreenSubtreeWasHidden = prevOffscreenSubtreeWasHidden; } - - return _retryCache; + } else { + recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); } - default: { - throw new Error( - "Unexpected Suspense handler tag (" + - finishedWork.tag + - "). This is a " + - "bug in React." - ); + if (flags & Ref) { + var props = finishedWork.memoizedProps; + + if (props.mode === 'manual') { + safelyAttachRef(finishedWork, finishedWork.return); + } else { + safelyDetachRef(finishedWork, finishedWork.return); + } } - } - } - function detachOffscreenInstance(instance) { - var fiber = instance._current; + break; + } - if (fiber === null) { - throw new Error( - "Calling Offscreen.detach before instance handle has been set." - ); + default: + { + recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); + break; } + } +} - 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. +function commitAttachRef(finishedWork) { + var ref = finishedWork.ref; - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + if (ref !== null) { + var instance = finishedWork.stateNode; + var instanceToUse; - if (root !== null) { - instance._pendingVisibility |= OffscreenDetached; - scheduleUpdateOnFiber(root, fiber, SyncLane); - } - } - function attachOffscreenInstance(instance) { - var fiber = instance._current; + switch (finishedWork.tag) { + case HostHoistable: + case HostSingleton: + case HostComponent: + instanceToUse = getPublicInstance(instance); + break; - if (fiber === null) { - throw new Error( - "Calling Offscreen.detach before instance handle has been set." - ); - } + default: + instanceToUse = instance; + } // Moved outside to ensure DCE works with this flag - if ((instance._pendingVisibility & OffscreenDetached) === NoFlags$1) { - // The instance is already attached, this is a noop. - return; + if (typeof ref === 'function') { + if (shouldProfile(finishedWork)) { + try { + startLayoutEffectTimer(); + finishedWork.refCleanup = ref(instanceToUse); + } finally { + recordLayoutEffectDuration(finishedWork); + } + } else { + finishedWork.refCleanup = ref(instanceToUse); } + } else { + { + // TODO: We should move these warnings to happen during the render + // phase (markRef). + if (!ref.hasOwnProperty('current')) { + error('Unexpected ref object provided for %s. ' + 'Use either a ref-setter function or React.createRef().', getComponentNameFromFiber(finishedWork)); + } + } // $FlowFixMe[incompatible-use] unable to narrow type to the non-function case - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - if (root !== null) { - instance._pendingVisibility &= ~OffscreenDetached; - scheduleUpdateOnFiber(root, fiber, SyncLane); - } + ref.current = instanceToUse; } + } +} - 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); +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; + } + + fiber.return = null; +} - if (!retryCache.has(wakeable)) { - retryCache.add(wakeable); +function detachFiberAfterEffects(fiber) { + var alternate = fiber.alternate; - { - 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." - ); - } - } - } + 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. - 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; - } - - 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; - - if (deletions !== null) { - for (var i = 0; i < deletions.length; i++) { - var childToDelete = deletions[i]; - try { - commitDeletionEffects(root, parentFiber, childToDelete); - } catch (error) { - captureCommitPhaseError(childToDelete, parentFiber, error); - } - } - } + fiber.child = null; + fiber.deletions = null; + fiber.sibling = null; // The `stateNode` is cyclical because on host nodes it points to the host - var prevDebugFiber = getCurrentFiber(); + fiber.stateNode = null; - if (parentFiber.subtreeFlags & MutationMask) { - var child = parentFiber.child; + { + 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. - while (child !== null) { - setCurrentFiber(child); - commitMutationEffectsOnFiber(child, root); - child = child.sibling; - } - } - setCurrentFiber(prevDebugFiber); - } + fiber.return = null; + fiber.dependencies = null; + fiber.memoizedProps = null; + fiber.memoizedState = null; + fiber.pendingProps = null; + fiber.stateNode = null; // TODO: Move to `commitPassiveUnmountInsideDeletedTreeOnFiber` instead. - 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. + fiber.updateQueue = null; +} - switch (finishedWork.tag) { - case FunctionComponent: - case ForwardRef: - case MemoComponent: - case SimpleMemoComponent: { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); +function emptyPortalContainer(current) { + createContainerChildSet(); +} - 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. +function commitPlacement(finishedWork) { + { + return; + } +} - if (shouldProfile(finishedWork)) { - try { - startLayoutEffectTimer(); - commitHookEffectListUnmount( - Layout | HasEffect, - finishedWork, - finishedWork.return - ); - } catch (error) { - captureCommitPhaseError( - finishedWork, - finishedWork.return, - error - ); - } +function commitDeletionEffects(root, returnFiber, deletedFiber) { + { + // Detach refs and call componentWillUnmount() on the whole subtree. + commitDeletionEffectsOnFiber(root, returnFiber, deletedFiber); + } - recordLayoutEffectDuration(finishedWork); - } else { - try { - commitHookEffectListUnmount( - Layout | HasEffect, - finishedWork, - finishedWork.return - ); - } catch (error) { - captureCommitPhaseError( - finishedWork, - finishedWork.return, - error - ); - } - } - } + detachFiberMutation(deletedFiber); +} - return; - } +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) { + commitDeletionEffectsOnFiber(finishedRoot, nearestMountedAncestor, child); + child = child.sibling; + } +} + +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. - case ClassComponent: { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); + switch (deletedFiber.tag) { + case HostHoistable: - if (flags & Ref) { - if (current !== null) { - safelyDetachRef(current, current.return); - } - } + case HostSingleton: - if (flags & Callback && offscreenSubtreeIsHidden) { - var updateQueue = finishedWork.updateQueue; + case HostComponent: + { + if (!offscreenSubtreeWasHidden) { + safelyDetachRef(deletedFiber, nearestMountedAncestor); + } // Intentional fallthrough to next branch - if (updateQueue !== null) { - deferHiddenCallbacks(updateQueue); - } - } + } - return; + 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); } - case HostHoistable: - - case HostSingleton: + return; + } - case HostComponent: { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); + case DehydratedFragment: + { - if (flags & Ref) { - if (current !== null) { - safelyDetachRef(current, current.return); - } - } + return; + } - return; + case HostPortal: + { + { + emptyPortalContainer(); + recursivelyTraverseDeletionEffects(finishedRoot, nearestMountedAncestor, deletedFiber); } - case HostText: { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); + return; + } - return; - } + case FunctionComponent: + case ForwardRef: + case MemoComponent: + case SimpleMemoComponent: + { + if (!offscreenSubtreeWasHidden) { + var updateQueue = deletedFiber.updateQueue; - case HostRoot: { - { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); - } + if (updateQueue !== null) { + var lastEffect = updateQueue.lastEffect; + + if (lastEffect !== null) { + var firstEffect = lastEffect.next; + var effect = firstEffect; + + do { + var tag = effect.tag; + var inst = effect.inst; + var destroy = inst.destroy; + + if (destroy !== undefined) { + if ((tag & Insertion) !== NoFlags) { + inst.destroy = undefined; + safelyCallDestroy(deletedFiber, nearestMountedAncestor, destroy); + } else if ((tag & Layout) !== NoFlags) { + { + markComponentLayoutEffectUnmountStarted(deletedFiber); + } - if (flags & Update) { - { - var containerInfo = root.containerInfo; - var pendingChildren = root.pendingChildren; + if (shouldProfile(deletedFiber)) { + startLayoutEffectTimer(); + inst.destroy = undefined; + safelyCallDestroy(deletedFiber, nearestMountedAncestor, destroy); + recordLayoutEffectDuration(deletedFiber); + } else { + inst.destroy = undefined; + safelyCallDestroy(deletedFiber, nearestMountedAncestor, destroy); + } - try { - replaceContainerChildren(containerInfo, pendingChildren); - } catch (error) { - captureCommitPhaseError( - finishedWork, - finishedWork.return, - error - ); - } + { + markComponentLayoutEffectUnmountStopped(); + } + } + } + + effect = effect.next; + } while (effect !== firstEffect); } } - - return; } - case HostPortal: { - { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); - } + recursivelyTraverseDeletionEffects(finishedRoot, nearestMountedAncestor, deletedFiber); + return; + } - if (flags & Update) { - { - var portal = finishedWork.stateNode; - var _containerInfo = portal.containerInfo; - var _pendingChildren = portal.pendingChildren; + case ClassComponent: + { + if (!offscreenSubtreeWasHidden) { + safelyDetachRef(deletedFiber, nearestMountedAncestor); + var instance = deletedFiber.stateNode; - try { - replaceContainerChildren(_containerInfo, _pendingChildren); - } catch (error) { - captureCommitPhaseError( - finishedWork, - finishedWork.return, - error - ); - } - } + if (typeof instance.componentWillUnmount === 'function') { + safelyCallComponentWillUnmount(deletedFiber, nearestMountedAncestor, instance); } - - return; } - case SuspenseComponent: { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); // TODO: We should mark a flag on the Suspense fiber itself, rather than - // relying on the Offscreen fiber having a flag also being marked. The - // reason is that this offscreen fiber might not be part of the work-in- - // progress tree! It could have been reused from a previous render. This - // doesn't lead to incorrect behavior because we don't rely on the flag - // check alone; we also compare the states explicitly below. But for - // modeling purposes, we _should_ be able to rely on the flag check alone. - // So this is a bit fragile. - // - // Also, all this logic could/should move to the passive phase so it - // doesn't block paint. + recursivelyTraverseDeletionEffects(finishedRoot, nearestMountedAncestor, deletedFiber); + return; + } - var offscreenFiber = finishedWork.child; + case ScopeComponent: + { - if (offscreenFiber.flags & Visibility) { - // Throttle the appearance and disappearance of Suspense fallbacks. - var isShowingFallback = finishedWork.memoizedState !== null; - var wasShowingFallback = - current !== null && current.memoizedState !== null; + recursivelyTraverseDeletionEffects(finishedRoot, nearestMountedAncestor, deletedFiber); + return; + } - if (alwaysThrottleRetries) { - if (isShowingFallback !== wasShowingFallback) { - // A fallback is either appearing or disappearing. - markCommitTimeOfFallback(); - } - } else { - if (isShowingFallback && !wasShowingFallback) { - // Old behavior. Only mark when a fallback appears, not when - // it disappears. - markCommitTimeOfFallback(); - } - } - } + case OffscreenComponent: + { + safelyDetachRef(deletedFiber, nearestMountedAncestor); + + 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); + } - if (flags & Update) { - try { - commitSuspenseCallback(finishedWork); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } + break; + } + + default: + { + recursivelyTraverseDeletionEffects(finishedRoot, nearestMountedAncestor, deletedFiber); + return; + } + } +} - var retryQueue = finishedWork.updateQueue; +function commitSuspenseCallback(finishedWork) { +} - if (retryQueue !== null) { - finishedWork.updateQueue = null; - attachSuspenseRetryListeners(finishedWork, retryQueue); - } - } +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; - return; + if (retryCache === null) { + retryCache = finishedWork.stateNode = new PossiblyWeakSet(); } - case OffscreenComponent: { - if (flags & Ref) { - if (current !== null) { - safelyDetachRef(current, current.return); - } - } + return retryCache; + } - var newState = finishedWork.memoizedState; - var isHidden = newState !== null; - var wasHidden = current !== null && current.memoizedState !== null; + case OffscreenComponent: + { + var instance = finishedWork.stateNode; + var _retryCache = instance._retryCache; - 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 (_retryCache === null) { + _retryCache = instance._retryCache = new PossiblyWeakSet(); + } - commitReconciliationEffects(finishedWork); - var offscreenInstance = finishedWork.stateNode; // TODO: Add explicit effect flag to set _current. + return _retryCache; + } - offscreenInstance._current = finishedWork; // Offscreen stores pending changes to visibility in `_pendingVisibility`. This is - // to support batching of `attach` and `detach` calls. + default: + { + throw new Error("Unexpected Suspense handler tag (" + finishedWork.tag + "). This is a " + 'bug in React.'); + } + } +} - offscreenInstance._visibility &= ~OffscreenDetached; - offscreenInstance._visibility |= - offscreenInstance._pendingVisibility & OffscreenDetached; +function detachOffscreenInstance(instance) { + var fiber = instance._current; - 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 (fiber === null) { + throw new Error('Calling Offscreen.detach before instance handle has been set.'); + } - 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 (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 + 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. - if (flags & Update) { - var offscreenQueue = finishedWork.updateQueue; - if (offscreenQueue !== null) { - var _retryQueue = offscreenQueue.retryQueue; + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - if (_retryQueue !== null) { - offscreenQueue.retryQueue = null; - attachSuspenseRetryListeners(finishedWork, _retryQueue); - } - } - } + if (root !== null) { + instance._pendingVisibility |= OffscreenDetached; + scheduleUpdateOnFiber(root, fiber, SyncLane); + } +} +function attachOffscreenInstance(instance) { + var fiber = instance._current; - return; - } + if (fiber === null) { + throw new Error('Calling Offscreen.detach before instance handle has been set.'); + } - case SuspenseListComponent: { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); + if ((instance._pendingVisibility & OffscreenDetached) === NoFlags$1) { + // The instance is already attached, this is a noop. + return; + } - if (flags & Update) { - var _retryQueue2 = finishedWork.updateQueue; + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - if (_retryQueue2 !== null) { - finishedWork.updateQueue = null; - attachSuspenseRetryListeners(finishedWork, _retryQueue2); - } - } + if (root !== null) { + instance._pendingVisibility &= ~OffscreenDetached; + scheduleUpdateOnFiber(root, fiber, SyncLane); + } +} - return; - } +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); - case ScopeComponent: { - return; - } + if (!retryCache.has(wakeable)) { + retryCache.add(wakeable); - default: { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); - return; + { + 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.'); + } } } - } - 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; + 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; +} - 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. +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; - finishedWork.flags &= ~Placement; - } + if (deletions !== null) { + for (var i = 0; i < deletions.length; i++) { + var childToDelete = deletions[i]; - if (flags & Hydrating) { - finishedWork.flags &= ~Hydrating; + try { + commitDeletionEffects(root, parentFiber, childToDelete); + } catch (error) { + captureCommitPhaseError(childToDelete, parentFiber, error); } } + } + + var prevDebugFiber = getCurrentFiber(); - function commitLayoutEffects(finishedWork, root, committedLanes) { - inProgressLanes = committedLanes; - inProgressRoot = root; - var current = finishedWork.alternate; - commitLayoutEffectOnFiber(root, current, finishedWork); - inProgressLanes = null; - inProgressRoot = null; + if (parentFiber.subtreeFlags & MutationMask) { + var child = parentFiber.child; + + while (child !== null) { + setCurrentFiber(child); + commitMutationEffectsOnFiber(child, root); + child = child.sibling; } + } - function recursivelyTraverseLayoutEffects(root, parentFiber, lanes) { - var prevDebugFiber = getCurrentFiber(); + setCurrentFiber(prevDebugFiber); +} - if (parentFiber.subtreeFlags & LayoutMask) { - var child = parentFiber.child; +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. - while (child !== null) { - setCurrentFiber(child); - var current = child.alternate; - commitLayoutEffectOnFiber(root, current, child); - child = child.sibling; - } - } + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case MemoComponent: + case SimpleMemoComponent: + { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); + + 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. - setCurrentFiber(prevDebugFiber); - } - function disappearLayoutEffects(finishedWork) { - switch (finishedWork.tag) { - case FunctionComponent: - case ForwardRef: - case MemoComponent: - case SimpleMemoComponent: { - // TODO (Offscreen) Check: flags & LayoutStatic if (shouldProfile(finishedWork)) { try { startLayoutEffectTimer(); - commitHookEffectListUnmount( - Layout, - finishedWork, - finishedWork.return - ); - } finally { - recordLayoutEffectDuration(finishedWork); + commitHookEffectListUnmount(Layout | HasEffect, finishedWork, finishedWork.return); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); } + + recordLayoutEffectDuration(finishedWork); } else { - commitHookEffectListUnmount( - Layout, - finishedWork, - finishedWork.return - ); + try { + commitHookEffectListUnmount(Layout | HasEffect, finishedWork, finishedWork.return); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } } - - recursivelyTraverseDisappearLayoutEffects(finishedWork); - break; } - case ClassComponent: { - // TODO (Offscreen) Check: flags & RefStatic - safelyDetachRef(finishedWork, finishedWork.return); - var instance = finishedWork.stateNode; + return; + } - if (typeof instance.componentWillUnmount === "function") { - safelyCallComponentWillUnmount( - finishedWork, - finishedWork.return, - instance - ); - } + case ClassComponent: + { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); - recursivelyTraverseDisappearLayoutEffects(finishedWork); - break; + if (flags & Ref) { + if (current !== null) { + safelyDetachRef(current, current.return); + } } - case HostHoistable: - case HostSingleton: - case HostComponent: { - // TODO (Offscreen) Check: flags & RefStatic - safelyDetachRef(finishedWork, finishedWork.return); - recursivelyTraverseDisappearLayoutEffects(finishedWork); - break; + if (flags & Callback && offscreenSubtreeIsHidden) { + var updateQueue = finishedWork.updateQueue; + + if (updateQueue !== null) { + deferHiddenCallbacks(updateQueue); + } } - case OffscreenComponent: { - // TODO (Offscreen) Check: flags & RefStatic - safelyDetachRef(finishedWork, finishedWork.return); - var isHidden = finishedWork.memoizedState !== null; + return; + } - if (isHidden); - else { - recursivelyTraverseDisappearLayoutEffects(finishedWork); - } + case HostHoistable: - break; - } + case HostSingleton: - default: { - recursivelyTraverseDisappearLayoutEffects(finishedWork); - break; + case HostComponent: + { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); + + if (flags & Ref) { + if (current !== null) { + safelyDetachRef(current, current.return); + } } + + return; } - } - function recursivelyTraverseDisappearLayoutEffects(parentFiber) { - // TODO (Offscreen) Check: flags & (RefStatic | LayoutStatic) - var child = parentFiber.child; + case HostText: + { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); - while (child !== null) { - disappearLayoutEffects(child); - child = child.sibling; + return; } - } - 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; + case HostRoot: + { + { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); + } - switch (finishedWork.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - recursivelyTraverseReappearLayoutEffects( - finishedRoot, - finishedWork, - includeWorkInProgressEffects - ); // TODO: Check flags & LayoutStatic - - commitHookLayoutEffects(finishedWork, Layout); - break; + if (flags & Update) { + + { + var containerInfo = root.containerInfo; + var pendingChildren = root.pendingChildren; + + try { + replaceContainerChildren(containerInfo, pendingChildren); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } + } } - case ClassComponent: { - recursivelyTraverseReappearLayoutEffects( - finishedRoot, - finishedWork, - includeWorkInProgressEffects - ); // TODO: Check for LayoutStatic flag + return; + } + + case HostPortal: + { + { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); + } - var instance = finishedWork.stateNode; + if (flags & Update) { + { + var portal = finishedWork.stateNode; + var _containerInfo = portal.containerInfo; + var _pendingChildren = portal.pendingChildren; - if (typeof instance.componentDidMount === "function") { try { - instance.componentDidMount(); + replaceContainerChildren(_containerInfo, _pendingChildren); } catch (error) { captureCommitPhaseError(finishedWork, finishedWork.return, error); } - } // Commit any callbacks that would have fired while the component - // was hidden. + } + } + + return; + } + + case SuspenseComponent: + { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); // TODO: We should mark a flag on the Suspense fiber itself, rather than + // relying on the Offscreen fiber having a flag also being marked. The + // reason is that this offscreen fiber might not be part of the work-in- + // progress tree! It could have been reused from a previous render. This + // doesn't lead to incorrect behavior because we don't rely on the flag + // check alone; we also compare the states explicitly below. But for + // modeling purposes, we _should_ be able to rely on the flag check alone. + // So this is a bit fragile. + // + // Also, all this logic could/should move to the passive phase so it + // doesn't block paint. + + var offscreenFiber = finishedWork.child; + + if (offscreenFiber.flags & Visibility) { + // Throttle the appearance and disappearance of Suspense fallbacks. + var isShowingFallback = finishedWork.memoizedState !== null; + var wasShowingFallback = current !== null && current.memoizedState !== null; + + if (alwaysThrottleRetries) { + if (isShowingFallback !== wasShowingFallback) { + // A fallback is either appearing or disappearing. + markCommitTimeOfFallback(); + } + } else { + if (isShowingFallback && !wasShowingFallback) { + // Old behavior. Only mark when a fallback appears, not when + // it disappears. + markCommitTimeOfFallback(); + } + } + } + + if (flags & Update) { + try { + commitSuspenseCallback(finishedWork); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } - var updateQueue = finishedWork.updateQueue; + var retryQueue = finishedWork.updateQueue; - if (updateQueue !== null) { - commitHiddenCallbacks(updateQueue, instance); - } // If this is newly finished work, check for setState callbacks + if (retryQueue !== null) { + finishedWork.updateQueue = null; + attachSuspenseRetryListeners(finishedWork, retryQueue); + } + } - if (includeWorkInProgressEffects && flags & Callback) { - commitClassCallbacks(finishedWork); - } // TODO: Check flags & RefStatic + return; + } - safelyAttachRef(finishedWork, finishedWork.return); - break; + case OffscreenComponent: + { + if (flags & Ref) { + if (current !== null) { + safelyDetachRef(current, current.return); + } } - // 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. - - if ( - includeWorkInProgressEffects && - current === null && - flags & Update - ) { - commitHostComponentMount(finishedWork); - } // TODO: Check flags & Ref + var newState = finishedWork.memoizedState; + var isHidden = newState !== null; + var wasHidden = current !== null && current.memoizedState !== null; - safelyAttachRef(finishedWork, finishedWork.return); - break; + 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); } - case Profiler: { - recursivelyTraverseReappearLayoutEffects( - finishedRoot, - finishedWork, - includeWorkInProgressEffects - ); // TODO: Figure out how Profiler updates should work with Offscreen + commitReconciliationEffects(finishedWork); + var offscreenInstance = finishedWork.stateNode; // TODO: Add explicit effect flag to set _current. + + offscreenInstance._current = finishedWork; // Offscreen stores pending changes to visibility in `_pendingVisibility`. This is + // to support batching of `attach` and `detach` calls. - if (includeWorkInProgressEffects && flags & Update) { - commitProfilerUpdate(finishedWork, current); + offscreenInstance._visibility &= ~OffscreenDetached; + offscreenInstance._visibility |= offscreenInstance._pendingVisibility & OffscreenDetached; + + 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; } - break; - } + 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 (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 - case SuspenseComponent: { - recursivelyTraverseReappearLayoutEffects( - finishedRoot, - finishedWork, - includeWorkInProgressEffects - ); // TODO: Figure out how Suspense hydration callbacks should work - break; + if (flags & Update) { + var offscreenQueue = finishedWork.updateQueue; + + if (offscreenQueue !== null) { + var _retryQueue = offscreenQueue.retryQueue; + + if (_retryQueue !== null) { + offscreenQueue.retryQueue = null; + attachSuspenseRetryListeners(finishedWork, _retryQueue); + } + } } - case OffscreenComponent: { - var offscreenState = finishedWork.memoizedState; - var isHidden = offscreenState !== null; + return; + } - if (isHidden); - else { - recursivelyTraverseReappearLayoutEffects( - finishedRoot, - finishedWork, - includeWorkInProgressEffects - ); - } // TODO: Check flags & Ref + case SuspenseListComponent: + { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); - safelyAttachRef(finishedWork, finishedWork.return); - break; - } + if (flags & Update) { + var _retryQueue2 = finishedWork.updateQueue; - default: { - recursivelyTraverseReappearLayoutEffects( - finishedRoot, - finishedWork, - includeWorkInProgressEffects - ); - break; + if (_retryQueue2 !== null) { + finishedWork.updateQueue = null; + attachSuspenseRetryListeners(finishedWork, _retryQueue2); + } } + + return; } - } - 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) + case ScopeComponent: + { - var prevDebugFiber = getCurrentFiber(); - var child = parentFiber.child; + return; + } - while (child !== null) { - var current = child.alternate; - reappearLayoutEffects( - finishedRoot, - current, - child, - childShouldIncludeWorkInProgressEffects - ); - child = child.sibling; + default: + { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); + return; } + } +} - setCurrentFiber(prevDebugFiber); - } +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; + + 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. + + + finishedWork.flags &= ~Placement; + } + + if (flags & Hydrating) { + finishedWork.flags &= ~Hydrating; + } +} - function commitHookPassiveMountEffects(finishedWork, hookFlags) { - if (shouldProfile(finishedWork)) { - startPassiveEffectTimer(); +function commitLayoutEffects(finishedWork, root, committedLanes) { + inProgressLanes = committedLanes; + inProgressRoot = root; + var current = finishedWork.alternate; + commitLayoutEffectOnFiber(root, current, finishedWork); + inProgressLanes = null; + inProgressRoot = null; +} - try { - commitHookEffectListMount(hookFlags, finishedWork); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } +function recursivelyTraverseLayoutEffects(root, parentFiber, lanes) { + var prevDebugFiber = getCurrentFiber(); - recordPassiveEffectDuration(finishedWork); - } else { - try { - commitHookEffectListMount(hookFlags, finishedWork); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } - } + if (parentFiber.subtreeFlags & LayoutMask) { + var child = parentFiber.child; + + while (child !== null) { + setCurrentFiber(child); + var current = child.alternate; + commitLayoutEffectOnFiber(root, current, child); + child = child.sibling; } + } - function commitOffscreenPassiveMountEffects( - current, - finishedWork, - instance - ) { - { - var previousCache = null; - - if ( - current !== null && - current.memoizedState !== null && - current.memoizedState.cachePool !== null - ) { - previousCache = current.memoizedState.cachePool.pool; - } - - var nextCache = null; - - if ( - finishedWork.memoizedState !== null && - finishedWork.memoizedState.cachePool !== null - ) { - nextCache = finishedWork.memoizedState.cachePool.pool; - } // Retain/release the cache used for pending (suspended) nodes. - // Note that this is only reached in the non-suspended/visible case: - // when the content is suspended/hidden, the retain/release occurs - // via the parent Suspense component (see case above). - - if (nextCache !== previousCache) { - if (nextCache != null) { - retainCache(nextCache); - } + setCurrentFiber(prevDebugFiber); +} - if (previousCache != null) { - releaseCache(previousCache); +function disappearLayoutEffects(finishedWork) { + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case MemoComponent: + case SimpleMemoComponent: + { + // TODO (Offscreen) Check: flags & LayoutStatic + if (shouldProfile(finishedWork)) { + try { + startLayoutEffectTimer(); + commitHookEffectListUnmount(Layout, finishedWork, finishedWork.return); + } finally { + recordLayoutEffectDuration(finishedWork); } + } else { + commitHookEffectListUnmount(Layout, finishedWork, finishedWork.return); } + + recursivelyTraverseDisappearLayoutEffects(finishedWork); + break; } - } - function commitCachePassiveMountEffect(current, finishedWork) { + case ClassComponent: { - var previousCache = null; + // TODO (Offscreen) Check: flags & RefStatic + safelyDetachRef(finishedWork, finishedWork.return); + var instance = finishedWork.stateNode; - if (finishedWork.alternate !== null) { - previousCache = finishedWork.alternate.memoizedState.cache; + if (typeof instance.componentWillUnmount === 'function') { + safelyCallComponentWillUnmount(finishedWork, finishedWork.return, instance); } - var nextCache = finishedWork.memoizedState.cache; // Retain/release the cache. In theory the cache component - // could be "borrowing" a cache instance owned by some parent, - // in which case we could avoid retaining/releasing. But it - // is non-trivial to determine when that is the case, so we - // always retain/release. - - if (nextCache !== previousCache) { - retainCache(nextCache); + recursivelyTraverseDisappearLayoutEffects(finishedWork); + break; + } - if (previousCache != null) { - releaseCache(previousCache); - } - } + case HostHoistable: + case HostSingleton: + case HostComponent: + { + // TODO (Offscreen) Check: flags & RefStatic + safelyDetachRef(finishedWork, finishedWork.return); + recursivelyTraverseDisappearLayoutEffects(finishedWork); + break; } - } - function commitPassiveMountEffects( - root, - finishedWork, - committedLanes, - committedTransitions - ) { - setCurrentFiber(finishedWork); - commitPassiveMountOnFiber( - root, - finishedWork, - committedLanes, - committedTransitions - ); - resetCurrentFiber(); - } + case OffscreenComponent: + { + // TODO (Offscreen) Check: flags & RefStatic + safelyDetachRef(finishedWork, finishedWork.return); + var isHidden = finishedWork.memoizedState !== null; - function recursivelyTraversePassiveMountEffects( - root, - parentFiber, - committedLanes, - committedTransitions - ) { - var prevDebugFiber = getCurrentFiber(); + if (isHidden) ; else { + recursivelyTraverseDisappearLayoutEffects(finishedWork); + } - if (parentFiber.subtreeFlags & PassiveMask) { - var child = parentFiber.child; + break; + } - while (child !== null) { - setCurrentFiber(child); - commitPassiveMountOnFiber( - root, - child, - committedLanes, - committedTransitions - ); - child = child.sibling; - } + default: + { + recursivelyTraverseDisappearLayoutEffects(finishedWork); + break; } + } +} - setCurrentFiber(prevDebugFiber); - } +function recursivelyTraverseDisappearLayoutEffects(parentFiber) { + // TODO (Offscreen) Check: flags & (RefStatic | LayoutStatic) + var child = parentFiber.child; - 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; + while (child !== null) { + disappearLayoutEffects(child); + child = child.sibling; + } +} - switch (finishedWork.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - recursivelyTraversePassiveMountEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions - ); - - if (flags & Passive$1) { - commitHookPassiveMountEffects(finishedWork, Passive | HasEffect); - } +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; - break; - } + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: + { + recursivelyTraverseReappearLayoutEffects(finishedRoot, finishedWork, includeWorkInProgressEffects); // TODO: Check flags & LayoutStatic - case HostRoot: { - recursivelyTraversePassiveMountEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions - ); + commitHookLayoutEffects(finishedWork, Layout); + break; + } - if (flags & Passive$1) { - { - var previousCache = null; + case ClassComponent: + { + recursivelyTraverseReappearLayoutEffects(finishedRoot, finishedWork, includeWorkInProgressEffects); // TODO: Check for LayoutStatic flag - if (finishedWork.alternate !== null) { - previousCache = finishedWork.alternate.memoizedState.cache; - } + var instance = finishedWork.stateNode; - var nextCache = finishedWork.memoizedState.cache; // Retain/release the root cache. - // Note that on initial mount, previousCache and nextCache will be the same - // and this retain won't occur. To counter this, we instead retain the HostRoot's - // initial cache when creating the root itself (see createFiberRoot() in - // ReactFiberRoot.js). Subsequent updates that change the cache are reflected - // here, such that previous/next caches are retained correctly. + 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 (nextCache !== previousCache) { - retainCache(nextCache); - if (previousCache != null) { - releaseCache(previousCache); - } - } - } - } + var updateQueue = finishedWork.updateQueue; - break; - } + if (updateQueue !== null) { + commitHiddenCallbacks(updateQueue, instance); + } // If this is newly finished work, check for setState callbacks - case LegacyHiddenComponent: { - break; - } - case OffscreenComponent: { - // TODO: Pass `current` as argument to this function - var _instance3 = finishedWork.stateNode; - var nextState = finishedWork.memoizedState; - var isHidden = nextState !== null; + if (includeWorkInProgressEffects && flags & Callback) { + commitClassCallbacks(finishedWork); + } // TODO: Check flags & RefStatic - if (isHidden) { - if (_instance3._visibility & OffscreenPassiveEffectsConnected) { - // The effects are currently connected. Update them. - recursivelyTraversePassiveMountEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions - ); - } else { - if (finishedWork.mode & ConcurrentMode) { - // The effects are currently disconnected. Since the tree is hidden, - // don't connect them. This also applies to the initial render. - { - // "Atomic" effects are ones that need to fire on every commit, - // even during pre-rendering. An example is updating the reference - // count on cache instances. - recursivelyTraverseAtomicPassiveEffects( - finishedRoot, - finishedWork - ); - } - } else { - // Legacy Mode: Fire the effects even if the tree is hidden. - _instance3._visibility |= OffscreenPassiveEffectsConnected; - recursivelyTraversePassiveMountEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions - ); - } - } - } else { - // Tree is visible - if (_instance3._visibility & OffscreenPassiveEffectsConnected) { - // The effects are currently connected. Update them. - recursivelyTraversePassiveMountEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions - ); - } 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; - var includeWorkInProgressEffects = - (finishedWork.subtreeFlags & PassiveMask) !== NoFlags$1; - recursivelyTraverseReconnectPassiveEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions, - includeWorkInProgressEffects - ); - } - } - if (flags & Passive$1) { - var _current = finishedWork.alternate; - commitOffscreenPassiveMountEffects(_current, finishedWork); - } + 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: { + // ... + // } - break; - } + 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. - case CacheComponent: { - recursivelyTraversePassiveMountEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions - ); + if (includeWorkInProgressEffects && current === null && flags & Update) { + commitHostComponentMount(finishedWork); + } // TODO: Check flags & Ref - if (flags & Passive$1) { - // TODO: Pass `current` as argument to this function - var _current2 = finishedWork.alternate; - commitCachePassiveMountEffect(_current2, finishedWork); - } - break; - } + safelyAttachRef(finishedWork, finishedWork.return); + break; + } - case TracingMarkerComponent: + case Profiler: + { + recursivelyTraverseReappearLayoutEffects(finishedRoot, finishedWork, includeWorkInProgressEffects); // TODO: Figure out how Profiler updates should work with Offscreen - default: { - recursivelyTraversePassiveMountEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions - ); - break; + if (includeWorkInProgressEffects && flags & Update) { + commitProfilerUpdate(finishedWork, current); } - } - } - function recursivelyTraverseReconnectPassiveEffects( - finishedRoot, - parentFiber, - committedLanes, - committedTransitions, - 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 & PassiveMask) !== NoFlags$1; // TODO (Offscreen) Check: flags & (RefStatic | LayoutStatic) + break; + } - var prevDebugFiber = getCurrentFiber(); - var child = parentFiber.child; + case SuspenseComponent: + { + recursivelyTraverseReappearLayoutEffects(finishedRoot, finishedWork, includeWorkInProgressEffects); // TODO: Figure out how Suspense hydration callbacks should work - while (child !== null) { - reconnectPassiveEffects( - finishedRoot, - child, - committedLanes, - committedTransitions, - childShouldIncludeWorkInProgressEffects - ); - child = child.sibling; + break; } - setCurrentFiber(prevDebugFiber); - } + case OffscreenComponent: + { + var offscreenState = finishedWork.memoizedState; + var isHidden = offscreenState !== null; - 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 - ) { - var flags = finishedWork.flags; + if (isHidden) ; else { + recursivelyTraverseReappearLayoutEffects(finishedRoot, finishedWork, includeWorkInProgressEffects); + } // TODO: Check flags & Ref - switch (finishedWork.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - recursivelyTraverseReconnectPassiveEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions, - includeWorkInProgressEffects - ); // TODO: Check for PassiveStatic flag - - 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: { - // ... - // } - case LegacyHiddenComponent: { - break; - } + safelyAttachRef(finishedWork, finishedWork.return); + break; + } + + default: + { + recursivelyTraverseReappearLayoutEffects(finishedRoot, finishedWork, includeWorkInProgressEffects); + break; + } + } +} - case OffscreenComponent: { - var _instance4 = finishedWork.stateNode; - var nextState = finishedWork.memoizedState; - var isHidden = nextState !== null; +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) - if (isHidden) { - if (_instance4._visibility & OffscreenPassiveEffectsConnected) { - // The effects are currently connected. Update them. - recursivelyTraverseReconnectPassiveEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions, - includeWorkInProgressEffects - ); - } else { - if (finishedWork.mode & ConcurrentMode) { - // The effects are currently disconnected. Since the tree is hidden, - // don't connect them. This also applies to the initial render. - { - // "Atomic" effects are ones that need to fire on every commit, - // even during pre-rendering. An example is updating the reference - // count on cache instances. - recursivelyTraverseAtomicPassiveEffects( - finishedRoot, - finishedWork - ); - } - } else { - // Legacy Mode: Fire the effects even if the tree is hidden. - _instance4._visibility |= OffscreenPassiveEffectsConnected; - recursivelyTraverseReconnectPassiveEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions, - includeWorkInProgressEffects - ); - } - } - } 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, - committedLanes, - committedTransitions, - includeWorkInProgressEffects - ); - } + var prevDebugFiber = getCurrentFiber(); + var child = parentFiber.child; - if (includeWorkInProgressEffects && flags & Passive$1) { - // TODO: Pass `current` as argument to this function - var _current3 = finishedWork.alternate; - commitOffscreenPassiveMountEffects(_current3, finishedWork); - } + while (child !== null) { + var current = child.alternate; + reappearLayoutEffects(finishedRoot, current, child, childShouldIncludeWorkInProgressEffects); + child = child.sibling; + } - break; - } + setCurrentFiber(prevDebugFiber); +} - case CacheComponent: { - recursivelyTraverseReconnectPassiveEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions, - includeWorkInProgressEffects - ); +function commitHookPassiveMountEffects(finishedWork, hookFlags) { + if (shouldProfile(finishedWork)) { + startPassiveEffectTimer(); - if (includeWorkInProgressEffects && flags & Passive$1) { - // TODO: Pass `current` as argument to this function - var _current4 = finishedWork.alternate; - commitCachePassiveMountEffect(_current4, finishedWork); - } + try { + commitHookEffectListMount(hookFlags, finishedWork); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } - break; - } + recordPassiveEffectDuration(finishedWork); + } else { + try { + commitHookEffectListMount(hookFlags, finishedWork); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } + } +} - case TracingMarkerComponent: +function commitOffscreenPassiveMountEffects(current, finishedWork, instance) { + { + var previousCache = null; - default: { - recursivelyTraverseReconnectPassiveEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions, - includeWorkInProgressEffects - ); - break; - } - } + if (current !== null && current.memoizedState !== null && current.memoizedState.cachePool !== null) { + previousCache = current.memoizedState.cachePool.pool; } - function recursivelyTraverseAtomicPassiveEffects( - finishedRoot, - parentFiber, - committedLanes, - committedTransitions - ) { - // "Atomic" effects are ones that need to fire on every commit, even during - // pre-rendering. We call this function when traversing a hidden tree whose - // regular effects are currently disconnected. - var prevDebugFiber = getCurrentFiber(); // TODO: Add special flag for atomic effects + var nextCache = null; - if (parentFiber.subtreeFlags & PassiveMask) { - var child = parentFiber.child; + if (finishedWork.memoizedState !== null && finishedWork.memoizedState.cachePool !== null) { + nextCache = finishedWork.memoizedState.cachePool.pool; + } // Retain/release the cache used for pending (suspended) nodes. + // Note that this is only reached in the non-suspended/visible case: + // when the content is suspended/hidden, the retain/release occurs + // via the parent Suspense component (see case above). - while (child !== null) { - setCurrentFiber(child); - commitAtomicPassiveEffects(finishedRoot, child); - child = child.sibling; - } + + if (nextCache !== previousCache) { + if (nextCache != null) { + retainCache(nextCache); } - setCurrentFiber(prevDebugFiber); + if (previousCache != null) { + releaseCache(previousCache); + } } + } +} - function commitAtomicPassiveEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions - ) { - // "Atomic" effects are ones that need to fire on every commit, even during - // pre-rendering. We call this function when traversing a hidden tree whose - // regular effects are currently disconnected. - var flags = finishedWork.flags; +function commitCachePassiveMountEffect(current, finishedWork) { + { + var previousCache = null; - switch (finishedWork.tag) { - case OffscreenComponent: { - recursivelyTraverseAtomicPassiveEffects(finishedRoot, finishedWork); + if (finishedWork.alternate !== null) { + previousCache = finishedWork.alternate.memoizedState.cache; + } - if (flags & Passive$1) { - // TODO: Pass `current` as argument to this function - var current = finishedWork.alternate; - commitOffscreenPassiveMountEffects(current, finishedWork); - } + var nextCache = finishedWork.memoizedState.cache; // Retain/release the cache. In theory the cache component + // could be "borrowing" a cache instance owned by some parent, + // in which case we could avoid retaining/releasing. But it + // is non-trivial to determine when that is the case, so we + // always retain/release. - break; - } + if (nextCache !== previousCache) { + retainCache(nextCache); - case CacheComponent: { - recursivelyTraverseAtomicPassiveEffects(finishedRoot, finishedWork); + if (previousCache != null) { + releaseCache(previousCache); + } + } + } +} - if (flags & Passive$1) { - // TODO: Pass `current` as argument to this function - var _current5 = finishedWork.alternate; - commitCachePassiveMountEffect(_current5, finishedWork); - } +function commitPassiveMountEffects(root, finishedWork, committedLanes, committedTransitions) { + setCurrentFiber(finishedWork); + commitPassiveMountOnFiber(root, finishedWork, committedLanes, committedTransitions); + resetCurrentFiber(); +} - break; - } +function recursivelyTraversePassiveMountEffects(root, parentFiber, committedLanes, committedTransitions) { + var prevDebugFiber = getCurrentFiber(); - default: { - recursivelyTraverseAtomicPassiveEffects(finishedRoot, finishedWork); - break; - } - } + if (parentFiber.subtreeFlags & PassiveMask) { + var child = parentFiber.child; + + while (child !== null) { + setCurrentFiber(child); + commitPassiveMountOnFiber(root, child, committedLanes, committedTransitions); + child = child.sibling; } + } - function commitPassiveUnmountEffects(finishedWork) { - setCurrentFiber(finishedWork); - commitPassiveUnmountOnFiber(finishedWork); - resetCurrentFiber(); - } // If we're inside a brand new tree, or a tree that was already visible, then we - // should only suspend host components that have a ShouldSuspendCommit flag. - // Components without it haven't changed since the last commit, so we can skip - // over those. - // - // When we enter a tree that is being revealed (going from hidden -> visible), - // we need to suspend _any_ component that _may_ suspend. Even if they're - // already in the "current" tree. Because their visibility has changed, the - // browser may not have prerendered them yet. So we check the MaySuspendCommit - // flag instead. + setCurrentFiber(prevDebugFiber); +} - var suspenseyCommitFlag = ShouldSuspendCommit; - function accumulateSuspenseyCommit(finishedWork) { - accumulateSuspenseyCommitOnFiber(finishedWork); - } +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 recursivelyAccumulateSuspenseyCommit(parentFiber) { - if (parentFiber.subtreeFlags & suspenseyCommitFlag) { - var child = parentFiber.child; + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: + { + recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork, committedLanes, committedTransitions); - while (child !== null) { - accumulateSuspenseyCommitOnFiber(child); - child = child.sibling; + if (flags & Passive$1) { + commitHookPassiveMountEffects(finishedWork, Passive | HasEffect); } + + break; } - } - function accumulateSuspenseyCommitOnFiber(fiber) { - switch (fiber.tag) { - case HostHoistable: { - recursivelyAccumulateSuspenseyCommit(fiber); + case HostRoot: + { + recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork, committedLanes, committedTransitions); + + if (flags & Passive$1) { + { + var previousCache = null; - if (fiber.flags & suspenseyCommitFlag) { - if (fiber.memoizedState !== null) { - suspendResource(); + if (finishedWork.alternate !== null) { + previousCache = finishedWork.alternate.memoizedState.cache; } - } - break; - } + var nextCache = finishedWork.memoizedState.cache; // Retain/release the root cache. + // Note that on initial mount, previousCache and nextCache will be the same + // and this retain won't occur. To counter this, we instead retain the HostRoot's + // initial cache when creating the root itself (see createFiberRoot() in + // ReactFiberRoot.js). Subsequent updates that change the cache are reflected + // here, such that previous/next caches are retained correctly. - case HostComponent: { - recursivelyAccumulateSuspenseyCommit(fiber); + if (nextCache !== previousCache) { + retainCache(nextCache); - break; + if (previousCache != null) { + releaseCache(previousCache); + } + } + } } - case HostRoot: - case HostPortal: { - { - recursivelyAccumulateSuspenseyCommit(fiber); - } + break; + } - break; - } + case LegacyHiddenComponent: + { - case OffscreenComponent: { - var isHidden = fiber.memoizedState !== null; + break; + } - if (isHidden); - else { - var current = fiber.alternate; - var wasHidden = current !== null && current.memoizedState !== null; + case OffscreenComponent: + { + // TODO: Pass `current` as argument to this function + var _instance3 = finishedWork.stateNode; + var nextState = finishedWork.memoizedState; + var isHidden = nextState !== null; - if (wasHidden) { - // This tree is being revealed. Visit all newly visible suspensey - // instances, even if they're in the current tree. - var prevFlags = suspenseyCommitFlag; - suspenseyCommitFlag = MaySuspendCommit; - recursivelyAccumulateSuspenseyCommit(fiber); - suspenseyCommitFlag = prevFlags; + if (isHidden) { + if (_instance3._visibility & OffscreenPassiveEffectsConnected) { + // The effects are currently connected. Update them. + recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork, committedLanes, committedTransitions); + } else { + if (finishedWork.mode & ConcurrentMode) { + // The effects are currently disconnected. Since the tree is hidden, + // don't connect them. This also applies to the initial render. + { + // "Atomic" effects are ones that need to fire on every commit, + // even during pre-rendering. An example is updating the reference + // count on cache instances. + recursivelyTraverseAtomicPassiveEffects(finishedRoot, finishedWork); + } } else { - recursivelyAccumulateSuspenseyCommit(fiber); + // Legacy Mode: Fire the effects even if the tree is hidden. + _instance3._visibility |= OffscreenPassiveEffectsConnected; + recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork, committedLanes, committedTransitions); } } - - break; + } else { + // Tree is visible + if (_instance3._visibility & OffscreenPassiveEffectsConnected) { + // The effects are currently connected. Update them. + recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork, committedLanes, committedTransitions); + } 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; + var includeWorkInProgressEffects = (finishedWork.subtreeFlags & PassiveMask) !== NoFlags$1; + recursivelyTraverseReconnectPassiveEffects(finishedRoot, finishedWork, committedLanes, committedTransitions, includeWorkInProgressEffects); + } } - default: { - recursivelyAccumulateSuspenseyCommit(fiber); + if (flags & Passive$1) { + var _current = finishedWork.alternate; + commitOffscreenPassiveMountEffects(_current, finishedWork); } - } - } - - 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; + break; + } - do { - // $FlowFixMe[incompatible-use] found when upgrading Flow - var detachedSibling = detachedChild.sibling; // $FlowFixMe[incompatible-use] found when upgrading Flow + case CacheComponent: + { + recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork, committedLanes, committedTransitions); - detachedChild.sibling = null; - detachedChild = detachedSibling; - } while (detachedChild !== null); + if (flags & Passive$1) { + // TODO: Pass `current` as argument to this function + var _current2 = finishedWork.alternate; + commitCachePassiveMountEffect(_current2, finishedWork); } + + break; } - } - function commitHookPassiveUnmountEffects( - finishedWork, - nearestMountedAncestor, - hookFlags - ) { - if (shouldProfile(finishedWork)) { - startPassiveEffectTimer(); - commitHookEffectListUnmount( - hookFlags, - finishedWork, - nearestMountedAncestor - ); - recordPassiveEffectDuration(finishedWork); - } else { - commitHookEffectListUnmount( - hookFlags, - finishedWork, - nearestMountedAncestor - ); + case TracingMarkerComponent: + + default: + { + recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork, committedLanes, committedTransitions); + break; } - } + } +} - 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; +function recursivelyTraverseReconnectPassiveEffects(finishedRoot, parentFiber, committedLanes, committedTransitions, 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 & PassiveMask) !== NoFlags$1; // TODO (Offscreen) Check: flags & (RefStatic | LayoutStatic) - 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 prevDebugFiber = getCurrentFiber(); + var child = parentFiber.child; - nextEffect = childToDelete; - commitPassiveUnmountEffectsInsideOfDeletedTree_begin( - childToDelete, - parentFiber - ); - } - } + while (child !== null) { + reconnectPassiveEffects(finishedRoot, child, committedLanes, committedTransitions, childShouldIncludeWorkInProgressEffects); + child = child.sibling; + } - detachAlternateSiblings(parentFiber); - } + setCurrentFiber(prevDebugFiber); +} - var prevDebugFiber = getCurrentFiber(); // TODO: Split PassiveMask into separate masks for mount and unmount? +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) { + var flags = finishedWork.flags; - if (parentFiber.subtreeFlags & PassiveMask) { - var child = parentFiber.child; + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: + { + recursivelyTraverseReconnectPassiveEffects(finishedRoot, finishedWork, committedLanes, committedTransitions, includeWorkInProgressEffects); // TODO: Check for PassiveStatic flag - while (child !== null) { - setCurrentFiber(child); - commitPassiveUnmountOnFiber(child); - child = child.sibling; - } + 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: { + // ... + // } - setCurrentFiber(prevDebugFiber); - } - - function commitPassiveUnmountOnFiber(finishedWork) { - switch (finishedWork.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - recursivelyTraversePassiveUnmountEffects(finishedWork); + case LegacyHiddenComponent: + { - if (finishedWork.flags & Passive$1) { - commitHookPassiveUnmountEffects( - finishedWork, - finishedWork.return, - Passive | HasEffect - ); - } + break; + } - break; - } + case OffscreenComponent: + { + var _instance4 = finishedWork.stateNode; + var nextState = finishedWork.memoizedState; + var isHidden = nextState !== null; - case OffscreenComponent: { - var instance = finishedWork.stateNode; - var nextState = finishedWork.memoizedState; - var isHidden = nextState !== null; - - 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); + if (isHidden) { + if (_instance4._visibility & OffscreenPassiveEffectsConnected) { + // The effects are currently connected. Update them. + recursivelyTraverseReconnectPassiveEffects(finishedRoot, finishedWork, committedLanes, committedTransitions, includeWorkInProgressEffects); } else { - recursivelyTraversePassiveUnmountEffects(finishedWork); + if (finishedWork.mode & ConcurrentMode) { + // The effects are currently disconnected. Since the tree is hidden, + // don't connect them. This also applies to the initial render. + { + // "Atomic" effects are ones that need to fire on every commit, + // even during pre-rendering. An example is updating the reference + // count on cache instances. + recursivelyTraverseAtomicPassiveEffects(finishedRoot, finishedWork); + } + } else { + // Legacy Mode: Fire the effects even if the tree is hidden. + _instance4._visibility |= OffscreenPassiveEffectsConnected; + recursivelyTraverseReconnectPassiveEffects(finishedRoot, finishedWork, committedLanes, committedTransitions, includeWorkInProgressEffects); + } } - - break; + } 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, committedLanes, committedTransitions, includeWorkInProgressEffects); } - default: { - recursivelyTraversePassiveUnmountEffects(finishedWork); - break; + if (includeWorkInProgressEffects && flags & Passive$1) { + // TODO: Pass `current` as argument to this function + var _current3 = finishedWork.alternate; + commitOffscreenPassiveMountEffects(_current3, finishedWork); } - } - } - 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; + break; + } - 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 + case CacheComponent: + { + recursivelyTraverseReconnectPassiveEffects(finishedRoot, finishedWork, committedLanes, committedTransitions, includeWorkInProgressEffects); - nextEffect = childToDelete; - commitPassiveUnmountEffectsInsideOfDeletedTree_begin( - childToDelete, - parentFiber - ); - } + if (includeWorkInProgressEffects && flags & Passive$1) { + // TODO: Pass `current` as argument to this function + var _current4 = finishedWork.alternate; + commitCachePassiveMountEffect(_current4, finishedWork); } - detachAlternateSiblings(parentFiber); + break; } - var prevDebugFiber = getCurrentFiber(); // TODO: Check PassiveStatic flag + case TracingMarkerComponent: - var child = parentFiber.child; - - while (child !== null) { - setCurrentFiber(child); - disconnectPassiveEffect(child); - child = child.sibling; + default: + { + recursivelyTraverseReconnectPassiveEffects(finishedRoot, finishedWork, committedLanes, committedTransitions, includeWorkInProgressEffects); + break; } + } +} - setCurrentFiber(prevDebugFiber); - } +function recursivelyTraverseAtomicPassiveEffects(finishedRoot, parentFiber, committedLanes, committedTransitions) { + // "Atomic" effects are ones that need to fire on every commit, even during + // pre-rendering. We call this function when traversing a hidden tree whose + // regular effects are currently disconnected. + var prevDebugFiber = getCurrentFiber(); // TODO: Add special flag for atomic effects - 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 (parentFiber.subtreeFlags & PassiveMask) { + var child = parentFiber.child; - recursivelyTraverseDisconnectPassiveEffects(finishedWork); - break; - } + while (child !== null) { + setCurrentFiber(child); + commitAtomicPassiveEffects(finishedRoot, child); + child = child.sibling; + } + } - case OffscreenComponent: { - var instance = finishedWork.stateNode; + setCurrentFiber(prevDebugFiber); +} - if (instance._visibility & OffscreenPassiveEffectsConnected) { - instance._visibility &= ~OffscreenPassiveEffectsConnected; - recursivelyTraverseDisconnectPassiveEffects(finishedWork); - } +function commitAtomicPassiveEffects(finishedRoot, finishedWork, committedLanes, committedTransitions) { + // "Atomic" effects are ones that need to fire on every commit, even during + // pre-rendering. We call this function when traversing a hidden tree whose + // regular effects are currently disconnected. + var flags = finishedWork.flags; - break; - } + switch (finishedWork.tag) { + case OffscreenComponent: + { + recursivelyTraverseAtomicPassiveEffects(finishedRoot, finishedWork); - default: { - recursivelyTraverseDisconnectPassiveEffects(finishedWork); - break; + if (flags & Passive$1) { + // TODO: Pass `current` as argument to this function + var current = finishedWork.alternate; + commitOffscreenPassiveMountEffects(current, 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 + break; + } - setCurrentFiber(fiber); - commitPassiveUnmountInsideDeletedTreeOnFiber( - fiber, - nearestMountedAncestor - ); - resetCurrentFiber(); - var child = fiber.child; // TODO: Only traverse subtree if it has a PassiveStatic flag. + case CacheComponent: + { + recursivelyTraverseAtomicPassiveEffects(finishedRoot, finishedWork); - if (child !== null) { - child.return = fiber; - nextEffect = child; - } else { - commitPassiveUnmountEffectsInsideOfDeletedTree_complete( - deletedSubtreeRoot - ); + if (flags & Passive$1) { + // TODO: Pass `current` as argument to this function + var _current5 = finishedWork.alternate; + commitCachePassiveMountEffect(_current5, finishedWork); } - } - } - 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. + break; + } - detachFiberAfterEffects(fiber); + default: + { + recursivelyTraverseAtomicPassiveEffects(finishedRoot, finishedWork); + break; + } + } +} - if (fiber === deletedSubtreeRoot) { - nextEffect = null; - return; - } +function commitPassiveUnmountEffects(finishedWork) { + setCurrentFiber(finishedWork); + commitPassiveUnmountOnFiber(finishedWork); + resetCurrentFiber(); +} // If we're inside a brand new tree, or a tree that was already visible, then we +// should only suspend host components that have a ShouldSuspendCommit flag. +// Components without it haven't changed since the last commit, so we can skip +// over those. +// +// When we enter a tree that is being revealed (going from hidden -> visible), +// we need to suspend _any_ component that _may_ suspend. Even if they're +// already in the "current" tree. Because their visibility has changed, the +// browser may not have prerendered them yet. So we check the MaySuspendCommit +// flag instead. + +var suspenseyCommitFlag = ShouldSuspendCommit; +function accumulateSuspenseyCommit(finishedWork) { + accumulateSuspenseyCommitOnFiber(finishedWork); +} - if (sibling !== null) { - sibling.return = returnFiber; - nextEffect = sibling; - return; - } +function recursivelyAccumulateSuspenseyCommit(parentFiber) { + if (parentFiber.subtreeFlags & suspenseyCommitFlag) { + var child = parentFiber.child; - nextEffect = returnFiber; - } + while (child !== null) { + accumulateSuspenseyCommitOnFiber(child); + child = child.sibling; } + } +} - function commitPassiveUnmountInsideDeletedTreeOnFiber( - current, - nearestMountedAncestor - ) { - switch (current.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - commitHookPassiveUnmountEffects( - current, - nearestMountedAncestor, - Passive - ); - break; - } - // TODO: run passive unmount effects when unmounting a root. - // Because passive unmount effects are not currently run, - // the cache instance owned by the root will never be freed. - // When effects are run, the cache should be freed here: - // case HostRoot: { - // if (enableCache) { - // const cache = current.memoizedState.cache; - // releaseCache(cache); - // } - // break; - // } - - case LegacyHiddenComponent: - case OffscreenComponent: { - { - if ( - current.memoizedState !== null && - current.memoizedState.cachePool !== null - ) { - var cache = current.memoizedState.cachePool.pool; // Retain/release the cache used for pending (suspended) nodes. - // Note that this is only reached in the non-suspended/visible case: - // when the content is suspended/hidden, the retain/release occurs - // via the parent Suspense component (see case above). - - if (cache != null) { - retainCache(cache); - } - } - } +function accumulateSuspenseyCommitOnFiber(fiber) { + switch (fiber.tag) { + case HostHoistable: + { + recursivelyAccumulateSuspenseyCommit(fiber); - break; + if (fiber.flags & suspenseyCommitFlag) { + if (fiber.memoizedState !== null) { + suspendResource(); + } } - case SuspenseComponent: { - break; - } + break; + } - case CacheComponent: { - { - var _cache = current.memoizedState.cache; - releaseCache(_cache); - } + case HostComponent: + { + recursivelyAccumulateSuspenseyCommit(fiber); - break; - } + break; } - } - function invokeLayoutEffectMountInDEV(fiber) { + case HostRoot: + case HostPortal: { - // 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); - } + { + recursivelyAccumulateSuspenseyCommit(fiber); + } - break; - } + break; + } - case ClassComponent: { - var instance = fiber.stateNode; + case OffscreenComponent: + { + var isHidden = fiber.memoizedState !== null; - if (typeof instance.componentDidMount === "function") { - try { - instance.componentDidMount(); - } catch (error) { - captureCommitPhaseError(fiber, fiber.return, error); - } - } + if (isHidden) ; else { + var current = fiber.alternate; + var wasHidden = current !== null && current.memoizedState !== null; - break; + if (wasHidden) { + // This tree is being revealed. Visit all newly visible suspensey + // instances, even if they're in the current tree. + var prevFlags = suspenseyCommitFlag; + suspenseyCommitFlag = MaySuspendCommit; + recursivelyAccumulateSuspenseyCommit(fiber); + suspenseyCommitFlag = prevFlags; + } else { + recursivelyAccumulateSuspenseyCommit(fiber); } } + + break; } - } - function invokePassiveEffectMountInDEV(fiber) { + default: { - // 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); - } + recursivelyAccumulateSuspenseyCommit(fiber); + } + } +} - break; - } - } +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); + } + } +} + +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; + + 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); } } - 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); - } + detachAlternateSiblings(parentFiber); + } - break; - } + var prevDebugFiber = getCurrentFiber(); // TODO: Split PassiveMask into separate masks for mount and unmount? - case ClassComponent: { - var instance = fiber.stateNode; + if (parentFiber.subtreeFlags & PassiveMask) { + var child = parentFiber.child; - if (typeof instance.componentWillUnmount === "function") { - safelyCallComponentWillUnmount(fiber, fiber.return, instance); - } + while (child !== null) { + setCurrentFiber(child); + commitPassiveUnmountOnFiber(child); + child = child.sibling; + } + } - break; - } + setCurrentFiber(prevDebugFiber); +} + +function commitPassiveUnmountOnFiber(finishedWork) { + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: + { + recursivelyTraversePassiveUnmountEffects(finishedWork); + + if (finishedWork.flags & Passive$1) { + commitHookPassiveUnmountEffects(finishedWork, finishedWork.return, Passive | HasEffect); } + + break; } - } - function invokePassiveEffectUnmountInDEV(fiber) { + case OffscreenComponent: { - // 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); - } - } + var instance = finishedWork.stateNode; + var nextState = finishedWork.memoizedState; + var isHidden = nextState !== null; + + 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); } - } - } - function getCacheForType(resourceType) { - var cache = readContext(CacheContext); - var cacheForType = cache.data.get(resourceType); + break; + } - if (cacheForType === undefined) { - cacheForType = resourceType(); - cache.data.set(resourceType, cacheForType); + default: + { + recursivelyTraversePassiveUnmountEffects(finishedWork); + break; } + } +} - return cacheForType; - } +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 DefaultCacheDispatcher = { - getCacheForType: getCacheForType - }; + 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 (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"); + nextEffect = childToDelete; + commitPassiveUnmountEffectsInsideOfDeletedTree_begin(childToDelete, parentFiber); + } } - 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[cannot-resolve-name] - 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 && - ReactSharedInternals.actQueue !== null - ) { - // TODO: Include link to relevant documentation page. - error( - "The current testing environment is not configured to support " + - "act(...)" - ); - } - - return isReactActEnvironmentGlobal; - } - } - - var PossiblyWeakMap = typeof WeakMap === "function" ? WeakMap : Map; - 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 executionContext = NoContext; // The root we're working on - - var workInProgressRoot = null; // The fiber we're working on - - var workInProgress = null; // The lanes we're rendering - - 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 entangledRenderLanes. - - var entangledRenderLanes = NoLanes; // Whether to root completed, errored, suspended, etc. + detachAlternateSiblings(parentFiber); + } - var workInProgressRootExitStatus = RootInProgress; // The work left over by components that were visited during this render. Only - // includes unprocessed updates, not work in bailed out children. + var prevDebugFiber = getCurrentFiber(); // TODO: Check PassiveStatic flag - var workInProgressRootSkippedLanes = NoLanes; // Lanes that were updated (in an interleaved event) during this render. + var child = parentFiber.child; - var workInProgressRootInterleavedUpdatedLanes = NoLanes; // Lanes that were updated during the render phase (*not* an interleaved event). + while (child !== null) { + setCurrentFiber(child); + disconnectPassiveEffect(child); + child = child.sibling; + } - var workInProgressRootPingedLanes = NoLanes; // If this lane scheduled deferred work, this is the lane of the deferred task. + setCurrentFiber(prevDebugFiber); +} - var workInProgressDeferredLane = NoLane; // Errors that are thrown during the render phase. +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 workInProgressRootConcurrentErrors = null; // These are errors that we recovered from without surfacing them to the UI. - // We will log them once the tree commits. + recursivelyTraverseDisconnectPassiveEffects(finishedWork); + break; + } - var workInProgressRootRecoverableErrors = null; // Tracks when an update occurs during the render phase. + case OffscreenComponent: + { + var instance = finishedWork.stateNode; - var workInProgressRootDidIncludeRecursiveRenderUpdate = false; // Thacks when an update occurs during the commit phase. It's a separate - // variable from the one for renders because the commit phase may run - // concurrently to a render phase. + if (instance._visibility & OffscreenPassiveEffectsConnected) { + instance._visibility &= ~OffscreenPassiveEffectsConnected; + recursivelyTraverseDisconnectPassiveEffects(finishedWork); + } - var didIncludeCommitPhaseUpdate = false; // The most recent time we either committed a fallback, or when a fallback was - // filled in with the resolved UI. This lets us throttle the appearance of new - // content as it streams in, to minimize jank. - // TODO: Think of a better name for this variable? + break; + } - var globalMostRecentFallbackTime = 0; - var FALLBACK_THROTTLE_MS = 300; // The absolute time for when we should start giving up on rendering - // more and prefer CPU suspense heuristics instead. + default: + { + recursivelyTraverseDisconnectPassiveEffects(finishedWork); + break; + } + } +} - 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. +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 - var RENDER_TIMEOUT_MS = 500; - var workInProgressTransitions = null; + setCurrentFiber(fiber); + commitPassiveUnmountInsideDeletedTreeOnFiber(fiber, nearestMountedAncestor); + resetCurrentFiber(); + var child = fiber.child; // TODO: Only traverse subtree if it has a PassiveStatic flag. - function resetRenderTimer() { - workInProgressRootRenderTargetTime = now$1() + RENDER_TIMEOUT_MS; + if (child !== null) { + child.return = fiber; + nextEffect = child; + } else { + commitPassiveUnmountEffectsInsideOfDeletedTree_complete(deletedSubtreeRoot); } + } +} - function getRenderTargetTime() { - return workInProgressRootRenderTargetTime; - } - var legacyErrorBoundariesThatAlreadyFailed = null; - var rootDoesHavePassiveEffects = false; - var rootWithPendingPassiveEffects = null; - var pendingPassiveEffectsLanes = NoLanes; - var pendingPassiveProfilerEffects = []; - var pendingPassiveEffectsRemainingLanes = NoLanes; - var pendingPassiveTransitions = null; // Use these to prevent an infinite loop of nested updates +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. - 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; - var isRunningInsertionEffect = false; - function getWorkInProgressRoot() { - return workInProgressRoot; - } - function getWorkInProgressRootRenderLanes() { - return workInProgressRootRenderLanes; - } - function isWorkLoopSuspendedOnData() { - return workInProgressSuspendedReason === SuspendedOnData; + detachFiberAfterEffects(fiber); + + if (fiber === deletedSubtreeRoot) { + nextEffect = null; + return; } - function requestUpdateLane(fiber) { - // Special cases - var mode = fiber.mode; - 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 (sibling !== null) { + sibling.return = returnFiber; + nextEffect = sibling; + return; + } - var transition = requestCurrentTransition(); + nextEffect = returnFiber; + } +} - if (transition !== null) { +function commitPassiveUnmountInsideDeletedTreeOnFiber(current, nearestMountedAncestor) { + switch (current.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: + { + commitHookPassiveUnmountEffects(current, nearestMountedAncestor, Passive); + break; + } + // TODO: run passive unmount effects when unmounting a root. + // Because passive unmount effects are not currently run, + // the cache instance owned by the root will never be freed. + // When effects are run, the cache should be freed here: + // case HostRoot: { + // if (enableCache) { + // const cache = current.memoizedState.cache; + // releaseCache(cache); + // } + // break; + // } + + case LegacyHiddenComponent: + case OffscreenComponent: + { { - if (!transition._updatedFibers) { - transition._updatedFibers = new Set(); + if (current.memoizedState !== null && current.memoizedState.cachePool !== null) { + var cache = current.memoizedState.cachePool.pool; // Retain/release the cache used for pending (suspended) nodes. + // Note that this is only reached in the non-suspended/visible case: + // when the content is suspended/hidden, the retain/release occurs + // via the parent Suspense component (see case above). + + if (cache != null) { + retainCache(cache); + } } - - transition._updatedFibers.add(fiber); } - var actionScopeLane = peekEntangledActionLane(); - return actionScopeLane !== NoLane // We're inside an async action scope. Reuse the same lane. - ? actionScopeLane // We may or may not be inside an async action scope. If we are, this - : // is the first update in that scope. Either way, we need to get a - // fresh transition lane. - requestTransitionLane(); + break; } - return eventPriorityToLane(resolveUpdatePriority()); - } - - 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; + case SuspenseComponent: + { - if ((mode & ConcurrentMode) === NoMode) { - return SyncLane; + break; } - return claimNextRetryLane(); - } + case CacheComponent: + { + { + var _cache = current.memoizedState.cache; + releaseCache(_cache); + } - function requestDeferredLane() { - if (workInProgressDeferredLane === NoLane) { - // If there are multiple useDeferredValue hooks in the same render, the - // tasks that they spawn should all be batched together, so they should all - // receive the same lane. - // Check the priority of the current render to decide the priority of the - // deferred task. - // OffscreenLane is used for prerendering, but we also use OffscreenLane - // for incremental hydration. It's given the lowest priority because the - // initial HTML is the same as the final UI. But useDeferredValue during - // hydration is an exception — we need to upgrade the UI to the final - // value. So if we're currently hydrating, we treat it like a transition. - var isPrerendering = - includesSomeLane(workInProgressRootRenderLanes, OffscreenLane) && - !getIsHydrating(); + break; + } + } +} - if (isPrerendering) { - // There's only one OffscreenLane, so if it contains deferred work, we - // should just reschedule using the same lane. - workInProgressDeferredLane = OffscreenLane; - } else { - // Everything else is spawned as a transition. - workInProgressDeferredLane = claimNextTransitionLane(); +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); + } + + break; } - } // Mark the parent Suspense boundary so it knows to spawn the deferred lane. - var suspenseHandler = getSuspenseHandler(); + case ClassComponent: + { + var instance = fiber.stateNode; - if (suspenseHandler !== null) { - // TODO: As an optimization, we shouldn't entangle the lanes at the root; we - // can entangle them using the baseLanes of the Suspense boundary instead. - // We only need to do something special if there's no Suspense boundary. - suspenseHandler.flags |= DidDefer; - } + if (typeof instance.componentDidMount === 'function') { + try { + instance.componentDidMount(); + } catch (error) { + captureCommitPhaseError(fiber, fiber.return, error); + } + } - return workInProgressDeferredLane; - } - function peekDeferredLane() { - return workInProgressDeferredLane; + break; + } } - function scheduleUpdateOnFiber(root, fiber, lane) { - { - if (isRunningInsertionEffect) { - error("useInsertionEffect must not schedule updates."); + } +} + +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; } - } + } + } +} - { - if (isFlushingPassiveEffects) { - didScheduleUpdateDuringPassiveEffects = true; - } - } // Check if the work loop is currently suspended and waiting for data to - // finish loading. - - if ( - // Suspended render phase - (root === workInProgressRoot && - workInProgressSuspendedReason === SuspendedOnData) || // Suspended commit phase - root.cancelPendingCommit !== null - ) { - // The incoming update might unblock the current render. Interrupt the - // current attempt and restart from the top. - prepareFreshStack(root, NoLanes); - markRootSuspended( - root, - workInProgressRootRenderLanes, - workInProgressDeferredLane - ); - } // Mark that the root has a pending update. - - markRootUpdated(root, lane); - - 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. +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: { - if (isDevToolsPresent) { - addFiberToLanesMap(root, fiber, lane); + try { + commitHookEffectListUnmount(Layout | HasEffect, fiber, fiber.return); + } catch (error) { + captureCommitPhaseError(fiber, fiber.return, error); } + + break; } - warnIfUpdatesNotWrappedWithActDEV(fiber); + case ClassComponent: + { + var instance = fiber.stateNode; - 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. - if ((executionContext & RenderContext) === NoContext) { - workInProgressRootInterleavedUpdatedLanes = mergeLanes( - workInProgressRootInterleavedUpdatedLanes, - lane - ); + if (typeof instance.componentWillUnmount === 'function') { + safelyCallComponentWillUnmount(fiber, fiber.return, instance); } - 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, - workInProgressDeferredLane - ); - } + break; } + } + } +} - ensureRootIsScheduled(root); - - if ( - lane === SyncLane && - executionContext === NoContext && - !disableLegacyMode && - (fiber.mode & ConcurrentMode) === NoMode - ) { - if (ReactSharedInternals.isBatchingLegacy); - else { - // 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(); - flushSyncWorkOnLegacyRootsOnly(); +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 isUnsafeClassRenderPhaseUpdate(fiber) { - // Check if this is a render phase update. Only called by class components, - // which special (deprecated) behavior for UNSAFE_componentWillReceive props. - return (executionContext & RenderContext) !== NoContext; - } // This is the entry point for every concurrent task, i.e. anything that - // goes through Scheduler. - - function performConcurrentWorkOnRoot(root, didTimeout) { - { - resetNestedUpdateFlag(); - } - - 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 originalCallbackNode = root.callbackNode; - var didFlushPassiveEffects = flushPassiveEffects(); - - 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. - // TODO: This was already computed in the caller. Pass it as an argument. + } +} - var lanes = getNextLanes( - root, - root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes - ); +function getCacheForType(resourceType) { - 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. - - var shouldTimeSlice = - !includesBlockingLane(root, lanes) && - !includesExpiredLane(root, lanes) && - !didTimeout; - var exitStatus = shouldTimeSlice - ? renderRootConcurrent(root, lanes) - : renderRootSync(root, lanes); - - if (exitStatus !== RootInProgress) { - var renderWasConcurrent = shouldTimeSlice; + var cache = readContext(CacheContext); + var cacheForType = cache.data.get(resourceType); - do { - 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, NoLane); - } 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 finishedWork = root.current.alternate; - - if ( - renderWasConcurrent && - !isRenderConsistentWithExternalStores(finishedWork) - ) { - // A store was mutated in an interleaved event. Render again, - // synchronously, to block further mutations. - exitStatus = renderRootSync(root, lanes); // We assume the tree is now consistent because we didn't yield to any - // concurrent events. - - renderWasConcurrent = false; // Need to check the exit status again. + if (cacheForType === undefined) { + cacheForType = resourceType(); + cache.data.set(resourceType, cacheForType); + } - continue; - } // Check if something threw - - if (exitStatus === RootErrored) { - var lanesThatJustErrored = lanes; - var errorRetryLanes = getLanesToRetrySynchronouslyOnError( - root, - lanesThatJustErrored - ); - - if (errorRetryLanes !== NoLanes) { - lanes = errorRetryLanes; - exitStatus = recoverFromConcurrentError( - root, - lanesThatJustErrored, - errorRetryLanes - ); - renderWasConcurrent = false; // Need to check the exit status again. - - if (exitStatus !== RootErrored) { - // The root did not error this time. Restart the exit algorithm - // from the beginning. - // TODO: Refactor the exit algorithm to be less confusing. Maybe - // more branches + recursion instead of a loop. I think the only - // thing that causes it to be a loop is the RootDidNotComplete - // check. If that's true, then we don't need a loop/recursion - // at all. - continue; - } - } - } + return cacheForType; +} - if (exitStatus === RootFatalErrored) { - prepareFreshStack(root, NoLanes); - markRootSuspended(root, lanes, NoLane); - break; - } // 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. +var DefaultCacheDispatcher = { + getCacheForType: getCacheForType +}; + +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'); +} - root.finishedWork = finishedWork; - root.finishedLanes = lanes; - finishConcurrentRender(root, exitStatus, finishedWork, lanes); - } +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[cannot-resolve-name] - 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; - break; - } while (true); - } - - ensureRootIsScheduled(root); - return getContinuationForRoot(root, originalCallbackNode); - } - - 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 = supportsHydration; - - var exitStatus = renderRootSync(root, errorRetryLanes); - - 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 (!isReactActEnvironmentGlobal && ReactSharedInternals.actQueue !== null) { + // TODO: Include link to relevant documentation page. + error('The current testing environment is not configured to support ' + 'act(...)'); + } - 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. + return isReactActEnvironmentGlobal; + } +} - 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. +var PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map; +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 executionContext = NoContext; // The root we're working on + +var workInProgressRoot = null; // The fiber we're working on + +var workInProgress = null; // The lanes we're rendering + +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 entangledRenderLanes. + +var entangledRenderLanes = NoLanes; // Whether to root completed, errored, suspended, etc. + +var workInProgressRootExitStatus = RootInProgress; // The work left over by components that were visited during this render. Only +// includes unprocessed updates, not work in bailed out children. + +var workInProgressRootSkippedLanes = NoLanes; // Lanes that were updated (in an interleaved event) during this render. + +var workInProgressRootInterleavedUpdatedLanes = NoLanes; // Lanes that were updated during the render phase (*not* an interleaved event). + +var workInProgressRootPingedLanes = NoLanes; // If this lane scheduled deferred work, this is the lane of the deferred task. + +var workInProgressDeferredLane = NoLane; // Errors that are thrown during the render phase. + +var workInProgressRootConcurrentErrors = null; // These are errors that we recovered from without surfacing them to the UI. +// We will log them once the tree commits. + +var workInProgressRootRecoverableErrors = null; // Tracks when an update occurs during the render phase. + +var workInProgressRootDidIncludeRecursiveRenderUpdate = false; // Thacks when an update occurs during the commit phase. It's a separate +// variable from the one for renders because the commit phase may run +// concurrently to a render phase. + +var didIncludeCommitPhaseUpdate = false; // The most recent time we either committed a fallback, or when a fallback was +// filled in with the resolved UI. This lets us throttle the appearance of new +// content as it streams in, to minimize jank. +// TODO: Think of a better name for this variable? + +var globalMostRecentFallbackTime = 0; +var FALLBACK_THROTTLE_MS = 300; // The absolute time for when we should start giving up on rendering +// more and prefer CPU suspense heuristics instead. + +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 RENDER_TIMEOUT_MS = 500; +var workInProgressTransitions = null; + +function resetRenderTimer() { + workInProgressRootRenderTargetTime = now$1() + RENDER_TIMEOUT_MS; +} - if (errorsFromSecondAttempt !== null) { - queueRecoverableErrors(errorsFromSecondAttempt); - } +function getRenderTargetTime() { + return workInProgressRootRenderTargetTime; +} +var legacyErrorBoundariesThatAlreadyFailed = null; +var rootDoesHavePassiveEffects = false; +var rootWithPendingPassiveEffects = null; +var pendingPassiveEffectsLanes = NoLanes; +var pendingPassiveProfilerEffects = []; +var pendingPassiveEffectsRemainingLanes = NoLanes; +var pendingPassiveTransitions = null; // Use these to prevent an infinite loop of nested updates + +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; +var isRunningInsertionEffect = false; +function getWorkInProgressRoot() { + return workInProgressRoot; +} +function getWorkInProgressRootRenderLanes() { + return workInProgressRootRenderLanes; +} +function isWorkLoopSuspendedOnData() { + return workInProgressSuspendedReason === SuspendedOnData; +} +function requestUpdateLane(fiber) { + // Special cases + var mode = fiber.mode; + + 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); + } + + var transition = requestCurrentTransition(); + + if (transition !== null) { + { + if (!transition._updatedFibers) { + transition._updatedFibers = new Set(); } - return exitStatus; + transition._updatedFibers.add(fiber); } - function queueRecoverableErrors(errors) { - if (workInProgressRootRecoverableErrors === null) { - workInProgressRootRecoverableErrors = errors; - } else { - // $FlowFixMe[method-unbinding] - workInProgressRootRecoverableErrors.push.apply( - workInProgressRootRecoverableErrors, - errors - ); - } - } - - function finishConcurrentRender(root, exitStatus, finishedWork, lanes) { - // TODO: The fact that most of these branches are identical suggests that some - // of the exit statuses are not best modeled as exit statuses and should be - // tracked orthogonally. - switch (exitStatus) { - case RootInProgress: - case RootFatalErrored: { - throw new Error("Root did not complete. This is a bug in React."); - } - - case RootSuspendedWithDelay: { - 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. - markRootSuspended(root, lanes, workInProgressDeferredLane); - return; - } // Commit the placeholder. + var actionScopeLane = peekEntangledActionLane(); + return actionScopeLane !== NoLane ? // We're inside an async action scope. Reuse the same lane. + actionScopeLane : // We may or may not be inside an async action scope. If we are, this + // is the first update in that scope. Either way, we need to get a + // fresh transition lane. + requestTransitionLane(); + } - break; - } + return eventPriorityToLane(resolveUpdatePriority()); +} - case RootErrored: { - // This render errored. Ignore any recoverable errors because we weren't actually - // able to recover. Instead, whatever the final errors were is the ones we log. - // This ensures that we only log the actual client side error if it's just a plain - // error thrown from a component on the server and the client. - workInProgressRootRecoverableErrors = null; - break; - } +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; - case RootSuspended: - case RootCompleted: { - break; - } + if ((mode & ConcurrentMode) === NoMode) { + return SyncLane; + } - default: { - throw new Error("Unknown root exit status."); - } + return claimNextRetryLane(); +} + +function requestDeferredLane() { + if (workInProgressDeferredLane === NoLane) { + // If there are multiple useDeferredValue hooks in the same render, the + // tasks that they spawn should all be batched together, so they should all + // receive the same lane. + // Check the priority of the current render to decide the priority of the + // deferred task. + // OffscreenLane is used for prerendering, but we also use OffscreenLane + // for incremental hydration. It's given the lowest priority because the + // initial HTML is the same as the final UI. But useDeferredValue during + // hydration is an exception — we need to upgrade the UI to the final + // value. So if we're currently hydrating, we treat it like a transition. + var isPrerendering = includesSomeLane(workInProgressRootRenderLanes, OffscreenLane) && !getIsHydrating(); + + if (isPrerendering) { + // There's only one OffscreenLane, so if it contains deferred work, we + // should just reschedule using the same lane. + workInProgressDeferredLane = OffscreenLane; + } else { + // Everything else is spawned as a transition. + workInProgressDeferredLane = claimNextTransitionLane(); + } + } // Mark the parent Suspense boundary so it knows to spawn the deferred lane. + + + var suspenseHandler = getSuspenseHandler(); + + if (suspenseHandler !== null) { + // TODO: As an optimization, we shouldn't entangle the lanes at the root; we + // can entangle them using the baseLanes of the Suspense boundary instead. + // We only need to do something special if there's no Suspense boundary. + suspenseHandler.flags |= DidDefer; + } + + return workInProgressDeferredLane; +} +function peekDeferredLane() { + return workInProgressDeferredLane; +} +function scheduleUpdateOnFiber(root, fiber, lane) { + { + if (isRunningInsertionEffect) { + error('useInsertionEffect must not schedule updates.'); + } + } + + { + if (isFlushingPassiveEffects) { + didScheduleUpdateDuringPassiveEffects = true; + } + } // Check if the work loop is currently suspended and waiting for data to + // finish loading. + + + if ( // Suspended render phase + root === workInProgressRoot && workInProgressSuspendedReason === SuspendedOnData || // Suspended commit phase + root.cancelPendingCommit !== null) { + // The incoming update might unblock the current render. Interrupt the + // current attempt and restart from the top. + prepareFreshStack(root, NoLanes); + markRootSuspended(root, workInProgressRootRenderLanes, workInProgressDeferredLane); + } // Mark that the root has a pending update. + + + markRootUpdated(root, lane); + + 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); } + } - if (shouldForceFlushFallbacksInDEV()) { - // We're inside an `act` scope. Commit immediately. - commitRoot( - root, - workInProgressRootRecoverableErrors, - workInProgressTransitions, - workInProgressRootDidIncludeRecursiveRenderUpdate, - workInProgressDeferredLane - ); - } else { - if ( - includesOnlyRetries(lanes) && - (alwaysThrottleRetries || exitStatus === RootSuspended) - ) { - // 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. - - if (msUntilTimeout > 10) { - markRootSuspended(root, lanes, workInProgressDeferredLane); - var nextLanes = getNextLanes(root, NoLanes); - - if (nextLanes !== NoLanes) { - // There's additional work we can do on this root. We might as well - // attempt to work on that while we're suspended. - return; - } // 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. - // TODO: Combine retry throttling with Suspensey commits. Right now they - // run one after the other. - - root.timeoutHandle = scheduleTimeout( - commitRootWhenReady.bind( - null, - root, - finishedWork, - workInProgressRootRecoverableErrors, - workInProgressTransitions, - workInProgressRootDidIncludeRecursiveRenderUpdate, - lanes, - workInProgressDeferredLane - ), - msUntilTimeout - ); - return; - } - } + warnIfUpdatesNotWrappedWithActDEV(fiber); - commitRootWhenReady( - root, - finishedWork, - workInProgressRootRecoverableErrors, - workInProgressTransitions, - workInProgressRootDidIncludeRecursiveRenderUpdate, - lanes, - workInProgressDeferredLane - ); - } - } - - function commitRootWhenReady( - root, - finishedWork, - recoverableErrors, - transitions, - didIncludeRenderPhaseUpdate, - lanes, - spawnedLane - ) { - // TODO: Combine retry throttling with Suspensey commits. Right now they run - // one after the other. - if (includesOnlyNonUrgentLanes(lanes)) { - // the suspensey resources. The renderer is responsible for accumulating - // all the load events. This all happens in a single synchronous - // transaction, so it track state in its own module scope. - - accumulateSuspenseyCommit(finishedWork); // At the end, ask the renderer if it's ready to commit, or if we should - // suspend. If it's not ready, it will return a callback to subscribe to - // a ready event. - - var schedulePendingCommit = waitForCommitToBeReady(); - - 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, - recoverableErrors, - transitions, - didIncludeRenderPhaseUpdate - ) - ); - markRootSuspended(root, lanes, spawnedLane); - return; - } - } // Otherwise, commit immediately. + 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. + 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, workInProgressDeferredLane); + } + } - commitRoot( - root, - recoverableErrors, - transitions, - didIncludeRenderPhaseUpdate, - spawnedLane - ); + ensureRootIsScheduled(root); + + if (lane === SyncLane && executionContext === NoContext && !disableLegacyMode && (fiber.mode & ConcurrentMode) === NoMode) { + if (ReactSharedInternals.isBatchingLegacy) ; else { + // 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(); + flushSyncWorkOnLegacyRootsOnly(); + } + } + } +} +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 (executionContext & RenderContext) !== NoContext; +} // This is the entry point for every concurrent task, i.e. anything that +// goes through Scheduler. + +function performConcurrentWorkOnRoot(root, didTimeout) { + { + resetNestedUpdateFlag(); + } + + 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 originalCallbackNode = root.callbackNode; + var didFlushPassiveEffects = flushPassiveEffects(); + + 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. + // TODO: This was already computed in the caller. Pass it as an argument. - 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; - while (true) { - if (node.flags & StoreConsistency) { - var updateQueue = node.updateQueue; + var lanes = getNextLanes(root, root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes); - if (updateQueue !== null) { - var checks = updateQueue.stores; - - if (checks !== null) { - for (var i = 0; i < checks.length; i++) { - var check = checks[i]; - var getSnapshot = check.getSnapshot; - var renderedValue = check.value; - - 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 (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. + + + var shouldTimeSlice = !includesBlockingLane(root, lanes) && !includesExpiredLane(root, lanes) && (!didTimeout); + var exitStatus = shouldTimeSlice ? renderRootConcurrent(root, lanes) : renderRootSync(root, lanes); + + if (exitStatus !== RootInProgress) { + var renderWasConcurrent = shouldTimeSlice; + + do { + 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, NoLane); + } 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 finishedWork = root.current.alternate; + + if (renderWasConcurrent && !isRenderConsistentWithExternalStores(finishedWork)) { + // A store was mutated in an interleaved event. Render again, + // synchronously, to block further mutations. + exitStatus = renderRootSync(root, lanes); // We assume the tree is now consistent because we didn't yield to any + // concurrent events. + + renderWasConcurrent = false; // Need to check the exit status again. + + continue; + } // Check if something threw + + + if (exitStatus === RootErrored) { + var lanesThatJustErrored = lanes; + var errorRetryLanes = getLanesToRetrySynchronouslyOnError(root, lanesThatJustErrored); + + if (errorRetryLanes !== NoLanes) { + lanes = errorRetryLanes; + exitStatus = recoverFromConcurrentError(root, lanesThatJustErrored, errorRetryLanes); + renderWasConcurrent = false; // Need to check the exit status again. + + if (exitStatus !== RootErrored) { + // The root did not error this time. Restart the exit algorithm + // from the beginning. + // TODO: Refactor the exit algorithm to be less confusing. Maybe + // more branches + recursion instead of a loop. I think the only + // thing that causes it to be a loop is the RootDidNotComplete + // check. If that's true, then we don't need a loop/recursion + // at all. + continue; } } } - var child = node.child; + if (exitStatus === RootFatalErrored) { + prepareFreshStack(root, NoLanes); + markRootSuspended(root, lanes, NoLane); + break; + } // 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. - if (node.subtreeFlags & StoreConsistency && child !== null) { - child.return = node; - node = child; - continue; - } - if (node === finishedWork) { - return true; - } + root.finishedWork = finishedWork; + root.finishedLanes = lanes; + finishConcurrentRender(root, exitStatus, finishedWork, lanes); + } - while (node.sibling === null) { - if (node.return === null || node.return === finishedWork) { - return true; - } + break; + } while (true); + } - node = node.return; - } + ensureRootIsScheduled(root); + return getContinuationForRoot(root, originalCallbackNode); +} - node.sibling.return = node.return; - node = node.sibling; - } // Flow doesn't know this is unreachable, but eslint does - // eslint-disable-next-line no-unreachable +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 = supportsHydration ; + + var exitStatus = renderRootSync(root, errorRetryLanes); + + 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. - return true; - } // The extra indirections around markRootUpdated and markRootSuspended is - // needed to avoid a circular dependency between this module and - // ReactFiberLane. There's probably a better way to split up these modules and - // avoid this problem. Perhaps all the root-marking functions should move into - // the work loop. + 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. - function markRootUpdated(root, updatedLanes) { - markRootUpdated$1(root, updatedLanes); - if (enableInfiniteRenderLoopDetection) { - // Check for recursive updates - if (executionContext & RenderContext) { - workInProgressRootDidIncludeRecursiveRenderUpdate = true; - } else if (executionContext & CommitContext) { - didIncludeCommitPhaseUpdate = true; - } + 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. - throwIfInfiniteUpdateLoopDetected(); - } + if (errorsFromSecondAttempt !== null) { + queueRecoverableErrors(errorsFromSecondAttempt); } + } - function markRootPinged(root, pingedLanes) { - markRootPinged$1(root, pingedLanes); + return exitStatus; +} - if (enableInfiniteRenderLoopDetection) { - // Check for recursive pings. Pings are conceptually different from updates in - // other contexts but we call it an "update" in this context because - // repeatedly pinging a suspended render can cause a recursive render loop. - // The relevant property is that it can result in a new render attempt - // being scheduled. - if (executionContext & RenderContext) { - workInProgressRootDidIncludeRecursiveRenderUpdate = true; - } else if (executionContext & CommitContext) { - didIncludeCommitPhaseUpdate = true; - } +function queueRecoverableErrors(errors) { + if (workInProgressRootRecoverableErrors === null) { + workInProgressRootRecoverableErrors = errors; + } else { + // $FlowFixMe[method-unbinding] + workInProgressRootRecoverableErrors.push.apply(workInProgressRootRecoverableErrors, errors); + } +} - throwIfInfiniteUpdateLoopDetected(); +function finishConcurrentRender(root, exitStatus, finishedWork, lanes) { + // TODO: The fact that most of these branches are identical suggests that some + // of the exit statuses are not best modeled as exit statuses and should be + // tracked orthogonally. + switch (exitStatus) { + case RootInProgress: + case RootFatalErrored: + { + throw new Error('Root did not complete. This is a bug in React.'); } - } - function markRootSuspended(root, suspendedLanes, spawnedLane) { - // When suspending, we should always exclude lanes that were pinged or (more - // rarely, since we try to avoid it) updated during the render phase. - suspendedLanes = removeLanes( - suspendedLanes, - workInProgressRootPingedLanes - ); - suspendedLanes = removeLanes( - suspendedLanes, - workInProgressRootInterleavedUpdatedLanes - ); + case RootSuspendedWithDelay: + { + 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. + markRootSuspended(root, lanes, workInProgressDeferredLane); + return; + } // Commit the placeholder. - markRootSuspended$1(root, suspendedLanes, spawnedLane); - } // This is the entry point for synchronous tasks that don't go - // through Scheduler - function performSyncWorkOnRoot(root, lanes) { - if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { - throw new Error("Should not already be working."); + break; } - var didFlushPassiveEffects = flushPassiveEffects(); + case RootErrored: + { + // This render errored. Ignore any recoverable errors because we weren't actually + // able to recover. Instead, whatever the final errors were is the ones we log. + // This ensures that we only log the actual client side error if it's just a plain + // error thrown from a component on the server and the client. + workInProgressRootRecoverableErrors = null; + break; + } - if (didFlushPassiveEffects) { - // If passive effects were flushed, exit to the outer work loop in the root - // scheduler, so we can recompute the priority. - // TODO: We don't actually need this `ensureRootIsScheduled` call because - // this path is only reachable if the root is already part of the schedule. - // I'm including it only for consistency with the other exit points from - // this function. Can address in a subsequent refactor. - ensureRootIsScheduled(root); - return null; + case RootSuspended: + case RootCompleted: + { + break; } + default: { - syncNestedUpdateFlag(); + throw new Error('Unknown root exit status.'); } + } + + if (shouldForceFlushFallbacksInDEV()) { + // We're inside an `act` scope. Commit immediately. + commitRoot(root, workInProgressRootRecoverableErrors, workInProgressTransitions, workInProgressRootDidIncludeRecursiveRenderUpdate, workInProgressDeferredLane); + } else { + if (includesOnlyRetries(lanes) && (alwaysThrottleRetries || exitStatus === RootSuspended)) { + // 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 exitStatus = renderRootSync(root, lanes); + if (msUntilTimeout > 10) { + markRootSuspended(root, lanes, workInProgressDeferredLane); + var nextLanes = getNextLanes(root, NoLanes); - 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 (nextLanes !== NoLanes) { + // There's additional work we can do on this root. We might as well + // attempt to work on that while we're suspended. + return; + } // 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. + // TODO: Combine retry throttling with Suspensey commits. Right now they + // run one after the other. - if (errorRetryLanes !== NoLanes) { - lanes = errorRetryLanes; - exitStatus = recoverFromConcurrentError( - root, - originallyAttemptedLanes, - errorRetryLanes - ); - } - } - if (exitStatus === RootFatalErrored) { - prepareFreshStack(root, NoLanes); - markRootSuspended(root, lanes, NoLane); - ensureRootIsScheduled(root); - return null; + root.timeoutHandle = scheduleTimeout(commitRootWhenReady.bind(null, root, finishedWork, workInProgressRootRecoverableErrors, workInProgressTransitions, workInProgressRootDidIncludeRecursiveRenderUpdate, lanes, workInProgressDeferredLane), msUntilTimeout); + return; } - - 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, workInProgressDeferredLane); - ensureRootIsScheduled(root); - 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, - workInProgressRootDidIncludeRecursiveRenderUpdate, - workInProgressDeferredLane - ); // Before exiting, make sure there's a callback scheduled for the next - // pending level. - - ensureRootIsScheduled(root); - return null; } - function getExecutionContext() { - return executionContext; + + commitRootWhenReady(root, finishedWork, workInProgressRootRecoverableErrors, workInProgressTransitions, workInProgressRootDidIncludeRecursiveRenderUpdate, lanes, workInProgressDeferredLane); + } +} + +function commitRootWhenReady(root, finishedWork, recoverableErrors, transitions, didIncludeRenderPhaseUpdate, lanes, spawnedLane) { + // TODO: Combine retry throttling with Suspensey commits. Right now they run + // one after the other. + if (includesOnlyNonUrgentLanes(lanes)) { + // the suspensey resources. The renderer is responsible for accumulating + // all the load events. This all happens in a single synchronous + // transaction, so it track state in its own module scope. + + accumulateSuspenseyCommit(finishedWork); // At the end, ask the renderer if it's ready to commit, or if we should + // suspend. If it's not ready, it will return a callback to subscribe to + // a ready event. + + var schedulePendingCommit = waitForCommitToBeReady(); + + 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, recoverableErrors, transitions, didIncludeRenderPhaseUpdate)); + markRootSuspended(root, lanes, spawnedLane); + return; } - function batchedUpdates(fn, a) { - { - var prevExecutionContext = executionContext; - executionContext |= BatchedContext; + } // Otherwise, commit immediately. - 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 ( - executionContext === NoContext && // Treat `act` as if it's inside `batchedUpdates`, even in legacy mode. - !ReactSharedInternals.isBatchingLegacy - ) { - resetRenderTimer(); - flushSyncWorkOnLegacyRootsOnly(); + + commitRoot(root, recoverableErrors, transitions, didIncludeRenderPhaseUpdate, spawnedLane); +} + +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; + + while (true) { + if (node.flags & StoreConsistency) { + var updateQueue = node.updateQueue; + + if (updateQueue !== null) { + var checks = updateQueue.stores; + + if (checks !== null) { + for (var i = 0; i < checks.length; i++) { + var check = checks[i]; + var getSnapshot = check.getSnapshot; + var renderedValue = check.value; + + 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; + } } } } } - // Returns whether the the call was during a render or not - function flushSyncWork() { - if ((executionContext & (RenderContext | CommitContext)) === NoContext) { - flushSyncWorkOnAllRoots(); - return false; - } + var child = node.child; - return true; + if (node.subtreeFlags & StoreConsistency && child !== null) { + child.return = node; + node = child; + continue; } - // 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 setEntangledRenderLanes(newEntangledRenderLanes) { - entangledRenderLanes = newEntangledRenderLanes; - } - function getEntangledRenderLanes() { - return entangledRenderLanes; + if (node === finishedWork) { + return true; } - 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(workInProgress); - interruptedWork = workInProgress; - } - - while (interruptedWork !== null) { - var current = interruptedWork.alternate; - unwindInterruptedWork(current, interruptedWork); - interruptedWork = interruptedWork.return; + while (node.sibling === null) { + if (node.return === null || node.return === finishedWork) { + return true; } - workInProgress = null; + node = node.return; } - function prepareFreshStack(root, lanes) { - root.finishedWork = null; - root.finishedLanes = NoLanes; - var timeoutHandle = root.timeoutHandle; + node.sibling.return = node.return; + node = node.sibling; + } // Flow doesn't know this is unreachable, but eslint does + // eslint-disable-next-line no-unreachable - 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[incompatible-call] Complains noTimeout is not a TimeoutID, despite the check above - cancelTimeout(timeoutHandle); - } + return true; +} // The extra indirections around markRootUpdated and markRootSuspended is +// needed to avoid a circular dependency between this module and +// ReactFiberLane. There's probably a better way to split up these modules and +// avoid this problem. Perhaps all the root-marking functions should move into +// the work loop. - var cancelPendingCommit = root.cancelPendingCommit; - if (cancelPendingCommit !== null) { - root.cancelPendingCommit = null; - cancelPendingCommit(); - } +function markRootUpdated(root, updatedLanes) { + markRootUpdated$1(root, updatedLanes); - resetWorkInProgressStack(); - workInProgressRoot = root; - var rootWorkInProgress = createWorkInProgress(root.current, null); - workInProgress = rootWorkInProgress; - workInProgressRootRenderLanes = lanes; - workInProgressSuspendedReason = NotSuspended; - workInProgressThrownValue = null; - workInProgressRootDidAttachPingListener = false; - workInProgressRootExitStatus = RootInProgress; - workInProgressRootSkippedLanes = NoLanes; - workInProgressRootInterleavedUpdatedLanes = NoLanes; - workInProgressRootPingedLanes = NoLanes; - workInProgressDeferredLane = NoLane; - workInProgressRootConcurrentErrors = null; - workInProgressRootRecoverableErrors = null; - workInProgressRootDidIncludeRecursiveRenderUpdate = false; // Get the lanes that are entangled with whatever we're about to render. We - // track these separately so we can distinguish the priority of the render - // task from the priority of the lanes it is entangled with. For example, a - // transition may not be allowed to finish unless it includes the Sync lane, - // which is currently suspended. We should be able to render the Transition - // and Sync lane in the same batch, but at Transition priority, because the - // Sync lane already suspended. + if (enableInfiniteRenderLoopDetection) { + // Check for recursive updates + if (executionContext & RenderContext) { + workInProgressRootDidIncludeRecursiveRenderUpdate = true; + } else if (executionContext & CommitContext) { + didIncludeCommitPhaseUpdate = true; + } - entangledRenderLanes = getEntangledLanes(root, lanes); - finishQueueingConcurrentUpdates(); + throwIfInfiniteUpdateLoopDetected(); + } +} - { - ReactStrictModeWarnings.discardPendingWarnings(); - } +function markRootPinged(root, pingedLanes) { + markRootPinged$1(root, pingedLanes); - return rootWorkInProgress; + if (enableInfiniteRenderLoopDetection) { + // Check for recursive pings. Pings are conceptually different from updates in + // other contexts but we call it an "update" in this context because + // repeatedly pinging a suspended render can cause a recursive render loop. + // The relevant property is that it can result in a new render attempt + // being scheduled. + if (executionContext & RenderContext) { + workInProgressRootDidIncludeRecursiveRenderUpdate = true; + } else if (executionContext & CommitContext) { + didIncludeCommitPhaseUpdate = true; } - function resetSuspendedWorkLoopOnUnwind(fiber) { - // Reset module-level state that was set during the render phase. - resetContextDependencies(); - resetHooksOnUnwind(fiber); - resetChildReconcilerOnUnwind(); + throwIfInfiniteUpdateLoopDetected(); + } +} + +function markRootSuspended(root, suspendedLanes, spawnedLane) { + // When suspending, we should always exclude lanes that were pinged or (more + // rarely, since we try to avoid it) updated during the render phase. + suspendedLanes = removeLanes(suspendedLanes, workInProgressRootPingedLanes); + suspendedLanes = removeLanes(suspendedLanes, workInProgressRootInterleavedUpdatedLanes); + + markRootSuspended$1(root, suspendedLanes, spawnedLane); +} // This is the entry point for synchronous tasks that don't go +// through Scheduler + + +function performSyncWorkOnRoot(root, lanes) { + if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { + throw new Error('Should not already be working.'); + } + + var didFlushPassiveEffects = flushPassiveEffects(); + + if (didFlushPassiveEffects) { + // If passive effects were flushed, exit to the outer work loop in the root + // scheduler, so we can recompute the priority. + // TODO: We don't actually need this `ensureRootIsScheduled` call because + // this path is only reachable if the root is already part of the schedule. + // I'm including it only for consistency with the other exit points from + // this function. Can address in a subsequent refactor. + ensureRootIsScheduled(root); + return null; + } + + { + syncNestedUpdateFlag(); + } + + 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 (exitStatus === RootFatalErrored) { + prepareFreshStack(root, NoLanes); + markRootSuspended(root, lanes, NoLane); + ensureRootIsScheduled(root); + return null; + } + + 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, workInProgressDeferredLane); + ensureRootIsScheduled(root); + 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, workInProgressRootDidIncludeRecursiveRenderUpdate, workInProgressDeferredLane); // Before exiting, make sure there's a callback scheduled for the next + // pending level. + + ensureRootIsScheduled(root); + return null; +} +function getExecutionContext() { + return executionContext; +} +function batchedUpdates(fn, a) { + { + var prevExecutionContext = executionContext; + executionContext |= BatchedContext; + + 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 (executionContext === NoContext && // Treat `act` as if it's inside `batchedUpdates`, even in legacy mode. + !(ReactSharedInternals.isBatchingLegacy)) { + resetRenderTimer(); + flushSyncWorkOnLegacyRootsOnly(); + } } + } +} +// Returns whether the the call was during a render or not - 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(); +function flushSyncWork() { + if ((executionContext & (RenderContext | CommitContext)) === NoContext) { + flushSyncWorkOnAllRoots(); + return false; + } - { - ReactSharedInternals.owner = null; - } - - 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; - } - - workInProgressThrownValue = thrownValue; - var erroredWork = workInProgress; - - if (erroredWork === null) { - // This is a fatal error - workInProgressRootExitStatus = RootFatalErrored; - logUncaughtError( - root, - createCapturedValueAtFiber(thrownValue, root.current) - ); - return; - } + return true; +} +// 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 - 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 setEntangledRenderLanes(newEntangledRenderLanes) { + entangledRenderLanes = newEntangledRenderLanes; +} +function getEntangledRenderLanes() { + return entangledRenderLanes; +} - { - markComponentRenderStopped(); +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(workInProgress); + interruptedWork = workInProgress; + } + + while (interruptedWork !== null) { + var current = interruptedWork.alternate; + unwindInterruptedWork(current, interruptedWork); + interruptedWork = interruptedWork.return; + } + + workInProgress = null; +} - switch (workInProgressSuspendedReason) { - case SuspendedOnError: { - markComponentErrored( - erroredWork, - thrownValue, - workInProgressRootRenderLanes - ); - 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[incompatible-call] Complains noTimeout is not a TimeoutID, despite the check above + + cancelTimeout(timeoutHandle); + } + + var cancelPendingCommit = root.cancelPendingCommit; + + if (cancelPendingCommit !== null) { + root.cancelPendingCommit = null; + cancelPendingCommit(); + } + + resetWorkInProgressStack(); + workInProgressRoot = root; + var rootWorkInProgress = createWorkInProgress(root.current, null); + workInProgress = rootWorkInProgress; + workInProgressRootRenderLanes = lanes; + workInProgressSuspendedReason = NotSuspended; + workInProgressThrownValue = null; + workInProgressRootDidAttachPingListener = false; + workInProgressRootExitStatus = RootInProgress; + workInProgressRootSkippedLanes = NoLanes; + workInProgressRootInterleavedUpdatedLanes = NoLanes; + workInProgressRootPingedLanes = NoLanes; + workInProgressDeferredLane = NoLane; + workInProgressRootConcurrentErrors = null; + workInProgressRootRecoverableErrors = null; + workInProgressRootDidIncludeRecursiveRenderUpdate = false; // Get the lanes that are entangled with whatever we're about to render. We + // track these separately so we can distinguish the priority of the render + // task from the priority of the lanes it is entangled with. For example, a + // transition may not be allowed to finish unless it includes the Sync lane, + // which is currently suspended. We should be able to render the Transition + // and Sync lane in the same batch, but at Transition priority, because the + // Sync lane already suspended. + + entangledRenderLanes = getEntangledLanes(root, lanes); + finishQueueingConcurrentUpdates(); + + { + ReactStrictModeWarnings.discardPendingWarnings(); + } + + return rootWorkInProgress; +} - case SuspendedOnData: - case SuspendedOnImmediate: - case SuspendedOnDeprecatedThrowPromise: - case SuspendedAndReadyToContinue: { - var wakeable = thrownValue; - markComponentSuspended( - erroredWork, - wakeable, - workInProgressRootRenderLanes - ); - break; - } +function resetSuspendedWorkLoopOnUnwind(fiber) { + // Reset module-level state that was set during the render phase. + resetContextDependencies(); + resetHooksOnUnwind(fiber); + resetChildReconcilerOnUnwind(); +} + +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(); + + { + ReactSharedInternals.owner = null; + } + + 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; + } + + workInProgressThrownValue = thrownValue; + var erroredWork = workInProgress; + + if (erroredWork === null) { + // This is a fatal error + workInProgressRootExitStatus = RootFatalErrored; + logUncaughtError(root, createCapturedValueAtFiber(thrownValue, root.current)); + 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); + } + + { + markComponentRenderStopped(); + + switch (workInProgressSuspendedReason) { + case SuspendedOnError: + { + markComponentErrored(erroredWork, thrownValue, workInProgressRootRenderLanes); + break; } - } + + case SuspendedOnData: + case SuspendedOnImmediate: + case SuspendedOnDeprecatedThrowPromise: + case SuspendedAndReadyToContinue: + { + var wakeable = thrownValue; + markComponentSuspended(erroredWork, wakeable, workInProgressRootRenderLanes); + break; + } + } + } +} + +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. + var handler = getSuspenseHandler(); + + if (handler === null) { + // There's no Suspense boundary that can provide a fallback. We have no + // choice but to remain on the previous screen. + // NOTE: We do this even for sync updates, for lack of any better option. In + // the future, we may change how we handle this, like by putting the whole + // root into a "detached" mode. + return true; + } // 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; } + } - 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. - var handler = getSuspenseHandler(); + if (includesOnlyRetries(workInProgressRootRenderLanes) || // In this context, an OffscreenLane counts as a Retry + // TODO: It's become increasingly clear that Retries and Offscreen are + // deeply connected. They probably can be unified further. + includesSomeLane(workInProgressRootRenderLanes, OffscreenLane)) { + // 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. + // + // The reason we must check if this is a retry is because it guarantees + // that suspending the work loop won't block an actual update, because + // retries don't "update" anything; they fill in fallbacks that were left + // behind by a previous transition. + return handler === getShellBoundary(); + } // For all other Lanes besides Transitions and Retries, we should not wait + // for the data to load. - if (handler === null) { - // There's no Suspense boundary that can provide a fallback. We have no - // choice but to remain on the previous screen. - // NOTE: We do this even for sync updates, for lack of any better option. In - // the future, we may change how we handle this, like by putting the whole - // root into a "detached" mode. - return true; - } // 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; - } - } - if ( - includesOnlyRetries(workInProgressRootRenderLanes) || // In this context, an OffscreenLane counts as a Retry - // TODO: It's become increasingly clear that Retries and Offscreen are - // deeply connected. They probably can be unified further. - includesSomeLane(workInProgressRootRenderLanes, OffscreenLane) - ) { - // 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. - // - // The reason we must check if this is a retry is because it guarantees - // that suspending the work loop won't block an actual update, because - // retries don't "update" anything; they fill in fallbacks that were left - // behind by a previous transition. - return handler === getShellBoundary(); - } // For all other Lanes besides Transitions and Retries, we should not wait - // for the data to load. + return false; +} + +function pushDispatcher(container) { + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = ContextOnlyDispatcher; + + 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; + } +} + +function popDispatcher(prevDispatcher) { + ReactSharedInternals.H = prevDispatcher; +} + +function pushCacheDispatcher() { + { + var prevCacheDispatcher = ReactSharedInternals.C; + ReactSharedInternals.C = DefaultCacheDispatcher; + return prevCacheDispatcher; + } +} + +function popCacheDispatcher(prevCacheDispatcher) { + { + ReactSharedInternals.C = prevCacheDispatcher; + } +} + +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. + + if ((includesNonIdleWork(workInProgressRootSkippedLanes) || includesNonIdleWork(workInProgressRootInterleavedUpdatedLanes)) && workInProgressRoot !== null) { + // 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. + markRootSuspended(workInProgressRoot, workInProgressRootRenderLanes, workInProgressDeferredLane); + } +} +function renderDidError() { + if (workInProgressRootExitStatus !== RootSuspendedWithDelay) { + workInProgressRootExitStatus = RootErrored; + } +} +function queueConcurrentError(error) { + 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. + +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. + +function renderRootSync(root, lanes) { + var prevExecutionContext = executionContext; + executionContext |= RenderContext; + var prevDispatcher = pushDispatcher(); + var prevCacheDispatcher = pushCacheDispatcher(); // If the root or lanes have changed, throw out the existing stack + // and prepare a fresh one. Otherwise we'll continue where we left off. + + if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) { + { + if (isDevToolsPresent) { + var memoizedUpdaters = root.memoizedUpdaters; - return false; - } + 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. - function pushDispatcher(container) { - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = ContextOnlyDispatcher; - 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; + movePendingFibersToMemoized(root, lanes); } } - function popDispatcher(prevDispatcher) { - ReactSharedInternals.H = prevDispatcher; - } + workInProgressTransitions = getTransitionsForLanes(); + prepareFreshStack(root, lanes); + } - function pushCacheDispatcher() { - { - var prevCacheDispatcher = ReactSharedInternals.C; - ReactSharedInternals.C = DefaultCacheDispatcher; - return prevCacheDispatcher; - } - } + { + markRenderStarted(lanes); + } - function popCacheDispatcher(prevCacheDispatcher) { - { - ReactSharedInternals.C = prevCacheDispatcher; - } - } + var didSuspendInShell = false; - 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. + 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; - if ( - (includesNonIdleWork(workInProgressRootSkippedLanes) || - includesNonIdleWork(workInProgressRootInterleavedUpdatedLanes)) && - workInProgressRoot !== null - ) { - // 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. - markRootSuspended( - workInProgressRoot, - workInProgressRootRenderLanes, - workInProgressDeferredLane - ); - } - } - function renderDidError() { - if (workInProgressRootExitStatus !== RootSuspendedWithDelay) { - workInProgressRootExitStatus = RootErrored; + 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; + } + + case SuspendedOnImmediate: + case SuspendedOnData: + { + if (!didSuspendInShell && getSuspenseHandler() === null) { + didSuspendInShell = true; + } // Intentional fallthrough + + } + + default: + { + // Unwind then continue with the normal work loop. + workInProgressSuspendedReason = NotSuspended; + workInProgressThrownValue = null; + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); + break; + } + } } + + workLoopSync(); + break; + } catch (thrownValue) { + handleThrow(root, thrownValue); } - function queueConcurrentError(error) { - 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. - - 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. - - function renderRootSync(root, lanes) { - var prevExecutionContext = executionContext; - executionContext |= RenderContext; - var prevDispatcher = pushDispatcher(); - var prevCacheDispatcher = pushCacheDispatcher(); // If the root or lanes have changed, throw out the existing stack - // and prepare a fresh one. Otherwise we'll continue where we left off. - - if ( - workInProgressRoot !== root || - workInProgressRootRenderLanes !== lanes - ) { - { - 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); - } - } + } while (true); // Check if something suspended in the shell. We use this to detect an + // infinite ping loop caused by an uncached promise. + // + // Only increment this counter once per synchronous render attempt across the + // whole tree. Even if there are many sibling components that suspend, this + // counter only gets incremented once. - workInProgressTransitions = getTransitionsForLanes(); - prepareFreshStack(root, lanes); - } - { - markRenderStarted(lanes); - } + if (didSuspendInShell) { + root.shellSuspendCounter++; + } - var didSuspendInShell = false; + resetContextDependencies(); + executionContext = prevExecutionContext; + popDispatcher(prevDispatcher); + popCacheDispatcher(prevCacheDispatcher); - 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; - - 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 (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.'); + } - case SuspendedOnImmediate: - case SuspendedOnData: { - if (!didSuspendInShell && getSuspenseHandler() === null) { - didSuspendInShell = true; - } // Intentional fallthrough - } + { + markRenderStopped(); + } // Set this to null to indicate there's no in-progress render. - default: { - // Unwind then continue with the normal work loop. - workInProgressSuspendedReason = NotSuspended; - workInProgressThrownValue = null; - throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); - break; - } - } - } - workLoopSync(); - break; - } catch (thrownValue) { - handleThrow(root, thrownValue); - } - } while (true); // Check if something suspended in the shell. We use this to detect an - // infinite ping loop caused by an uncached promise. - // - // Only increment this counter once per synchronous render attempt across the - // whole tree. Even if there are many sibling components that suspend, this - // counter only gets incremented once. + workInProgressRoot = null; + workInProgressRootRenderLanes = NoLanes; // It's safe to process the queue now that the render phase is complete. - if (didSuspendInShell) { - root.shellSuspendCounter++; - } + finishQueueingConcurrentUpdates(); + return workInProgressRootExitStatus; +} // The work loop is an extremely hot path. Tell Closure not to inline it. - resetContextDependencies(); - executionContext = prevExecutionContext; - popDispatcher(prevDispatcher); - popCacheDispatcher(prevCacheDispatcher); +/** @noinline */ - 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." - ); - } - { - markRenderStopped(); - } // Set this to null to indicate there's no in-progress render. +function workLoopSync() { + // Perform work without checking if we need to yield between fiber. + while (workInProgress !== null) { + performUnitOfWork(workInProgress); + } +} - workInProgressRoot = null; - workInProgressRootRenderLanes = NoLanes; // It's safe to process the queue now that the render phase is complete. +function renderRootConcurrent(root, lanes) { + var prevExecutionContext = executionContext; + executionContext |= RenderContext; + var prevDispatcher = pushDispatcher(); + var prevCacheDispatcher = pushCacheDispatcher(); // If the root or lanes have changed, throw out the existing stack + // and prepare a fresh one. Otherwise we'll continue where we left off. + + if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) { + { + if (isDevToolsPresent) { + var memoizedUpdaters = root.memoizedUpdaters; - finishQueueingConcurrentUpdates(); - return workInProgressRootExitStatus; - } // The work loop is an extremely hot path. Tell Closure not to inline it. + 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. - /** @noinline */ - function workLoopSync() { - // Perform work without checking if we need to yield between fiber. - while (workInProgress !== null) { - performUnitOfWork(workInProgress); + movePendingFibersToMemoized(root, lanes); } } - function renderRootConcurrent(root, lanes) { - var prevExecutionContext = executionContext; - executionContext |= RenderContext; - var prevDispatcher = pushDispatcher(); - var prevCacheDispatcher = pushCacheDispatcher(); // If the root or lanes have changed, throw out the existing stack - // and prepare a fresh one. Otherwise we'll continue where we left off. + workInProgressTransitions = getTransitionsForLanes(); + resetRenderTimer(); + prepareFreshStack(root, lanes); + } - if ( - workInProgressRoot !== root || - workInProgressRootRenderLanes !== lanes - ) { - { - 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); - } - } + { + markRenderStarted(lanes); + } - workInProgressTransitions = getTransitionsForLanes(); - resetRenderTimer(); - prepareFreshStack(root, lanes); - } + 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; - { - markRenderStarted(lanes); - } + resumeOrUnwind: switch (workInProgressSuspendedReason) { + case SuspendedOnError: + { + // Unwind then continue with the normal work loop. + workInProgressSuspendedReason = NotSuspended; + workInProgressThrownValue = null; + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); + break; + } - 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; - - resumeOrUnwind: switch (workInProgressSuspendedReason) { - case SuspendedOnError: { - // Unwind then continue with the normal work loop. + case SuspendedOnData: + { + var thenable = thrownValue; + + if (isThenableResolved(thenable)) { + // The data resolved. Try rendering the component again. workInProgressSuspendedReason = NotSuspended; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); + 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. - case SuspendedOnData: { - var thenable = thrownValue; - 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. - - 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. - - ensureRootIsScheduled(root); - }; - - thenable.then(onResolution, onResolution); - break outer; - } + 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. - 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; - } + ensureRootIsScheduled(root); + }; - case SuspendedAndReadyToContinue: { - var _thenable = thrownValue; + thenable.then(onResolution, onResolution); + break outer; + } - 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(root, unitOfWork, thrownValue); - } + 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; + } - break; + 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(root, unitOfWork, thrownValue); } - case SuspendedOnInstanceAndReadyToContinue: { - switch (workInProgress.tag) { - case HostComponent: - case HostHoistable: - case HostSingleton: { + 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. @@ -27441,4144 +23526,3576 @@ to return true:wantsResponderID| | break; } - default: { + 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." - ); + error('Unexpected type of fiber triggered a suspensey commit. ' + 'This is a bug in React.'); } break; } - } // Otherwise, unwind then continue with the normal work loop. - - workInProgressSuspendedReason = NotSuspended; - workInProgressThrownValue = null; - throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); - break; - } + } // Otherwise, unwind then continue with the normal work loop. - 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(root, unitOfWork, thrownValue); - break; - } - 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; - } + workInProgressSuspendedReason = NotSuspended; + workInProgressThrownValue = null; + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); + break; + } - default: { - throw new Error( - "Unexpected SuspendedReason. This is a bug in React." - ); - } + 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(root, unitOfWork, thrownValue); + break; } - } - if (true && ReactSharedInternals.actQueue !== 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(); - } + 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; + } - break; - } catch (thrownValue) { - handleThrow(root, thrownValue); + default: + { + throw new Error('Unexpected SuspendedReason. This is a bug in React.'); + } } - } while (true); + } + + if (true && ReactSharedInternals.actQueue !== 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(); + } + + break; + } catch (thrownValue) { + handleThrow(root, thrownValue); + } + } while (true); + + resetContextDependencies(); + popDispatcher(prevDispatcher); + popCacheDispatcher(prevCacheDispatcher); + executionContext = prevExecutionContext; + + + if (workInProgress !== null) { + // Still work remaining. + { + markRenderYielded(); + } - resetContextDependencies(); - popDispatcher(prevDispatcher); - popCacheDispatcher(prevCacheDispatcher); - executionContext = prevExecutionContext; + return RootInProgress; + } else { + // Completed the tree. + { + 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. + + finishQueueingConcurrentUpdates(); // Return the final exit status. + + return workInProgressRootExitStatus; + } +} +/** @noinline */ + + +function workLoopConcurrent() { + // Perform work until Scheduler asks us to yield + while (workInProgress !== null && !shouldYield()) { + // $FlowFixMe[incompatible-call] found when upgrading Flow + performUnitOfWork(workInProgress); + } +} + +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; + + if ((unitOfWork.mode & ProfileMode) !== NoMode) { + startProfilerTimer(unitOfWork); + next = beginWork(current, unitOfWork, entangledRenderLanes); + stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true); + } else { + next = beginWork(current, unitOfWork, entangledRenderLanes); + } + + resetCurrentFiber(); + unitOfWork.memoizedProps = unitOfWork.pendingProps; + + if (next === null) { + // If this doesn't spawn new work, complete the current work. + completeUnitOfWork(unitOfWork); + } else { + workInProgress = next; + } + + { + ReactSharedInternals.owner = null; + } +} + +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; + + if (isProfilingMode) { + startProfilerTimer(unitOfWork); + } + + switch (unitOfWork.tag) { + case SimpleMemoComponent: + case FunctionComponent: + { + // 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 = disableDefaultPropsExceptForClasses || unitOfWork.elementType === Component ? unresolvedProps : resolveDefaultPropsOnNonClassComponent(Component, unresolvedProps); + var context; - if (workInProgress !== null) { - // Still work remaining. { - markRenderYielded(); + var unmaskedContext = getUnmaskedContext(unitOfWork, Component, true); + context = getMaskedContext(unitOfWork, unmaskedContext); } - return RootInProgress; - } else { - // Completed the tree. - { - markRenderStopped(); - } // Set this to null to indicate there's no in-progress render. + next = replayFunctionComponent(current, unitOfWork, resolvedProps, Component, context, workInProgressRootRenderLanes); + break; + } - workInProgressRoot = null; - workInProgressRootRenderLanes = NoLanes; // It's safe to process the queue now that the render phase is complete. + 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.render; + var _unresolvedProps = unitOfWork.pendingProps; - finishQueueingConcurrentUpdates(); // Return the final exit status. + var _resolvedProps = disableDefaultPropsExceptForClasses || unitOfWork.elementType === _Component ? _unresolvedProps : resolveDefaultPropsOnNonClassComponent(_Component, _unresolvedProps); - return workInProgressRootExitStatus; + next = replayFunctionComponent(current, unitOfWork, _resolvedProps, _Component, unitOfWork.ref, workInProgressRootRenderLanes); + break; } - } - /** @noinline */ - function workLoopConcurrent() { - // Perform work until Scheduler asks us to yield - while (workInProgress !== null && !shouldYield()) { - // $FlowFixMe[incompatible-call] found when upgrading Flow - performUnitOfWork(workInProgress); + case HostComponent: + { + // Some host components are stateful (that's how we implement form + // actions) but we don't bother to reuse the memoized state because it's + // not worth the extra code. The main reason to reuse the previous hooks + // is to reuse uncached promises, but we happen to know that the only + // promises that a host component might suspend on are definitely cached + // because they are controlled by us. So don't bother. + resetHooksOnUnwind(unitOfWork); // Fallthrough to the next branch. } - } - - 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; - if ((unitOfWork.mode & ProfileMode) !== NoMode) { - startProfilerTimer(unitOfWork); - next = beginWork(current, unitOfWork, entangledRenderLanes); - stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true); - } else { + 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, entangledRenderLanes); next = beginWork(current, unitOfWork, entangledRenderLanes); + break; } + } - resetCurrentFiber(); - unitOfWork.memoizedProps = unitOfWork.pendingProps; + if (isProfilingMode) { + stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true); + } // The begin phase finished successfully without suspending. Return to the + // normal work loop. - if (next === null) { - // If this doesn't spawn new work, complete the current work. - completeUnitOfWork(unitOfWork); - } else { - workInProgress = next; - } - { - ReactSharedInternals.owner = null; + resetCurrentFiber(); + unitOfWork.memoizedProps = unitOfWork.pendingProps; + + if (next === null) { + // If this doesn't spawn new work, complete the current work. + completeUnitOfWork(unitOfWork); + } else { + workInProgress = next; + } + + { + ReactSharedInternals.owner = null; + } +} + +function throwAndUnwindWorkLoop(root, 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(unitOfWork); + var returnFiber = unitOfWork.return; + + try { + // Find and mark the nearest Suspense or error boundary that can handle + // this "exception". + var didFatal = throwException(root, returnFiber, unitOfWork, thrownValue, workInProgressRootRenderLanes); + + if (didFatal) { + panicOnRootError(root, thrownValue); + return; + } + } 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. + if (returnFiber !== null) { + workInProgress = returnFiber; + throw error; + } else { + panicOnRootError(root, 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); + } +} + +function panicOnRootError(root, error) { + // There's no ancestor that can handle this exception. This should never + // happen because the root is supposed to capture all errors that weren't + // caught by an error boundary. This is a fatal error, or panic condition, + // because we've run out of ways to recover. + workInProgressRootExitStatus = RootFatalErrored; + logUncaughtError(root, createCapturedValueAtFiber(error, root.current)); // 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. + + workInProgress = null; +} + +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; + + 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."); } + } // 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; + + if ((completedWork.mode & ProfileMode) === NoMode) { + next = completeWork(current, completedWork, entangledRenderLanes); + } else { + startProfilerTimer(completedWork); + next = completeWork(current, completedWork, entangledRenderLanes); // Update render duration assuming we didn't error. + + stopProfilerTimerIfRunningAndRecordDelta(completedWork, false); } - 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; + resetCurrentFiber(); - if (isProfilingMode) { - startProfilerTimer(unitOfWork); - } + if (next !== null) { + // Completing this fiber spawned new work. Work on that next. + workInProgress = next; + return; + } - switch (unitOfWork.tag) { - case SimpleMemoComponent: - case FunctionComponent: { - // 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 = - disableDefaultPropsExceptForClasses || - unitOfWork.elementType === Component - ? unresolvedProps - : resolveDefaultPropsOnNonClassComponent( - Component, - unresolvedProps - ); - var context; + var siblingFiber = completedWork.sibling; - { - var unmaskedContext = getUnmaskedContext( - unitOfWork, - Component, - true - ); - context = getMaskedContext(unitOfWork, unmaskedContext); - } + 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 - next = replayFunctionComponent( - current, - unitOfWork, - resolvedProps, - Component, - context, - workInProgressRootRenderLanes - ); - break; - } - 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.render; - var _unresolvedProps = unitOfWork.pendingProps; - - var _resolvedProps = - disableDefaultPropsExceptForClasses || - unitOfWork.elementType === _Component - ? _unresolvedProps - : resolveDefaultPropsOnNonClassComponent( - _Component, - _unresolvedProps - ); - - next = replayFunctionComponent( - current, - unitOfWork, - _resolvedProps, - _Component, - unitOfWork.ref, - workInProgressRootRenderLanes - ); - break; - } + completedWork = returnFiber; // Update the next thing we're working on in case something throws. - case HostComponent: { - // Some host components are stateful (that's how we implement form - // actions) but we don't bother to reuse the memoized state because it's - // not worth the extra code. The main reason to reuse the previous hooks - // is to reuse uncached promises, but we happen to know that the only - // promises that a host component might suspend on are definitely cached - // because they are controlled by us. So don't bother. - resetHooksOnUnwind(unitOfWork); // Fallthrough to the next branch. - } + workInProgress = completedWork; + } while (completedWork !== null); // We've reached the root. - 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, - entangledRenderLanes - ); - next = beginWork(current, unitOfWork, entangledRenderLanes); - break; - } - } - if (isProfilingMode) { - stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true); - } // The begin phase finished successfully without suspending. Return to the - // normal work loop. + if (workInProgressRootExitStatus === RootInProgress) { + workInProgressRootExitStatus = RootCompleted; + } +} - resetCurrentFiber(); - unitOfWork.memoizedProps = unitOfWork.pendingProps; +function unwindUnitOfWork(unitOfWork) { + var incompleteWork = unitOfWork; - if (next === null) { - // If this doesn't spawn new work, complete the current work. - completeUnitOfWork(unitOfWork); - } else { - workInProgress = next; - } + 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. - { - ReactSharedInternals.owner = null; - } - } + var next = unwindWork(current, incompleteWork); // Because this fiber did not complete, don't reset its lanes. - function throwAndUnwindWorkLoop(root, unitOfWork, thrownValue) { - // This is a fork of performUnitOfWork specifcally for unwinding a fiber - // that threw an exception. + 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. // - // Return to the normal work loop. This will unwind the stack, and potentially - // result in showing a fallback. - resetSuspendedWorkLoopOnUnwind(unitOfWork); - var returnFiber = unitOfWork.return; + // 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. - try { - // Find and mark the nearest Suspense or error boundary that can handle - // this "exception". - var didFatal = throwException( - root, - returnFiber, - unitOfWork, - thrownValue, - workInProgressRootRenderLanes - ); - - if (didFatal) { - panicOnRootError(root, thrownValue); - return; - } - } 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. - if (returnFiber !== null) { - workInProgress = returnFiber; - throw error; - } else { - panicOnRootError(root, 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 ((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. + + var actualDuration = incompleteWork.actualDuration; + var child = incompleteWork.child; + + while (child !== null) { + // $FlowFixMe[unsafe-addition] addition with possible null/undefined value + actualDuration += child.actualDuration; + child = child.sibling; } - } - function panicOnRootError(root, error) { - // There's no ancestor that can handle this exception. This should never - // happen because the root is supposed to capture all errors that weren't - // caught by an error boundary. This is a fatal error, or panic condition, - // because we've run out of ways to recover. - workInProgressRootExitStatus = RootFatalErrored; - logUncaughtError(root, createCapturedValueAtFiber(error, root.current)); // 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. + 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; + + 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; + } // NOTE: If we re-enable sibling prerendering in some cases, here we + // would switch to the normal completion path: check if a sibling + // exists, and if so, begin work on it. + // Otherwise, return to the parent + // $FlowFixMe[incompatible-type] we bail out when we get a null + + + incompleteWork = returnFiber; // Update the next thing we're working on in case something throws. + + workInProgress = incompleteWork; + } while (incompleteWork !== null); // We've unwound all the way to the root. + + + workInProgressRootExitStatus = RootDidNotComplete; + workInProgress = null; +} + +function commitRoot(root, recoverableErrors, transitions, didIncludeRenderPhaseUpdate, spawnedLane) { + // TODO: This no longer makes any sense. We already wrap the mutation and + // layout phases. Should be able to remove. + var prevTransition = ReactSharedInternals.T; + var previousUpdateLanePriority = getCurrentUpdatePriority(); + + try { + setCurrentUpdatePriority(DiscreteEventPriority); + ReactSharedInternals.T = null; + commitRootImpl(root, recoverableErrors, transitions, didIncludeRenderPhaseUpdate, previousUpdateLanePriority, spawnedLane); + } finally { + ReactSharedInternals.T = prevTransition; + setCurrentUpdatePriority(previousUpdateLanePriority); + } + + return null; +} + +function commitRootImpl(root, recoverableErrors, transitions, didIncludeRenderPhaseUpdate, renderPriorityLevel, spawnedLane) { + 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); - workInProgress = null; + flushRenderPhaseStrictModeWarningsInDEV(); + + if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { + throw new Error('Should not already be working.'); + } + + 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.'); + } } + } - 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; + root.finishedWork = null; + root.finishedLanes = NoLanes; - 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." - ); - } - } // 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. + 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 current = completedWork.alternate; - var returnFiber = completedWork.return; - setCurrentFiber(completedWork); - var next = void 0; - if ((completedWork.mode & ProfileMode) === NoMode) { - next = completeWork(current, completedWork, entangledRenderLanes); - } else { - startProfilerTimer(completedWork); - next = completeWork(current, completedWork, entangledRenderLanes); // Update render duration assuming we didn't error. + 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. - stopProfilerTimerIfRunningAndRecordDelta(completedWork, false); - } + 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. - resetCurrentFiber(); + var concurrentlyUpdatedLanes = getConcurrentlyUpdatedLanes(); + remainingLanes = mergeLanes(remainingLanes, concurrentlyUpdatedLanes); + markRootFinished(root, remainingLanes, spawnedLane); // Reset this before firing side effects so we can detect recursive updates. - if (next !== null) { - // Completing this fiber spawned new work. Work on that next. - workInProgress = next; - return; - } + didIncludeCommitPhaseUpdate = false; - var siblingFiber = completedWork.sibling; + 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. - 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 - completedWork = returnFiber; // Update the next thing we're working on in case something throws. + if ((finishedWork.subtreeFlags & PassiveMask) !== NoFlags$1 || (finishedWork.flags & PassiveMask) !== NoFlags$1) { + if (!rootDoesHavePassiveEffects) { + rootDoesHavePassiveEffects = true; + pendingPassiveEffectsRemainingLanes = remainingLanes; // workInProgressTransitions might be overwritten, so we want + // to store it in pendingPassiveTransitions until they get processed + // We need to pass this through as an argument to commitRoot + // because workInProgressTransitions might have changed between + // the previous render and commit if we throttle the commit + // with setTimeout - workInProgress = completedWork; - } while (completedWork !== null); // We've reached the root. + pendingPassiveTransitions = transitions; + scheduleCallback(NormalPriority$1, 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) - if (workInProgressRootExitStatus === RootInProgress) { - workInProgressRootExitStatus = RootCompleted; - } + 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. - function unwindUnitOfWork(unitOfWork) { - var incompleteWork = unitOfWork; - 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. - - var next = unwindWork(current, incompleteWork); // Because this fiber did not complete, don't reset its lanes. - - 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. + var subtreeHasEffects = (finishedWork.subtreeFlags & (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !== NoFlags$1; + var rootHasEffect = (finishedWork.flags & (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !== NoFlags$1; - 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 (subtreeHasEffects || rootHasEffect) { + var prevTransition = ReactSharedInternals.T; + ReactSharedInternals.T = null; + var previousPriority = getCurrentUpdatePriority(); + setCurrentUpdatePriority(DiscreteEventPriority); + var prevExecutionContext = executionContext; + executionContext |= CommitContext; // Reset this to null before calling lifecycles - var actualDuration = incompleteWork.actualDuration; - var child = incompleteWork.child; + { + ReactSharedInternals.owner = 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. - while (child !== null) { - // $FlowFixMe[unsafe-addition] addition with possible null/undefined value - actualDuration += child.actualDuration; - child = child.sibling; - } - 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; - - 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; - } // NOTE: If we re-enable sibling prerendering in some cases, here we - // would switch to the normal completion path: check if a sibling - // exists, and if so, begin work on it. - // Otherwise, return to the parent - // $FlowFixMe[incompatible-type] we bail out when we get a null - - incompleteWork = returnFiber; // Update the next thing we're working on in case something throws. - - workInProgress = incompleteWork; - } while (incompleteWork !== null); // We've unwound all the way to the root. - - workInProgressRootExitStatus = RootDidNotComplete; - workInProgress = null; - } - - function commitRoot( - root, - recoverableErrors, - transitions, - didIncludeRenderPhaseUpdate, - spawnedLane - ) { - // TODO: This no longer makes any sense. We already wrap the mutation and - // layout phases. Should be able to remove. - var prevTransition = ReactSharedInternals.T; - var previousUpdateLanePriority = getCurrentUpdatePriority(); + commitBeforeMutationEffects(root, finishedWork); - try { - setCurrentUpdatePriority(DiscreteEventPriority); - ReactSharedInternals.T = null; - commitRootImpl( - root, - recoverableErrors, - transitions, - didIncludeRenderPhaseUpdate, - previousUpdateLanePriority, - spawnedLane - ); - } finally { - ReactSharedInternals.T = prevTransition; - setCurrentUpdatePriority(previousUpdateLanePriority); - } + { + // Mark the current commit time to be shared by all Profilers in this + // batch. This enables them to be grouped later. + recordCommitTime(); + } // The next phase is the mutation phase, where we mutate the host tree. - return null; - } - function commitRootImpl( - root, - recoverableErrors, - transitions, - didIncludeRenderPhaseUpdate, - renderPriorityLevel, - spawnedLane - ) { - 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); + 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. - flushRenderPhaseStrictModeWarningsInDEV(); + root.current = finishedWork; // The next phase is the layout phase, where we call effects that read - if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { - throw new Error("Should not already be working."); - } + { + markLayoutEffectsStarted(lanes); + } - var finishedWork = root.finishedWork; - var lanes = root.finishedLanes; + commitLayoutEffects(finishedWork, root, lanes); - { - markCommitStarted(lanes); - } + { + markLayoutEffectsStopped(); + } // Tell Scheduler to yield at the end of the frame, so the browser has an + // opportunity to paint. - 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." - ); - } - } - } + requestPaint(); + executionContext = prevExecutionContext; // Reset the priority to the previous non-sync value. - root.finishedWork = null; - root.finishedLanes = NoLanes; - - 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. - - 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. - - 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. - - var concurrentlyUpdatedLanes = getConcurrentlyUpdatedLanes(); - remainingLanes = mergeLanes(remainingLanes, concurrentlyUpdatedLanes); - markRootFinished(root, remainingLanes, spawnedLane); // Reset this before firing side effects so we can detect recursive updates. - - didIncludeCommitPhaseUpdate = false; - - 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. - - if ( - (finishedWork.subtreeFlags & PassiveMask) !== NoFlags$1 || - (finishedWork.flags & PassiveMask) !== NoFlags$1 - ) { - if (!rootDoesHavePassiveEffects) { - rootDoesHavePassiveEffects = true; - pendingPassiveEffectsRemainingLanes = remainingLanes; // workInProgressTransitions might be overwritten, so we want - // to store it in pendingPassiveTransitions until they get processed - // We need to pass this through as an argument to commitRoot - // because workInProgressTransitions might have changed between - // the previous render and commit if we throttle the commit - // with setTimeout - - pendingPassiveTransitions = transitions; - scheduleCallback(NormalPriority$1, 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) + setCurrentUpdatePriority(previousPriority); + ReactSharedInternals.T = 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. - 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. - - var subtreeHasEffects = - (finishedWork.subtreeFlags & - (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !== - NoFlags$1; - var rootHasEffect = - (finishedWork.flags & - (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !== - NoFlags$1; - - if (subtreeHasEffects || rootHasEffect) { - var prevTransition = ReactSharedInternals.T; - ReactSharedInternals.T = null; - var previousPriority = getCurrentUpdatePriority(); - setCurrentUpdatePriority(DiscreteEventPriority); - var prevExecutionContext = executionContext; - executionContext |= CommitContext; // Reset this to null before calling lifecycles + { + recordCommitTime(); + } + } - { - ReactSharedInternals.owner = 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. + var rootDidHavePassiveEffects = rootDoesHavePassiveEffects; - commitBeforeMutationEffects(root, finishedWork); + 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 { + // There were no passive effects, so we can immediately release the cache + // pool for this render. + releaseRootPooledCache(root, remainingLanes); - { - // Mark the current commit time to be shared by all Profilers in this - // batch. This enables them to be grouped later. - recordCommitTime(); - } // The next phase is the mutation phase, where we mutate the host tree. + { + nestedPassiveUpdateCount = 0; + rootWithPassiveNestedUpdates = null; + } + } // Read this again, since an effect might have updated it - 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. - root.current = finishedWork; // The next phase is the layout phase, where we call effects that read + 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. - { - markLayoutEffectsStarted(lanes); - } + if (remainingLanes === NoLanes) { + // If there's no remaining work, we can clear the set of already failed + // error boundaries. + legacyErrorBoundariesThatAlreadyFailed = null; + } - commitLayoutEffects(finishedWork, root, lanes); + { + if (!rootDidHavePassiveEffects) { + commitDoubleInvokeEffectsInDEV(root, false); + } + } - { - markLayoutEffectsStopped(); - } // Tell Scheduler to yield at the end of the frame, so the browser has an - // opportunity to paint. + onCommitRoot(finishedWork.stateNode, renderPriorityLevel); - requestPaint(); - executionContext = prevExecutionContext; // Reset the priority to the previous non-sync value. + { + if (isDevToolsPresent) { + root.memoizedUpdaters.clear(); + } + } + // additional work on this root is scheduled. - setCurrentUpdatePriority(previousPriority); - ReactSharedInternals.T = 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(); - } - } + ensureRootIsScheduled(root); - var rootDidHavePassiveEffects = rootDoesHavePassiveEffects; + 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 (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 { - // There were no passive effects, so we can immediately release the cache - // pool for this render. - releaseRootPooledCache(root, remainingLanes); + for (var i = 0; i < recoverableErrors.length; i++) { + var recoverableError = recoverableErrors[i]; + var errorInfo = makeErrorInfo(recoverableError.stack); + onRecoverableError(recoverableError.value, errorInfo); + } + } // 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. - { - nestedPassiveUpdateCount = 0; - rootWithPassiveNestedUpdates = null; - } - } // Read this again, since an effect might have updated it - 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 (includesSyncLane(pendingPassiveEffectsLanes) && (root.tag !== LegacyRoot)) { + flushPassiveEffects(); + } // Read this again, since a passive effect might have updated it - if (remainingLanes === NoLanes) { - // If there's no remaining work, we can clear the set of already failed - // error boundaries. - legacyErrorBoundariesThatAlreadyFailed = null; - } - { - if (!rootDidHavePassiveEffects) { - commitDoubleInvokeEffectsInDEV(root, false); - } - } + remainingLanes = root.pendingLanes; // Check if this render scheduled a cascading synchronous update. This is a + // heurstic to detect infinite update loops. We are intentionally excluding + // hydration lanes in this check, because render triggered by selective + // hydration is conceptually not an update. - onCommitRoot(finishedWork.stateNode, renderPriorityLevel); + if ( // Check if there was a recursive update spawned by this render, in either + // the render phase or the commit phase. We track these explicitly because + // we can't infer from the remaining lanes alone. + enableInfiniteRenderLoopDetection && (didIncludeRenderPhaseUpdate || didIncludeCommitPhaseUpdate) || // Was the finished render the result of an update (not hydration)? + includesSomeLane(lanes, UpdateLanes) && // Did it schedule a sync update? + includesSomeLane(remainingLanes, SyncUpdateLanes)) { + { + markNestedUpdateScheduled(); + } // Count the number of times the root synchronously re-renders without + // finishing. If there are too many, it indicates an infinite update loop. - { - if (isDevToolsPresent) { - root.memoizedUpdaters.clear(); - } - } - // additional work on this root is scheduled. - ensureRootIsScheduled(root); + if (root === rootWithNestedUpdates) { + nestedUpdateCount++; + } else { + nestedUpdateCount = 0; + rootWithNestedUpdates = root; + } + } else { + nestedUpdateCount = 0; + } // If layout work was scheduled, flush it now. - 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; - for (var i = 0; i < recoverableErrors.length; i++) { - var recoverableError = recoverableErrors[i]; - var errorInfo = makeErrorInfo(recoverableError.stack); - onRecoverableError(recoverableError.value, errorInfo); - } - } // 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. + flushSyncWorkOnAllRoots(); - if ( - includesSyncLane(pendingPassiveEffectsLanes) && - root.tag !== LegacyRoot - ) { - flushPassiveEffects(); - } // Read this again, since a passive effect might have updated it - - remainingLanes = root.pendingLanes; // Check if this render scheduled a cascading synchronous update. This is a - // heurstic to detect infinite update loops. We are intentionally excluding - // hydration lanes in this check, because render triggered by selective - // hydration is conceptually not an update. - - if ( - // Check if there was a recursive update spawned by this render, in either - // the render phase or the commit phase. We track these explicitly because - // we can't infer from the remaining lanes alone. - (enableInfiniteRenderLoopDetection && - (didIncludeRenderPhaseUpdate || didIncludeCommitPhaseUpdate)) || // Was the finished render the result of an update (not hydration)? - (includesSomeLane(lanes, UpdateLanes) && // Did it schedule a sync update? - includesSomeLane(remainingLanes, SyncUpdateLanes)) - ) { - { - markNestedUpdateScheduled(); - } // Count the number of times the root synchronously re-renders without - // finishing. If there are too many, it indicates an infinite update loop. + { + markCommitStopped(); + } - if (root === rootWithNestedUpdates) { - nestedUpdateCount++; - } else { - nestedUpdateCount = 0; - rootWithNestedUpdates = root; - } - } else { - nestedUpdateCount = 0; - } // If layout work was scheduled, flush it now. + return null; +} - flushSyncWorkOnAllRoots(); +function makeErrorInfo(componentStack) { + var errorInfo = { + componentStack: componentStack + }; - { - markCommitStopped(); + { + Object.defineProperty(errorInfo, 'digest', { + get: function () { + error('You are accessing "digest" from the errorInfo object passed to onRecoverableError.' + ' This property is no longer provided as part of errorInfo but can be accessed as a property' + ' of the Error instance itself.'); } + }); + } - return null; - } + return errorInfo; +} - function makeErrorInfo(componentStack) { - var errorInfo = { - componentStack: componentStack - }; +function releaseRootPooledCache(root, remainingLanes) { + { + var pooledCacheLanes = root.pooledCacheLanes &= remainingLanes; - { - Object.defineProperty(errorInfo, "digest", { - get: function () { - error( - 'You are accessing "digest" from the errorInfo object passed to onRecoverableError.' + - " This property is no longer provided as part of errorInfo but can be accessed as a property" + - " of the Error instance itself." - ); - } - }); + if (pooledCacheLanes === NoLanes) { + // None of the remaining work relies on the cache pool. Clear it so + // subsequent requests get a new cache + var pooledCache = root.pooledCache; + + if (pooledCache != null) { + root.pooledCache = null; + releaseCache(pooledCache); } + } + } +} + +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) { + // Cache the root since rootWithPendingPassiveEffects is cleared in + // flushPassiveEffectsImpl + var root = rootWithPendingPassiveEffects; // Cache and clear the remaining lanes flag; it must be reset since this + // method can be called from various places, not always from commitRoot + // where the remaining lanes are known + + var remainingLanes = pendingPassiveEffectsRemainingLanes; + pendingPassiveEffectsRemainingLanes = NoLanes; + var renderPriority = lanesToEventPriority(pendingPassiveEffectsLanes); + var priority = lowerEventPriority(DefaultEventPriority, renderPriority); + var prevTransition = ReactSharedInternals.T; + var previousPriority = getCurrentUpdatePriority(); + + try { + setCurrentUpdatePriority(priority); + ReactSharedInternals.T = null; + return flushPassiveEffectsImpl(); + } finally { + setCurrentUpdatePriority(previousPriority); + ReactSharedInternals.T = prevTransition; // Once passive effects have run for the tree - giving components a + // chance to retain cache instances they use - release the pooled + // cache at the root (if there is one) + + releaseRootPooledCache(root, remainingLanes); + } + } + + return false; +} +function enqueuePendingPassiveProfilerEffect(fiber) { + { + pendingPassiveProfilerEffects.push(fiber); - return errorInfo; + if (!rootDoesHavePassiveEffects) { + rootDoesHavePassiveEffects = true; + scheduleCallback(NormalPriority$1, function () { + flushPassiveEffects(); + return null; + }); } + } +} - function releaseRootPooledCache(root, remainingLanes) { - { - var pooledCacheLanes = (root.pooledCacheLanes &= remainingLanes); +function flushPassiveEffectsImpl() { + if (rootWithPendingPassiveEffects === null) { + return false; + } // Cache and clear the transitions flag - if (pooledCacheLanes === NoLanes) { - // None of the remaining work relies on the cache pool. Clear it so - // subsequent requests get a new cache - var pooledCache = root.pooledCache; - if (pooledCache != null) { - root.pooledCache = null; - releaseCache(pooledCache); - } - } - } - } + var transitions = pendingPassiveTransitions; + pendingPassiveTransitions = null; + 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. - 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) { - // Cache the root since rootWithPendingPassiveEffects is cleared in - // flushPassiveEffectsImpl - var root = rootWithPendingPassiveEffects; // Cache and clear the remaining lanes flag; it must be reset since this - // method can be called from various places, not always from commitRoot - // where the remaining lanes are known + pendingPassiveEffectsLanes = NoLanes; - var remainingLanes = pendingPassiveEffectsRemainingLanes; - pendingPassiveEffectsRemainingLanes = NoLanes; - var renderPriority = lanesToEventPriority(pendingPassiveEffectsLanes); - var priority = lowerEventPriority(DefaultEventPriority, renderPriority); - var prevTransition = ReactSharedInternals.T; - var previousPriority = getCurrentUpdatePriority(); + if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { + throw new Error('Cannot flush passive effects while already rendering.'); + } - try { - setCurrentUpdatePriority(priority); - ReactSharedInternals.T = null; - return flushPassiveEffectsImpl(); - } finally { - setCurrentUpdatePriority(previousPriority); - ReactSharedInternals.T = prevTransition; // Once passive effects have run for the tree - giving components a - // chance to retain cache instances they use - release the pooled - // cache at the root (if there is one) + { + isFlushingPassiveEffects = true; + didScheduleUpdateDuringPassiveEffects = false; + } - releaseRootPooledCache(root, remainingLanes); - } - } + { + markPassiveEffectsStarted(lanes); + } - return false; - } - function enqueuePendingPassiveProfilerEffect(fiber) { - { - pendingPassiveProfilerEffects.push(fiber); + var prevExecutionContext = executionContext; + executionContext |= CommitContext; + commitPassiveUnmountEffects(root.current); + commitPassiveMountEffects(root, root.current, lanes, transitions); // TODO: Move to commitPassiveMountEffects - if (!rootDoesHavePassiveEffects) { - rootDoesHavePassiveEffects = true; - scheduleCallback(NormalPriority$1, function () { - flushPassiveEffects(); - return null; - }); - } - } - } + { + var profilerEffects = pendingPassiveProfilerEffects; + pendingPassiveProfilerEffects = []; - function flushPassiveEffectsImpl() { - if (rootWithPendingPassiveEffects === null) { - return false; - } // Cache and clear the transitions flag + for (var i = 0; i < profilerEffects.length; i++) { + var fiber = profilerEffects[i]; + commitPassiveEffectDurations(root, fiber); + } + } - var transitions = pendingPassiveTransitions; - pendingPassiveTransitions = null; - 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. + { + markPassiveEffectsStopped(); + } - pendingPassiveEffectsLanes = NoLanes; + { + commitDoubleInvokeEffectsInDEV(root, true); + } - if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { - throw new Error( - "Cannot flush passive effects while already rendering." - ); - } + executionContext = prevExecutionContext; + flushSyncWorkOnAllRoots(); - { - isFlushingPassiveEffects = true; - didScheduleUpdateDuringPassiveEffects = false; + { + // 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 { + nestedPassiveUpdateCount = 0; + } - { - markPassiveEffectsStarted(lanes); - } + isFlushingPassiveEffects = false; + didScheduleUpdateDuringPassiveEffects = false; + } // TODO: Move to commitPassiveMountEffects - var prevExecutionContext = executionContext; - executionContext |= CommitContext; - commitPassiveUnmountEffects(root.current); - commitPassiveMountEffects(root, root.current, lanes, transitions); // TODO: Move to commitPassiveMountEffects - { - var profilerEffects = pendingPassiveProfilerEffects; - pendingPassiveProfilerEffects = []; + onPostCommitRoot(root); - for (var i = 0; i < profilerEffects.length; i++) { - var fiber = profilerEffects[i]; - commitPassiveEffectDurations(root, fiber); - } - } + { + var stateNode = root.current.stateNode; + stateNode.effectDuration = 0; + stateNode.passiveEffectDuration = 0; + } - { - markPassiveEffectsStopped(); - } + return true; +} - { - commitDoubleInvokeEffectsInDEV(root, true); - } +function isAlreadyFailedLegacyErrorBoundary(instance) { + return legacyErrorBoundariesThatAlreadyFailed !== null && legacyErrorBoundariesThatAlreadyFailed.has(instance); +} +function markLegacyErrorBoundaryAsFailed(instance) { + if (legacyErrorBoundariesThatAlreadyFailed === null) { + legacyErrorBoundariesThatAlreadyFailed = new Set([instance]); + } else { + legacyErrorBoundariesThatAlreadyFailed.add(instance); + } +} - executionContext = prevExecutionContext; - flushSyncWorkOnAllRoots(); +function captureCommitPhaseErrorOnRoot(rootFiber, sourceFiber, error) { + var errorInfo = createCapturedValueAtFiber(error, sourceFiber); + var update = createRootErrorUpdate(rootFiber.stateNode, errorInfo, SyncLane); + var root = enqueueUpdate(rootFiber, update, SyncLane); - { - // 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 { - nestedPassiveUpdateCount = 0; - } + if (root !== null) { + markRootUpdated(root, SyncLane); + ensureRootIsScheduled(root); + } +} - isFlushingPassiveEffects = false; - didScheduleUpdateDuringPassiveEffects = false; - } // TODO: Move to commitPassiveMountEffects +function captureCommitPhaseError(sourceFiber, nearestMountedAncestor, 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; + } + + var fiber = nearestMountedAncestor; + + 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 (typeof ctor.getDerivedStateFromError === 'function' || typeof instance.componentDidCatch === 'function' && !isAlreadyFailedLegacyErrorBoundary(instance)) { + var errorInfo = createCapturedValueAtFiber(error$1, sourceFiber); + var update = createClassErrorUpdate(SyncLane); + var root = enqueueUpdate(fiber, update, SyncLane); - onPostCommitRoot(root); + if (root !== null) { + initializeClassErrorUpdate(update, root, fiber, errorInfo); + markRootUpdated(root, SyncLane); + ensureRootIsScheduled(root); + } - { - var stateNode = root.current.stateNode; - stateNode.effectDuration = 0; - stateNode.passiveEffectDuration = 0; + return; } - - return true; } - function isAlreadyFailedLegacyErrorBoundary(instance) { - return ( - legacyErrorBoundariesThatAlreadyFailed !== null && - legacyErrorBoundariesThatAlreadyFailed.has(instance) - ); - } - function markLegacyErrorBoundaryAsFailed(instance) { - if (legacyErrorBoundariesThatAlreadyFailed === null) { - legacyErrorBoundariesThatAlreadyFailed = new Set([instance]); - } else { - legacyErrorBoundariesThatAlreadyFailed.add(instance); - } - } + fiber = fiber.return; + } - function captureCommitPhaseErrorOnRoot(rootFiber, sourceFiber, error) { - var errorInfo = createCapturedValueAtFiber(error, sourceFiber); - var update = createRootErrorUpdate( - rootFiber.stateNode, - errorInfo, - SyncLane - ); - var root = enqueueUpdate(rootFiber, update, SyncLane); + { + error('Internal React error: Attempted to capture a commit phase error ' + 'inside a detached tree. This indicates a bug in React. Potential ' + '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; + + if (pingCache === null) { + pingCache = root.pingCache = new PossiblyWeakMap(); + threadIDs = new Set(); + pingCache.set(wakeable, threadIDs); + } else { + threadIDs = pingCache.get(wakeable); + + if (threadIDs === undefined) { + threadIDs = new Set(); + pingCache.set(wakeable, threadIDs); + } + } + + if (!threadIDs.has(lanes)) { + workInProgressRootDidAttachPingListener = true; // Memoize using the thread ID to prevent redundant listeners. + + threadIDs.add(lanes); + var ping = pingSuspendedRoot.bind(null, root, wakeable, lanes); - if (root !== null) { - markRootUpdated(root, SyncLane); - ensureRootIsScheduled(root); + { + if (isDevToolsPresent) { + // If we have pending work still, restore the original updaters + restorePendingUpdaters(root, lanes); } } - function captureCommitPhaseError( - sourceFiber, - nearestMountedAncestor, - error$1 - ) { - { - setIsRunningInsertionEffect(false); - } + wakeable.then(ping, ping); + } +} - 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 pingSuspendedRoot(root, wakeable, pingedLanes) { + var pingCache = root.pingCache; + + if (pingCache !== null) { + // The wakeable resolved, so we no longer need to memoize, because it will + // never be thrown again. + pingCache.delete(wakeable); + } + + markRootPinged(root, pingedLanes); + warnIfSuspenseResolutionNotWrappedWithActDEV(root); + + 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); + } + } - var fiber = nearestMountedAncestor; + ensureRootIsScheduled(root); +} - 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; +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 ( - typeof ctor.getDerivedStateFromError === "function" || - (typeof instance.componentDidCatch === "function" && - !isAlreadyFailedLegacyErrorBoundary(instance)) - ) { - var errorInfo = createCapturedValueAtFiber(error$1, sourceFiber); - var update = createClassErrorUpdate(SyncLane); - var root = enqueueUpdate(fiber, update, SyncLane); - - if (root !== null) { - initializeClassErrorUpdate(update, root, fiber, errorInfo); - markRootUpdated(root, SyncLane); - ensureRootIsScheduled(root); - } - return; - } - } + var root = enqueueConcurrentRenderForLane(boundaryFiber, retryLane); - fiber = fiber.return; - } + if (root !== null) { + markRootUpdated(root, retryLane); + ensureRootIsScheduled(root); + } +} - { - error( - "Internal React error: Attempted to capture a commit phase error " + - "inside a detached tree. This indicates a bug in React. Potential " + - "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; - - if (pingCache === null) { - pingCache = root.pingCache = new PossiblyWeakMap(); - threadIDs = new Set(); - pingCache.set(wakeable, threadIDs); - } else { - threadIDs = pingCache.get(wakeable); +function retryDehydratedSuspenseBoundary(boundaryFiber) { + var suspenseState = boundaryFiber.memoizedState; + var retryLane = NoLane; - if (threadIDs === undefined) { - threadIDs = new Set(); - pingCache.set(wakeable, threadIDs); - } - } + if (suspenseState !== null) { + retryLane = suspenseState.retryLane; + } - if (!threadIDs.has(lanes)) { - workInProgressRootDidAttachPingListener = true; // Memoize using the thread ID to prevent redundant listeners. + retryTimedOutBoundary(boundaryFiber, retryLane); +} +function resolveRetryWakeable(boundaryFiber, wakeable) { + var retryLane = NoLane; // Default - threadIDs.add(lanes); - var ping = pingSuspendedRoot.bind(null, root, wakeable, lanes); + var retryCache; - { - if (isDevToolsPresent) { - // If we have pending work still, restore the original updaters - restorePendingUpdaters(root, lanes); - } - } + switch (boundaryFiber.tag) { + case SuspenseComponent: + retryCache = boundaryFiber.stateNode; + var suspenseState = boundaryFiber.memoizedState; - wakeable.then(ping, ping); + if (suspenseState !== null) { + retryLane = suspenseState.retryLane; } - } - function pingSuspendedRoot(root, wakeable, pingedLanes) { - var pingCache = root.pingCache; - - if (pingCache !== null) { - // The wakeable resolved, so we no longer need to memoize, because it will - // never be thrown again. - pingCache.delete(wakeable); - } + break; - markRootPinged(root, pingedLanes); - warnIfSuspenseResolutionNotWrappedWithActDEV(root); + case SuspenseListComponent: + retryCache = boundaryFiber.stateNode; + break; - 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 - ); - } + case OffscreenComponent: + { + var instance = boundaryFiber.stateNode; + retryCache = instance._retryCache; + break; } - ensureRootIsScheduled(root); - } + default: + throw new Error('Pinged unknown suspense boundary type. ' + 'This is probably a bug in React.'); + } - 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 (retryCache !== null) { + // The wakeable resolved, so we no longer need to memoize, because it will + // never be thrown again. + retryCache.delete(wakeable); + } - var root = enqueueConcurrentRenderForLane(boundaryFiber, retryLane); + retryTimedOutBoundary(boundaryFiber, retryLane); +} +function throwIfInfiniteUpdateLoopDetected() { + if (nestedUpdateCount > NESTED_UPDATE_LIMIT) { + nestedUpdateCount = 0; + nestedPassiveUpdateCount = 0; + rootWithNestedUpdates = null; + rootWithPassiveNestedUpdates = null; - if (root !== null) { - markRootUpdated(root, retryLane); - ensureRootIsScheduled(root); + if (enableInfiniteRenderLoopDetection) { + if (executionContext & RenderContext && workInProgressRoot !== null) { + // We're in the render phase. Disable the concurrent error recovery + // mechanism to ensure that the error we're about to throw gets handled. + // We need it to trigger the nearest error boundary so that the infinite + // update loop is broken. + workInProgressRoot.errorRecoveryDisabledLanes = mergeLanes(workInProgressRoot.errorRecoveryDisabledLanes, workInProgressRootRenderLanes); } } - function retryDehydratedSuspenseBoundary(boundaryFiber) { - var suspenseState = boundaryFiber.memoizedState; - var retryLane = NoLane; + 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 (suspenseState !== null) { - retryLane = suspenseState.retryLane; - } + { + if (nestedPassiveUpdateCount > NESTED_PASSIVE_UPDATE_LIMIT) { + nestedPassiveUpdateCount = 0; + rootWithPassiveNestedUpdates = null; - retryTimedOutBoundary(boundaryFiber, retryLane); + 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.'); } - function resolveRetryWakeable(boundaryFiber, wakeable) { - var retryLane = NoLane; // Default + } +} - var retryCache; +function flushRenderPhaseStrictModeWarningsInDEV() { + { + ReactStrictModeWarnings.flushLegacyContextWarning(); + ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings(); + } +} - switch (boundaryFiber.tag) { - case SuspenseComponent: - retryCache = boundaryFiber.stateNode; - var suspenseState = boundaryFiber.memoizedState; +function recursivelyTraverseAndDoubleInvokeEffectsInDEV(root, parentFiber, isInStrictMode) { + if ((parentFiber.subtreeFlags & (PlacementDEV | Visibility)) === NoFlags$1) { + // Parent's descendants have already had effects double invoked. + // Early exit to avoid unnecessary tree traversal. + return; + } - if (suspenseState !== null) { - retryLane = suspenseState.retryLane; - } + var child = parentFiber.child; - break; + while (child !== null) { + doubleInvokeEffectsInDEVIfNecessary(root, child, isInStrictMode); + child = child.sibling; + } +} // Unconditionally disconnects and connects passive and layout effects. - case SuspenseListComponent: - retryCache = boundaryFiber.stateNode; - break; - case OffscreenComponent: { - var instance = boundaryFiber.stateNode; - retryCache = instance._retryCache; - break; - } +function doubleInvokeEffectsOnFiber(root, fiber) { + var shouldDoubleInvokePassiveEffects = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true; + disappearLayoutEffects(fiber); - default: - throw new Error( - "Pinged unknown suspense boundary type. " + - "This is probably a bug in React." - ); - } + if (shouldDoubleInvokePassiveEffects) { + disconnectPassiveEffect(fiber); + } - if (retryCache !== null) { - // The wakeable resolved, so we no longer need to memoize, because it will - // never be thrown again. - retryCache.delete(wakeable); - } + reappearLayoutEffects(root, fiber.alternate, fiber, false); - retryTimedOutBoundary(boundaryFiber, retryLane); - } - function throwIfInfiniteUpdateLoopDetected() { - if (nestedUpdateCount > NESTED_UPDATE_LIMIT) { - nestedUpdateCount = 0; - nestedPassiveUpdateCount = 0; - rootWithNestedUpdates = null; - rootWithPassiveNestedUpdates = null; - - if (enableInfiniteRenderLoopDetection) { - if (executionContext & RenderContext && workInProgressRoot !== null) { - // We're in the render phase. Disable the concurrent error recovery - // mechanism to ensure that the error we're about to throw gets handled. - // We need it to trigger the nearest error boundary so that the infinite - // update loop is broken. - workInProgressRoot.errorRecoveryDisabledLanes = mergeLanes( - workInProgressRoot.errorRecoveryDisabledLanes, - workInProgressRootRenderLanes - ); - } - } + if (shouldDoubleInvokePassiveEffects) { + reconnectPassiveEffects(root, fiber, NoLanes, null, false); + } +} - 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." - ); - } +function doubleInvokeEffectsInDEVIfNecessary(root, fiber, parentIsInStrictMode) { + var isStrictModeFiber = fiber.type === REACT_STRICT_MODE_TYPE; + var isInStrictMode = parentIsInStrictMode || isStrictModeFiber; // First case: the fiber **is not** of type OffscreenComponent. No + // special rules apply to double invoking effects. - { - if (nestedPassiveUpdateCount > NESTED_PASSIVE_UPDATE_LIMIT) { - nestedPassiveUpdateCount = 0; - rootWithPassiveNestedUpdates = null; + if (fiber.tag !== OffscreenComponent) { + if (fiber.flags & PlacementDEV) { + setCurrentFiber(fiber); - 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." - ); - } + if (isInStrictMode) { + doubleInvokeEffectsOnFiber(root, fiber, (fiber.mode & NoStrictPassiveEffectsMode) === NoMode); } + + resetCurrentFiber(); + } else { + recursivelyTraverseAndDoubleInvokeEffectsInDEV(root, fiber, isInStrictMode); } - function flushRenderPhaseStrictModeWarningsInDEV() { - { - ReactStrictModeWarnings.flushLegacyContextWarning(); - ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings(); - } - } - - function recursivelyTraverseAndDoubleInvokeEffectsInDEV( - root, - parentFiber, - isInStrictMode - ) { - if ( - (parentFiber.subtreeFlags & (PlacementDEV | Visibility)) === - NoFlags$1 - ) { - // Parent's descendants have already had effects double invoked. - // Early exit to avoid unnecessary tree traversal. - return; - } + return; + } // Second case: the fiber **is** of type OffscreenComponent. + // This branch contains cases specific to Offscreen. - var child = parentFiber.child; - while (child !== null) { - doubleInvokeEffectsInDEVIfNecessary(root, child, isInStrictMode); - child = child.sibling; - } - } // Unconditionally disconnects and connects passive and layout effects. + if (fiber.memoizedState === null) { + // Only consider Offscreen that is visible. + // TODO (Offscreen) Handle manual mode. + setCurrentFiber(fiber); - function doubleInvokeEffectsOnFiber(root, fiber) { - var shouldDoubleInvokePassiveEffects = - arguments.length > 2 && arguments[2] !== undefined - ? arguments[2] - : true; - disappearLayoutEffects(fiber); + if (isInStrictMode && fiber.flags & Visibility) { + // Double invoke effects on Offscreen's subtree only + // if it is visible and its visibility has changed. + doubleInvokeEffectsOnFiber(root, fiber); + } else if (fiber.subtreeFlags & PlacementDEV) { + // Something in the subtree could have been suspended. + // We need to continue traversal and find newly inserted fibers. + recursivelyTraverseAndDoubleInvokeEffectsInDEV(root, fiber, isInStrictMode); + } - if (shouldDoubleInvokePassiveEffects) { - disconnectPassiveEffect(fiber); - } + resetCurrentFiber(); + } +} - reappearLayoutEffects(root, fiber.alternate, fiber, false); +function commitDoubleInvokeEffectsInDEV(root, hasPassiveEffects) { + { + if (useModernStrictMode && (root.tag !== LegacyRoot)) { + var doubleInvokeEffects = true; - if (shouldDoubleInvokePassiveEffects) { - reconnectPassiveEffects(root, fiber, NoLanes, null, false); + if ((root.tag === ConcurrentRoot) && !(root.current.mode & (StrictLegacyMode | StrictEffectsMode))) { + doubleInvokeEffects = false; } + + recursivelyTraverseAndDoubleInvokeEffectsInDEV(root, root.current, doubleInvokeEffects); + } else { + legacyCommitDoubleInvokeEffectsInDEV(root.current, hasPassiveEffects); } + } +} - function doubleInvokeEffectsInDEVIfNecessary( - root, - fiber, - parentIsInStrictMode - ) { - var isStrictModeFiber = fiber.type === REACT_STRICT_MODE_TYPE; - var isInStrictMode = parentIsInStrictMode || isStrictModeFiber; // First case: the fiber **is not** of type OffscreenComponent. No - // special rules apply to double invoking effects. +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 (fiber.tag !== OffscreenComponent) { - if (fiber.flags & PlacementDEV) { - setCurrentFiber(fiber); + if (hasPassiveEffects) { + invokeEffectsInDev(fiber, MountPassiveDev, invokePassiveEffectUnmountInDEV); + } - if (isInStrictMode) { - doubleInvokeEffectsOnFiber( - root, - fiber, - (fiber.mode & NoStrictPassiveEffectsMode) === NoMode - ); - } + invokeEffectsInDev(fiber, MountLayoutDev, invokeLayoutEffectMountInDEV); - resetCurrentFiber(); - } else { - recursivelyTraverseAndDoubleInvokeEffectsInDEV( - root, - fiber, - isInStrictMode - ); - } + if (hasPassiveEffects) { + invokeEffectsInDev(fiber, MountPassiveDev, invokePassiveEffectMountInDEV); + } - return; - } // Second case: the fiber **is** of type OffscreenComponent. - // This branch contains cases specific to Offscreen. + resetCurrentFiber(); +} - if (fiber.memoizedState === null) { - // Only consider Offscreen that is visible. - // TODO (Offscreen) Handle manual mode. - setCurrentFiber(fiber); +function invokeEffectsInDev(firstChild, fiberFlags, invokeEffectFn) { + var current = firstChild; + var subtreeRoot = null; - if (isInStrictMode && fiber.flags & Visibility) { - // Double invoke effects on Offscreen's subtree only - // if it is visible and its visibility has changed. - doubleInvokeEffectsOnFiber(root, fiber); - } else if (fiber.subtreeFlags & PlacementDEV) { - // Something in the subtree could have been suspended. - // We need to continue traversal and find newly inserted fibers. - recursivelyTraverseAndDoubleInvokeEffectsInDEV( - root, - fiber, - isInStrictMode - ); - } + while (current != null) { + var primarySubtreeFlag = current.subtreeFlags & fiberFlags; - resetCurrentFiber(); + if (current !== subtreeRoot && current.child != null && primarySubtreeFlag !== NoFlags$1) { + current = current.child; + } else { + if ((current.flags & fiberFlags) !== NoFlags$1) { + invokeEffectFn(current); + } + + if (current.sibling !== null) { + current = current.sibling; + } else { + current = subtreeRoot = current.return; } } + } +} - function commitDoubleInvokeEffectsInDEV(root, hasPassiveEffects) { - { - if (useModernStrictMode && root.tag !== LegacyRoot) { - var doubleInvokeEffects = true; - - if ( - root.tag === ConcurrentRoot && - !(root.current.mode & (StrictLegacyMode | StrictEffectsMode)) - ) { - doubleInvokeEffects = false; - } +var didWarnStateUpdateForNotYetMountedComponent = null; +function warnAboutUpdateOnNotYetMountedFiberInDEV(fiber) { + { + if ((executionContext & RenderContext) !== NoContext) { + // We let the other warning about render phase updates deal with this one. + return; + } - recursivelyTraverseAndDoubleInvokeEffectsInDEV( - root, - root.current, - doubleInvokeEffects - ); - } else { - legacyCommitDoubleInvokeEffectsInDEV(root.current, hasPassiveEffects); - } - } + if (!(fiber.mode & ConcurrentMode)) { + return; } - 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); + var tag = fiber.tag; - if (hasPassiveEffects) { - invokeEffectsInDev( - fiber, - MountPassiveDev, - invokePassiveEffectUnmountInDEV - ); - } + if (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. - invokeEffectsInDev(fiber, MountLayoutDev, invokeLayoutEffectMountInDEV); - if (hasPassiveEffects) { - invokeEffectsInDev( - fiber, - MountPassiveDev, - invokePassiveEffectMountInDEV - ); - } + var componentName = getComponentNameFromFiber(fiber) || 'ReactComponent'; + + if (didWarnStateUpdateForNotYetMountedComponent !== null) { + if (didWarnStateUpdateForNotYetMountedComponent.has(componentName)) { + return; + } // $FlowFixMe[incompatible-use] found when upgrading Flow - resetCurrentFiber(); - } - function invokeEffectsInDev(firstChild, fiberFlags, invokeEffectFn) { - var current = firstChild; - var subtreeRoot = null; + didWarnStateUpdateForNotYetMountedComponent.add(componentName); + } else { + didWarnStateUpdateForNotYetMountedComponent = new Set([componentName]); + } - while (current != null) { - var primarySubtreeFlag = current.subtreeFlags & fiberFlags; + var previousFiber = current; - if ( - current !== subtreeRoot && - current.child != null && - primarySubtreeFlag !== NoFlags$1 - ) { - current = current.child; - } else { - if ((current.flags & fiberFlags) !== NoFlags$1) { - invokeEffectFn(current); - } + try { + setCurrentFiber(fiber); - if (current.sibling !== null) { - current = current.sibling; - } else { - current = subtreeRoot = current.return; - } - } + 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 didWarnAboutUpdateInRender = false; +var didWarnAboutUpdateInRenderForAnotherComponent; - 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; - } +{ + didWarnAboutUpdateInRenderForAnotherComponent = new Set(); +} - var tag = fiber.tag; +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. - if ( - 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. + var dedupeKey = renderingComponentName; - var componentName = - getComponentNameFromFiber(fiber) || "ReactComponent"; + if (!didWarnAboutUpdateInRenderForAnotherComponent.has(dedupeKey)) { + didWarnAboutUpdateInRenderForAnotherComponent.add(dedupeKey); + var setStateComponentName = getComponentNameFromFiber(fiber) || 'Unknown'; - if (didWarnStateUpdateForNotYetMountedComponent !== null) { - if (didWarnStateUpdateForNotYetMountedComponent.has(componentName)) { - return; - } // $FlowFixMe[incompatible-use] found when upgrading Flow + 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://react.dev/link/setstate-in-render', setStateComponentName, renderingComponentName, renderingComponentName); + } - didWarnStateUpdateForNotYetMountedComponent.add(componentName); - } else { - didWarnStateUpdateForNotYetMountedComponent = new Set([ - componentName - ]); - } + break; + } - var previousFiber = current; + 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.'); - try { - setCurrentFiber(fiber); + didWarnAboutUpdateInRender = true; + } - 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(); + break; } - } } } - var didWarnAboutUpdateInRender = false; - var didWarnAboutUpdateInRenderForAnotherComponent; + } +} - { - didWarnAboutUpdateInRenderForAnotherComponent = new Set(); +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). } + } +} +var fakeActCallbackNode = {}; // $FlowFixMe[missing-local-annot] - 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. - - var dedupeKey = renderingComponentName; - - 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://react.dev/link/setstate-in-render", - setStateComponentName, - renderingComponentName, - renderingComponentName - ); - } +function scheduleCallback(priorityLevel, callback) { + { + // If we're currently inside an `act` scope, bypass Scheduler and push to + // the `act` queue instead. + var actQueue = ReactSharedInternals.actQueue; - break; - } + if (actQueue !== null) { + actQueue.push(callback); + return fakeActCallbackNode; + } else { + return scheduleCallback$3(priorityLevel, callback); + } + } +} - 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." - ); +function shouldForceFlushFallbacksInDEV() { + // Never force flush in production. This function should get stripped out. + return ReactSharedInternals.actQueue !== null; +} - didWarnAboutUpdateInRender = true; - } +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; + } - break; - } - } - } + if (executionContext !== NoContext) { + // Legacy mode doesn't warn if the update is batched, i.e. + // batchedUpdates or flushSync. + return; } - } - 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). - } + 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; } } - var fakeActCallbackNode = {}; // $FlowFixMe[missing-local-annot] - function scheduleCallback(priorityLevel, callback) { - { - // If we're currently inside an `act` scope, bypass Scheduler and push to - // the `act` queue instead. - var actQueue = ReactSharedInternals.actQueue; + if (ReactSharedInternals.actQueue === null) { + var previousFiber = current; + + try { + setCurrentFiber(fiber); - if (actQueue !== null) { - actQueue.push(callback); - return fakeActCallbackNode; + 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://react.dev/link/wrap-tests-with-act', getComponentNameFromFiber(fiber)); + } finally { + if (previousFiber) { + setCurrentFiber(fiber); } else { - return scheduleCallback$3(priorityLevel, callback); + resetCurrentFiber(); } } } + } +} - function shouldForceFlushFallbacksInDEV() { - // Never force flush in production. This function should get stripped out. - return ReactSharedInternals.actQueue !== null; +function warnIfSuspenseResolutionNotWrappedWithActDEV(root) { + { + if ((root.tag !== LegacyRoot) && isConcurrentActEnvironment() && ReactSharedInternals.actQueue === 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://react.dev/link/wrap-tests-with-act'); } + } +} - 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 (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; - } - } +function setIsRunningInsertionEffect(isRunning) { + { + isRunningInsertionEffect = isRunning; + } +} - if (ReactSharedInternals.actQueue === null) { - var previousFiber = current; +/* eslint-disable react-internal/prod-error-codes */ +// Used by React Refresh runtime through DevTools Global Hook. - try { - setCurrentFiber(fiber); - - 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://react.dev/link/wrap-tests-with-act", - getComponentNameFromFiber(fiber) - ); - } finally { - if (previousFiber) { - setCurrentFiber(fiber); - } else { - resetCurrentFiber(); - } - } - } - } +var resolveFamily = null; +var failedBoundaries = null; +var setRefreshHandler = function (handler) { + { + resolveFamily = handler; + } +}; +function resolveFunctionForHotReloading(type) { + { + if (resolveFamily === null) { + // Hot reloading is disabled. + return type; } - function warnIfSuspenseResolutionNotWrappedWithActDEV(root) { - { - if ( - root.tag !== LegacyRoot && - isConcurrentActEnvironment() && - ReactSharedInternals.actQueue === 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://react.dev/link/wrap-tests-with-act" - ); - } - } - } - - function setIsRunningInsertionEffect(isRunning) { - { - isRunningInsertionEffect = isRunning; - } - } + var family = resolveFamily(type); - /* eslint-disable react-internal/prod-error-codes */ - // Used by React Refresh runtime through DevTools Global Hook. + if (family === undefined) { + return type; + } // Use the latest known implementation. - var resolveFamily = null; - var failedBoundaries = null; - var setRefreshHandler = function (handler) { - { - resolveFamily = handler; - } - }; - function resolveFunctionForHotReloading(type) { - { - if (resolveFamily === null) { - // Hot reloading is disabled. - return type; - } - var family = resolveFamily(type); + return family.current; + } +} +function resolveClassForHotReloading(type) { + // No implementation differences. + return resolveFunctionForHotReloading(type); +} +function resolveForwardRefForHotReloading(type) { + { + if (resolveFamily === null) { + // Hot reloading is disabled. + return type; + } + + var family = resolveFamily(type); + + 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 (type.render !== currentRender) { + var syntheticType = { + $$typeof: REACT_FORWARD_REF_TYPE, + render: currentRender + }; - if (family === undefined) { - return type; - } // Use the latest known implementation. + if (type.displayName !== undefined) { + syntheticType.displayName = type.displayName; + } - return family.current; + return syntheticType; + } } - } - function resolveClassForHotReloading(type) { - // No implementation differences. - return resolveFunctionForHotReloading(type); - } - function resolveForwardRefForHotReloading(type) { - { - if (resolveFamily === null) { - // Hot reloading is disabled. - return type; - } - - var family = resolveFamily(type); - - 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 (type.render !== currentRender) { - var syntheticType = { - $$typeof: REACT_FORWARD_REF_TYPE, - render: currentRender - }; - - if (type.displayName !== undefined) { - syntheticType.displayName = type.displayName; - } - return syntheticType; - } - } + return type; + } // Use the latest known implementation. - return type; - } // Use the latest known implementation. - return family.current; - } + return family.current; + } +} +function isCompatibleFamilyForHotReloading(fiber, element) { + { + if (resolveFamily === null) { + // Hot reloading is disabled. + return false; } - 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 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; + var needsCompareFamilies = false; + var $$typeofNextType = typeof nextType === 'object' && nextType !== null ? nextType.$$typeof : null; - switch (fiber.tag) { - case ClassComponent: { - if (typeof nextType === "function") { - needsCompareFamilies = true; - } - - break; + switch (fiber.tag) { + case ClassComponent: + { + if (typeof nextType === 'function') { + needsCompareFamilies = true; } - 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; - } + break; + } - break; + 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; } - case ForwardRef: { - if ($$typeofNextType === REACT_FORWARD_REF_TYPE) { - needsCompareFamilies = true; - } else if ($$typeofNextType === REACT_LAZY_TYPE) { - needsCompareFamilies = true; - } + break; + } - break; + case ForwardRef: + { + if ($$typeofNextType === REACT_FORWARD_REF_TYPE) { + needsCompareFamilies = true; + } else if ($$typeofNextType === REACT_LAZY_TYPE) { + needsCompareFamilies = true; } - 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; - } + break; + } - break; + 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; } - default: - return false; - } // Check if both types have a family and it's the same one. - - 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 - - if ( - prevFamily !== undefined && - prevFamily === resolveFamily(nextType) - ) { - return true; - } + break; } + default: return false; - } - } - function markFailedErrorBoundaryForHotReloading(fiber) { - { - if (resolveFamily === null) { - // Hot reloading is disabled. - return; - } + } // Check if both types have a family and it's the same one. - if (typeof WeakSet !== "function") { - return; - } - if (failedBoundaries === null) { - failedBoundaries = new WeakSet(); - } + 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 - failedBoundaries.add(fiber); + if (prevFamily !== undefined && prevFamily === resolveFamily(nextType)) { + return true; } } - var scheduleRefresh = function (root, update) { - { - if (resolveFamily === null) { - // Hot reloading is disabled. - return; - } - var staleFamilies = update.staleFamilies, - updatedFamilies = update.updatedFamilies; - flushPassiveEffects(); - scheduleFibersWithFamiliesRecursively( - root.current, - updatedFamilies, - staleFamilies - ); - flushSyncWork(); - } - }; - 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; - } + return false; + } +} +function markFailedErrorBoundaryForHotReloading(fiber) { + { + if (resolveFamily === null) { + // Hot reloading is disabled. + return; + } - updateContainerSync(element, root, null, null); - flushSyncWork(); - } - }; + if (typeof WeakSet !== 'function') { + return; + } - function scheduleFibersWithFamiliesRecursively( - fiber, - updatedFamilies, - staleFamilies - ) { - { - var alternate = fiber.alternate, - 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; + if (failedBoundaries === null) { + failedBoundaries = new WeakSet(); + } - case ForwardRef: - candidateType = type.render; - break; - } + failedBoundaries.add(fiber); + } +} +var scheduleRefresh = function (root, update) { + { + if (resolveFamily === null) { + // Hot reloading is disabled. + return; + } + + var staleFamilies = update.staleFamilies, + updatedFamilies = update.updatedFamilies; + flushPassiveEffects(); + scheduleFibersWithFamiliesRecursively(root.current, updatedFamilies, staleFamilies); + flushSyncWork(); + } +}; +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; + } + + updateContainerSync(element, root, null, null); + flushSyncWork(); + } +}; + +function scheduleFibersWithFamiliesRecursively(fiber, updatedFamilies, staleFamilies) { + { + var alternate = fiber.alternate, + child = fiber.child, + sibling = fiber.sibling, + tag = fiber.tag, + type = fiber.type; + var candidateType = null; - if (resolveFamily === null) { - throw new Error( - "Expected resolveFamily to be set during hot reload." - ); - } + switch (tag) { + case FunctionComponent: + case SimpleMemoComponent: + case ClassComponent: + candidateType = type; + break; - var needsRender = false; - var needsRemount = false; + case ForwardRef: + candidateType = type.render; + break; + } - if (candidateType !== null) { - var family = resolveFamily(candidateType); + if (resolveFamily === null) { + throw new Error('Expected resolveFamily to be set during hot reload.'); + } - if (family !== undefined) { - if (staleFamilies.has(family)) { - needsRemount = true; - } else if (updatedFamilies.has(family)) { - if (tag === ClassComponent) { - needsRemount = true; - } else { - needsRender = true; - } - } - } - } + var needsRender = false; + var needsRemount = false; - if (failedBoundaries !== null) { - if ( - failedBoundaries.has(fiber) || // $FlowFixMe[incompatible-use] found when upgrading Flow - (alternate !== null && failedBoundaries.has(alternate)) - ) { + if (candidateType !== null) { + var family = resolveFamily(candidateType); + + if (family !== undefined) { + if (staleFamilies.has(family)) { + needsRemount = true; + } else if (updatedFamilies.has(family)) { + if (tag === ClassComponent) { needsRemount = true; + } else { + needsRender = true; } } + } + } - if (needsRemount) { - fiber._debugNeedsRemount = true; - } - - if (needsRemount || needsRender) { - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + if (failedBoundaries !== null) { + if (failedBoundaries.has(fiber) || // $FlowFixMe[incompatible-use] found when upgrading Flow + alternate !== null && failedBoundaries.has(alternate)) { + needsRemount = true; + } + } - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane); - } - } + if (needsRemount) { + fiber._debugNeedsRemount = true; + } - if (child !== null && !needsRemount) { - scheduleFibersWithFamiliesRecursively( - child, - updatedFamilies, - staleFamilies - ); - } + if (needsRemount || needsRender) { + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - if (sibling !== null) { - scheduleFibersWithFamiliesRecursively( - sibling, - updatedFamilies, - staleFamilies - ); - } + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane); } } - 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; - } - }; + if (child !== null && !needsRemount) { + scheduleFibersWithFamiliesRecursively(child, updatedFamilies, staleFamilies); + } - 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; + if (sibling !== null) { + scheduleFibersWithFamiliesRecursively(sibling, updatedFamilies, staleFamilies); + } + } +} - case ForwardRef: - candidateType = type.render; - break; - } +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; - var didMatch = false; + switch (tag) { + case FunctionComponent: + case SimpleMemoComponent: + case ClassComponent: + candidateType = type; + break; - if (candidateType !== null) { - if (types.has(candidateType)) { - didMatch = true; - } - } + case ForwardRef: + candidateType = type.render; + break; + } - 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 - ); - } - } + var didMatch = false; - if (sibling !== null) { - findHostInstancesForMatchingFibersRecursively( - sibling, - types, - hostInstances - ); - } + if (candidateType !== null) { + if (types.has(candidateType)) { + didMatch = true; } } - function findHostInstancesForFiberShallowly(fiber, hostInstances) { - { - var foundHostInstances = findChildHostInstancesForFiberShallowly( - fiber, - hostInstances - ); + 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); + } + } - if (foundHostInstances) { - return; - } // If we didn't find any host children, fallback to closest host parent. + if (sibling !== null) { + findHostInstancesForMatchingFibersRecursively(sibling, types, hostInstances); + } + } +} - var node = fiber; +function findHostInstancesForFiberShallowly(fiber, hostInstances) { + { + var foundHostInstances = findChildHostInstancesForFiberShallowly(fiber, hostInstances); - while (true) { - switch (node.tag) { - case HostSingleton: - case HostComponent: - hostInstances.add(node.stateNode); - return; + if (foundHostInstances) { + return; + } // If we didn't find any host children, fallback to closest host parent. - case HostPortal: - hostInstances.add(node.stateNode.containerInfo); - return; - case HostRoot: - hostInstances.add(node.stateNode.containerInfo); - return; - } + var node = fiber; - if (node.return === null) { - throw new Error("Expected to reach root first."); - } + while (true) { + switch (node.tag) { + case HostSingleton: + case HostComponent: + hostInstances.add(node.stateNode); + return; - node = node.return; - } + case HostPortal: + hostInstances.add(node.stateNode.containerInfo); + return; + + case HostRoot: + hostInstances.add(node.stateNode.containerInfo); + return; } - } - function findChildHostInstancesForFiberShallowly(fiber, hostInstances) { - { - var node = fiber; - var foundHostInstances = false; - - 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; - } + if (node.return === null) { + throw new Error('Expected to reach root first.'); + } - if (node === fiber) { - return foundHostInstances; - } + node = node.return; + } + } +} - while (node.sibling === null) { - if (node.return === null || node.return === fiber) { - return foundHostInstances; - } +function findChildHostInstancesForFiberShallowly(fiber, hostInstances) { + { + var node = fiber; + var foundHostInstances = false; - node = node.return; - } + 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; + } + + if (node === fiber) { + return foundHostInstances; + } - node.sibling.return = node.return; - node = node.sibling; + while (node.sibling === null) { + if (node.return === null || node.return === fiber) { + return foundHostInstances; } + + node = node.return; } - return false; + node.sibling.return = node.return; + node = node.sibling; } + } - var hasBadMapPolyfill; - - { - hasBadMapPolyfill = false; + return false; +} - try { - var nonExtensibleObject = Object.preventExtensions({}); - /* eslint-disable no-new */ - - new Map([[nonExtensibleObject, null]]); - new Set([nonExtensibleObject]); - /* eslint-enable no-new */ - } catch (e) { - // TODO: Consider warning about bad polyfills - hasBadMapPolyfill = true; - } - } - - function FiberNode(tag, pendingProps, key, mode) { - // Instance - this.tag = tag; - this.key = key; - this.elementType = null; - this.type = null; - this.stateNode = null; // Fiber - - 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.flags = NoFlags$1; - this.subtreeFlags = NoFlags$1; - this.deletions = null; - this.lanes = NoLanes; - this.childLanes = NoLanes; - this.alternate = null; +var hasBadMapPolyfill; - { - // 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). - - this.actualDuration = 0; - this.actualStartTime = -1; - this.selfBaseDuration = 0; - this.treeBaseDuration = 0; - } +{ + hasBadMapPolyfill = false; - { - // This isn't directly used but is handy for debugging internals: - this._debugInfo = null; - this._debugOwner = null; - this._debugNeedsRemount = false; - this._debugHookTypes = null; - - 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[invalid-constructor]: the shapes are exact here but Flow doesn't like constructors - return new FiberNode(tag, pendingProps, key, mode); - } - - function shouldConstruct(Component) { - var prototype = Component.prototype; - return !!(prototype && prototype.isReactComponent); - } - - function isSimpleFunctionComponent(type) { - return ( - typeof type === "function" && - !shouldConstruct(type) && - type.defaultProps === undefined - ); - } - function isFunctionClassComponent(type) { - return shouldConstruct(type); - } // This is used to create an alternate fiber to do work on. - - function createWorkInProgress(current, pendingProps) { - var workInProgress = current.alternate; - - 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; + try { + var nonExtensibleObject = Object.preventExtensions({}); + /* eslint-disable no-new */ - { - // DEV-only fields - workInProgress._debugOwner = current._debugOwner; - workInProgress._debugHookTypes = current._debugHookTypes; - } + new Map([[nonExtensibleObject, null]]); + new Set([nonExtensibleObject]); + /* eslint-enable no-new */ + } catch (e) { + // TODO: Consider warning about bad polyfills + hasBadMapPolyfill = true; + } +} - workInProgress.alternate = current; - current.alternate = workInProgress; - } else { - workInProgress.pendingProps = pendingProps; // Needed because Blocks store data on type. +function FiberNode(tag, pendingProps, key, mode) { + // Instance + this.tag = tag; + this.key = key; + this.elementType = null; + this.type = null; + this.stateNode = null; // Fiber + + 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.flags = NoFlags$1; + this.subtreeFlags = NoFlags$1; + this.deletions = null; + this.lanes = NoLanes; + this.childLanes = NoLanes; + this.alternate = null; + + { + // 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). + + this.actualDuration = 0; + this.actualStartTime = -1; + this.selfBaseDuration = 0; + this.treeBaseDuration = 0; + } + + { + // This isn't directly used but is handy for debugging internals: + this._debugInfo = null; + this._debugOwner = null; + this._debugNeedsRemount = false; + this._debugHookTypes = null; + + 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[invalid-constructor]: the shapes are exact here but Flow doesn't like constructors + return new FiberNode(tag, pendingProps, key, mode); +} - workInProgress.type = current.type; // We already have an alternate. - // Reset the effect tag. +function shouldConstruct(Component) { + var prototype = Component.prototype; + return !!(prototype && prototype.isReactComponent); +} - workInProgress.flags = NoFlags$1; // The effects are no longer valid. +function isSimpleFunctionComponent(type) { + return typeof type === 'function' && !shouldConstruct(type) && type.defaultProps === undefined; +} +function isFunctionClassComponent(type) { + return shouldConstruct(type); +} // This is used to create an alternate fiber to do work on. + +function createWorkInProgress(current, pendingProps) { + var workInProgress = current.alternate; + + 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; - workInProgress.subtreeFlags = NoFlags$1; - workInProgress.deletions = null; + { + // DEV-only fields + workInProgress._debugOwner = current._debugOwner; + workInProgress._debugHookTypes = current._debugHookTypes; + } - { - // 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. - - 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 - - workInProgress.sibling = current.sibling; - workInProgress.index = current.index; - workInProgress.ref = current.ref; - workInProgress.refCleanup = current.refCleanup; + workInProgress.alternate = current; + current.alternate = workInProgress; + } else { + workInProgress.pendingProps = pendingProps; // Needed because Blocks store data on type. - { - workInProgress.selfBaseDuration = current.selfBaseDuration; - workInProgress.treeBaseDuration = current.treeBaseDuration; - } + workInProgress.type = current.type; // We already have an alternate. + // Reset the effect tag. - { - workInProgress._debugInfo = current._debugInfo; - workInProgress._debugNeedsRemount = current._debugNeedsRemount; + workInProgress.flags = NoFlags$1; // The effects are no longer valid. - switch (workInProgress.tag) { - case FunctionComponent: - case SimpleMemoComponent: - workInProgress.type = resolveFunctionForHotReloading(current.type); - break; + workInProgress.subtreeFlags = NoFlags$1; + workInProgress.deletions = null; - case ClassComponent: - workInProgress.type = resolveClassForHotReloading(current.type); - break; + { + // 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. + + + 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 + + workInProgress.sibling = current.sibling; + workInProgress.index = current.index; + workInProgress.ref = current.ref; + workInProgress.refCleanup = current.refCleanup; + + { + workInProgress.selfBaseDuration = current.selfBaseDuration; + workInProgress.treeBaseDuration = current.treeBaseDuration; + } + + { + workInProgress._debugInfo = current._debugInfo; + workInProgress._debugNeedsRemount = current._debugNeedsRemount; + + switch (workInProgress.tag) { + case FunctionComponent: + case SimpleMemoComponent: + workInProgress.type = resolveFunctionForHotReloading(current.type); + break; + + case ClassComponent: + workInProgress.type = resolveClassForHotReloading(current.type); + break; + + case ForwardRef: + workInProgress.type = resolveForwardRefForHotReloading(current.type); + break; + } + } + + 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 current = workInProgress.alternate; + + 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; - case ForwardRef: - workInProgress.type = resolveForwardRefForHotReloading( - current.type - ); - break; - } - } + { + // 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. + + workInProgress.type = current.type; // 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 + }; - return workInProgress; - } // Used to reuse a Fiber for a second pass. + { + // 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; + } + } - 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. + return workInProgress; +} +function createHostRootFiber(tag, isStrictMode, concurrentUpdatesByDefaultOverride) { + var mode; - var current = workInProgress.alternate; + if (tag === ConcurrentRoot) { + mode = ConcurrentMode; - 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 (isStrictMode === true) { + mode |= StrictLegacyMode | StrictEffectsMode; + } + } else { + mode = NoMode; + } - { - // 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. - - workInProgress.type = current.type; // 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 - }; + 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; + } - { - // 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 createFiber(HostRoot, null, null, mode); +} +function createFiberFromTypeAndProps(type, // React$ElementType +key, pendingProps, owner, mode, lanes) { + var fiberTag = FunctionComponent; // The resolved type is set if we know what the final type will be. I.e. it's not lazy. - return workInProgress; - } - function createHostRootFiber( - tag, - isStrictMode, - concurrentUpdatesByDefaultOverride - ) { - var mode; + var resolvedType = type; - if (tag === ConcurrentRoot) { - mode = ConcurrentMode; + if (typeof type === 'function') { + if (shouldConstruct(type)) { + fiberTag = ClassComponent; - if (isStrictMode === true) { - mode |= StrictLegacyMode | StrictEffectsMode; - } - } else { - mode = NoMode; + { + resolvedType = resolveClassForHotReloading(resolvedType); } - - 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; + } else { + { + resolvedType = resolveFunctionForHotReloading(resolvedType); } - - return createFiber(HostRoot, null, null, mode); } - function createFiberFromTypeAndProps( - type, // React$ElementType - key, - pendingProps, - owner, - mode, - lanes - ) { - var fiberTag = FunctionComponent; // The resolved type is set if we know what the final type will be. I.e. it's not lazy. - - var resolvedType = type; + } else if (typeof type === 'string') { + { + fiberTag = HostComponent; + } + } else { + getTag: switch (type) { + case REACT_FRAGMENT_TYPE: + return createFiberFromFragment(pendingProps.children, mode, lanes, key); - if (typeof type === "function") { - if (shouldConstruct(type)) { - fiberTag = ClassComponent; + case REACT_STRICT_MODE_TYPE: + fiberTag = Mode; + mode |= StrictLegacyMode; - { - resolvedType = resolveClassForHotReloading(resolvedType); - } - } else { - { - resolvedType = resolveFunctionForHotReloading(resolvedType); - } - } - } else if (typeof type === "string") { - { - fiberTag = HostComponent; + if ((mode & ConcurrentMode) !== NoMode) { + // Strict effects should never run on legacy roots + mode |= StrictEffectsMode; } - } 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; - } - break; + break; - case REACT_PROFILER_TYPE: - return createFiberFromProfiler(pendingProps, mode, lanes, key); + case REACT_PROFILER_TYPE: + return createFiberFromProfiler(pendingProps, mode, lanes, key); - case REACT_SUSPENSE_TYPE: - return createFiberFromSuspense(pendingProps, mode, lanes, key); + case REACT_SUSPENSE_TYPE: + return createFiberFromSuspense(pendingProps, mode, lanes, key); - case REACT_SUSPENSE_LIST_TYPE: - return createFiberFromSuspenseList(pendingProps, mode, lanes, key); + case REACT_SUSPENSE_LIST_TYPE: + return createFiberFromSuspenseList(pendingProps, mode, lanes, key); - case REACT_OFFSCREEN_TYPE: - return createFiberFromOffscreen(pendingProps, mode, lanes, key); + case REACT_OFFSCREEN_TYPE: + return createFiberFromOffscreen(pendingProps, mode, lanes, key); - case REACT_LEGACY_HIDDEN_TYPE: + case REACT_LEGACY_HIDDEN_TYPE: - // Fall through + // Fall through - case REACT_SCOPE_TYPE: + case REACT_SCOPE_TYPE: - // Fall through + // Fall through - case REACT_TRACING_MARKER_TYPE: + case REACT_TRACING_MARKER_TYPE: - // Fall through + // Fall through - case REACT_DEBUG_TRACING_MODE_TYPE: + case REACT_DEBUG_TRACING_MODE_TYPE: - // Fall through + // Fall through - default: { - if (typeof type === "object" && type !== null) { - switch (type.$$typeof) { - case REACT_PROVIDER_TYPE: - if (!enableRenderableContext) { - fiberTag = ContextProvider; - break getTag; - } + default: + { + if (typeof type === 'object' && type !== null) { + switch (type.$$typeof) { + case REACT_PROVIDER_TYPE: + if (!enableRenderableContext) { + fiberTag = ContextProvider; + break getTag; + } - // Fall through + // Fall through - case REACT_CONTEXT_TYPE: - if (enableRenderableContext) { - fiberTag = ContextProvider; - break getTag; - } else { - fiberTag = ContextConsumer; - break getTag; - } + case REACT_CONTEXT_TYPE: + if (enableRenderableContext) { + fiberTag = ContextProvider; + break getTag; + } else { + fiberTag = ContextConsumer; + break getTag; + } - case REACT_CONSUMER_TYPE: - if (enableRenderableContext) { - fiberTag = ContextConsumer; - break getTag; - } + case REACT_CONSUMER_TYPE: + if (enableRenderableContext) { + fiberTag = ContextConsumer; + break getTag; + } - // Fall through + // Fall through - case REACT_FORWARD_REF_TYPE: - fiberTag = ForwardRef; + case REACT_FORWARD_REF_TYPE: + fiberTag = ForwardRef; - { - resolvedType = - resolveForwardRefForHotReloading(resolvedType); - } + { + resolvedType = resolveForwardRefForHotReloading(resolvedType); + } - break getTag; + break getTag; - case REACT_MEMO_TYPE: - fiberTag = MemoComponent; - break getTag; + case REACT_MEMO_TYPE: + fiberTag = MemoComponent; + break getTag; - case REACT_LAZY_TYPE: - fiberTag = LazyComponent; - resolvedType = null; - break getTag; - } + case REACT_LAZY_TYPE: + fiberTag = LazyComponent; + resolvedType = null; + break getTag; } + } - var info = ""; + var info = ''; - { - 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 (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 ownerName = owner ? getComponentNameFromOwner(owner) : null; + var ownerName = owner ? getComponentNameFromOwner(owner) : null; - if (ownerName) { - info += "\n\nCheck the render method of `" + ownerName + "`."; - } + if (ownerName) { + info += '\n\nCheck the render method of `' + ownerName + '`.'; } - - 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) - ); } + + 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)); } - } + } + } - var fiber = createFiber(fiberTag, pendingProps, key, mode); - fiber.elementType = type; - fiber.type = resolvedType; - fiber.lanes = lanes; + var fiber = createFiber(fiberTag, pendingProps, key, mode); + fiber.elementType = type; + fiber.type = resolvedType; + fiber.lanes = lanes; - { - fiber._debugOwner = owner; - } + { + fiber._debugOwner = owner; + } - return fiber; - } - function createFiberFromElement(element, mode, lanes) { - var owner = null; + return fiber; +} +function createFiberFromElement(element, mode, lanes) { + var owner = null; - { - owner = element._owner; - } + { + owner = element._owner; + } - var type = element.type; - var key = element.key; - var pendingProps = element.props; - var fiber = createFiberFromTypeAndProps( - type, - key, - pendingProps, - owner, - mode, - lanes - ); + var type = element.type; + var key = element.key; + var pendingProps = element.props; + var fiber = createFiberFromTypeAndProps(type, key, pendingProps, owner, mode, lanes); - { - fiber._debugOwner = element._owner; - } + { + fiber._debugOwner = element._owner; + } - return fiber; - } - function createFiberFromFragment(elements, mode, lanes, key) { - var fiber = createFiber(Fragment, elements, key, mode); - fiber.lanes = lanes; - return fiber; + return fiber; +} +function createFiberFromFragment(elements, mode, lanes, key) { + var fiber = createFiber(Fragment, elements, key, mode); + fiber.lanes = lanes; + return fiber; +} + +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); } + } - 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 - ); - } - } + var fiber = createFiber(Profiler, pendingProps, key, mode | ProfileMode); + fiber.elementType = REACT_PROFILER_TYPE; + fiber.lanes = lanes; - var fiber = createFiber(Profiler, pendingProps, key, mode | ProfileMode); - fiber.elementType = REACT_PROFILER_TYPE; - fiber.lanes = lanes; + { + fiber.stateNode = { + effectDuration: 0, + passiveEffectDuration: 0 + }; + } - { - fiber.stateNode = { - effectDuration: 0, - passiveEffectDuration: 0 - }; - } + return fiber; +} - return fiber; - } - - 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 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; - } - - function FiberRootNode( - containerInfo, // $FlowFixMe[missing-local-annot] - tag, - hydrate, - identifierPrefix, - onUncaughtError, - onCaughtError, - onRecoverableError, - formState - ) { - 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.next = null; - this.callbackNode = null; - this.callbackPriority = NoLane; - this.expirationTimes = createLaneMap(NoTimestamp); - this.pendingLanes = NoLanes; - this.suspendedLanes = NoLanes; - this.pingedLanes = NoLanes; - this.expiredLanes = NoLanes; - this.finishedLanes = NoLanes; - this.errorRecoveryDisabledLanes = NoLanes; - this.shellSuspendCounter = 0; - this.entangledLanes = NoLanes; - this.entanglements = createLaneMap(NoLanes); - this.hiddenUpdates = createLaneMap(null); - this.identifierPrefix = identifierPrefix; - this.onUncaughtError = onUncaughtError; - this.onCaughtError = onCaughtError; - this.onRecoverableError = onRecoverableError; +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 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; +} - { - this.pooledCache = null; - this.pooledCacheLanes = NoLanes; +function FiberRootNode(containerInfo, // $FlowFixMe[missing-local-annot] +tag, hydrate, identifierPrefix, onUncaughtError, onCaughtError, onRecoverableError, formState) { + 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.next = null; + this.callbackNode = null; + this.callbackPriority = NoLane; + this.expirationTimes = createLaneMap(NoTimestamp); + this.pendingLanes = NoLanes; + this.suspendedLanes = NoLanes; + this.pingedLanes = NoLanes; + this.expiredLanes = NoLanes; + this.finishedLanes = NoLanes; + this.errorRecoveryDisabledLanes = NoLanes; + this.shellSuspendCounter = 0; + this.entangledLanes = NoLanes; + this.entanglements = createLaneMap(NoLanes); + this.hiddenUpdates = createLaneMap(null); + this.identifierPrefix = identifierPrefix; + this.onUncaughtError = onUncaughtError; + this.onCaughtError = onCaughtError; + this.onRecoverableError = onRecoverableError; + + { + this.pooledCache = null; + this.pooledCacheLanes = NoLanes; + } + + this.formState = formState; + this.incompleteTransitions = new Map(); + + { + this.effectDuration = 0; + this.passiveEffectDuration = 0; + } + + { + this.memoizedUpdaters = new Set(); + var pendingUpdatersLaneMap = this.pendingUpdatersLaneMap = []; + + for (var _i = 0; _i < TotalLanes; _i++) { + pendingUpdatersLaneMap.push(new Set()); + } + } + + { + { + switch (tag) { + case ConcurrentRoot: + this._debugRootType = hydrate ? 'hydrateRoot()' : 'createRoot()'; + break; + + case LegacyRoot: + this._debugRootType = hydrate ? 'hydrate()' : 'render()'; + break; } + } + } +} - this.formState = formState; - this.incompleteTransitions = new Map(); +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, onUncaughtError, onCaughtError, onRecoverableError, transitionCallbacks, formState) { + // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions + var root = new FiberRootNode(containerInfo, tag, hydrate, identifierPrefix, onUncaughtError, onCaughtError, onRecoverableError, formState); + // stateNode is any. + + + var uninitializedFiber = createHostRootFiber(tag, isStrictMode); + root.current = uninitializedFiber; + uninitializedFiber.stateNode = root; + + { + var initialCache = createCache(); + retainCache(initialCache); // The pooledCache is a fresh cache instance that is used temporarily + // for newly mounted boundaries during a render. In general, the + // pooledCache is always cleared from the root at the end of a render: + // it is either released when render commits, or moved to an Offscreen + // component if rendering suspends. Because the lifetime of the pooled + // cache is distinct from the main memoizedState.cache, it must be + // retained separately. + + root.pooledCache = initialCache; + retainCache(initialCache); + var initialState = { + element: initialChildren, + isDehydrated: hydrate, + cache: initialCache + }; + uninitializedFiber.memoizedState = initialState; + } - { - this.effectDuration = 0; - this.passiveEffectDuration = 0; - } + initializeUpdateQueue(uninitializedFiber); + return root; +} - { - this.memoizedUpdaters = new Set(); - var pendingUpdatersLaneMap = (this.pendingUpdatersLaneMap = []); +var ReactVersion = '19.0.0-canary-bd0f09e6'; - for (var _i = 0; _i < TotalLanes; _i++) { - pendingUpdatersLaneMap.push(new Set()); - } - } +/* + * 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[incompatible-return] 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[incompatible-return] + + return type; + } +} // $FlowFixMe[incompatible-return] only called in DEV, so void return is not possible. + + +function willCoercionThrow(value) { + { + try { + testStringCoercion(value); + return false; + } catch (e) { + return true; + } + } +} - { - { - switch (tag) { - case ConcurrentRoot: - this._debugRootType = hydrate ? "hydrateRoot()" : "createRoot()"; - break; +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 using it here.', typeName(value)); - case LegacyRoot: - this._debugRootType = hydrate ? "hydrate()" : "render()"; - break; - } - } - } + return testStringCoercion(value); // throw (to help callers find troubleshooting comments) } + } +} - 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, - onUncaughtError, - onCaughtError, - onRecoverableError, - transitionCallbacks, - formState - ) { - // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions - var root = new FiberRootNode( - containerInfo, - tag, - hydrate, - identifierPrefix, - onUncaughtError, - onCaughtError, - onRecoverableError, - formState - ); - // stateNode is any. - - var uninitializedFiber = createHostRootFiber(tag, isStrictMode); - root.current = uninitializedFiber; - uninitializedFiber.stateNode = root; +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 { + // 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 + }; +} - { - var initialCache = createCache(); - retainCache(initialCache); // The pooledCache is a fresh cache instance that is used temporarily - // for newly mounted boundaries during a render. In general, the - // pooledCache is always cleared from the root at the end of a render: - // it is either released when render commits, or moved to an Offscreen - // component if rendering suspends. Because the lifetime of the pooled - // cache is distinct from the main memoizedState.cache, it must be - // retained separately. - - root.pooledCache = initialCache; - retainCache(initialCache); - var initialState = { - element: initialChildren, - isDehydrated: hydrate, - cache: initialCache - }; - uninitializedFiber.memoizedState = initialState; - } +// Might add PROFILE later. - initializeUpdateQueue(uninitializedFiber); - return root; - } +var didWarnAboutNestedUpdates; +var didWarnAboutFindNodeInStrictMode; - var ReactVersion = "19.0.0-canary-adfb7d73"; +{ + didWarnAboutNestedUpdates = false; + didWarnAboutFindNodeInStrictMode = {}; +} - /* - * 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[incompatible-return] 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[incompatible-return] +function getContextForSubtree(parentComponent) { + if (!parentComponent) { + return emptyContextObject; + } - return type; - } - } // $FlowFixMe[incompatible-return] only called in DEV, so void return is not possible. + var fiber = get(parentComponent); + var parentContext = findCurrentUnmaskedContext(fiber); - function willCoercionThrow(value) { - { - try { - testStringCoercion(value); - return false; - } catch (e) { - return true; - } - } - } + if (fiber.tag === ClassComponent) { + var Component = fiber.type; - 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; + if (isContextProvider(Component)) { + return processChildContext(fiber, Component, parentContext); } - function checkKeyStringCoercion(value) { - { - if (willCoercionThrow(value)) { - error( - "The provided key is an unsupported type %s." + - " This value must be coerced to a string before using it here.", - typeName(value) - ); + } - return testStringCoercion(value); // throw (to help callers find troubleshooting comments) - } - } - } + return parentContext; +} - 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; +function findHostInstanceWithWarning(component, methodName) { + { + var fiber = get(component); - { - checkKeyStringCoercion(key); + 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); } - - 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 - }; } - // Might add PROFILE later. + var hostFiber = findCurrentHostFiber(fiber); - var didWarnAboutNestedUpdates; - var didWarnAboutFindNodeInStrictMode; - - { - didWarnAboutNestedUpdates = false; - didWarnAboutFindNodeInStrictMode = {}; + if (hostFiber === null) { + return null; } - function getContextForSubtree(parentComponent) { - if (!parentComponent) { - return emptyContextObject; - } + if (hostFiber.mode & StrictLegacyMode) { + var componentName = getComponentNameFromFiber(fiber) || 'Component'; - var fiber = get(parentComponent); - var parentContext = findCurrentUnmaskedContext(fiber); + if (!didWarnAboutFindNodeInStrictMode[componentName]) { + didWarnAboutFindNodeInStrictMode[componentName] = true; + var previousFiber = current; - if (fiber.tag === ClassComponent) { - var Component = fiber.type; + try { + setCurrentFiber(hostFiber); - if (isContextProvider(Component)) { - return processChildContext(fiber, Component, parentContext); + 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://react.dev/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://react.dev/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(); + } } } - - return parentContext; } - function findHostInstanceWithWarning(component, methodName) { - { - var fiber = get(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 - ); - } - } + return getPublicInstance(hostFiber.stateNode); + } +} - var hostFiber = findCurrentHostFiber(fiber); +function createContainer(containerInfo, tag, hydrationCallbacks, isStrictMode, concurrentUpdatesByDefaultOverride, identifierPrefix, onUncaughtError, onCaughtError, onRecoverableError, transitionCallbacks) { + var hydrate = false; + var initialChildren = null; + return createFiberRoot(containerInfo, tag, hydrate, initialChildren, hydrationCallbacks, isStrictMode, concurrentUpdatesByDefaultOverride, identifierPrefix, onUncaughtError, onCaughtError, onRecoverableError, transitionCallbacks, null); +} +function updateContainer(element, container, parentComponent, callback) { + var current = container.current; + var lane = requestUpdateLane(current); + updateContainerImpl(current, lane, element, container, parentComponent, callback); + return lane; +} +function updateContainerSync(element, container, parentComponent, callback) { + if (container.tag === LegacyRoot) { + flushPassiveEffects(); + } + + var current = container.current; + updateContainerImpl(current, SyncLane, element, container, parentComponent, callback); + return SyncLane; +} - if (hostFiber === null) { - return null; - } +function updateContainerImpl(rootFiber, lane, element, container, parentComponent, callback) { + { + onScheduleRoot(container, element); + } - if (hostFiber.mode & StrictLegacyMode) { - var componentName = getComponentNameFromFiber(fiber) || "Component"; + { + markRenderScheduled(lane); + } - if (!didWarnAboutFindNodeInStrictMode[componentName]) { - didWarnAboutFindNodeInStrictMode[componentName] = true; - var previousFiber = current; + var context = getContextForSubtree(parentComponent); - try { - setCurrentFiber(hostFiber); - - 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://react.dev/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://react.dev/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(); - } - } - } - } + if (container.context === null) { + container.context = context; + } else { + container.pendingContext = context; + } - return getPublicInstance(hostFiber.stateNode); - } - } - - function createContainer( - containerInfo, - tag, - hydrationCallbacks, - isStrictMode, - concurrentUpdatesByDefaultOverride, - identifierPrefix, - onUncaughtError, - onCaughtError, - onRecoverableError, - transitionCallbacks - ) { - var hydrate = false; - var initialChildren = null; - return createFiberRoot( - containerInfo, - tag, - hydrate, - initialChildren, - hydrationCallbacks, - isStrictMode, - concurrentUpdatesByDefaultOverride, - identifierPrefix, - onUncaughtError, - onCaughtError, - onRecoverableError, - transitionCallbacks, - null - ); - } - function updateContainer(element, container, parentComponent, callback) { - var current = container.current; - var lane = requestUpdateLane(current); - updateContainerImpl( - current, - lane, - element, - container, - parentComponent, - callback - ); - return lane; - } - function updateContainerSync( - element, - container, - parentComponent, - callback - ) { - if (container.tag === LegacyRoot) { - flushPassiveEffects(); - } + { + if (isRendering && current !== null && !didWarnAboutNestedUpdates) { + didWarnAboutNestedUpdates = true; - var current = container.current; - updateContainerImpl( - current, - SyncLane, - element, - container, - parentComponent, - callback - ); - return SyncLane; + 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'); } + } - function updateContainerImpl( - rootFiber, - lane, - element, - container, - parentComponent, - callback - ) { - { - onScheduleRoot(container, element); - } + var update = createUpdate(lane); // Caution: React DevTools currently depends on this property + // being called "element". - { - markRenderScheduled(lane); + update.payload = { + element: element + }; + callback = callback === undefined ? null : callback; + + if (callback !== null) { + { + if (typeof callback !== 'function') { + error('Expected the last optional `callback` argument to be a ' + 'function. Instead received: %s.', callback); } + } + + update.callback = callback; + } + + var root = enqueueUpdate(rootFiber, update, lane); + + if (root !== null) { + scheduleUpdateOnFiber(root, rootFiber, lane); + entangleTransitions(root, rootFiber, lane); + } +} +function getPublicRootInstance(container) { + var containerFiber = container.current; + + if (!containerFiber.child) { + return null; + } + + switch (containerFiber.child.tag) { + case HostSingleton: + case HostComponent: + return getPublicInstance(containerFiber.child.stateNode); + + default: + return containerFiber.child.stateNode; + } +} + +var shouldErrorImpl = function (fiber) { + return null; +}; + +function shouldError(fiber) { + return shouldErrorImpl(fiber); +} - var context = getContextForSubtree(parentComponent); +var shouldSuspendImpl = function (fiber) { + return false; +}; - if (container.context === null) { - container.context = context; +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; + +{ + var copyWithDeleteImpl = function (obj, path, index) { + var key = path[index]; + var updated = isArray(obj) ? obj.slice() : assign({}, obj); + + if (index + 1 === path.length) { + if (isArray(updated)) { + updated.splice(key, 1); } else { - container.pendingContext = context; + delete updated[key]; } - { - if (isRendering && current !== null && !didWarnAboutNestedUpdates) { - didWarnAboutNestedUpdates = true; + return updated; + } // $FlowFixMe[incompatible-use] number or string is fine here - 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" - ); - } - } - var update = createUpdate(lane); // Caution: React DevTools currently depends on this property - // being called "element". + updated[key] = copyWithDeleteImpl(obj[key], path, index + 1); + return updated; + }; - update.payload = { - element: element - }; - callback = callback === undefined ? null : callback; + var copyWithDelete = function (obj, path) { + return copyWithDeleteImpl(obj, path, 0); + }; - if (callback !== null) { - { - if (typeof callback !== "function") { - error( - "Expected the last optional `callback` argument to be a " + - "function. Instead received: %s.", - callback - ); - } - } + var copyWithRenameImpl = function (obj, oldPath, newPath, index) { + var oldKey = oldPath[index]; + var updated = isArray(obj) ? obj.slice() : assign({}, obj); - update.callback = callback; - } + if (index + 1 === oldPath.length) { + var newKey = newPath[index]; // $FlowFixMe[incompatible-use] number or string is fine here - var root = enqueueUpdate(rootFiber, update, lane); + updated[newKey] = updated[oldKey]; - if (root !== null) { - scheduleUpdateOnFiber(root, rootFiber, lane); - entangleTransitions(root, rootFiber, lane); + if (isArray(updated)) { + updated.splice(oldKey, 1); + } else { + delete updated[oldKey]; } + } else { + // $FlowFixMe[incompatible-use] number or string is fine here + updated[oldKey] = copyWithRenameImpl( // $FlowFixMe[incompatible-use] number or string is fine here + obj[oldKey], oldPath, newPath, index + 1); } - function getPublicRootInstance(container) { - var containerFiber = container.current; - if (!containerFiber.child) { - return null; - } - - switch (containerFiber.child.tag) { - case HostSingleton: - case HostComponent: - return getPublicInstance(containerFiber.child.stateNode); + return updated; + }; - default: - return containerFiber.child.stateNode; - } - } + var copyWithRename = function (obj, oldPath, newPath) { + if (oldPath.length !== newPath.length) { + warn('copyWithRename() expects paths of the same length'); - var shouldErrorImpl = function (fiber) { - return null; - }; + 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'); - function shouldError(fiber) { - return shouldErrorImpl(fiber); + return; + } + } } - var shouldSuspendImpl = function (fiber) { - return false; - }; + return copyWithRenameImpl(obj, oldPath, newPath, 0); + }; - function shouldSuspend(fiber) { - return shouldSuspendImpl(fiber); + var copyWithSetImpl = function (obj, path, index, value) { + if (index >= path.length) { + return value; } - 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; - - { - var copyWithDeleteImpl = function (obj, path, index) { - var key = path[index]; - var updated = isArray(obj) ? obj.slice() : assign({}, obj); - - if (index + 1 === path.length) { - if (isArray(updated)) { - updated.splice(key, 1); - } else { - delete updated[key]; - } - return updated; - } // $FlowFixMe[incompatible-use] number or string is fine here + var key = path[index]; + var updated = isArray(obj) ? obj.slice() : assign({}, obj); // $FlowFixMe[incompatible-use] number or string is fine here - updated[key] = copyWithDeleteImpl(obj[key], path, index + 1); - return updated; - }; + updated[key] = copyWithSetImpl(obj[key], path, index + 1, value); + return updated; + }; - var copyWithDelete = function (obj, path) { - return copyWithDeleteImpl(obj, path, 0); - }; + var copyWithSet = function (obj, path, value) { + return copyWithSetImpl(obj, path, 0, value); + }; - var copyWithRenameImpl = function (obj, oldPath, newPath, index) { - var oldKey = oldPath[index]; - var updated = isArray(obj) ? obj.slice() : assign({}, obj); + 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 (index + 1 === oldPath.length) { - var newKey = newPath[index]; // $FlowFixMe[incompatible-use] number or string is fine here + while (currentHook !== null && id > 0) { + currentHook = currentHook.next; + id--; + } - updated[newKey] = updated[oldKey]; + return currentHook; + }; // Support DevTools editable values for useState and useReducer. - if (isArray(updated)) { - updated.splice(oldKey, 1); - } else { - delete updated[oldKey]; - } - } else { - // $FlowFixMe[incompatible-use] number or string is fine here - updated[oldKey] = copyWithRenameImpl( - // $FlowFixMe[incompatible-use] number or string is fine here - obj[oldKey], - oldPath, - newPath, - index + 1 - ); - } - return updated; - }; + overrideHookState = function (fiber, id, path, value) { + var hook = findHook(fiber, id); - var copyWithRename = function (obj, oldPath, newPath) { - if (oldPath.length !== newPath.length) { - warn("copyWithRename() expects paths of the same length"); + 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. - 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" - ); + fiber.memoizedProps = assign({}, fiber.memoizedProps); + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - return; - } - } - } + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane); + } + } + }; - return copyWithRenameImpl(obj, oldPath, newPath, 0); - }; + overrideHookStateDeletePath = function (fiber, id, path) { + var hook = findHook(fiber, id); - var copyWithSetImpl = function (obj, path, index, value) { - if (index >= path.length) { - return value; - } + 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. - var key = path[index]; - var updated = isArray(obj) ? obj.slice() : assign({}, obj); // $FlowFixMe[incompatible-use] number or string is fine here + fiber.memoizedProps = assign({}, fiber.memoizedProps); + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - updated[key] = copyWithSetImpl(obj[key], path, index + 1, value); - return updated; - }; + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane); + } + } + }; - var copyWithSet = function (obj, path, value) { - return copyWithSetImpl(obj, path, 0, value); - }; + overrideHookStateRenamePath = function (fiber, id, oldPath, newPath) { + var hook = findHook(fiber, id); - 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 (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. - while (currentHook !== null && id > 0) { - currentHook = currentHook.next; - id--; - } + fiber.memoizedProps = assign({}, fiber.memoizedProps); + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - return currentHook; - }; // Support DevTools editable values for useState and useReducer. + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane); + } + } + }; // Support DevTools props for function components, forwardRef, memo, host components, etc. - overrideHookState = function (fiber, id, path, value) { - var hook = findHook(fiber, id); - 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. + overrideProps = function (fiber, path, value) { + fiber.pendingProps = copyWithSet(fiber.memoizedProps, path, value); - fiber.memoizedProps = assign({}, fiber.memoizedProps); - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + if (fiber.alternate) { + fiber.alternate.pendingProps = fiber.pendingProps; + } - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane); - } - } - }; + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - overrideHookStateDeletePath = function (fiber, id, path) { - var hook = findHook(fiber, id); + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane); + } + }; - 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. + overridePropsDeletePath = function (fiber, path) { + fiber.pendingProps = copyWithDelete(fiber.memoizedProps, path); - fiber.memoizedProps = assign({}, fiber.memoizedProps); - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + if (fiber.alternate) { + fiber.alternate.pendingProps = fiber.pendingProps; + } - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane); - } - } - }; + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - overrideHookStateRenamePath = function (fiber, id, oldPath, newPath) { - var hook = findHook(fiber, id); + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane); + } + }; - 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. + overridePropsRenamePath = function (fiber, oldPath, newPath) { + fiber.pendingProps = copyWithRename(fiber.memoizedProps, oldPath, newPath); - fiber.memoizedProps = assign({}, fiber.memoizedProps); - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + if (fiber.alternate) { + fiber.alternate.pendingProps = fiber.pendingProps; + } - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane); - } - } - }; // Support DevTools props for function components, forwardRef, memo, host components, etc. + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - overrideProps = function (fiber, path, value) { - fiber.pendingProps = copyWithSet(fiber.memoizedProps, path, value); + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane); + } + }; - if (fiber.alternate) { - fiber.alternate.pendingProps = fiber.pendingProps; - } + scheduleUpdate = function (fiber) { + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane); + } + }; - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane); - } - }; + setErrorHandler = function (newShouldErrorImpl) { + shouldErrorImpl = newShouldErrorImpl; + }; - overridePropsDeletePath = function (fiber, path) { - fiber.pendingProps = copyWithDelete(fiber.memoizedProps, path); + setSuspenseHandler = function (newShouldSuspendImpl) { + shouldSuspendImpl = newShouldSuspendImpl; + }; +} - if (fiber.alternate) { - fiber.alternate.pendingProps = fiber.pendingProps; - } +function findHostInstanceByFiber(fiber) { + var hostFiber = findCurrentHostFiber(fiber); - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + if (hostFiber === null) { + return null; + } - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane); - } - }; + return hostFiber.stateNode; +} - overridePropsRenamePath = function (fiber, oldPath, newPath) { - fiber.pendingProps = copyWithRename( - fiber.memoizedProps, - oldPath, - newPath - ); +function emptyFindFiberByHostInstance(instance) { + return null; +} - if (fiber.alternate) { - fiber.alternate.pendingProps = fiber.pendingProps; - } +function getCurrentFiberForDevTools() { + return current; +} - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); +function injectIntoDevTools(devToolsConfig) { + var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; + 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: ReactSharedInternals, + 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 + }); +} - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane); - } - }; +var instanceCache = new Map(); - scheduleUpdate = function (fiber) { - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); +function getInstanceFromTag(tag) { + return instanceCache.get(tag) || null; +} - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane); - } - }; +function findHostInstance_DEPRECATED(componentOrHandle) { + { + var owner = ReactSharedInternals.owner; - setErrorHandler = function (newShouldErrorImpl) { - shouldErrorImpl = newShouldErrorImpl; - }; + 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'); + } - setSuspenseHandler = function (newShouldSuspendImpl) { - shouldSuspendImpl = newShouldSuspendImpl; - }; + owner.stateNode._warnedAboutRefsInRender = true; } + } - function findHostInstanceByFiber(fiber) { - var hostFiber = findCurrentHostFiber(fiber); + if (componentOrHandle == null) { + return null; + } // For compatibility with Fabric instances - if (hostFiber === null) { - return null; - } - return hostFiber.stateNode; - } + 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 - function emptyFindFiberByHostInstance(instance) { - return null; - } - function getCurrentFiberForDevTools() { - return current; - } + if (componentOrHandle._nativeTag) { + // $FlowFixMe[incompatible-exact] Necessary when running Flow on Fabric + // $FlowFixMe[incompatible-return] + return componentOrHandle; + } - function injectIntoDevTools(devToolsConfig) { - var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; - 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: ReactSharedInternals, - 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 - }); - } + var hostInstance; - var instanceCache = new Map(); + { + 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] - function getInstanceFromTag(tag) { - return instanceCache.get(tag) || null; - } - function findHostInstance_DEPRECATED(componentOrHandle) { - { - var owner = ReactSharedInternals.owner; - - 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" - ); - } + return hostInstance; +} +function findNodeHandle(componentOrHandle) { + { + var owner = ReactSharedInternals.owner; - owner.stateNode._warnedAboutRefsInRender = true; - } + 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 (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 + owner.stateNode._warnedAboutRefsInRender = true; + } + } - if (componentOrHandle._nativeTag) { - // $FlowFixMe[incompatible-exact] Necessary when running Flow on Fabric - // $FlowFixMe[incompatible-return] - return componentOrHandle; - } + if (componentOrHandle == null) { + return null; + } - var hostInstance; + if (typeof componentOrHandle === 'number') { + // Already a node handle + return componentOrHandle; + } // For compatibility with legacy renderer instances - { - 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 findNodeHandle(componentOrHandle) { - { - var owner = ReactSharedInternals.owner; - - 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 (componentOrHandle._nativeTag) { + return componentOrHandle._nativeTag; + } // For compatibility with Fabric instances - owner.stateNode._warnedAboutRefsInRender = true; - } - } - if (componentOrHandle == null) { - return null; - } + if (componentOrHandle.canonical != null && componentOrHandle.canonical.nativeTag != null) { + return componentOrHandle.canonical.nativeTag; + } // For compatibility with Fabric public instances - 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 + var nativeTag = ReactNativePrivateInterface.getNativeTagFromPublicInstance(componentOrHandle); - if ( - componentOrHandle.canonical != null && - componentOrHandle.canonical.nativeTag != null - ) { - return componentOrHandle.canonical.nativeTag; - } // For compatibility with Fabric public instances + if (nativeTag) { + return nativeTag; + } - var nativeTag = - ReactNativePrivateInterface.getNativeTagFromPublicInstance( - componentOrHandle - ); + var hostInstance; - if (nativeTag) { - return nativeTag; - } + { + hostInstance = findHostInstanceWithWarning(componentOrHandle, 'findNodeHandle'); + } - var hostInstance; + if (hostInstance == null) { + // $FlowFixMe[incompatible-return] Flow limitation in refining an opaque type + return hostInstance; + } - { - hostInstance = findHostInstanceWithWarning( - componentOrHandle, - "findNodeHandle" - ); - } + if (hostInstance._nativeTag != null) { + // $FlowFixMe[incompatible-return] For compatibility with legacy renderer instances + return hostInstance._nativeTag; + } // $FlowFixMe[incompatible-call] Necessary when running Flow on the legacy renderer - if (hostInstance == null) { - // $FlowFixMe[incompatible-return] Flow limitation in refining an opaque type - return hostInstance; - } - if (hostInstance._nativeTag != null) { - // $FlowFixMe[incompatible-return] For compatibility with legacy renderer instances - 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); - return ReactNativePrivateInterface.getNativeTagFromPublicInstance( - hostInstance - ); + 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'); } - function dispatchCommand(handle, command, args) { - var nativeTag = - handle._nativeTag != null - ? handle._nativeTag - : ReactNativePrivateInterface.getNativeTagFromPublicInstance(handle); - 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" - ); - } + return; + } - return; - } + var node = ReactNativePrivateInterface.getNodeFromPublicInstance(handle); - 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 (node != null) { - nativeFabricUIManager.dispatchCommand(node, command, args); - } else { - ReactNativePrivateInterface.UIManager.dispatchViewManagerCommand( - nativeTag, - command, - args - ); - } + 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'); } - 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" - ); - } - return; - } + return; + } - var node = ReactNativePrivateInterface.getNodeFromPublicInstance(handle); + var node = ReactNativePrivateInterface.getNodeFromPublicInstance(handle); - 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 - ); - } // Should have been PublicInstance from ReactFiberConfigFabric - // Should have been PublicInstance from ReactFiberConfigNative - // Remove this once Paper is no longer supported and DOM Node API are enabled by default in RN. - - function isChildPublicInstance(parentInstance, childInstance) { - { - // Paper - if ( - // $FlowExpectedError[incompatible-type] - // $FlowExpectedError[prop-missing] Don't check via `instanceof ReactNativeFiberHostComponent`, so it won't be leaked to Fabric. - parentInstance._internalFiberInstanceHandleDEV && // $FlowExpectedError[incompatible-type] - // $FlowExpectedError[prop-missing] Don't check via `instanceof ReactNativeFiberHostComponent`, so it won't be leaked to Fabric. - childInstance._internalFiberInstanceHandleDEV - ) { - return doesFiberContain( - // $FlowExpectedError[incompatible-call] - parentInstance._internalFiberInstanceHandleDEV, // $FlowExpectedError[incompatible-call] - childInstance._internalFiberInstanceHandleDEV - ); - } - - var parentInternalInstanceHandle = // $FlowExpectedError[incompatible-call] Type for parentInstance should have been PublicInstance from ReactFiberConfigFabric. - ReactNativePrivateInterface.getInternalInstanceHandleFromPublicInstance( - parentInstance - ); - var childInternalInstanceHandle = // $FlowExpectedError[incompatible-call] Type for childInstance should have been PublicInstance from ReactFiberConfigFabric. - ReactNativePrivateInterface.getInternalInstanceHandleFromPublicInstance( - childInstance - ); // Fabric - - if ( - parentInternalInstanceHandle != null && - childInternalInstanceHandle != null - ) { - return doesFiberContain( - parentInternalInstanceHandle, - childInternalInstanceHandle - ); - } // Means that one instance is from Fabric and other is from Paper. + 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 + ); +} // Should have been PublicInstance from ReactFiberConfigFabric +// Should have been PublicInstance from ReactFiberConfigNative +// Remove this once Paper is no longer supported and DOM Node API are enabled by default in RN. + +function isChildPublicInstance(parentInstance, childInstance) { + { + // Paper + if ( // $FlowExpectedError[incompatible-type] + // $FlowExpectedError[prop-missing] Don't check via `instanceof ReactNativeFiberHostComponent`, so it won't be leaked to Fabric. + parentInstance._internalFiberInstanceHandleDEV && // $FlowExpectedError[incompatible-type] + // $FlowExpectedError[prop-missing] Don't check via `instanceof ReactNativeFiberHostComponent`, so it won't be leaked to Fabric. + childInstance._internalFiberInstanceHandleDEV) { + return doesFiberContain( // $FlowExpectedError[incompatible-call] + parentInstance._internalFiberInstanceHandleDEV, // $FlowExpectedError[incompatible-call] + childInstance._internalFiberInstanceHandleDEV); + } + + var parentInternalInstanceHandle = // $FlowExpectedError[incompatible-call] Type for parentInstance should have been PublicInstance from ReactFiberConfigFabric. + ReactNativePrivateInterface.getInternalInstanceHandleFromPublicInstance(parentInstance); + var childInternalInstanceHandle = // $FlowExpectedError[incompatible-call] Type for childInstance should have been PublicInstance from ReactFiberConfigFabric. + ReactNativePrivateInterface.getInternalInstanceHandleFromPublicInstance(childInstance); // Fabric + + if (parentInternalInstanceHandle != null && childInternalInstanceHandle != null) { + return doesFiberContain(parentInternalInstanceHandle, childInternalInstanceHandle); + } // Means that one instance is from Fabric and other is from Paper. + + + return false; + } +} - return false; - } - } +var emptyObject = {}; - var emptyObject = {}; +{ + Object.freeze(emptyObject); +} // $FlowFixMe[missing-local-annot] - { - Object.freeze(emptyObject); - } // $FlowFixMe[missing-local-annot] - function createHierarchy(fiberHierarchy) { - return fiberHierarchy.map(function (fiber) { +function createHierarchy(fiberHierarchy) { + return fiberHierarchy.map(function (fiber) { + return { + name: getComponentNameFromType(fiber.type), + getInspectorData: function (findNodeHandle) { return { - name: getComponentNameFromType(fiber.type), - getInspectorData: function (findNodeHandle) { - return { - props: getHostProps(fiber), - measure: function (callback) { - // If this is Fabric, we'll find a shadow node and use that to measure. - var hostFiber = findCurrentHostFiber(fiber); - var node = - hostFiber != null && - hostFiber.stateNode !== null && - hostFiber.stateNode.node; - - if (node) { - nativeFabricUIManager.measure(node, callback); - } else { - return ReactNativePrivateInterface.UIManager.measure( - getHostNode(fiber, findNodeHandle), - callback - ); - } - } - }; + props: getHostProps(fiber), + measure: function (callback) { + // If this is Fabric, we'll find a shadow node and use that to measure. + var hostFiber = findCurrentHostFiber(fiber); + var node = hostFiber != null && hostFiber.stateNode !== null && hostFiber.stateNode.node; + + if (node) { + nativeFabricUIManager.measure(node, callback); + } else { + return ReactNativePrivateInterface.UIManager.measure(getHostNode(fiber, findNodeHandle), callback); + } } }; - }); - } // $FlowFixMe[missing-local-annot] - - function getHostNode(fiber, findNodeHandle) { - { - var hostNode; // look for children first for the hostNode - // as composite fibers do not have a hostNode - - while (fiber) { - if (fiber.stateNode !== null && fiber.tag === HostComponent) { - hostNode = findNodeHandle(fiber.stateNode); - } + } + }; + }); +} // $FlowFixMe[missing-local-annot] - if (hostNode) { - return hostNode; - } - fiber = fiber.child; - } +function getHostNode(fiber, findNodeHandle) { + { + var hostNode; // look for children first for the hostNode + // as composite fibers do not have a hostNode - return null; + while (fiber) { + if (fiber.stateNode !== null && fiber.tag === HostComponent) { + hostNode = findNodeHandle(fiber.stateNode); } - } // $FlowFixMe[missing-local-annot] - function getHostProps(fiber) { - var host = findCurrentHostFiber(fiber); - - if (host) { - return host.memoizedProps || emptyObject; + if (hostNode) { + return hostNode; } - return emptyObject; + fiber = fiber.child; } - function getInspectorDataForInstance(closestInstance) { - { - // Handle case where user clicks outside of ReactNative - if (!closestInstance) { - return { - hierarchy: [], - props: emptyObject, - selectedIndex: null, - componentStack: "" - }; - } + return null; + } +} // $FlowFixMe[missing-local-annot] - var fiber = findCurrentFiberUsingSlowPath(closestInstance); - if (fiber === null) { - // Might not be currently mounted. - return { - hierarchy: [], - props: emptyObject, - selectedIndex: null, - componentStack: "" - }; - } +function getHostProps(fiber) { + var host = findCurrentHostFiber(fiber); - var fiberHierarchy = getOwnerHierarchy(fiber); - var instance = lastNonHostInstance(fiberHierarchy); - var hierarchy = createHierarchy(fiberHierarchy); - var props = getHostProps(instance); - var selectedIndex = fiberHierarchy.indexOf(instance); - var componentStack = getStackByFiberInDevAndProd(fiber); - return { - closestInstance: instance, - hierarchy: hierarchy, - props: props, - selectedIndex: selectedIndex, - componentStack: componentStack - }; - } - } + if (host) { + return host.memoizedProps || emptyObject; + } - function getOwnerHierarchy(instance) { - var hierarchy = []; - traverseOwnerTreeUp(hierarchy, instance); - return hierarchy; - } // $FlowFixMe[missing-local-annot] + return emptyObject; +} - function lastNonHostInstance(hierarchy) { - for (var i = hierarchy.length - 1; i > 1; i--) { - var instance = hierarchy[i]; +function getInspectorDataForInstance(closestInstance) { + { + // Handle case where user clicks outside of ReactNative + if (!closestInstance) { + return { + hierarchy: [], + props: emptyObject, + selectedIndex: null, + componentStack: '' + }; + } - if (instance.tag !== HostComponent) { - return instance; - } - } + var fiber = findCurrentFiberUsingSlowPath(closestInstance); - return hierarchy[0]; + if (fiber === null) { + // Might not be currently mounted. + return { + hierarchy: [], + props: emptyObject, + selectedIndex: null, + componentStack: '' + }; } - function traverseOwnerTreeUp(hierarchy, instance) { - { - hierarchy.unshift(instance); - var owner = instance._debugOwner; + var fiberHierarchy = getOwnerHierarchy(fiber); + var instance = lastNonHostInstance(fiberHierarchy); + var hierarchy = createHierarchy(fiberHierarchy); + var props = getHostProps(instance); + var selectedIndex = fiberHierarchy.indexOf(instance); + var componentStack = getStackByFiberInDevAndProd(fiber); + return { + closestInstance: instance, + hierarchy: hierarchy, + props: props, + selectedIndex: selectedIndex, + componentStack: componentStack + }; + } +} - if (owner != null && typeof owner.tag === "number") { - traverseOwnerTreeUp(hierarchy, owner); - } - } +function getOwnerHierarchy(instance) { + var hierarchy = []; + traverseOwnerTreeUp(hierarchy, instance); + return hierarchy; +} // $FlowFixMe[missing-local-annot] + + +function lastNonHostInstance(hierarchy) { + for (var i = hierarchy.length - 1; i > 1; i--) { + var instance = hierarchy[i]; + + if (instance.tag !== HostComponent) { + return instance; } + } - function getInspectorDataForViewTag(viewTag) { - { - var closestInstance = getInstanceFromTag(viewTag); - return getInspectorDataForInstance(closestInstance); - } + return hierarchy[0]; +} + +function traverseOwnerTreeUp(hierarchy, instance) { + { + hierarchy.unshift(instance); + var owner = instance._debugOwner; + + if (owner != null && typeof owner.tag === 'number') { + traverseOwnerTreeUp(hierarchy, owner); } + } +} - function getInspectorDataForViewAtPoint( - findNodeHandle, - inspectedView, - locationX, - locationY, - callback - ) { - { - var closestInstance = null; - var fabricNode = - ReactNativePrivateInterface.getNodeFromPublicInstance(inspectedView); - - if (fabricNode) { - // For Fabric we can look up the instance handle directly and measure it. - nativeFabricUIManager.findNodeAtPoint( - fabricNode, - locationX, - locationY, - function (internalInstanceHandle) { - var node = - internalInstanceHandle != null - ? getNodeFromInternalInstanceHandle(internalInstanceHandle) - : null; - - if (internalInstanceHandle == null || node == null) { - callback( - assign( - { - pointerY: locationY, - frame: { - left: 0, - top: 0, - width: 0, - height: 0 - } - }, - getInspectorDataForInstance(closestInstance) - ) - ); - return; - } +function getInspectorDataForViewTag(viewTag) { + { + var closestInstance = getInstanceFromTag(viewTag); + return getInspectorDataForInstance(closestInstance); + } +} - closestInstance = - internalInstanceHandle.stateNode.canonical - .internalInstanceHandle; // Note: this is deprecated and we want to remove it ASAP. Keeping it here for React DevTools compatibility for now. - - var nativeViewTag = - internalInstanceHandle.stateNode.canonical.nativeTag; - nativeFabricUIManager.measure( - node, - function (x, y, width, height, pageX, pageY) { - var inspectorData = - getInspectorDataForInstance(closestInstance); - callback( - assign({}, inspectorData, { - pointerY: locationY, - frame: { - left: pageX, - top: pageY, - width: width, - height: height - }, - touchedViewTag: nativeViewTag - }) - ); - } - ); +function getInspectorDataForViewAtPoint(findNodeHandle, inspectedView, locationX, locationY, callback) { + { + var closestInstance = null; + var fabricNode = ReactNativePrivateInterface.getNodeFromPublicInstance(inspectedView); + + if (fabricNode) { + // For Fabric we can look up the instance handle directly and measure it. + nativeFabricUIManager.findNodeAtPoint(fabricNode, locationX, locationY, function (internalInstanceHandle) { + var node = internalInstanceHandle != null ? getNodeFromInternalInstanceHandle(internalInstanceHandle) : null; + + if (internalInstanceHandle == null || node == null) { + callback(assign({ + pointerY: locationY, + frame: { + left: 0, + top: 0, + width: 0, + height: 0 } - ); - } else if (inspectedView._internalFiberInstanceHandleDEV != null) { - // For Paper we fall back to the old strategy using the React tag. - ReactNativePrivateInterface.UIManager.findSubviewIn( - findNodeHandle(inspectedView), - [locationX, locationY], - function (nativeViewTag, left, top, width, height) { - var inspectorData = getInspectorDataForInstance( - getInstanceFromTag(nativeViewTag) - ); - callback( - assign({}, inspectorData, { - pointerY: locationY, - frame: { - left: left, - top: top, - width: width, - height: height - }, - touchedViewTag: nativeViewTag - }) - ); - } - ); - } else { - error( - "getInspectorDataForViewAtPoint expects to receive a host component" - ); - + }, getInspectorDataForInstance(closestInstance))); return; } - } - } - if ( - typeof ReactNativePrivateInterface.ReactFiberErrorDialog - .showErrorDialog !== "function" - ) { - throw new Error( - "Expected ReactFiberErrorDialog.showErrorDialog to be a function." - ); + closestInstance = internalInstanceHandle.stateNode.canonical.internalInstanceHandle; // Note: this is deprecated and we want to remove it ASAP. Keeping it here for React DevTools compatibility for now. + + var nativeViewTag = internalInstanceHandle.stateNode.canonical.nativeTag; + nativeFabricUIManager.measure(node, function (x, y, width, height, pageX, pageY) { + var inspectorData = getInspectorDataForInstance(closestInstance); + callback(assign({}, inspectorData, { + pointerY: locationY, + frame: { + left: pageX, + top: pageY, + width: width, + height: height + }, + touchedViewTag: nativeViewTag + })); + }); + }); + } else if (inspectedView._internalFiberInstanceHandleDEV != null) { + // For Paper we fall back to the old strategy using the React tag. + ReactNativePrivateInterface.UIManager.findSubviewIn(findNodeHandle(inspectedView), [locationX, locationY], function (nativeViewTag, left, top, width, height) { + var inspectorData = getInspectorDataForInstance(getInstanceFromTag(nativeViewTag)); + callback(assign({}, inspectorData, { + pointerY: locationY, + frame: { + left: left, + top: top, + width: width, + height: height + }, + touchedViewTag: nativeViewTag + })); + }); + } else { + error('getInspectorDataForViewAtPoint expects to receive a host component'); + + return; } + } +} - function nativeOnUncaughtError(error, errorInfo) { - var componentStack = - errorInfo.componentStack != null ? errorInfo.componentStack : ""; - var logError = - ReactNativePrivateInterface.ReactFiberErrorDialog.showErrorDialog({ - errorBoundary: null, - error: error, - componentStack: componentStack - }); // Allow injected showErrorDialog() to prevent default console.error logging. - // This enables renderers like ReactNative to better manage redbox behavior. +if (typeof ReactNativePrivateInterface.ReactFiberErrorDialog.showErrorDialog !== 'function') { + throw new Error('Expected ReactFiberErrorDialog.showErrorDialog to be a function.'); +} - if (logError === false) { - return; - } +function nativeOnUncaughtError(error, errorInfo) { + var componentStack = errorInfo.componentStack != null ? errorInfo.componentStack : ''; + var logError = ReactNativePrivateInterface.ReactFiberErrorDialog.showErrorDialog({ + errorBoundary: null, + error: error, + componentStack: componentStack + }); // Allow injected showErrorDialog() to prevent default console.error logging. + // This enables renderers like ReactNative to better manage redbox behavior. - defaultOnUncaughtError(error, errorInfo); - } + if (logError === false) { + return; + } - function nativeOnCaughtError(error, errorInfo) { - var errorBoundary = errorInfo.errorBoundary; - var componentStack = - errorInfo.componentStack != null ? errorInfo.componentStack : ""; - var logError = - ReactNativePrivateInterface.ReactFiberErrorDialog.showErrorDialog({ - errorBoundary: errorBoundary, - error: error, - componentStack: componentStack - }); // Allow injected showErrorDialog() to prevent default console.error logging. - // This enables renderers like ReactNative to better manage redbox behavior. + defaultOnUncaughtError(error, errorInfo); +} - if (logError === false) { - return; - } +function nativeOnCaughtError(error, errorInfo) { + var errorBoundary = errorInfo.errorBoundary; + var componentStack = errorInfo.componentStack != null ? errorInfo.componentStack : ''; + var logError = ReactNativePrivateInterface.ReactFiberErrorDialog.showErrorDialog({ + errorBoundary: errorBoundary, + error: error, + componentStack: componentStack + }); // Allow injected showErrorDialog() to prevent default console.error logging. + // This enables renderers like ReactNative to better manage redbox behavior. + + if (logError === false) { + return; + } + + defaultOnCaughtError(error, errorInfo); +} - defaultOnCaughtError(error, errorInfo); - } +function render(element, containerTag, callback, concurrentRoot, options) { - function render(element, containerTag, callback, concurrentRoot, options) { - var root = roots.get(containerTag); + var root = roots.get(containerTag); - if (!root) { - // TODO: these defaults are for backwards compatibility. - // Once RN implements these options internally, - // we can remove the defaults and ReactFiberErrorDialog. - var onUncaughtError = nativeOnUncaughtError; - var onCaughtError = nativeOnCaughtError; - var onRecoverableError = defaultOnRecoverableError; + if (!root) { + // TODO: these defaults are for backwards compatibility. + // Once RN implements these options internally, + // we can remove the defaults and ReactFiberErrorDialog. + var onUncaughtError = nativeOnUncaughtError; + var onCaughtError = nativeOnCaughtError; + var onRecoverableError = defaultOnRecoverableError; - if (options && options.onUncaughtError !== undefined) { - onUncaughtError = options.onUncaughtError; - } + if (options && options.onUncaughtError !== undefined) { + onUncaughtError = options.onUncaughtError; + } - if (options && options.onCaughtError !== undefined) { - onCaughtError = options.onCaughtError; - } + if (options && options.onCaughtError !== undefined) { + onCaughtError = options.onCaughtError; + } - if (options && options.onRecoverableError !== undefined) { - onRecoverableError = options.onRecoverableError; - } // TODO (bvaughn): If we decide to keep the wrapper component, - // We could create a wrapper for containerTag as well to reduce special casing. + if (options && options.onRecoverableError !== undefined) { + onRecoverableError = options.onRecoverableError; + } // TODO (bvaughn): If we decide to keep the wrapper component, + // We could create a wrapper for containerTag as well to reduce special casing. - root = createContainer( - containerTag, - concurrentRoot ? ConcurrentRoot : LegacyRoot, - null, - false, - null, - "", - onUncaughtError, - onCaughtError, - onRecoverableError, - null - ); - roots.set(containerTag, root); - } - updateContainer(element, root, null, callback); - return getPublicRootInstance(root); - } // $FlowFixMe[missing-this-annot] + root = createContainer(containerTag, concurrentRoot ? ConcurrentRoot : LegacyRoot, null, false, null, '', onUncaughtError, onCaughtError, onRecoverableError, null); + roots.set(containerTag, root); + } - function unmountComponentAtNode(containerTag) { - this.stopSurface(containerTag); - } + updateContainer(element, root, null, callback); + return getPublicRootInstance(root); +} // $FlowFixMe[missing-this-annot] - function stopSurface(containerTag) { - var root = roots.get(containerTag); - if (root) { - // TODO: Is it safe to reset this now or should I wait since this unmount could be deferred? - updateContainer(null, root, null, function () { - roots.delete(containerTag); - }); - } - } +function unmountComponentAtNode(containerTag) { + this.stopSurface(containerTag); +} - function createPortal(children, containerTag) { - var key = - arguments.length > 2 && arguments[2] !== undefined - ? arguments[2] - : null; - return createPortal$1(children, containerTag, null, key); - } +function stopSurface(containerTag) { + var root = roots.get(containerTag); - 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. - findFiberByHostInstance: getInstanceFromNode, - bundleType: 1, - version: ReactVersion, - rendererPackageName: "react-native-renderer", - rendererConfig: { - getInspectorDataForInstance: getInspectorDataForInstance, - getInspectorDataForViewTag: getInspectorDataForViewTag, - getInspectorDataForViewAtPoint: getInspectorDataForViewAtPoint.bind( - null, - findNodeHandle - ) - } + if (root) { + // TODO: Is it safe to reset this now or should I wait since this unmount could be deferred? + updateContainer(null, root, null, function () { + roots.delete(containerTag); }); + } +} - exports.createPortal = createPortal; - exports.dispatchCommand = dispatchCommand; - exports.findHostInstance_DEPRECATED = findHostInstance_DEPRECATED; - exports.findNodeHandle = findNodeHandle; - exports.getInspectorDataForInstance = getInspectorDataForInstance; - exports.getNodeFromInternalInstanceHandle = - getNodeFromInternalInstanceHandle; - exports.getPublicInstanceFromInternalInstanceHandle = - getPublicInstanceFromInternalInstanceHandle; - exports.isChildPublicInstance = isChildPublicInstance; - exports.render = render; - exports.sendAccessibilityEvent = sendAccessibilityEvent; - exports.stopSurface = stopSurface; - exports.unmountComponentAtNode = unmountComponentAtNode; - /* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */ - if ( - typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== "undefined" && - typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop === - "function" - ) { - __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(new Error()); - } +function createPortal(children, containerTag) { + var key = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; + return createPortal$1(children, containerTag, null, key); +} + +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. + findFiberByHostInstance: getInstanceFromNode, + bundleType: 1 , + version: ReactVersion, + rendererPackageName: 'react-native-renderer', + rendererConfig: { + getInspectorDataForInstance: getInspectorDataForInstance, + getInspectorDataForViewTag: getInspectorDataForViewTag, + getInspectorDataForViewAtPoint: getInspectorDataForViewAtPoint.bind(null, findNodeHandle) + } +}); + +exports.createPortal = createPortal; +exports.dispatchCommand = dispatchCommand; +exports.findHostInstance_DEPRECATED = findHostInstance_DEPRECATED; +exports.findNodeHandle = findNodeHandle; +exports.getInspectorDataForInstance = getInspectorDataForInstance; +exports.getNodeFromInternalInstanceHandle = getNodeFromInternalInstanceHandle; +exports.getPublicInstanceFromInternalInstanceHandle = getPublicInstanceFromInternalInstanceHandle; +exports.isChildPublicInstance = isChildPublicInstance; +exports.render = render; +exports.sendAccessibilityEvent = sendAccessibilityEvent; +exports.stopSurface = stopSurface; +exports.unmountComponentAtNode = unmountComponentAtNode; + /* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */ +if ( + typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' && + typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop === + 'function' +) { + __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(new Error()); +} + })(); } 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 4dcdf67ad4c2e..6140888aa1024 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 @@ -7,1411 +7,1273 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<> + * @generated SignedSource<<3659a427365aaec7f1c22e3be8b66f08>> */ -"use strict"; +'use strict'; if (__DEV__) { - (function () { - "use strict"; - - /* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */ - if ( - typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== "undefined" && - typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart === - "function" - ) { - __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error()); - } - require("react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore"); - var React = require("react"); - var ReactNativePrivateInterface = require("react-native/Libraries/ReactPrivate/ReactNativePrivateInterface"); - var dynamicFlagsUntyped = require("ReactNativeInternalFeatureFlags"); - var Scheduler = require("scheduler"); - - var ReactSharedInternals = - React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE; - - var suppressWarning = false; - function setSuppressWarning(newSuppressWarning) { - { - suppressWarning = newSuppressWarning; - } - } // In DEV, calls to console.warn and console.error get replaced - // by calls to these methods by a Babel plugin. - // - // In PROD (or in packages without access to React internals), - // they are left as they are instead. + (function() { - function warn(format) { - { - if (!suppressWarning) { - for ( - var _len = arguments.length, - args = new Array(_len > 1 ? _len - 1 : 0), - _key = 1; - _key < _len; - _key++ - ) { - args[_key - 1] = arguments[_key]; - } + 'use strict'; - printWarning("warn", format, args); - } +/* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */ +if ( + typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' && + typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart === + 'function' +) { + __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error()); +} + require('react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore'); +var React = require('react'); +var ReactNativePrivateInterface = require('react-native/Libraries/ReactPrivate/ReactNativePrivateInterface'); +var dynamicFlagsUntyped = require('ReactNativeInternalFeatureFlags'); +var Scheduler = require('scheduler'); + +var ReactSharedInternals = React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE; + +var suppressWarning = false; +function setSuppressWarning(newSuppressWarning) { + { + suppressWarning = newSuppressWarning; + } +} // In DEV, calls to console.warn and console.error get replaced +// by calls to these methods by a Babel plugin. +// +// In PROD (or in packages without access to React internals), +// they are left as they are instead. + +function warn(format) { + { + if (!suppressWarning) { + for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + + printWarning('warn', format, args); + } + } +} +function error(format) { + { + if (!suppressWarning) { + for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { + args[_key2 - 1] = arguments[_key2]; } - } - function error(format) { - { - if (!suppressWarning) { - for ( - var _len2 = arguments.length, - args = new Array(_len2 > 1 ? _len2 - 1 : 0), - _key2 = 1; - _key2 < _len2; - _key2++ - ) { - args[_key2 - 1] = arguments[_key2]; - } - printWarning("error", format, args); - } - } + printWarning('error', format, args); } + } +} - function printWarning(level, format, args) { - // When changing this logic, you might want to also - // update consoleWithStackDev.www.js as well. - { - var stack = ReactSharedInternals.getStackAddendum(); +function printWarning(level, format, args) { + // When changing this logic, you might want to also + // update consoleWithStackDev.www.js as well. + { + var stack = ReactSharedInternals.getStackAddendum(); - if (stack !== "") { - format += "%s"; - args = args.concat([stack]); - } // eslint-disable-next-line react-internal/safe-string-coercion + if (stack !== '') { + format += '%s'; + args = args.concat([stack]); + } // eslint-disable-next-line react-internal/safe-string-coercion - var argsWithFormat = args.map(function (item) { - return String(item); - }); // Careful: RN currently depends on this prefix - argsWithFormat.unshift("Warning: " + format); // We intentionally don't use spread (or .apply) directly because it - // breaks IE9: https://github.com/facebook/react/issues/13610 - // eslint-disable-next-line react-internal/no-production-logging + var argsWithFormat = args.map(function (item) { + return String(item); + }); // Careful: RN currently depends on this prefix - Function.prototype.apply.call(console[level], console, argsWithFormat); - } - } + argsWithFormat.unshift('Warning: ' + format); // We intentionally don't use spread (or .apply) directly because it + // breaks IE9: https://github.com/facebook/react/issues/13610 + // eslint-disable-next-line react-internal/no-production-logging - var isArrayImpl = Array.isArray; // eslint-disable-next-line no-redeclare + Function.prototype.apply.call(console[level], console, argsWithFormat); + } +} - function isArray(a) { - return isArrayImpl(a); - } +var isArrayImpl = Array.isArray; // eslint-disable-next-line no-redeclare - var hasError = false; - var caughtError = null; - var getFiberCurrentPropsFromNode$1 = null; - var getInstanceFromNode = null; - var getNodeFromInstance = null; - function setComponentTree( - getFiberCurrentPropsFromNodeImpl, - getInstanceFromNodeImpl, - getNodeFromInstanceImpl - ) { - getFiberCurrentPropsFromNode$1 = getFiberCurrentPropsFromNodeImpl; - getInstanceFromNode = getInstanceFromNodeImpl; - getNodeFromInstance = getNodeFromInstanceImpl; +function isArray(a) { + return isArrayImpl(a); +} - { - if (!getNodeFromInstance || !getInstanceFromNode) { - error( - "Injected " + - "module is missing getNodeFromInstance or getInstanceFromNode." - ); - } - } - } +var hasError = false; +var caughtError = null; +var getFiberCurrentPropsFromNode$1 = null; +var getInstanceFromNode = null; +var getNodeFromInstance = null; +function setComponentTree(getFiberCurrentPropsFromNodeImpl, getInstanceFromNodeImpl, getNodeFromInstanceImpl) { + getFiberCurrentPropsFromNode$1 = getFiberCurrentPropsFromNodeImpl; + getInstanceFromNode = getInstanceFromNodeImpl; + getNodeFromInstance = getNodeFromInstanceImpl; + + { + if (!getNodeFromInstance || !getInstanceFromNode) { + error('Injected ' + 'module is missing getNodeFromInstance or getInstanceFromNode.'); + } + } +} - function validateEventDispatches(event) { - { - var dispatchListeners = event._dispatchListeners; - var dispatchInstances = event._dispatchInstances; - var listenersIsArr = isArray(dispatchListeners); - var listenersLen = listenersIsArr - ? dispatchListeners.length - : dispatchListeners - ? 1 - : 0; - var instancesIsArr = isArray(dispatchInstances); - var instancesLen = instancesIsArr - ? dispatchInstances.length - : dispatchInstances - ? 1 - : 0; - - if ( - instancesIsArr !== listenersIsArr || - instancesLen !== listenersLen - ) { - error("EventPluginUtils: Invalid `event`."); - } - } +function validateEventDispatches(event) { + { + var dispatchListeners = event._dispatchListeners; + var dispatchInstances = event._dispatchInstances; + var listenersIsArr = isArray(dispatchListeners); + var listenersLen = listenersIsArr ? dispatchListeners.length : dispatchListeners ? 1 : 0; + var instancesIsArr = isArray(dispatchInstances); + var instancesLen = instancesIsArr ? dispatchInstances.length : dispatchInstances ? 1 : 0; + + if (instancesIsArr !== listenersIsArr || instancesLen !== listenersLen) { + error('EventPluginUtils: Invalid `event`.'); } - /** - * Dispatch the event to the listener. - * @param {SyntheticEvent} event SyntheticEvent to handle - * @param {function} listener Application-level callback - * @param {*} inst Internal component instance - */ + } +} +/** + * Dispatch the event to the listener. + * @param {SyntheticEvent} event SyntheticEvent to handle + * @param {function} listener Application-level callback + * @param {*} inst Internal component instance + */ - function executeDispatch(event, listener, inst) { - event.currentTarget = getNodeFromInstance(inst); - try { - listener(event); - } catch (error) { - if (!hasError) { - hasError = true; - caughtError = error; - } - } +function executeDispatch(event, listener, inst) { + event.currentTarget = getNodeFromInstance(inst); - event.currentTarget = null; + try { + listener(event); + } catch (error) { + if (!hasError) { + hasError = true; + caughtError = error; } - /** - * Standard/simple iteration through an event's collected dispatches. - */ + } - function executeDispatchesInOrder(event) { - var dispatchListeners = event._dispatchListeners; - var dispatchInstances = event._dispatchInstances; + event.currentTarget = null; +} +/** + * Standard/simple iteration through an event's collected dispatches. + */ - { - validateEventDispatches(event); - } +function executeDispatchesInOrder(event) { + var dispatchListeners = event._dispatchListeners; + var dispatchInstances = event._dispatchInstances; - if (isArray(dispatchListeners)) { - for (var i = 0; i < dispatchListeners.length; i++) { - if (event.isPropagationStopped()) { - break; - } // Listeners and Instances are two parallel arrays that are always in sync. + { + validateEventDispatches(event); + } - executeDispatch(event, dispatchListeners[i], dispatchInstances[i]); - } - } else if (dispatchListeners) { - executeDispatch(event, dispatchListeners, dispatchInstances); - } + if (isArray(dispatchListeners)) { + for (var i = 0; i < dispatchListeners.length; i++) { + if (event.isPropagationStopped()) { + break; + } // Listeners and Instances are two parallel arrays that are always in sync. - event._dispatchListeners = null; - event._dispatchInstances = null; - } - /** - * Standard/simple iteration through an event's collected dispatches, but stops - * at the first dispatch execution returning true, and returns that id. - * - * @return {?string} id of the first dispatch execution who's listener returns - * true, or null if no listener returned true. - */ - function executeDispatchesInOrderStopAtTrueImpl(event) { - var dispatchListeners = event._dispatchListeners; - var dispatchInstances = event._dispatchInstances; + executeDispatch(event, dispatchListeners[i], dispatchInstances[i]); + } + } else if (dispatchListeners) { + executeDispatch(event, dispatchListeners, dispatchInstances); + } - { - validateEventDispatches(event); - } + event._dispatchListeners = null; + event._dispatchInstances = null; +} +/** + * Standard/simple iteration through an event's collected dispatches, but stops + * at the first dispatch execution returning true, and returns that id. + * + * @return {?string} id of the first dispatch execution who's listener returns + * true, or null if no listener returned true. + */ - if (isArray(dispatchListeners)) { - for (var i = 0; i < dispatchListeners.length; i++) { - if (event.isPropagationStopped()) { - break; - } // Listeners and Instances are two parallel arrays that are always in sync. +function executeDispatchesInOrderStopAtTrueImpl(event) { + var dispatchListeners = event._dispatchListeners; + var dispatchInstances = event._dispatchInstances; - if (dispatchListeners[i](event, dispatchInstances[i])) { - return dispatchInstances[i]; - } - } - } else if (dispatchListeners) { - if (dispatchListeners(event, dispatchInstances)) { - return dispatchInstances; - } - } + { + validateEventDispatches(event); + } - return null; - } - /** - * @see executeDispatchesInOrderStopAtTrueImpl - */ + if (isArray(dispatchListeners)) { + for (var i = 0; i < dispatchListeners.length; i++) { + if (event.isPropagationStopped()) { + break; + } // Listeners and Instances are two parallel arrays that are always in sync. - function executeDispatchesInOrderStopAtTrue(event) { - var ret = executeDispatchesInOrderStopAtTrueImpl(event); - event._dispatchInstances = null; - event._dispatchListeners = null; - return ret; - } - /** - * Execution of a "direct" dispatch - there must be at most one dispatch - * accumulated on the event or it is considered an error. It doesn't really make - * sense for an event with multiple dispatches (bubbled) to keep track of the - * return values at each dispatch execution, but it does tend to make sense when - * dealing with "direct" dispatches. - * - * @return {*} The return value of executing the single dispatch. - */ - function executeDirectDispatch(event) { - { - validateEventDispatches(event); + if (dispatchListeners[i](event, dispatchInstances[i])) { + return dispatchInstances[i]; } + } + } else if (dispatchListeners) { + if (dispatchListeners(event, dispatchInstances)) { + return dispatchInstances; + } + } - var dispatchListener = event._dispatchListeners; - var dispatchInstance = event._dispatchInstances; + return null; +} +/** + * @see executeDispatchesInOrderStopAtTrueImpl + */ - if (isArray(dispatchListener)) { - throw new Error("Invalid `event`."); - } - event.currentTarget = dispatchListener - ? getNodeFromInstance(dispatchInstance) - : null; - var res = dispatchListener ? dispatchListener(event) : null; - event.currentTarget = null; - event._dispatchListeners = null; - event._dispatchInstances = null; - return res; - } - /** - * @param {SyntheticEvent} event - * @return {boolean} True iff number of dispatches accumulated is greater than 0. - */ +function executeDispatchesInOrderStopAtTrue(event) { + var ret = executeDispatchesInOrderStopAtTrueImpl(event); + event._dispatchInstances = null; + event._dispatchListeners = null; + return ret; +} +/** + * Execution of a "direct" dispatch - there must be at most one dispatch + * accumulated on the event or it is considered an error. It doesn't really make + * sense for an event with multiple dispatches (bubbled) to keep track of the + * return values at each dispatch execution, but it does tend to make sense when + * dealing with "direct" dispatches. + * + * @return {*} The return value of executing the single dispatch. + */ - function hasDispatches(event) { - return !!event._dispatchListeners; - } - function rethrowCaughtError() { - if (hasError) { - var error = caughtError; - hasError = false; - caughtError = null; - throw error; - } - } +function executeDirectDispatch(event) { + { + validateEventDispatches(event); + } - var assign = Object.assign; + var dispatchListener = event._dispatchListeners; + var dispatchInstance = event._dispatchInstances; - var EVENT_POOL_SIZE = 10; - /** - * @interface Event - * @see http://www.w3.org/TR/DOM-Level-3-Events/ - */ + if (isArray(dispatchListener)) { + throw new Error('Invalid `event`.'); + } - var EventInterface = { - type: null, - target: null, - // currentTarget is set when dispatching; no use in copying it here - currentTarget: function () { - return null; - }, - eventPhase: null, - bubbles: null, - cancelable: null, - timeStamp: function (event) { - return event.timeStamp || Date.now(); - }, - defaultPrevented: null, - isTrusted: null - }; + event.currentTarget = dispatchListener ? getNodeFromInstance(dispatchInstance) : null; + var res = dispatchListener ? dispatchListener(event) : null; + event.currentTarget = null; + event._dispatchListeners = null; + event._dispatchInstances = null; + return res; +} +/** + * @param {SyntheticEvent} event + * @return {boolean} True iff number of dispatches accumulated is greater than 0. + */ - function functionThatReturnsTrue() { - return true; - } +function hasDispatches(event) { + return !!event._dispatchListeners; +} +function rethrowCaughtError() { + if (hasError) { + var error = caughtError; + hasError = false; + caughtError = null; + throw error; + } +} - function functionThatReturnsFalse() { - return false; - } - /** - * Synthetic events are dispatched by event plugins, typically in response to a - * top-level event delegation handler. - * - * These systems should generally use pooling to reduce the frequency of garbage - * collection. The system should check `isPersistent` to determine whether the - * event should be released into the pool after being dispatched. Users that - * need a persisted event should invoke `persist`. - * - * Synthetic events (and subclasses) implement the DOM Level 3 Events API by - * normalizing browser quirks. Subclasses do not necessarily have to implement a - * DOM interface; custom application-specific events can also subclass this. - * - * @param {object} dispatchConfig Configuration used to dispatch this event. - * @param {*} targetInst Marker identifying the event target. - * @param {object} nativeEvent Native browser event. - * @param {DOMEventTarget} nativeEventTarget Target node. - */ +var assign = Object.assign; - function SyntheticEvent( - dispatchConfig, - targetInst, - nativeEvent, - nativeEventTarget - ) { - { - // these have a getter/setter for warnings - delete this.nativeEvent; - delete this.preventDefault; - delete this.stopPropagation; - delete this.isDefaultPrevented; - delete this.isPropagationStopped; - } - - this.dispatchConfig = dispatchConfig; - this._targetInst = targetInst; - this.nativeEvent = nativeEvent; - this._dispatchListeners = null; - this._dispatchInstances = null; - var Interface = this.constructor.Interface; - - for (var propName in Interface) { - if (!Interface.hasOwnProperty(propName)) { - continue; - } +var EVENT_POOL_SIZE = 10; +/** + * @interface Event + * @see http://www.w3.org/TR/DOM-Level-3-Events/ + */ - { - delete this[propName]; // this has a getter/setter for warnings - } +var EventInterface = { + type: null, + target: null, + // currentTarget is set when dispatching; no use in copying it here + currentTarget: function () { + return null; + }, + eventPhase: null, + bubbles: null, + cancelable: null, + timeStamp: function (event) { + return event.timeStamp || Date.now(); + }, + defaultPrevented: null, + isTrusted: null +}; + +function functionThatReturnsTrue() { + return true; +} - var normalize = Interface[propName]; +function functionThatReturnsFalse() { + return false; +} +/** + * Synthetic events are dispatched by event plugins, typically in response to a + * top-level event delegation handler. + * + * These systems should generally use pooling to reduce the frequency of garbage + * collection. The system should check `isPersistent` to determine whether the + * event should be released into the pool after being dispatched. Users that + * need a persisted event should invoke `persist`. + * + * Synthetic events (and subclasses) implement the DOM Level 3 Events API by + * normalizing browser quirks. Subclasses do not necessarily have to implement a + * DOM interface; custom application-specific events can also subclass this. + * + * @param {object} dispatchConfig Configuration used to dispatch this event. + * @param {*} targetInst Marker identifying the event target. + * @param {object} nativeEvent Native browser event. + * @param {DOMEventTarget} nativeEventTarget Target node. + */ - if (normalize) { - this[propName] = normalize(nativeEvent); - } else { - if (propName === "target") { - this.target = nativeEventTarget; - } else { - this[propName] = nativeEvent[propName]; - } - } - } - var defaultPrevented = - nativeEvent.defaultPrevented != null - ? nativeEvent.defaultPrevented - : nativeEvent.returnValue === false; +function SyntheticEvent(dispatchConfig, targetInst, nativeEvent, nativeEventTarget) { + { + // these have a getter/setter for warnings + delete this.nativeEvent; + delete this.preventDefault; + delete this.stopPropagation; + delete this.isDefaultPrevented; + delete this.isPropagationStopped; + } - if (defaultPrevented) { - this.isDefaultPrevented = functionThatReturnsTrue; - } else { - this.isDefaultPrevented = functionThatReturnsFalse; - } + this.dispatchConfig = dispatchConfig; + this._targetInst = targetInst; + this.nativeEvent = nativeEvent; + this._dispatchListeners = null; + this._dispatchInstances = null; + var Interface = this.constructor.Interface; - this.isPropagationStopped = functionThatReturnsFalse; - return this; + for (var propName in Interface) { + if (!Interface.hasOwnProperty(propName)) { + continue; } - assign(SyntheticEvent.prototype, { - preventDefault: function () { - this.defaultPrevented = true; - var event = this.nativeEvent; + { + delete this[propName]; // this has a getter/setter for warnings + } - if (!event) { - return; - } + var normalize = Interface[propName]; - if (event.preventDefault) { - event.preventDefault(); - } else if (typeof event.returnValue !== "unknown") { - event.returnValue = false; - } + if (normalize) { + this[propName] = normalize(nativeEvent); + } else { + if (propName === 'target') { + this.target = nativeEventTarget; + } else { + this[propName] = nativeEvent[propName]; + } + } + } - this.isDefaultPrevented = functionThatReturnsTrue; - }, - stopPropagation: function () { - var event = this.nativeEvent; + var defaultPrevented = nativeEvent.defaultPrevented != null ? nativeEvent.defaultPrevented : nativeEvent.returnValue === false; - if (!event) { - return; - } + if (defaultPrevented) { + this.isDefaultPrevented = functionThatReturnsTrue; + } else { + this.isDefaultPrevented = functionThatReturnsFalse; + } - if (event.stopPropagation) { - event.stopPropagation(); - } else if (typeof event.cancelBubble !== "unknown") { - // The ChangeEventPlugin registers a "propertychange" event for - // IE. This event does not support bubbling or cancelling, and - // any references to cancelBubble throw "Member not found". A - // typeof check of "unknown" circumvents this issue (and is also - // IE specific). - event.cancelBubble = true; - } - - this.isPropagationStopped = functionThatReturnsTrue; - }, - - /** - * We release all dispatched `SyntheticEvent`s after each event loop, adding - * them back into the pool. This allows a way to hold onto a reference that - * won't be added back into the pool. - */ - persist: function () { - this.isPersistent = functionThatReturnsTrue; - }, - - /** - * Checks if this event should be released back into the pool. - * - * @return {boolean} True if this should not be released, false otherwise. - */ - isPersistent: functionThatReturnsFalse, - - /** - * `PooledClass` looks for `destructor` on each instance it releases. - */ - destructor: function () { - var Interface = this.constructor.Interface; - - for (var propName in Interface) { - { - Object.defineProperty( - this, - propName, - getPooledWarningPropertyDefinition(propName, Interface[propName]) - ); - } - } + this.isPropagationStopped = functionThatReturnsFalse; + return this; +} - this.dispatchConfig = null; - this._targetInst = null; - this.nativeEvent = null; - this.isDefaultPrevented = functionThatReturnsFalse; - this.isPropagationStopped = functionThatReturnsFalse; - this._dispatchListeners = null; - this._dispatchInstances = null; +assign(SyntheticEvent.prototype, { + preventDefault: function () { + this.defaultPrevented = true; + var event = this.nativeEvent; - { - Object.defineProperty( - this, - "nativeEvent", - getPooledWarningPropertyDefinition("nativeEvent", null) - ); - Object.defineProperty( - this, - "isDefaultPrevented", - getPooledWarningPropertyDefinition( - "isDefaultPrevented", - functionThatReturnsFalse - ) - ); - Object.defineProperty( - this, - "isPropagationStopped", - getPooledWarningPropertyDefinition( - "isPropagationStopped", - functionThatReturnsFalse - ) - ); - Object.defineProperty( - this, - "preventDefault", - getPooledWarningPropertyDefinition("preventDefault", function () {}) - ); - Object.defineProperty( - this, - "stopPropagation", - getPooledWarningPropertyDefinition( - "stopPropagation", - function () {} - ) - ); - } - } - }); - SyntheticEvent.Interface = EventInterface; - /** - * Helper to reduce boilerplate when creating subclasses. - */ + if (!event) { + return; + } - SyntheticEvent.extend = function (Interface) { - var Super = this; + if (event.preventDefault) { + event.preventDefault(); + } else if (typeof event.returnValue !== 'unknown') { + event.returnValue = false; + } - var E = function () {}; + this.isDefaultPrevented = functionThatReturnsTrue; + }, + stopPropagation: function () { + var event = this.nativeEvent; - E.prototype = Super.prototype; - var prototype = new E(); + if (!event) { + return; + } - function Class() { - return Super.apply(this, arguments); - } + if (event.stopPropagation) { + event.stopPropagation(); + } else if (typeof event.cancelBubble !== 'unknown') { + // The ChangeEventPlugin registers a "propertychange" event for + // IE. This event does not support bubbling or cancelling, and + // any references to cancelBubble throw "Member not found". A + // typeof check of "unknown" circumvents this issue (and is also + // IE specific). + event.cancelBubble = true; + } - assign(prototype, Class.prototype); - Class.prototype = prototype; - Class.prototype.constructor = Class; - Class.Interface = assign({}, Super.Interface, Interface); - Class.extend = Super.extend; - addEventPoolingTo(Class); - return Class; - }; + this.isPropagationStopped = functionThatReturnsTrue; + }, - addEventPoolingTo(SyntheticEvent); - /** - * Helper to nullify syntheticEvent instance properties when destructing - * - * @param {String} propName - * @param {?object} getVal - * @return {object} defineProperty object - */ + /** + * We release all dispatched `SyntheticEvent`s after each event loop, adding + * them back into the pool. This allows a way to hold onto a reference that + * won't be added back into the pool. + */ + persist: function () { + this.isPersistent = functionThatReturnsTrue; + }, - function getPooledWarningPropertyDefinition(propName, getVal) { - function set(val) { - var action = isFunction ? "setting the method" : "setting the property"; - warn(action, "This is effectively a no-op"); - return val; - } + /** + * Checks if this event should be released back into the pool. + * + * @return {boolean} True if this should not be released, false otherwise. + */ + isPersistent: functionThatReturnsFalse, - function get() { - var action = isFunction - ? "accessing the method" - : "accessing the property"; - var result = isFunction - ? "This is a no-op function" - : "This is set to null"; - warn(action, result); - return getVal; - } + /** + * `PooledClass` looks for `destructor` on each instance it releases. + */ + destructor: function () { + var Interface = this.constructor.Interface; - function warn(action, result) { - { - error( - "This synthetic event is reused for performance reasons. If you're seeing this, " + - "you're %s `%s` on a released/nullified synthetic event. %s. " + - "If you must keep the original synthetic event around, use event.persist(). " + - "See https://react.dev/link/event-pooling for more information.", - action, - propName, - result - ); - } + for (var propName in Interface) { + { + Object.defineProperty(this, propName, getPooledWarningPropertyDefinition(propName, Interface[propName])); } - - var isFunction = typeof getVal === "function"; - return { - configurable: true, - set: set, - get: get - }; } - function createOrGetPooledEvent( - dispatchConfig, - targetInst, - nativeEvent, - nativeInst - ) { - var EventConstructor = this; + this.dispatchConfig = null; + this._targetInst = null; + this.nativeEvent = null; + this.isDefaultPrevented = functionThatReturnsFalse; + this.isPropagationStopped = functionThatReturnsFalse; + this._dispatchListeners = null; + this._dispatchInstances = null; - if (EventConstructor.eventPool.length) { - var instance = EventConstructor.eventPool.pop(); - EventConstructor.call( - instance, - dispatchConfig, - targetInst, - nativeEvent, - nativeInst - ); - return instance; - } + { + Object.defineProperty(this, 'nativeEvent', getPooledWarningPropertyDefinition('nativeEvent', null)); + Object.defineProperty(this, 'isDefaultPrevented', getPooledWarningPropertyDefinition('isDefaultPrevented', functionThatReturnsFalse)); + Object.defineProperty(this, 'isPropagationStopped', getPooledWarningPropertyDefinition('isPropagationStopped', functionThatReturnsFalse)); + Object.defineProperty(this, 'preventDefault', getPooledWarningPropertyDefinition('preventDefault', function () {})); + Object.defineProperty(this, 'stopPropagation', getPooledWarningPropertyDefinition('stopPropagation', function () {})); + } + } +}); +SyntheticEvent.Interface = EventInterface; +/** + * Helper to reduce boilerplate when creating subclasses. + */ - return new EventConstructor( - dispatchConfig, - targetInst, - nativeEvent, - nativeInst - ); - } +SyntheticEvent.extend = function (Interface) { + var Super = this; - function releasePooledEvent(event) { - var EventConstructor = this; + var E = function () {}; - if (!(event instanceof EventConstructor)) { - throw new Error( - "Trying to release an event instance into a pool of a different type." - ); - } + E.prototype = Super.prototype; + var prototype = new E(); - event.destructor(); + function Class() { + return Super.apply(this, arguments); + } - if (EventConstructor.eventPool.length < EVENT_POOL_SIZE) { - EventConstructor.eventPool.push(event); - } - } + assign(prototype, Class.prototype); + Class.prototype = prototype; + Class.prototype.constructor = Class; + Class.Interface = assign({}, Super.Interface, Interface); + Class.extend = Super.extend; + addEventPoolingTo(Class); + return Class; +}; + +addEventPoolingTo(SyntheticEvent); +/** + * Helper to nullify syntheticEvent instance properties when destructing + * + * @param {String} propName + * @param {?object} getVal + * @return {object} defineProperty object + */ - function addEventPoolingTo(EventConstructor) { - EventConstructor.getPooled = createOrGetPooledEvent; - EventConstructor.eventPool = []; - EventConstructor.release = releasePooledEvent; +function getPooledWarningPropertyDefinition(propName, getVal) { + function set(val) { + var action = isFunction ? 'setting the method' : 'setting the property'; + warn(action, 'This is effectively a no-op'); + return val; + } + + function get() { + var action = isFunction ? 'accessing the method' : 'accessing the property'; + var result = isFunction ? 'This is a no-op function' : 'This is set to null'; + warn(action, result); + return getVal; + } + + function warn(action, result) { + { + error("This synthetic event is reused for performance reasons. If you're seeing this, " + "you're %s `%s` on a released/nullified synthetic event. %s. " + 'If you must keep the original synthetic event around, use event.persist(). ' + 'See https://react.dev/link/event-pooling for more information.', action, propName, result); } + } - /** - * `touchHistory` isn't actually on the native event, but putting it in the - * interface will ensure that it is cleaned up when pooled/destroyed. The - * `ResponderEventPlugin` will populate it appropriately. - */ + var isFunction = typeof getVal === 'function'; + return { + configurable: true, + set: set, + get: get + }; +} - var ResponderSyntheticEvent = SyntheticEvent.extend({ - touchHistory: function (nativeEvent) { - return null; // Actually doesn't even look at the native event. - } - }); +function createOrGetPooledEvent(dispatchConfig, targetInst, nativeEvent, nativeInst) { + var EventConstructor = this; - var TOP_TOUCH_START = "topTouchStart"; - var TOP_TOUCH_MOVE = "topTouchMove"; - var TOP_TOUCH_END = "topTouchEnd"; - var TOP_TOUCH_CANCEL = "topTouchCancel"; - var TOP_SCROLL = "topScroll"; - var TOP_SELECTION_CHANGE = "topSelectionChange"; - function isStartish(topLevelType) { - return topLevelType === TOP_TOUCH_START; - } - function isMoveish(topLevelType) { - return topLevelType === TOP_TOUCH_MOVE; - } - function isEndish(topLevelType) { - return ( - topLevelType === TOP_TOUCH_END || topLevelType === TOP_TOUCH_CANCEL - ); - } - var startDependencies = [TOP_TOUCH_START]; - var moveDependencies = [TOP_TOUCH_MOVE]; - var endDependencies = [TOP_TOUCH_CANCEL, TOP_TOUCH_END]; + if (EventConstructor.eventPool.length) { + var instance = EventConstructor.eventPool.pop(); + EventConstructor.call(instance, dispatchConfig, targetInst, nativeEvent, nativeInst); + return instance; + } - /** - * Tracks the position and time of each active touch by `touch.identifier`. We - * should typically only see IDs in the range of 1-20 because IDs get recycled - * when touches end and start again. - */ + return new EventConstructor(dispatchConfig, targetInst, nativeEvent, nativeInst); +} - var MAX_TOUCH_BANK = 20; - var touchBank = []; - var touchHistory = { - touchBank: touchBank, - numberActiveTouches: 0, - // If there is only one active touch, we remember its location. This prevents - // us having to loop through all of the touches all the time in the most - // common case. - indexOfSingleActiveTouch: -1, - mostRecentTimeStamp: 0 - }; +function releasePooledEvent(event) { + var EventConstructor = this; - function timestampForTouch(touch) { - // The legacy internal implementation provides "timeStamp", which has been - // renamed to "timestamp". Let both work for now while we iron it out - // TODO (evv): rename timeStamp to timestamp in internal code - return touch.timeStamp || touch.timestamp; - } - /** - * TODO: Instead of making gestures recompute filtered velocity, we could - * include a built in velocity computation that can be reused globally. - */ + if (!(event instanceof EventConstructor)) { + throw new Error('Trying to release an event instance into a pool of a different type.'); + } - function createTouchRecord(touch) { - return { - touchActive: true, - startPageX: touch.pageX, - startPageY: touch.pageY, - startTimeStamp: timestampForTouch(touch), - currentPageX: touch.pageX, - currentPageY: touch.pageY, - currentTimeStamp: timestampForTouch(touch), - previousPageX: touch.pageX, - previousPageY: touch.pageY, - previousTimeStamp: timestampForTouch(touch) - }; - } + event.destructor(); - function resetTouchRecord(touchRecord, touch) { - touchRecord.touchActive = true; - touchRecord.startPageX = touch.pageX; - touchRecord.startPageY = touch.pageY; - touchRecord.startTimeStamp = timestampForTouch(touch); - touchRecord.currentPageX = touch.pageX; - touchRecord.currentPageY = touch.pageY; - touchRecord.currentTimeStamp = timestampForTouch(touch); - touchRecord.previousPageX = touch.pageX; - touchRecord.previousPageY = touch.pageY; - touchRecord.previousTimeStamp = timestampForTouch(touch); - } + if (EventConstructor.eventPool.length < EVENT_POOL_SIZE) { + EventConstructor.eventPool.push(event); + } +} - function getTouchIdentifier(_ref) { - var identifier = _ref.identifier; +function addEventPoolingTo(EventConstructor) { + EventConstructor.getPooled = createOrGetPooledEvent; + EventConstructor.eventPool = []; + EventConstructor.release = releasePooledEvent; +} - if (identifier == null) { - throw new Error("Touch object is missing identifier."); - } +/** + * `touchHistory` isn't actually on the native event, but putting it in the + * interface will ensure that it is cleaned up when pooled/destroyed. The + * `ResponderEventPlugin` will populate it appropriately. + */ - { - if (identifier > MAX_TOUCH_BANK) { - error( - "Touch identifier %s is greater than maximum supported %s which causes " + - "performance issues backfilling array locations for all of the indices.", - identifier, - MAX_TOUCH_BANK - ); - } - } +var ResponderSyntheticEvent = SyntheticEvent.extend({ + touchHistory: function (nativeEvent) { + return null; // Actually doesn't even look at the native event. + } +}); + +var TOP_TOUCH_START = 'topTouchStart'; +var TOP_TOUCH_MOVE = 'topTouchMove'; +var TOP_TOUCH_END = 'topTouchEnd'; +var TOP_TOUCH_CANCEL = 'topTouchCancel'; +var TOP_SCROLL = 'topScroll'; +var TOP_SELECTION_CHANGE = 'topSelectionChange'; +function isStartish(topLevelType) { + return topLevelType === TOP_TOUCH_START; +} +function isMoveish(topLevelType) { + return topLevelType === TOP_TOUCH_MOVE; +} +function isEndish(topLevelType) { + return topLevelType === TOP_TOUCH_END || topLevelType === TOP_TOUCH_CANCEL; +} +var startDependencies = [TOP_TOUCH_START]; +var moveDependencies = [TOP_TOUCH_MOVE]; +var endDependencies = [TOP_TOUCH_CANCEL, TOP_TOUCH_END]; - return identifier; - } +/** + * Tracks the position and time of each active touch by `touch.identifier`. We + * should typically only see IDs in the range of 1-20 because IDs get recycled + * when touches end and start again. + */ - function recordTouchStart(touch) { - var identifier = getTouchIdentifier(touch); - var touchRecord = touchBank[identifier]; +var MAX_TOUCH_BANK = 20; +var touchBank = []; +var touchHistory = { + touchBank: touchBank, + numberActiveTouches: 0, + // If there is only one active touch, we remember its location. This prevents + // us having to loop through all of the touches all the time in the most + // common case. + indexOfSingleActiveTouch: -1, + mostRecentTimeStamp: 0 +}; + +function timestampForTouch(touch) { + // The legacy internal implementation provides "timeStamp", which has been + // renamed to "timestamp". Let both work for now while we iron it out + // TODO (evv): rename timeStamp to timestamp in internal code + return touch.timeStamp || touch.timestamp; +} +/** + * TODO: Instead of making gestures recompute filtered velocity, we could + * include a built in velocity computation that can be reused globally. + */ - if (touchRecord) { - resetTouchRecord(touchRecord, touch); - } else { - touchBank[identifier] = createTouchRecord(touch); - } - touchHistory.mostRecentTimeStamp = timestampForTouch(touch); - } +function createTouchRecord(touch) { + return { + touchActive: true, + startPageX: touch.pageX, + startPageY: touch.pageY, + startTimeStamp: timestampForTouch(touch), + currentPageX: touch.pageX, + currentPageY: touch.pageY, + currentTimeStamp: timestampForTouch(touch), + previousPageX: touch.pageX, + previousPageY: touch.pageY, + previousTimeStamp: timestampForTouch(touch) + }; +} - function recordTouchMove(touch) { - var touchRecord = touchBank[getTouchIdentifier(touch)]; +function resetTouchRecord(touchRecord, touch) { + touchRecord.touchActive = true; + touchRecord.startPageX = touch.pageX; + touchRecord.startPageY = touch.pageY; + touchRecord.startTimeStamp = timestampForTouch(touch); + touchRecord.currentPageX = touch.pageX; + touchRecord.currentPageY = touch.pageY; + touchRecord.currentTimeStamp = timestampForTouch(touch); + touchRecord.previousPageX = touch.pageX; + touchRecord.previousPageY = touch.pageY; + touchRecord.previousTimeStamp = timestampForTouch(touch); +} - if (touchRecord) { - touchRecord.touchActive = true; - touchRecord.previousPageX = touchRecord.currentPageX; - touchRecord.previousPageY = touchRecord.currentPageY; - touchRecord.previousTimeStamp = touchRecord.currentTimeStamp; - touchRecord.currentPageX = touch.pageX; - touchRecord.currentPageY = touch.pageY; - touchRecord.currentTimeStamp = timestampForTouch(touch); - touchHistory.mostRecentTimeStamp = timestampForTouch(touch); - } else { - { - warn( - "Cannot record touch move without a touch start.\n" + - "Touch Move: %s\n" + - "Touch Bank: %s", - printTouch(touch), - printTouchBank() - ); - } - } - } +function getTouchIdentifier(_ref) { + var identifier = _ref.identifier; - function recordTouchEnd(touch) { - var touchRecord = touchBank[getTouchIdentifier(touch)]; + if (identifier == null) { + throw new Error('Touch object is missing identifier.'); + } - if (touchRecord) { - touchRecord.touchActive = false; - touchRecord.previousPageX = touchRecord.currentPageX; - touchRecord.previousPageY = touchRecord.currentPageY; - touchRecord.previousTimeStamp = touchRecord.currentTimeStamp; - touchRecord.currentPageX = touch.pageX; - touchRecord.currentPageY = touch.pageY; - touchRecord.currentTimeStamp = timestampForTouch(touch); - touchHistory.mostRecentTimeStamp = timestampForTouch(touch); - } else { - { - warn( - "Cannot record touch end without a touch start.\n" + - "Touch End: %s\n" + - "Touch Bank: %s", - printTouch(touch), - printTouchBank() - ); - } - } + { + if (identifier > MAX_TOUCH_BANK) { + error('Touch identifier %s is greater than maximum supported %s which causes ' + 'performance issues backfilling array locations for all of the indices.', identifier, MAX_TOUCH_BANK); } + } - function printTouch(touch) { - return JSON.stringify({ - identifier: touch.identifier, - pageX: touch.pageX, - pageY: touch.pageY, - timestamp: timestampForTouch(touch) - }); - } + return identifier; +} - function printTouchBank() { - var printed = JSON.stringify(touchBank.slice(0, MAX_TOUCH_BANK)); +function recordTouchStart(touch) { + var identifier = getTouchIdentifier(touch); + var touchRecord = touchBank[identifier]; - if (touchBank.length > MAX_TOUCH_BANK) { - printed += " (original size: " + touchBank.length + ")"; - } + if (touchRecord) { + resetTouchRecord(touchRecord, touch); + } else { + touchBank[identifier] = createTouchRecord(touch); + } - return printed; - } + touchHistory.mostRecentTimeStamp = timestampForTouch(touch); +} - var instrumentationCallback; - var ResponderTouchHistoryStore = { - /** - * Registers a listener which can be used to instrument every touch event. - */ - instrument: function (callback) { - instrumentationCallback = callback; - }, - recordTouchTrack: function (topLevelType, nativeEvent) { - if (instrumentationCallback != null) { - instrumentationCallback(topLevelType, nativeEvent); - } +function recordTouchMove(touch) { + var touchRecord = touchBank[getTouchIdentifier(touch)]; + + if (touchRecord) { + touchRecord.touchActive = true; + touchRecord.previousPageX = touchRecord.currentPageX; + touchRecord.previousPageY = touchRecord.currentPageY; + touchRecord.previousTimeStamp = touchRecord.currentTimeStamp; + touchRecord.currentPageX = touch.pageX; + touchRecord.currentPageY = touch.pageY; + touchRecord.currentTimeStamp = timestampForTouch(touch); + touchHistory.mostRecentTimeStamp = timestampForTouch(touch); + } else { + { + warn('Cannot record touch move without a touch start.\n' + 'Touch Move: %s\n' + 'Touch Bank: %s', printTouch(touch), printTouchBank()); + } + } +} - if (isMoveish(topLevelType)) { - nativeEvent.changedTouches.forEach(recordTouchMove); - } else if (isStartish(topLevelType)) { - nativeEvent.changedTouches.forEach(recordTouchStart); - touchHistory.numberActiveTouches = nativeEvent.touches.length; +function recordTouchEnd(touch) { + var touchRecord = touchBank[getTouchIdentifier(touch)]; + + if (touchRecord) { + touchRecord.touchActive = false; + touchRecord.previousPageX = touchRecord.currentPageX; + touchRecord.previousPageY = touchRecord.currentPageY; + touchRecord.previousTimeStamp = touchRecord.currentTimeStamp; + touchRecord.currentPageX = touch.pageX; + touchRecord.currentPageY = touch.pageY; + touchRecord.currentTimeStamp = timestampForTouch(touch); + touchHistory.mostRecentTimeStamp = timestampForTouch(touch); + } else { + { + warn('Cannot record touch end without a touch start.\n' + 'Touch End: %s\n' + 'Touch Bank: %s', printTouch(touch), printTouchBank()); + } + } +} - if (touchHistory.numberActiveTouches === 1) { - touchHistory.indexOfSingleActiveTouch = - nativeEvent.touches[0].identifier; - } - } else if (isEndish(topLevelType)) { - nativeEvent.changedTouches.forEach(recordTouchEnd); - touchHistory.numberActiveTouches = nativeEvent.touches.length; +function printTouch(touch) { + return JSON.stringify({ + identifier: touch.identifier, + pageX: touch.pageX, + pageY: touch.pageY, + timestamp: timestampForTouch(touch) + }); +} - if (touchHistory.numberActiveTouches === 1) { - for (var i = 0; i < touchBank.length; i++) { - var touchTrackToCheck = touchBank[i]; +function printTouchBank() { + var printed = JSON.stringify(touchBank.slice(0, MAX_TOUCH_BANK)); - if (touchTrackToCheck != null && touchTrackToCheck.touchActive) { - touchHistory.indexOfSingleActiveTouch = i; - break; - } - } + if (touchBank.length > MAX_TOUCH_BANK) { + printed += ' (original size: ' + touchBank.length + ')'; + } - { - var activeRecord = - touchBank[touchHistory.indexOfSingleActiveTouch]; + return printed; +} - if (activeRecord == null || !activeRecord.touchActive) { - error("Cannot find single active touch."); - } - } +var instrumentationCallback; +var ResponderTouchHistoryStore = { + /** + * Registers a listener which can be used to instrument every touch event. + */ + instrument: function (callback) { + instrumentationCallback = callback; + }, + recordTouchTrack: function (topLevelType, nativeEvent) { + if (instrumentationCallback != null) { + instrumentationCallback(topLevelType, nativeEvent); + } + + if (isMoveish(topLevelType)) { + nativeEvent.changedTouches.forEach(recordTouchMove); + } else if (isStartish(topLevelType)) { + nativeEvent.changedTouches.forEach(recordTouchStart); + touchHistory.numberActiveTouches = nativeEvent.touches.length; + + if (touchHistory.numberActiveTouches === 1) { + touchHistory.indexOfSingleActiveTouch = nativeEvent.touches[0].identifier; + } + } else if (isEndish(topLevelType)) { + nativeEvent.changedTouches.forEach(recordTouchEnd); + touchHistory.numberActiveTouches = nativeEvent.touches.length; + + if (touchHistory.numberActiveTouches === 1) { + for (var i = 0; i < touchBank.length; i++) { + var touchTrackToCheck = touchBank[i]; + + if (touchTrackToCheck != null && touchTrackToCheck.touchActive) { + touchHistory.indexOfSingleActiveTouch = i; + break; } } - }, - touchHistory: touchHistory - }; - /** - * Accumulates items that must not be null or undefined. - * - * This is used to conserve memory by avoiding array allocations. - * - * @return {*|array<*>} An accumulation of items. - */ + { + var activeRecord = touchBank[touchHistory.indexOfSingleActiveTouch]; - function accumulate(current, next) { - if (next == null) { - throw new Error("Accumulated items must not be null or undefined."); + if (activeRecord == null || !activeRecord.touchActive) { + error('Cannot find single active touch.'); + } + } } + } + }, + touchHistory: touchHistory +}; - if (current == null) { - return next; - } // Both are not empty. Warning: Never call x.concat(y) when you are not - // certain that x is an Array (x could be a string with concat method). - - if (isArray(current)) { - /* $FlowFixMe[incompatible-return] if `current` is `T` and `T` an array, - * `isArray` might refine to the array element type of `T` */ - return current.concat(next); - } +/** + * Accumulates items that must not be null or undefined. + * + * This is used to conserve memory by avoiding array allocations. + * + * @return {*|array<*>} An accumulation of items. + */ - if (isArray(next)) { - /* $FlowFixMe[incompatible-return] unsound if `next` is `T` and `T` an array, - * `isArray` might refine to the array element type of `T` */ - return [current].concat(next); - } +function accumulate(current, next) { + if (next == null) { + throw new Error('Accumulated items must not be null or undefined.'); + } - return [current, next]; - } + if (current == null) { + return next; + } // Both are not empty. Warning: Never call x.concat(y) when you are not + // certain that x is an Array (x could be a string with concat method). - /** - * Accumulates items that must not be null or undefined into the first one. This - * is used to conserve memory by avoiding array allocations, and thus sacrifices - * API cleanness. Since `current` can be null before being passed in and not - * null after this function, make sure to assign it back to `current`: - * - * `a = accumulateInto(a, b);` - * - * This API should be sparingly used. Try `accumulate` for something cleaner. - * - * @return {*|array<*>} An accumulation of items. - */ - function accumulateInto(current, next) { - if (next == null) { - throw new Error("Accumulated items must not be null or undefined."); - } + if (isArray(current)) { + /* $FlowFixMe[incompatible-return] if `current` is `T` and `T` an array, + * `isArray` might refine to the array element type of `T` */ + return current.concat(next); + } - if (current == null) { - return next; - } // Both are not empty. Warning: Never call x.concat(y) when you are not - // certain that x is an Array (x could be a string with concat method). + if (isArray(next)) { + /* $FlowFixMe[incompatible-return] unsound if `next` is `T` and `T` an array, + * `isArray` might refine to the array element type of `T` */ + return [current].concat(next); + } - if (isArray(current)) { - if (isArray(next)) { - // $FlowFixMe[prop-missing] `isArray` does not ensure array is mutable - // $FlowFixMe[method-unbinding] - current.push.apply(current, next); - return current; - } // $FlowFixMe[prop-missing] `isArray` does not ensure array is mutable + return [current, next]; +} - current.push(next); - return current; - } +/** + * Accumulates items that must not be null or undefined into the first one. This + * is used to conserve memory by avoiding array allocations, and thus sacrifices + * API cleanness. Since `current` can be null before being passed in and not + * null after this function, make sure to assign it back to `current`: + * + * `a = accumulateInto(a, b);` + * + * This API should be sparingly used. Try `accumulate` for something cleaner. + * + * @return {*|array<*>} An accumulation of items. + */ - if (isArray(next)) { - // A bit too dangerous to mutate `next`. +function accumulateInto(current, next) { + if (next == null) { + throw new Error('Accumulated items must not be null or undefined.'); + } - /* $FlowFixMe[incompatible-return] unsound if `next` is `T` and `T` an array, - * `isArray` might refine to the array element type of `T` */ - return [current].concat(next); - } + if (current == null) { + return next; + } // Both are not empty. Warning: Never call x.concat(y) when you are not + // certain that x is an Array (x could be a string with concat method). - return [current, next]; - } - /** - * @param {array} arr an "accumulation" of items which is either an Array or - * a single item. Useful when paired with the `accumulate` module. This is a - * simple utility that allows us to reason about a collection of items, but - * handling the case when there is exactly one item (and we do not need to - * allocate an array). - * @param {function} cb Callback invoked with each element or a collection. - * @param {?} [scope] Scope used as `this` in a callback. - */ - function forEachAccumulated(arr, cb, scope) { - if (Array.isArray(arr)) { - // $FlowFixMe[incompatible-call] if `T` is an array, `cb` cannot be called - arr.forEach(cb, scope); - } else if (arr) { - cb.call(scope, arr); - } - } - - var FunctionComponent = 0; - var ClassComponent = 1; - var HostRoot = 3; // Root of a host tree. Could be nested inside another node. - - var HostPortal = 4; // A subtree. Could be an entry point to a different renderer. - - var HostComponent = 5; - var HostText = 6; - var Fragment = 7; - var Mode = 8; - var ContextConsumer = 9; - var ContextProvider = 10; - var ForwardRef = 11; - var Profiler = 12; - var SuspenseComponent = 13; - var MemoComponent = 14; - var SimpleMemoComponent = 15; - var LazyComponent = 16; - var IncompleteClassComponent = 17; - var DehydratedFragment = 18; - var SuspenseListComponent = 19; - var ScopeComponent = 21; - var OffscreenComponent = 22; - var LegacyHiddenComponent = 23; - var CacheComponent = 24; - var TracingMarkerComponent = 25; - var HostHoistable = 26; - var HostSingleton = 27; - var IncompleteFunctionComponent = 28; + if (isArray(current)) { + if (isArray(next)) { + // $FlowFixMe[prop-missing] `isArray` does not ensure array is mutable + // $FlowFixMe[method-unbinding] + current.push.apply(current, next); + return current; + } // $FlowFixMe[prop-missing] `isArray` does not ensure array is mutable - /** - * Instance of element that should respond to touch/move types of interactions, - * as indicated explicitly by relevant callbacks. - */ - var responderInst = null; - /** - * Count of current touches. A textInput should become responder iff the - * selection changes while there is a touch on the screen. - */ + current.push(next); + return current; + } - var trackedTouchCount = 0; - - function changeResponder(nextResponderInst, blockHostResponder) { - var oldResponderInst = responderInst; - responderInst = nextResponderInst; - - if (ResponderEventPlugin.GlobalResponderHandler !== null) { - ResponderEventPlugin.GlobalResponderHandler.onChange( - oldResponderInst, - nextResponderInst, - blockHostResponder - ); - } - } - - var eventTypes = { - /** - * On a `touchStart`/`mouseDown`, is it desired that this element become the - * responder? - */ - startShouldSetResponder: { - phasedRegistrationNames: { - bubbled: "onStartShouldSetResponder", - captured: "onStartShouldSetResponderCapture" - }, - dependencies: startDependencies - }, - - /** - * On a `scroll`, is it desired that this element become the responder? This - * is usually not needed, but should be used to retroactively infer that a - * `touchStart` had occurred during momentum scroll. During a momentum scroll, - * a touch start will be immediately followed by a scroll event if the view is - * currently scrolling. - * - * TODO: This shouldn't bubble. - */ - scrollShouldSetResponder: { - phasedRegistrationNames: { - bubbled: "onScrollShouldSetResponder", - captured: "onScrollShouldSetResponderCapture" - }, - dependencies: [TOP_SCROLL] - }, - - /** - * On text selection change, should this element become the responder? This - * is needed for text inputs or other views with native selection, so the - * JS view can claim the responder. - * - * TODO: This shouldn't bubble. - */ - selectionChangeShouldSetResponder: { - phasedRegistrationNames: { - bubbled: "onSelectionChangeShouldSetResponder", - captured: "onSelectionChangeShouldSetResponderCapture" - }, - dependencies: [TOP_SELECTION_CHANGE] - }, - - /** - * On a `touchMove`/`mouseMove`, is it desired that this element become the - * responder? - */ - moveShouldSetResponder: { - phasedRegistrationNames: { - bubbled: "onMoveShouldSetResponder", - captured: "onMoveShouldSetResponderCapture" - }, - dependencies: moveDependencies - }, - - /** - * Direct responder events dispatched directly to responder. Do not bubble. - */ - responderStart: { - registrationName: "onResponderStart", - dependencies: startDependencies - }, - responderMove: { - registrationName: "onResponderMove", - dependencies: moveDependencies - }, - responderEnd: { - registrationName: "onResponderEnd", - dependencies: endDependencies - }, - responderRelease: { - registrationName: "onResponderRelease", - dependencies: endDependencies - }, - responderTerminationRequest: { - registrationName: "onResponderTerminationRequest", - dependencies: [] - }, - responderGrant: { - registrationName: "onResponderGrant", - dependencies: [] - }, - responderReject: { - registrationName: "onResponderReject", - dependencies: [] - }, - responderTerminate: { - registrationName: "onResponderTerminate", - dependencies: [] - } - }; // Start of inline: the below functions were inlined from - // EventPropagator.js, as they deviated from ReactDOM's newer - // implementations. - - function getParent$1(inst) { - do { - inst = inst.return; // TODO: If this is a HostRoot we might want to bail out. - // That is depending on if we want nested subtrees (layers) to bubble - // events to their parent. We could also go through parentNode on the - // host node but that wouldn't work for React Native and doesn't let us - // do the portal feature. - } while (inst && inst.tag !== HostComponent); + if (isArray(next)) { + // A bit too dangerous to mutate `next`. - if (inst) { - return inst; - } + /* $FlowFixMe[incompatible-return] unsound if `next` is `T` and `T` an array, + * `isArray` might refine to the array element type of `T` */ + return [current].concat(next); + } - return null; - } - /** - * Return the lowest common ancestor of A and B, or null if they are in - * different trees. - */ + return [current, next]; +} - function getLowestCommonAncestor(instA, instB) { - var depthA = 0; +/** + * @param {array} arr an "accumulation" of items which is either an Array or + * a single item. Useful when paired with the `accumulate` module. This is a + * simple utility that allows us to reason about a collection of items, but + * handling the case when there is exactly one item (and we do not need to + * allocate an array). + * @param {function} cb Callback invoked with each element or a collection. + * @param {?} [scope] Scope used as `this` in a callback. + */ +function forEachAccumulated(arr, cb, scope) { + if (Array.isArray(arr)) { + // $FlowFixMe[incompatible-call] if `T` is an array, `cb` cannot be called + arr.forEach(cb, scope); + } else if (arr) { + cb.call(scope, arr); + } +} - for (var tempA = instA; tempA; tempA = getParent$1(tempA)) { - depthA++; - } +var FunctionComponent = 0; +var ClassComponent = 1; +var HostRoot = 3; // Root of a host tree. Could be nested inside another node. + +var HostPortal = 4; // A subtree. Could be an entry point to a different renderer. + +var HostComponent = 5; +var HostText = 6; +var Fragment = 7; +var Mode = 8; +var ContextConsumer = 9; +var ContextProvider = 10; +var ForwardRef = 11; +var Profiler = 12; +var SuspenseComponent = 13; +var MemoComponent = 14; +var SimpleMemoComponent = 15; +var LazyComponent = 16; +var IncompleteClassComponent = 17; +var DehydratedFragment = 18; +var SuspenseListComponent = 19; +var ScopeComponent = 21; +var OffscreenComponent = 22; +var LegacyHiddenComponent = 23; +var CacheComponent = 24; +var TracingMarkerComponent = 25; +var HostHoistable = 26; +var HostSingleton = 27; +var IncompleteFunctionComponent = 28; - var depthB = 0; +/** + * Instance of element that should respond to touch/move types of interactions, + * as indicated explicitly by relevant callbacks. + */ - for (var tempB = instB; tempB; tempB = getParent$1(tempB)) { - depthB++; - } // If A is deeper, crawl up. +var responderInst = null; +/** + * Count of current touches. A textInput should become responder iff the + * selection changes while there is a touch on the screen. + */ - while (depthA - depthB > 0) { - instA = getParent$1(instA); - depthA--; - } // If B is deeper, crawl up. +var trackedTouchCount = 0; - while (depthB - depthA > 0) { - instB = getParent$1(instB); - depthB--; - } // Walk in lockstep until we find a match. +function changeResponder(nextResponderInst, blockHostResponder) { + var oldResponderInst = responderInst; + responderInst = nextResponderInst; - var depth = depthA; + if (ResponderEventPlugin.GlobalResponderHandler !== null) { + ResponderEventPlugin.GlobalResponderHandler.onChange(oldResponderInst, nextResponderInst, blockHostResponder); + } +} - while (depth--) { - if (instA === instB || instA === instB.alternate) { - return instA; - } +var eventTypes = { + /** + * On a `touchStart`/`mouseDown`, is it desired that this element become the + * responder? + */ + startShouldSetResponder: { + phasedRegistrationNames: { + bubbled: 'onStartShouldSetResponder', + captured: 'onStartShouldSetResponderCapture' + }, + dependencies: startDependencies + }, + + /** + * On a `scroll`, is it desired that this element become the responder? This + * is usually not needed, but should be used to retroactively infer that a + * `touchStart` had occurred during momentum scroll. During a momentum scroll, + * a touch start will be immediately followed by a scroll event if the view is + * currently scrolling. + * + * TODO: This shouldn't bubble. + */ + scrollShouldSetResponder: { + phasedRegistrationNames: { + bubbled: 'onScrollShouldSetResponder', + captured: 'onScrollShouldSetResponderCapture' + }, + dependencies: [TOP_SCROLL] + }, + + /** + * On text selection change, should this element become the responder? This + * is needed for text inputs or other views with native selection, so the + * JS view can claim the responder. + * + * TODO: This shouldn't bubble. + */ + selectionChangeShouldSetResponder: { + phasedRegistrationNames: { + bubbled: 'onSelectionChangeShouldSetResponder', + captured: 'onSelectionChangeShouldSetResponderCapture' + }, + dependencies: [TOP_SELECTION_CHANGE] + }, + + /** + * On a `touchMove`/`mouseMove`, is it desired that this element become the + * responder? + */ + moveShouldSetResponder: { + phasedRegistrationNames: { + bubbled: 'onMoveShouldSetResponder', + captured: 'onMoveShouldSetResponderCapture' + }, + dependencies: moveDependencies + }, + + /** + * Direct responder events dispatched directly to responder. Do not bubble. + */ + responderStart: { + registrationName: 'onResponderStart', + dependencies: startDependencies + }, + responderMove: { + registrationName: 'onResponderMove', + dependencies: moveDependencies + }, + responderEnd: { + registrationName: 'onResponderEnd', + dependencies: endDependencies + }, + responderRelease: { + registrationName: 'onResponderRelease', + dependencies: endDependencies + }, + responderTerminationRequest: { + registrationName: 'onResponderTerminationRequest', + dependencies: [] + }, + responderGrant: { + registrationName: 'onResponderGrant', + dependencies: [] + }, + responderReject: { + registrationName: 'onResponderReject', + dependencies: [] + }, + responderTerminate: { + registrationName: 'onResponderTerminate', + dependencies: [] + } +}; // Start of inline: the below functions were inlined from +// EventPropagator.js, as they deviated from ReactDOM's newer +// implementations. + +function getParent$1(inst) { + do { + inst = inst.return; // TODO: If this is a HostRoot we might want to bail out. + // That is depending on if we want nested subtrees (layers) to bubble + // events to their parent. We could also go through parentNode on the + // host node but that wouldn't work for React Native and doesn't let us + // do the portal feature. + } while (inst && inst.tag !== HostComponent); + + if (inst) { + return inst; + } + + return null; +} +/** + * Return the lowest common ancestor of A and B, or null if they are in + * different trees. + */ - instA = getParent$1(instA); - instB = getParent$1(instB); - } - return null; +function getLowestCommonAncestor(instA, instB) { + var depthA = 0; + + for (var tempA = instA; tempA; tempA = getParent$1(tempA)) { + depthA++; + } + + var depthB = 0; + + for (var tempB = instB; tempB; tempB = getParent$1(tempB)) { + depthB++; + } // If A is deeper, crawl up. + + + while (depthA - depthB > 0) { + instA = getParent$1(instA); + depthA--; + } // If B is deeper, crawl up. + + + while (depthB - depthA > 0) { + instB = getParent$1(instB); + depthB--; + } // Walk in lockstep until we find a match. + + + var depth = depthA; + + while (depth--) { + if (instA === instB || instA === instB.alternate) { + return instA; } - /** - * Return if A is an ancestor of B. - */ - function isAncestor(instA, instB) { - while (instB) { - if (instA === instB || instA === instB.alternate) { - return true; - } + instA = getParent$1(instA); + instB = getParent$1(instB); + } - instB = getParent$1(instB); - } + return null; +} +/** + * Return if A is an ancestor of B. + */ - return false; +function isAncestor(instA, instB) { + while (instB) { + if (instA === instB || instA === instB.alternate) { + return true; } - /** - * Simulates the traversal of a two-phase, capture/bubble event dispatch. - */ - function traverseTwoPhase$1(inst, fn, arg) { - var path = []; + instB = getParent$1(instB); + } - while (inst) { - path.push(inst); - inst = getParent$1(inst); - } + return false; +} +/** + * Simulates the traversal of a two-phase, capture/bubble event dispatch. + */ - var i; - for (i = path.length; i-- > 0; ) { - fn(path[i], "captured", arg); - } +function traverseTwoPhase$1(inst, fn, arg) { + var path = []; - for (i = 0; i < path.length; i++) { - fn(path[i], "bubbled", arg); - } - } + while (inst) { + path.push(inst); + inst = getParent$1(inst); + } - function getListener$1(inst, registrationName) { - var stateNode = inst.stateNode; + var i; - if (stateNode === null) { - // Work in progress (ex: onload events in incremental mode). - return null; - } + for (i = path.length; i-- > 0;) { + fn(path[i], 'captured', arg); + } - var props = getFiberCurrentPropsFromNode$1(stateNode); + for (i = 0; i < path.length; i++) { + fn(path[i], 'bubbled', arg); + } +} - if (props === null) { - // Work in progress. - return null; - } +function getListener$1(inst, registrationName) { + var stateNode = inst.stateNode; - var listener = props[registrationName]; + if (stateNode === null) { + // Work in progress (ex: onload events in incremental mode). + return null; + } - if (listener && typeof listener !== "function") { - throw new Error( - "Expected `" + - registrationName + - "` listener to be a function, instead got a value of `" + - typeof listener + - "` type." - ); - } + var props = getFiberCurrentPropsFromNode$1(stateNode); - return listener; - } + if (props === null) { + // Work in progress. + return null; + } - function listenerAtPhase$1(inst, event, propagationPhase) { - var registrationName = - event.dispatchConfig.phasedRegistrationNames[propagationPhase]; - return getListener$1(inst, registrationName); - } + var listener = props[registrationName]; - function accumulateDirectionalDispatches$1(inst, phase, event) { - { - if (!inst) { - error("Dispatching inst must not be null"); - } - } + if (listener && typeof listener !== 'function') { + throw new Error("Expected `" + registrationName + "` listener to be a function, instead got a value of `" + typeof listener + "` type."); + } + + return listener; +} - var listener = listenerAtPhase$1(inst, event, phase); +function listenerAtPhase$1(inst, event, propagationPhase) { + var registrationName = event.dispatchConfig.phasedRegistrationNames[propagationPhase]; + return getListener$1(inst, registrationName); +} - if (listener) { - event._dispatchListeners = accumulateInto( - event._dispatchListeners, - listener - ); - event._dispatchInstances = accumulateInto( - event._dispatchInstances, - inst - ); - } +function accumulateDirectionalDispatches$1(inst, phase, event) { + { + if (!inst) { + error('Dispatching inst must not be null'); } - /** - * Accumulates without regard to direction, does not look for phased - * registration names. Same as `accumulateDirectDispatchesSingle` but without - * requiring that the `dispatchMarker` be the same as the dispatched ID. - */ + } - function accumulateDispatches$1(inst, ignoredDirection, event) { - if (inst && event && event.dispatchConfig.registrationName) { - var registrationName = event.dispatchConfig.registrationName; - var listener = getListener$1(inst, registrationName); + var listener = listenerAtPhase$1(inst, event, phase); - if (listener) { - event._dispatchListeners = accumulateInto( - event._dispatchListeners, - listener - ); - event._dispatchInstances = accumulateInto( - event._dispatchInstances, - inst - ); - } - } - } - /** - * Accumulates dispatches on an `SyntheticEvent`, but only for the - * `dispatchMarker`. - * @param {SyntheticEvent} event - */ + if (listener) { + event._dispatchListeners = accumulateInto(event._dispatchListeners, listener); + event._dispatchInstances = accumulateInto(event._dispatchInstances, inst); + } +} +/** + * Accumulates without regard to direction, does not look for phased + * registration names. Same as `accumulateDirectDispatchesSingle` but without + * requiring that the `dispatchMarker` be the same as the dispatched ID. + */ - function accumulateDirectDispatchesSingle$1(event) { - if (event && event.dispatchConfig.registrationName) { - accumulateDispatches$1(event._targetInst, null, event); - } - } - function accumulateDirectDispatches$1(events) { - forEachAccumulated(events, accumulateDirectDispatchesSingle$1); - } +function accumulateDispatches$1(inst, ignoredDirection, event) { + if (inst && event && event.dispatchConfig.registrationName) { + var registrationName = event.dispatchConfig.registrationName; + var listener = getListener$1(inst, registrationName); - function accumulateTwoPhaseDispatchesSingleSkipTarget(event) { - if (event && event.dispatchConfig.phasedRegistrationNames) { - var targetInst = event._targetInst; - var parentInst = targetInst ? getParent$1(targetInst) : null; - traverseTwoPhase$1( - parentInst, - accumulateDirectionalDispatches$1, - event - ); - } + if (listener) { + event._dispatchListeners = accumulateInto(event._dispatchListeners, listener); + event._dispatchInstances = accumulateInto(event._dispatchInstances, inst); } + } +} +/** + * Accumulates dispatches on an `SyntheticEvent`, but only for the + * `dispatchMarker`. + * @param {SyntheticEvent} event + */ - function accumulateTwoPhaseDispatchesSkipTarget(events) { - forEachAccumulated(events, accumulateTwoPhaseDispatchesSingleSkipTarget); - } - function accumulateTwoPhaseDispatchesSingle$1(event) { - if (event && event.dispatchConfig.phasedRegistrationNames) { - traverseTwoPhase$1( - event._targetInst, - accumulateDirectionalDispatches$1, - event - ); - } - } +function accumulateDirectDispatchesSingle$1(event) { + if (event && event.dispatchConfig.registrationName) { + accumulateDispatches$1(event._targetInst, null, event); + } +} - function accumulateTwoPhaseDispatches$1(events) { - forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle$1); - } // End of inline +function accumulateDirectDispatches$1(events) { + forEachAccumulated(events, accumulateDirectDispatchesSingle$1); +} - /** - * - * Responder System: - * ---------------- - * - * - A global, solitary "interaction lock" on a view. - * - If a node becomes the responder, it should convey visual feedback - * immediately to indicate so, either by highlighting or moving accordingly. - * - To be the responder means, that touches are exclusively important to that - * responder view, and no other view. - * - While touches are still occurring, the responder lock can be transferred to - * a new view, but only to increasingly "higher" views (meaning ancestors of - * the current responder). - * - * Responder being granted: - * ------------------------ - * - * - Touch starts, moves, and scrolls can cause an ID to become the responder. - * - We capture/bubble `startShouldSetResponder`/`moveShouldSetResponder` to - * the "appropriate place". - * - If nothing is currently the responder, the "appropriate place" is the - * initiating event's `targetID`. - * - If something *is* already the responder, the "appropriate place" is the - * first common ancestor of the event target and the current `responderInst`. - * - Some negotiation happens: See the timing diagram below. - * - Scrolled views automatically become responder. The reasoning is that a - * platform scroll view that isn't built on top of the responder system has - * began scrolling, and the active responder must now be notified that the - * interaction is no longer locked to it - the system has taken over. - * - * - Responder being released: - * As soon as no more touches that *started* inside of descendants of the - * *current* responderInst, an `onResponderRelease` event is dispatched to the - * current responder, and the responder lock is released. - * - * TODO: - * - on "end", a callback hook for `onResponderEndShouldRemainResponder` that - * determines if the responder lock should remain. - * - If a view shouldn't "remain" the responder, any active touches should by - * default be considered "dead" and do not influence future negotiations or - * bubble paths. It should be as if those touches do not exist. - * -- For multitouch: Usually a translate-z will choose to "remain" responder - * after one out of many touches ended. For translate-y, usually the view - * doesn't wish to "remain" responder after one of many touches end. - * - Consider building this on top of a `stopPropagation` model similar to - * `W3C` events. - * - Ensure that `onResponderTerminate` is called on touch cancels, whether or - * not `onResponderTerminationRequest` returns `true` or `false`. - * - */ +function accumulateTwoPhaseDispatchesSingleSkipTarget(event) { + if (event && event.dispatchConfig.phasedRegistrationNames) { + var targetInst = event._targetInst; + var parentInst = targetInst ? getParent$1(targetInst) : null; + traverseTwoPhase$1(parentInst, accumulateDirectionalDispatches$1, event); + } +} + +function accumulateTwoPhaseDispatchesSkipTarget(events) { + forEachAccumulated(events, accumulateTwoPhaseDispatchesSingleSkipTarget); +} + +function accumulateTwoPhaseDispatchesSingle$1(event) { + if (event && event.dispatchConfig.phasedRegistrationNames) { + traverseTwoPhase$1(event._targetInst, accumulateDirectionalDispatches$1, event); + } +} + +function accumulateTwoPhaseDispatches$1(events) { + forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle$1); +} // End of inline + +/** + * + * Responder System: + * ---------------- + * + * - A global, solitary "interaction lock" on a view. + * - If a node becomes the responder, it should convey visual feedback + * immediately to indicate so, either by highlighting or moving accordingly. + * - To be the responder means, that touches are exclusively important to that + * responder view, and no other view. + * - While touches are still occurring, the responder lock can be transferred to + * a new view, but only to increasingly "higher" views (meaning ancestors of + * the current responder). + * + * Responder being granted: + * ------------------------ + * + * - Touch starts, moves, and scrolls can cause an ID to become the responder. + * - We capture/bubble `startShouldSetResponder`/`moveShouldSetResponder` to + * the "appropriate place". + * - If nothing is currently the responder, the "appropriate place" is the + * initiating event's `targetID`. + * - If something *is* already the responder, the "appropriate place" is the + * first common ancestor of the event target and the current `responderInst`. + * - Some negotiation happens: See the timing diagram below. + * - Scrolled views automatically become responder. The reasoning is that a + * platform scroll view that isn't built on top of the responder system has + * began scrolling, and the active responder must now be notified that the + * interaction is no longer locked to it - the system has taken over. + * + * - Responder being released: + * As soon as no more touches that *started* inside of descendants of the + * *current* responderInst, an `onResponderRelease` event is dispatched to the + * current responder, and the responder lock is released. + * + * TODO: + * - on "end", a callback hook for `onResponderEndShouldRemainResponder` that + * determines if the responder lock should remain. + * - If a view shouldn't "remain" the responder, any active touches should by + * default be considered "dead" and do not influence future negotiations or + * bubble paths. It should be as if those touches do not exist. + * -- For multitouch: Usually a translate-z will choose to "remain" responder + * after one out of many touches ended. For translate-y, usually the view + * doesn't wish to "remain" responder after one of many touches end. + * - Consider building this on top of a `stopPropagation` model similar to + * `W3C` events. + * - Ensure that `onResponderTerminate` is called on touch cancels, whether or + * not `onResponderTerminationRequest` returns `true` or `false`. + * + */ - /* Negotiation Performed +/* Negotiation Performed +-----------------------+ / \ Process low level events to + Current Responder + wantsResponderID @@ -1490,8508 +1352,8198 @@ to return true:wantsResponderID| | | | + + */ - /** - * A note about event ordering in the `EventPluginRegistry`. - * - * Suppose plugins are injected in the following order: - * - * `[R, S, C]` - * - * To help illustrate the example, assume `S` is `SimpleEventPlugin` (for - * `onClick` etc) and `R` is `ResponderEventPlugin`. - * - * "Deferred-Dispatched Events": - * - * - The current event plugin system will traverse the list of injected plugins, - * in order, and extract events by collecting the plugin's return value of - * `extractEvents()`. - * - These events that are returned from `extractEvents` are "deferred - * dispatched events". - * - When returned from `extractEvents`, deferred-dispatched events contain an - * "accumulation" of deferred dispatches. - * - These deferred dispatches are accumulated/collected before they are - * returned, but processed at a later time by the `EventPluginRegistry` (hence the - * name deferred). - * - * In the process of returning their deferred-dispatched events, event plugins - * themselves can dispatch events on-demand without returning them from - * `extractEvents`. Plugins might want to do this, so that they can use event - * dispatching as a tool that helps them decide which events should be extracted - * in the first place. - * - * "On-Demand-Dispatched Events": - * - * - On-demand-dispatched events are not returned from `extractEvents`. - * - On-demand-dispatched events are dispatched during the process of returning - * the deferred-dispatched events. - * - They should not have side effects. - * - They should be avoided, and/or eventually be replaced with another - * abstraction that allows event plugins to perform multiple "rounds" of event - * extraction. - * - * Therefore, the sequence of event dispatches becomes: - * - * - `R`s on-demand events (if any) (dispatched by `R` on-demand) - * - `S`s on-demand events (if any) (dispatched by `S` on-demand) - * - `C`s on-demand events (if any) (dispatched by `C` on-demand) - * - `R`s extracted events (if any) (dispatched by `EventPluginRegistry`) - * - `S`s extracted events (if any) (dispatched by `EventPluginRegistry`) - * - `C`s extracted events (if any) (dispatched by `EventPluginRegistry`) - * - * In the case of `ResponderEventPlugin`: If the `startShouldSetResponder` - * on-demand dispatch returns `true` (and some other details are satisfied) the - * `onResponderGrant` deferred dispatched event is returned from - * `extractEvents`. The sequence of dispatch executions in this case - * will appear as follows: - * - * - `startShouldSetResponder` (`ResponderEventPlugin` dispatches on-demand) - * - `touchStartCapture` (`EventPluginRegistry` dispatches as usual) - * - `touchStart` (`EventPluginRegistry` dispatches as usual) - * - `responderGrant/Reject` (`EventPluginRegistry` dispatches as usual) - */ - - function setResponderAndExtractTransfer( - topLevelType, - targetInst, - nativeEvent, - nativeEventTarget - ) { - var shouldSetEventType = isStartish(topLevelType) - ? eventTypes.startShouldSetResponder - : isMoveish(topLevelType) - ? eventTypes.moveShouldSetResponder - : topLevelType === TOP_SELECTION_CHANGE - ? eventTypes.selectionChangeShouldSetResponder - : eventTypes.scrollShouldSetResponder; // TODO: stop one short of the current responder. - - var bubbleShouldSetFrom = !responderInst - ? targetInst - : getLowestCommonAncestor(responderInst, targetInst); // When capturing/bubbling the "shouldSet" event, we want to skip the target - // (deepest ID) if it happens to be the current responder. The reasoning: - // It's strange to get an `onMoveShouldSetResponder` when you're *already* - // the responder. - - var skipOverBubbleShouldSetFrom = bubbleShouldSetFrom === responderInst; - var shouldSetEvent = ResponderSyntheticEvent.getPooled( - shouldSetEventType, - bubbleShouldSetFrom, - nativeEvent, - nativeEventTarget - ); - shouldSetEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; - - if (skipOverBubbleShouldSetFrom) { - accumulateTwoPhaseDispatchesSkipTarget(shouldSetEvent); - } else { - accumulateTwoPhaseDispatches$1(shouldSetEvent); - } - - var wantsResponderInst = - executeDispatchesInOrderStopAtTrue(shouldSetEvent); +/** + * A note about event ordering in the `EventPluginRegistry`. + * + * Suppose plugins are injected in the following order: + * + * `[R, S, C]` + * + * To help illustrate the example, assume `S` is `SimpleEventPlugin` (for + * `onClick` etc) and `R` is `ResponderEventPlugin`. + * + * "Deferred-Dispatched Events": + * + * - The current event plugin system will traverse the list of injected plugins, + * in order, and extract events by collecting the plugin's return value of + * `extractEvents()`. + * - These events that are returned from `extractEvents` are "deferred + * dispatched events". + * - When returned from `extractEvents`, deferred-dispatched events contain an + * "accumulation" of deferred dispatches. + * - These deferred dispatches are accumulated/collected before they are + * returned, but processed at a later time by the `EventPluginRegistry` (hence the + * name deferred). + * + * In the process of returning their deferred-dispatched events, event plugins + * themselves can dispatch events on-demand without returning them from + * `extractEvents`. Plugins might want to do this, so that they can use event + * dispatching as a tool that helps them decide which events should be extracted + * in the first place. + * + * "On-Demand-Dispatched Events": + * + * - On-demand-dispatched events are not returned from `extractEvents`. + * - On-demand-dispatched events are dispatched during the process of returning + * the deferred-dispatched events. + * - They should not have side effects. + * - They should be avoided, and/or eventually be replaced with another + * abstraction that allows event plugins to perform multiple "rounds" of event + * extraction. + * + * Therefore, the sequence of event dispatches becomes: + * + * - `R`s on-demand events (if any) (dispatched by `R` on-demand) + * - `S`s on-demand events (if any) (dispatched by `S` on-demand) + * - `C`s on-demand events (if any) (dispatched by `C` on-demand) + * - `R`s extracted events (if any) (dispatched by `EventPluginRegistry`) + * - `S`s extracted events (if any) (dispatched by `EventPluginRegistry`) + * - `C`s extracted events (if any) (dispatched by `EventPluginRegistry`) + * + * In the case of `ResponderEventPlugin`: If the `startShouldSetResponder` + * on-demand dispatch returns `true` (and some other details are satisfied) the + * `onResponderGrant` deferred dispatched event is returned from + * `extractEvents`. The sequence of dispatch executions in this case + * will appear as follows: + * + * - `startShouldSetResponder` (`ResponderEventPlugin` dispatches on-demand) + * - `touchStartCapture` (`EventPluginRegistry` dispatches as usual) + * - `touchStart` (`EventPluginRegistry` dispatches as usual) + * - `responderGrant/Reject` (`EventPluginRegistry` dispatches as usual) + */ - if (!shouldSetEvent.isPersistent()) { - shouldSetEvent.constructor.release(shouldSetEvent); - } - if (!wantsResponderInst || wantsResponderInst === responderInst) { - return null; - } +function setResponderAndExtractTransfer(topLevelType, targetInst, nativeEvent, nativeEventTarget) { + var shouldSetEventType = isStartish(topLevelType) ? eventTypes.startShouldSetResponder : isMoveish(topLevelType) ? eventTypes.moveShouldSetResponder : topLevelType === TOP_SELECTION_CHANGE ? eventTypes.selectionChangeShouldSetResponder : eventTypes.scrollShouldSetResponder; // TODO: stop one short of the current responder. + + var bubbleShouldSetFrom = !responderInst ? targetInst : getLowestCommonAncestor(responderInst, targetInst); // When capturing/bubbling the "shouldSet" event, we want to skip the target + // (deepest ID) if it happens to be the current responder. The reasoning: + // It's strange to get an `onMoveShouldSetResponder` when you're *already* + // the responder. + + var skipOverBubbleShouldSetFrom = bubbleShouldSetFrom === responderInst; + var shouldSetEvent = ResponderSyntheticEvent.getPooled(shouldSetEventType, bubbleShouldSetFrom, nativeEvent, nativeEventTarget); + shouldSetEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + + if (skipOverBubbleShouldSetFrom) { + accumulateTwoPhaseDispatchesSkipTarget(shouldSetEvent); + } else { + accumulateTwoPhaseDispatches$1(shouldSetEvent); + } + + var wantsResponderInst = executeDispatchesInOrderStopAtTrue(shouldSetEvent); + + if (!shouldSetEvent.isPersistent()) { + shouldSetEvent.constructor.release(shouldSetEvent); + } + + if (!wantsResponderInst || wantsResponderInst === responderInst) { + return null; + } + + var extracted; + var grantEvent = ResponderSyntheticEvent.getPooled(eventTypes.responderGrant, wantsResponderInst, nativeEvent, nativeEventTarget); + grantEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches$1(grantEvent); + var blockHostResponder = executeDirectDispatch(grantEvent) === true; + + if (responderInst) { + var terminationRequestEvent = ResponderSyntheticEvent.getPooled(eventTypes.responderTerminationRequest, responderInst, nativeEvent, nativeEventTarget); + terminationRequestEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches$1(terminationRequestEvent); + var shouldSwitch = !hasDispatches(terminationRequestEvent) || executeDirectDispatch(terminationRequestEvent); + + if (!terminationRequestEvent.isPersistent()) { + terminationRequestEvent.constructor.release(terminationRequestEvent); + } + + if (shouldSwitch) { + var terminateEvent = ResponderSyntheticEvent.getPooled(eventTypes.responderTerminate, responderInst, nativeEvent, nativeEventTarget); + terminateEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches$1(terminateEvent); + extracted = accumulate(extracted, [grantEvent, terminateEvent]); + changeResponder(wantsResponderInst, blockHostResponder); + } else { + var rejectEvent = ResponderSyntheticEvent.getPooled(eventTypes.responderReject, wantsResponderInst, nativeEvent, nativeEventTarget); + rejectEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches$1(rejectEvent); + extracted = accumulate(extracted, rejectEvent); + } + } else { + extracted = accumulate(extracted, grantEvent); + changeResponder(wantsResponderInst, blockHostResponder); + } + + return extracted; +} +/** + * A transfer is a negotiation between a currently set responder and the next + * element to claim responder status. Any start event could trigger a transfer + * of responderInst. Any move event could trigger a transfer. + * + * @param {string} topLevelType Record from `BrowserEventConstants`. + * @return {boolean} True if a transfer of responder could possibly occur. + */ - var extracted; - var grantEvent = ResponderSyntheticEvent.getPooled( - eventTypes.responderGrant, - wantsResponderInst, - nativeEvent, - nativeEventTarget - ); - grantEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; - accumulateDirectDispatches$1(grantEvent); - var blockHostResponder = executeDirectDispatch(grantEvent) === true; - - if (responderInst) { - var terminationRequestEvent = ResponderSyntheticEvent.getPooled( - eventTypes.responderTerminationRequest, - responderInst, - nativeEvent, - nativeEventTarget - ); - terminationRequestEvent.touchHistory = - ResponderTouchHistoryStore.touchHistory; - accumulateDirectDispatches$1(terminationRequestEvent); - var shouldSwitch = - !hasDispatches(terminationRequestEvent) || - executeDirectDispatch(terminationRequestEvent); - - if (!terminationRequestEvent.isPersistent()) { - terminationRequestEvent.constructor.release(terminationRequestEvent); - } - - if (shouldSwitch) { - var terminateEvent = ResponderSyntheticEvent.getPooled( - eventTypes.responderTerminate, - responderInst, - nativeEvent, - nativeEventTarget - ); - terminateEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; - accumulateDirectDispatches$1(terminateEvent); - extracted = accumulate(extracted, [grantEvent, terminateEvent]); - changeResponder(wantsResponderInst, blockHostResponder); - } else { - var rejectEvent = ResponderSyntheticEvent.getPooled( - eventTypes.responderReject, - wantsResponderInst, - nativeEvent, - nativeEventTarget - ); - rejectEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; - accumulateDirectDispatches$1(rejectEvent); - extracted = accumulate(extracted, rejectEvent); - } - } else { - extracted = accumulate(extracted, grantEvent); - changeResponder(wantsResponderInst, blockHostResponder); - } - return extracted; - } - /** - * A transfer is a negotiation between a currently set responder and the next - * element to claim responder status. Any start event could trigger a transfer - * of responderInst. Any move event could trigger a transfer. - * - * @param {string} topLevelType Record from `BrowserEventConstants`. - * @return {boolean} True if a transfer of responder could possibly occur. - */ +function canTriggerTransfer(topLevelType, topLevelInst, nativeEvent) { + return topLevelInst && ( // responderIgnoreScroll: We are trying to migrate away from specifically + // tracking native scroll events here and responderIgnoreScroll indicates we + // will send topTouchCancel to handle canceling touch events instead + topLevelType === TOP_SCROLL && !nativeEvent.responderIgnoreScroll || trackedTouchCount > 0 && topLevelType === TOP_SELECTION_CHANGE || isStartish(topLevelType) || isMoveish(topLevelType)); +} +/** + * Returns whether or not this touch end event makes it such that there are no + * longer any touches that started inside of the current `responderInst`. + * + * @param {NativeEvent} nativeEvent Native touch end event. + * @return {boolean} Whether or not this touch end event ends the responder. + */ - function canTriggerTransfer(topLevelType, topLevelInst, nativeEvent) { - return ( - topLevelInst && // responderIgnoreScroll: We are trying to migrate away from specifically - // tracking native scroll events here and responderIgnoreScroll indicates we - // will send topTouchCancel to handle canceling touch events instead - ((topLevelType === TOP_SCROLL && !nativeEvent.responderIgnoreScroll) || - (trackedTouchCount > 0 && topLevelType === TOP_SELECTION_CHANGE) || - isStartish(topLevelType) || - isMoveish(topLevelType)) - ); - } - /** - * Returns whether or not this touch end event makes it such that there are no - * longer any touches that started inside of the current `responderInst`. - * - * @param {NativeEvent} nativeEvent Native touch end event. - * @return {boolean} Whether or not this touch end event ends the responder. - */ - function noResponderTouches(nativeEvent) { - var touches = nativeEvent.touches; +function noResponderTouches(nativeEvent) { + var touches = nativeEvent.touches; - if (!touches || touches.length === 0) { - return true; - } + if (!touches || touches.length === 0) { + return true; + } - for (var i = 0; i < touches.length; i++) { - var activeTouch = touches[i]; - var target = activeTouch.target; + for (var i = 0; i < touches.length; i++) { + var activeTouch = touches[i]; + var target = activeTouch.target; - if (target !== null && target !== undefined && target !== 0) { - // Is the original touch location inside of the current responder? - var targetInst = getInstanceFromNode(target); + if (target !== null && target !== undefined && target !== 0) { + // Is the original touch location inside of the current responder? + var targetInst = getInstanceFromNode(target); - if (isAncestor(responderInst, targetInst)) { - return false; - } - } + if (isAncestor(responderInst, targetInst)) { + return false; } - - return true; } + } - var ResponderEventPlugin = { - /* For unit testing only */ - _getResponder: function () { - return responderInst; - }, - eventTypes: eventTypes, - - /** - * We must be resilient to `targetInst` being `null` on `touchMove` or - * `touchEnd`. On certain platforms, this means that a native scroll has - * assumed control and the original touch targets are destroyed. - */ - extractEvents: function ( - topLevelType, - targetInst, - nativeEvent, - nativeEventTarget, - eventSystemFlags - ) { - if (isStartish(topLevelType)) { - trackedTouchCount += 1; - } else if (isEndish(topLevelType)) { - if (trackedTouchCount >= 0) { - trackedTouchCount -= 1; - } else { - { - warn( - "Ended a touch event which was not counted in `trackedTouchCount`." - ); - } + return true; +} - return null; - } +var ResponderEventPlugin = { + /* For unit testing only */ + _getResponder: function () { + return responderInst; + }, + eventTypes: eventTypes, + + /** + * We must be resilient to `targetInst` being `null` on `touchMove` or + * `touchEnd`. On certain platforms, this means that a native scroll has + * assumed control and the original touch targets are destroyed. + */ + extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget, eventSystemFlags) { + if (isStartish(topLevelType)) { + trackedTouchCount += 1; + } else if (isEndish(topLevelType)) { + if (trackedTouchCount >= 0) { + trackedTouchCount -= 1; + } else { + { + warn('Ended a touch event which was not counted in `trackedTouchCount`.'); } - ResponderTouchHistoryStore.recordTouchTrack(topLevelType, nativeEvent); - var extracted = canTriggerTransfer( - topLevelType, - targetInst, - nativeEvent - ) - ? setResponderAndExtractTransfer( - topLevelType, - targetInst, - nativeEvent, - nativeEventTarget - ) - : null; // Responder may or may not have transferred on a new touch start/move. - // Regardless, whoever is the responder after any potential transfer, we - // direct all touch start/move/ends to them in the form of - // `onResponderMove/Start/End`. These will be called for *every* additional - // finger that move/start/end, dispatched directly to whoever is the - // current responder at that moment, until the responder is "released". - // - // These multiple individual change touch events are are always bookended - // by `onResponderGrant`, and one of - // (`onResponderRelease/onResponderTerminate`). - - var isResponderTouchStart = responderInst && isStartish(topLevelType); - var isResponderTouchMove = responderInst && isMoveish(topLevelType); - var isResponderTouchEnd = responderInst && isEndish(topLevelType); - var incrementalTouch = isResponderTouchStart - ? eventTypes.responderStart - : isResponderTouchMove - ? eventTypes.responderMove - : isResponderTouchEnd - ? eventTypes.responderEnd - : null; - - if (incrementalTouch) { - var gesture = ResponderSyntheticEvent.getPooled( - incrementalTouch, - responderInst, - nativeEvent, - nativeEventTarget - ); - gesture.touchHistory = ResponderTouchHistoryStore.touchHistory; - accumulateDirectDispatches$1(gesture); - extracted = accumulate(extracted, gesture); - } - - var isResponderTerminate = - responderInst && topLevelType === TOP_TOUCH_CANCEL; - var isResponderRelease = - responderInst && - !isResponderTerminate && - isEndish(topLevelType) && - noResponderTouches(nativeEvent); - var finalTouch = isResponderTerminate - ? eventTypes.responderTerminate - : isResponderRelease - ? eventTypes.responderRelease - : null; - - if (finalTouch) { - var finalEvent = ResponderSyntheticEvent.getPooled( - finalTouch, - responderInst, - nativeEvent, - nativeEventTarget - ); - finalEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; - accumulateDirectDispatches$1(finalEvent); - extracted = accumulate(extracted, finalEvent); - changeResponder(null); - } - - return extracted; - }, - GlobalResponderHandler: null, - injection: { - /** - * @param {{onChange: (ReactID, ReactID) => void} GlobalResponderHandler - * Object that handles any change in responder. Use this to inject - * integration with an existing touch handling system etc. - */ - injectGlobalResponderHandler: function (GlobalResponderHandler) { - ResponderEventPlugin.GlobalResponderHandler = GlobalResponderHandler; - } + return null; } - }; - - /** - * Injectable ordering of event plugins. - */ - var eventPluginOrder = null; - /** - * Injectable mapping from names to event plugin modules. - */ + } - var namesToPlugins = {}; + ResponderTouchHistoryStore.recordTouchTrack(topLevelType, nativeEvent); + var extracted = canTriggerTransfer(topLevelType, targetInst, nativeEvent) ? setResponderAndExtractTransfer(topLevelType, targetInst, nativeEvent, nativeEventTarget) : null; // Responder may or may not have transferred on a new touch start/move. + // Regardless, whoever is the responder after any potential transfer, we + // direct all touch start/move/ends to them in the form of + // `onResponderMove/Start/End`. These will be called for *every* additional + // finger that move/start/end, dispatched directly to whoever is the + // current responder at that moment, until the responder is "released". + // + // These multiple individual change touch events are are always bookended + // by `onResponderGrant`, and one of + // (`onResponderRelease/onResponderTerminate`). + + var isResponderTouchStart = responderInst && isStartish(topLevelType); + var isResponderTouchMove = responderInst && isMoveish(topLevelType); + var isResponderTouchEnd = responderInst && isEndish(topLevelType); + var incrementalTouch = isResponderTouchStart ? eventTypes.responderStart : isResponderTouchMove ? eventTypes.responderMove : isResponderTouchEnd ? eventTypes.responderEnd : null; + + if (incrementalTouch) { + var gesture = ResponderSyntheticEvent.getPooled(incrementalTouch, responderInst, nativeEvent, nativeEventTarget); + gesture.touchHistory = ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches$1(gesture); + extracted = accumulate(extracted, gesture); + } + + var isResponderTerminate = responderInst && topLevelType === TOP_TOUCH_CANCEL; + var isResponderRelease = responderInst && !isResponderTerminate && isEndish(topLevelType) && noResponderTouches(nativeEvent); + var finalTouch = isResponderTerminate ? eventTypes.responderTerminate : isResponderRelease ? eventTypes.responderRelease : null; + + if (finalTouch) { + var finalEvent = ResponderSyntheticEvent.getPooled(finalTouch, responderInst, nativeEvent, nativeEventTarget); + finalEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches$1(finalEvent); + extracted = accumulate(extracted, finalEvent); + changeResponder(null); + } + + return extracted; + }, + GlobalResponderHandler: null, + injection: { /** - * Recomputes the plugin list using the injected plugins and plugin ordering. - * - * @private + * @param {{onChange: (ReactID, ReactID) => void} GlobalResponderHandler + * Object that handles any change in responder. Use this to inject + * integration with an existing touch handling system etc. */ + injectGlobalResponderHandler: function (GlobalResponderHandler) { + ResponderEventPlugin.GlobalResponderHandler = GlobalResponderHandler; + } + } +}; - function recomputePluginOrdering() { - if (!eventPluginOrder) { - // Wait until an `eventPluginOrder` is injected. - return; - } +/** + * Injectable ordering of event plugins. + */ +var eventPluginOrder = null; +/** + * Injectable mapping from names to event plugin modules. + */ - for (var pluginName in namesToPlugins) { - var pluginModule = namesToPlugins[pluginName]; // $FlowFixMe[incompatible-use] found when upgrading Flow +var namesToPlugins = {}; +/** + * Recomputes the plugin list using the injected plugins and plugin ordering. + * + * @private + */ - var pluginIndex = eventPluginOrder.indexOf(pluginName); +function recomputePluginOrdering() { + if (!eventPluginOrder) { + // Wait until an `eventPluginOrder` is injected. + return; + } - if (pluginIndex <= -1) { - throw new Error( - "EventPluginRegistry: Cannot inject event plugins that do not exist in " + - ("the plugin ordering, `" + pluginName + "`.") - ); - } + for (var pluginName in namesToPlugins) { + var pluginModule = namesToPlugins[pluginName]; // $FlowFixMe[incompatible-use] found when upgrading Flow - if (plugins[pluginIndex]) { - continue; - } + var pluginIndex = eventPluginOrder.indexOf(pluginName); - if (!pluginModule.extractEvents) { - throw new Error( - "EventPluginRegistry: Event plugins must implement an `extractEvents` " + - ("method, but `" + pluginName + "` does not.") - ); - } - - plugins[pluginIndex] = pluginModule; - var publishedEvents = pluginModule.eventTypes; - - for (var eventName in publishedEvents) { - if ( - !publishEventForPlugin( - publishedEvents[eventName], - pluginModule, - eventName - ) - ) { - throw new Error( - "EventPluginRegistry: Failed to publish event `" + - eventName + - "` for plugin `" + - pluginName + - "`." - ); - } - } - } + if (pluginIndex <= -1) { + throw new Error('EventPluginRegistry: Cannot inject event plugins that do not exist in ' + ("the plugin ordering, `" + pluginName + "`.")); } - /** - * Publishes an event so that it can be dispatched by the supplied plugin. - * - * @param {object} dispatchConfig Dispatch configuration for the event. - * @param {object} PluginModule Plugin publishing the event. - * @return {boolean} True if the event was successfully published. - * @private - */ - function publishEventForPlugin(dispatchConfig, pluginModule, eventName) { - if (eventNameDispatchConfigs.hasOwnProperty(eventName)) { - throw new Error( - "EventPluginRegistry: More than one plugin attempted to publish the same " + - ("event name, `" + eventName + "`.") - ); - } + if (plugins[pluginIndex]) { + continue; + } - eventNameDispatchConfigs[eventName] = dispatchConfig; - var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames; + if (!pluginModule.extractEvents) { + throw new Error('EventPluginRegistry: Event plugins must implement an `extractEvents` ' + ("method, but `" + pluginName + "` does not.")); + } - if (phasedRegistrationNames) { - for (var phaseName in phasedRegistrationNames) { - if (phasedRegistrationNames.hasOwnProperty(phaseName)) { - var phasedRegistrationName = phasedRegistrationNames[phaseName]; - publishRegistrationName(phasedRegistrationName, pluginModule); - } - } + plugins[pluginIndex] = pluginModule; + var publishedEvents = pluginModule.eventTypes; - return true; - } else if (dispatchConfig.registrationName) { - publishRegistrationName(dispatchConfig.registrationName, pluginModule); - return true; + for (var eventName in publishedEvents) { + if (!publishEventForPlugin(publishedEvents[eventName], pluginModule, eventName)) { + throw new Error("EventPluginRegistry: Failed to publish event `" + eventName + "` for plugin `" + pluginName + "`."); } - - return false; } - /** - * Publishes a registration name that is used to identify dispatched events. - * - * @param {string} registrationName Registration name to add. - * @param {object} PluginModule Plugin publishing the event. - * @private - */ + } +} +/** + * Publishes an event so that it can be dispatched by the supplied plugin. + * + * @param {object} dispatchConfig Dispatch configuration for the event. + * @param {object} PluginModule Plugin publishing the event. + * @return {boolean} True if the event was successfully published. + * @private + */ - function publishRegistrationName( - registrationName, - pluginModule, - eventName - ) { - if (registrationNameModules[registrationName]) { - throw new Error( - "EventPluginRegistry: More than one plugin attempted to publish the same " + - ("registration name, `" + registrationName + "`.") - ); - } - registrationNameModules[registrationName] = pluginModule; +function publishEventForPlugin(dispatchConfig, pluginModule, eventName) { + if (eventNameDispatchConfigs.hasOwnProperty(eventName)) { + throw new Error('EventPluginRegistry: More than one plugin attempted to publish the same ' + ("event name, `" + eventName + "`.")); + } - { - registrationName.toLowerCase(); + eventNameDispatchConfigs[eventName] = dispatchConfig; + var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames; + + if (phasedRegistrationNames) { + for (var phaseName in phasedRegistrationNames) { + if (phasedRegistrationNames.hasOwnProperty(phaseName)) { + var phasedRegistrationName = phasedRegistrationNames[phaseName]; + publishRegistrationName(phasedRegistrationName, pluginModule); } } - /** - * Registers plugins so that they can extract and dispatch events. - */ - - /** - * Ordered list of injected plugins. - */ - var plugins = []; - /** - * Mapping from event name to dispatch config - */ + return true; + } else if (dispatchConfig.registrationName) { + publishRegistrationName(dispatchConfig.registrationName, pluginModule); + return true; + } - var eventNameDispatchConfigs = {}; - /** - * Mapping from registration name to plugin module - */ + return false; +} +/** + * Publishes a registration name that is used to identify dispatched events. + * + * @param {string} registrationName Registration name to add. + * @param {object} PluginModule Plugin publishing the event. + * @private + */ - var registrationNameModules = {}; - /** - * Injects an ordering of plugins (by plugin name). This allows the ordering - * to be decoupled from injection of the actual plugins so that ordering is - * always deterministic regardless of packaging, on-the-fly injection, etc. - * - * @param {array} InjectedEventPluginOrder - * @internal - */ +function publishRegistrationName(registrationName, pluginModule, eventName) { + if (registrationNameModules[registrationName]) { + throw new Error('EventPluginRegistry: More than one plugin attempted to publish the same ' + ("registration name, `" + registrationName + "`.")); + } - function injectEventPluginOrder(injectedEventPluginOrder) { - if (eventPluginOrder) { - throw new Error( - "EventPluginRegistry: Cannot inject event plugin ordering more than " + - "once. You are likely trying to load more than one copy of React." - ); - } // Clone the ordering so it cannot be dynamically mutated. - // $FlowFixMe[method-unbinding] found when upgrading Flow + registrationNameModules[registrationName] = pluginModule; - eventPluginOrder = Array.prototype.slice.call(injectedEventPluginOrder); - recomputePluginOrdering(); - } - /** - * Injects plugins to be used by plugin event system. The plugin names must be - * in the ordering injected by `injectEventPluginOrder`. - * - * Plugins can be injected as part of page initialization or on-the-fly. - * - * @param {object} injectedNamesToPlugins Map from names to plugin modules. - * @internal - */ + { + registrationName.toLowerCase(); + } +} +/** + * Registers plugins so that they can extract and dispatch events. + */ - function injectEventPluginsByName(injectedNamesToPlugins) { - var isOrderingDirty = false; +/** + * Ordered list of injected plugins. + */ - for (var pluginName in injectedNamesToPlugins) { - if (!injectedNamesToPlugins.hasOwnProperty(pluginName)) { - continue; - } - var pluginModule = injectedNamesToPlugins[pluginName]; +var plugins = []; +/** + * Mapping from event name to dispatch config + */ - if ( - !namesToPlugins.hasOwnProperty(pluginName) || - namesToPlugins[pluginName] !== pluginModule - ) { - if (namesToPlugins[pluginName]) { - throw new Error( - "EventPluginRegistry: Cannot inject two different event plugins " + - ("using the same name, `" + pluginName + "`.") - ); - } +var eventNameDispatchConfigs = {}; +/** + * Mapping from registration name to plugin module + */ - namesToPlugins[pluginName] = pluginModule; - isOrderingDirty = true; - } - } +var registrationNameModules = {}; - if (isOrderingDirty) { - recomputePluginOrdering(); - } - } +/** + * Injects an ordering of plugins (by plugin name). This allows the ordering + * to be decoupled from injection of the actual plugins so that ordering is + * always deterministic regardless of packaging, on-the-fly injection, etc. + * + * @param {array} InjectedEventPluginOrder + * @internal + */ - function getListener(inst, registrationName) { - var stateNode = inst.stateNode; +function injectEventPluginOrder(injectedEventPluginOrder) { + if (eventPluginOrder) { + throw new Error('EventPluginRegistry: Cannot inject event plugin ordering more than ' + 'once. You are likely trying to load more than one copy of React.'); + } // Clone the ordering so it cannot be dynamically mutated. + // $FlowFixMe[method-unbinding] found when upgrading Flow - if (stateNode === null) { - // Work in progress (ex: onload events in incremental mode). - return null; - } - var props = getFiberCurrentPropsFromNode$1(stateNode); + eventPluginOrder = Array.prototype.slice.call(injectedEventPluginOrder); + recomputePluginOrdering(); +} +/** + * Injects plugins to be used by plugin event system. The plugin names must be + * in the ordering injected by `injectEventPluginOrder`. + * + * Plugins can be injected as part of page initialization or on-the-fly. + * + * @param {object} injectedNamesToPlugins Map from names to plugin modules. + * @internal + */ + +function injectEventPluginsByName(injectedNamesToPlugins) { + var isOrderingDirty = false; - if (props === null) { - // Work in progress. - return null; - } + for (var pluginName in injectedNamesToPlugins) { + if (!injectedNamesToPlugins.hasOwnProperty(pluginName)) { + continue; + } - var listener = props[registrationName]; + var pluginModule = injectedNamesToPlugins[pluginName]; - if (listener && typeof listener !== "function") { - throw new Error( - "Expected `" + - registrationName + - "` listener to be a function, instead got a value of `" + - typeof listener + - "` type." - ); + if (!namesToPlugins.hasOwnProperty(pluginName) || namesToPlugins[pluginName] !== pluginModule) { + if (namesToPlugins[pluginName]) { + throw new Error('EventPluginRegistry: Cannot inject two different event plugins ' + ("using the same name, `" + pluginName + "`.")); } - return listener; + namesToPlugins[pluginName] = pluginModule; + isOrderingDirty = true; } + } - var customBubblingEventTypes = - ReactNativePrivateInterface.ReactNativeViewConfigRegistry - .customBubblingEventTypes, - customDirectEventTypes = - ReactNativePrivateInterface.ReactNativeViewConfigRegistry - .customDirectEventTypes; // Start of inline: the below functions were inlined from - // EventPropagator.js, as they deviated from ReactDOM's newer - // implementations. - // $FlowFixMe[missing-local-annot] + if (isOrderingDirty) { + recomputePluginOrdering(); + } +} - function listenerAtPhase(inst, event, propagationPhase) { - var registrationName = - event.dispatchConfig.phasedRegistrationNames[propagationPhase]; - return getListener(inst, registrationName); - } // $FlowFixMe[missing-local-annot] +function getListener(inst, registrationName) { + var stateNode = inst.stateNode; - function accumulateDirectionalDispatches(inst, phase, event) { - { - if (!inst) { - error("Dispatching inst must not be null"); - } - } + if (stateNode === null) { + // Work in progress (ex: onload events in incremental mode). + return null; + } - var listener = listenerAtPhase(inst, event, phase); + var props = getFiberCurrentPropsFromNode$1(stateNode); - if (listener) { - event._dispatchListeners = accumulateInto( - event._dispatchListeners, - listener - ); - event._dispatchInstances = accumulateInto( - event._dispatchInstances, - inst - ); - } - } // $FlowFixMe[missing-local-annot] + if (props === null) { + // Work in progress. + return null; + } - function getParent(inst) { - do { - inst = inst.return; // TODO: If this is a HostRoot we might want to bail out. - // That is depending on if we want nested subtrees (layers) to bubble - // events to their parent. We could also go through parentNode on the - // host node but that wouldn't work for React Native and doesn't let us - // do the portal feature. - } while (inst && inst.tag !== HostComponent); + var listener = props[registrationName]; - if (inst) { - return inst; - } + if (listener && typeof listener !== 'function') { + throw new Error("Expected `" + registrationName + "` listener to be a function, instead got a value of `" + typeof listener + "` type."); + } - return null; - } - /** - * Simulates the traversal of a two-phase, capture/bubble event dispatch. - */ + return listener; +} - function traverseTwoPhase(inst, fn, arg, skipBubbling) { - var path = []; +var customBubblingEventTypes = ReactNativePrivateInterface.ReactNativeViewConfigRegistry.customBubblingEventTypes, + customDirectEventTypes = ReactNativePrivateInterface.ReactNativeViewConfigRegistry.customDirectEventTypes; // Start of inline: the below functions were inlined from +// EventPropagator.js, as they deviated from ReactDOM's newer +// implementations. +// $FlowFixMe[missing-local-annot] - while (inst) { - path.push(inst); - inst = getParent(inst); - } +function listenerAtPhase(inst, event, propagationPhase) { + var registrationName = event.dispatchConfig.phasedRegistrationNames[propagationPhase]; + return getListener(inst, registrationName); +} // $FlowFixMe[missing-local-annot] - var i; - for (i = path.length; i-- > 0; ) { - fn(path[i], "captured", arg); - } +function accumulateDirectionalDispatches(inst, phase, event) { + { + if (!inst) { + error('Dispatching inst must not be null'); + } + } - if (skipBubbling) { - // Dispatch on target only - fn(path[0], "bubbled", arg); - } else { - for (i = 0; i < path.length; i++) { - fn(path[i], "bubbled", arg); - } - } - } // $FlowFixMe[missing-local-annot] + var listener = listenerAtPhase(inst, event, phase); - function accumulateTwoPhaseDispatchesSingle(event) { - if (event && event.dispatchConfig.phasedRegistrationNames) { - traverseTwoPhase( - event._targetInst, - accumulateDirectionalDispatches, - event, - false - ); - } - } // $FlowFixMe[missing-local-annot] + if (listener) { + event._dispatchListeners = accumulateInto(event._dispatchListeners, listener); + event._dispatchInstances = accumulateInto(event._dispatchInstances, inst); + } +} // $FlowFixMe[missing-local-annot] - function accumulateTwoPhaseDispatches(events) { - forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle); - } // $FlowFixMe[missing-local-annot] - function accumulateCapturePhaseDispatches(event) { - if (event && event.dispatchConfig.phasedRegistrationNames) { - traverseTwoPhase( - event._targetInst, - accumulateDirectionalDispatches, - event, - true - ); - } - } - /** - * Accumulates without regard to direction, does not look for phased - * registration names. Same as `accumulateDirectDispatchesSingle` but without - * requiring that the `dispatchMarker` be the same as the dispatched ID. - */ +function getParent(inst) { + do { + inst = inst.return; // TODO: If this is a HostRoot we might want to bail out. + // That is depending on if we want nested subtrees (layers) to bubble + // events to their parent. We could also go through parentNode on the + // host node but that wouldn't work for React Native and doesn't let us + // do the portal feature. + } while (inst && inst.tag !== HostComponent); - function accumulateDispatches(inst, ignoredDirection, event) { - if (inst && event && event.dispatchConfig.registrationName) { - var registrationName = event.dispatchConfig.registrationName; - var listener = getListener(inst, registrationName); + if (inst) { + return inst; + } - if (listener) { - event._dispatchListeners = accumulateInto( - event._dispatchListeners, - listener - ); - event._dispatchInstances = accumulateInto( - event._dispatchInstances, - inst - ); - } - } - } - /** - * Accumulates dispatches on an `SyntheticEvent`, but only for the - * `dispatchMarker`. - * @param {SyntheticEvent} event - */ + return null; +} +/** + * Simulates the traversal of a two-phase, capture/bubble event dispatch. + */ - function accumulateDirectDispatchesSingle(event) { - if (event && event.dispatchConfig.registrationName) { - accumulateDispatches(event._targetInst, null, event); - } - } - function accumulateDirectDispatches(events) { - forEachAccumulated(events, accumulateDirectDispatchesSingle); - } // End of inline +function traverseTwoPhase(inst, fn, arg, skipBubbling) { + var path = []; - var ReactNativeBridgeEventPlugin = { - eventTypes: {}, - extractEvents: function ( - topLevelType, - targetInst, - nativeEvent, - nativeEventTarget - ) { - if (targetInst == null) { - // Probably a node belonging to another renderer's tree. - return null; - } + while (inst) { + path.push(inst); + inst = getParent(inst); + } - var bubbleDispatchConfig = customBubblingEventTypes[topLevelType]; - var directDispatchConfig = customDirectEventTypes[topLevelType]; + var i; - if (!bubbleDispatchConfig && !directDispatchConfig) { - throw new Error( // $FlowFixMe[incompatible-type] - Flow doesn't like this string coercion because DOMTopLevelEventType is opaque - 'Unsupported top level event type "' + topLevelType + '" dispatched' - ); - } + for (i = path.length; i-- > 0;) { + fn(path[i], 'captured', arg); + } - var event = SyntheticEvent.getPooled( - bubbleDispatchConfig || directDispatchConfig, - targetInst, - nativeEvent, - nativeEventTarget - ); + if (skipBubbling) { + // Dispatch on target only + fn(path[0], 'bubbled', arg); + } else { + for (i = 0; i < path.length; i++) { + fn(path[i], 'bubbled', arg); + } + } +} // $FlowFixMe[missing-local-annot] - if (bubbleDispatchConfig) { - var skipBubbling = - event != null && - event.dispatchConfig.phasedRegistrationNames != null && - event.dispatchConfig.phasedRegistrationNames.skipBubbling; +function accumulateTwoPhaseDispatchesSingle(event) { + if (event && event.dispatchConfig.phasedRegistrationNames) { + traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event, false); + } +} // $FlowFixMe[missing-local-annot] - if (skipBubbling) { - accumulateCapturePhaseDispatches(event); - } else { - accumulateTwoPhaseDispatches(event); - } - } else if (directDispatchConfig) { - accumulateDirectDispatches(event); - } else { - return null; - } - return event; - } - }; +function accumulateTwoPhaseDispatches(events) { + forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle); +} // $FlowFixMe[missing-local-annot] - var ReactNativeEventPluginOrder = [ - "ResponderEventPlugin", - "ReactNativeBridgeEventPlugin" - ]; - /** - * Make sure essential globals are available and are patched correctly. Please don't remove this - * line. Bundles created by react-packager `require` it before executing any application code. This - * ensures it exists in the dependency graph and can be `require`d. - * TODO: require this in packager, not in React #10932517 - */ - /** - * Inject module for resolving DOM hierarchy and plugin ordering. - */ +function accumulateCapturePhaseDispatches(event) { + if (event && event.dispatchConfig.phasedRegistrationNames) { + traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event, true); + } +} +/** + * Accumulates without regard to direction, does not look for phased + * registration names. Same as `accumulateDirectDispatchesSingle` but without + * requiring that the `dispatchMarker` be the same as the dispatched ID. + */ - injectEventPluginOrder(ReactNativeEventPluginOrder); - /** - * Some important event plugins included by default (without having to require - * them). - */ - injectEventPluginsByName({ - ResponderEventPlugin: ResponderEventPlugin, - ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin - }); +function accumulateDispatches(inst, ignoredDirection, event) { + if (inst && event && event.dispatchConfig.registrationName) { + var registrationName = event.dispatchConfig.registrationName; + var listener = getListener(inst, registrationName); - var instanceCache = new Map(); - var instanceProps = new Map(); - function precacheFiberNode(hostInst, tag) { - instanceCache.set(tag, hostInst); - } - function uncacheFiberNode(tag) { - instanceCache.delete(tag); - instanceProps.delete(tag); + if (listener) { + event._dispatchListeners = accumulateInto(event._dispatchListeners, listener); + event._dispatchInstances = accumulateInto(event._dispatchInstances, inst); } + } +} +/** + * Accumulates dispatches on an `SyntheticEvent`, but only for the + * `dispatchMarker`. + * @param {SyntheticEvent} event + */ - function getInstanceFromTag(tag) { - return instanceCache.get(tag) || null; - } - function getTagFromInstance(inst) { - var nativeInstance = inst.stateNode; - var tag = nativeInstance._nativeTag; +function accumulateDirectDispatchesSingle(event) { + if (event && event.dispatchConfig.registrationName) { + accumulateDispatches(event._targetInst, null, event); + } +} - if (tag === undefined && nativeInstance.canonical != null) { - // For compatibility with Fabric - tag = nativeInstance.canonical.nativeTag; - nativeInstance = nativeInstance.canonical.publicInstance; - } +function accumulateDirectDispatches(events) { + forEachAccumulated(events, accumulateDirectDispatchesSingle); +} // End of inline - if (!tag) { - throw new Error("All native instances should have a tag."); - } - return nativeInstance; - } - function getFiberCurrentPropsFromNode(stateNode) { - return instanceProps.get(stateNode._nativeTag) || null; - } - function updateFiberProps(tag, props) { - instanceProps.set(tag, props); +var ReactNativeBridgeEventPlugin = { + eventTypes: {}, + extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { + if (targetInst == null) { + // Probably a node belonging to another renderer's tree. + return null; } - // 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 bubbleDispatchConfig = customBubblingEventTypes[topLevelType]; + var directDispatchConfig = customDirectEventTypes[topLevelType]; - 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); - } + if (!bubbleDispatchConfig && !directDispatchConfig) { + throw new Error( // $FlowFixMe[incompatible-type] - Flow doesn't like this string coercion because DOMTopLevelEventType is opaque + "Unsupported top level event type \"" + topLevelType + "\" dispatched"); + } - isInsideEventHandler = true; + var event = SyntheticEvent.getPooled(bubbleDispatchConfig || directDispatchConfig, targetInst, nativeEvent, nativeEventTarget); - try { - return batchedUpdatesImpl(fn, bookkeeping); - } finally { - isInsideEventHandler = false; + if (bubbleDispatchConfig) { + var skipBubbling = event != null && event.dispatchConfig.phasedRegistrationNames != null && event.dispatchConfig.phasedRegistrationNames.skipBubbling; + + if (skipBubbling) { + accumulateCapturePhaseDispatches(event); + } else { + accumulateTwoPhaseDispatches(event); } - } - function setBatchingImplementation( - _batchedUpdatesImpl, - _discreteUpdatesImpl - ) { - batchedUpdatesImpl = _batchedUpdatesImpl; + } else if (directDispatchConfig) { + accumulateDirectDispatches(event); + } else { + return null; } - /** - * Internal queue of events that have accumulated their dispatches and are - * waiting to have their dispatches executed. - */ + return event; + } +}; - 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 ReactNativeEventPluginOrder = ['ResponderEventPlugin', 'ReactNativeBridgeEventPlugin']; - function executeDispatchesAndRelease(event) { - if (event) { - executeDispatchesInOrder(event); +/** + * Make sure essential globals are available and are patched correctly. Please don't remove this + * line. Bundles created by react-packager `require` it before executing any application code. This + * ensures it exists in the dependency graph and can be `require`d. + * TODO: require this in packager, not in React #10932517 + */ +/** + * Inject module for resolving DOM hierarchy and plugin ordering. + */ - if (!event.isPersistent()) { - event.constructor.release(event); - } - } - } // $FlowFixMe[missing-local-annot] +injectEventPluginOrder(ReactNativeEventPluginOrder); +/** + * Some important event plugins included by default (without having to require + * them). + */ - function executeDispatchesAndReleaseTopLevel(e) { - return executeDispatchesAndRelease(e); - } +injectEventPluginsByName({ + ResponderEventPlugin: ResponderEventPlugin, + ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin +}); - 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 instanceCache = new Map(); +var instanceProps = new Map(); +function precacheFiberNode(hostInst, tag) { + instanceCache.set(tag, hostInst); +} +function uncacheFiberNode(tag) { + instanceCache.delete(tag); + instanceProps.delete(tag); +} - var processingEventQueue = eventQueue; - eventQueue = null; +function getInstanceFromTag(tag) { + return instanceCache.get(tag) || null; +} - if (!processingEventQueue) { - return; - } +function getTagFromInstance(inst) { + var nativeInstance = inst.stateNode; + var tag = nativeInstance._nativeTag; - forEachAccumulated( - processingEventQueue, - executeDispatchesAndReleaseTopLevel - ); + if (tag === undefined && nativeInstance.canonical != null) { + // For compatibility with Fabric + tag = nativeInstance.canonical.nativeTag; + nativeInstance = nativeInstance.canonical.publicInstance; + } - 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 (!tag) { + throw new Error('All native instances should have a tag.'); + } - rethrowCaughtError(); - } + return nativeInstance; +} +function getFiberCurrentPropsFromNode(stateNode) { + return instanceProps.get(stateNode._nativeTag) || null; +} +function updateFiberProps(tag, props) { + instanceProps.set(tag, props); +} - /** - * Version of `ReactBrowserEventEmitter` that works on the receiving side of a - * serialized worker boundary. - */ - // Shared default empty native event - conserve memory. +// 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$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); + } + + isInsideEventHandler = true; + + try { + return batchedUpdatesImpl(fn, bookkeeping); + } finally { + isInsideEventHandler = false; + } +} +function setBatchingImplementation(_batchedUpdatesImpl, _discreteUpdatesImpl) { + batchedUpdatesImpl = _batchedUpdatesImpl; +} - var EMPTY_NATIVE_EVENT = {}; - /** - * Selects a subsequence of `Touch`es, without destroying `touches`. - * - * @param {Array} touches Deserialized touch objects. - * @param {Array} indices Indices by which to pull subsequence. - * @return {Array} Subsequence of touch objects. - */ - // $FlowFixMe[missing-local-annot] +/** + * Internal queue of events that have accumulated their dispatches and are + * waiting to have their dispatches executed. + */ - function touchSubsequence(touches, indices) { - var ret = []; +var eventQueue = null; +/** + * Dispatches an event and releases it back into the pool, unless persistent. + * + * @param {?object} event Synthetic event to be dispatched. + * @private + */ - for (var i = 0; i < indices.length; i++) { - ret.push(touches[indices[i]]); - } +function executeDispatchesAndRelease(event) { + if (event) { + executeDispatchesInOrder(event); - return ret; + if (!event.isPersistent()) { + event.constructor.release(event); } - /** - * TODO: Pool all of this. - * - * Destroys `touches` by removing touch objects at indices `indices`. This is - * to maintain compatibility with W3C touch "end" events, where the active - * touches don't include the set that has just been "ended". - * - * @param {Array} touches Deserialized touch objects. - * @param {Array} indices Indices to remove from `touches`. - * @return {Array} Subsequence of removed touch objects. - */ + } +} // $FlowFixMe[missing-local-annot] - function removeTouchesAtIndices(touches, indices) { - var rippedOut = []; // use an unsafe downcast to alias to nullable elements, - // so we can delete and then compact. - var temp = touches; +function executeDispatchesAndReleaseTopLevel(e) { + return executeDispatchesAndRelease(e); +} - for (var i = 0; i < indices.length; i++) { - var index = indices[i]; - rippedOut.push(touches[index]); - temp[index] = null; - } +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 fillAt = 0; - for (var j = 0; j < temp.length; j++) { - var cur = temp[j]; + var processingEventQueue = eventQueue; + eventQueue = null; - if (cur !== null) { - temp[fillAt++] = cur; - } - } + if (!processingEventQueue) { + return; + } - temp.length = fillAt; - return rippedOut; - } - /** - * Internal version of `receiveEvent` in terms of normalized (non-tag) - * `rootNodeID`. - * - * @see receiveEvent. - * - * @param {rootNodeID} rootNodeID React root node ID that event occurred on. - * @param {TopLevelType} topLevelType Top level type of event. - * @param {?object} nativeEventParam Object passed from native. - */ + forEachAccumulated(processingEventQueue, executeDispatchesAndReleaseTopLevel); - function _receiveRootNodeIDEvent( - rootNodeID, - topLevelType, - nativeEventParam - ) { - var nativeEvent = nativeEventParam || EMPTY_NATIVE_EVENT; - var inst = getInstanceFromTag(rootNodeID); - var target = null; - - if (inst != null) { - target = inst.stateNode; - } - - batchedUpdates$1(function () { - runExtractedPluginEventsInBatch( - topLevelType, - inst, - nativeEvent, - target - ); - }); // React Native doesn't use ReactControlledComponent but if it did, here's - // where it would do it. - } - /** - * Allows registered plugins an opportunity to extract events from top-level - * native browser events. - * - * @return {*} An accumulation of synthetic events. - * @internal - */ + 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. - function extractPluginEvents( - topLevelType, - targetInst, - nativeEvent, - nativeEventTarget - ) { - var events = null; - var legacyPlugins = plugins; - - for (var i = 0; i < legacyPlugins.length; i++) { - // Not every plugin in the ordering may be loaded at runtime. - var possiblePlugin = legacyPlugins[i]; - - if (possiblePlugin) { - var extractedEvents = possiblePlugin.extractEvents( - topLevelType, - targetInst, - nativeEvent, - nativeEventTarget - ); - - if (extractedEvents) { - events = accumulateInto(events, extractedEvents); - } - } - } - return events; - } + rethrowCaughtError(); +} - function runExtractedPluginEventsInBatch( - topLevelType, - targetInst, - nativeEvent, - nativeEventTarget - ) { - var events = extractPluginEvents( - topLevelType, - targetInst, - nativeEvent, - nativeEventTarget - ); - runEventsInBatch(events); - } - /** - * Publicly exposed method on module for native objc to invoke when a top - * level event is extracted. - * @param {rootNodeID} rootNodeID React root node ID that event occurred on. - * @param {TopLevelType} topLevelType Top level type of event. - * @param {object} nativeEventParam Object passed from native. - */ +/** + * Version of `ReactBrowserEventEmitter` that works on the receiving side of a + * serialized worker boundary. + */ +// Shared default empty native event - conserve memory. - function receiveEvent(rootNodeID, topLevelType, nativeEventParam) { - _receiveRootNodeIDEvent(rootNodeID, topLevelType, nativeEventParam); - } - /** - * Simple multi-wrapper around `receiveEvent` that is intended to receive an - * efficient representation of `Touch` objects, and other information that - * can be used to construct W3C compliant `Event` and `Touch` lists. - * - * This may create dispatch behavior that differs than web touch handling. We - * loop through each of the changed touches and receive it as a single event. - * So two `touchStart`/`touchMove`s that occur simultaneously are received as - * two separate touch event dispatches - when they arguably should be one. - * - * This implementation reuses the `Touch` objects themselves as the `Event`s - * since we dispatch an event for each touch (though that might not be spec - * compliant). The main purpose of reusing them is to save allocations. - * - * TODO: Dispatch multiple changed touches in one event. The bubble path - * could be the first common ancestor of all the `changedTouches`. - * - * One difference between this behavior and W3C spec: cancelled touches will - * not appear in `.touches`, or in any future `.touches`, though they may - * still be "actively touching the surface". - * - * Web desktop polyfills only need to construct a fake touch event with - * identifier 0, also abandoning traditional click handlers. - */ +var EMPTY_NATIVE_EVENT = {}; +/** + * Selects a subsequence of `Touch`es, without destroying `touches`. + * + * @param {Array} touches Deserialized touch objects. + * @param {Array} indices Indices by which to pull subsequence. + * @return {Array} Subsequence of touch objects. + */ +// $FlowFixMe[missing-local-annot] - function receiveTouches(eventTopLevelType, touches, changedIndices) { - var changedTouches = - eventTopLevelType === "topTouchEnd" || - eventTopLevelType === "topTouchCancel" - ? removeTouchesAtIndices(touches, changedIndices) - : touchSubsequence(touches, changedIndices); - - for (var jj = 0; jj < changedTouches.length; jj++) { - var touch = changedTouches[jj]; // Touch objects can fulfill the role of `DOM` `Event` objects if we set - // the `changedTouches`/`touches`. This saves allocations. - - touch.changedTouches = changedTouches; - touch.touches = touches; - var nativeEvent = touch; - var rootNodeID = null; - var target = nativeEvent.target; - - if (target !== null && target !== undefined) { - if (target < 1) { - { - error("A view is reporting that a touch occurred on tag zero."); - } - } else { - rootNodeID = target; - } - } // $FlowFixMe[incompatible-call] Shouldn't we *not* call it if rootNodeID is null? +function touchSubsequence(touches, indices) { + var ret = []; - _receiveRootNodeIDEvent(rootNodeID, eventTopLevelType, nativeEvent); - } - } + for (var i = 0; i < indices.length; i++) { + ret.push(touches[indices[i]]); + } - // Module provided by RN: - var ReactNativeGlobalResponderHandler = { - onChange: function (from, to, blockNativeResponder) { - if (to !== null) { - var tag = to.stateNode._nativeTag; - ReactNativePrivateInterface.UIManager.setJSResponder( - tag, - blockNativeResponder - ); - } else { - ReactNativePrivateInterface.UIManager.clearJSResponder(); - } - } - }; + return ret; +} +/** + * TODO: Pool all of this. + * + * Destroys `touches` by removing touch objects at indices `indices`. This is + * to maintain compatibility with W3C touch "end" events, where the active + * touches don't include the set that has just been "ended". + * + * @param {Array} touches Deserialized touch objects. + * @param {Array} indices Indices to remove from `touches`. + * @return {Array} Subsequence of removed touch objects. + */ - /** - * Register the event emitter with the native bridge - */ - ReactNativePrivateInterface.RCTEventEmitter.register({ - receiveEvent: receiveEvent, - receiveTouches: receiveTouches - }); - setComponentTree( - getFiberCurrentPropsFromNode, - getInstanceFromTag, - getTagFromInstance - ); - ResponderEventPlugin.injection.injectGlobalResponderHandler( - ReactNativeGlobalResponderHandler - ); +function removeTouchesAtIndices(touches, indices) { + var rippedOut = []; // use an unsafe downcast to alias to nullable elements, + // so we can delete and then compact. - var LegacyRoot = 0; - var ConcurrentRoot = 1; + var temp = touches; - /** - * `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; - } - - // Re-export dynamic flags from the internal module. - var dynamicFlags = dynamicFlagsUntyped; // We destructure each value before re-exporting to avoid a dynamic look-up on - // the exports object every time a flag is read. - - var alwaysThrottleRetries = dynamicFlags.alwaysThrottleRetries, - consoleManagedByDevToolsDuringStrictMode = - dynamicFlags.consoleManagedByDevToolsDuringStrictMode, - enableAsyncActions = dynamicFlags.enableAsyncActions, - enableEarlyReturnForPropDiffing = - dynamicFlags.enableEarlyReturnForPropDiffing, - enableComponentStackLocations = - dynamicFlags.enableComponentStackLocations, - enableDeferRootSchedulingToMicrotask = - dynamicFlags.enableDeferRootSchedulingToMicrotask, - enableInfiniteRenderLoopDetection = - dynamicFlags.enableInfiniteRenderLoopDetection, - enableRenderableContext = dynamicFlags.enableRenderableContext, - enableUnifiedSyncLane = dynamicFlags.enableUnifiedSyncLane, - useModernStrictMode = dynamicFlags.useModernStrictMode, - disableDefaultPropsExceptForClasses = - dynamicFlags.disableDefaultPropsExceptForClasses; // 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 syncLaneExpirationMs = 250; - var transitionLaneExpirationMs = 5000; - var enableLazyContextPropagation = false; - var enableLegacyHidden = false; - var disableLegacyMode = false; - - // 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"); // TODO: Delete with enableRenderableContext - - var REACT_CONSUMER_TYPE = Symbol.for("react.consumer"); - var REACT_CONTEXT_TYPE = Symbol.for("react.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_TRACING_MARKER_TYPE = Symbol.for("react.tracing_marker"); - 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; - } + for (var i = 0; i < indices.length; i++) { + var index = indices[i]; + rippedOut.push(touches[index]); + temp[index] = null; + } - var maybeIterator = - (MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL]) || - maybeIterable[FAUX_ITERATOR_SYMBOL]; + var fillAt = 0; - if (typeof maybeIterator === "function") { - return maybeIterator; - } + for (var j = 0; j < temp.length; j++) { + var cur = temp[j]; - return null; + if (cur !== null) { + temp[fillAt++] = cur; } + } - function getWrappedName$1(outerType, innerType, wrapperName) { - var displayName = outerType.displayName; + temp.length = fillAt; + return rippedOut; +} +/** + * Internal version of `receiveEvent` in terms of normalized (non-tag) + * `rootNodeID`. + * + * @see receiveEvent. + * + * @param {rootNodeID} rootNodeID React root node ID that event occurred on. + * @param {TopLevelType} topLevelType Top level type of event. + * @param {?object} nativeEventParam Object passed from native. + */ - if (displayName) { - return displayName; - } - var functionName = innerType.displayName || innerType.name || ""; - return functionName !== "" - ? wrapperName + "(" + functionName + ")" - : wrapperName; - } // Keep in sync with react-reconciler/getComponentNameFromFiber +function _receiveRootNodeIDEvent(rootNodeID, topLevelType, nativeEventParam) { + var nativeEvent = nativeEventParam || EMPTY_NATIVE_EVENT; + var inst = getInstanceFromTag(rootNodeID); + var target = null; - function getContextName$1(type) { - return type.displayName || "Context"; - } + if (inst != null) { + target = inst.stateNode; + } - var REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference"); // Note that the reconciler package should generally prefer to use getComponentNameFromFiber() instead. + batchedUpdates$1(function () { + runExtractedPluginEventsInBatch(topLevelType, inst, nativeEvent, target); + }); // React Native doesn't use ReactControlledComponent but if it did, here's + // where it would do it. +} +/** + * Allows registered plugins an opportunity to extract events from top-level + * native browser events. + * + * @return {*} An accumulation of synthetic events. + * @internal + */ - function getComponentNameFromType(type) { - if (type == null) { - // Host root, text node or just invalid type. - return null; - } - if (typeof type === "function") { - if (type.$$typeof === REACT_CLIENT_REFERENCE) { - // TODO: Create a convention for naming client references with debug info. - return null; - } +function extractPluginEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget) { + var events = null; + var legacyPlugins = plugins; - return type.displayName || type.name || null; - } + for (var i = 0; i < legacyPlugins.length; i++) { + // Not every plugin in the ordering may be loaded at runtime. + var possiblePlugin = legacyPlugins[i]; - if (typeof type === "string") { - return type; + if (possiblePlugin) { + var extractedEvents = possiblePlugin.extractEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget); + + if (extractedEvents) { + events = accumulateInto(events, extractedEvents); } + } + } - switch (type) { - case REACT_FRAGMENT_TYPE: - return "Fragment"; + return events; +} + +function runExtractedPluginEventsInBatch(topLevelType, targetInst, nativeEvent, nativeEventTarget) { + var events = extractPluginEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget); + runEventsInBatch(events); +} +/** + * Publicly exposed method on module for native objc to invoke when a top + * level event is extracted. + * @param {rootNodeID} rootNodeID React root node ID that event occurred on. + * @param {TopLevelType} topLevelType Top level type of event. + * @param {object} nativeEventParam Object passed from native. + */ - case REACT_PORTAL_TYPE: - return "Portal"; - case REACT_PROFILER_TYPE: - return "Profiler"; +function receiveEvent(rootNodeID, topLevelType, nativeEventParam) { + _receiveRootNodeIDEvent(rootNodeID, topLevelType, nativeEventParam); +} +/** + * Simple multi-wrapper around `receiveEvent` that is intended to receive an + * efficient representation of `Touch` objects, and other information that + * can be used to construct W3C compliant `Event` and `Touch` lists. + * + * This may create dispatch behavior that differs than web touch handling. We + * loop through each of the changed touches and receive it as a single event. + * So two `touchStart`/`touchMove`s that occur simultaneously are received as + * two separate touch event dispatches - when they arguably should be one. + * + * This implementation reuses the `Touch` objects themselves as the `Event`s + * since we dispatch an event for each touch (though that might not be spec + * compliant). The main purpose of reusing them is to save allocations. + * + * TODO: Dispatch multiple changed touches in one event. The bubble path + * could be the first common ancestor of all the `changedTouches`. + * + * One difference between this behavior and W3C spec: cancelled touches will + * not appear in `.touches`, or in any future `.touches`, though they may + * still be "actively touching the surface". + * + * Web desktop polyfills only need to construct a fake touch event with + * identifier 0, also abandoning traditional click handlers. + */ - case REACT_STRICT_MODE_TYPE: - return "StrictMode"; +function receiveTouches(eventTopLevelType, touches, changedIndices) { + var changedTouches = eventTopLevelType === 'topTouchEnd' || eventTopLevelType === 'topTouchCancel' ? removeTouchesAtIndices(touches, changedIndices) : touchSubsequence(touches, changedIndices); - case REACT_SUSPENSE_TYPE: - return "Suspense"; + for (var jj = 0; jj < changedTouches.length; jj++) { + var touch = changedTouches[jj]; // Touch objects can fulfill the role of `DOM` `Event` objects if we set + // the `changedTouches`/`touches`. This saves allocations. - case REACT_SUSPENSE_LIST_TYPE: - return "SuspenseList"; - } + touch.changedTouches = changedTouches; + touch.touches = touches; + var nativeEvent = touch; + var rootNodeID = null; + var target = nativeEvent.target; - if (typeof type === "object") { + if (target !== null && target !== undefined) { + if (target < 1) { { - if (typeof type.tag === "number") { - error( - "Received an unexpected object in getComponentNameFromType(). " + - "This is likely a bug in React. Please file an issue." - ); - } + error('A view is reporting that a touch occurred on tag zero.'); } + } else { + rootNodeID = target; + } + } // $FlowFixMe[incompatible-call] Shouldn't we *not* call it if rootNodeID is null? - switch (type.$$typeof) { - case REACT_PROVIDER_TYPE: - if (enableRenderableContext) { - return null; - } else { - var provider = type; - return getContextName$1(provider._context) + ".Provider"; - } - case REACT_CONTEXT_TYPE: - var context = type; + _receiveRootNodeIDEvent(rootNodeID, eventTopLevelType, nativeEvent); + } +} - if (enableRenderableContext) { - return getContextName$1(context) + ".Provider"; - } else { - return getContextName$1(context) + ".Consumer"; - } +// Module provided by RN: +var ReactNativeGlobalResponderHandler = { + onChange: function (from, to, blockNativeResponder) { + if (to !== null) { + var tag = to.stateNode._nativeTag; + ReactNativePrivateInterface.UIManager.setJSResponder(tag, blockNativeResponder); + } else { + ReactNativePrivateInterface.UIManager.clearJSResponder(); + } + } +}; - case REACT_CONSUMER_TYPE: - if (enableRenderableContext) { - var consumer = type; - return getContextName$1(consumer._context) + ".Consumer"; - } else { - return null; - } +/** + * Register the event emitter with the native bridge + */ - case REACT_FORWARD_REF_TYPE: - return getWrappedName$1(type, type.render, "ForwardRef"); +ReactNativePrivateInterface.RCTEventEmitter.register({ + receiveEvent: receiveEvent, + receiveTouches: receiveTouches +}); +setComponentTree(getFiberCurrentPropsFromNode, getInstanceFromTag, getTagFromInstance); +ResponderEventPlugin.injection.injectGlobalResponderHandler(ReactNativeGlobalResponderHandler); - case REACT_MEMO_TYPE: - var outerName = type.displayName || null; +var LegacyRoot = 0; +var ConcurrentRoot = 1; - if (outerName !== null) { - return outerName; - } +/** + * `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; +} - return getComponentNameFromType(type.type) || "Memo"; +// Re-export dynamic flags from the internal module. +var dynamicFlags = dynamicFlagsUntyped; // We destructure each value before re-exporting to avoid a dynamic look-up on +// the exports object every time a flag is read. + +var alwaysThrottleRetries = dynamicFlags.alwaysThrottleRetries, + consoleManagedByDevToolsDuringStrictMode = dynamicFlags.consoleManagedByDevToolsDuringStrictMode, + enableAsyncActions = dynamicFlags.enableAsyncActions, + enableEarlyReturnForPropDiffing = dynamicFlags.enableEarlyReturnForPropDiffing, + enableComponentStackLocations = dynamicFlags.enableComponentStackLocations, + enableDeferRootSchedulingToMicrotask = dynamicFlags.enableDeferRootSchedulingToMicrotask, + enableInfiniteRenderLoopDetection = dynamicFlags.enableInfiniteRenderLoopDetection, + enableRenderableContext = dynamicFlags.enableRenderableContext, + enableUnifiedSyncLane = dynamicFlags.enableUnifiedSyncLane, + useModernStrictMode = dynamicFlags.useModernStrictMode, + disableDefaultPropsExceptForClasses = dynamicFlags.disableDefaultPropsExceptForClasses; // 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 syncLaneExpirationMs = 250; +var transitionLaneExpirationMs = 5000; +var enableLazyContextPropagation = false; +var enableLegacyHidden = false; +var disableLegacyMode = false; + +// 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'); // TODO: Delete with enableRenderableContext + +var REACT_CONSUMER_TYPE = Symbol.for('react.consumer'); +var REACT_CONTEXT_TYPE = Symbol.for('react.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_TRACING_MARKER_TYPE = Symbol.for('react.tracing_marker'); +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 maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]; + + if (typeof maybeIterator === 'function') { + return maybeIterator; + } + + return null; +} - case REACT_LAZY_TYPE: { - var lazyComponent = type; - var payload = lazyComponent._payload; - var init = lazyComponent._init; +function getWrappedName$1(outerType, innerType, wrapperName) { + var displayName = outerType.displayName; - try { - return getComponentNameFromType(init(payload)); - } catch (x) { - return null; - } - } - } - } + if (displayName) { + return displayName; + } - return null; - } + var functionName = innerType.displayName || innerType.name || ''; + return functionName !== '' ? wrapperName + "(" + functionName + ")" : wrapperName; +} // Keep in sync with react-reconciler/getComponentNameFromFiber - 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"; - } +function getContextName$1(type) { + return type.displayName || 'Context'; +} - function getComponentNameFromOwner(owner) { - if (typeof owner.tag === "number") { - return getComponentNameFromFiber(owner); - } +var REACT_CLIENT_REFERENCE = Symbol.for('react.client.reference'); // Note that the reconciler package should generally prefer to use getComponentNameFromFiber() instead. - if (typeof owner.name === "string") { - return owner.name; - } +function getComponentNameFromType(type) { + if (type == null) { + // Host root, text node or just invalid type. + return null; + } + if (typeof type === 'function') { + if (type.$$typeof === REACT_CLIENT_REFERENCE) { + // TODO: Create a convention for naming client references with debug info. return null; } - function getComponentNameFromFiber(fiber) { - var tag = fiber.tag, - type = fiber.type; - - switch (tag) { - case CacheComponent: - return "Cache"; - - case ContextConsumer: - if (enableRenderableContext) { - var consumer = type; - return getContextName(consumer._context) + ".Consumer"; - } else { - var context = type; - return getContextName(context) + ".Consumer"; - } - - case ContextProvider: - if (enableRenderableContext) { - var _context = type; - return getContextName(_context) + ".Provider"; - } else { - var provider = type; - return getContextName(provider._context) + ".Provider"; - } - case DehydratedFragment: - return "DehydratedFragment"; + return type.displayName || type.name || null; + } - case ForwardRef: - return getWrappedName(type, type.render, "ForwardRef"); + if (typeof type === 'string') { + return type; + } - case Fragment: - return "Fragment"; + switch (type) { + case REACT_FRAGMENT_TYPE: + return 'Fragment'; - case HostHoistable: - case HostSingleton: - case HostComponent: - // Host component type is the display name (e.g. "div", "View") - return type; + case REACT_PORTAL_TYPE: + return 'Portal'; - case HostPortal: - return "Portal"; + case REACT_PROFILER_TYPE: + return 'Profiler'; - case HostRoot: - return "Root"; + case REACT_STRICT_MODE_TYPE: + return 'StrictMode'; - case HostText: - return "Text"; + case REACT_SUSPENSE_TYPE: + return 'Suspense'; - case LazyComponent: - // Name comes from the type in this case; we don't have a tag. - return getComponentNameFromType(type); + case REACT_SUSPENSE_LIST_TYPE: + return 'SuspenseList'; - case Mode: - if (type === REACT_STRICT_MODE_TYPE) { - // Don't be less specific than shared/getComponentNameFromType - return "StrictMode"; - } + } - return "Mode"; + if (typeof type === 'object') { + { + if (typeof type.tag === 'number') { + error('Received an unexpected object in getComponentNameFromType(). ' + 'This is likely a bug in React. Please file an issue.'); + } + } - case OffscreenComponent: - return "Offscreen"; + switch (type.$$typeof) { + case REACT_PROVIDER_TYPE: + if (enableRenderableContext) { + return null; + } else { + var provider = type; + return getContextName$1(provider._context) + '.Provider'; + } - case Profiler: - return "Profiler"; + case REACT_CONTEXT_TYPE: + var context = type; - case ScopeComponent: - return "Scope"; + if (enableRenderableContext) { + return getContextName$1(context) + '.Provider'; + } else { + return getContextName$1(context) + '.Consumer'; + } - case SuspenseComponent: - return "Suspense"; + case REACT_CONSUMER_TYPE: + if (enableRenderableContext) { + var consumer = type; + return getContextName$1(consumer._context) + '.Consumer'; + } else { + return null; + } - case SuspenseListComponent: - return "SuspenseList"; + case REACT_FORWARD_REF_TYPE: + return getWrappedName$1(type, type.render, 'ForwardRef'); - case TracingMarkerComponent: - return "TracingMarker"; - // The display name for these tags come from the user-provided type: + case REACT_MEMO_TYPE: + var outerName = type.displayName || null; - case IncompleteClassComponent: - case IncompleteFunctionComponent: + if (outerName !== null) { + return outerName; + } - // Fallthrough + return getComponentNameFromType(type.type) || 'Memo'; - case ClassComponent: - case FunctionComponent: - case MemoComponent: - case SimpleMemoComponent: - if (typeof type === "function") { - return type.displayName || type.name || null; - } + case REACT_LAZY_TYPE: + { + var lazyComponent = type; + var payload = lazyComponent._payload; + var init = lazyComponent._init; - if (typeof type === "string") { - return type; + try { + return getComponentNameFromType(init(payload)); + } catch (x) { + return null; } - - break; - } - - return null; + } } + } - var NoFlags$1 = - /* */ - 0; - var PerformedWork = - /* */ - 1; - var Placement = - /* */ - 2; - var DidCapture = - /* */ - 128; - var Hydrating = - /* */ - 4096; // You can change the rest (and add more). - - var Update = - /* */ - 4; - /* Skipped value: 0b0000000000000000000000001000; */ - - var ChildDeletion = - /* */ - 16; - var ContentReset = - /* */ - 32; - var Callback = - /* */ - 64; - /* Used by DidCapture: 0b0000000000000000000010000000; */ - - var ForceClientRender = - /* */ - 256; - var Ref = - /* */ - 512; - var Snapshot = - /* */ - 1024; - var Passive$1 = - /* */ - 2048; - /* Used by Hydrating: 0b0000000000000001000000000000; */ - - var Visibility = - /* */ - 8192; - var StoreConsistency = - /* */ - 16384; // It's OK to reuse these bits because these flags are mutually exclusive for - // different fiber types. We should really be doing this for as many flags as - // possible, because we're about to run out of bits. - - var ScheduleRetry = StoreConsistency; - var ShouldSuspendCommit = Visibility; - var DidDefer = ContentReset; - var FormReset = Snapshot; - var LifecycleEffectMask = - Passive$1 | Update | Callback | Ref | Snapshot | StoreConsistency; // Union of all commit flags (flags with the lifetime of a particular commit) - - var HostEffectMask = - /* */ - 32767; // These are not really side effects, but we still reuse this field. - - var Incomplete = - /* */ - 32768; - var ShouldCapture = - /* */ - 65536; - var ForceUpdateForLegacySuspense = - /* */ - 131072; - var Forked = - /* */ - 1048576; // Static tags describe aspects of a fiber that are not specific to a render, - // e.g. a fiber uses a passive effect (even if there are no updates on this particular render). - // This enables us to defer more work in the unmount case, - // since we can defer traversing the tree during layout to look for Passive effects, - // and instead rely on the static flag as a signal that there may be cleanup work. - - var RefStatic = - /* */ - 2097152; - var LayoutStatic = - /* */ - 4194304; - var PassiveStatic = - /* */ - 8388608; - var MaySuspendCommit = - /* */ - 16777216; // Flag used to identify newly inserted fibers. It isn't reset after commit unlike `Placement`. - - var PlacementDEV = - /* */ - 33554432; - var MountLayoutDev = - /* */ - 67108864; - var MountPassiveDev = - /* */ - 134217728; // Groups of flags that are used in the commit phase to skip over trees that - // don't contain effects, by checking subtreeFlags. - - var BeforeMutationMask = // TODO: Remove Update flag from before mutation phase by re-landing Visibility - // flag logic (see #20043) - Update | Snapshot | 0; - var MutationMask = - Placement | - Update | - ChildDeletion | - ContentReset | - Ref | - Hydrating | - Visibility | - FormReset; - var LayoutMask = Update | Callback | Ref | Visibility; // TODO: Split into PassiveMountMask and PassiveUnmountMask - - var PassiveMask = Passive$1 | Visibility | ChildDeletion; // Union of tags that don't get reset on clones. - // This allows certain concepts to persist without recalculating them, - // e.g. whether a subtree contains passive effects or portals. - - var StaticMask = - LayoutStatic | PassiveStatic | RefStatic | MaySuspendCommit; - - function getNearestMountedFiber(fiber) { - var node = fiber; - var nearestMounted = fiber; - - 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; + return null; +} - do { - node = nextNode; +function getWrappedName(outerType, innerType, wrapperName) { + var functionName = innerType.displayName || innerType.name || ''; + return outerType.displayName || (functionName !== '' ? wrapperName + "(" + functionName + ")" : wrapperName); +} // Keep in sync with shared/getComponentNameFromType - 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; - } - } +function getContextName(type) { + return type.displayName || 'Context'; +} - 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 getComponentNameFromOwner(owner) { + if (typeof owner.tag === 'number') { + return getComponentNameFromFiber(owner); + } - return null; - } - function isFiberMounted(fiber) { - return getNearestMountedFiber(fiber) === fiber; - } - function isMounted(component) { - { - var owner = ReactSharedInternals.owner; - - if (owner !== null && owner.tag === ClassComponent) { - var ownerFiber = owner; - var instance = ownerFiber.stateNode; - - 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" - ); - } + if (typeof owner.name === 'string') { + return owner.name; + } - instance._warnedAboutRefsInRender = true; - } - } + return null; +} +function getComponentNameFromFiber(fiber) { + var tag = fiber.tag, + type = fiber.type; - var fiber = get(component); + switch (tag) { + case CacheComponent: + return 'Cache'; - if (!fiber) { - return false; + case ContextConsumer: + if (enableRenderableContext) { + var consumer = type; + return getContextName(consumer._context) + '.Consumer'; + } else { + var context = type; + return getContextName(context) + '.Consumer'; } - return getNearestMountedFiber(fiber) === fiber; - } - - function assertIsMounted(fiber) { - if (getNearestMountedFiber(fiber) !== fiber) { - throw new Error("Unable to find node on an unmounted component."); + case ContextProvider: + if (enableRenderableContext) { + var _context = type; + return getContextName(_context) + '.Provider'; + } else { + var provider = type; + return getContextName(provider._context) + '.Provider'; } - } - function findCurrentFiberUsingSlowPath(fiber) { - var alternate = fiber.alternate; + case DehydratedFragment: + return 'DehydratedFragment'; - if (!alternate) { - // If there is no alternate, then we only need to check if it is mounted. - var nearestMounted = getNearestMountedFiber(fiber); + case ForwardRef: + return getWrappedName(type, type.render, 'ForwardRef'); - if (nearestMounted === null) { - throw new Error("Unable to find node on an unmounted component."); - } + case Fragment: + return 'Fragment'; - if (nearestMounted !== fiber) { - return null; - } + case HostHoistable: + case HostSingleton: + case HostComponent: + // Host component type is the display name (e.g. "div", "View") + return type; - 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. + case HostPortal: + return 'Portal'; - var a = fiber; - var b = alternate; + case HostRoot: + return 'Root'; - while (true) { - var parentA = a.return; + case HostText: + return 'Text'; - if (parentA === null) { - // We're at the root. - break; - } + case LazyComponent: + // Name comes from the type in this case; we don't have a tag. + return getComponentNameFromType(type); - var parentB = parentA.alternate; + case Mode: + if (type === REACT_STRICT_MODE_TYPE) { + // Don't be less specific than shared/getComponentNameFromType + return 'StrictMode'; + } - 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; + return 'Mode'; - if (nextParent !== null) { - a = b = nextParent; - continue; - } // If there's no parent, we're at the root. + case OffscreenComponent: + return 'Offscreen'; - 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; - } + case Profiler: + return 'Profiler'; - if (child === b) { - // We've determined that B is the current branch. - assertIsMounted(parentA); - return alternate; - } + case ScopeComponent: + return 'Scope'; - 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. + case SuspenseComponent: + return 'Suspense'; - throw new Error("Unable to find node on an unmounted component."); - } + case SuspenseListComponent: + return 'SuspenseList'; - 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; - } + case TracingMarkerComponent: + return 'TracingMarker'; + // The display name for these tags come from the user-provided type: - if (_child === b) { - didFindChild = true; - b = parentA; - a = parentB; - break; - } + case IncompleteClassComponent: + case IncompleteFunctionComponent: - _child = _child.sibling; - } + // Fallthrough - if (!didFindChild) { - // Search parent B's child set - _child = parentB.child; + case ClassComponent: + case FunctionComponent: + case MemoComponent: + case SimpleMemoComponent: + if (typeof type === 'function') { + return type.displayName || type.name || null; + } - while (_child) { - if (_child === a) { - didFindChild = true; - a = parentB; - b = parentA; - break; - } + if (typeof type === 'string') { + return type; + } - if (_child === b) { - didFindChild = true; - b = parentB; - a = parentA; - break; - } + 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." - ); - } - } - } + return null; +} - 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. +var NoFlags$1 = +/* */ +0; +var PerformedWork = +/* */ +1; +var Placement = +/* */ +2; +var DidCapture = +/* */ +128; +var Hydrating = +/* */ +4096; // You can change the rest (and add more). + +var Update = +/* */ +4; +/* Skipped value: 0b0000000000000000000000001000; */ + +var ChildDeletion = +/* */ +16; +var ContentReset = +/* */ +32; +var Callback = +/* */ +64; +/* Used by DidCapture: 0b0000000000000000000010000000; */ + +var ForceClientRender = +/* */ +256; +var Ref = +/* */ +512; +var Snapshot = +/* */ +1024; +var Passive$1 = +/* */ +2048; +/* Used by Hydrating: 0b0000000000000001000000000000; */ + +var Visibility = +/* */ +8192; +var StoreConsistency = +/* */ +16384; // It's OK to reuse these bits because these flags are mutually exclusive for +// different fiber types. We should really be doing this for as many flags as +// possible, because we're about to run out of bits. + +var ScheduleRetry = StoreConsistency; +var ShouldSuspendCommit = Visibility; +var DidDefer = ContentReset; +var FormReset = Snapshot; +var LifecycleEffectMask = Passive$1 | Update | Callback | Ref | Snapshot | StoreConsistency; // Union of all commit flags (flags with the lifetime of a particular commit) + +var HostEffectMask = +/* */ +32767; // These are not really side effects, but we still reuse this field. + +var Incomplete = +/* */ +32768; +var ShouldCapture = +/* */ +65536; +var ForceUpdateForLegacySuspense = +/* */ +131072; +var Forked = +/* */ +1048576; // Static tags describe aspects of a fiber that are not specific to a render, +// e.g. a fiber uses a passive effect (even if there are no updates on this particular render). +// This enables us to defer more work in the unmount case, +// since we can defer traversing the tree during layout to look for Passive effects, +// and instead rely on the static flag as a signal that there may be cleanup work. + +var RefStatic = +/* */ +2097152; +var LayoutStatic = +/* */ +4194304; +var PassiveStatic = +/* */ +8388608; +var MaySuspendCommit = +/* */ +16777216; // Flag used to identify newly inserted fibers. It isn't reset after commit unlike `Placement`. + +var PlacementDEV = +/* */ +33554432; +var MountLayoutDev = +/* */ +67108864; +var MountPassiveDev = +/* */ +134217728; // Groups of flags that are used in the commit phase to skip over trees that +// don't contain effects, by checking subtreeFlags. + +var BeforeMutationMask = // TODO: Remove Update flag from before mutation phase by re-landing Visibility +// flag logic (see #20043) +Update | Snapshot | (0); +var MutationMask = Placement | Update | ChildDeletion | ContentReset | Ref | Hydrating | Visibility | FormReset; +var LayoutMask = Update | Callback | Ref | Visibility; // TODO: Split into PassiveMountMask and PassiveUnmountMask + +var PassiveMask = Passive$1 | Visibility | ChildDeletion; // Union of tags that don't get reset on clones. +// This allows certain concepts to persist without recalculating them, +// e.g. whether a subtree contains passive effects or portals. + +var StaticMask = LayoutStatic | PassiveStatic | RefStatic | MaySuspendCommit; + +function getNearestMountedFiber(fiber) { + var node = fiber; + var nearestMounted = fiber; + + 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; + + do { + node = nextNode; + + 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; + } + } + + 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. + + + return null; +} +function isFiberMounted(fiber) { + return getNearestMountedFiber(fiber) === fiber; +} +function isMounted(component) { + { + var owner = ReactSharedInternals.owner; - if (a.tag !== HostRoot) { - throw new Error("Unable to find node on an unmounted component."); - } + if (owner !== null && owner.tag === ClassComponent) { + var ownerFiber = owner; + var instance = ownerFiber.stateNode; - if (a.stateNode.current === a) { - // We've determined that A is the current branch. - return fiber; - } // Otherwise B has to be current branch. + 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'); + } - return alternate; - } - function findCurrentHostFiber(parent) { - var currentParent = findCurrentFiberUsingSlowPath(parent); - return currentParent !== null - ? findCurrentHostFiberImpl(currentParent) - : null; + instance._warnedAboutRefsInRender = true; } + } - function findCurrentHostFiberImpl(node) { - // Next we'll drill down this component to find the first HostComponent/Text. - var tag = node.tag; + var fiber = get(component); - if ( - tag === HostComponent || - tag === HostHoistable || - tag === HostSingleton || - tag === HostText - ) { - return node; - } + if (!fiber) { + return false; + } - var child = node.child; + return getNearestMountedFiber(fiber) === fiber; +} - while (child !== null) { - var match = findCurrentHostFiberImpl(child); +function assertIsMounted(fiber) { + if (getNearestMountedFiber(fiber) !== fiber) { + throw new Error('Unable to find node on an unmounted component.'); + } +} - if (match !== null) { - return match; - } +function findCurrentFiberUsingSlowPath(fiber) { + var alternate = fiber.alternate; - child = child.sibling; - } + if (!alternate) { + // If there is no alternate, then we only need to check if it is mounted. + var nearestMounted = getNearestMountedFiber(fiber); + if (nearestMounted === null) { + throw new Error('Unable to find node on an unmounted component.'); + } + + if (nearestMounted !== fiber) { return null; } - function doesFiberContain(parentFiber, childFiber) { - var node = childFiber; - var parentFiberAlternate = parentFiber.alternate; - while (node !== null) { - if (node === parentFiber || node === parentFiberAlternate) { - return true; - } + 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. - node = node.return; - } - return false; - } + var a = fiber; + var b = alternate; - // Modules provided by RN: - var emptyObject$1 = {}; - /** - * Create a payload that contains all the updates between two sets of props. - * - * These helpers are all encapsulated into a single module, because they use - * mutation as a performance optimization which leads to subtle shared - * dependencies between the code paths. To avoid this mutable state leaking - * across modules, I've kept them isolated to this module. - */ - // Tracks removed keys + while (true) { + var parentA = a.return; - var removedKeys = null; - var removedKeyCount = 0; - var deepDifferOptions = { - unsafelyIgnoreFunctions: true - }; + if (parentA === null) { + // We're at the root. + break; + } - function defaultDiffer(prevProp, nextProp) { - if (typeof nextProp !== "object" || nextProp === null) { - // Scalars have already been checked for equality - return true; - } else { - // For objects and arrays, the default diffing algorithm is a deep compare - return ReactNativePrivateInterface.deepDiffer( - prevProp, - nextProp, - deepDifferOptions - ); - } - } - - function restoreDeletedValuesInNestedArray( - updatePayload, - node, - validAttributes - ) { - if (isArray(node)) { - var i = node.length; - - while (i-- && removedKeyCount > 0) { - restoreDeletedValuesInNestedArray( - updatePayload, - node[i], - validAttributes - ); - } - } else if (node && removedKeyCount > 0) { - var obj = node; - - for (var propKey in removedKeys) { - // $FlowFixMe[incompatible-use] found when upgrading Flow - if (!removedKeys[propKey]) { - continue; - } + var parentB = parentA.alternate; - var nextProp = obj[propKey]; + 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 (nextProp === undefined) { - continue; - } + if (nextParent !== null) { + a = b = nextParent; + continue; + } // If there's no parent, we're at the root. - var attributeConfig = validAttributes[propKey]; - if (!attributeConfig) { - continue; // not a valid native prop - } + 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 (typeof nextProp === "function") { - // $FlowFixMe[incompatible-type] found when upgrading Flow - nextProp = true; - } - if (typeof nextProp === "undefined") { - // $FlowFixMe[incompatible-type] found when upgrading Flow - nextProp = null; - } + if (parentA.child === parentB.child) { + var child = parentA.child; - if (typeof attributeConfig !== "object") { - // case: !Object is the default case - updatePayload[propKey] = nextProp; - } else if ( - typeof attributeConfig.diff === "function" || - typeof attributeConfig.process === "function" - ) { - // case: CustomAttributeConfiguration - var nextValue = - typeof attributeConfig.process === "function" - ? attributeConfig.process(nextProp) - : nextProp; - updatePayload[propKey] = nextValue; - } // $FlowFixMe[incompatible-use] found when upgrading Flow - - removedKeys[propKey] = false; - removedKeyCount--; + while (child) { + if (child === a) { + // We've determined that A is the current branch. + assertIsMounted(parentA); + return fiber; } - } - } - - function diffNestedArrayProperty( - updatePayload, - prevArray, - nextArray, - validAttributes - ) { - var minLength = - prevArray.length < nextArray.length - ? prevArray.length - : nextArray.length; - var i; - - for (i = 0; i < minLength; i++) { - // Diff any items in the array in the forward direction. Repeated keys - // will be overwritten by later values. - updatePayload = diffNestedProperty( - updatePayload, - prevArray[i], - nextArray[i], - validAttributes - ); - } - - for (; i < prevArray.length; i++) { - // Clear out all remaining properties. - updatePayload = clearNestedProperty( - updatePayload, - prevArray[i], - validAttributes - ); - } - - for (; i < nextArray.length; i++) { - // Add all remaining properties. - updatePayload = addNestedProperty( - updatePayload, - nextArray[i], - validAttributes - ); - } - - return updatePayload; - } - - function diffNestedProperty( - updatePayload, - prevProp, - nextProp, - validAttributes - ) { - if (!updatePayload && prevProp === nextProp) { - // If no properties have been added, then we can bail out quickly on object - // equality. - return updatePayload; - } - - if (!prevProp || !nextProp) { - if (nextProp) { - return addNestedProperty(updatePayload, nextProp, validAttributes); - } - - if (prevProp) { - return clearNestedProperty(updatePayload, prevProp, validAttributes); - } - - return updatePayload; - } - - if (!isArray(prevProp) && !isArray(nextProp)) { - // Both are leaves, we can diff the leaves. - return diffProperties( - updatePayload, - prevProp, - nextProp, - validAttributes - ); - } - - if (isArray(prevProp) && isArray(nextProp)) { - // Both are arrays, we can diff the arrays. - return diffNestedArrayProperty( - updatePayload, - prevProp, - nextProp, - validAttributes - ); - } - if (isArray(prevProp)) { - return diffProperties( - updatePayload, - ReactNativePrivateInterface.flattenStyle(prevProp), - nextProp, - validAttributes - ); - } + if (child === b) { + // We've determined that B is the current branch. + assertIsMounted(parentA); + return alternate; + } - return diffProperties( - updatePayload, - prevProp, - ReactNativePrivateInterface.flattenStyle(nextProp), - validAttributes - ); - } - /** - * addNestedProperty takes a single set of props and valid attribute - * attribute configurations. It processes each prop and adds it to the - * updatePayload. - */ + 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. - function addNestedProperty(updatePayload, nextProp, validAttributes) { - if (!nextProp) { - return updatePayload; - } - if (!isArray(nextProp)) { - // Add each property of the leaf. - return addProperties(updatePayload, nextProp, validAttributes); - } + throw new Error('Unable to find node on an unmounted component.'); + } - for (var i = 0; i < nextProp.length; i++) { - // Add all the properties of the array. - updatePayload = addNestedProperty( - updatePayload, - nextProp[i], - validAttributes - ); - } + 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; - return updatePayload; - } - /** - * clearNestedProperty takes a single set of props and valid attributes. It - * adds a null sentinel to the updatePayload, for each prop key. - */ + while (_child) { + if (_child === a) { + didFindChild = true; + a = parentA; + b = parentB; + break; + } - function clearNestedProperty(updatePayload, prevProp, validAttributes) { - if (!prevProp) { - return updatePayload; - } + if (_child === b) { + didFindChild = true; + b = parentA; + a = parentB; + break; + } - if (!isArray(prevProp)) { - // Add each property of the leaf. - return clearProperties(updatePayload, prevProp, validAttributes); + _child = _child.sibling; } - for (var i = 0; i < prevProp.length; i++) { - // Add all the properties of the array. - updatePayload = clearNestedProperty( - updatePayload, - prevProp[i], - validAttributes - ); - } + if (!didFindChild) { + // Search parent B's child set + _child = parentB.child; - return updatePayload; - } - /** - * diffProperties takes two sets of props and a set of valid attributes - * and write to updatePayload the values that changed or were deleted. - * If no updatePayload is provided, a new one is created and returned if - * anything changed. - */ + while (_child) { + if (_child === a) { + didFindChild = true; + a = parentB; + b = parentA; + break; + } - function diffProperties( - updatePayload, - prevProps, - nextProps, - validAttributes - ) { - var attributeConfig; - var nextProp; - var prevProp; + if (_child === b) { + didFindChild = true; + b = parentB; + a = parentA; + break; + } - for (var propKey in nextProps) { - attributeConfig = validAttributes[propKey]; + _child = _child.sibling; + } - if (!attributeConfig) { - continue; // not a valid native prop + 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.'); } + } + } - prevProp = prevProps[propKey]; - nextProp = nextProps[propKey]; // functions are converted to booleans as markers that the associated - // events should be sent from native. + 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. - if (typeof nextProp === "function") { - nextProp = true; // If nextProp is not a function, then don't bother changing prevProp - // since nextProp will win and go into the updatePayload regardless. - if (typeof prevProp === "function") { - prevProp = true; - } - } // An explicit value of undefined is treated as a null because it overrides - // any other preceding value. + if (a.tag !== HostRoot) { + throw new Error('Unable to find node on an unmounted component.'); + } - if (typeof nextProp === "undefined") { - nextProp = null; + if (a.stateNode.current === a) { + // We've determined that A is the current branch. + return fiber; + } // Otherwise B has to be current branch. - if (typeof prevProp === "undefined") { - prevProp = null; - } - } - if (removedKeys) { - removedKeys[propKey] = false; - } - - if (updatePayload && updatePayload[propKey] !== undefined) { - // Something else already triggered an update to this key because another - // value diffed. Since we're now later in the nested arrays our value is - // more important so we need to calculate it and override the existing - // value. It doesn't matter if nothing changed, we'll set it anyway. - // Pattern match on: attributeConfig - if (typeof attributeConfig !== "object") { - // case: !Object is the default case - updatePayload[propKey] = nextProp; - } else if ( - typeof attributeConfig.diff === "function" || - typeof attributeConfig.process === "function" - ) { - // case: CustomAttributeConfiguration - var nextValue = - typeof attributeConfig.process === "function" - ? attributeConfig.process(nextProp) - : nextProp; - updatePayload[propKey] = nextValue; - } + return alternate; +} +function findCurrentHostFiber(parent) { + var currentParent = findCurrentFiberUsingSlowPath(parent); + return currentParent !== null ? findCurrentHostFiberImpl(currentParent) : null; +} - continue; - } +function findCurrentHostFiberImpl(node) { + // Next we'll drill down this component to find the first HostComponent/Text. + var tag = node.tag; - if (prevProp === nextProp) { - continue; // nothing changed - } // Pattern match on: attributeConfig + if (tag === HostComponent || tag === HostHoistable || tag === HostSingleton || tag === HostText) { + return node; + } - if (typeof attributeConfig !== "object") { - // case: !Object is the default case - if (defaultDiffer(prevProp, nextProp)) { - // a normal leaf has changed - (updatePayload || (updatePayload = {}))[propKey] = nextProp; - } - } else if ( - typeof attributeConfig.diff === "function" || - typeof attributeConfig.process === "function" - ) { - // case: CustomAttributeConfiguration - var shouldUpdate = - prevProp === undefined || - (typeof attributeConfig.diff === "function" - ? attributeConfig.diff(prevProp, nextProp) - : defaultDiffer(prevProp, nextProp)); - - if (shouldUpdate) { - var _nextValue = - typeof attributeConfig.process === "function" // $FlowFixMe[incompatible-use] found when upgrading Flow - ? attributeConfig.process(nextProp) - : nextProp; - - (updatePayload || (updatePayload = {}))[propKey] = _nextValue; - } - } else { - // default: fallthrough case when nested properties are defined - removedKeys = null; - removedKeyCount = 0; // We think that attributeConfig is not CustomAttributeConfiguration at - // this point so we assume it must be AttributeConfiguration. - - updatePayload = diffNestedProperty( - updatePayload, - prevProp, - nextProp, - attributeConfig - ); - - if (removedKeyCount > 0 && updatePayload) { - restoreDeletedValuesInNestedArray( - updatePayload, - nextProp, - attributeConfig - ); - removedKeys = null; - } - } - } // Also iterate through all the previous props to catch any that have been - // removed and make sure native gets the signal so it can reset them to the - // default. + var child = node.child; - for (var _propKey in prevProps) { - if (nextProps[_propKey] !== undefined) { - continue; // we've already covered this key in the previous pass - } + while (child !== null) { + var match = findCurrentHostFiberImpl(child); - attributeConfig = validAttributes[_propKey]; + if (match !== null) { + return match; + } - if (!attributeConfig) { - continue; // not a valid native prop - } + child = child.sibling; + } - if (updatePayload && updatePayload[_propKey] !== undefined) { - // This was already updated to a diff result earlier. - continue; - } + return null; +} +function doesFiberContain(parentFiber, childFiber) { + var node = childFiber; + var parentFiberAlternate = parentFiber.alternate; - prevProp = prevProps[_propKey]; + while (node !== null) { + if (node === parentFiber || node === parentFiberAlternate) { + return true; + } - if (prevProp === undefined) { - continue; // was already empty anyway - } // Pattern match on: attributeConfig + node = node.return; + } - if ( - typeof attributeConfig !== "object" || - typeof attributeConfig.diff === "function" || - typeof attributeConfig.process === "function" - ) { - // case: CustomAttributeConfiguration | !Object - // Flag the leaf property for removal by sending a sentinel. - (updatePayload || (updatePayload = {}))[_propKey] = null; + return false; +} - if (!removedKeys) { - removedKeys = {}; - } +// Modules provided by RN: +var emptyObject$1 = {}; +/** + * Create a payload that contains all the updates between two sets of props. + * + * These helpers are all encapsulated into a single module, because they use + * mutation as a performance optimization which leads to subtle shared + * dependencies between the code paths. To avoid this mutable state leaking + * across modules, I've kept them isolated to this module. + */ +// Tracks removed keys + +var removedKeys = null; +var removedKeyCount = 0; +var deepDifferOptions = { + unsafelyIgnoreFunctions: true +}; + +function defaultDiffer(prevProp, nextProp) { + if (typeof nextProp !== 'object' || nextProp === null) { + // Scalars have already been checked for equality + return true; + } else { + // For objects and arrays, the default diffing algorithm is a deep compare + return ReactNativePrivateInterface.deepDiffer(prevProp, nextProp, deepDifferOptions); + } +} - if (!removedKeys[_propKey]) { - removedKeys[_propKey] = true; - removedKeyCount++; - } - } else { - // default: - // This is a nested attribute configuration where all the properties - // were removed so we need to go through and clear out all of them. - updatePayload = clearNestedProperty( - updatePayload, - prevProp, - attributeConfig - ); - } - } +function restoreDeletedValuesInNestedArray(updatePayload, node, validAttributes) { + if (isArray(node)) { + var i = node.length; - return updatePayload; + while (i-- && removedKeyCount > 0) { + restoreDeletedValuesInNestedArray(updatePayload, node[i], validAttributes); } - /** - * addProperties adds all the valid props to the payload after being processed. - */ + } else if (node && removedKeyCount > 0) { + var obj = node; - function addProperties(updatePayload, props, validAttributes) { - // TODO: Fast path - return diffProperties( - updatePayload, - emptyObject$1, - props, - validAttributes - ); - } - /** - * clearProperties clears all the previous props by adding a null sentinel - * to the payload for each valid key. - */ + for (var propKey in removedKeys) { + // $FlowFixMe[incompatible-use] found when upgrading Flow + if (!removedKeys[propKey]) { + continue; + } - function clearProperties(updatePayload, prevProps, validAttributes) { - // TODO: Fast path - return diffProperties( - updatePayload, - prevProps, - emptyObject$1, - validAttributes - ); - } + var nextProp = obj[propKey]; - function create(props, validAttributes) { - return addProperties( - null, // updatePayload - props, - validAttributes - ); - } - function diff(prevProps, nextProps, validAttributes) { - if (enableEarlyReturnForPropDiffing) { - if (prevProps === nextProps) { - return null; // no change - } + if (nextProp === undefined) { + continue; } - return diffProperties( - null, // updatePayload - prevProps, - nextProps, - validAttributes - ); - } + var attributeConfig = validAttributes[propKey]; - /** - * In the future, we should cleanup callbacks by cancelling them instead of - * using this. - */ - function mountSafeCallback_NOT_REALLY_SAFE(context, callback) { - return function () { - if (!callback) { - return undefined; - } // This protects against createClass() components. - // We don't know if there is code depending on it. - // We intentionally don't use isMounted() because even accessing - // isMounted property on a React ES6 class will trigger a warning. - - if (typeof context.__isMounted === "boolean") { - if (!context.__isMounted) { - return undefined; - } - } // FIXME: there used to be other branches that protected - // against unmounted host components. But RN host components don't - // define isMounted() anymore, so those checks didn't do anything. - // They caused false positive warning noise so we removed them: - // https://github.com/facebook/react-native/issues/18868#issuecomment-413579095 - // However, this means that the callback is NOT guaranteed to be safe - // for host components. The solution we should implement is to make - // UIManager.measure() and similar calls truly cancelable. Then we - // can change our own code calling them to cancel when something unmounts. - - return callback.apply(context, arguments); - }; - } - 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 - ); - } - } + if (!attributeConfig) { + continue; // not a valid native prop } - } - var ReactNativeFiberHostComponent = /*#__PURE__*/ (function () { - function ReactNativeFiberHostComponent( - tag, - viewConfig, - internalInstanceHandleDEV - ) { - this._children = void 0; - this._nativeTag = void 0; - this._internalFiberInstanceHandleDEV = void 0; - this.viewConfig = void 0; - this._nativeTag = tag; - this._children = []; - this.viewConfig = viewConfig; + if (typeof nextProp === 'function') { + // $FlowFixMe[incompatible-type] found when upgrading Flow + nextProp = true; + } - { - this._internalFiberInstanceHandleDEV = internalInstanceHandleDEV; - } + if (typeof nextProp === 'undefined') { + // $FlowFixMe[incompatible-type] found when upgrading Flow + nextProp = null; } - var _proto = ReactNativeFiberHostComponent.prototype; + if (typeof attributeConfig !== 'object') { + // case: !Object is the default case + updatePayload[propKey] = nextProp; + } else if (typeof attributeConfig.diff === 'function' || typeof attributeConfig.process === 'function') { + // case: CustomAttributeConfiguration + var nextValue = typeof attributeConfig.process === 'function' ? attributeConfig.process(nextProp) : nextProp; + updatePayload[propKey] = nextValue; + } // $FlowFixMe[incompatible-use] found when upgrading Flow - _proto.blur = function blur() { - ReactNativePrivateInterface.TextInputState.blurTextInput(this); - }; - _proto.focus = function focus() { - ReactNativePrivateInterface.TextInputState.focusTextInput(this); - }; + removedKeys[propKey] = false; + removedKeyCount--; + } + } +} - _proto.measure = function measure(callback) { - ReactNativePrivateInterface.UIManager.measure( - this._nativeTag, - mountSafeCallback_NOT_REALLY_SAFE(this, callback) - ); - }; +function diffNestedArrayProperty(updatePayload, prevArray, nextArray, validAttributes) { + var minLength = prevArray.length < nextArray.length ? prevArray.length : nextArray.length; + var i; - _proto.measureInWindow = function measureInWindow(callback) { - ReactNativePrivateInterface.UIManager.measureInWindow( - this._nativeTag, - mountSafeCallback_NOT_REALLY_SAFE(this, callback) - ); - }; + for (i = 0; i < minLength; i++) { + // Diff any items in the array in the forward direction. Repeated keys + // will be overwritten by later values. + updatePayload = diffNestedProperty(updatePayload, prevArray[i], nextArray[i], validAttributes); + } - _proto.measureLayout = function measureLayout( - relativeToNativeNode, - onSuccess, - onFail - /* currently unused */ - ) { - var relativeNode; - - if (typeof relativeToNativeNode === "number") { - // Already a node handle - relativeNode = relativeToNativeNode; - } else { - var nativeNode = relativeToNativeNode; + for (; i < prevArray.length; i++) { + // Clear out all remaining properties. + updatePayload = clearNestedProperty(updatePayload, prevArray[i], validAttributes); + } - if (nativeNode._nativeTag) { - relativeNode = nativeNode._nativeTag; - } - } + for (; i < nextArray.length; i++) { + // Add all remaining properties. + updatePayload = addNestedProperty(updatePayload, nextArray[i], validAttributes); + } - if (relativeNode == null) { - { - error( - "Warning: ref.measureLayout must be called with a node handle or a ref to a native component." - ); - } + return updatePayload; +} - return; - } +function diffNestedProperty(updatePayload, prevProp, nextProp, validAttributes) { + if (!updatePayload && prevProp === nextProp) { + // If no properties have been added, then we can bail out quickly on object + // equality. + return updatePayload; + } - ReactNativePrivateInterface.UIManager.measureLayout( - this._nativeTag, - relativeNode, - mountSafeCallback_NOT_REALLY_SAFE(this, onFail), - mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) - ); - }; + if (!prevProp || !nextProp) { + if (nextProp) { + return addNestedProperty(updatePayload, nextProp, validAttributes); + } - _proto.setNativeProps = function setNativeProps(nativeProps) { - { - warnForStyleProps(nativeProps, this.viewConfig.validAttributes); - } + if (prevProp) { + return clearNestedProperty(updatePayload, prevProp, validAttributes); + } - var updatePayload = create( - nativeProps, - this.viewConfig.validAttributes - ); // Avoid the overhead of bridge calls if there's no update. - // This is an expensive no-op for Android, and causes an unnecessary - // view invalidation for certain components (eg RCTTextInput) on iOS. + return updatePayload; + } - if (updatePayload != null) { - ReactNativePrivateInterface.UIManager.updateView( - this._nativeTag, - this.viewConfig.uiViewClassName, - updatePayload - ); - } - }; + if (!isArray(prevProp) && !isArray(nextProp)) { + // Both are leaves, we can diff the leaves. + return diffProperties(updatePayload, prevProp, nextProp, validAttributes); + } - return ReactNativeFiberHostComponent; - })(); - - // This module only exists as an ESM wrapper around the external CommonJS - var scheduleCallback$3 = 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$1 = Scheduler.unstable_NormalPriority; - var IdlePriority = Scheduler.unstable_IdlePriority; // this doesn't actually exist on the scheduler, but it *does* - // on scheduler/unstable_mock, which we'll need for internal testing - - var log$1 = Scheduler.log; - var unstable_setDisableYieldValue = Scheduler.unstable_setDisableYieldValue; - - // 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[cannot-write] 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 */ - } + if (isArray(prevProp) && isArray(nextProp)) { + // Both are arrays, we can diff the arrays. + return diffNestedArrayProperty(updatePayload, prevProp, nextProp, validAttributes); + } - disabledDepth++; + if (isArray(prevProp)) { + return diffProperties(updatePayload, ReactNativePrivateInterface.flattenStyle(prevProp), nextProp, validAttributes); + } + + return diffProperties(updatePayload, prevProp, ReactNativePrivateInterface.flattenStyle(nextProp), validAttributes); +} +/** + * addNestedProperty takes a single set of props and valid attribute + * attribute configurations. It processes each prop and adds it to the + * updatePayload. + */ + + +function addNestedProperty(updatePayload, nextProp, validAttributes) { + if (!nextProp) { + return updatePayload; + } + + if (!isArray(nextProp)) { + // Add each property of the leaf. + return addProperties(updatePayload, nextProp, validAttributes); + } + + for (var i = 0; i < nextProp.length; i++) { + // Add all the properties of the array. + updatePayload = addNestedProperty(updatePayload, nextProp[i], validAttributes); + } + + return updatePayload; +} +/** + * clearNestedProperty takes a single set of props and valid attributes. It + * adds a null sentinel to the updatePayload, for each prop key. + */ + + +function clearNestedProperty(updatePayload, prevProp, validAttributes) { + if (!prevProp) { + return updatePayload; + } + + if (!isArray(prevProp)) { + // Add each property of the leaf. + return clearProperties(updatePayload, prevProp, validAttributes); + } + + for (var i = 0; i < prevProp.length; i++) { + // Add all the properties of the array. + updatePayload = clearNestedProperty(updatePayload, prevProp[i], validAttributes); + } + + return updatePayload; +} +/** + * diffProperties takes two sets of props and a set of valid attributes + * and write to updatePayload the values that changed or were deleted. + * If no updatePayload is provided, a new one is created and returned if + * anything changed. + */ + + +function diffProperties(updatePayload, prevProps, nextProps, validAttributes) { + var attributeConfig; + var nextProp; + var prevProp; + + for (var propKey in nextProps) { + attributeConfig = validAttributes[propKey]; + + if (!attributeConfig) { + continue; // not a valid native prop + } + + prevProp = prevProps[propKey]; + nextProp = nextProps[propKey]; // functions are converted to booleans as markers that the associated + // events should be sent from native. + + if (typeof nextProp === 'function') { + nextProp = true; // If nextProp is not a function, then don't bother changing prevProp + // since nextProp will win and go into the updatePayload regardless. + + if (typeof prevProp === 'function') { + prevProp = true; + } + } // An explicit value of undefined is treated as a null because it overrides + // any other preceding value. + + + if (typeof nextProp === 'undefined') { + nextProp = null; + + if (typeof prevProp === 'undefined') { + prevProp = null; } } - function reenableLogs() { - { - disabledDepth--; - - if (disabledDepth === 0) { - /* eslint-disable react-internal/no-production-logging */ - var props = { - configurable: true, - enumerable: true, - writable: true - }; // $FlowFixMe[cannot-write] 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 (removedKeys) { + removedKeys[propKey] = false; + } + + if (updatePayload && updatePayload[propKey] !== undefined) { + // Something else already triggered an update to this key because another + // value diffed. Since we're now later in the nested arrays our value is + // more important so we need to calculate it and override the existing + // value. It doesn't matter if nothing changed, we'll set it anyway. + // Pattern match on: attributeConfig + if (typeof attributeConfig !== 'object') { + // case: !Object is the default case + updatePayload[propKey] = nextProp; + } else if (typeof attributeConfig.diff === 'function' || typeof attributeConfig.process === 'function') { + // case: CustomAttributeConfiguration + var nextValue = typeof attributeConfig.process === 'function' ? attributeConfig.process(nextProp) : nextProp; + updatePayload[propKey] = nextValue; } + + continue; } - 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; + if (prevProp === nextProp) { + continue; // nothing changed + } // Pattern match on: attributeConfig + + + if (typeof attributeConfig !== 'object') { + // case: !Object is the default case + if (defaultDiffer(prevProp, nextProp)) { + // a normal leaf has changed + (updatePayload || (updatePayload = {}))[propKey] = nextProp; } + } else if (typeof attributeConfig.diff === 'function' || typeof attributeConfig.process === 'function') { + // case: CustomAttributeConfiguration + var shouldUpdate = prevProp === undefined || (typeof attributeConfig.diff === 'function' ? attributeConfig.diff(prevProp, nextProp) : defaultDiffer(prevProp, nextProp)); - var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__; + if (shouldUpdate) { + var _nextValue = typeof attributeConfig.process === 'function' ? // $FlowFixMe[incompatible-use] found when upgrading Flow + attributeConfig.process(nextProp) : nextProp; - 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; + (updatePayload || (updatePayload = {}))[propKey] = _nextValue; } + } else { + // default: fallthrough case when nested properties are defined + removedKeys = null; + removedKeyCount = 0; // We think that attributeConfig is not CustomAttributeConfiguration at + // this point so we assume it must be AttributeConfiguration. - 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://react.dev/link/react-devtools" - ); - } // DevTools exists, even though it doesn't support Fiber. + updatePayload = diffNestedProperty(updatePayload, prevProp, nextProp, attributeConfig); - return true; + if (removedKeyCount > 0 && updatePayload) { + restoreDeletedValuesInNestedArray(updatePayload, nextProp, attributeConfig); + removedKeys = null; } + } + } // Also iterate through all the previous props to catch any that have been + // removed and make sure native gets the signal so it can reset them to the + // default. - 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. + for (var _propKey in prevProps) { + if (nextProps[_propKey] !== undefined) { + continue; // we've already covered this key in the previous pass + } - injectedHook = hook; - } catch (err) { - // Catch all errors because it is unsafe to throw during initialization. - { - error("React instrumentation encountered an error: %s.", err); - } + attributeConfig = validAttributes[_propKey]; + + if (!attributeConfig) { + continue; // not a valid native prop + } + + if (updatePayload && updatePayload[_propKey] !== undefined) { + // This was already updated to a diff result earlier. + continue; + } + + prevProp = prevProps[_propKey]; + + if (prevProp === undefined) { + continue; // was already empty anyway + } // Pattern match on: attributeConfig + + + if (typeof attributeConfig !== 'object' || typeof attributeConfig.diff === 'function' || typeof attributeConfig.process === 'function') { + // case: CustomAttributeConfiguration | !Object + // Flag the leaf property for removal by sending a sentinel. + (updatePayload || (updatePayload = {}))[_propKey] = null; + + if (!removedKeys) { + removedKeys = {}; } - if (hook.checkDCE) { - // This is the real DevTools. - return true; - } else { - // This is likely a hook installed by Fast Refresh runtime. - return false; + if (!removedKeys[_propKey]) { + removedKeys[_propKey] = true; + removedKeyCount++; } + } else { + // default: + // This is a nested attribute configuration where all the properties + // were removed so we need to go through and clear out all of them. + updatePayload = clearNestedProperty(updatePayload, prevProp, attributeConfig); } - function onScheduleRoot(root, children) { - { - 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); - } - } - } + return updatePayload; +} +/** + * addProperties adds all the valid props to the payload after being processed. + */ + + +function addProperties(updatePayload, props, validAttributes) { + // TODO: Fast path + return diffProperties(updatePayload, emptyObject$1, props, validAttributes); +} +/** + * clearProperties clears all the previous props by adding a null sentinel + * to the payload for each valid key. + */ + + +function clearProperties(updatePayload, prevProps, validAttributes) { + // TODO: Fast path + return diffProperties(updatePayload, prevProps, emptyObject$1, validAttributes); +} + +function create(props, validAttributes) { + return addProperties(null, // updatePayload + props, validAttributes); +} +function diff(prevProps, nextProps, validAttributes) { + if (enableEarlyReturnForPropDiffing) { + if (prevProps === nextProps) { + return null; // no change + } + } + + return diffProperties(null, // updatePayload + prevProps, nextProps, validAttributes); +} + +/** + * In the future, we should cleanup callbacks by cancelling them instead of + * using this. + */ +function mountSafeCallback_NOT_REALLY_SAFE(context, callback) { + return function () { + if (!callback) { + return undefined; + } // This protects against createClass() components. + // We don't know if there is code depending on it. + // We intentionally don't use isMounted() because even accessing + // isMounted property on a React ES6 class will trigger a warning. + + + if (typeof context.__isMounted === 'boolean') { + if (!context.__isMounted) { + return undefined; + } + } // FIXME: there used to be other branches that protected + // against unmounted host components. But RN host components don't + // define isMounted() anymore, so those checks didn't do anything. + // They caused false positive warning noise so we removed them: + // https://github.com/facebook/react-native/issues/18868#issuecomment-413579095 + // However, this means that the callback is NOT guaranteed to be safe + // for host components. The solution we should implement is to make + // UIManager.measure() and similar calls truly cancelable. Then we + // can change our own code calling them to cancel when something unmounts. + + + return callback.apply(context, arguments); + }; +} +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); } } - function onCommitRoot(root, eventPriority) { - if ( - injectedHook && - typeof injectedHook.onCommitFiberRoot === "function" - ) { - try { - var didError = (root.current.flags & DidCapture) === DidCapture; + } +} - if (enableProfilerTimer) { - var schedulerPriority; +var ReactNativeFiberHostComponent = /*#__PURE__*/function () { + function ReactNativeFiberHostComponent(tag, viewConfig, internalInstanceHandleDEV) { + this._children = void 0; + this._nativeTag = void 0; + this._internalFiberInstanceHandleDEV = void 0; + this.viewConfig = void 0; + this._nativeTag = tag; + this._children = []; + this.viewConfig = viewConfig; - switch (eventPriority) { - case DiscreteEventPriority: - schedulerPriority = ImmediatePriority; - break; + { + this._internalFiberInstanceHandleDEV = internalInstanceHandleDEV; + } + } - case ContinuousEventPriority: - schedulerPriority = UserBlockingPriority; - break; + var _proto = ReactNativeFiberHostComponent.prototype; - case DefaultEventPriority: - schedulerPriority = NormalPriority$1; - break; + _proto.blur = function blur() { + ReactNativePrivateInterface.TextInputState.blurTextInput(this); + }; - case IdleEventPriority: - schedulerPriority = IdlePriority; - break; + _proto.focus = function focus() { + ReactNativePrivateInterface.TextInputState.focusTextInput(this); + }; - default: - schedulerPriority = NormalPriority$1; - break; - } + _proto.measure = function measure(callback) { + ReactNativePrivateInterface.UIManager.measure(this._nativeTag, mountSafeCallback_NOT_REALLY_SAFE(this, callback)); + }; - injectedHook.onCommitFiberRoot( - rendererID, - root, - schedulerPriority, - didError - ); - } - } catch (err) { - { - if (!hasLoggedError) { - hasLoggedError = true; + _proto.measureInWindow = function measureInWindow(callback) { + ReactNativePrivateInterface.UIManager.measureInWindow(this._nativeTag, mountSafeCallback_NOT_REALLY_SAFE(this, callback)); + }; - error("React instrumentation encountered an error: %s", err); - } - } - } + _proto.measureLayout = function measureLayout(relativeToNativeNode, onSuccess, onFail + /* currently unused */ + ) { + var relativeNode; + + if (typeof relativeToNativeNode === 'number') { + // Already a node handle + relativeNode = relativeToNativeNode; + } else { + var nativeNode = relativeToNativeNode; + + if (nativeNode._nativeTag) { + relativeNode = nativeNode._nativeTag; } } - 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); - } - } - } + if (relativeNode == null) { + { + error('Warning: ref.measureLayout must be called with a node handle or a ref to a native component.'); } + + return; } - function onCommitUnmount(fiber) { - if ( - injectedHook && - typeof injectedHook.onCommitFiberUnmount === "function" - ) { - try { - injectedHook.onCommitFiberUnmount(rendererID, fiber); - } catch (err) { - { - if (!hasLoggedError) { - hasLoggedError = true; - error("React instrumentation encountered an error: %s", err); - } - } - } - } + ReactNativePrivateInterface.UIManager.measureLayout(this._nativeTag, relativeNode, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess)); + }; + + _proto.setNativeProps = function setNativeProps(nativeProps) { + { + warnForStyleProps(nativeProps, this.viewConfig.validAttributes); + } + + var updatePayload = create(nativeProps, this.viewConfig.validAttributes); // Avoid the overhead of bridge calls if there's no update. + // This is an expensive no-op for Android, and causes an unnecessary + // view invalidation for certain components (eg RCTTextInput) on iOS. + + if (updatePayload != null) { + ReactNativePrivateInterface.UIManager.updateView(this._nativeTag, this.viewConfig.uiViewClassName, updatePayload); + } + }; + + return ReactNativeFiberHostComponent; +}(); + +// This module only exists as an ESM wrapper around the external CommonJS +var scheduleCallback$3 = 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$1 = Scheduler.unstable_NormalPriority; +var IdlePriority = Scheduler.unstable_IdlePriority; // this doesn't actually exist on the scheduler, but it *does* +// on scheduler/unstable_mock, which we'll need for internal testing + +var log$1 = Scheduler.log; +var unstable_setDisableYieldValue = Scheduler.unstable_setDisableYieldValue; + +// 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[cannot-write] 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 */ } - function setIsStrictModeForDevtools(newIsStrictMode) { - if (consoleManagedByDevToolsDuringStrictMode) { - if (typeof log$1 === "function") { - // We're in a test because Scheduler.log only exists - // in SchedulerMock. To reduce the noise in strict mode tests, - // suppress warnings and disable scheduler yielding during the double render - unstable_setDisableYieldValue(newIsStrictMode); - setSuppressWarning(newIsStrictMode); - } - if (injectedHook && typeof injectedHook.setStrictMode === "function") { - try { - injectedHook.setStrictMode(rendererID, newIsStrictMode); - } catch (err) { - { - if (!hasLoggedError) { - hasLoggedError = true; + disabledDepth++; + } +} +function reenableLogs() { + { + disabledDepth--; - error("React instrumentation encountered an error: %s", err); - } - } - } - } - } else { - if (newIsStrictMode) { - disableLogs(); - } else { - reenableLogs(); - } - } - } // Profiler API hooks + if (disabledDepth === 0) { + /* eslint-disable react-internal/no-production-logging */ + var props = { + configurable: true, + enumerable: true, + writable: true + }; // $FlowFixMe[cannot-write] Flow thinks console is immutable. - function injectProfilingHooks(profilingHooks) { - injectedProfilingHooks = profilingHooks; + 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 */ } - function getLaneLabelMap() { - { - var map = new Map(); - var lane = 1; + if (disabledDepth < 0) { + error('disabledDepth fell below zero. ' + 'This is a bug in React. Please file an issue.'); + } + } +} - for (var index = 0; index < TotalLanes; index++) { - var label = getLabelForLane(lane); - map.set(lane, label); - lane *= 2; - } +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; + } + + var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__; + + 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; + } + + 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://react.dev/link/react-devtools'); + } // DevTools exists, even though it doesn't support Fiber. - return map; - } + + return true; + } + + 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 + }); } - function markCommitStarted(lanes) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markCommitStarted === "function" - ) { - injectedProfilingHooks.markCommitStarted(lanes); - } - } + 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); } - function markCommitStopped() { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markCommitStopped === "function" - ) { - injectedProfilingHooks.markCommitStopped(); + } + + 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; + + error('React instrumentation encountered an error: %s', err); } } } - function markComponentRenderStarted(fiber) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentRenderStarted === - "function" - ) { - injectedProfilingHooks.markComponentRenderStarted(fiber); + } +} +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; + + case ContinuousEventPriority: + schedulerPriority = UserBlockingPriority; + break; + + case DefaultEventPriority: + schedulerPriority = NormalPriority$1; + break; + + case IdleEventPriority: + schedulerPriority = IdlePriority; + break; + + default: + schedulerPriority = NormalPriority$1; + break; } + + injectedHook.onCommitFiberRoot(rendererID, root, schedulerPriority, didError); } - } - function markComponentRenderStopped() { + } catch (err) { { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentRenderStopped === - "function" - ) { - injectedProfilingHooks.markComponentRenderStopped(); + if (!hasLoggedError) { + hasLoggedError = true; + + error('React instrumentation encountered an error: %s', err); } } } - function markComponentPassiveEffectMountStarted(fiber) { + } +} +function onPostCommitRoot(root) { + if (injectedHook && typeof injectedHook.onPostCommitFiberRoot === 'function') { + try { + injectedHook.onPostCommitFiberRoot(rendererID, root); + } catch (err) { { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentPassiveEffectMountStarted === - "function" - ) { - injectedProfilingHooks.markComponentPassiveEffectMountStarted(fiber); + if (!hasLoggedError) { + hasLoggedError = true; + + error('React instrumentation encountered an error: %s', err); } } } - function markComponentPassiveEffectMountStopped() { + } +} +function onCommitUnmount(fiber) { + if (injectedHook && typeof injectedHook.onCommitFiberUnmount === 'function') { + try { + injectedHook.onCommitFiberUnmount(rendererID, fiber); + } catch (err) { { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentPassiveEffectMountStopped === - "function" - ) { - injectedProfilingHooks.markComponentPassiveEffectMountStopped(); + if (!hasLoggedError) { + hasLoggedError = true; + + error('React instrumentation encountered an error: %s', err); } } } - function markComponentPassiveEffectUnmountStarted(fiber) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentPassiveEffectUnmountStarted === - "function" - ) { - injectedProfilingHooks.markComponentPassiveEffectUnmountStarted( - fiber - ); - } - } + } +} +function setIsStrictModeForDevtools(newIsStrictMode) { + if (consoleManagedByDevToolsDuringStrictMode) { + if (typeof log$1 === 'function') { + // We're in a test because Scheduler.log only exists + // in SchedulerMock. To reduce the noise in strict mode tests, + // suppress warnings and disable scheduler yielding during the double render + unstable_setDisableYieldValue(newIsStrictMode); + setSuppressWarning(newIsStrictMode); } - function markComponentPassiveEffectUnmountStopped() { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentPassiveEffectUnmountStopped === - "function" - ) { - injectedProfilingHooks.markComponentPassiveEffectUnmountStopped(); + + if (injectedHook && typeof injectedHook.setStrictMode === 'function') { + try { + injectedHook.setStrictMode(rendererID, newIsStrictMode); + } catch (err) { + { + if (!hasLoggedError) { + hasLoggedError = true; + + error('React instrumentation encountered an error: %s', err); + } } } } - function markComponentLayoutEffectMountStarted(fiber) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentLayoutEffectMountStarted === - "function" - ) { - injectedProfilingHooks.markComponentLayoutEffectMountStarted(fiber); - } - } + } else { + if (newIsStrictMode) { + disableLogs(); + } else { + reenableLogs(); } - function markComponentLayoutEffectMountStopped() { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentLayoutEffectMountStopped === - "function" - ) { - injectedProfilingHooks.markComponentLayoutEffectMountStopped(); - } - } + } +} // Profiler API hooks + +function injectProfilingHooks(profilingHooks) { + injectedProfilingHooks = profilingHooks; +} + +function getLaneLabelMap() { + { + var map = new Map(); + var lane = 1; + + for (var index = 0; index < TotalLanes; index++) { + var label = getLabelForLane(lane); + map.set(lane, label); + lane *= 2; } - function markComponentLayoutEffectUnmountStarted(fiber) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentLayoutEffectUnmountStarted === - "function" - ) { - injectedProfilingHooks.markComponentLayoutEffectUnmountStarted(fiber); - } - } + + return map; + } +} + +function markCommitStarted(lanes) { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markCommitStarted === 'function') { + injectedProfilingHooks.markCommitStarted(lanes); } - function markComponentLayoutEffectUnmountStopped() { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentLayoutEffectUnmountStopped === - "function" - ) { - injectedProfilingHooks.markComponentLayoutEffectUnmountStopped(); - } - } + } +} +function markCommitStopped() { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markCommitStopped === 'function') { + injectedProfilingHooks.markCommitStopped(); } - function markComponentErrored(fiber, thrownValue, lanes) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentErrored === "function" - ) { - injectedProfilingHooks.markComponentErrored( - fiber, - thrownValue, - lanes - ); - } - } + } +} +function markComponentRenderStarted(fiber) { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentRenderStarted === 'function') { + injectedProfilingHooks.markComponentRenderStarted(fiber); } - function markComponentSuspended(fiber, wakeable, lanes) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentSuspended === "function" - ) { - injectedProfilingHooks.markComponentSuspended(fiber, wakeable, lanes); - } - } + } +} +function markComponentRenderStopped() { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentRenderStopped === 'function') { + injectedProfilingHooks.markComponentRenderStopped(); } - function markLayoutEffectsStarted(lanes) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markLayoutEffectsStarted === "function" - ) { - injectedProfilingHooks.markLayoutEffectsStarted(lanes); - } - } + } +} +function markComponentPassiveEffectMountStarted(fiber) { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentPassiveEffectMountStarted === 'function') { + injectedProfilingHooks.markComponentPassiveEffectMountStarted(fiber); } - function markLayoutEffectsStopped() { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markLayoutEffectsStopped === "function" - ) { - injectedProfilingHooks.markLayoutEffectsStopped(); - } - } + } +} +function markComponentPassiveEffectMountStopped() { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentPassiveEffectMountStopped === 'function') { + injectedProfilingHooks.markComponentPassiveEffectMountStopped(); } - function markPassiveEffectsStarted(lanes) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markPassiveEffectsStarted === "function" - ) { - injectedProfilingHooks.markPassiveEffectsStarted(lanes); - } - } + } +} +function markComponentPassiveEffectUnmountStarted(fiber) { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentPassiveEffectUnmountStarted === 'function') { + injectedProfilingHooks.markComponentPassiveEffectUnmountStarted(fiber); } - function markPassiveEffectsStopped() { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markPassiveEffectsStopped === "function" - ) { - injectedProfilingHooks.markPassiveEffectsStopped(); - } - } + } +} +function markComponentPassiveEffectUnmountStopped() { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentPassiveEffectUnmountStopped === 'function') { + injectedProfilingHooks.markComponentPassiveEffectUnmountStopped(); } - function markRenderStarted(lanes) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markRenderStarted === "function" - ) { - injectedProfilingHooks.markRenderStarted(lanes); - } - } + } +} +function markComponentLayoutEffectMountStarted(fiber) { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentLayoutEffectMountStarted === 'function') { + injectedProfilingHooks.markComponentLayoutEffectMountStarted(fiber); } - function markRenderYielded() { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markRenderYielded === "function" - ) { - injectedProfilingHooks.markRenderYielded(); - } - } + } +} +function markComponentLayoutEffectMountStopped() { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentLayoutEffectMountStopped === 'function') { + injectedProfilingHooks.markComponentLayoutEffectMountStopped(); } - function markRenderStopped() { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markRenderStopped === "function" - ) { - injectedProfilingHooks.markRenderStopped(); - } - } + } +} +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 markRenderScheduled(lane) { + } +} +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(); + } + } +} +function markRenderScheduled(lane) { + { + if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markRenderScheduled === 'function') { + injectedProfilingHooks.markRenderScheduled(lane); + } + } +} +function markForceUpdateScheduled(fiber, lane) { + { + 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); + } + } +} + +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 NoStrictPassiveEffectsMode = +/* */ +64; + +// 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. + +var TotalLanes = 31; +var NoLanes = +/* */ +0; +var NoLane = +/* */ +0; +var SyncHydrationLane = +/* */ +1; +var SyncLane = +/* */ +2; +var SyncLaneIndex = 1; +var InputContinuousHydrationLane = +/* */ +4; +var InputContinuousLane = +/* */ +8; +var DefaultHydrationLane = +/* */ +16; +var DefaultLane = +/* */ +32; +var SyncUpdateLanes = enableUnifiedSyncLane ? SyncLane | InputContinuousLane | DefaultLane : SyncLane; +var TransitionHydrationLane = +/* */ +64; +var TransitionLanes = +/* */ +4194176; +var TransitionLane1 = +/* */ +128; +var TransitionLane2 = +/* */ +256; +var TransitionLane3 = +/* */ +512; +var TransitionLane4 = +/* */ +1024; +var TransitionLane5 = +/* */ +2048; +var TransitionLane6 = +/* */ +4096; +var TransitionLane7 = +/* */ +8192; +var TransitionLane8 = +/* */ +16384; +var TransitionLane9 = +/* */ +32768; +var TransitionLane10 = +/* */ +65536; +var TransitionLane11 = +/* */ +131072; +var TransitionLane12 = +/* */ +262144; +var TransitionLane13 = +/* */ +524288; +var TransitionLane14 = +/* */ +1048576; +var TransitionLane15 = +/* */ +2097152; +var RetryLanes = +/* */ +62914560; +var RetryLane1 = +/* */ +4194304; +var RetryLane2 = +/* */ +8388608; +var RetryLane3 = +/* */ +16777216; +var RetryLane4 = +/* */ +33554432; +var SomeRetryLane = RetryLane1; +var SelectiveHydrationLane = +/* */ +67108864; +var NonIdleLanes = +/* */ +134217727; +var IdleHydrationLane = +/* */ +134217728; +var IdleLane = +/* */ +268435456; +var OffscreenLane = +/* */ +536870912; +var DeferredLane = +/* */ +1073741824; // Any lane that might schedule an update. This is used to detect infinite +// update loops, so it doesn't include hydration lanes or retries. + +var UpdateLanes = SyncLane | InputContinuousLane | DefaultLane | TransitionLanes; // This function is used for the experimental timeline (react-devtools-timeline) +// It should be kept in sync with the Lanes values above. + +function getLabelForLane(lane) { + { + if (lane & SyncHydrationLane) { + return 'SyncHydrationLane'; + } + + if (lane & SyncLane) { + return 'Sync'; + } + + if (lane & InputContinuousHydrationLane) { + return 'InputContinuousHydration'; + } + + if (lane & InputContinuousLane) { + return 'InputContinuous'; + } + + if (lane & DefaultHydrationLane) { + return 'DefaultHydration'; + } + + if (lane & DefaultLane) { + return 'Default'; + } + + if (lane & TransitionHydrationLane) { + return 'TransitionHydration'; + } + + if (lane & TransitionLanes) { + return 'Transition'; + } + + if (lane & RetryLanes) { + return 'Retry'; + } + + if (lane & SelectiveHydrationLane) { + return 'SelectiveHydration'; + } + + if (lane & IdleHydrationLane) { + return 'IdleHydration'; + } + + if (lane & IdleLane) { + return 'Idle'; + } + + if (lane & OffscreenLane) { + return 'Offscreen'; + } + + if (lane & DeferredLane) { + return 'Deferred'; + } + } +} +var NoTimestamp = -1; +var nextTransitionLane = TransitionLane1; +var nextRetryLane = RetryLane1; + +function getHighestPriorityLanes(lanes) { + if (enableUnifiedSyncLane) { + var pendingSyncLanes = lanes & SyncUpdateLanes; + + if (pendingSyncLanes !== 0) { + return pendingSyncLanes; + } + } + + switch (getHighestPriorityLane(lanes)) { + case SyncHydrationLane: + return SyncHydrationLane; + + case SyncLane: + return SyncLane; + + case InputContinuousHydrationLane: + return InputContinuousHydrationLane; + + case InputContinuousLane: + return InputContinuousLane; + + case DefaultHydrationLane: + return DefaultHydrationLane; + + case DefaultLane: + return DefaultLane; + + case TransitionHydrationLane: + return TransitionHydrationLane; + + case TransitionLane1: + case TransitionLane2: + case TransitionLane3: + case TransitionLane4: + case TransitionLane5: + case TransitionLane6: + case TransitionLane7: + case TransitionLane8: + case TransitionLane9: + case TransitionLane10: + case TransitionLane11: + case TransitionLane12: + case TransitionLane13: + case TransitionLane14: + case TransitionLane15: + return lanes & TransitionLanes; + + case RetryLane1: + case RetryLane2: + case RetryLane3: + case RetryLane4: + return lanes & RetryLanes; + + case SelectiveHydrationLane: + return SelectiveHydrationLane; + + case IdleHydrationLane: + return IdleHydrationLane; + + case IdleLane: + return IdleLane; + + case OffscreenLane: + return OffscreenLane; + + case DeferredLane: + // This shouldn't be reachable because deferred work is always entangled + // with something else. + return NoLanes; + + default: { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markRenderScheduled === "function" - ) { - injectedProfilingHooks.markRenderScheduled(lane); - } + error('Should have found matching lanes. This is a bug in React.'); + } // This shouldn't be reachable, but as a fallback, return the entire bitmask. + + + return lanes; + } +} + +function getNextLanes(root, wipLanes) { + // Early bailout if there's no pending work left. + var pendingLanes = root.pendingLanes; + + if (pendingLanes === NoLanes) { + return NoLanes; + } + + var nextLanes = NoLanes; + var suspendedLanes = root.suspendedLanes; + var pingedLanes = root.pingedLanes; // Do not work on any idle work until all the non-idle work has finished, + // even if the work is suspended. + + var nonIdlePendingLanes = pendingLanes & NonIdleLanes; + + if (nonIdlePendingLanes !== NoLanes) { + var nonIdleUnblockedLanes = nonIdlePendingLanes & ~suspendedLanes; + + if (nonIdleUnblockedLanes !== NoLanes) { + nextLanes = getHighestPriorityLanes(nonIdleUnblockedLanes); + } else { + var nonIdlePingedLanes = nonIdlePendingLanes & pingedLanes; + + if (nonIdlePingedLanes !== NoLanes) { + nextLanes = getHighestPriorityLanes(nonIdlePingedLanes); } } - function markForceUpdateScheduled(fiber, lane) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markForceUpdateScheduled === "function" - ) { - injectedProfilingHooks.markForceUpdateScheduled(fiber, lane); - } + } else { + // The only remaining work is Idle. + var unblockedLanes = pendingLanes & ~suspendedLanes; + + if (unblockedLanes !== NoLanes) { + nextLanes = getHighestPriorityLanes(unblockedLanes); + } else { + if (pingedLanes !== NoLanes) { + nextLanes = getHighestPriorityLanes(pingedLanes); } } - function markStateUpdateScheduled(fiber, lane) { - { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markStateUpdateScheduled === "function" - ) { - injectedProfilingHooks.markStateUpdateScheduled(fiber, lane); - } - } - } - - 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 NoStrictPassiveEffectsMode = - /* */ - 64; - - // 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. - - var TotalLanes = 31; - var NoLanes = - /* */ - 0; - var NoLane = - /* */ - 0; - var SyncHydrationLane = - /* */ - 1; - var SyncLane = - /* */ - 2; - var SyncLaneIndex = 1; - var InputContinuousHydrationLane = - /* */ - 4; - var InputContinuousLane = - /* */ - 8; - var DefaultHydrationLane = - /* */ - 16; - var DefaultLane = - /* */ - 32; - var SyncUpdateLanes = enableUnifiedSyncLane - ? SyncLane | InputContinuousLane | DefaultLane - : SyncLane; - var TransitionHydrationLane = - /* */ - 64; - var TransitionLanes = - /* */ - 4194176; - var TransitionLane1 = - /* */ - 128; - var TransitionLane2 = - /* */ - 256; - var TransitionLane3 = - /* */ - 512; - var TransitionLane4 = - /* */ - 1024; - var TransitionLane5 = - /* */ - 2048; - var TransitionLane6 = - /* */ - 4096; - var TransitionLane7 = - /* */ - 8192; - var TransitionLane8 = - /* */ - 16384; - var TransitionLane9 = - /* */ - 32768; - var TransitionLane10 = - /* */ - 65536; - var TransitionLane11 = - /* */ - 131072; - var TransitionLane12 = - /* */ - 262144; - var TransitionLane13 = - /* */ - 524288; - var TransitionLane14 = - /* */ - 1048576; - var TransitionLane15 = - /* */ - 2097152; - var RetryLanes = - /* */ - 62914560; - var RetryLane1 = - /* */ - 4194304; - var RetryLane2 = - /* */ - 8388608; - var RetryLane3 = - /* */ - 16777216; - var RetryLane4 = - /* */ - 33554432; - var SomeRetryLane = RetryLane1; - var SelectiveHydrationLane = - /* */ - 67108864; - var NonIdleLanes = - /* */ - 134217727; - var IdleHydrationLane = - /* */ - 134217728; - var IdleLane = - /* */ - 268435456; - var OffscreenLane = - /* */ - 536870912; - var DeferredLane = - /* */ - 1073741824; // Any lane that might schedule an update. This is used to detect infinite - // update loops, so it doesn't include hydration lanes or retries. - - var UpdateLanes = - SyncLane | InputContinuousLane | DefaultLane | TransitionLanes; // This function is used for the experimental timeline (react-devtools-timeline) - // It should be kept in sync with the Lanes values above. - - function getLabelForLane(lane) { - { - if (lane & SyncHydrationLane) { - return "SyncHydrationLane"; - } + } - if (lane & SyncLane) { - return "Sync"; - } + if (nextLanes === NoLanes) { + // This should only be reachable if we're suspended + // TODO: Consider warning in this path if a fallback timer is not scheduled. + return NoLanes; + } // If we're already in the middle of a render, switching lanes will interrupt + // it and we'll lose our progress. We should only do this if the new lanes are + // higher priority. - if (lane & InputContinuousHydrationLane) { - return "InputContinuousHydration"; - } - if (lane & InputContinuousLane) { - return "InputContinuous"; - } + if (wipLanes !== NoLanes && wipLanes !== nextLanes && // If we already suspended with a delay, then interrupting is fine. Don't + // bother waiting until the root is complete. + (wipLanes & suspendedLanes) === NoLanes) { + var nextLane = getHighestPriorityLane(nextLanes); + var wipLane = getHighestPriorityLane(wipLanes); - if (lane & DefaultHydrationLane) { - return "DefaultHydration"; - } + if ( // Tests whether the next lane is equal or lower priority than the wip + // one. This works because the bits decrease in priority as you go left. + nextLane >= wipLane || // Default priority updates should not interrupt transition updates. The + // only difference between default updates and transition updates is that + // default updates do not support refresh transitions. + nextLane === DefaultLane && (wipLane & TransitionLanes) !== NoLanes) { + // Keep working on the existing in-progress tree. Do not interrupt. + return wipLanes; + } + } - if (lane & DefaultLane) { - return "Default"; - } + return nextLanes; +} +function getEntangledLanes(root, renderLanes) { + var entangledLanes = renderLanes; + + if ((entangledLanes & InputContinuousLane) !== NoLanes) { + // When updates are sync by default, we entangle continuous priority updates + // and default updates, so they render in the same batch. The only reason + // they use separate lanes is because continuous updates should interrupt + // transitions, but default updates should not. + entangledLanes |= entangledLanes & DefaultLane; + } // Check for entangled lanes and add them to the batch. + // + // A lane is said to be entangled with another when it's not allowed to render + // in a batch that does not also include the other lane. Typically we do this + // when multiple updates have the same source, and we only want to respond to + // the most recent event from that source. + // + // Note that we apply entanglements *after* checking for partial work above. + // This means that if a lane is entangled during an interleaved event while + // it's already rendering, we won't interrupt it. This is intentional, since + // entanglement is usually "best effort": we'll try our best to render the + // lanes in the same batch, but it's not worth throwing out partially + // completed work in order to do it. + // TODO: Reconsider this. The counter-argument is that the partial work + // represents an intermediate state, which we don't want to show to the user. + // And by spending extra time finishing it, we're increasing the amount of + // time it takes to show the final state, which is what they are actually + // waiting for. + // + // For those exceptions where entanglement is semantically important, + // we should ensure that there is no partial work at the + // time we apply the entanglement. + + + var allEntangledLanes = root.entangledLanes; + + if (allEntangledLanes !== NoLanes) { + var entanglements = root.entanglements; + var lanes = entangledLanes & allEntangledLanes; + + while (lanes > 0) { + var index = pickArbitraryLaneIndex(lanes); + var lane = 1 << index; + entangledLanes |= entanglements[index]; + lanes &= ~lane; + } + } + + return entangledLanes; +} - if (lane & TransitionHydrationLane) { - return "TransitionHydration"; - } +function computeExpirationTime(lane, currentTime) { + switch (lane) { + case SyncHydrationLane: + case SyncLane: + case InputContinuousHydrationLane: + case InputContinuousLane: + // User interactions should expire slightly more quickly. + // + // NOTE: This is set to the corresponding constant as in Scheduler.js. + // When we made it larger, a product metric in www regressed, suggesting + // there's a user interaction that's being starved by a series of + // synchronous updates. If that theory is correct, the proper solution is + // to fix the starvation. However, this scenario supports the idea that + // expiration times are an important safeguard when starvation + // does happen. + return currentTime + syncLaneExpirationMs; + + case DefaultHydrationLane: + case DefaultLane: + case TransitionHydrationLane: + case TransitionLane1: + case TransitionLane2: + case TransitionLane3: + case TransitionLane4: + case TransitionLane5: + case TransitionLane6: + case TransitionLane7: + case TransitionLane8: + case TransitionLane9: + case TransitionLane10: + case TransitionLane11: + case TransitionLane12: + case TransitionLane13: + case TransitionLane14: + case TransitionLane15: + return currentTime + transitionLaneExpirationMs; + + case RetryLane1: + case RetryLane2: + case RetryLane3: + case RetryLane4: + // TODO: Retries should be allowed to expire if they are CPU bound for + // too long, but when I made this change it caused a spike in browser + // crashes. There must be some other underlying bug; not super urgent but + // ideally should figure out why and fix it. Unfortunately we don't have + // a repro for the crashes, only detected via production metrics. + return NoTimestamp; + + case SelectiveHydrationLane: + case IdleHydrationLane: + case IdleLane: + case OffscreenLane: + case DeferredLane: + // Anything idle priority or lower should never expire. + return NoTimestamp; + + default: + { + error('Should have found matching lanes. This is a bug in React.'); + } + + return NoTimestamp; + } +} - if (lane & TransitionLanes) { - return "Transition"; - } +function markStarvedLanesAsExpired(root, currentTime) { + // TODO: This gets called every time we yield. We can optimize by storing + // the earliest expiration time on the root. Then use that to quickly bail out + // of this function. + var pendingLanes = root.pendingLanes; + var suspendedLanes = root.suspendedLanes; + var pingedLanes = root.pingedLanes; + var expirationTimes = root.expirationTimes; // Iterate through the pending lanes and check if we've reached their + // expiration time. If so, we'll assume the update is being starved and mark + // it as expired to force it to finish. + // TODO: We should be able to replace this with upgradePendingLanesToSync + // + // We exclude retry lanes because those must always be time sliced, in order + // to unwrap uncached promises. + // TODO: Write a test for this + + var lanes = pendingLanes & ~RetryLanes; + + while (lanes > 0) { + var index = pickArbitraryLaneIndex(lanes); + var lane = 1 << index; + var expirationTime = expirationTimes[index]; + + if (expirationTime === NoTimestamp) { + // Found a pending lane with no expiration time. If it's not suspended, or + // if it's pinged, assume it's CPU-bound. Compute a new expiration time + // using the current time. + if ((lane & suspendedLanes) === NoLanes || (lane & pingedLanes) !== NoLanes) { + // Assumes timestamps are monotonically increasing. + expirationTimes[index] = computeExpirationTime(lane, currentTime); + } + } else if (expirationTime <= currentTime) { + // This lane expired + root.expiredLanes |= lane; + } + + lanes &= ~lane; + } +} // This returns the highest priority pending lanes regardless of whether they +function getLanesToRetrySynchronouslyOnError(root, originallyAttemptedLanes) { + if (root.errorRecoveryDisabledLanes & originallyAttemptedLanes) { + // The error recovery mechanism is disabled until these lanes are cleared. + return NoLanes; + } + + var everythingButOffscreen = root.pendingLanes & ~OffscreenLane; + + if (everythingButOffscreen !== NoLanes) { + return everythingButOffscreen; + } + + if (everythingButOffscreen & OffscreenLane) { + return OffscreenLane; + } + + return NoLanes; +} +function includesSyncLane(lanes) { + return (lanes & (SyncLane | SyncHydrationLane)) !== NoLanes; +} +function includesNonIdleWork(lanes) { + return (lanes & NonIdleLanes) !== NoLanes; +} +function includesOnlyRetries(lanes) { + return (lanes & RetryLanes) === lanes; +} +function includesOnlyNonUrgentLanes(lanes) { + // TODO: Should hydration lanes be included here? This function is only + // used in `updateDeferredValueImpl`. + var UrgentLanes = SyncLane | InputContinuousLane | DefaultLane; + return (lanes & UrgentLanes) === NoLanes; +} +function includesOnlyTransitions(lanes) { + return (lanes & TransitionLanes) === lanes; +} +function includesBlockingLane(root, lanes) { - if (lane & RetryLanes) { - return "Retry"; - } + var SyncDefaultLanes = InputContinuousHydrationLane | InputContinuousLane | DefaultHydrationLane | DefaultLane; + return (lanes & SyncDefaultLanes) !== NoLanes; +} +function includesExpiredLane(root, lanes) { + // This is a separate check from includesBlockingLane because a lane can + // expire after a render has already started. + return (lanes & root.expiredLanes) !== NoLanes; +} +function isTransitionLane(lane) { + return (lane & TransitionLanes) !== NoLanes; +} +function claimNextTransitionLane() { + // Cycle through the lanes, assigning each new transition to the next lane. + // In most cases, this means every transition gets its own lane, until we + // run out of lanes and cycle back to the beginning. + var lane = nextTransitionLane; + nextTransitionLane <<= 1; + + if ((nextTransitionLane & TransitionLanes) === NoLanes) { + nextTransitionLane = TransitionLane1; + } + + return lane; +} +function claimNextRetryLane() { + var lane = nextRetryLane; + nextRetryLane <<= 1; - if (lane & SelectiveHydrationLane) { - return "SelectiveHydration"; - } + if ((nextRetryLane & RetryLanes) === NoLanes) { + nextRetryLane = RetryLane1; + } - if (lane & IdleHydrationLane) { - return "IdleHydration"; - } + return lane; +} +function getHighestPriorityLane(lanes) { + return lanes & -lanes; +} +function pickArbitraryLane(lanes) { + // This wrapper function gets inlined. Only exists so to communicate that it + // doesn't matter which bit is selected; you can pick any bit without + // affecting the algorithms where its used. Here I'm using + // getHighestPriorityLane because it requires the fewest operations. + return getHighestPriorityLane(lanes); +} - if (lane & IdleLane) { - return "Idle"; - } +function pickArbitraryLaneIndex(lanes) { + return 31 - clz32(lanes); +} - if (lane & OffscreenLane) { - return "Offscreen"; - } +function laneToIndex(lane) { + return pickArbitraryLaneIndex(lane); +} + +function includesSomeLane(a, b) { + return (a & b) !== NoLanes; +} +function isSubsetOfLanes(set, subset) { + return (set & subset) === subset; +} +function mergeLanes(a, b) { + return a | b; +} +function removeLanes(set, subset) { + return set & ~subset; +} +function intersectLanes(a, b) { + return a & b; +} // Seems redundant, but it changes the type from a single lane (used for +// updates) to a group of lanes (used for flushing work). + +function laneToLanes(lane) { + return lane; +} +function createLaneMap(initial) { + // Intentionally pushing one by one. + // https://v8.dev/blog/elements-kinds#avoid-creating-holes + var laneMap = []; + + for (var i = 0; i < TotalLanes; i++) { + laneMap.push(initial); + } - if (lane & DeferredLane) { - return "Deferred"; + return laneMap; +} +function markRootUpdated$1(root, updateLane) { + root.pendingLanes |= updateLane; // If there are any suspended transitions, it's possible this new update + // could unblock them. Clear the suspended lanes so that we can try rendering + // them again. + // + // TODO: We really only need to unsuspend only lanes that are in the + // `subtreeLanes` of the updated fiber, or the update lanes of the return + // path. This would exclude suspended updates in an unrelated sibling tree, + // since there's no way for this update to unblock it. + // + // We don't do this if the incoming update is idle, because we never process + // idle updates until after all the regular updates have finished; there's no + // way it could unblock a transition. + + if (updateLane !== IdleLane) { + root.suspendedLanes = NoLanes; + root.pingedLanes = NoLanes; + } +} +function markRootSuspended$1(root, suspendedLanes, spawnedLane) { + root.suspendedLanes |= suspendedLanes; + root.pingedLanes &= ~suspendedLanes; // The suspended lanes are no longer CPU-bound. Clear their expiration times. + + var expirationTimes = root.expirationTimes; + var lanes = suspendedLanes; + + while (lanes > 0) { + var index = pickArbitraryLaneIndex(lanes); + var lane = 1 << index; + expirationTimes[index] = NoTimestamp; + lanes &= ~lane; + } + + if (spawnedLane !== NoLane) { + markSpawnedDeferredLane(root, spawnedLane, suspendedLanes); + } +} +function markRootPinged$1(root, pingedLanes) { + root.pingedLanes |= root.suspendedLanes & pingedLanes; +} +function markRootFinished(root, remainingLanes, spawnedLane) { + var noLongerPendingLanes = root.pendingLanes & ~remainingLanes; + root.pendingLanes = remainingLanes; // Let's try everything again + + root.suspendedLanes = NoLanes; + root.pingedLanes = NoLanes; + root.expiredLanes &= remainingLanes; + root.entangledLanes &= remainingLanes; + root.errorRecoveryDisabledLanes &= remainingLanes; + root.shellSuspendCounter = 0; + var entanglements = root.entanglements; + var expirationTimes = root.expirationTimes; + var hiddenUpdates = root.hiddenUpdates; // Clear the lanes that no longer have pending work + + var lanes = noLongerPendingLanes; + + while (lanes > 0) { + var index = pickArbitraryLaneIndex(lanes); + var lane = 1 << index; + entanglements[index] = NoLanes; + expirationTimes[index] = NoTimestamp; + var hiddenUpdatesForLane = hiddenUpdates[index]; + + if (hiddenUpdatesForLane !== null) { + hiddenUpdates[index] = null; // "Hidden" updates are updates that were made to a hidden component. They + // have special logic associated with them because they may be entangled + // with updates that occur outside that tree. But once the outer tree + // commits, they behave like regular updates. + + for (var i = 0; i < hiddenUpdatesForLane.length; i++) { + var update = hiddenUpdatesForLane[i]; + + if (update !== null) { + update.lane &= ~OffscreenLane; } } } - var NoTimestamp = -1; - var nextTransitionLane = TransitionLane1; - var nextRetryLane = RetryLane1; - function getHighestPriorityLanes(lanes) { - if (enableUnifiedSyncLane) { - var pendingSyncLanes = lanes & SyncUpdateLanes; + lanes &= ~lane; + } + + if (spawnedLane !== NoLane) { + markSpawnedDeferredLane(root, spawnedLane, // This render finished successfully without suspending, so we don't need + // to entangle the spawned task with the parent task. + NoLanes); + } +} + +function markSpawnedDeferredLane(root, spawnedLane, entangledLanes) { + // This render spawned a deferred task. Mark it as pending. + root.pendingLanes |= spawnedLane; + root.suspendedLanes &= ~spawnedLane; // Entangle the spawned lane with the DeferredLane bit so that we know it + // was the result of another render. This lets us avoid a useDeferredValue + // waterfall — only the first level will defer. + + var spawnedLaneIndex = laneToIndex(spawnedLane); + root.entangledLanes |= spawnedLane; + root.entanglements[spawnedLaneIndex] |= DeferredLane | // If the parent render task suspended, we must also entangle those lanes + // with the spawned task, so that the deferred task includes all the same + // updates that the parent task did. We can exclude any lane that is not + // used for updates (e.g. Offscreen). + entangledLanes & UpdateLanes; +} + +function markRootEntangled(root, entangledLanes) { + // In addition to entangling each of the given lanes with each other, we also + // have to consider _transitive_ entanglements. For each lane that is already + // entangled with *any* of the given lanes, that lane is now transitively + // entangled with *all* the given lanes. + // + // Translated: If C is entangled with A, then entangling A with B also + // entangles C with B. + // + // If this is hard to grasp, it might help to intentionally break this + // function and look at the tests that fail in ReactTransition-test.js. Try + // commenting out one of the conditions below. + var rootEntangledLanes = root.entangledLanes |= entangledLanes; + var entanglements = root.entanglements; + var lanes = rootEntangledLanes; + + while (lanes) { + var index = pickArbitraryLaneIndex(lanes); + var lane = 1 << index; + + if ( // Is this one of the newly entangled lanes? + lane & entangledLanes | // Is this lane transitively entangled with the newly entangled lanes? + entanglements[index] & entangledLanes) { + entanglements[index] |= entangledLanes; + } + + lanes &= ~lane; + } +} +function upgradePendingLaneToSync(root, lane) { + // Since we're upgrading the priority of the given lane, there is now pending + // sync work. + root.pendingLanes |= SyncLane; // Entangle the sync lane with the lane we're upgrading. This means SyncLane + // will not be allowed to finish without also finishing the given lane. + + root.entangledLanes |= SyncLane; + root.entanglements[SyncLaneIndex] |= lane; +} +function markHiddenUpdate(root, update, lane) { + var index = laneToIndex(lane); + var hiddenUpdates = root.hiddenUpdates; + var hiddenUpdatesForLane = hiddenUpdates[index]; + + if (hiddenUpdatesForLane === null) { + hiddenUpdates[index] = [update]; + } else { + hiddenUpdatesForLane.push(update); + } + + update.lane = lane | OffscreenLane; +} +function getBumpedLaneForHydration(root, renderLanes) { + var renderLane = getHighestPriorityLane(renderLanes); + var lane; + + if (enableUnifiedSyncLane && (renderLane & SyncUpdateLanes) !== NoLane) { + lane = SyncHydrationLane; + } else { + switch (renderLane) { + case SyncLane: + lane = SyncHydrationLane; + break; + + case InputContinuousLane: + lane = InputContinuousHydrationLane; + break; + + case DefaultLane: + lane = DefaultHydrationLane; + break; + + case TransitionLane1: + case TransitionLane2: + case TransitionLane3: + case TransitionLane4: + case TransitionLane5: + case TransitionLane6: + case TransitionLane7: + case TransitionLane8: + case TransitionLane9: + case TransitionLane10: + case TransitionLane11: + case TransitionLane12: + case TransitionLane13: + case TransitionLane14: + case TransitionLane15: + case RetryLane1: + case RetryLane2: + case RetryLane3: + case RetryLane4: + lane = TransitionHydrationLane; + break; + + case IdleLane: + lane = IdleHydrationLane; + break; + + default: + // Everything else is already either a hydration lane, or shouldn't + // be retried at a hydration lane. + lane = NoLane; + break; + } + } // Check if the lane we chose is suspended. If so, that indicates that we + // already attempted and failed to hydrate at that level. Also check if we're + // already rendering that lane, which is rare but could happen. + + + if ((lane & (root.suspendedLanes | renderLanes)) !== NoLane) { + // Give up trying to hydrate and fall back to client render. + return NoLane; + } + + return lane; +} +function addFiberToLanesMap(root, fiber, lanes) { + + if (!isDevToolsPresent) { + return; + } + + var pendingUpdatersLaneMap = root.pendingUpdatersLaneMap; + + while (lanes > 0) { + var index = laneToIndex(lanes); + var lane = 1 << index; + var updaters = pendingUpdatersLaneMap[index]; + updaters.add(fiber); + lanes &= ~lane; + } +} +function movePendingFibersToMemoized(root, lanes) { + + if (!isDevToolsPresent) { + return; + } - if (pendingSyncLanes !== 0) { - return pendingSyncLanes; + var pendingUpdatersLaneMap = root.pendingUpdatersLaneMap; + var memoizedUpdaters = root.memoizedUpdaters; + + while (lanes > 0) { + var index = laneToIndex(lanes); + var lane = 1 << index; + var updaters = pendingUpdatersLaneMap[index]; + + if (updaters.size > 0) { + updaters.forEach(function (fiber) { + var alternate = fiber.alternate; + + if (alternate === null || !memoizedUpdaters.has(alternate)) { + memoizedUpdaters.add(fiber); } - } + }); + updaters.clear(); + } + + lanes &= ~lane; + } +} +function getTransitionsForLanes(root, lanes) { + { + return null; + } +} - switch (getHighestPriorityLane(lanes)) { - case SyncHydrationLane: - return SyncHydrationLane; +var NoEventPriority = NoLane; +var DiscreteEventPriority = SyncLane; +var ContinuousEventPriority = InputContinuousLane; +var DefaultEventPriority = DefaultLane; +var IdleEventPriority = IdleLane; +function higherEventPriority(a, b) { + return a !== 0 && a < b ? a : b; +} +function lowerEventPriority(a, b) { + return a === 0 || a > b ? a : b; +} +function isHigherEventPriority(a, b) { + return a !== 0 && a < b; +} +function eventPriorityToLane(updatePriority) { + return updatePriority; +} +function lanesToEventPriority(lanes) { + var lane = getHighestPriorityLane(lanes); - case SyncLane: - return SyncLane; + if (!isHigherEventPriority(DiscreteEventPriority, lane)) { + return DiscreteEventPriority; + } - case InputContinuousHydrationLane: - return InputContinuousHydrationLane; + if (!isHigherEventPriority(ContinuousEventPriority, lane)) { + return ContinuousEventPriority; + } - case InputContinuousLane: - return InputContinuousLane; + if (includesNonIdleWork(lane)) { + return DefaultEventPriority; + } - case DefaultHydrationLane: - return DefaultHydrationLane; + return IdleEventPriority; +} - case DefaultLane: - return DefaultLane; +// Renderers that don't support hydration +// can re-export everything from this module. +function shim$1() { + 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 supportsHydration = false; +var isSuspenseInstancePending = shim$1; +var isSuspenseInstanceFallback = shim$1; +var getSuspenseInstanceFallbackErrorDetails = shim$1; +var registerSuspenseInstanceRetry = shim$1; +var clearSuspenseBoundary = shim$1; +var clearSuspenseBoundaryFromContainer = shim$1; + +// Renderers that don't support hydration +// can re-export everything from this module. +function shim() { + throw new Error('The current renderer does not support Resources. ' + 'This error is likely caused by a bug in React. ' + 'Please file an issue.'); +} // Resources (when unsupported) +var suspendResource = shim; + +var getViewConfigForType = ReactNativePrivateInterface.ReactNativeViewConfigRegistry.get; // Unused +// Unused +// Counter for uniquely identifying views. +// % 10 === 1 means it is a rootTag. +// % 2 === 0 means it is a Fabric tag. + +var nextReactTag = 3; + +function allocateTag() { + var tag = nextReactTag; + + if (tag % 10 === 1) { + tag += 2; + } + + nextReactTag = tag + 2; + return tag; +} - case TransitionHydrationLane: - return TransitionHydrationLane; +function recursivelyUncacheFiberNode(node) { + if (typeof node === 'number') { + // Leaf node (eg text) + uncacheFiberNode(node); + } else { + uncacheFiberNode(node._nativeTag); - case TransitionLane1: - case TransitionLane2: - case TransitionLane3: - case TransitionLane4: - case TransitionLane5: - case TransitionLane6: - case TransitionLane7: - case TransitionLane8: - case TransitionLane9: - case TransitionLane10: - case TransitionLane11: - case TransitionLane12: - case TransitionLane13: - case TransitionLane14: - case TransitionLane15: - return lanes & TransitionLanes; + node._children.forEach(recursivelyUncacheFiberNode); + } +} +function appendInitialChild(parentInstance, child) { + parentInstance._children.push(child); +} +function createInstance(type, props, rootContainerInstance, hostContext, internalInstanceHandle) { + var tag = allocateTag(); + var viewConfig = getViewConfigForType(type); + + { + for (var key in viewConfig.validAttributes) { + if (props.hasOwnProperty(key)) { + ReactNativePrivateInterface.deepFreezeAndThrowOnMutationInDev(props[key]); + } + } + } + + var updatePayload = create(props, viewConfig.validAttributes); + ReactNativePrivateInterface.UIManager.createView(tag, // reactTag + viewConfig.uiViewClassName, // viewName + rootContainerInstance, // rootTag + updatePayload // props + ); + var component = new ReactNativeFiberHostComponent(tag, viewConfig, internalInstanceHandle); + precacheFiberNode(internalInstanceHandle, tag); + updateFiberProps(tag, props); // Not sure how to avoid this cast. Flow is okay if the component is defined + // in the same file but if it's external it can't see the types. + + return component; +} +function createTextInstance(text, rootContainerInstance, hostContext, internalInstanceHandle) { + if (!hostContext.isInAParentText) { + throw new Error('Text strings must be rendered within a component.'); + } + + var tag = allocateTag(); + ReactNativePrivateInterface.UIManager.createView(tag, // reactTag + 'RCTRawText', // viewName + rootContainerInstance, // rootTag + { + text: text + } // props + ); + precacheFiberNode(internalInstanceHandle, tag); + return tag; +} +function finalizeInitialChildren(parentInstance, type, props, hostContext) { + // Don't send a no-op message over the bridge. + if (parentInstance._children.length === 0) { + return false; + } // Map from child objects to native tags. + // Either way we need to pass a copy of the Array to prevent it from being frozen. + + + var nativeTags = parentInstance._children.map(function (child) { + return typeof child === 'number' ? child // Leaf node (eg text) + : child._nativeTag; + }); + + ReactNativePrivateInterface.UIManager.setChildren(parentInstance._nativeTag, // containerTag + nativeTags // reactTags + ); + return false; +} +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'; + + if (prevIsInAParentText !== isInAParentText) { + return { + isInAParentText: isInAParentText + }; + } else { + return parentHostContext; + } +} +function getPublicInstance(instance) { + // $FlowExpectedError[prop-missing] For compatibility with Fabric + if (instance.canonical != null && instance.canonical.publicInstance != null) { + // $FlowFixMe[incompatible-return] + return instance.canonical.publicInstance; + } + + return instance; +} +var scheduleTimeout = setTimeout; +var cancelTimeout = clearTimeout; +var noTimeout = -1; +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 currentUpdatePriority = NoEventPriority; +function setCurrentUpdatePriority(newPriority) { + currentUpdatePriority = newPriority; +} +function getCurrentUpdatePriority() { + return currentUpdatePriority; +} +function resolveUpdatePriority() { + if (currentUpdatePriority !== NoEventPriority) { + return currentUpdatePriority; + } - case RetryLane1: - case RetryLane2: - case RetryLane3: - case RetryLane4: - return lanes & RetryLanes; + return DefaultEventPriority; +} +function shouldAttemptEagerTransition() { + return false; +} // ------------------- +function appendChild(parentInstance, child) { + var childTag = typeof child === 'number' ? child : child._nativeTag; + var children = parentInstance._children; + var index = children.indexOf(child); + + if (index >= 0) { + children.splice(index, 1); + children.push(child); + ReactNativePrivateInterface.UIManager.manageChildren(parentInstance._nativeTag, // containerTag + [index], // moveFromIndices + [children.length - 1], // moveToIndices + [], // addChildReactTags + [], // addAtIndices + [] // removeAtIndices + ); + } else { + children.push(child); + ReactNativePrivateInterface.UIManager.manageChildren(parentInstance._nativeTag, // containerTag + [], // moveFromIndices + [], // moveToIndices + [childTag], // addChildReactTags + [children.length - 1], // addAtIndices + [] // removeAtIndices + ); + } +} +function appendChildToContainer(parentInstance, child) { + var childTag = typeof child === 'number' ? child : child._nativeTag; + ReactNativePrivateInterface.UIManager.setChildren(parentInstance, // containerTag + [childTag] // reactTags + ); +} +function commitTextUpdate(textInstance, oldText, newText) { + ReactNativePrivateInterface.UIManager.updateView(textInstance, // reactTag + 'RCTRawText', // viewName + { + text: newText + } // props + ); +} +function commitMount(instance, type, newProps, internalInstanceHandle) {// Noop +} +function commitUpdate(instance, updatePayloadTODO, type, oldProps, newProps, internalInstanceHandle) { + var viewConfig = instance.viewConfig; + updateFiberProps(instance._nativeTag, newProps); + var updatePayload = diff(oldProps, newProps, viewConfig.validAttributes); // Avoid the overhead of bridge calls if there's no update. + // This is an expensive no-op for Android, and causes an unnecessary + // view invalidation for certain components (eg RCTTextInput) on iOS. + + if (updatePayload != null) { + ReactNativePrivateInterface.UIManager.updateView(instance._nativeTag, // reactTag + viewConfig.uiViewClassName, // viewName + updatePayload // props + ); + } +} +function insertBefore(parentInstance, child, beforeChild) { + var children = parentInstance._children; + var index = children.indexOf(child); // Move existing child or add new child? + + if (index >= 0) { + children.splice(index, 1); + var beforeChildIndex = children.indexOf(beforeChild); + children.splice(beforeChildIndex, 0, child); + ReactNativePrivateInterface.UIManager.manageChildren(parentInstance._nativeTag, // containerID + [index], // moveFromIndices + [beforeChildIndex], // moveToIndices + [], // addChildReactTags + [], // addAtIndices + [] // removeAtIndices + ); + } else { + var _beforeChildIndex = children.indexOf(beforeChild); + + children.splice(_beforeChildIndex, 0, child); + var childTag = typeof child === 'number' ? child : child._nativeTag; + ReactNativePrivateInterface.UIManager.manageChildren(parentInstance._nativeTag, // containerID + [], // moveFromIndices + [], // moveToIndices + [childTag], // addChildReactTags + [_beforeChildIndex], // addAtIndices + [] // removeAtIndices + ); + } +} +function insertInContainerBefore(parentInstance, child, beforeChild) { + // TODO (bvaughn): Remove this check when... + // We create a wrapper object for the container in ReactNative render() + // Or we refactor to remove wrapper objects entirely. + // For more info on pros/cons see PR #8560 description. + if (typeof parentInstance === 'number') { + throw new Error('Container does not support insertBefore operation'); + } +} +function removeChild(parentInstance, child) { + recursivelyUncacheFiberNode(child); + var children = parentInstance._children; + var index = children.indexOf(child); + children.splice(index, 1); + ReactNativePrivateInterface.UIManager.manageChildren(parentInstance._nativeTag, // containerID + [], // moveFromIndices + [], // moveToIndices + [], // addChildReactTags + [], // addAtIndices + [index] // removeAtIndices + ); +} +function removeChildFromContainer(parentInstance, child) { + recursivelyUncacheFiberNode(child); + ReactNativePrivateInterface.UIManager.manageChildren(parentInstance, // containerID + [], // moveFromIndices + [], // moveToIndices + [], // addChildReactTags + [], // addAtIndices + [0] // removeAtIndices + ); +} +function resetTextContent(instance) {// Noop +} +function hideInstance(instance) { + var viewConfig = instance.viewConfig; + var updatePayload = create({ + style: { + display: 'none' + } + }, viewConfig.validAttributes); + ReactNativePrivateInterface.UIManager.updateView(instance._nativeTag, viewConfig.uiViewClassName, updatePayload); +} +function hideTextInstance(textInstance) { + throw new Error('Not yet implemented.'); +} +function unhideInstance(instance, props) { + var viewConfig = instance.viewConfig; + var updatePayload = diff(assign({}, props, { + style: [props.style, { + display: 'none' + }] + }), props, viewConfig.validAttributes); + ReactNativePrivateInterface.UIManager.updateView(instance._nativeTag, viewConfig.uiViewClassName, updatePayload); +} +function unhideTextInstance(textInstance, text) { + throw new Error('Not yet implemented.'); +} +function preloadInstance(type, props) { + // Return true to indicate it's already loaded + return true; +} +function waitForCommitToBeReady() { + return null; +} +var NotPendingTransition = null; - case SelectiveHydrationLane: - return SelectiveHydrationLane; +var valueStack = []; +var fiberStack; - case IdleHydrationLane: - return IdleHydrationLane; +{ + fiberStack = []; +} - case IdleLane: - return IdleLane; +var index = -1; - case OffscreenLane: - return OffscreenLane; +function createCursor(defaultValue) { + return { + current: defaultValue + }; +} - case DeferredLane: - // This shouldn't be reachable because deferred work is always entangled - // with something else. - return NoLanes; +function pop(cursor, fiber) { + if (index < 0) { + { + error('Unexpected pop.'); + } - default: - { - error("Should have found matching lanes. This is a bug in React."); - } // This shouldn't be reachable, but as a fallback, return the entire bitmask. + return; + } - return lanes; - } + { + if (fiber !== fiberStack[index]) { + error('Unexpected Fiber popped.'); } + } - function getNextLanes(root, wipLanes) { - // Early bailout if there's no pending work left. - var pendingLanes = root.pendingLanes; + cursor.current = valueStack[index]; + valueStack[index] = null; - if (pendingLanes === NoLanes) { - return NoLanes; - } + { + fiberStack[index] = null; + } - var nextLanes = NoLanes; - var suspendedLanes = root.suspendedLanes; - var pingedLanes = root.pingedLanes; // Do not work on any idle work until all the non-idle work has finished, - // even if the work is suspended. + index--; +} - var nonIdlePendingLanes = pendingLanes & NonIdleLanes; +function push(cursor, value, fiber) { + index++; + valueStack[index] = cursor.current; - if (nonIdlePendingLanes !== NoLanes) { - var nonIdleUnblockedLanes = nonIdlePendingLanes & ~suspendedLanes; + { + fiberStack[index] = fiber; + } - if (nonIdleUnblockedLanes !== NoLanes) { - nextLanes = getHighestPriorityLanes(nonIdleUnblockedLanes); - } else { - var nonIdlePingedLanes = nonIdlePendingLanes & pingedLanes; + cursor.current = value; +} - if (nonIdlePingedLanes !== NoLanes) { - nextLanes = getHighestPriorityLanes(nonIdlePingedLanes); - } - } - } else { - // The only remaining work is Idle. - var unblockedLanes = pendingLanes & ~suspendedLanes; +var warnedAboutMissingGetChildContext; - if (unblockedLanes !== NoLanes) { - nextLanes = getHighestPriorityLanes(unblockedLanes); - } else { - if (pingedLanes !== NoLanes) { - nextLanes = getHighestPriorityLanes(pingedLanes); - } - } - } +{ + warnedAboutMissingGetChildContext = {}; +} - if (nextLanes === NoLanes) { - // This should only be reachable if we're suspended - // TODO: Consider warning in this path if a fallback timer is not scheduled. - return NoLanes; - } // If we're already in the middle of a render, switching lanes will interrupt - // it and we'll lose our progress. We should only do this if the new lanes are - // higher priority. - - if ( - wipLanes !== NoLanes && - wipLanes !== nextLanes && // If we already suspended with a delay, then interrupting is fine. Don't - // bother waiting until the root is complete. - (wipLanes & suspendedLanes) === NoLanes - ) { - var nextLane = getHighestPriorityLane(nextLanes); - var wipLane = getHighestPriorityLane(wipLanes); - - if ( - // Tests whether the next lane is equal or lower priority than the wip - // one. This works because the bits decrease in priority as you go left. - nextLane >= wipLane || // Default priority updates should not interrupt transition updates. The - // only difference between default updates and transition updates is that - // default updates do not support refresh transitions. - (nextLane === DefaultLane && (wipLane & TransitionLanes) !== NoLanes) - ) { - // Keep working on the existing in-progress tree. Do not interrupt. - return wipLanes; - } - } - - return nextLanes; - } - function getEntangledLanes(root, renderLanes) { - var entangledLanes = renderLanes; - - if ((entangledLanes & InputContinuousLane) !== NoLanes) { - // When updates are sync by default, we entangle continuous priority updates - // and default updates, so they render in the same batch. The only reason - // they use separate lanes is because continuous updates should interrupt - // transitions, but default updates should not. - entangledLanes |= entangledLanes & DefaultLane; - } // Check for entangled lanes and add them to the batch. - // - // A lane is said to be entangled with another when it's not allowed to render - // in a batch that does not also include the other lane. Typically we do this - // when multiple updates have the same source, and we only want to respond to - // the most recent event from that source. - // - // Note that we apply entanglements *after* checking for partial work above. - // This means that if a lane is entangled during an interleaved event while - // it's already rendering, we won't interrupt it. This is intentional, since - // entanglement is usually "best effort": we'll try our best to render the - // lanes in the same batch, but it's not worth throwing out partially - // completed work in order to do it. - // TODO: Reconsider this. The counter-argument is that the partial work - // represents an intermediate state, which we don't want to show to the user. - // And by spending extra time finishing it, we're increasing the amount of - // time it takes to show the final state, which is what they are actually - // waiting for. - // - // For those exceptions where entanglement is semantically important, - // we should ensure that there is no partial work at the - // time we apply the entanglement. +var emptyContextObject = {}; - var allEntangledLanes = root.entangledLanes; +{ + Object.freeze(emptyContextObject); +} // A cursor to the current merged context object on the stack. - if (allEntangledLanes !== NoLanes) { - var entanglements = root.entanglements; - var lanes = entangledLanes & allEntangledLanes; - while (lanes > 0) { - var index = pickArbitraryLaneIndex(lanes); - var lane = 1 << index; - entangledLanes |= entanglements[index]; - lanes &= ~lane; - } - } +var contextStackCursor$1 = createCursor(emptyContextObject); // A cursor to a boolean indicating whether the context has changed. - return entangledLanes; - } +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. - function computeExpirationTime(lane, currentTime) { - switch (lane) { - case SyncHydrationLane: - case SyncLane: - case InputContinuousHydrationLane: - case InputContinuousLane: - // User interactions should expire slightly more quickly. - // - // NOTE: This is set to the corresponding constant as in Scheduler.js. - // When we made it larger, a product metric in www regressed, suggesting - // there's a user interaction that's being starved by a series of - // synchronous updates. If that theory is correct, the proper solution is - // to fix the starvation. However, this scenario supports the idea that - // expiration times are an important safeguard when starvation - // does happen. - return currentTime + syncLaneExpirationMs; - - case DefaultHydrationLane: - case DefaultLane: - case TransitionHydrationLane: - case TransitionLane1: - case TransitionLane2: - case TransitionLane3: - case TransitionLane4: - case TransitionLane5: - case TransitionLane6: - case TransitionLane7: - case TransitionLane8: - case TransitionLane9: - case TransitionLane10: - case TransitionLane11: - case TransitionLane12: - case TransitionLane13: - case TransitionLane14: - case TransitionLane15: - return currentTime + transitionLaneExpirationMs; - - case RetryLane1: - case RetryLane2: - case RetryLane3: - case RetryLane4: - // TODO: Retries should be allowed to expire if they are CPU bound for - // too long, but when I made this change it caused a spike in browser - // crashes. There must be some other underlying bug; not super urgent but - // ideally should figure out why and fix it. Unfortunately we don't have - // a repro for the crashes, only detected via production metrics. - return NoTimestamp; - - case SelectiveHydrationLane: - case IdleHydrationLane: - case IdleLane: - case OffscreenLane: - case DeferredLane: - // Anything idle priority or lower should never expire. - return NoTimestamp; - - default: - { - error("Should have found matching lanes. This is a bug in React."); - } +var previousContext = emptyContextObject; - return NoTimestamp; - } +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; } - function markStarvedLanesAsExpired(root, currentTime) { - // TODO: This gets called every time we yield. We can optimize by storing - // the earliest expiration time on the root. Then use that to quickly bail out - // of this function. - var pendingLanes = root.pendingLanes; - var suspendedLanes = root.suspendedLanes; - var pingedLanes = root.pingedLanes; - var expirationTimes = root.expirationTimes; // Iterate through the pending lanes and check if we've reached their - // expiration time. If so, we'll assume the update is being starved and mark - // it as expired to force it to finish. - // TODO: We should be able to replace this with upgradePendingLanesToSync - // - // We exclude retry lanes because those must always be time sliced, in order - // to unwrap uncached promises. - // TODO: Write a test for this - - var lanes = pendingLanes & ~RetryLanes; - - while (lanes > 0) { - var index = pickArbitraryLaneIndex(lanes); - var lane = 1 << index; - var expirationTime = expirationTimes[index]; - - if (expirationTime === NoTimestamp) { - // Found a pending lane with no expiration time. If it's not suspended, or - // if it's pinged, assume it's CPU-bound. Compute a new expiration time - // using the current time. - if ( - (lane & suspendedLanes) === NoLanes || - (lane & pingedLanes) !== NoLanes - ) { - // Assumes timestamps are monotonically increasing. - expirationTimes[index] = computeExpirationTime(lane, currentTime); - } - } else if (expirationTime <= currentTime) { - // This lane expired - root.expiredLanes |= lane; - } + return contextStackCursor$1.current; + } +} - lanes &= ~lane; - } - } // This returns the highest priority pending lanes regardless of whether they - function getLanesToRetrySynchronouslyOnError( - root, - originallyAttemptedLanes - ) { - if (root.errorRecoveryDisabledLanes & originallyAttemptedLanes) { - // The error recovery mechanism is disabled until these lanes are cleared. - return NoLanes; - } +function cacheContext(workInProgress, unmaskedContext, maskedContext) { + { + var instance = workInProgress.stateNode; + instance.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext; + instance.__reactInternalMemoizedMaskedChildContext = maskedContext; + } +} - var everythingButOffscreen = root.pendingLanes & ~OffscreenLane; +function getMaskedContext(workInProgress, unmaskedContext) { + { + var type = workInProgress.type; + var contextTypes = type.contextTypes; - if (everythingButOffscreen !== NoLanes) { - return everythingButOffscreen; - } + 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. - if (everythingButOffscreen & OffscreenLane) { - return OffscreenLane; - } - return NoLanes; - } - function includesSyncLane(lanes) { - return (lanes & (SyncLane | SyncHydrationLane)) !== NoLanes; - } - function includesNonIdleWork(lanes) { - return (lanes & NonIdleLanes) !== NoLanes; - } - function includesOnlyRetries(lanes) { - return (lanes & RetryLanes) === lanes; - } - function includesOnlyNonUrgentLanes(lanes) { - // TODO: Should hydration lanes be included here? This function is only - // used in `updateDeferredValueImpl`. - var UrgentLanes = SyncLane | InputContinuousLane | DefaultLane; - return (lanes & UrgentLanes) === NoLanes; - } - function includesOnlyTransitions(lanes) { - return (lanes & TransitionLanes) === lanes; - } - function includesBlockingLane(root, lanes) { - var SyncDefaultLanes = - InputContinuousHydrationLane | - InputContinuousLane | - DefaultHydrationLane | - DefaultLane; - return (lanes & SyncDefaultLanes) !== NoLanes; - } - function includesExpiredLane(root, lanes) { - // This is a separate check from includesBlockingLane because a lane can - // expire after a render has already started. - return (lanes & root.expiredLanes) !== NoLanes; - } - function isTransitionLane(lane) { - return (lane & TransitionLanes) !== NoLanes; + var instance = workInProgress.stateNode; + + if (instance && instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext) { + return instance.__reactInternalMemoizedMaskedChildContext; } - function claimNextTransitionLane() { - // Cycle through the lanes, assigning each new transition to the next lane. - // In most cases, this means every transition gets its own lane, until we - // run out of lanes and cycle back to the beginning. - var lane = nextTransitionLane; - nextTransitionLane <<= 1; - if ((nextTransitionLane & TransitionLanes) === NoLanes) { - nextTransitionLane = TransitionLane1; - } + var context = {}; - return lane; - } - function claimNextRetryLane() { - var lane = nextRetryLane; - nextRetryLane <<= 1; + for (var key in contextTypes) { + context[key] = unmaskedContext[key]; + } // 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 ((nextRetryLane & RetryLanes) === NoLanes) { - nextRetryLane = RetryLane1; - } - return lane; - } - function getHighestPriorityLane(lanes) { - return lanes & -lanes; - } - function pickArbitraryLane(lanes) { - // This wrapper function gets inlined. Only exists so to communicate that it - // doesn't matter which bit is selected; you can pick any bit without - // affecting the algorithms where its used. Here I'm using - // getHighestPriorityLane because it requires the fewest operations. - return getHighestPriorityLane(lanes); + if (instance) { + cacheContext(workInProgress, unmaskedContext, context); } - function pickArbitraryLaneIndex(lanes) { - return 31 - clz32(lanes); - } + return context; + } +} - function laneToIndex(lane) { - return pickArbitraryLaneIndex(lane); - } +function hasContextChanged() { + { + return didPerformWorkStackCursor.current; + } +} - function includesSomeLane(a, b) { - return (a & b) !== NoLanes; - } - function isSubsetOfLanes(set, subset) { - return (set & subset) === subset; - } - function mergeLanes(a, b) { - return a | b; - } - function removeLanes(set, subset) { - return set & ~subset; - } - function intersectLanes(a, b) { - return a & b; - } // Seems redundant, but it changes the type from a single lane (used for - // updates) to a group of lanes (used for flushing work). +function isContextProvider(type) { + { + var childContextTypes = type.childContextTypes; + return childContextTypes !== null && childContextTypes !== undefined; + } +} - function laneToLanes(lane) { - return lane; - } - function createLaneMap(initial) { - // Intentionally pushing one by one. - // https://v8.dev/blog/elements-kinds#avoid-creating-holes - var laneMap = []; +function popContext(fiber) { + { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor$1, fiber); + } +} - for (var i = 0; i < TotalLanes; i++) { - laneMap.push(initial); - } +function popTopLevelContextObject(fiber) { + { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor$1, fiber); + } +} - return laneMap; +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.'); } - function markRootUpdated$1(root, updateLane) { - root.pendingLanes |= updateLane; // If there are any suspended transitions, it's possible this new update - // could unblock them. Clear the suspended lanes so that we can try rendering - // them again. - // - // TODO: We really only need to unsuspend only lanes that are in the - // `subtreeLanes` of the updated fiber, or the update lanes of the return - // path. This would exclude suspended updates in an unrelated sibling tree, - // since there's no way for this update to unblock it. - // - // We don't do this if the incoming update is idle, because we never process - // idle updates until after all the regular updates have finished; there's no - // way it could unblock a transition. - if (updateLane !== IdleLane) { - root.suspendedLanes = NoLanes; - root.pingedLanes = NoLanes; - } - } - function markRootSuspended$1(root, suspendedLanes, spawnedLane) { - root.suspendedLanes |= suspendedLanes; - root.pingedLanes &= ~suspendedLanes; // The suspended lanes are no longer CPU-bound. Clear their expiration times. + push(contextStackCursor$1, context, fiber); + push(didPerformWorkStackCursor, didChange, fiber); + } +} - var expirationTimes = root.expirationTimes; - var lanes = suspendedLanes; +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. - while (lanes > 0) { - var index = pickArbitraryLaneIndex(lanes); - var lane = 1 << index; - expirationTimes[index] = NoTimestamp; - lanes &= ~lane; - } + if (typeof instance.getChildContext !== 'function') { + { + var componentName = getComponentNameFromFiber(fiber) || 'Unknown'; - if (spawnedLane !== NoLane) { - markSpawnedDeferredLane(root, spawnedLane, suspendedLanes); - } - } - function markRootPinged$1(root, pingedLanes) { - root.pingedLanes |= root.suspendedLanes & pingedLanes; - } - function markRootFinished(root, remainingLanes, spawnedLane) { - var noLongerPendingLanes = root.pendingLanes & ~remainingLanes; - root.pendingLanes = remainingLanes; // Let's try everything again + if (!warnedAboutMissingGetChildContext[componentName]) { + warnedAboutMissingGetChildContext[componentName] = true; - root.suspendedLanes = NoLanes; - root.pingedLanes = NoLanes; - root.expiredLanes &= remainingLanes; - root.entangledLanes &= remainingLanes; - root.errorRecoveryDisabledLanes &= remainingLanes; - root.shellSuspendCounter = 0; - var entanglements = root.entanglements; - var expirationTimes = root.expirationTimes; - var hiddenUpdates = root.hiddenUpdates; // Clear the lanes that no longer have pending work + 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 lanes = noLongerPendingLanes; + return parentContext; + } - while (lanes > 0) { - var index = pickArbitraryLaneIndex(lanes); - var lane = 1 << index; - entanglements[index] = NoLanes; - expirationTimes[index] = NoTimestamp; - var hiddenUpdatesForLane = hiddenUpdates[index]; + var childContext = instance.getChildContext(); - if (hiddenUpdatesForLane !== null) { - hiddenUpdates[index] = null; // "Hidden" updates are updates that were made to a hidden component. They - // have special logic associated with them because they may be entangled - // with updates that occur outside that tree. But once the outer tree - // commits, they behave like regular updates. + for (var contextKey in childContext) { + if (!(contextKey in childContextTypes)) { + throw new Error((getComponentNameFromFiber(fiber) || 'Unknown') + ".getChildContext(): key \"" + contextKey + "\" is not defined in childContextTypes."); + } + } - for (var i = 0; i < hiddenUpdatesForLane.length; i++) { - var update = hiddenUpdatesForLane[i]; + return assign({}, parentContext, childContext); + } +} - if (update !== null) { - update.lane &= ~OffscreenLane; - } - } - } +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. - lanes &= ~lane; - } + 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 (spawnedLane !== NoLane) { - markSpawnedDeferredLane( - root, - spawnedLane, // This render finished successfully without suspending, so we don't need - // to entangle the spawned task with the parent task. - NoLanes - ); - } - } + previousContext = contextStackCursor$1.current; + push(contextStackCursor$1, memoizedMergedChildContext, workInProgress); + push(didPerformWorkStackCursor, didPerformWorkStackCursor.current, workInProgress); + return true; + } +} - function markSpawnedDeferredLane(root, spawnedLane, entangledLanes) { - // This render spawned a deferred task. Mark it as pending. - root.pendingLanes |= spawnedLane; - root.suspendedLanes &= ~spawnedLane; // Entangle the spawned lane with the DeferredLane bit so that we know it - // was the result of another render. This lets us avoid a useDeferredValue - // waterfall — only the first level will defer. +function invalidateContextProvider(workInProgress, type, didChange) { + { + var instance = workInProgress.stateNode; - var spawnedLaneIndex = laneToIndex(spawnedLane); - root.entangledLanes |= spawnedLane; - root.entanglements[spawnedLaneIndex] |= - DeferredLane | // If the parent render task suspended, we must also entangle those lanes - // with the spawned task, so that the deferred task includes all the same - // updates that the parent task did. We can exclude any lane that is not - // used for updates (e.g. Offscreen). - (entangledLanes & UpdateLanes); + 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.'); } - function markRootEntangled(root, entangledLanes) { - // In addition to entangling each of the given lanes with each other, we also - // have to consider _transitive_ entanglements. For each lane that is already - // entangled with *any* of the given lanes, that lane is now transitively - // entangled with *all* the given lanes. - // - // Translated: If C is entangled with A, then entangling A with B also - // entangles C with B. - // - // If this is hard to grasp, it might help to intentionally break this - // function and look at the tests that fail in ReactTransition-test.js. Try - // commenting out one of the conditions below. - var rootEntangledLanes = (root.entangledLanes |= entangledLanes); - var entanglements = root.entanglements; - var lanes = rootEntangledLanes; - - while (lanes) { - var index = pickArbitraryLaneIndex(lanes); - var lane = 1 << index; + 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. - if ( - // Is this one of the newly entangled lanes? - (lane & entangledLanes) | // Is this lane transitively entangled with the newly entangled lanes? - (entanglements[index] & entangledLanes) - ) { - entanglements[index] |= entangledLanes; - } + pop(didPerformWorkStackCursor, workInProgress); + pop(contextStackCursor$1, workInProgress); // Now push the new context and mark that it has changed. - lanes &= ~lane; - } + push(contextStackCursor$1, mergedContext, workInProgress); + push(didPerformWorkStackCursor, didChange, workInProgress); + } else { + pop(didPerformWorkStackCursor, workInProgress); + push(didPerformWorkStackCursor, didChange, workInProgress); } - function upgradePendingLaneToSync(root, lane) { - // Since we're upgrading the priority of the given lane, there is now pending - // sync work. - root.pendingLanes |= SyncLane; // Entangle the sync lane with the lane we're upgrading. This means SyncLane - // will not be allowed to finish without also finishing the given lane. + } +} - root.entangledLanes |= SyncLane; - root.entanglements[SyncLaneIndex] |= lane; +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.'); } - function markHiddenUpdate(root, update, lane) { - var index = laneToIndex(lane); - var hiddenUpdates = root.hiddenUpdates; - var hiddenUpdatesForLane = hiddenUpdates[index]; - if (hiddenUpdatesForLane === null) { - hiddenUpdates[index] = [update]; - } else { - hiddenUpdatesForLane.push(update); - } + var node = fiber; - update.lane = lane | OffscreenLane; - } - function getBumpedLaneForHydration(root, renderLanes) { - var renderLane = getHighestPriorityLane(renderLanes); - var lane; + do { + switch (node.tag) { + case HostRoot: + return node.stateNode.context; - if (enableUnifiedSyncLane && (renderLane & SyncUpdateLanes) !== NoLane) { - lane = SyncHydrationLane; - } else { - switch (renderLane) { - case SyncLane: - lane = SyncHydrationLane; - break; + case ClassComponent: + { + var Component = node.type; - case InputContinuousLane: - lane = InputContinuousHydrationLane; - break; + if (isContextProvider(Component)) { + return node.stateNode.__reactInternalMemoizedMergedChildContext; + } - case DefaultLane: - lane = DefaultHydrationLane; break; + } + } // $FlowFixMe[incompatible-type] we bail out when we get a null - case TransitionLane1: - case TransitionLane2: - case TransitionLane3: - case TransitionLane4: - case TransitionLane5: - case TransitionLane6: - case TransitionLane7: - case TransitionLane8: - case TransitionLane9: - case TransitionLane10: - case TransitionLane11: - case TransitionLane12: - case TransitionLane13: - case TransitionLane14: - case TransitionLane15: - case RetryLane1: - case RetryLane2: - case RetryLane3: - case RetryLane4: - lane = TransitionHydrationLane; - break; - case IdleLane: - lane = IdleHydrationLane; - break; + node = node.return; + } while (node !== null); - default: - // Everything else is already either a hydration lane, or shouldn't - // be retried at a hydration lane. - lane = NoLane; - break; - } - } // Check if the lane we chose is suspended. If so, that indicates that we - // already attempted and failed to hydrate at that level. Also check if we're - // already rendering that lane, which is rare but could happen. + throw new Error('Found unexpected detached subtree parent. ' + 'This error is likely caused by a bug in React. Please file an issue.'); + } +} - if ((lane & (root.suspendedLanes | renderLanes)) !== NoLane) { - // Give up trying to hydrate and fall back to client render. - return NoLane; - } +// 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'; +} - return lane; - } - function addFiberToLanesMap(root, fiber, lanes) { - if (!isDevToolsPresent) { - return; - } +/** + * 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 + ; +} - var pendingUpdatersLaneMap = root.pendingUpdatersLaneMap; +var objectIs = // $FlowFixMe[method-unbinding] +typeof Object.is === 'function' ? Object.is : is; - while (lanes > 0) { - var index = laneToIndex(lanes); - var lane = 1 << index; - var updaters = pendingUpdatersLaneMap[index]; - updaters.add(fiber); - lanes &= ~lane; - } - } - function movePendingFibersToMemoized(root, lanes) { - if (!isDevToolsPresent) { - return; +var prefix; +function describeBuiltInComponentFrame(name) { + if (enableComponentStackLocations) { + if (prefix === undefined) { + // Extract the VM specific prefix used by each line. + try { + throw Error(); + } catch (x) { + var match = x.stack.trim().match(/\n( *(at )?)/); + prefix = match && match[1] || ''; } + } // We use the prefix to ensure our stacks line up with native stack frames. - var pendingUpdatersLaneMap = root.pendingUpdatersLaneMap; - var memoizedUpdaters = root.memoizedUpdaters; - while (lanes > 0) { - var index = laneToIndex(lanes); - var lane = 1 << index; - var updaters = pendingUpdatersLaneMap[index]; + return '\n' + prefix + name; + } else { + return describeComponentFrame(name); + } +} +function describeDebugInfoFrame(name, env) { + return describeBuiltInComponentFrame(name + (env ? ' (' + env + ')' : '')); +} +var reentry = false; +var componentFrameCache; - if (updaters.size > 0) { - updaters.forEach(function (fiber) { - var alternate = fiber.alternate; +{ + var PossiblyWeakMap$1 = typeof WeakMap === 'function' ? WeakMap : Map; + componentFrameCache = new PossiblyWeakMap$1(); +} +/** + * Leverages native browser/VM stack frames to get proper details (e.g. + * filename, line + col number) for a single component in a component stack. We + * do this by: + * (1) throwing and catching an error in the function - this will be our + * control error. + * (2) calling the component which will eventually throw an error that we'll + * catch - this will be our sample error. + * (3) diffing the control and sample error stacks to find the stack frame + * which represents our component. + */ - if (alternate === null || !memoizedUpdaters.has(alternate)) { - memoizedUpdaters.add(fiber); - } - }); - updaters.clear(); - } - lanes &= ~lane; - } - } - function getTransitionsForLanes(root, lanes) { - { - return null; - } - } +function describeNativeComponentFrame(fn, construct) { + // If something asked for a stack inside a fake render, it should get ignored. + if (!fn || reentry) { + return ''; + } - var NoEventPriority = NoLane; - var DiscreteEventPriority = SyncLane; - var ContinuousEventPriority = InputContinuousLane; - var DefaultEventPriority = DefaultLane; - var IdleEventPriority = IdleLane; - function higherEventPriority(a, b) { - return a !== 0 && a < b ? a : b; - } - function lowerEventPriority(a, b) { - return a === 0 || a > b ? a : b; - } - function isHigherEventPriority(a, b) { - return a !== 0 && a < b; - } - function eventPriorityToLane(updatePriority) { - return updatePriority; + { + var frame = componentFrameCache.get(fn); + + if (frame !== undefined) { + return frame; } - function lanesToEventPriority(lanes) { - var lane = getHighestPriorityLane(lanes); + } - if (!isHigherEventPriority(DiscreteEventPriority, lane)) { - return DiscreteEventPriority; - } + reentry = true; + var previousPrepareStackTrace = Error.prepareStackTrace; // $FlowFixMe[incompatible-type] It does accept undefined. - if (!isHigherEventPriority(ContinuousEventPriority, lane)) { - return ContinuousEventPriority; - } + Error.prepareStackTrace = undefined; + var previousDispatcher = null; - if (includesNonIdleWork(lane)) { - return DefaultEventPriority; - } + { + previousDispatcher = ReactSharedInternals.H; // Set the dispatcher in DEV because this might be call in the render function + // for warnings. + + ReactSharedInternals.H = null; + disableLogs(); + } + /** + * Finding a common stack frame between sample and control errors can be + * tricky given the different types and levels of stack trace truncation from + * different JS VMs. So instead we'll attempt to control what that common + * frame should be through this object method: + * Having both the sample and control errors be in the function under the + * `DescribeNativeComponentFrameRoot` property, + setting the `name` and + * `displayName` properties of the function ensures that a stack + * frame exists that has the method name `DescribeNativeComponentFrameRoot` in + * it for both control and sample stacks. + */ - return IdleEventPriority; - } - // Renderers that don't support hydration - // can re-export everything from this module. - function shim$1() { - 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 RunInRootFrame = { + DetermineComponentFrameRoot: function () { + var control; - var supportsHydration = false; - var isSuspenseInstancePending = shim$1; - var isSuspenseInstanceFallback = shim$1; - var getSuspenseInstanceFallbackErrorDetails = shim$1; - var registerSuspenseInstanceRetry = shim$1; - var clearSuspenseBoundary = shim$1; - var clearSuspenseBoundaryFromContainer = shim$1; + try { + // This should throw. + if (construct) { + // Something should be setting the props in the constructor. + var Fake = function () { + throw Error(); + }; // $FlowFixMe[prop-missing] - // Renderers that don't support hydration - // can re-export everything from this module. - function shim() { - throw new Error( - "The current renderer does not support Resources. " + - "This error is likely caused by a bug in React. " + - "Please file an issue." - ); - } // Resources (when unsupported) - var suspendResource = shim; - var getViewConfigForType = - ReactNativePrivateInterface.ReactNativeViewConfigRegistry.get; // Unused - // Unused - // Counter for uniquely identifying views. - // % 10 === 1 means it is a rootTag. - // % 2 === 0 means it is a Fabric tag. + Object.defineProperty(Fake.prototype, 'props', { + set: function () { + // We use a throwing setter instead of frozen or non-writable props + // because that won't throw in a non-strict mode function. + throw Error(); + } + }); - var nextReactTag = 3; + if (typeof Reflect === 'object' && Reflect.construct) { + // We construct a different control for this case to include any extra + // frames added by the construct call. + try { + Reflect.construct(Fake, []); + } catch (x) { + control = x; + } - function allocateTag() { - var tag = nextReactTag; + Reflect.construct(fn, [], Fake); + } else { + try { + Fake.call(); + } catch (x) { + control = x; + } // $FlowFixMe[prop-missing] found when upgrading Flow - if (tag % 10 === 1) { - tag += 2; - } - nextReactTag = tag + 2; - return tag; - } + fn.call(Fake.prototype); + } + } else { + try { + throw Error(); + } catch (x) { + control = x; + } // TODO(luna): This will currently only throw if the function component + // tries to access React/ReactDOM/props. We should probably make this throw + // in simple components too - function recursivelyUncacheFiberNode(node) { - if (typeof node === "number") { - // Leaf node (eg text) - uncacheFiberNode(node); - } else { - uncacheFiberNode(node._nativeTag); - node._children.forEach(recursivelyUncacheFiberNode); - } - } - function appendInitialChild(parentInstance, child) { - parentInstance._children.push(child); - } - function createInstance( - type, - props, - rootContainerInstance, - hostContext, - internalInstanceHandle - ) { - var tag = allocateTag(); - var viewConfig = getViewConfigForType(type); + var maybePromise = fn(); // If the function component returns a promise, it's likely an async + // component, which we don't yet support. Attach a noop catch handler to + // silence the error. + // TODO: Implement component stacks for async client components? - { - for (var key in viewConfig.validAttributes) { - if (props.hasOwnProperty(key)) { - ReactNativePrivateInterface.deepFreezeAndThrowOnMutationInDev( - props[key] - ); + if (maybePromise && typeof maybePromise.catch === 'function') { + maybePromise.catch(function () {}); } } + } catch (sample) { + // This is inlined manually because closure doesn't do it for us. + if (sample && control && typeof sample.stack === 'string') { + return [sample.stack, control.stack]; + } } - var updatePayload = create(props, viewConfig.validAttributes); - ReactNativePrivateInterface.UIManager.createView( - tag, // reactTag - viewConfig.uiViewClassName, // viewName - rootContainerInstance, // rootTag - updatePayload // props - ); - var component = new ReactNativeFiberHostComponent( - tag, - viewConfig, - internalInstanceHandle - ); - precacheFiberNode(internalInstanceHandle, tag); - updateFiberProps(tag, props); // Not sure how to avoid this cast. Flow is okay if the component is defined - // in the same file but if it's external it can't see the types. - - return component; - } - function createTextInstance( - text, - rootContainerInstance, - hostContext, - internalInstanceHandle - ) { - if (!hostContext.isInAParentText) { - throw new Error( - "Text strings must be rendered within a component." - ); - } - - var tag = allocateTag(); - ReactNativePrivateInterface.UIManager.createView( - tag, // reactTag - "RCTRawText", // viewName - rootContainerInstance, // rootTag - { - text: text - } // props - ); - precacheFiberNode(internalInstanceHandle, tag); - return tag; - } - function finalizeInitialChildren(parentInstance, type, props, hostContext) { - // Don't send a no-op message over the bridge. - if (parentInstance._children.length === 0) { - return false; - } // Map from child objects to native tags. - // Either way we need to pass a copy of the Array to prevent it from being frozen. + return [null, null]; + } + }; // $FlowFixMe[prop-missing] - var nativeTags = parentInstance._children.map(function (child) { - return typeof child === "number" - ? child // Leaf node (eg text) - : child._nativeTag; - }); + RunInRootFrame.DetermineComponentFrameRoot.displayName = 'DetermineComponentFrameRoot'; + var namePropDescriptor = Object.getOwnPropertyDescriptor(RunInRootFrame.DetermineComponentFrameRoot, 'name'); // Before ES6, the `name` property was not configurable. - ReactNativePrivateInterface.UIManager.setChildren( - parentInstance._nativeTag, // containerTag - nativeTags // reactTags - ); - return false; - } - 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"; + if (namePropDescriptor && namePropDescriptor.configurable) { + // V8 utilizes a function's `name` property when generating a stack trace. + Object.defineProperty(RunInRootFrame.DetermineComponentFrameRoot, // Configurable properties can be updated even if its writable descriptor + // is set to `false`. + // $FlowFixMe[cannot-write] + 'name', { + value: 'DetermineComponentFrameRoot' + }); + } + + try { + var _RunInRootFrame$Deter = RunInRootFrame.DetermineComponentFrameRoot(), + sampleStack = _RunInRootFrame$Deter[0], + controlStack = _RunInRootFrame$Deter[1]; + + if (sampleStack && controlStack) { + // This extracts the first frame from the sample that isn't also in the control. + // Skipping one frame that we assume is the frame that calls the two. + var sampleLines = sampleStack.split('\n'); + var controlLines = controlStack.split('\n'); + var s = 0; + var c = 0; + + while (s < sampleLines.length && !sampleLines[s].includes('DetermineComponentFrameRoot')) { + s++; + } + + while (c < controlLines.length && !controlLines[c].includes('DetermineComponentFrameRoot')) { + c++; + } // We couldn't find our intentionally injected common root frame, attempt + // to find another common root frame by search from the bottom of the + // control stack... + + + if (s === sampleLines.length || c === controlLines.length) { + s = sampleLines.length - 1; + c = controlLines.length - 1; + + while (s >= 1 && c >= 0 && sampleLines[s] !== controlLines[c]) { + // We expect at least one stack frame to be shared. + // Typically this will be the root most one. However, stack frames may be + // cut off due to maximum stack limits. In this case, one maybe cut off + // earlier than the other. We assume that the sample is longer or the same + // and there for cut off earlier. So we should find the root most frame in + // the sample somewhere in the control. + c--; + } + } + + for (; s >= 1 && c >= 0; s--, c--) { + // Next we find the first one that isn't the same which should be the + // frame that called our sample function and the control. + if (sampleLines[s] !== controlLines[c]) { + // In V8, the first line is describing the message but other VMs don't. + // If we're about to return the first line, and the control is also on the same + // line, that's a pretty good indicator that our sample threw at same line as + // the control. I.e. before we entered the sample frame. So we ignore this result. + // This can happen if you passed a class to function component, or non-function. + if (s !== 1 || c !== 1) { + do { + s--; + c--; // We may still have similar intermediate frames from the construct call. + // The next one that isn't the same should be our match though. - if (prevIsInAParentText !== isInAParentText) { - return { - isInAParentText: isInAParentText - }; - } else { - return parentHostContext; - } - } - function getPublicInstance(instance) { - // $FlowExpectedError[prop-missing] For compatibility with Fabric - if ( - instance.canonical != null && - instance.canonical.publicInstance != null - ) { - // $FlowFixMe[incompatible-return] - return instance.canonical.publicInstance; - } + if (c < 0 || sampleLines[s] !== controlLines[c]) { + // V8 adds a "new" prefix for native classes. Let's remove it to make it prettier. + var _frame = '\n' + sampleLines[s].replace(' at new ', ' at '); // If our component frame is labeled "" + // but we have a user-provided "displayName" + // splice it in to make the stack more readable. - return instance; - } - var scheduleTimeout = setTimeout; - var cancelTimeout = clearTimeout; - var noTimeout = -1; - 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 currentUpdatePriority = NoEventPriority; - function setCurrentUpdatePriority(newPriority) { - currentUpdatePriority = newPriority; - } - function getCurrentUpdatePriority() { - return currentUpdatePriority; - } - function resolveUpdatePriority() { - if (currentUpdatePriority !== NoEventPriority) { - return currentUpdatePriority; - } - return DefaultEventPriority; - } - function shouldAttemptEagerTransition() { - return false; - } // ------------------- - function appendChild(parentInstance, child) { - var childTag = typeof child === "number" ? child : child._nativeTag; - var children = parentInstance._children; - var index = children.indexOf(child); - - if (index >= 0) { - children.splice(index, 1); - children.push(child); - ReactNativePrivateInterface.UIManager.manageChildren( - parentInstance._nativeTag, // containerTag - [index], // moveFromIndices - [children.length - 1], // moveToIndices - [], // addChildReactTags - [], // addAtIndices - [] // removeAtIndices - ); - } else { - children.push(child); - ReactNativePrivateInterface.UIManager.manageChildren( - parentInstance._nativeTag, // containerTag - [], // moveFromIndices - [], // moveToIndices - [childTag], // addChildReactTags - [children.length - 1], // addAtIndices - [] // removeAtIndices - ); - } - } - function appendChildToContainer(parentInstance, child) { - var childTag = typeof child === "number" ? child : child._nativeTag; - ReactNativePrivateInterface.UIManager.setChildren( - parentInstance, // containerTag - [childTag] // reactTags - ); - } - function commitTextUpdate(textInstance, oldText, newText) { - ReactNativePrivateInterface.UIManager.updateView( - textInstance, // reactTag - "RCTRawText", // viewName - { - text: newText - } // props - ); - } - function commitMount(instance, type, newProps, internalInstanceHandle) { - // Noop - } - function commitUpdate( - instance, - updatePayloadTODO, - type, - oldProps, - newProps, - internalInstanceHandle - ) { - var viewConfig = instance.viewConfig; - updateFiberProps(instance._nativeTag, newProps); - var updatePayload = diff(oldProps, newProps, viewConfig.validAttributes); // Avoid the overhead of bridge calls if there's no update. - // This is an expensive no-op for Android, and causes an unnecessary - // view invalidation for certain components (eg RCTTextInput) on iOS. - - if (updatePayload != null) { - ReactNativePrivateInterface.UIManager.updateView( - instance._nativeTag, // reactTag - viewConfig.uiViewClassName, // viewName - updatePayload // props - ); - } - } - function insertBefore(parentInstance, child, beforeChild) { - var children = parentInstance._children; - var index = children.indexOf(child); // Move existing child or add new child? - - if (index >= 0) { - children.splice(index, 1); - var beforeChildIndex = children.indexOf(beforeChild); - children.splice(beforeChildIndex, 0, child); - ReactNativePrivateInterface.UIManager.manageChildren( - parentInstance._nativeTag, // containerID - [index], // moveFromIndices - [beforeChildIndex], // moveToIndices - [], // addChildReactTags - [], // addAtIndices - [] // removeAtIndices - ); - } else { - var _beforeChildIndex = children.indexOf(beforeChild); - - children.splice(_beforeChildIndex, 0, child); - var childTag = typeof child === "number" ? child : child._nativeTag; - ReactNativePrivateInterface.UIManager.manageChildren( - parentInstance._nativeTag, // containerID - [], // moveFromIndices - [], // moveToIndices - [childTag], // addChildReactTags - [_beforeChildIndex], // addAtIndices - [] // removeAtIndices - ); - } - } - function insertInContainerBefore(parentInstance, child, beforeChild) { - // TODO (bvaughn): Remove this check when... - // We create a wrapper object for the container in ReactNative render() - // Or we refactor to remove wrapper objects entirely. - // For more info on pros/cons see PR #8560 description. - if (typeof parentInstance === "number") { - throw new Error("Container does not support insertBefore operation"); - } - } - function removeChild(parentInstance, child) { - recursivelyUncacheFiberNode(child); - var children = parentInstance._children; - var index = children.indexOf(child); - children.splice(index, 1); - ReactNativePrivateInterface.UIManager.manageChildren( - parentInstance._nativeTag, // containerID - [], // moveFromIndices - [], // moveToIndices - [], // addChildReactTags - [], // addAtIndices - [index] // removeAtIndices - ); - } - function removeChildFromContainer(parentInstance, child) { - recursivelyUncacheFiberNode(child); - ReactNativePrivateInterface.UIManager.manageChildren( - parentInstance, // containerID - [], // moveFromIndices - [], // moveToIndices - [], // addChildReactTags - [], // addAtIndices - [0] // removeAtIndices - ); - } - function resetTextContent(instance) { - // Noop - } - function hideInstance(instance) { - var viewConfig = instance.viewConfig; - var updatePayload = create( - { - style: { - display: "none" + if (fn.displayName && _frame.includes('')) { + _frame = _frame.replace('', fn.displayName); + } + + if (true) { + if (typeof fn === 'function') { + componentFrameCache.set(fn, _frame); + } + } // Return the line we found. + + + return _frame; + } + } while (s >= 1 && c >= 0); } - }, - viewConfig.validAttributes - ); - ReactNativePrivateInterface.UIManager.updateView( - instance._nativeTag, - viewConfig.uiViewClassName, - updatePayload - ); - } - function hideTextInstance(textInstance) { - throw new Error("Not yet implemented."); - } - function unhideInstance(instance, props) { - var viewConfig = instance.viewConfig; - var updatePayload = diff( - assign({}, props, { - style: [ - props.style, - { - display: "none" - } - ] - }), - props, - viewConfig.validAttributes - ); - ReactNativePrivateInterface.UIManager.updateView( - instance._nativeTag, - viewConfig.uiViewClassName, - updatePayload - ); - } - function unhideTextInstance(textInstance, text) { - throw new Error("Not yet implemented."); - } - function preloadInstance(type, props) { - // Return true to indicate it's already loaded - return true; - } - function waitForCommitToBeReady() { - return null; + + break; + } + } } - var NotPendingTransition = null; - - var valueStack = []; - var fiberStack; + } finally { + reentry = false; { - fiberStack = []; + ReactSharedInternals.H = previousDispatcher; + reenableLogs(); } - var index = -1; + Error.prepareStackTrace = previousPrepareStackTrace; + } // Fallback to just using the name if we couldn't make it throw. - function createCursor(defaultValue) { - return { - current: defaultValue - }; + + var name = fn ? fn.displayName || fn.name : ''; + var syntheticFrame = name ? describeBuiltInComponentFrame(name) : ''; + + { + if (typeof fn === 'function') { + componentFrameCache.set(fn, syntheticFrame); } + } - function pop(cursor, fiber) { - if (index < 0) { - { - error("Unexpected pop."); - } + return syntheticFrame; +} - return; - } +function describeComponentFrame(name) { + return '\n in ' + (name || 'Unknown'); +} - { - if (fiber !== fiberStack[index]) { - error("Unexpected Fiber popped."); - } - } +function describeClassComponentFrame(ctor) { + if (enableComponentStackLocations) { + return describeNativeComponentFrame(ctor, true); + } else { + return describeFunctionComponentFrame(ctor); + } +} +function describeFunctionComponentFrame(fn) { + if (enableComponentStackLocations) { + return describeNativeComponentFrame(fn, false); + } else { + if (!fn) { + return ''; + } - cursor.current = valueStack[index]; - valueStack[index] = null; + var name = fn.displayName || fn.name || null; + return describeComponentFrame(name); + } +} - { - fiberStack[index] = null; - } +function describeFiber(fiber) { + switch (fiber.tag) { + case HostHoistable: + case HostSingleton: + case HostComponent: + return describeBuiltInComponentFrame(fiber.type); - index--; - } + case LazyComponent: + return describeBuiltInComponentFrame('Lazy'); - function push(cursor, value, fiber) { - index++; - valueStack[index] = cursor.current; + case SuspenseComponent: + return describeBuiltInComponentFrame('Suspense'); - { - fiberStack[index] = fiber; - } + case SuspenseListComponent: + return describeBuiltInComponentFrame('SuspenseList'); - cursor.current = value; - } + case FunctionComponent: + case SimpleMemoComponent: + return describeFunctionComponentFrame(fiber.type); - var warnedAboutMissingGetChildContext; + case ForwardRef: + return describeFunctionComponentFrame(fiber.type.render); - { - warnedAboutMissingGetChildContext = {}; - } + case ClassComponent: + return describeClassComponentFrame(fiber.type); - var emptyContextObject = {}; + default: + return ''; + } +} - { - Object.freeze(emptyContextObject); - } // A cursor to the current merged context object on the stack. +function getStackByFiberInDevAndProd(workInProgress) { + try { + var info = ''; + var node = workInProgress; - var contextStackCursor$1 = createCursor(emptyContextObject); // A cursor to a boolean indicating whether the context has changed. + do { + info += describeFiber(node); - 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. + if (true) { + // Add any Server Component stack frames in reverse order. + var debugInfo = node._debugInfo; - var previousContext = emptyContextObject; + if (debugInfo) { + for (var i = debugInfo.length - 1; i >= 0; i--) { + var entry = debugInfo[i]; - 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; + if (typeof entry.name === 'string') { + info += describeDebugInfoFrame(entry.name, entry.env); + } + } } + } // $FlowFixMe[incompatible-type] we bail out when we get a null - return contextStackCursor$1.current; - } - } - function cacheContext(workInProgress, unmaskedContext, maskedContext) { - { - var instance = workInProgress.stateNode; - instance.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext; - instance.__reactInternalMemoizedMaskedChildContext = maskedContext; - } - } + node = node.return; + } while (node); - function getMaskedContext(workInProgress, unmaskedContext) { - { - var type = workInProgress.type; - var contextTypes = type.contextTypes; + return info; + } catch (x) { + return '\nError generating stack: ' + x.message + '\n' + x.stack; + } +} - 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 CapturedStacks = new WeakMap(); +function createCapturedValueAtFiber(value, source) { + // If the value is an error, call this function immediately after it is thrown + // so the stack is accurate. + var stack; + + if (typeof value === 'object' && value !== null) { + var capturedStack = CapturedStacks.get(value); + + if (typeof capturedStack === 'string') { + stack = capturedStack; + } else { + stack = getStackByFiberInDevAndProd(source); + CapturedStacks.set(value, stack); + } + } else { + stack = getStackByFiberInDevAndProd(source); + } + + return { + value: value, + source: source, + stack: stack + }; +} +function createCapturedValueFromError(value, stack) { + if (typeof stack === 'string') { + CapturedStacks.set(value, stack); + } + + return { + value: value, + source: null, + stack: stack + }; +} - var instance = workInProgress.stateNode; +var contextStackCursor = createCursor(null); +var contextFiberStackCursor = createCursor(null); +var rootInstanceStackCursor = createCursor(null); // Represents the nearest host transition provider (in React DOM, a ) +// NOTE: Since forms cannot be nested, and this feature is only implemented by +// React DOM, we don't technically need this to be a stack. It could be a single +// module variable instead. + +var hostTransitionProviderCursor = createCursor(null); // TODO: This should initialize to NotPendingTransition, a constant +// imported from the fiber config. However, because of a cycle in the module +// graph, that value isn't defined during this module's initialization. I can't +// think of a way to work around this without moving that value out of the +// fiber config. For now, the "no provider" case is handled when reading, +// inside useHostTransitionStatus. + +var HostTransitionContext = { + $$typeof: REACT_CONTEXT_TYPE, + Provider: null, + Consumer: null, + _currentValue: null, + _currentValue2: null, + _threadCount: 0 +}; + +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 c; +} - if ( - instance && - instance.__reactInternalMemoizedUnmaskedChildContext === - unmaskedContext - ) { - return instance.__reactInternalMemoizedMaskedChildContext; - } +function getRootHostContainer() { + var rootInstance = requiredContext(rootInstanceStackCursor.current); + return rootInstance; +} - var context = {}; +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. - for (var key in contextTypes) { - context[key] = unmaskedContext[key]; - } // 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. + 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) { - cacheContext(workInProgress, unmaskedContext, context); - } + push(contextStackCursor, null, fiber); + var nextRootContext = getRootHostContext(); // Now that we know this function doesn't throw, replace it. - return context; - } - } + pop(contextStackCursor, fiber); + push(contextStackCursor, nextRootContext, fiber); +} - function hasContextChanged() { - { - return didPerformWorkStackCursor.current; - } +function popHostContainer(fiber) { + pop(contextStackCursor, fiber); + pop(contextFiberStackCursor, fiber); + pop(rootInstanceStackCursor, fiber); +} + +function getHostContext() { + var context = requiredContext(contextStackCursor.current); + return context; +} + +function pushHostContext(fiber) { + if (enableAsyncActions) { + var stateHook = fiber.memoizedState; + + if (stateHook !== null) { + // Only provide context if this fiber has been upgraded by a host + // transition. We use the same optimization for regular host context below. + push(hostTransitionProviderCursor, fiber, fiber); } + } + + var context = requiredContext(contextStackCursor.current); + var nextContext = getChildHostContext(context, fiber.type); // Don't push this Fiber's context unless it's unique. + + if (context !== nextContext) { + // 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 popHostContext(fiber) { + if (contextFiberStackCursor.current === fiber) { + // Do not pop unless this Fiber provided the current context. + // pushHostContext() only pushes Fibers that provide unique contexts. + pop(contextStackCursor, fiber); + pop(contextFiberStackCursor, fiber); + } + + if (enableAsyncActions) { + if (hostTransitionProviderCursor.current === fiber) { + // Do not pop unless this Fiber provided the current context. This is mostly + // a performance optimization, but conveniently it also prevents a potential + // data race where a host provider is upgraded (i.e. memoizedState becomes + // non-null) during a concurrent event. This is a bit of a flaw in the way + // we upgrade host components, but because we're accounting for it here, it + // should be fine. + pop(hostTransitionProviderCursor, fiber); // When popping the transition provider, we reset the context value back + // to `null`. We can do this because you're not allowd to nest forms. If + // we allowed for multiple nested host transition providers, then we'd + // need to reset this to the parent provider's status. - function isContextProvider(type) { { - var childContextTypes = type.childContextTypes; - return childContextTypes !== null && childContextTypes !== undefined; + HostTransitionContext._currentValue = null; } } + } +} - function popContext(fiber) { - { - pop(didPerformWorkStackCursor, fiber); - pop(contextStackCursor$1, fiber); +var maxRowLength = 120; +var idealDepth = 15; + +function findNotableNode(node, indent) { + if (node.serverProps === undefined && node.serverTail.length === 0 && node.children.length === 1 && node.distanceFromLeaf > 3 && node.distanceFromLeaf > idealDepth - indent) { + // This is not an interesting node for contextual purposes so we can skip it. + var child = node.children[0]; + return findNotableNode(child, indent); + } + + return node; +} + +function indentation(indent) { + return ' ' + ' '.repeat(indent); +} + +function added(indent) { + return '+ ' + ' '.repeat(indent); +} + +function removed(indent) { + return '- ' + ' '.repeat(indent); +} + +function describeFiberType(fiber) { + switch (fiber.tag) { + case HostHoistable: + case HostSingleton: + case HostComponent: + return fiber.type; + + case LazyComponent: + return 'Lazy'; + + case SuspenseComponent: + return 'Suspense'; + + case SuspenseListComponent: + return 'SuspenseList'; + + case FunctionComponent: + case SimpleMemoComponent: + var fn = fiber.type; + return fn.displayName || fn.name || null; + + case ForwardRef: + var render = fiber.type.render; + return render.displayName || render.name || null; + + case ClassComponent: + var ctr = fiber.type; + return ctr.displayName || ctr.name || null; + + default: + // Skip + return null; + } +} + +var needsEscaping = /["'&<>\n\t]/; + +function describeTextNode(content, maxLength) { + if (needsEscaping.test(content)) { + var encoded = JSON.stringify(content); + + if (encoded.length > maxLength - 2) { + if (maxLength < 8) { + return '{"..."}'; } + + return '{' + encoded.slice(0, maxLength - 7) + '..."}'; } - function popTopLevelContextObject(fiber) { - { - pop(didPerformWorkStackCursor, fiber); - pop(contextStackCursor$1, fiber); + return '{' + encoded + '}'; + } else { + if (content.length > maxLength) { + if (maxLength < 5) { + return '{"..."}'; } + + return content.slice(0, maxLength - 3) + '...'; } - 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." - ); - } + return content; + } +} + +function describeTextDiff(clientText, serverProps, indent) { + var maxLength = maxRowLength - indent * 2; - push(contextStackCursor$1, context, fiber); - push(didPerformWorkStackCursor, didChange, fiber); + if (serverProps === null) { + return added(indent) + describeTextNode(clientText, maxLength) + '\n'; + } else if (typeof serverProps === 'string') { + var serverText = serverProps; + var firstDiff = 0; + + for (; firstDiff < serverText.length && firstDiff < clientText.length; firstDiff++) { + if (serverText.charCodeAt(firstDiff) !== clientText.charCodeAt(firstDiff)) { + break; } } - 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 (firstDiff > maxLength - 8 && firstDiff > 10) { + // The first difference between the two strings would be cut off, so cut off in + // the beginning instead. + clientText = '...' + clientText.slice(firstDiff - 8); + serverText = '...' + serverText.slice(firstDiff - 8); + } - if (typeof instance.getChildContext !== "function") { - { - var componentName = getComponentNameFromFiber(fiber) || "Unknown"; - - if (!warnedAboutMissingGetChildContext[componentName]) { - warnedAboutMissingGetChildContext[componentName] = true; - - 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 added(indent) + describeTextNode(clientText, maxLength) + '\n' + removed(indent) + describeTextNode(serverText, maxLength) + '\n'; + } else { + return indentation(indent) + describeTextNode(clientText, maxLength) + '\n'; + } +} - return parentContext; - } +function objectName(object) { + // $FlowFixMe[method-unbinding] + var name = Object.prototype.toString.call(object); + return name.replace(/^\[object (.*)\]$/, function (m, p0) { + return p0; + }); +} - var childContext = instance.getChildContext(); +function describeValue(value, maxLength) { + switch (typeof value) { + case 'string': + { + var encoded = JSON.stringify(value); - for (var contextKey in childContext) { - if (!(contextKey in childContextTypes)) { - throw new Error( - (getComponentNameFromFiber(fiber) || "Unknown") + - '.getChildContext(): key "' + - contextKey + - '" is not defined in childContextTypes.' - ); + if (encoded.length > maxLength) { + if (maxLength < 5) { + return '"..."'; } - } - return assign({}, parentContext, childContext); - } - } + return encoded.slice(0, maxLength - 4) + '..."'; + } - 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; + return encoded; } - } - function invalidateContextProvider(workInProgress, type, didChange) { + case 'object': { - var instance = workInProgress.stateNode; + if (value === null) { + return 'null'; + } - 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); + if (isArray(value)) { + return '[...]'; } - } - } - 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." - ); + if (value.$$typeof === REACT_ELEMENT_TYPE) { + var type = getComponentNameFromType(value.type); + return type ? '<' + type + '>' : '<...>'; } - var node = fiber; + var name = objectName(value); - do { - switch (node.tag) { - case HostRoot: - return node.stateNode.context; + if (name === 'Object') { + var properties = ''; + maxLength -= 2; + + for (var propName in value) { + if (!value.hasOwnProperty(propName)) { + continue; + } - case ClassComponent: { - var Component = node.type; + var jsonPropName = JSON.stringify(propName); - if (isContextProvider(Component)) { - return node.stateNode.__reactInternalMemoizedMergedChildContext; - } + if (jsonPropName !== '"' + propName + '"') { + propName = jsonPropName; + } + + maxLength -= propName.length - 2; + var propValue = describeValue(value[propName], maxLength < 15 ? maxLength : 15); + maxLength -= propValue.length; + if (maxLength < 0) { + properties += properties === '' ? '...' : ', ...'; break; } - } // $FlowFixMe[incompatible-type] we bail out when we get a null - node = node.return; - } while (node !== null); + properties += (properties === '' ? '' : ',') + propName + ':' + propValue; + } + + return '{' + properties + '}'; + } - throw new Error( - "Found unexpected detached subtree parent. " + - "This error is likely caused by a bug in React. Please file an issue." - ); + return name; } - } - // 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" - ); - } + case 'function': + { + var _name = value.displayName || value.name; - /** - * 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 - ); + return _name ? 'function ' + _name : 'function'; + } + + default: + // eslint-disable-next-line react-internal/safe-string-coercion + return String(value); + } +} + +function describePropValue(value, maxLength) { + if (typeof value === 'string' && !needsEscaping.test(value)) { + if (value.length > maxLength - 2) { + if (maxLength < 5) { + return '"..."'; + } + + return '"' + value.slice(0, maxLength - 5) + '..."'; } - var objectIs = typeof Object.is === "function" ? Object.is : is; // $FlowFixMe[method-unbinding] + return '"' + value + '"'; + } - var prefix; - function describeBuiltInComponentFrame(name) { - if (enableComponentStackLocations) { - if (prefix === undefined) { - // Extract the VM specific prefix used by each line. - try { - throw Error(); - } catch (x) { - var match = x.stack.trim().match(/\n( *(at )?)/); - prefix = (match && match[1]) || ""; - } - } // We use the prefix to ensure our stacks line up with native stack frames. + return '{' + describeValue(value, maxLength - 2) + '}'; +} - return "\n" + prefix + name; - } else { - return describeComponentFrame(name); - } +function describeCollapsedElement(type, props, indent) { + // This function tries to fit the props into a single line for non-essential elements. + // We also ignore children because we're not going deeper. + var maxLength = maxRowLength - indent * 2 - type.length - 2; + var content = ''; + + for (var propName in props) { + if (!props.hasOwnProperty(propName)) { + continue; } - function describeDebugInfoFrame(name, env) { - return describeBuiltInComponentFrame( - name + (env ? " (" + env + ")" : "") - ); + + if (propName === 'children') { + // Ignored. + continue; } - var reentry = false; - var componentFrameCache; - { - var PossiblyWeakMap$1 = typeof WeakMap === "function" ? WeakMap : Map; - componentFrameCache = new PossiblyWeakMap$1(); + var propValue = describePropValue(props[propName], 15); + maxLength -= propName.length + propValue.length + 2; + + if (maxLength < 0) { + content += ' ...'; + break; } - /** - * Leverages native browser/VM stack frames to get proper details (e.g. - * filename, line + col number) for a single component in a component stack. We - * do this by: - * (1) throwing and catching an error in the function - this will be our - * control error. - * (2) calling the component which will eventually throw an error that we'll - * catch - this will be our sample error. - * (3) diffing the control and sample error stacks to find the stack frame - * which represents our component. - */ - function describeNativeComponentFrame(fn, construct) { - // If something asked for a stack inside a fake render, it should get ignored. - if (!fn || reentry) { - return ""; - } + content += ' ' + propName + '=' + propValue; + } - { - var frame = componentFrameCache.get(fn); + return indentation(indent) + '<' + type + content + '>\n'; +} - if (frame !== undefined) { - return frame; - } - } +function describeExpandedElement(type, props, rowPrefix) { + // This function tries to fit the props into a single line for non-essential elements. + // We also ignore children because we're not going deeper. + var remainingRowLength = maxRowLength - rowPrefix.length - type.length; // We add the properties to a set so we can choose later whether we'll put it on one + // line or multiple lines. - reentry = true; - var previousPrepareStackTrace = Error.prepareStackTrace; // $FlowFixMe[incompatible-type] It does accept undefined. + var properties = []; - Error.prepareStackTrace = undefined; - var previousDispatcher = null; + for (var propName in props) { + if (!props.hasOwnProperty(propName)) { + continue; + } - { - previousDispatcher = ReactSharedInternals.H; // Set the dispatcher in DEV because this might be call in the render function - // for warnings. - - ReactSharedInternals.H = null; - disableLogs(); - } - /** - * Finding a common stack frame between sample and control errors can be - * tricky given the different types and levels of stack trace truncation from - * different JS VMs. So instead we'll attempt to control what that common - * frame should be through this object method: - * Having both the sample and control errors be in the function under the - * `DescribeNativeComponentFrameRoot` property, + setting the `name` and - * `displayName` properties of the function ensures that a stack - * frame exists that has the method name `DescribeNativeComponentFrameRoot` in - * it for both control and sample stacks. - */ - - var RunInRootFrame = { - DetermineComponentFrameRoot: function () { - var control; + if (propName === 'children') { + // Ignored. + continue; + } - try { - // This should throw. - if (construct) { - // Something should be setting the props in the constructor. - var Fake = function () { - throw Error(); - }; // $FlowFixMe[prop-missing] - - Object.defineProperty(Fake.prototype, "props", { - set: function () { - // We use a throwing setter instead of frozen or non-writable props - // because that won't throw in a non-strict mode function. - throw Error(); - } - }); - - if (typeof Reflect === "object" && Reflect.construct) { - // We construct a different control for this case to include any extra - // frames added by the construct call. - try { - Reflect.construct(Fake, []); - } catch (x) { - control = x; - } + var maxLength = maxRowLength - rowPrefix.length - propName.length - 1; + var propValue = describePropValue(props[propName], maxLength); + remainingRowLength -= propName.length + propValue.length + 2; + properties.push(propName + '=' + propValue); + } - Reflect.construct(fn, [], Fake); - } else { - try { - Fake.call(); - } catch (x) { - control = x; - } // $FlowFixMe[prop-missing] found when upgrading Flow + if (properties.length === 0) { + return rowPrefix + '<' + type + '>\n'; + } else if (remainingRowLength > 0) { + // We can fit all on one row. + return rowPrefix + '<' + type + ' ' + properties.join(' ') + '>\n'; + } else { + // Split into one row per property: + return rowPrefix + '<' + type + '\n' + rowPrefix + ' ' + properties.join('\n' + rowPrefix + ' ') + '\n' + rowPrefix + '>\n'; + } +} - fn.call(Fake.prototype); - } - } else { - try { - throw Error(); - } catch (x) { - control = x; - } // TODO(luna): This will currently only throw if the function component - // tries to access React/ReactDOM/props. We should probably make this throw - // in simple components too - - var maybePromise = fn(); // If the function component returns a promise, it's likely an async - // component, which we don't yet support. Attach a noop catch handler to - // silence the error. - // TODO: Implement component stacks for async client components? - - if (maybePromise && typeof maybePromise.catch === "function") { - maybePromise.catch(function () {}); - } - } - } catch (sample) { - // This is inlined manually because closure doesn't do it for us. - if (sample && control && typeof sample.stack === "string") { - return [sample.stack, control.stack]; - } - } +function describePropertiesDiff(clientObject, serverObject, indent) { + var properties = ''; + var remainingServerProperties = assign({}, serverObject); - return [null, null]; - } - }; // $FlowFixMe[prop-missing] + for (var propName in clientObject) { + if (!clientObject.hasOwnProperty(propName)) { + continue; + } - RunInRootFrame.DetermineComponentFrameRoot.displayName = - "DetermineComponentFrameRoot"; - var namePropDescriptor = Object.getOwnPropertyDescriptor( - RunInRootFrame.DetermineComponentFrameRoot, - "name" - ); // Before ES6, the `name` property was not configurable. + delete remainingServerProperties[propName]; + var maxLength = maxRowLength - indent * 2 - propName.length - 2; + var clientValue = clientObject[propName]; + var clientPropValue = describeValue(clientValue, maxLength); - if (namePropDescriptor && namePropDescriptor.configurable) { - // V8 utilizes a function's `name` property when generating a stack trace. - Object.defineProperty( - RunInRootFrame.DetermineComponentFrameRoot, // Configurable properties can be updated even if its writable descriptor - // is set to `false`. - // $FlowFixMe[cannot-write] - "name", - { - value: "DetermineComponentFrameRoot" - } - ); - } + if (serverObject.hasOwnProperty(propName)) { + var serverValue = serverObject[propName]; + var serverPropValue = describeValue(serverValue, maxLength); + properties += added(indent) + propName + ': ' + clientPropValue + '\n'; + properties += removed(indent) + propName + ': ' + serverPropValue + '\n'; + } else { + properties += added(indent) + propName + ': ' + clientPropValue + '\n'; + } + } - try { - var _RunInRootFrame$Deter = - RunInRootFrame.DetermineComponentFrameRoot(), - sampleStack = _RunInRootFrame$Deter[0], - controlStack = _RunInRootFrame$Deter[1]; - - if (sampleStack && controlStack) { - // This extracts the first frame from the sample that isn't also in the control. - // Skipping one frame that we assume is the frame that calls the two. - var sampleLines = sampleStack.split("\n"); - var controlLines = controlStack.split("\n"); - var s = 0; - var c = 0; - - while ( - s < sampleLines.length && - !sampleLines[s].includes("DetermineComponentFrameRoot") - ) { - s++; - } + for (var _propName in remainingServerProperties) { + if (!remainingServerProperties.hasOwnProperty(_propName)) { + continue; + } - while ( - c < controlLines.length && - !controlLines[c].includes("DetermineComponentFrameRoot") - ) { - c++; - } // We couldn't find our intentionally injected common root frame, attempt - // to find another common root frame by search from the bottom of the - // control stack... - - if (s === sampleLines.length || c === controlLines.length) { - s = sampleLines.length - 1; - c = controlLines.length - 1; - - while (s >= 1 && c >= 0 && sampleLines[s] !== controlLines[c]) { - // We expect at least one stack frame to be shared. - // Typically this will be the root most one. However, stack frames may be - // cut off due to maximum stack limits. In this case, one maybe cut off - // earlier than the other. We assume that the sample is longer or the same - // and there for cut off earlier. So we should find the root most frame in - // the sample somewhere in the control. - c--; - } - } + var _maxLength = maxRowLength - indent * 2 - _propName.length - 2; - for (; s >= 1 && c >= 0; s--, c--) { - // Next we find the first one that isn't the same which should be the - // frame that called our sample function and the control. - if (sampleLines[s] !== controlLines[c]) { - // In V8, the first line is describing the message but other VMs don't. - // If we're about to return the first line, and the control is also on the same - // line, that's a pretty good indicator that our sample threw at same line as - // the control. I.e. before we entered the sample frame. So we ignore this result. - // This can happen if you passed a class to function component, or non-function. - if (s !== 1 || c !== 1) { - do { - s--; - c--; // We may still have similar intermediate frames from the construct call. - // The next one that isn't the same should be our match though. - - if (c < 0 || sampleLines[s] !== controlLines[c]) { - // V8 adds a "new" prefix for native classes. Let's remove it to make it prettier. - var _frame = - "\n" + sampleLines[s].replace(" at new ", " at "); // If our component frame is labeled "" - // but we have a user-provided "displayName" - // splice it in to make the stack more readable. - - if (fn.displayName && _frame.includes("")) { - _frame = _frame.replace("", fn.displayName); - } + var _serverValue = remainingServerProperties[_propName]; - if (true) { - if (typeof fn === "function") { - componentFrameCache.set(fn, _frame); - } - } // Return the line we found. + var _serverPropValue = describeValue(_serverValue, _maxLength); - return _frame; - } - } while (s >= 1 && c >= 0); - } + properties += removed(indent) + _propName + ': ' + _serverPropValue + '\n'; + } - break; - } - } - } - } finally { - reentry = false; + return properties; +} - { - ReactSharedInternals.H = previousDispatcher; - reenableLogs(); - } +function describeElementDiff(type, clientProps, serverProps, indent) { + var content = ''; // Maps any previously unmatched lower case server prop name to its full prop name - Error.prepareStackTrace = previousPrepareStackTrace; - } // Fallback to just using the name if we couldn't make it throw. + var serverPropNames = new Map(); - var name = fn ? fn.displayName || fn.name : ""; - var syntheticFrame = name ? describeBuiltInComponentFrame(name) : ""; + for (var propName in serverProps) { + if (!serverProps.hasOwnProperty(propName)) { + continue; + } - { - if (typeof fn === "function") { - componentFrameCache.set(fn, syntheticFrame); - } + serverPropNames.set(propName.toLowerCase(), propName); + } + + if (serverPropNames.size === 1 && serverPropNames.has('children')) { + content += describeExpandedElement(type, clientProps, indentation(indent)); + } else { + for (var _propName2 in clientProps) { + if (!clientProps.hasOwnProperty(_propName2)) { + continue; } - return syntheticFrame; - } + if (_propName2 === 'children') { + // Handled below. + continue; + } - function describeComponentFrame(name) { - return "\n in " + (name || "Unknown"); - } + var maxLength = maxRowLength - (indent + 1) * 2 - _propName2.length - 1; + var serverPropName = serverPropNames.get(_propName2.toLowerCase()); - function describeClassComponentFrame(ctor) { - if (enableComponentStackLocations) { - return describeNativeComponentFrame(ctor, true); + if (serverPropName !== undefined) { + serverPropNames.delete(_propName2.toLowerCase()); // There's a diff here. + + var clientValue = clientProps[_propName2]; + var serverValue = serverProps[serverPropName]; + var clientPropValue = describePropValue(clientValue, maxLength); + var serverPropValue = describePropValue(serverValue, maxLength); + + if (typeof clientValue === 'object' && clientValue !== null && typeof serverValue === 'object' && serverValue !== null && objectName(clientValue) === 'Object' && objectName(serverValue) === 'Object' && ( // Only do the diff if the object has a lot of keys or was shortened. + Object.keys(clientValue).length > 2 || Object.keys(serverValue).length > 2 || clientPropValue.indexOf('...') > -1 || serverPropValue.indexOf('...') > -1)) { + // We're comparing two plain objects. We can diff the nested objects instead. + content += indentation(indent + 1) + _propName2 + '={{\n' + describePropertiesDiff(clientValue, serverValue, indent + 2) + indentation(indent + 1) + '}}\n'; + } else { + content += added(indent + 1) + _propName2 + '=' + clientPropValue + '\n'; + content += removed(indent + 1) + _propName2 + '=' + serverPropValue + '\n'; + } } else { - return describeFunctionComponentFrame(ctor); + // Considered equal. + content += indentation(indent + 1) + _propName2 + '=' + describePropValue(clientProps[_propName2], maxLength) + '\n'; } } - function describeFunctionComponentFrame(fn) { - if (enableComponentStackLocations) { - return describeNativeComponentFrame(fn, false); - } else { - if (!fn) { - return ""; - } - var name = fn.displayName || fn.name || null; - return describeComponentFrame(name); + serverPropNames.forEach(function (propName) { + if (propName === 'children') { + // Handled below. + return; } + + var maxLength = maxRowLength - (indent + 1) * 2 - propName.length - 1; + content += removed(indent + 1) + propName + '=' + describePropValue(serverProps[propName], maxLength) + '\n'; + }); + + if (content === '') { + // No properties + content = indentation(indent) + '<' + type + '>\n'; + } else { + // Had properties + content = indentation(indent) + '<' + type + '\n' + content + indentation(indent) + '>\n'; } + } - function describeFiber(fiber) { - switch (fiber.tag) { - case HostHoistable: - case HostSingleton: - case HostComponent: - return describeBuiltInComponentFrame(fiber.type); + var serverChildren = serverProps.children; + var clientChildren = clientProps.children; - case LazyComponent: - return describeBuiltInComponentFrame("Lazy"); + if (typeof serverChildren === 'string' || typeof serverChildren === 'number' || typeof serverChildren === 'bigint') { + // There's a diff of the children. + // $FlowFixMe[unsafe-addition] + var serverText = '' + serverChildren; + var clientText = ''; - case SuspenseComponent: - return describeBuiltInComponentFrame("Suspense"); + if (typeof clientChildren === 'string' || typeof clientChildren === 'number' || typeof clientChildren === 'bigint') { + // $FlowFixMe[unsafe-addition] + clientText = '' + clientChildren; + } - case SuspenseListComponent: - return describeBuiltInComponentFrame("SuspenseList"); + content += describeTextDiff(clientText, serverText, indent + 1); + } else if (typeof clientChildren === 'string' || typeof clientChildren === 'number' || typeof clientChildren === 'bigint') { + // The client has children but it's not considered a difference from the server. + // $FlowFixMe[unsafe-addition] + content += describeTextDiff('' + clientChildren, undefined, indent + 1); + } - case FunctionComponent: - case SimpleMemoComponent: - return describeFunctionComponentFrame(fiber.type); + return content; +} - case ForwardRef: - return describeFunctionComponentFrame(fiber.type.render); +function describeSiblingFiber(fiber, indent) { + var type = describeFiberType(fiber); - case ClassComponent: - return describeClassComponentFrame(fiber.type); + if (type === null) { + // Skip this type of fiber. We currently treat this as a fragment + // so it's just part of the parent's children. + var flatContent = ''; + var childFiber = fiber.child; - default: - return ""; - } + while (childFiber) { + flatContent += describeSiblingFiber(childFiber, indent); + childFiber = childFiber.sibling; } - function getStackByFiberInDevAndProd(workInProgress) { - try { - var info = ""; - var node = workInProgress; + return flatContent; + } - do { - info += describeFiber(node); + return indentation(indent) + '<' + type + '>' + '\n'; +} - if (true) { - // Add any Server Component stack frames in reverse order. - var debugInfo = node._debugInfo; +function describeNode(node, indent) { + var skipToNode = findNotableNode(node, indent); - if (debugInfo) { - for (var i = debugInfo.length - 1; i >= 0; i--) { - var entry = debugInfo[i]; + if (skipToNode !== node && (node.children.length !== 1 || node.children[0] !== skipToNode)) { + return indentation(indent) + '...\n' + describeNode(skipToNode, indent + 1); + } // Prefix with any server components for context - if (typeof entry.name === "string") { - info += describeDebugInfoFrame(entry.name, entry.env); - } - } - } - } // $FlowFixMe[incompatible-type] we bail out when we get a null - node = node.return; - } while (node); + var parentContent = ''; + var debugInfo = node.fiber._debugInfo; - return info; - } catch (x) { - return "\nError generating stack: " + x.message + "\n" + x.stack; + if (debugInfo) { + for (var i = 0; i < debugInfo.length; i++) { + var serverComponentName = debugInfo[i].name; + + if (typeof serverComponentName === 'string') { + parentContent += indentation(indent) + '<' + serverComponentName + '>' + '\n'; + indent++; } } + } // Self - var CapturedStacks = new WeakMap(); - function createCapturedValueAtFiber(value, source) { - // If the value is an error, call this function immediately after it is thrown - // so the stack is accurate. - var stack; - if (typeof value === "object" && value !== null) { - var capturedStack = CapturedStacks.get(value); + var selfContent = ''; // We use the pending props since we might be generating a diff before the complete phase + // when something throws. - if (typeof capturedStack === "string") { - stack = capturedStack; - } else { - stack = getStackByFiberInDevAndProd(source); - CapturedStacks.set(value, stack); + var clientProps = node.fiber.pendingProps; + + if (node.fiber.tag === HostText) { + // Text Node + selfContent = describeTextDiff(clientProps, node.serverProps, indent); + } else { + var type = describeFiberType(node.fiber); + + if (type !== null) { + // Element Node + if (node.serverProps === undefined) { + // Just a reference node for context. + selfContent = describeCollapsedElement(type, clientProps, indent); + indent++; + } else if (node.serverProps === null) { + selfContent = describeExpandedElement(type, clientProps, added(indent)); // If this was an insertion we won't step down further. Any tail + // are considered siblings so we don't indent. + // TODO: Model this a little better. + } else if (typeof node.serverProps === 'string') { + { + error('Should not have matched a non HostText fiber to a Text node. This is a bug in React.'); } } else { - stack = getStackByFiberInDevAndProd(source); + selfContent = describeElementDiff(type, clientProps, node.serverProps, indent); + indent++; } - - return { - value: value, - source: source, - stack: stack - }; } - function createCapturedValueFromError(value, stack) { - if (typeof stack === "string") { - CapturedStacks.set(value, stack); - } + } // Compute children - return { - value: value, - source: null, - stack: stack - }; + + var childContent = ''; + var childFiber = node.fiber.child; + var diffIdx = 0; + + while (childFiber && diffIdx < node.children.length) { + var childNode = node.children[diffIdx]; + + if (childNode.fiber === childFiber) { + // This was a match in the diff. + childContent += describeNode(childNode, indent); + diffIdx++; + } else { + // This is an unrelated previous sibling. + childContent += describeSiblingFiber(childFiber, indent); } - var contextStackCursor = createCursor(null); - var contextFiberStackCursor = createCursor(null); - var rootInstanceStackCursor = createCursor(null); // Represents the nearest host transition provider (in React DOM, a ) - // NOTE: Since forms cannot be nested, and this feature is only implemented by - // React DOM, we don't technically need this to be a stack. It could be a single - // module variable instead. - - var hostTransitionProviderCursor = createCursor(null); // TODO: This should initialize to NotPendingTransition, a constant - // imported from the fiber config. However, because of a cycle in the module - // graph, that value isn't defined during this module's initialization. I can't - // think of a way to work around this without moving that value out of the - // fiber config. For now, the "no provider" case is handled when reading, - // inside useHostTransitionStatus. - - var HostTransitionContext = { - $$typeof: REACT_CONTEXT_TYPE, - Provider: null, - Consumer: null, - _currentValue: null, - _currentValue2: null, - _threadCount: 0 - }; + childFiber = childFiber.sibling; + } - 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 (childFiber && node.children.length > 0) { + // If we had any further siblings after the last mismatch, we can't be sure if it's + // actually a valid match since it might not have found a match. So we exclude next + // siblings to avoid confusion. + childContent += indentation(indent) + '...' + '\n'; + } // Deleted tail nodes + + + var serverTail = node.serverTail; - return c; - } + for (var _i = 0; _i < serverTail.length; _i++) { + var tailNode = serverTail[_i]; - function getRootHostContainer() { - var rootInstance = requiredContext(rootInstanceStackCursor.current); - return rootInstance; + if (typeof tailNode === 'string') { + // Removed text node + childContent += removed(indent) + describeTextNode(tailNode, maxRowLength - indent * 2) + '\n'; + } else { + // Removed element + childContent += describeExpandedElement(tailNode.type, tailNode.props, removed(indent)); } + } - 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. + return parentContent + selfContent + childContent; +} - 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. +function describeDiff(rootNode) { + try { + return '\n\n' + describeNode(rootNode, 0); + } catch (x) { + return ''; + } +} - push(contextStackCursor, null, fiber); - var nextRootContext = getRootHostContext(); // Now that we know this function doesn't throw, replace it. +var isHydrating = false; // This flag allows for warning supression when we expect there to be mismatches - pop(contextStackCursor, fiber); - push(contextStackCursor, nextRootContext, fiber); - } +var hydrationDiffRootDEV = null; // Hydration errors that were thrown inside this boundary - function popHostContainer(fiber) { - pop(contextStackCursor, fiber); - pop(contextFiberStackCursor, fiber); - pop(rootInstanceStackCursor, fiber); - } +var hydrationErrors = null; - function getHostContext() { - var context = requiredContext(contextStackCursor.current); - return context; - } +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.'); + } +} - function pushHostContext(fiber) { - if (enableAsyncActions) { - var stateHook = fiber.memoizedState; +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 (stateHook !== null) { - // Only provide context if this fiber has been upgraded by a host - // transition. We use the same optimization for regular host context below. - push(hostTransitionProviderCursor, fiber, fiber); - } - } +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.'); + } +} - var context = requiredContext(contextStackCursor.current); - var nextContext = getChildHostContext(context, fiber.type); // Don't push this Fiber's context unless it's unique. +function popHydrationState(fiber) { + { + return false; + } +} - if (context !== nextContext) { - // 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 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 popHostContext(fiber) { - if (contextFiberStackCursor.current === fiber) { - // Do not pop unless this Fiber provided the current context. - // pushHostContext() only pushes Fibers that provide unique contexts. - pop(contextStackCursor, fiber); - pop(contextFiberStackCursor, fiber); - } +function getIsHydrating() { + return isHydrating; +} - if (enableAsyncActions) { - if (hostTransitionProviderCursor.current === fiber) { - // Do not pop unless this Fiber provided the current context. This is mostly - // a performance optimization, but conveniently it also prevents a potential - // data race where a host provider is upgraded (i.e. memoizedState becomes - // non-null) during a concurrent event. This is a bit of a flaw in the way - // we upgrade host components, but because we're accounting for it here, it - // should be fine. - pop(hostTransitionProviderCursor, fiber); // When popping the transition provider, we reset the context value back - // to `null`. We can do this because you're not allowd to nest forms. If - // we allowed for multiple nested host transition providers, then we'd - // need to reset this to the parent provider's status. +function queueHydrationError(error) { + if (hydrationErrors === null) { + hydrationErrors = [error]; + } else { + hydrationErrors.push(error); + } +} +function emitPendingHydrationWarnings() { + { + // If we haven't yet thrown any hydration errors by the time we reach the end we've successfully + // hydrated, however, we might still have DEV-only mismatches that we log now. + var diffRoot = hydrationDiffRootDEV; - { - HostTransitionContext._currentValue = null; - } - } - } + if (diffRoot !== null) { + hydrationDiffRootDEV = null; + var diff = describeDiff(diffRoot); + + error("A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. " + 'This can happen if a SSR-ed Client Component used:\n' + '\n' + "- A server/client branch `if (typeof window !== 'undefined')`.\n" + "- Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.\n" + "- Date formatting in a user's locale which doesn't match the server.\n" + '- External changing data without sending a snapshot of it along with the HTML.\n' + '- Invalid HTML tag nesting.\n' + '\n' + 'It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.\n' + '\n' + '%s%s', 'https://react.dev/link/hydration-mismatch', diff); } + } +} - var maxRowLength = 120; - var idealDepth = 15; +// 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 concurrentQueues = []; +var concurrentQueuesIndex = 0; +var concurrentlyUpdatedLanes = NoLanes; +function finishQueueingConcurrentUpdates() { + var endIndex = concurrentQueuesIndex; + concurrentQueuesIndex = 0; + concurrentlyUpdatedLanes = NoLanes; + var i = 0; + + 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; - function findNotableNode(node, indent) { - if ( - node.serverProps === undefined && - node.serverTail.length === 0 && - node.children.length === 1 && - node.distanceFromLeaf > 3 && - node.distanceFromLeaf > idealDepth - indent - ) { - // This is not an interesting node for contextual purposes so we can skip it. - var child = node.children[0]; - return findNotableNode(child, indent); + if (pending === null) { + // This is the first update. Create a circular list. + update.next = update; + } else { + update.next = pending.next; + pending.next = update; } - return node; + queue.pending = update; } - function indentation(indent) { - return " " + " ".repeat(indent); + if (lane !== NoLane) { + markUpdateLaneFromFiberToRoot(fiber, update, lane); } + } +} +function getConcurrentlyUpdatedLanes() { + return concurrentlyUpdatedLanes; +} - function added(indent) { - return "+ " + " ".repeat(indent); - } +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. + + fiber.lanes = mergeLanes(fiber.lanes, lane); + var alternate = fiber.alternate; + + if (alternate !== null) { + alternate.lanes = mergeLanes(alternate.lanes, lane); + } +} - function removed(indent) { - return "- " + " ".repeat(indent); - } +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; + + 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. + +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 describeFiberType(fiber) { - switch (fiber.tag) { - case HostHoistable: - case HostSingleton: - case HostComponent: - return fiber.type; +function markUpdateLaneFromFiberToRoot(sourceFiber, update, lane) { + // Update the source fiber's lanes + sourceFiber.lanes = mergeLanes(sourceFiber.lanes, lane); + var alternate = sourceFiber.alternate; - case LazyComponent: - return "Lazy"; + if (alternate !== null) { + alternate.lanes = mergeLanes(alternate.lanes, lane); + } // Walk the parent path to the root and update the child lanes. - case SuspenseComponent: - return "Suspense"; - case SuspenseListComponent: - return "SuspenseList"; + var isHidden = false; + var parent = sourceFiber.return; + var node = sourceFiber; - case FunctionComponent: - case SimpleMemoComponent: - var fn = fiber.type; - return fn.displayName || fn.name || null; + while (parent !== null) { + parent.childLanes = mergeLanes(parent.childLanes, lane); + alternate = parent.alternate; - case ForwardRef: - var render = fiber.type.render; - return render.displayName || render.name || null; + if (alternate !== null) { + alternate.childLanes = mergeLanes(alternate.childLanes, lane); + } - case ClassComponent: - var ctr = fiber.type; - return ctr.displayName || ctr.name || 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; - default: - // Skip - return null; + if (offscreenInstance !== null && !(offscreenInstance._visibility & OffscreenVisible)) { + isHidden = true; } } - var needsEscaping = /["'&<>\n\t]/; + node = parent; + parent = parent.return; + } - function describeTextNode(content, maxLength) { - if (needsEscaping.test(content)) { - var encoded = JSON.stringify(content); + if (isHidden && update !== null && node.tag === HostRoot) { + var root = node.stateNode; + markHiddenUpdate(root, update, lane); + } +} - if (encoded.length > maxLength - 2) { - if (maxLength < 8) { - return '{"..."}'; - } +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. + + detectUpdateOnUnmountedFiber(sourceFiber, sourceFiber); + var node = sourceFiber; + var parent = node.return; + + while (parent !== null) { + detectUpdateOnUnmountedFiber(sourceFiber, node); + node = parent; + parent = node.return; + } + + return node.tag === HostRoot ? node.stateNode : null; +} - return "{" + encoded.slice(0, maxLength - 7) + '..."}'; - } +function detectUpdateOnUnmountedFiber(sourceFiber, parent) { + { + var alternate = parent.alternate; - return "{" + encoded + "}"; - } else { - if (content.length > maxLength) { - if (maxLength < 5) { - return '{"..."}'; - } + if (alternate === null && (parent.flags & (Placement | Hydrating)) !== NoFlags$1) { + warnAboutUpdateOnNotYetMountedFiberInDEV(sourceFiber); + } + } +} - return content.slice(0, maxLength - 3) + "..."; - } +// there's only a single root, but we do support multi root apps, hence this +// extra complexity. But this module is optimized for the single root case. + +var firstScheduledRoot = null; +var lastScheduledRoot = null; // Used to prevent redundant mircotasks from being scheduled. + +var didScheduleMicrotask = false; // `act` "microtasks" are scheduled on the `act` queue instead of an actual +// microtask, so we have to dedupe those separately. This wouldn't be an issue +// if we required all `act` calls to be awaited, which we might in the future. + +var didScheduleMicrotask_act = false; // Used to quickly bail out of flushSync if there's no sync work to do. + +var mightHavePendingSyncWork = false; +var isFlushingWork = false; +var currentEventTransitionLane = NoLane; +function ensureRootIsScheduled(root) { + // This function is called whenever a root receives an update. It does two + // things 1) it ensures the root is in the root schedule, and 2) it ensures + // there's a pending microtask to process the root schedule. + // + // Most of the actual scheduling logic does not happen until + // `scheduleTaskForRootDuringMicrotask` runs. + // Add the root to the schedule + if (root === lastScheduledRoot || root.next !== null) ; else { + if (lastScheduledRoot === null) { + firstScheduledRoot = lastScheduledRoot = root; + } else { + lastScheduledRoot.next = root; + lastScheduledRoot = root; + } + } // Any time a root received an update, we set this to true until the next time + // we process the schedule. If it's false, then we can quickly exit flushSync + // without consulting the schedule. + + + mightHavePendingSyncWork = true; // At the end of the current event, go through each of the roots and ensure + // there's a task scheduled for each one at the correct priority. + + if (ReactSharedInternals.actQueue !== null) { + // We're inside an `act` scope. + if (!didScheduleMicrotask_act) { + didScheduleMicrotask_act = true; + scheduleImmediateTask(processRootScheduleInMicrotask); + } + } else { + if (!didScheduleMicrotask) { + didScheduleMicrotask = true; + scheduleImmediateTask(processRootScheduleInMicrotask); + } + } + + if (!enableDeferRootSchedulingToMicrotask) { + // While this flag is disabled, we schedule the render task immediately + // instead of waiting a microtask. + // TODO: We need to land enableDeferRootSchedulingToMicrotask ASAP to + // unblock additional features we have planned. + scheduleTaskForRootDuringMicrotask(root, now$1()); + } + + if (ReactSharedInternals.isBatchingLegacy && root.tag === LegacyRoot) { + // Special `act` case: Record whenever a legacy update is scheduled. + ReactSharedInternals.didScheduleLegacyUpdate = true; + } +} +function flushSyncWorkOnAllRoots() { + // This is allowed to be called synchronously, but the caller should check + // the execution context first. + flushSyncWorkAcrossRoots_impl(false); +} +function flushSyncWorkOnLegacyRootsOnly() { + // This is allowed to be called synchronously, but the caller should check + // the execution context first. + { + flushSyncWorkAcrossRoots_impl(true); + } +} - return content; - } - } +function flushSyncWorkAcrossRoots_impl(onlyLegacy) { + if (isFlushingWork) { + // Prevent reentrancy. + // TODO: Is this overly defensive? The callers must check the execution + // context first regardless. + return; + } - function describeTextDiff(clientText, serverProps, indent) { - var maxLength = maxRowLength - indent * 2; + if (!mightHavePendingSyncWork) { + // Fast path. There's no sync work to do. + return; + } // There may or may not be synchronous work scheduled. Let's check. - if (serverProps === null) { - return added(indent) + describeTextNode(clientText, maxLength) + "\n"; - } else if (typeof serverProps === "string") { - var serverText = serverProps; - var firstDiff = 0; - for ( - ; - firstDiff < serverText.length && firstDiff < clientText.length; - firstDiff++ - ) { - if ( - serverText.charCodeAt(firstDiff) !== - clientText.charCodeAt(firstDiff) - ) { - break; - } - } + var didPerformSomeWork; + isFlushingWork = true; - if (firstDiff > maxLength - 8 && firstDiff > 10) { - // The first difference between the two strings would be cut off, so cut off in - // the beginning instead. - clientText = "..." + clientText.slice(firstDiff - 8); - serverText = "..." + serverText.slice(firstDiff - 8); - } + do { + didPerformSomeWork = false; + var root = firstScheduledRoot; - return ( - added(indent) + - describeTextNode(clientText, maxLength) + - "\n" + - removed(indent) + - describeTextNode(serverText, maxLength) + - "\n" - ); - } else { - return ( - indentation(indent) + describeTextNode(clientText, maxLength) + "\n" - ); + while (root !== null) { + if (onlyLegacy && (root.tag !== LegacyRoot)) ; else { + var workInProgressRoot = getWorkInProgressRoot(); + var workInProgressRootRenderLanes = getWorkInProgressRootRenderLanes(); + var nextLanes = getNextLanes(root, root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes); + + if (includesSyncLane(nextLanes)) { + // This root has pending sync work. Flush it now. + didPerformSomeWork = true; + performSyncWorkOnRoot(root, nextLanes); + } } - } - function objectName(object) { - // $FlowFixMe[method-unbinding] - var name = Object.prototype.toString.call(object); - return name.replace(/^\[object (.*)\]$/, function (m, p0) { - return p0; - }); + root = root.next; } + } while (didPerformSomeWork); - function describeValue(value, maxLength) { - switch (typeof value) { - case "string": { - var encoded = JSON.stringify(value); + isFlushingWork = false; +} - if (encoded.length > maxLength) { - if (maxLength < 5) { - return '"..."'; - } +function processRootScheduleInMicrotask() { + // This function is always called inside a microtask. It should never be + // called synchronously. + didScheduleMicrotask = false; - return encoded.slice(0, maxLength - 4) + '..."'; - } + { + didScheduleMicrotask_act = false; + } // We'll recompute this as we iterate through all the roots and schedule them. - return encoded; - } - case "object": { - if (value === null) { - return "null"; - } + mightHavePendingSyncWork = false; + var currentTime = now$1(); + var prev = null; + var root = firstScheduledRoot; - if (isArray(value)) { - return "[...]"; - } + while (root !== null) { + var next = root.next; - if (value.$$typeof === REACT_ELEMENT_TYPE) { - var type = getComponentNameFromType(value.type); - return type ? "<" + type + ">" : "<...>"; - } + if (currentEventTransitionLane !== NoLane && shouldAttemptEagerTransition()) { + // A transition was scheduled during an event, but we're going to try to + // render it synchronously anyway. We do this during a popstate event to + // preserve the scroll position of the previous page. + upgradePendingLaneToSync(root, currentEventTransitionLane); + } - var name = objectName(value); + var nextLanes = scheduleTaskForRootDuringMicrotask(root, currentTime); - if (name === "Object") { - var properties = ""; - maxLength -= 2; + if (nextLanes === NoLane) { + // This root has no more pending work. Remove it from the schedule. To + // guard against subtle reentrancy bugs, this microtask is the only place + // we do this — you can add roots to the schedule whenever, but you can + // only remove them here. + // Null this out so we know it's been removed from the schedule. + root.next = null; - for (var propName in value) { - if (!value.hasOwnProperty(propName)) { - continue; - } + if (prev === null) { + // This is the new head of the list + firstScheduledRoot = next; + } else { + prev.next = next; + } - var jsonPropName = JSON.stringify(propName); + if (next === null) { + // This is the new tail of the list + lastScheduledRoot = prev; + } + } else { + // This root still has work. Keep it in the list. + prev = root; - if (jsonPropName !== '"' + propName + '"') { - propName = jsonPropName; - } + if (includesSyncLane(nextLanes)) { + mightHavePendingSyncWork = true; + } + } - maxLength -= propName.length - 2; - var propValue = describeValue( - value[propName], - maxLength < 15 ? maxLength : 15 - ); - maxLength -= propValue.length; + root = next; + } - if (maxLength < 0) { - properties += properties === "" ? "..." : ", ..."; - break; - } + currentEventTransitionLane = NoLane; // At the end of the microtask, flush any pending synchronous work. This has + // to come at the end, because it does actual rendering work that might throw. - properties += - (properties === "" ? "" : ",") + propName + ":" + propValue; - } + flushSyncWorkOnAllRoots(); +} - return "{" + properties + "}"; - } +function scheduleTaskForRootDuringMicrotask(root, currentTime) { + // This function is always called inside a microtask, or at the very end of a + // rendering task right before we yield to the main thread. It should never be + // called synchronously. + // + // TODO: Unless enableDeferRootSchedulingToMicrotask is off. We need to land + // that ASAP to unblock additional features we have planned. + // + // This function also never performs React work synchronously; it should + // only schedule work to be performed later, in a separate task or microtask. + // Check if any lanes are being starved by other work. If so, mark them as + // expired so we know to work on those next. + markStarvedLanesAsExpired(root, currentTime); // Determine the next lanes to work on, and their priority. + + var workInProgressRoot = getWorkInProgressRoot(); + var workInProgressRootRenderLanes = getWorkInProgressRootRenderLanes(); + var nextLanes = getNextLanes(root, root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes); + var existingCallbackNode = root.callbackNode; + + if ( // Check if there's nothing to work on + nextLanes === NoLanes || // 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. + // + // Suspended render phase + root === workInProgressRoot && isWorkLoopSuspendedOnData() || // Suspended commit phase + root.cancelPendingCommit !== null) { + // Fast path: There's nothing to work on. + if (existingCallbackNode !== null) { + cancelCallback(existingCallbackNode); + } + + root.callbackNode = null; + root.callbackPriority = NoLane; + return NoLane; + } // Schedule a new callback in the host environment. + + + if (includesSyncLane(nextLanes)) { + // Synchronous work is always flushed at the end of the microtask, so we + // don't need to schedule an additional task. + if (existingCallbackNode !== null) { + cancelCallback(existingCallbackNode); + } + + root.callbackPriority = SyncLane; + root.callbackNode = null; + return SyncLane; + } else { + // We use the highest priority lane to represent the priority of the callback. + var existingCallbackPriority = root.callbackPriority; + var newCallbackPriority = getHighestPriorityLane(nextLanes); + + if (newCallbackPriority === existingCallbackPriority && // Special case related to `act`. If the currently scheduled task is a + // Scheduler task, rather than an `act` task, cancel it and re-schedule + // on the `act` queue. + !(ReactSharedInternals.actQueue !== null && existingCallbackNode !== fakeActCallbackNode$1)) { + // The priority hasn't changed. We can reuse the existing task. + return newCallbackPriority; + } else { + // Cancel the existing callback. We'll schedule a new one below. + cancelCallback(existingCallbackNode); + } + + var schedulerPriorityLevel; + + switch (lanesToEventPriority(nextLanes)) { + case DiscreteEventPriority: + schedulerPriorityLevel = ImmediatePriority; + break; + + case ContinuousEventPriority: + schedulerPriorityLevel = UserBlockingPriority; + break; + + case DefaultEventPriority: + schedulerPriorityLevel = NormalPriority$1; + break; + + case IdleEventPriority: + schedulerPriorityLevel = IdlePriority; + break; + + default: + schedulerPriorityLevel = NormalPriority$1; + break; + } + + var newCallbackNode = scheduleCallback$2(schedulerPriorityLevel, performConcurrentWorkOnRoot.bind(null, root)); + root.callbackPriority = newCallbackPriority; + root.callbackNode = newCallbackNode; + return newCallbackPriority; + } +} - return name; - } +function getContinuationForRoot(root, originalCallbackNode) { + // This is called at the end of `performConcurrentWorkOnRoot` to determine + // if we need to schedule a continuation task. + // + // Usually `scheduleTaskForRootDuringMicrotask` only runs inside a microtask; + // however, since most of the logic for determining if we need a continuation + // versus a new task is the same, we cheat a bit and call it here. This is + // only safe to do because we know we're at the end of the browser task. + // So although it's not an actual microtask, it might as well be. + scheduleTaskForRootDuringMicrotask(root, now$1()); + + 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); + } + + return null; +} +var fakeActCallbackNode$1 = {}; + +function scheduleCallback$2(priorityLevel, callback) { + if (ReactSharedInternals.actQueue !== null) { + // Special case: We're inside an `act` scope (a testing utility). + // Instead of scheduling work in the host environment, add it to a + // fake internal queue that's managed by the `act` implementation. + ReactSharedInternals.actQueue.push(callback); + return fakeActCallbackNode$1; + } else { + return scheduleCallback$3(priorityLevel, callback); + } +} - case "function": { - var _name = value.displayName || value.name; +function cancelCallback(callbackNode) { + if (callbackNode === fakeActCallbackNode$1) ; else if (callbackNode !== null) { + cancelCallback$1(callbackNode); + } +} - return _name ? "function " + _name : "function"; - } +function scheduleImmediateTask(cb) { + if (ReactSharedInternals.actQueue !== null) { + // Special case: Inside an `act` scope, we push microtasks to the fake `act` + // callback queue. This is because we currently support calling `act` + // without awaiting the result. The plan is to deprecate that, and require + // that you always await the result so that the microtasks have a chance to + // run. But it hasn't happened yet. + ReactSharedInternals.actQueue.push(function () { + cb(); + return null; + }); + } // TODO: Can we land supportsMicrotasks? Which environments don't support it? + // Alternatively, can we move this check to the host config? - default: - // eslint-disable-next-line react-internal/safe-string-coercion - return String(value); - } - } - function describePropValue(value, maxLength) { - if (typeof value === "string" && !needsEscaping.test(value)) { - if (value.length > maxLength - 2) { - if (maxLength < 5) { - return '"..."'; - } + { + // If microtasks are not supported, use Scheduler. + scheduleCallback$3(ImmediatePriority, cb); + } +} - return '"' + value.slice(0, maxLength - 5) + '..."'; - } +function requestTransitionLane( // This argument isn't used, it's only here to encourage the caller to +// check that it's inside a transition before calling this function. +// TODO: Make this non-nullable. Requires a tweak to useOptimistic. +transition) { + // 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(); + } + + return currentEventTransitionLane; +} - return '"' + value + '"'; +// transition updates that occur while the async action is still in progress +// are treated as part of the action. +// +// The ideal behavior would be to treat each async function as an independent +// action. However, without a mechanism like AsyncContext, we can't tell which +// action an update corresponds to. So instead, we entangle them all into one. +// The listeners to notify once the entangled scope completes. + +var currentEntangledListeners = null; // The number of pending async actions in the entangled scope. + +var currentEntangledPendingCount = 0; // The transition lane shared by all updates in the entangled scope. + +var currentEntangledLane = NoLane; // A thenable that resolves when the entangled scope completes. It does not +// resolve to a particular value because it's only used for suspending the UI +// until the async action scope has completed. + +var currentEntangledActionThenable = null; +function entangleAsyncAction(transition, thenable) { + // `thenable` is the return value of the async action scope function. Create + // a combined thenable that resolves once every entangled scope function + // has finished. + if (currentEntangledListeners === null) { + // There's no outer async action scope. Create a new one. + var entangledListeners = currentEntangledListeners = []; + currentEntangledPendingCount = 0; + currentEntangledLane = requestTransitionLane(); + var entangledThenable = { + status: 'pending', + value: undefined, + then: function (resolve) { + entangledListeners.push(resolve); } + }; + currentEntangledActionThenable = entangledThenable; + } - return "{" + describeValue(value, maxLength - 2) + "}"; - } - - function describeCollapsedElement(type, props, indent) { - // This function tries to fit the props into a single line for non-essential elements. - // We also ignore children because we're not going deeper. - var maxLength = maxRowLength - indent * 2 - type.length - 2; - var content = ""; - - for (var propName in props) { - if (!props.hasOwnProperty(propName)) { - continue; - } + currentEntangledPendingCount++; + thenable.then(pingEngtangledActionScope, pingEngtangledActionScope); + return thenable; +} - if (propName === "children") { - // Ignored. - continue; - } +function pingEngtangledActionScope() { + if (currentEntangledListeners !== null && --currentEntangledPendingCount === 0) { + // All the actions have finished. Close the entangled async action scope + // and notify all the listeners. + if (currentEntangledActionThenable !== null) { + var fulfilledThenable = currentEntangledActionThenable; + fulfilledThenable.status = 'fulfilled'; + } - var propValue = describePropValue(props[propName], 15); - maxLength -= propName.length + propValue.length + 2; + var listeners = currentEntangledListeners; + currentEntangledListeners = null; + currentEntangledLane = NoLane; + currentEntangledActionThenable = null; - if (maxLength < 0) { - content += " ..."; - break; - } + for (var i = 0; i < listeners.length; i++) { + var listener = listeners[i]; + listener(); + } + } +} - content += " " + propName + "=" + propValue; - } +function chainThenableValue(thenable, result) { + // Equivalent to: Promise.resolve(thenable).then(() => result), except we can + // cheat a bit since we know that that this thenable is only ever consumed + // by React. + // + // We don't technically require promise support on the client yet, hence this + // extra code. + var listeners = []; + var thenableWithOverride = { + status: 'pending', + value: null, + reason: null, + then: function (resolve) { + listeners.push(resolve); + } + }; + thenable.then(function (value) { + var fulfilledThenable = thenableWithOverride; + fulfilledThenable.status = 'fulfilled'; + fulfilledThenable.value = result; + + for (var i = 0; i < listeners.length; i++) { + var listener = listeners[i]; + listener(result); + } + }, function (error) { + var rejectedThenable = thenableWithOverride; + rejectedThenable.status = 'rejected'; + rejectedThenable.reason = error; + + for (var i = 0; i < listeners.length; i++) { + var listener = listeners[i]; // This is a perf hack where we call the `onFulfill` ping function + // instead of `onReject`, because we know that React is the only + // consumer of these promises, and it passes the same listener to both. + // We also know that it will read the error directly off the + // `.reason` field. + + listener(undefined); + } + }); + return thenableWithOverride; +} +function peekEntangledActionLane() { + return currentEntangledLane; +} +function peekEntangledActionThenable() { + return currentEntangledActionThenable; +} - return indentation(indent) + "<" + type + content + ">\n"; - } +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`. - function describeExpandedElement(type, props, rowPrefix) { - // This function tries to fit the props into a single line for non-essential elements. - // We also ignore children because we're not going deeper. - var remainingRowLength = maxRowLength - rowPrefix.length - type.length; // We add the properties to a set so we can choose later whether we'll put it on one - // line or multiple lines. +var hasForceUpdate = false; +var didWarnUpdateInsideUpdate; +var currentlyProcessingQueue; - var properties = []; +{ + didWarnUpdateInsideUpdate = false; + currentlyProcessingQueue = null; +} - for (var propName in props) { - if (!props.hasOwnProperty(propName)) { - continue; - } +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 (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; - if (propName === "children") { - // Ignored. - continue; - } + if (updateQueue === null) { + // Only occurs if the fiber has been unmounted. + return null; + } - var maxLength = maxRowLength - rowPrefix.length - propName.length - 1; - var propValue = describePropValue(props[propName], maxLength); - remainingRowLength -= propName.length + propValue.length + 2; - properties.push(propName + "=" + propValue); - } + var sharedQueue = updateQueue.shared; - if (properties.length === 0) { - return rowPrefix + "<" + type + ">\n"; - } else if (remainingRowLength > 0) { - // We can fit all on one row. - return rowPrefix + "<" + type + " " + properties.join(" ") + ">\n"; - } else { - // Split into one row per property: - return ( - rowPrefix + - "<" + - type + - "\n" + - rowPrefix + - " " + - properties.join("\n" + rowPrefix + " ") + - "\n" + - rowPrefix + - ">\n" - ); - } - } - - function describePropertiesDiff(clientObject, serverObject, indent) { - var properties = ""; - var remainingServerProperties = assign({}, serverObject); - - for (var propName in clientObject) { - if (!clientObject.hasOwnProperty(propName)) { - continue; - } + { + if (currentlyProcessingQueue === sharedQueue && !didWarnUpdateInsideUpdate) { + var componentName = getComponentNameFromFiber(fiber); - delete remainingServerProperties[propName]; - var maxLength = maxRowLength - indent * 2 - propName.length - 2; - var clientValue = clientObject[propName]; - var clientPropValue = describeValue(clientValue, maxLength); + 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 (serverObject.hasOwnProperty(propName)) { - var serverValue = serverObject[propName]; - var serverPropValue = describeValue(serverValue, maxLength); - properties += - added(indent) + propName + ": " + clientPropValue + "\n"; - properties += - removed(indent) + propName + ": " + serverPropValue + "\n"; - } else { - properties += - added(indent) + propName + ": " + clientPropValue + "\n"; - } - } + didWarnUpdateInsideUpdate = true; + } + } - for (var _propName in remainingServerProperties) { - if (!remainingServerProperties.hasOwnProperty(_propName)) { - continue; - } + 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; - var _maxLength = maxRowLength - indent * 2 - _propName.length - 2; + if (pending === null) { + // This is the first update. Create a circular list. + update.next = update; + } else { + update.next = pending.next; + pending.next = update; + } - var _serverValue = remainingServerProperties[_propName]; + 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 _serverPropValue = describeValue(_serverValue, _maxLength); + return unsafe_markUpdateLaneFromFiberToRoot(fiber, lane); + } else { + return enqueueConcurrentClassUpdate(fiber, sharedQueue, update, lane); + } +} +function entangleTransitions(root, fiber, lane) { + var updateQueue = fiber.updateQueue; - properties += - removed(indent) + _propName + ": " + _serverPropValue + "\n"; - } + if (updateQueue === null) { + // Only occurs if the fiber has been unmounted. + return; + } - return properties; - } + var sharedQueue = updateQueue.shared; - function describeElementDiff(type, clientProps, serverProps, indent) { - var content = ""; // Maps any previously unmatched lower case server prop name to its full prop name + 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. - var serverPropNames = new Map(); + queueLanes = intersectLanes(queueLanes, root.pendingLanes); // Entangle the new transition lane with the other transition lanes. - for (var propName in serverProps) { - if (!serverProps.hasOwnProperty(propName)) { - continue; - } + 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. - serverPropNames.set(propName.toLowerCase(), propName); - } + 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 current = workInProgress.alternate; + + if (current !== null) { + var currentQueue = current.updateQueue; + + 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; - if (serverPropNames.size === 1 && serverPropNames.has("children")) { - content += describeExpandedElement( - type, - clientProps, - indentation(indent) - ); - } else { - for (var _propName2 in clientProps) { - if (!clientProps.hasOwnProperty(_propName2)) { - continue; - } + if (firstBaseUpdate !== null) { + // Loop through the updates and clone them. + var update = firstBaseUpdate; - if (_propName2 === "children") { - // Handled below. - continue; - } + 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 maxLength = - maxRowLength - (indent + 1) * 2 - _propName2.length - 1; - var serverPropName = serverPropNames.get(_propName2.toLowerCase()); - - if (serverPropName !== undefined) { - serverPropNames.delete(_propName2.toLowerCase()); // There's a diff here. - - var clientValue = clientProps[_propName2]; - var serverValue = serverProps[serverPropName]; - var clientPropValue = describePropValue(clientValue, maxLength); - var serverPropValue = describePropValue(serverValue, maxLength); - - if ( - typeof clientValue === "object" && - clientValue !== null && - typeof serverValue === "object" && - serverValue !== null && - objectName(clientValue) === "Object" && - objectName(serverValue) === "Object" && // Only do the diff if the object has a lot of keys or was shortened. - (Object.keys(clientValue).length > 2 || - Object.keys(serverValue).length > 2 || - clientPropValue.indexOf("...") > -1 || - serverPropValue.indexOf("...") > -1) - ) { - // We're comparing two plain objects. We can diff the nested objects instead. - content += - indentation(indent + 1) + - _propName2 + - "={{\n" + - describePropertiesDiff(clientValue, serverValue, indent + 2) + - indentation(indent + 1) + - "}}\n"; - } else { - content += - added(indent + 1) + _propName2 + "=" + clientPropValue + "\n"; - content += - removed(indent + 1) + _propName2 + "=" + serverPropValue + "\n"; - } + if (newLast === null) { + newFirst = newLast = clone; } else { - // Considered equal. - content += - indentation(indent + 1) + - _propName2 + - "=" + - describePropValue(clientProps[_propName2], maxLength) + - "\n"; - } - } + newLast.next = clone; + newLast = clone; + } // $FlowFixMe[incompatible-type] we bail out when we get a null - serverPropNames.forEach(function (propName) { - if (propName === "children") { - // Handled below. - return; - } - var maxLength = maxRowLength - (indent + 1) * 2 - propName.length - 1; - content += - removed(indent + 1) + - propName + - "=" + - describePropValue(serverProps[propName], maxLength) + - "\n"; - }); + update = update.next; + } while (update !== null); // Append the captured update the end of the cloned list. - if (content === "") { - // No properties - content = indentation(indent) + "<" + type + ">\n"; + + if (newLast === null) { + newFirst = newLast = capturedUpdate; } else { - // Had properties - content = - indentation(indent) + - "<" + - type + - "\n" + - content + - indentation(indent) + - ">\n"; + newLast.next = capturedUpdate; + newLast = capturedUpdate; } + } else { + // There are no base updates. + newFirst = newLast = capturedUpdate; } - var serverChildren = serverProps.children; - var clientChildren = clientProps.children; - - if ( - typeof serverChildren === "string" || - typeof serverChildren === "number" || - typeof serverChildren === "bigint" - ) { - // There's a diff of the children. - // $FlowFixMe[unsafe-addition] - var serverText = "" + serverChildren; - var clientText = ""; + 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. - if ( - typeof clientChildren === "string" || - typeof clientChildren === "number" || - typeof clientChildren === "bigint" - ) { - // $FlowFixMe[unsafe-addition] - clientText = "" + clientChildren; - } - content += describeTextDiff(clientText, serverText, indent + 1); - } else if ( - typeof clientChildren === "string" || - typeof clientChildren === "number" || - typeof clientChildren === "bigint" - ) { - // The client has children but it's not considered a difference from the server. - // $FlowFixMe[unsafe-addition] - content += describeTextDiff("" + clientChildren, undefined, indent + 1); - } + var lastBaseUpdate = queue.lastBaseUpdate; - return content; - } + if (lastBaseUpdate === null) { + queue.firstBaseUpdate = capturedUpdate; + } else { + lastBaseUpdate.next = capturedUpdate; + } - function describeSiblingFiber(fiber, indent) { - var type = describeFiberType(fiber); + queue.lastBaseUpdate = capturedUpdate; +} - if (type === null) { - // Skip this type of fiber. We currently treat this as a fragment - // so it's just part of the parent's children. - var flatContent = ""; - var childFiber = fiber.child; +function getStateFromUpdate(workInProgress, queue, update, prevState, nextProps, instance) { + switch (update.tag) { + case ReplaceState: + { + var payload = update.payload; - while (childFiber) { - flatContent += describeSiblingFiber(childFiber, indent); - childFiber = childFiber.sibling; - } + if (typeof payload === 'function') { + // Updater function + { + enterDisallowedContextReadInDEV(); + } - return flatContent; - } + var nextState = payload.call(instance, prevState, nextProps); - return indentation(indent) + "<" + type + ">" + "\n"; - } + { + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); - function describeNode(node, indent) { - var skipToNode = findNotableNode(node, indent); + try { + payload.call(instance, prevState, nextProps); + } finally { + setIsStrictModeForDevtools(false); + } + } - if ( - skipToNode !== node && - (node.children.length !== 1 || node.children[0] !== skipToNode) - ) { - return ( - indentation(indent) + "...\n" + describeNode(skipToNode, indent + 1) - ); - } // Prefix with any server components for context + exitDisallowedContextReadInDEV(); + } - var parentContent = ""; - var debugInfo = node.fiber._debugInfo; + return nextState; + } // State object - if (debugInfo) { - for (var i = 0; i < debugInfo.length; i++) { - var serverComponentName = debugInfo[i].name; - if (typeof serverComponentName === "string") { - parentContent += - indentation(indent) + "<" + serverComponentName + ">" + "\n"; - indent++; - } - } - } // Self + return payload; + } - var selfContent = ""; // We use the pending props since we might be generating a diff before the complete phase - // when something throws. + case CaptureUpdate: + { + workInProgress.flags = workInProgress.flags & ~ShouldCapture | DidCapture; + } + // Intentional fallthrough - var clientProps = node.fiber.pendingProps; + case UpdateState: + { + var _payload = update.payload; + var partialState; - if (node.fiber.tag === HostText) { - // Text Node - selfContent = describeTextDiff(clientProps, node.serverProps, indent); - } else { - var type = describeFiberType(node.fiber); - - if (type !== null) { - // Element Node - if (node.serverProps === undefined) { - // Just a reference node for context. - selfContent = describeCollapsedElement(type, clientProps, indent); - indent++; - } else if (node.serverProps === null) { - selfContent = describeExpandedElement( - type, - clientProps, - added(indent) - ); // If this was an insertion we won't step down further. Any tail - // are considered siblings so we don't indent. - // TODO: Model this a little better. - } else if (typeof node.serverProps === "string") { - { - error( - "Should not have matched a non HostText fiber to a Text node. This is a bug in React." - ); - } - } else { - selfContent = describeElementDiff( - type, - clientProps, - node.serverProps, - indent - ); - indent++; + if (typeof _payload === 'function') { + // Updater function + { + enterDisallowedContextReadInDEV(); } - } - } // Compute children - var childContent = ""; - var childFiber = node.fiber.child; - var diffIdx = 0; + partialState = _payload.call(instance, prevState, nextProps); + + { + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); - while (childFiber && diffIdx < node.children.length) { - var childNode = node.children[diffIdx]; + try { + _payload.call(instance, prevState, nextProps); + } finally { + setIsStrictModeForDevtools(false); + } + } - if (childNode.fiber === childFiber) { - // This was a match in the diff. - childContent += describeNode(childNode, indent); - diffIdx++; + exitDisallowedContextReadInDEV(); + } } else { - // This is an unrelated previous sibling. - childContent += describeSiblingFiber(childFiber, indent); + // Partial state object + partialState = _payload; } - childFiber = childFiber.sibling; - } - - if (childFiber && node.children.length > 0) { - // If we had any further siblings after the last mismatch, we can't be sure if it's - // actually a valid match since it might not have found a match. So we exclude next - // siblings to avoid confusion. - childContent += indentation(indent) + "..." + "\n"; - } // Deleted tail nodes + if (partialState === null || partialState === undefined) { + // Null and undefined are treated as no-ops. + return prevState; + } // Merge the partial state and the previous state. - var serverTail = node.serverTail; - for (var _i = 0; _i < serverTail.length; _i++) { - var tailNode = serverTail[_i]; + return assign({}, prevState, partialState); + } - if (typeof tailNode === "string") { - // Removed text node - childContent += - removed(indent) + - describeTextNode(tailNode, maxRowLength - indent * 2) + - "\n"; - } else { - // Removed element - childContent += describeExpandedElement( - tailNode.type, - tailNode.props, - removed(indent) - ); - } + case ForceUpdate: + { + hasForceUpdate = true; + return prevState; } + } - return parentContent + selfContent + childContent; - } + return prevState; +} - function describeDiff(rootNode) { - try { - return "\n\n" + describeNode(rootNode, 0); - } catch (x) { - return ""; - } - } +var didReadFromEntangledAsyncAction = false; // Each call to processUpdateQueue should be accompanied by a call to this. It's +// only in a separate function because in updateHostRoot, it must happen after +// all the context stacks have been pushed to, to prevent a stack mismatch. A +// bit unfortunate. + +function suspendIfUpdateReadFromEntangledAsyncAction() { + // Check if this update is part of a pending async action. If so, we'll + // need to suspend until the action has finished, so that it's batched + // together with future updates in the same action. + // TODO: Once we support hooks inside useMemo (or an equivalent + // memoization boundary like Forget), hoist this logic so that it only + // suspends if the memo boundary produces a new value. + if (didReadFromEntangledAsyncAction) { + var entangledActionThenable = peekEntangledActionThenable(); + + if (entangledActionThenable !== null) { + // TODO: Instead of the throwing the thenable directly, throw a + // special object like `use` does so we can detect if it's captured + // by userspace. + throw entangledActionThenable; + } + } +} +function processUpdateQueue(workInProgress, props, instance, renderLanes) { + didReadFromEntangledAsyncAction = false; // This is always non-null on a ClassComponent or HostRoot - var isHydrating = false; // This flag allows for warning supression when we expect there to be mismatches + var queue = workInProgress.updateQueue; + hasForceUpdate = false; - var hydrationDiffRootDEV = null; // Hydration errors that were thrown inside this boundary + { + currentlyProcessingQueue = queue.shared; + } - var hydrationErrors = null; + var firstBaseUpdate = queue.firstBaseUpdate; + var lastBaseUpdate = queue.lastBaseUpdate; // Check if there are pending updates. If so, transfer them to the base queue. - 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 pendingQueue = queue.shared.pending; - 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 (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 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." - ); - } - } + var lastPendingUpdate = pendingQueue; + var firstPendingUpdate = lastPendingUpdate.next; + lastPendingUpdate.next = null; // Append pending updates to base queue - function popHydrationState(fiber) { - { - return false; - } + if (lastBaseUpdate === null) { + firstBaseUpdate = firstPendingUpdate; + } else { + lastBaseUpdate.next = firstPendingUpdate; } - 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; - } - } + 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 - function getIsHydrating() { - return isHydrating; - } + var current = workInProgress.alternate; - function queueHydrationError(error) { - if (hydrationErrors === null) { - hydrationErrors = [error]; - } else { - hydrationErrors.push(error); - } - } - function emitPendingHydrationWarnings() { - { - // If we haven't yet thrown any hydration errors by the time we reach the end we've successfully - // hydrated, however, we might still have DEV-only mismatches that we log now. - var diffRoot = hydrationDiffRootDEV; - - if (diffRoot !== null) { - hydrationDiffRootDEV = null; - var diff = describeDiff(diffRoot); - - error( - "A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. " + - "This can happen if a SSR-ed Client Component used:\n" + - "\n" + - "- A server/client branch `if (typeof window !== 'undefined')`.\n" + - "- Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.\n" + - "- Date formatting in a user's locale which doesn't match the server.\n" + - "- External changing data without sending a snapshot of it along with the HTML.\n" + - "- Invalid HTML tag nesting.\n" + - "\n" + - "It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.\n" + - "\n" + - "%s%s", - "https://react.dev/link/hydration-mismatch", - diff - ); - } - } - } - - // 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 concurrentQueues = []; - var concurrentQueuesIndex = 0; - var concurrentlyUpdatedLanes = NoLanes; - function finishQueueingConcurrentUpdates() { - var endIndex = concurrentQueuesIndex; - concurrentQueuesIndex = 0; - concurrentlyUpdatedLanes = NoLanes; - var i = 0; - - 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; - } + if (current !== null) { + // This is always non-null on a ClassComponent or HostRoot + var currentQueue = current.updateQueue; + var currentLastBaseUpdate = currentQueue.lastBaseUpdate; - queue.pending = update; + if (currentLastBaseUpdate !== lastBaseUpdate) { + if (currentLastBaseUpdate === null) { + currentQueue.firstBaseUpdate = firstPendingUpdate; + } else { + currentLastBaseUpdate.next = firstPendingUpdate; } - if (lane !== NoLane) { - markUpdateLaneFromFiberToRoot(fiber, update, lane); - } + currentQueue.lastBaseUpdate = lastPendingUpdate; } } - function getConcurrentlyUpdatedLanes() { - return concurrentlyUpdatedLanes; - } + } // These values may change as we process the queue. - 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. - fiber.lanes = mergeLanes(fiber.lanes, lane); - var alternate = fiber.alternate; + 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. - if (alternate !== null) { - alternate.lanes = mergeLanes(alternate.lanes, lane); - } - } - - 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 newLanes = NoLanes; + var newBaseState = null; + var newFirstBaseUpdate = null; + var newLastBaseUpdate = null; + var update = firstBaseUpdate; - var isConcurrentlyRendering = getWorkInProgressRoot() !== null; + 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 (!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. + var shouldSkipUpdate = isHiddenUpdate ? !isSubsetOfLanes(getWorkInProgressRootRenderLanes(), updateLane) : !isSubsetOfLanes(renderLanes, updateLane); - 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 (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 + }; + + if (newLastBaseUpdate === null) { + newFirstBaseUpdate = newLastBaseUpdate = clone; + newBaseState = newState; + } else { + newLastBaseUpdate = newLastBaseUpdate.next = clone; + } // Update the remaining priority in the queue. - function markUpdateLaneFromFiberToRoot(sourceFiber, update, lane) { - // Update the source fiber's lanes - sourceFiber.lanes = mergeLanes(sourceFiber.lanes, lane); - var alternate = sourceFiber.alternate; - if (alternate !== null) { - alternate.lanes = mergeLanes(alternate.lanes, lane); - } // Walk the parent path to the root and update the child lanes. + newLanes = mergeLanes(newLanes, updateLane); + } else { + // This update does have sufficient priority. + // Check if this update is part of a pending async action. If so, + // we'll need to suspend until the action has finished, so that it's + // batched together with future updates in the same action. + if (updateLane !== NoLane && updateLane === peekEntangledActionLane()) { + didReadFromEntangledAsyncAction = true; + } + + 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. - var isHidden = false; - var parent = sourceFiber.return; - var node = sourceFiber; - while (parent !== null) { - parent.childLanes = mergeLanes(parent.childLanes, lane); - alternate = parent.alternate; + newState = getStateFromUpdate(workInProgress, queue, update, newState, props, instance); + var callback = update.callback; - if (alternate !== null) { - alternate.childLanes = mergeLanes(alternate.childLanes, lane); - } + if (callback !== null) { + workInProgress.flags |= Callback; - 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 ( - offscreenInstance !== null && - !(offscreenInstance._visibility & OffscreenVisible) - ) { - isHidden = true; + if (isHiddenUpdate) { + workInProgress.flags |= Visibility; } - } - node = parent; - parent = parent.return; - } - - if (isHidden && update !== null && node.tag === HostRoot) { - var root = node.stateNode; - markHiddenUpdate(root, update, lane); - } - } + var callbacks = queue.callbacks; - 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 (callbacks === null) { + queue.callbacks = [callback]; + } else { + callbacks.push(callback); + } + } + } // $FlowFixMe[incompatible-type] we bail out when we get a null - detectUpdateOnUnmountedFiber(sourceFiber, sourceFiber); - var node = sourceFiber; - var parent = node.return; - while (parent !== null) { - detectUpdateOnUnmountedFiber(sourceFiber, node); - node = parent; - parent = node.return; - } + update = update.next; - return node.tag === HostRoot ? node.stateNode : null; - } + if (update === null) { + pendingQueue = queue.shared.pending; - function detectUpdateOnUnmountedFiber(sourceFiber, parent) { - { - var alternate = parent.alternate; + 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 ( - alternate === null && - (parent.flags & (Placement | Hydrating)) !== NoFlags$1 - ) { - warnAboutUpdateOnNotYetMountedFiberInDEV(sourceFiber); + var _firstPendingUpdate = _lastPendingUpdate.next; + _lastPendingUpdate.next = null; + update = _firstPendingUpdate; + queue.lastBaseUpdate = _lastPendingUpdate; + queue.shared.pending = null; } } + } while (true); + + if (newLastBaseUpdate === null) { + newBaseState = newState; } - // there's only a single root, but we do support multi root apps, hence this - // extra complexity. But this module is optimized for the single root case. + queue.baseState = newBaseState; + queue.firstBaseUpdate = newFirstBaseUpdate; + queue.lastBaseUpdate = newLastBaseUpdate; - var firstScheduledRoot = null; - var lastScheduledRoot = null; // Used to prevent redundant mircotasks from being scheduled. + 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. - var didScheduleMicrotask = false; // `act` "microtasks" are scheduled on the `act` queue instead of an actual - // microtask, so we have to dedupe those separately. This wouldn't be an issue - // if we required all `act` calls to be awaited, which we might in the future. - var didScheduleMicrotask_act = false; // Used to quickly bail out of flushSync if there's no sync work to do. + markSkippedUpdateLanes(newLanes); + workInProgress.lanes = newLanes; + workInProgress.memoizedState = newState; + } - var mightHavePendingSyncWork = false; - var isFlushingWork = false; - var currentEventTransitionLane = NoLane; - function ensureRootIsScheduled(root) { - // This function is called whenever a root receives an update. It does two - // things 1) it ensures the root is in the root schedule, and 2) it ensures - // there's a pending microtask to process the root schedule. - // - // Most of the actual scheduling logic does not happen until - // `scheduleTaskForRootDuringMicrotask` runs. - // Add the root to the schedule - if (root === lastScheduledRoot || root.next !== null); - else { - if (lastScheduledRoot === null) { - firstScheduledRoot = lastScheduledRoot = root; - } else { - lastScheduledRoot.next = root; - lastScheduledRoot = root; - } - } // Any time a root received an update, we set this to true until the next time - // we process the schedule. If it's false, then we can quickly exit flushSync - // without consulting the schedule. + { + currentlyProcessingQueue = null; + } +} - mightHavePendingSyncWork = true; // At the end of the current event, go through each of the roots and ensure - // there's a task scheduled for each one at the correct priority. +function callCallback(callback, context) { + if (typeof callback !== 'function') { + throw new Error('Invalid argument passed as callback. Expected a function. Instead ' + ("received: " + callback)); + } - if (ReactSharedInternals.actQueue !== null) { - // We're inside an `act` scope. - if (!didScheduleMicrotask_act) { - didScheduleMicrotask_act = true; - scheduleImmediateTask(processRootScheduleInMicrotask); - } - } else { - if (!didScheduleMicrotask) { - didScheduleMicrotask = true; - scheduleImmediateTask(processRootScheduleInMicrotask); - } - } + callback.call(context); +} - if (!enableDeferRootSchedulingToMicrotask) { - // While this flag is disabled, we schedule the render task immediately - // instead of waiting a microtask. - // TODO: We need to land enableDeferRootSchedulingToMicrotask ASAP to - // unblock additional features we have planned. - scheduleTaskForRootDuringMicrotask(root, now$1()); - } +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; - if (ReactSharedInternals.isBatchingLegacy && root.tag === LegacyRoot) { - // Special `act` case: Record whenever a legacy update is scheduled. - ReactSharedInternals.didScheduleLegacyUpdate = true; - } + if (newHiddenCallbacks !== null) { + var existingHiddenCallbacks = updateQueue.shared.hiddenCallbacks; + + if (existingHiddenCallbacks === null) { + updateQueue.shared.hiddenCallbacks = newHiddenCallbacks; + } else { + updateQueue.shared.hiddenCallbacks = existingHiddenCallbacks.concat(newHiddenCallbacks); } - function flushSyncWorkOnAllRoots() { - // This is allowed to be called synchronously, but the caller should check - // the execution context first. - flushSyncWorkAcrossRoots_impl(false); + } +} +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 flushSyncWorkOnLegacyRootsOnly() { - // This is allowed to be called synchronously, but the caller should check - // the execution context first. - { - flushSyncWorkAcrossRoots_impl(true); - } + } +} +function commitCallbacks(updateQueue, context) { + var callbacks = updateQueue.callbacks; + + if (callbacks !== null) { + updateQueue.callbacks = null; + + for (var i = 0; i < callbacks.length; i++) { + var callback = callbacks[i]; + callCallback(callback, context); } + } +} - function flushSyncWorkAcrossRoots_impl(onlyLegacy) { - if (isFlushingWork) { - // Prevent reentrancy. - // TODO: Is this overly defensive? The callers must check the execution - // context first regardless. - return; - } +// $FlowFixMe[method-unbinding] +var hasOwnProperty = Object.prototype.hasOwnProperty; - if (!mightHavePendingSyncWork) { - // Fast path. There's no sync work to do. - return; - } // There may or may not be synchronous work scheduled. Let's check. +/** + * 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. + */ - var didPerformSomeWork; - isFlushingWork = true; +function shallowEqual(objA, objB) { + if (objectIs(objA, objB)) { + return true; + } - do { - didPerformSomeWork = false; - var root = firstScheduledRoot; - - while (root !== null) { - if (onlyLegacy && root.tag !== LegacyRoot); - else { - var workInProgressRoot = getWorkInProgressRoot(); - var workInProgressRootRenderLanes = - getWorkInProgressRootRenderLanes(); - var nextLanes = getNextLanes( - root, - root === workInProgressRoot - ? workInProgressRootRenderLanes - : NoLanes - ); + if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) { + return false; + } - if (includesSyncLane(nextLanes)) { - // This root has pending sync work. Flush it now. - didPerformSomeWork = true; - performSyncWorkOnRoot(root, nextLanes); - } - } + var keysA = Object.keys(objA); + var keysB = Object.keys(objB); - root = root.next; - } - } while (didPerformSomeWork); + if (keysA.length !== keysB.length) { + return false; + } // Test for A's keys different from B. + + + for (var i = 0; i < keysA.length; i++) { + var currentKey = keysA[i]; - isFlushingWork = false; + if (!hasOwnProperty.call(objB, currentKey) || // $FlowFixMe[incompatible-use] lost refinement of `objB` + !objectIs(objA[currentKey], objB[currentKey])) { + return false; } + } - function processRootScheduleInMicrotask() { - // This function is always called inside a microtask. It should never be - // called synchronously. - didScheduleMicrotask = false; + return true; +} - { - didScheduleMicrotask_act = false; - } // We'll recompute this as we iterate through all the roots and schedule them. - - mightHavePendingSyncWork = false; - var currentTime = now$1(); - var prev = null; - var root = firstScheduledRoot; - - while (root !== null) { - var next = root.next; - - if ( - currentEventTransitionLane !== NoLane && - shouldAttemptEagerTransition() - ) { - // A transition was scheduled during an event, but we're going to try to - // render it synchronously anyway. We do this during a popstate event to - // preserve the scroll position of the previous page. - upgradePendingLaneToSync(root, currentEventTransitionLane); - } - - var nextLanes = scheduleTaskForRootDuringMicrotask(root, currentTime); - - if (nextLanes === NoLane) { - // This root has no more pending work. Remove it from the schedule. To - // guard against subtle reentrancy bugs, this microtask is the only place - // we do this — you can add roots to the schedule whenever, but you can - // only remove them here. - // Null this out so we know it's been removed from the schedule. - root.next = null; - - if (prev === null) { - // This is the new head of the list - firstScheduledRoot = next; - } else { - prev.next = next; - } +var current = null; +var isRendering = false; +function getCurrentFiberOwnerNameInDevOrNull() { + { + if (current === null) { + return null; + } - if (next === null) { - // This is the new tail of the list - lastScheduledRoot = prev; - } - } else { - // This root still has work. Keep it in the list. - prev = root; + var owner = current._debugOwner; - if (includesSyncLane(nextLanes)) { - mightHavePendingSyncWork = true; - } - } + if (owner != null) { + return getComponentNameFromOwner(owner); + } + } - root = next; - } + return null; +} - currentEventTransitionLane = NoLane; // At the end of the microtask, flush any pending synchronous work. This has - // to come at the end, because it does actual rendering work that might throw. +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. - flushSyncWorkOnAllRoots(); - } - function scheduleTaskForRootDuringMicrotask(root, currentTime) { - // This function is always called inside a microtask, or at the very end of a - // rendering task right before we yield to the main thread. It should never be - // called synchronously. - // - // TODO: Unless enableDeferRootSchedulingToMicrotask is off. We need to land - // that ASAP to unblock additional features we have planned. - // - // This function also never performs React work synchronously; it should - // only schedule work to be performed later, in a separate task or microtask. - // Check if any lanes are being starved by other work. If so, mark them as - // expired so we know to work on those next. - markStarvedLanesAsExpired(root, currentTime); // Determine the next lanes to work on, and their priority. - - var workInProgressRoot = getWorkInProgressRoot(); - var workInProgressRootRenderLanes = getWorkInProgressRootRenderLanes(); - var nextLanes = getNextLanes( - root, - root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes - ); - var existingCallbackNode = root.callbackNode; - - if ( - // Check if there's nothing to work on - nextLanes === NoLanes || // 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. - // - // Suspended render phase - (root === workInProgressRoot && isWorkLoopSuspendedOnData()) || // Suspended commit phase - root.cancelPendingCommit !== null - ) { - // Fast path: There's nothing to work on. - if (existingCallbackNode !== null) { - cancelCallback(existingCallbackNode); - } + return getStackByFiberInDevAndProd(current); + } +} - root.callbackNode = null; - root.callbackPriority = NoLane; - return NoLane; - } // Schedule a new callback in the host environment. +function resetCurrentFiber() { + { + ReactSharedInternals.getCurrentStack = null; + current = null; + isRendering = false; + } +} +function setCurrentFiber(fiber) { + { + ReactSharedInternals.getCurrentStack = fiber === null ? null : getCurrentFiberStackInDev; + current = fiber; + isRendering = false; + } +} +function getCurrentFiber() { + { + return current; + } +} +function setIsRendering(rendering) { + { + isRendering = rendering; + } +} - if (includesSyncLane(nextLanes)) { - // Synchronous work is always flushed at the end of the microtask, so we - // don't need to schedule an additional task. - if (existingCallbackNode !== null) { - cancelCallback(existingCallbackNode); - } +var ReactStrictModeWarnings = { + recordUnsafeLifecycleWarnings: function (fiber, instance) {}, + flushPendingUnsafeLifecycleWarnings: function () {}, + recordLegacyContextWarning: function (fiber, instance) {}, + flushLegacyContextWarning: function () {}, + discardPendingWarnings: function () {} +}; - root.callbackPriority = SyncLane; - root.callbackNode = null; - return SyncLane; - } else { - // We use the highest priority lane to represent the priority of the callback. - var existingCallbackPriority = root.callbackPriority; - var newCallbackPriority = getHighestPriorityLane(nextLanes); - - if ( - newCallbackPriority === existingCallbackPriority && // Special case related to `act`. If the currently scheduled task is a - // Scheduler task, rather than an `act` task, cancel it and re-schedule - // on the `act` queue. - !( - ReactSharedInternals.actQueue !== null && - existingCallbackNode !== fakeActCallbackNode$1 - ) - ) { - // The priority hasn't changed. We can reuse the existing task. - return newCallbackPriority; - } else { - // Cancel the existing callback. We'll schedule a new one below. - cancelCallback(existingCallbackNode); - } +{ + var findStrictRoot = function (fiber) { + var maybeStrictRoot = null; + var node = fiber; - var schedulerPriorityLevel; + while (node !== null) { + if (node.mode & StrictLegacyMode) { + maybeStrictRoot = node; + } - switch (lanesToEventPriority(nextLanes)) { - case DiscreteEventPriority: - schedulerPriorityLevel = ImmediatePriority; - break; + node = node.return; + } - case ContinuousEventPriority: - schedulerPriorityLevel = UserBlockingPriority; - break; + return maybeStrictRoot; + }; - case DefaultEventPriority: - schedulerPriorityLevel = NormalPriority$1; - break; + var setToSortedString = function (set) { + var array = []; + set.forEach(function (value) { + array.push(value); + }); + return array.sort().join(', '); + }; - case IdleEventPriority: - schedulerPriorityLevel = IdlePriority; - break; + var pendingComponentWillMountWarnings = []; + var pendingUNSAFE_ComponentWillMountWarnings = []; + var pendingComponentWillReceivePropsWarnings = []; + var pendingUNSAFE_ComponentWillReceivePropsWarnings = []; + var pendingComponentWillUpdateWarnings = []; + var pendingUNSAFE_ComponentWillUpdateWarnings = []; // Tracks components we have already warned about. - default: - schedulerPriorityLevel = NormalPriority$1; - break; - } + var didWarnAboutUnsafeLifecycles = new Set(); - var newCallbackNode = scheduleCallback$2( - schedulerPriorityLevel, - performConcurrentWorkOnRoot.bind(null, root) - ); - root.callbackPriority = newCallbackPriority; - root.callbackNode = newCallbackNode; - return newCallbackPriority; - } + ReactStrictModeWarnings.recordUnsafeLifecycleWarnings = function (fiber, instance) { + // Dedupe strategy: Warn once per component. + if (didWarnAboutUnsafeLifecycles.has(fiber.type)) { + return; } - function getContinuationForRoot(root, originalCallbackNode) { - // This is called at the end of `performConcurrentWorkOnRoot` to determine - // if we need to schedule a continuation task. - // - // Usually `scheduleTaskForRootDuringMicrotask` only runs inside a microtask; - // however, since most of the logic for determining if we need a continuation - // versus a new task is the same, we cheat a bit and call it here. This is - // only safe to do because we know we're at the end of the browser task. - // So although it's not an actual microtask, it might as well be. - scheduleTaskForRootDuringMicrotask(root, now$1()); - - 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); - } + if (typeof instance.componentWillMount === 'function' && // Don't warn about react-lifecycles-compat polyfilled components. + instance.componentWillMount.__suppressDeprecationWarning !== true) { + pendingComponentWillMountWarnings.push(fiber); + } - return null; + if (fiber.mode & StrictLegacyMode && typeof instance.UNSAFE_componentWillMount === 'function') { + pendingUNSAFE_ComponentWillMountWarnings.push(fiber); } - var fakeActCallbackNode$1 = {}; - function scheduleCallback$2(priorityLevel, callback) { - if (ReactSharedInternals.actQueue !== null) { - // Special case: We're inside an `act` scope (a testing utility). - // Instead of scheduling work in the host environment, add it to a - // fake internal queue that's managed by the `act` implementation. - ReactSharedInternals.actQueue.push(callback); - return fakeActCallbackNode$1; - } else { - return scheduleCallback$3(priorityLevel, callback); - } + if (typeof instance.componentWillReceiveProps === 'function' && instance.componentWillReceiveProps.__suppressDeprecationWarning !== true) { + pendingComponentWillReceivePropsWarnings.push(fiber); } - function cancelCallback(callbackNode) { - if (callbackNode === fakeActCallbackNode$1); - else if (callbackNode !== null) { - cancelCallback$1(callbackNode); - } + if (fiber.mode & StrictLegacyMode && typeof instance.UNSAFE_componentWillReceiveProps === 'function') { + pendingUNSAFE_ComponentWillReceivePropsWarnings.push(fiber); } - function scheduleImmediateTask(cb) { - if (ReactSharedInternals.actQueue !== null) { - // Special case: Inside an `act` scope, we push microtasks to the fake `act` - // callback queue. This is because we currently support calling `act` - // without awaiting the result. The plan is to deprecate that, and require - // that you always await the result so that the microtasks have a chance to - // run. But it hasn't happened yet. - ReactSharedInternals.actQueue.push(function () { - cb(); - return null; - }); - } // TODO: Can we land supportsMicrotasks? Which environments don't support it? - // Alternatively, can we move this check to the host config? + if (typeof instance.componentWillUpdate === 'function' && instance.componentWillUpdate.__suppressDeprecationWarning !== true) { + pendingComponentWillUpdateWarnings.push(fiber); + } - { - // If microtasks are not supported, use Scheduler. - scheduleCallback$3(ImmediatePriority, cb); - } + if (fiber.mode & StrictLegacyMode && typeof instance.UNSAFE_componentWillUpdate === 'function') { + pendingUNSAFE_ComponentWillUpdateWarnings.push(fiber); } + }; - function requestTransitionLane( // This argument isn't used, it's only here to encourage the caller to - // check that it's inside a transition before calling this function. - // TODO: Make this non-nullable. Requires a tweak to useOptimistic. - transition - ) { - // 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(); - } + ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = function () { + // We do an initial pass to gather component names + var componentWillMountUniqueNames = new Set(); - return currentEventTransitionLane; + if (pendingComponentWillMountWarnings.length > 0) { + pendingComponentWillMountWarnings.forEach(function (fiber) { + componentWillMountUniqueNames.add(getComponentNameFromFiber(fiber) || 'Component'); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingComponentWillMountWarnings = []; } - // transition updates that occur while the async action is still in progress - // are treated as part of the action. - // - // The ideal behavior would be to treat each async function as an independent - // action. However, without a mechanism like AsyncContext, we can't tell which - // action an update corresponds to. So instead, we entangle them all into one. - // The listeners to notify once the entangled scope completes. - - var currentEntangledListeners = null; // The number of pending async actions in the entangled scope. - - var currentEntangledPendingCount = 0; // The transition lane shared by all updates in the entangled scope. - - var currentEntangledLane = NoLane; // A thenable that resolves when the entangled scope completes. It does not - // resolve to a particular value because it's only used for suspending the UI - // until the async action scope has completed. - - var currentEntangledActionThenable = null; - function entangleAsyncAction(transition, thenable) { - // `thenable` is the return value of the async action scope function. Create - // a combined thenable that resolves once every entangled scope function - // has finished. - if (currentEntangledListeners === null) { - // There's no outer async action scope. Create a new one. - var entangledListeners = (currentEntangledListeners = []); - currentEntangledPendingCount = 0; - currentEntangledLane = requestTransitionLane(); - var entangledThenable = { - status: "pending", - value: undefined, - then: function (resolve) { - entangledListeners.push(resolve); - } - }; - currentEntangledActionThenable = entangledThenable; - } + var UNSAFE_componentWillMountUniqueNames = new Set(); - currentEntangledPendingCount++; - thenable.then(pingEngtangledActionScope, pingEngtangledActionScope); - return thenable; + if (pendingUNSAFE_ComponentWillMountWarnings.length > 0) { + pendingUNSAFE_ComponentWillMountWarnings.forEach(function (fiber) { + UNSAFE_componentWillMountUniqueNames.add(getComponentNameFromFiber(fiber) || 'Component'); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingUNSAFE_ComponentWillMountWarnings = []; } - function pingEngtangledActionScope() { - if ( - currentEntangledListeners !== null && - --currentEntangledPendingCount === 0 - ) { - // All the actions have finished. Close the entangled async action scope - // and notify all the listeners. - if (currentEntangledActionThenable !== null) { - var fulfilledThenable = currentEntangledActionThenable; - fulfilledThenable.status = "fulfilled"; - } + var componentWillReceivePropsUniqueNames = new Set(); + + if (pendingComponentWillReceivePropsWarnings.length > 0) { + pendingComponentWillReceivePropsWarnings.forEach(function (fiber) { + componentWillReceivePropsUniqueNames.add(getComponentNameFromFiber(fiber) || 'Component'); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingComponentWillReceivePropsWarnings = []; + } - var listeners = currentEntangledListeners; - currentEntangledListeners = null; - currentEntangledLane = NoLane; - currentEntangledActionThenable = null; + var UNSAFE_componentWillReceivePropsUniqueNames = new Set(); - for (var i = 0; i < listeners.length; i++) { - var listener = listeners[i]; - listener(); - } - } + if (pendingUNSAFE_ComponentWillReceivePropsWarnings.length > 0) { + pendingUNSAFE_ComponentWillReceivePropsWarnings.forEach(function (fiber) { + UNSAFE_componentWillReceivePropsUniqueNames.add(getComponentNameFromFiber(fiber) || 'Component'); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingUNSAFE_ComponentWillReceivePropsWarnings = []; } - function chainThenableValue(thenable, result) { - // Equivalent to: Promise.resolve(thenable).then(() => result), except we can - // cheat a bit since we know that that this thenable is only ever consumed - // by React. - // - // We don't technically require promise support on the client yet, hence this - // extra code. - var listeners = []; - var thenableWithOverride = { - status: "pending", - value: null, - reason: null, - then: function (resolve) { - listeners.push(resolve); - } - }; - thenable.then( - function (value) { - var fulfilledThenable = thenableWithOverride; - fulfilledThenable.status = "fulfilled"; - fulfilledThenable.value = result; - - for (var i = 0; i < listeners.length; i++) { - var listener = listeners[i]; - listener(result); - } - }, - function (error) { - var rejectedThenable = thenableWithOverride; - rejectedThenable.status = "rejected"; - rejectedThenable.reason = error; - - for (var i = 0; i < listeners.length; i++) { - var listener = listeners[i]; // This is a perf hack where we call the `onFulfill` ping function - // instead of `onReject`, because we know that React is the only - // consumer of these promises, and it passes the same listener to both. - // We also know that it will read the error directly off the - // `.reason` field. - - listener(undefined); - } - } - ); - return thenableWithOverride; + var componentWillUpdateUniqueNames = new Set(); + + if (pendingComponentWillUpdateWarnings.length > 0) { + pendingComponentWillUpdateWarnings.forEach(function (fiber) { + componentWillUpdateUniqueNames.add(getComponentNameFromFiber(fiber) || 'Component'); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingComponentWillUpdateWarnings = []; } - function peekEntangledActionLane() { - return currentEntangledLane; + + var UNSAFE_componentWillUpdateUniqueNames = new Set(); + + 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 (UNSAFE_componentWillMountUniqueNames.size > 0) { + var sortedNames = setToSortedString(UNSAFE_componentWillMountUniqueNames); + + error('Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code. ' + 'See https://react.dev/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 peekEntangledActionThenable() { - return currentEntangledActionThenable; + + if (UNSAFE_componentWillReceivePropsUniqueNames.size > 0) { + var _sortedNames = setToSortedString(UNSAFE_componentWillReceivePropsUniqueNames); + + error('Using UNSAFE_componentWillReceiveProps in strict mode is not recommended ' + 'and may indicate bugs in your code. ' + 'See https://react.dev/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://react.dev/link/derived-state\n' + '\nPlease update the following components: %s', _sortedNames); } - 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 (UNSAFE_componentWillUpdateUniqueNames.size > 0) { + var _sortedNames2 = setToSortedString(UNSAFE_componentWillUpdateUniqueNames); - var hasForceUpdate = false; - var didWarnUpdateInsideUpdate; - var currentlyProcessingQueue; + error('Using UNSAFE_componentWillUpdate in strict mode is not recommended ' + 'and may indicate bugs in your code. ' + 'See https://react.dev/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); + } - { - didWarnUpdateInsideUpdate = false; - currentlyProcessingQueue = null; - } - - function initializeUpdateQueue(fiber) { - var queue = { - baseState: fiber.memoizedState, - firstBaseUpdate: null, - lastBaseUpdate: null, - shared: { - pending: null, - lanes: NoLanes, - hiddenCallbacks: null - }, - callbacks: null - }; - fiber.updateQueue = queue; + if (componentWillMountUniqueNames.size > 0) { + var _sortedNames3 = setToSortedString(componentWillMountUniqueNames); + + warn('componentWillMount has been renamed, and is not recommended for use. ' + 'See https://react.dev/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); } - 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 (queue === currentQueue) { - var clone = { - baseState: currentQueue.baseState, - firstBaseUpdate: currentQueue.firstBaseUpdate, - lastBaseUpdate: currentQueue.lastBaseUpdate, - shared: currentQueue.shared, - callbacks: null - }; - workInProgress.updateQueue = clone; - } + if (componentWillReceivePropsUniqueNames.size > 0) { + var _sortedNames4 = setToSortedString(componentWillReceivePropsUniqueNames); + + warn('componentWillReceiveProps has been renamed, and is not recommended for use. ' + 'See https://react.dev/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://react.dev/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); } - function createUpdate(lane) { - var update = { - lane: lane, - tag: UpdateState, - payload: null, - callback: null, - next: null - }; - return update; + + if (componentWillUpdateUniqueNames.size > 0) { + var _sortedNames5 = setToSortedString(componentWillUpdateUniqueNames); + + warn('componentWillUpdate has been renamed, and is not recommended for use. ' + 'See https://react.dev/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); } - function enqueueUpdate(fiber, update, lane) { - var updateQueue = fiber.updateQueue; + }; - if (updateQueue === null) { - // Only occurs if the fiber has been unmounted. - return null; - } + var pendingLegacyContextWarning = new Map(); // Tracks components we have already warned about. - var sharedQueue = updateQueue.shared; + var didWarnAboutLegacyContext = new Set(); - { - if ( - currentlyProcessingQueue === sharedQueue && - !didWarnUpdateInsideUpdate - ) { - var componentName = getComponentNameFromFiber(fiber); + ReactStrictModeWarnings.recordLegacyContextWarning = function (fiber, instance) { + var strictRoot = findStrictRoot(fiber); - 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 (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.'); - didWarnUpdateInsideUpdate = true; - } - } + return; + } // Dedup strategy: Warn once per component. - 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; - if (pending === null) { - // This is the first update. Create a circular list. - update.next = update; - } else { - update.next = pending.next; - pending.next = update; - } + if (didWarnAboutLegacyContext.has(fiber.type)) { + return; + } - 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 warningsForRoot = pendingLegacyContextWarning.get(strictRoot); - return unsafe_markUpdateLaneFromFiberToRoot(fiber, lane); - } else { - return enqueueConcurrentClassUpdate(fiber, sharedQueue, update, lane); + if (fiber.type.contextTypes != null || fiber.type.childContextTypes != null || instance !== null && typeof instance.getChildContext === 'function') { + if (warningsForRoot === undefined) { + warningsForRoot = []; + pendingLegacyContextWarning.set(strictRoot, warningsForRoot); } + + warningsForRoot.push(fiber); } - function entangleTransitions(root, fiber, lane) { - var updateQueue = fiber.updateQueue; + }; - if (updateQueue === null) { - // Only occurs if the fiber has been unmounted. + ReactStrictModeWarnings.flushLegacyContextWarning = function () { + pendingLegacyContextWarning.forEach(function (fiberArray, strictRoot) { + if (fiberArray.length === 0) { return; } - var sharedQueue = updateQueue.shared; + 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 (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 { + setCurrentFiber(firstFiber); - queueLanes = intersectLanes(queueLanes, root.pendingLanes); // Entangle the new transition lane with the other transition lanes. + 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://react.dev/link/legacy-context', sortedNames); + } finally { + resetCurrentFiber(); + } + }); + }; + + ReactStrictModeWarnings.discardPendingWarnings = function () { + pendingComponentWillMountWarnings = []; + pendingUNSAFE_ComponentWillMountWarnings = []; + pendingComponentWillReceivePropsWarnings = []; + pendingUNSAFE_ComponentWillReceivePropsWarnings = []; + pendingComponentWillUpdateWarnings = []; + pendingUNSAFE_ComponentWillUpdateWarnings = []; + pendingLegacyContextWarning = new Map(); + }; +} - 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. +function getThenablesFromState(state) { + { + var devState = state; + return devState.thenables; + } +} // 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. - 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 current = workInProgress.alternate; +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. - if (current !== null) { - var currentQueue = current.updateQueue; - - 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; - - if (firstBaseUpdate !== null) { - // Loop through the updates and clone them. - var update = firstBaseUpdate; +var noopSuspenseyCommitThenable = { + then: function () { + { + error('Internal React error: A listener was unexpectedly attached to a ' + '"noop" thenable. This is a bug in React. Please file an issue.'); + } + } +}; +function createThenableState() { + // The ThenableState is created the first time a component suspends. If it + // suspends again, we'll reuse the same state. + { + return { + didWarnAboutUncachedPromise: false, + thenables: [] + }; + } +} +function isThenableResolved(thenable) { + var status = thenable.status; + return status === 'fulfilled' || status === 'rejected'; +} - 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 - }; +function noop() {} - if (newLast === null) { - newFirst = newLast = clone; - } else { - newLast.next = clone; - newLast = clone; - } // $FlowFixMe[incompatible-type] we bail out when we get a null +function trackUsedThenable(thenableState, thenable, index) { + if (ReactSharedInternals.actQueue !== null) { + ReactSharedInternals.didUsePromise = true; + } - update = update.next; - } while (update !== null); // Append the captured update the end of the cloned list. + var trackedThenables = getThenablesFromState(thenableState); + var previous = trackedThenables[index]; - if (newLast === null) { - newFirst = newLast = capturedUpdate; - } else { - newLast.next = capturedUpdate; - newLast = capturedUpdate; - } - } else { - // There are no base updates. - newFirst = newLast = capturedUpdate; - } + if (previous === undefined) { + trackedThenables.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. + { + var thenableStateDev = thenableState; - queue = { - baseState: currentQueue.baseState, - firstBaseUpdate: newFirst, - lastBaseUpdate: newLast, - shared: currentQueue.shared, - callbacks: currentQueue.callbacks - }; - workInProgress.updateQueue = queue; - return; + if (!thenableStateDev.didWarnAboutUncachedPromise) { + // We should only warn the first time an uncached thenable is + // discovered per component, because if there are multiple, the + // subsequent ones are likely derived from the first. + // + // We track this on the thenableState instead of deduping using the + // component name like we usually do, because in the case of a + // promise-as-React-node, the owner component is likely different from + // the parent that's currently being reconciled. We'd have to track + // the owner using state, which we're trying to move away from. Though + // since this is dev-only, maybe that'd be OK. + // + // However, another benefit of doing it this way is we might + // eventually have a thenableState per memo/Forget boundary instead + // of per component, so this would allow us to have more + // granular warnings. + thenableStateDev.didWarnAboutUncachedPromise = true; // TODO: This warning should link to a corresponding docs page. + + error('A component was suspended by an uncached promise. Creating ' + 'promises inside a Client Component or hook is not yet ' + 'supported, except via a Suspense-compatible library or framework.'); } - } // Append the update to the end of the list. + } // Avoid an unhandled rejection errors for the Promises that we'll + // intentionally ignore. - var lastBaseUpdate = queue.lastBaseUpdate; - if (lastBaseUpdate === null) { - queue.firstBaseUpdate = capturedUpdate; - } else { - lastBaseUpdate.next = capturedUpdate; + thenable.then(noop, noop); + thenable = previous; + } + } // 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; } - queue.lastBaseUpdate = capturedUpdate; - } + case 'rejected': + { + var rejectedError = thenable.reason; + checkIfUseWrappedInAsyncCatch(rejectedError); + throw rejectedError; + } - function getStateFromUpdate( - workInProgress, - queue, - update, - prevState, - nextProps, - instance - ) { - switch (update.tag) { - case ReplaceState: { - var payload = update.payload; + 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 { + // This is an uncached thenable that we haven't seen before. + // Detect infinite ping loops caused by uncached promises. + var root = getWorkInProgressRoot(); - if (typeof payload === "function") { - // Updater function - { - enterDisallowedContextReadInDEV(); + if (root !== null && root.shellSuspendCounter > 100) { + // This root has suspended repeatedly in the shell without making any + // progress (i.e. committing something). This is highly suggestive of + // an infinite ping loop, often caused by an accidental Async Client + // Component. + // + // During a transition, we can suspend the work loop until the promise + // to resolve, but this is a sync render, so that's not an option. We + // also can't show a fallback, because none was provided. So our last + // resort is to throw an error. + // + // TODO: Remove this error in a future release. Other ways of handling + // this case include forcing a concurrent render, or putting the whole + // root into offscreen mode. + throw new Error('async/await is not yet supported in Client Components, only ' + 'Server Components. This error is often caused by accidentally ' + "adding `'use client'` to a module that was originally written " + 'for the server.'); + } + + 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. - var nextState = payload.call(instance, prevState, nextProps); + switch (thenable.status) { + case 'fulfilled': { - if (workInProgress.mode & StrictLegacyMode) { - setIsStrictModeForDevtools(true); - - try { - payload.call(instance, prevState, nextProps); - } finally { - setIsStrictModeForDevtools(false); - } - } + var fulfilledThenable = thenable; + return fulfilledThenable.value; + } - exitDisallowedContextReadInDEV(); + case 'rejected': + { + var rejectedThenable = thenable; + var _rejectedError = rejectedThenable.reason; + checkIfUseWrappedInAsyncCatch(_rejectedError); + throw _rejectedError; } + } // 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. - return nextState; - } // State object - return payload; - } + suspendedThenable = thenable; - case CaptureUpdate: { - workInProgress.flags = - (workInProgress.flags & ~ShouldCapture) | DidCapture; + { + needsToResetSuspendedThenableDEV = true; } - // Intentional fallthrough - case UpdateState: { - var _payload = update.payload; - var partialState; - - if (typeof _payload === "function") { - // Updater function - { - enterDisallowedContextReadInDEV(); - } + throw SuspenseException; + } + } +} +// 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.'); + } + + 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; + } + } - partialState = _payload.call(instance, prevState, nextProps); + return false; +} +function checkIfUseWrappedInAsyncCatch(rejectedReason) { + // This check runs in prod, too, because it prevents a more confusing + // downstream error, where SuspenseException is caught by a promise and + // thrown asynchronously. + // TODO: Another way to prevent SuspenseException from leaking into an async + // execution context is to check the dispatcher every time `use` is called, + // or some equivalent. That might be preferable for other reasons, too, since + // it matches how we prevent similar mistakes for other hooks. + if (rejectedReason === SuspenseException) { + throw new Error('Hooks are not supported inside an async component. This ' + "error is often caused by accidentally adding `'use client'` " + 'to a module that was originally written for the server.'); + } +} - { - if (workInProgress.mode & StrictLegacyMode) { - setIsStrictModeForDevtools(true); +var thenableState$1 = null; +var thenableIndexCounter$1 = 0; + +function mergeDebugInfo(outer, inner) { + + if (inner == null) { + return outer; + } else if (outer === null) { + return inner; + } else { + // If we have two debugInfo, we need to create a new one. This makes the array no longer + // live so we'll miss any future updates if we received more so ideally we should always + // do this after both have fully resolved/unsuspended. + return outer.concat(inner); + } +} - try { - _payload.call(instance, prevState, nextProps); - } finally { - setIsStrictModeForDevtools(false); - } - } +var didWarnAboutMaps; +var didWarnAboutGenerators; +var ownerHasKeyUseWarning; +var ownerHasFunctionTypeWarning; +var ownerHasSymbolTypeWarning; - exitDisallowedContextReadInDEV(); - } - } else { - // Partial state object - partialState = _payload; - } +var warnForMissingKey = function (child, returnFiber) {}; - if (partialState === null || partialState === undefined) { - // Null and undefined are treated as no-ops. - return prevState; - } // Merge the partial state and the previous state. +{ + didWarnAboutMaps = false; + didWarnAboutGenerators = false; + /** + * 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. + */ - return assign({}, prevState, partialState); - } + ownerHasKeyUseWarning = {}; + ownerHasFunctionTypeWarning = {}; + ownerHasSymbolTypeWarning = {}; - case ForceUpdate: { - hasForceUpdate = true; - return prevState; - } - } + warnForMissingKey = function (child, returnFiber) { + if (child === null || typeof child !== 'object') { + return; + } - return prevState; + if (!child._store || child._store.validated || child.key != null) { + return; } - var didReadFromEntangledAsyncAction = false; // Each call to processUpdateQueue should be accompanied by a call to this. It's - // only in a separate function because in updateHostRoot, it must happen after - // all the context stacks have been pushed to, to prevent a stack mismatch. A - // bit unfortunate. + 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[cannot-write] unable to narrow type from mixed to writable object - function suspendIfUpdateReadFromEntangledAsyncAction() { - // Check if this update is part of a pending async action. If so, we'll - // need to suspend until the action has finished, so that it's batched - // together with future updates in the same action. - // TODO: Once we support hooks inside useMemo (or an equivalent - // memoization boundary like Forget), hoist this logic so that it only - // suspends if the memo boundary produces a new value. - if (didReadFromEntangledAsyncAction) { - var entangledActionThenable = peekEntangledActionThenable(); - if (entangledActionThenable !== null) { - // TODO: Instead of the throwing the thenable directly, throw a - // special object like `use` does so we can detect if it's captured - // by userspace. - throw entangledActionThenable; - } - } - } - function processUpdateQueue(workInProgress, props, instance, renderLanes) { - didReadFromEntangledAsyncAction = false; // This is always non-null on a ClassComponent or HostRoot + child._store.validated = true; + var componentName = getComponentNameFromFiber(returnFiber) || 'Component'; - var queue = workInProgress.updateQueue; - hasForceUpdate = false; + if (ownerHasKeyUseWarning[componentName]) { + return; + } - { - currentlyProcessingQueue = queue.shared; - } + ownerHasKeyUseWarning[componentName] = true; - var firstBaseUpdate = queue.firstBaseUpdate; - var lastBaseUpdate = queue.lastBaseUpdate; // Check if there are pending updates. If so, transfer them to the base queue. + error('Each child in a list should have a unique ' + '"key" prop. See https://react.dev/link/warning-keys for ' + 'more information.'); + }; +} - var pendingQueue = queue.shared.pending; +function unwrapThenable(thenable) { + var index = thenableIndexCounter$1; + thenableIndexCounter$1 += 1; - 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. + if (thenableState$1 === null) { + thenableState$1 = createThenableState(); + } - var lastPendingUpdate = pendingQueue; - var firstPendingUpdate = lastPendingUpdate.next; - lastPendingUpdate.next = null; // Append pending updates to base queue + return trackUsedThenable(thenableState$1, thenable, index); +} - if (lastBaseUpdate === null) { - firstBaseUpdate = firstPendingUpdate; - } else { - lastBaseUpdate.next = firstPendingUpdate; - } +function coerceRef(returnFiber, current, workInProgress, element) { + var ref; - 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 + { + // Old behavior. + ref = element.ref; + } // TODO: If enableRefAsProp is on, we shouldn't use the `ref` field. We + // should always read the ref from the prop. - var current = workInProgress.alternate; - if (current !== null) { - // This is always non-null on a ClassComponent or HostRoot - var currentQueue = current.updateQueue; - var currentLastBaseUpdate = currentQueue.lastBaseUpdate; + workInProgress.ref = ref; +} - if (currentLastBaseUpdate !== lastBaseUpdate) { - if (currentLastBaseUpdate === null) { - currentQueue.firstBaseUpdate = firstPendingUpdate; - } else { - currentLastBaseUpdate.next = firstPendingUpdate; - } +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.'); +} - currentQueue.lastBaseUpdate = lastPendingUpdate; - } - } - } // These values may change as we process the queue. +function warnOnFunctionType(returnFiber, invalidChild) { + { + var parentName = getComponentNameFromFiber(returnFiber) || 'Component'; - 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 newLanes = NoLanes; - var newBaseState = null; - var newFirstBaseUpdate = null; - var newLastBaseUpdate = null; - var update = firstBaseUpdate; + if (ownerHasFunctionTypeWarning[parentName]) { + return; + } - 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); - - 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 - }; + ownerHasFunctionTypeWarning[parentName] = true; + var name = invalidChild.displayName || invalidChild.name || 'Component'; - if (newLastBaseUpdate === null) { - newFirstBaseUpdate = newLastBaseUpdate = clone; - newBaseState = newState; - } else { - newLastBaseUpdate = newLastBaseUpdate.next = clone; - } // Update the remaining priority in the queue. + if (returnFiber.tag === HostRoot) { + error('Functions are not valid as a React child. This may happen if ' + 'you return %s instead of <%s /> from render. ' + 'Or maybe you meant to call this function rather than return it.\n' + ' root.render(%s)', name, name, name); + } else { + error('Functions are not valid as a React child. This may happen if ' + 'you return %s instead of <%s /> from render. ' + 'Or maybe you meant to call this function rather than return it.\n' + ' <%s>{%s}', name, name, parentName, name, parentName); + } + } +} - newLanes = mergeLanes(newLanes, updateLane); - } else { - // This update does have sufficient priority. - // Check if this update is part of a pending async action. If so, - // we'll need to suspend until the action has finished, so that it's - // batched together with future updates in the same action. - if ( - updateLane !== NoLane && - updateLane === peekEntangledActionLane() - ) { - didReadFromEntangledAsyncAction = true; - } +function warnOnSymbolType(returnFiber, invalidChild) { + { + var parentName = getComponentNameFromFiber(returnFiber) || 'Component'; - 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. - - newState = getStateFromUpdate( - workInProgress, - queue, - update, - newState, - props, - instance - ); - var callback = update.callback; + if (ownerHasSymbolTypeWarning[parentName]) { + return; + } - if (callback !== null) { - workInProgress.flags |= Callback; + ownerHasSymbolTypeWarning[parentName] = true; // eslint-disable-next-line react-internal/safe-string-coercion - if (isHiddenUpdate) { - workInProgress.flags |= Visibility; - } + var name = String(invalidChild); - var callbacks = queue.callbacks; + if (returnFiber.tag === HostRoot) { + error('Symbols are not valid as a React child.\n' + ' root.render(%s)', name); + } else { + error('Symbols are not valid as a React child.\n' + ' <%s>%s', parentName, name, parentName); + } + } +} - if (callbacks === null) { - queue.callbacks = [callback]; - } else { - callbacks.push(callback); - } - } - } // $FlowFixMe[incompatible-type] we bail out when we get a null +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. - update = update.next; - if (update === null) { - pendingQueue = queue.shared.pending; +function createChildReconciler(shouldTrackSideEffects) { + function deleteChild(returnFiber, childToDelete) { + if (!shouldTrackSideEffects) { + // Noop. + return; + } - 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. - - var _firstPendingUpdate = _lastPendingUpdate.next; - _lastPendingUpdate.next = null; - update = _firstPendingUpdate; - queue.lastBaseUpdate = _lastPendingUpdate; - queue.shared.pending = null; - } - } - } while (true); + var deletions = returnFiber.deletions; - if (newLastBaseUpdate === null) { - newBaseState = newState; - } + if (deletions === null) { + returnFiber.deletions = [childToDelete]; + returnFiber.flags |= ChildDeletion; + } else { + deletions.push(childToDelete); + } + } - queue.baseState = newBaseState; - queue.firstBaseUpdate = newFirstBaseUpdate; - queue.lastBaseUpdate = newLastBaseUpdate; + 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 (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. - markSkippedUpdateLanes(newLanes); - workInProgress.lanes = newLanes; - workInProgress.memoizedState = newState; - } + var childToDelete = currentFirstChild; - { - currentlyProcessingQueue = null; - } + while (childToDelete !== null) { + deleteChild(returnFiber, childToDelete); + childToDelete = childToDelete.sibling; } - function callCallback(callback, context) { - if (typeof callback !== "function") { - throw new Error( - "Invalid argument passed as callback. Expected a function. Instead " + - ("received: " + callback) - ); + return null; + } + + function mapRemainingChildren(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; + + while (existingChild !== null) { + if (existingChild.key !== null) { + existingChildren.set(existingChild.key, existingChild); + } else { + existingChildren.set(existingChild.index, existingChild); } - callback.call(context); + existingChild = existingChild.sibling; } - 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; + return existingChildren; + } - if (newHiddenCallbacks !== null) { - var existingHiddenCallbacks = updateQueue.shared.hiddenCallbacks; + 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; + } - if (existingHiddenCallbacks === null) { - updateQueue.shared.hiddenCallbacks = newHiddenCallbacks; - } else { - updateQueue.shared.hiddenCallbacks = - existingHiddenCallbacks.concat(newHiddenCallbacks); - } - } + function placeChild(newFiber, lastPlacedIndex, newIndex) { + newFiber.index = newIndex; + + 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; } - 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; + var current = newFiber.alternate; - for (var i = 0; i < hiddenCallbacks.length; i++) { - var callback = hiddenCallbacks[i]; - callCallback(callback, context); - } + if (current !== null) { + var oldIndex = current.index; + + 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; } - function commitCallbacks(updateQueue, context) { - var callbacks = updateQueue.callbacks; + } - if (callbacks !== null) { - updateQueue.callbacks = null; - - for (var i = 0; i < callbacks.length; i++) { - var callback = callbacks[i]; - callCallback(callback, context); - } - } + 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; } - // $FlowFixMe[method-unbinding] - var hasOwnProperty = Object.prototype.hasOwnProperty; + return newFiber; + } - /** - * 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. - */ + function updateTextNode(returnFiber, current, textContent, lanes, debugInfo) { + if (current === null || current.tag !== HostText) { + // Insert + var created = createFiberFromText(textContent, returnFiber.mode, lanes); + created.return = returnFiber; - function shallowEqual(objA, objB) { - if (objectIs(objA, objB)) { - return true; + { + created._debugInfo = debugInfo; } - if ( - typeof objA !== "object" || - objA === null || - typeof objB !== "object" || - objB === null - ) { - return false; + return created; + } else { + // Update + var existing = useFiber(current, textContent); + existing.return = returnFiber; + + { + existing._debugInfo = debugInfo; } - var keysA = Object.keys(objA); - var keysB = Object.keys(objB); + return existing; + } + } + + function updateElement(returnFiber, current, element, lanes, debugInfo) { + var elementType = element.type; - if (keysA.length !== keysB.length) { - return false; - } // Test for A's keys different from B. + if (elementType === REACT_FRAGMENT_TYPE) { + return updateFragment(returnFiber, current, element.props.children, lanes, element.key, debugInfo); + } - for (var i = 0; i < keysA.length; i++) { - var currentKey = keysA[i]; + 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); + coerceRef(returnFiber, current, existing, element); + existing.return = returnFiber; - if ( - !hasOwnProperty.call(objB, currentKey) || // $FlowFixMe[incompatible-use] lost refinement of `objB` - !objectIs(objA[currentKey], objB[currentKey]) - ) { - return false; + { + existing._debugOwner = element._owner; + existing._debugInfo = debugInfo; } + + return existing; } + } // Insert - return true; - } - var current = null; - var isRendering = false; - function getCurrentFiberOwnerNameInDevOrNull() { - { - if (current === null) { - return null; - } + var created = createFiberFromElement(element, returnFiber.mode, lanes); + coerceRef(returnFiber, current, created, element); + created.return = returnFiber; - var owner = current._debugOwner; + { + created._debugInfo = debugInfo; + } - if (owner != null) { - return getComponentNameFromOwner(owner); - } - } + return created; + } - return null; - } + function updatePortal(returnFiber, current, portal, lanes, debugInfo) { + 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; - 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. - - return getStackByFiberInDevAndProd(current); + created._debugInfo = debugInfo; } - } - function resetCurrentFiber() { + return created; + } else { + // Update + var existing = useFiber(current, portal.children || []); + existing.return = returnFiber; + { - ReactSharedInternals.getCurrentStack = null; - current = null; - isRendering = false; + existing._debugInfo = debugInfo; } + + return existing; } - function setCurrentFiber(fiber) { + } + + function updateFragment(returnFiber, current, fragment, lanes, key, debugInfo) { + if (current === null || current.tag !== Fragment) { + // Insert + var created = createFiberFromFragment(fragment, returnFiber.mode, lanes, key); + created.return = returnFiber; + { - ReactSharedInternals.getCurrentStack = - fiber === null ? null : getCurrentFiberStackInDev; - current = fiber; - isRendering = false; + created._debugInfo = debugInfo; } - } - function getCurrentFiber() { + + return created; + } else { + // Update + var existing = useFiber(current, fragment); + existing.return = returnFiber; + { - return current; + existing._debugInfo = debugInfo; } + + return existing; } - function setIsRendering(rendering) { + } + + function createChild(returnFiber, newChild, lanes, debugInfo) { + if (typeof newChild === 'string' && newChild !== '' || typeof newChild === 'number' || typeof newChild === 'bigint') { + // 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( // $FlowFixMe[unsafe-addition] Flow doesn't want us to use `+` operator with string and bigint + '' + newChild, returnFiber.mode, lanes); + created.return = returnFiber; + { - isRendering = rendering; + created._debugInfo = debugInfo; } - } - var ReactStrictModeWarnings = { - recordUnsafeLifecycleWarnings: function (fiber, instance) {}, - flushPendingUnsafeLifecycleWarnings: function () {}, - recordLegacyContextWarning: function (fiber, instance) {}, - flushLegacyContextWarning: function () {}, - discardPendingWarnings: function () {} - }; + return created; + } - { - var findStrictRoot = function (fiber) { - var maybeStrictRoot = null; - var node = fiber; + if (typeof newChild === 'object' && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + { + var _created = createFiberFromElement(newChild, returnFiber.mode, lanes); - while (node !== null) { - if (node.mode & StrictLegacyMode) { - maybeStrictRoot = node; - } + coerceRef(returnFiber, null, _created, newChild); + _created.return = returnFiber; - node = node.return; - } + { + _created._debugInfo = mergeDebugInfo(debugInfo, newChild._debugInfo); + } - return maybeStrictRoot; - }; + return _created; + } - var setToSortedString = function (set) { - var array = []; - set.forEach(function (value) { - array.push(value); - }); - return array.sort().join(", "); - }; + case REACT_PORTAL_TYPE: + { + var _created2 = createFiberFromPortal(newChild, returnFiber.mode, lanes); - var pendingComponentWillMountWarnings = []; - var pendingUNSAFE_ComponentWillMountWarnings = []; - var pendingComponentWillReceivePropsWarnings = []; - var pendingUNSAFE_ComponentWillReceivePropsWarnings = []; - var pendingComponentWillUpdateWarnings = []; - var pendingUNSAFE_ComponentWillUpdateWarnings = []; // Tracks components we have already warned about. - - var didWarnAboutUnsafeLifecycles = new Set(); - - ReactStrictModeWarnings.recordUnsafeLifecycleWarnings = function ( - fiber, - instance - ) { - // Dedupe strategy: Warn once per component. - if (didWarnAboutUnsafeLifecycles.has(fiber.type)) { - return; - } + _created2.return = returnFiber; - if ( - typeof instance.componentWillMount === "function" && // Don't warn about react-lifecycles-compat polyfilled components. - instance.componentWillMount.__suppressDeprecationWarning !== true - ) { - pendingComponentWillMountWarnings.push(fiber); - } + { + _created2._debugInfo = debugInfo; + } - if ( - fiber.mode & StrictLegacyMode && - typeof instance.UNSAFE_componentWillMount === "function" - ) { - pendingUNSAFE_ComponentWillMountWarnings.push(fiber); - } + return _created2; + } - if ( - typeof instance.componentWillReceiveProps === "function" && - instance.componentWillReceiveProps.__suppressDeprecationWarning !== - true - ) { - pendingComponentWillReceivePropsWarnings.push(fiber); - } + case REACT_LAZY_TYPE: + { + var payload = newChild._payload; + var init = newChild._init; + return createChild(returnFiber, init(payload), lanes, mergeDebugInfo(debugInfo, newChild._debugInfo) // call merge after init + ); + } + } - if ( - fiber.mode & StrictLegacyMode && - typeof instance.UNSAFE_componentWillReceiveProps === "function" - ) { - pendingUNSAFE_ComponentWillReceivePropsWarnings.push(fiber); - } + if (isArray(newChild) || getIteratorFn(newChild)) { + var _created3 = createFiberFromFragment(newChild, returnFiber.mode, lanes, null); - if ( - typeof instance.componentWillUpdate === "function" && - instance.componentWillUpdate.__suppressDeprecationWarning !== true - ) { - pendingComponentWillUpdateWarnings.push(fiber); - } + _created3.return = returnFiber; - if ( - fiber.mode & StrictLegacyMode && - typeof instance.UNSAFE_componentWillUpdate === "function" - ) { - pendingUNSAFE_ComponentWillUpdateWarnings.push(fiber); + { + _created3._debugInfo = mergeDebugInfo(debugInfo, newChild._debugInfo); } - }; - ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = - function () { - // We do an initial pass to gather component names - var componentWillMountUniqueNames = new Set(); - - if (pendingComponentWillMountWarnings.length > 0) { - pendingComponentWillMountWarnings.forEach(function (fiber) { - componentWillMountUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingComponentWillMountWarnings = []; - } - - var UNSAFE_componentWillMountUniqueNames = new Set(); + return _created3; + } // Usable node types + // + // Unwrap the inner value and recursively call this function again. - if (pendingUNSAFE_ComponentWillMountWarnings.length > 0) { - pendingUNSAFE_ComponentWillMountWarnings.forEach(function (fiber) { - UNSAFE_componentWillMountUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingUNSAFE_ComponentWillMountWarnings = []; - } - var componentWillReceivePropsUniqueNames = new Set(); + if (typeof newChild.then === 'function') { + var thenable = newChild; + return createChild(returnFiber, unwrapThenable(thenable), lanes, mergeDebugInfo(debugInfo, newChild._debugInfo)); + } - if (pendingComponentWillReceivePropsWarnings.length > 0) { - pendingComponentWillReceivePropsWarnings.forEach(function (fiber) { - componentWillReceivePropsUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingComponentWillReceivePropsWarnings = []; - } + if (newChild.$$typeof === REACT_CONTEXT_TYPE) { + var context = newChild; + return createChild(returnFiber, readContextDuringReconciliation(returnFiber, context, lanes), lanes, debugInfo); + } - var UNSAFE_componentWillReceivePropsUniqueNames = new Set(); + throwOnInvalidObjectType(returnFiber, newChild); + } - if (pendingUNSAFE_ComponentWillReceivePropsWarnings.length > 0) { - pendingUNSAFE_ComponentWillReceivePropsWarnings.forEach( - function (fiber) { - UNSAFE_componentWillReceivePropsUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - } - ); - pendingUNSAFE_ComponentWillReceivePropsWarnings = []; - } + { + if (typeof newChild === 'function') { + warnOnFunctionType(returnFiber, newChild); + } - var componentWillUpdateUniqueNames = new Set(); + if (typeof newChild === 'symbol') { + warnOnSymbolType(returnFiber, newChild); + } + } - if (pendingComponentWillUpdateWarnings.length > 0) { - pendingComponentWillUpdateWarnings.forEach(function (fiber) { - componentWillUpdateUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingComponentWillUpdateWarnings = []; - } + return null; + } - var UNSAFE_componentWillUpdateUniqueNames = new Set(); - - 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 (UNSAFE_componentWillMountUniqueNames.size > 0) { - var sortedNames = setToSortedString( - UNSAFE_componentWillMountUniqueNames - ); + function updateSlot(returnFiber, oldFiber, newChild, lanes, debugInfo) { + // Update the fiber if the keys match, otherwise return null. + var key = oldFiber !== null ? oldFiber.key : null; - error( - "Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code. " + - "See https://react.dev/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 (typeof newChild === 'string' && newChild !== '' || typeof newChild === 'number' || typeof newChild === 'bigint') { + // 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; + } - if (UNSAFE_componentWillReceivePropsUniqueNames.size > 0) { - var _sortedNames = setToSortedString( - UNSAFE_componentWillReceivePropsUniqueNames - ); + return updateTextNode(returnFiber, oldFiber, // $FlowFixMe[unsafe-addition] Flow doesn't want us to use `+` operator with string and bigint + '' + newChild, lanes, debugInfo); + } - error( - "Using UNSAFE_componentWillReceiveProps in strict mode is not recommended " + - "and may indicate bugs in your code. " + - "See https://react.dev/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://react.dev/link/derived-state\n" + - "\nPlease update the following components: %s", - _sortedNames - ); + if (typeof newChild === 'object' && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + { + if (newChild.key === key) { + return updateElement(returnFiber, oldFiber, newChild, lanes, mergeDebugInfo(debugInfo, newChild._debugInfo)); + } else { + return null; + } } - if (UNSAFE_componentWillUpdateUniqueNames.size > 0) { - var _sortedNames2 = setToSortedString( - UNSAFE_componentWillUpdateUniqueNames - ); - - error( - "Using UNSAFE_componentWillUpdate in strict mode is not recommended " + - "and may indicate bugs in your code. " + - "See https://react.dev/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 - ); + case REACT_PORTAL_TYPE: + { + if (newChild.key === key) { + return updatePortal(returnFiber, oldFiber, newChild, lanes, debugInfo); + } else { + return null; + } } - if (componentWillMountUniqueNames.size > 0) { - var _sortedNames3 = setToSortedString( - componentWillMountUniqueNames - ); - - warn( - "componentWillMount has been renamed, and is not recommended for use. " + - "See https://react.dev/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 - ); + case REACT_LAZY_TYPE: + { + var payload = newChild._payload; + var init = newChild._init; + return updateSlot(returnFiber, oldFiber, init(payload), lanes, mergeDebugInfo(debugInfo, newChild._debugInfo)); } + } - if (componentWillReceivePropsUniqueNames.size > 0) { - var _sortedNames4 = setToSortedString( - componentWillReceivePropsUniqueNames - ); + if (isArray(newChild) || getIteratorFn(newChild)) { + if (key !== null) { + return null; + } - warn( - "componentWillReceiveProps has been renamed, and is not recommended for use. " + - "See https://react.dev/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://react.dev/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 - ); - } + return updateFragment(returnFiber, oldFiber, newChild, lanes, null, mergeDebugInfo(debugInfo, newChild._debugInfo)); + } // Usable node types + // + // Unwrap the inner value and recursively call this function again. - if (componentWillUpdateUniqueNames.size > 0) { - var _sortedNames5 = setToSortedString( - componentWillUpdateUniqueNames - ); - warn( - "componentWillUpdate has been renamed, and is not recommended for use. " + - "See https://react.dev/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 (typeof newChild.then === 'function') { + var thenable = newChild; + return updateSlot(returnFiber, oldFiber, unwrapThenable(thenable), lanes, debugInfo); + } - var pendingLegacyContextWarning = new Map(); // Tracks components we have already warned about. + if (newChild.$$typeof === REACT_CONTEXT_TYPE) { + var context = newChild; + return updateSlot(returnFiber, oldFiber, readContextDuringReconciliation(returnFiber, context, lanes), lanes, debugInfo); + } - var didWarnAboutLegacyContext = new Set(); + throwOnInvalidObjectType(returnFiber, newChild); + } - ReactStrictModeWarnings.recordLegacyContextWarning = function ( - fiber, - instance - ) { - var strictRoot = findStrictRoot(fiber); + { + if (typeof newChild === 'function') { + warnOnFunctionType(returnFiber, newChild); + } - 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 (typeof newChild === 'symbol') { + warnOnSymbolType(returnFiber, newChild); + } + } - return; - } // Dedup strategy: Warn once per component. + return null; + } - if (didWarnAboutLegacyContext.has(fiber.type)) { - return; - } + function updateFromMap(existingChildren, returnFiber, newIdx, newChild, lanes, debugInfo) { + if (typeof newChild === 'string' && newChild !== '' || typeof newChild === 'number' || typeof newChild === 'bigint') { + // 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, // $FlowFixMe[unsafe-addition] Flow doesn't want us to use `+` operator with string and bigint + '' + newChild, lanes, debugInfo); + } - var warningsForRoot = pendingLegacyContextWarning.get(strictRoot); + 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.type.contextTypes != null || - fiber.type.childContextTypes != null || - (instance !== null && typeof instance.getChildContext === "function") - ) { - if (warningsForRoot === undefined) { - warningsForRoot = []; - pendingLegacyContextWarning.set(strictRoot, warningsForRoot); + return updateElement(returnFiber, _matchedFiber, newChild, lanes, mergeDebugInfo(debugInfo, newChild._debugInfo)); } - warningsForRoot.push(fiber); - } - }; + case REACT_PORTAL_TYPE: + { + var _matchedFiber2 = existingChildren.get(newChild.key === null ? newIdx : newChild.key) || null; - ReactStrictModeWarnings.flushLegacyContextWarning = function () { - pendingLegacyContextWarning.forEach(function (fiberArray, strictRoot) { - if (fiberArray.length === 0) { - return; + return updatePortal(returnFiber, _matchedFiber2, newChild, lanes, debugInfo); } - 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); + case REACT_LAZY_TYPE: + var payload = newChild._payload; + var init = newChild._init; + return updateFromMap(existingChildren, returnFiber, newIdx, init(payload), lanes, mergeDebugInfo(debugInfo, newChild._debugInfo)); + } - try { - setCurrentFiber(firstFiber); - - 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://react.dev/link/legacy-context", - sortedNames - ); - } finally { - resetCurrentFiber(); - } - }); - }; + if (isArray(newChild) || getIteratorFn(newChild)) { + var _matchedFiber3 = existingChildren.get(newIdx) || null; - ReactStrictModeWarnings.discardPendingWarnings = function () { - pendingComponentWillMountWarnings = []; - pendingUNSAFE_ComponentWillMountWarnings = []; - pendingComponentWillReceivePropsWarnings = []; - pendingUNSAFE_ComponentWillReceivePropsWarnings = []; - pendingComponentWillUpdateWarnings = []; - pendingUNSAFE_ComponentWillUpdateWarnings = []; - pendingLegacyContextWarning = new Map(); - }; - } + return updateFragment(returnFiber, _matchedFiber3, newChild, lanes, null, mergeDebugInfo(debugInfo, newChild._debugInfo)); + } // Usable node types + // + // Unwrap the inner value and recursively call this function again. - function getThenablesFromState(state) { - { - var devState = state; - return devState.thenables; - } - } // 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. - - 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 noopSuspenseyCommitThenable = { - then: function () { - { - error( - "Internal React error: A listener was unexpectedly attached to a " + - '"noop" thenable. This is a bug in React. Please file an issue.' - ); - } + + if (typeof newChild.then === 'function') { + var thenable = newChild; + return updateFromMap(existingChildren, returnFiber, newIdx, unwrapThenable(thenable), lanes, debugInfo); } - }; - function createThenableState() { - // The ThenableState is created the first time a component suspends. If it - // suspends again, we'll reuse the same state. - { - return { - didWarnAboutUncachedPromise: false, - thenables: [] - }; + + if (newChild.$$typeof === REACT_CONTEXT_TYPE) { + var context = newChild; + return updateFromMap(existingChildren, returnFiber, newIdx, readContextDuringReconciliation(returnFiber, context, lanes), lanes, debugInfo); } - } - function isThenableResolved(thenable) { - var status = thenable.status; - return status === "fulfilled" || status === "rejected"; - } - function noop() {} + throwOnInvalidObjectType(returnFiber, newChild); + } - function trackUsedThenable(thenableState, thenable, index) { - if (ReactSharedInternals.actQueue !== null) { - ReactSharedInternals.didUsePromise = true; + { + if (typeof newChild === 'function') { + warnOnFunctionType(returnFiber, newChild); } - var trackedThenables = getThenablesFromState(thenableState); - var previous = trackedThenables[index]; + if (typeof newChild === 'symbol') { + warnOnSymbolType(returnFiber, newChild); + } + } - if (previous === undefined) { - trackedThenables.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. - { - var thenableStateDev = thenableState; + return null; + } + /** + * Warns if there is a duplicate or missing key + */ - if (!thenableStateDev.didWarnAboutUncachedPromise) { - // We should only warn the first time an uncached thenable is - // discovered per component, because if there are multiple, the - // subsequent ones are likely derived from the first. - // - // We track this on the thenableState instead of deduping using the - // component name like we usually do, because in the case of a - // promise-as-React-node, the owner component is likely different from - // the parent that's currently being reconciled. We'd have to track - // the owner using state, which we're trying to move away from. Though - // since this is dev-only, maybe that'd be OK. - // - // However, another benefit of doing it this way is we might - // eventually have a thenableState per memo/Forget boundary instead - // of per component, so this would allow us to have more - // granular warnings. - thenableStateDev.didWarnAboutUncachedPromise = true; // TODO: This warning should link to a corresponding docs page. - - error( - "A component was suspended by an uncached promise. Creating " + - "promises inside a Client Component or hook is not yet " + - "supported, except via a Suspense-compatible library or framework." - ); - } - } // Avoid an unhandled rejection errors for the Promises that we'll - // intentionally ignore. - thenable.then(noop, noop); - thenable = previous; - } - } // 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. + function warnOnInvalidKey(child, knownKeys, returnFiber) { + { + if (typeof child !== 'object' || child === null) { + return knownKeys; + } - switch (thenable.status) { - case "fulfilled": { - var fulfilledValue = thenable.value; - return fulfilledValue; - } + switch (child.$$typeof) { + case REACT_ELEMENT_TYPE: + case REACT_PORTAL_TYPE: + warnForMissingKey(child, returnFiber); + var key = child.key; - case "rejected": { - var rejectedError = thenable.reason; - checkIfUseWrappedInAsyncCatch(rejectedError); - throw rejectedError; - } + if (typeof key !== 'string') { + break; + } - 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 { - // This is an uncached thenable that we haven't seen before. - // Detect infinite ping loops caused by uncached promises. - var root = getWorkInProgressRoot(); - - if (root !== null && root.shellSuspendCounter > 100) { - // This root has suspended repeatedly in the shell without making any - // progress (i.e. committing something). This is highly suggestive of - // an infinite ping loop, often caused by an accidental Async Client - // Component. - // - // During a transition, we can suspend the work loop until the promise - // to resolve, but this is a sync render, so that's not an option. We - // also can't show a fallback, because none was provided. So our last - // resort is to throw an error. - // - // TODO: Remove this error in a future release. Other ways of handling - // this case include forcing a concurrent render, or putting the whole - // root into offscreen mode. - throw new Error( - "async/await is not yet supported in Client Components, only " + - "Server Components. This error is often caused by accidentally " + - "adding `'use client'` to a module that was originally written " + - "for the server." - ); - } + if (knownKeys === null) { + knownKeys = new Set(); + knownKeys.add(key); + break; + } - 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 (!knownKeys.has(key)) { + knownKeys.add(key); + break; + } - switch (thenable.status) { - case "fulfilled": { - var fulfilledThenable = thenable; - return fulfilledThenable.value; - } + 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); - case "rejected": { - var rejectedThenable = thenable; - var _rejectedError = rejectedThenable.reason; - checkIfUseWrappedInAsyncCatch(_rejectedError); - throw _rejectedError; - } - } // 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. + break; - suspendedThenable = thenable; + case REACT_LAZY_TYPE: + var payload = child._payload; + var init = child._init; + warnOnInvalidKey(init(payload), knownKeys, returnFiber); + break; + } + } - { - needsToResetSuspendedThenableDEV = true; - } + return knownKeys; + } + + function reconcileChildrenArray(returnFiber, currentFirstChild, newChildren, lanes, debugInfo) { + // 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; - throw SuspenseException; - } + for (var i = 0; i < newChildren.length; i++) { + var child = newChildren[i]; + knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber); } } - // 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." - ); + 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; } - var thenable = suspendedThenable; - suspendedThenable = null; + var newFiber = updateSlot(returnFiber, oldFiber, newChildren[newIdx], lanes, debugInfo); - { - needsToResetSuspendedThenableDEV = false; + 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; + } + + break; } - 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 (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); } } - return false; - } - function checkIfUseWrappedInAsyncCatch(rejectedReason) { - // This check runs in prod, too, because it prevents a more confusing - // downstream error, where SuspenseException is caught by a promise and - // thrown asynchronously. - // TODO: Another way to prevent SuspenseException from leaking into an async - // execution context is to check the dispatcher every time `use` is called, - // or some equivalent. That might be preferable for other reasons, too, since - // it matches how we prevent similar mistakes for other hooks. - if (rejectedReason === SuspenseException) { - throw new Error( - "Hooks are not supported inside an async component. This " + - "error is often caused by accidentally adding `'use client'` " + - "to a module that was originally written for the server." - ); - } - } - - var thenableState$1 = null; - var thenableIndexCounter$1 = 0; - - function mergeDebugInfo(outer, inner) { - if (inner == null) { - return outer; - } else if (outer === null) { - return inner; + lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); + + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = newFiber; } else { - // If we have two debugInfo, we need to create a new one. This makes the array no longer - // live so we'll miss any future updates if we received more so ideally we should always - // do this after both have fully resolved/unsuspended. - return outer.concat(inner); + // 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; } + + previousNewFiber = newFiber; + oldFiber = nextOldFiber; } - var didWarnAboutMaps; - var didWarnAboutGenerators; - var ownerHasKeyUseWarning; - var ownerHasFunctionTypeWarning; - var ownerHasSymbolTypeWarning; + if (newIdx === newChildren.length) { + // We've reached the end of the new children. We can delete the rest. + deleteRemainingChildren(returnFiber, oldFiber); - var warnForMissingKey = function (child, returnFiber) {}; + return resultingFirstChild; + } - { - didWarnAboutMaps = false; - didWarnAboutGenerators = false; - /** - * 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 = {}; - ownerHasSymbolTypeWarning = {}; - - warnForMissingKey = function (child, returnFiber) { - if (child === null || typeof child !== "object") { - 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, debugInfo); + + if (_newFiber === null) { + continue; } - if (!child._store || child._store.validated || child.key != null) { - return; + 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; } - 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[cannot-write] unable to narrow type from mixed to writable object + previousNewFiber = _newFiber; + } - child._store.validated = true; - var componentName = - getComponentNameFromFiber(returnFiber) || "Component"; + return resultingFirstChild; + } // Add all children to a key map for quick lookups. - if (ownerHasKeyUseWarning[componentName]) { - return; - } - ownerHasKeyUseWarning[componentName] = true; + var existingChildren = mapRemainingChildren(oldFiber); // Keep scanning and use the map to restore deleted items as moves. - error( - "Each child in a list should have a unique " + - '"key" prop. See https://react.dev/link/warning-keys for ' + - "more information." - ); - }; - } + for (; newIdx < newChildren.length; newIdx++) { + var _newFiber2 = updateFromMap(existingChildren, returnFiber, newIdx, newChildren[newIdx], lanes, debugInfo); + + 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); + } + } + + lastPlacedIndex = placeChild(_newFiber2, lastPlacedIndex, newIdx); - function unwrapThenable(thenable) { - var index = thenableIndexCounter$1; - thenableIndexCounter$1 += 1; + if (previousNewFiber === null) { + resultingFirstChild = _newFiber2; + } else { + previousNewFiber.sibling = _newFiber2; + } - if (thenableState$1 === null) { - thenableState$1 = createThenableState(); + previousNewFiber = _newFiber2; } + } - return trackUsedThenable(thenableState$1, thenable, index); + 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 coerceRef(returnFiber, current, workInProgress, element) { - var ref; + return resultingFirstChild; + } - { - // Old behavior. - ref = element.ref; - } // TODO: If enableRefAsProp is on, we shouldn't use the `ref` field. We - // should always read the ref from the prop. + function reconcileChildrenIterator(returnFiber, currentFirstChild, newChildrenIterable, lanes, debugInfo) { + // This is the same implementation as reconcileChildrenArray(), + // but using the iterator instead. + var iteratorFn = getIteratorFn(newChildrenIterable); - workInProgress.ref = ref; + 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 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 warnOnFunctionType(returnFiber, invalidChild) { - { - var parentName = getComponentNameFromFiber(returnFiber) || "Component"; - - if (ownerHasFunctionTypeWarning[parentName]) { - return; + { + // We don't support rendering Generators because it's a mutation. + // See https://github.com/facebook/react/issues/12995 + if (typeof Symbol === 'function' && // $FlowFixMe[prop-missing] 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.'); } - ownerHasFunctionTypeWarning[parentName] = true; - var name = invalidChild.displayName || invalidChild.name || "Component"; + didWarnAboutGenerators = true; + } // Warn about using Maps as children - if (returnFiber.tag === HostRoot) { - error( - "Functions are not valid as a React child. This may happen if " + - "you return %s instead of <%s /> from render. " + - "Or maybe you meant to call this function rather than return it.\n" + - " root.render(%s)", - name, - name, - name - ); - } else { - error( - "Functions are not valid as a React child. This may happen if " + - "you return %s instead of <%s /> from render. " + - "Or maybe you meant to call this function rather than return it.\n" + - " <%s>{%s}", - name, - name, - parentName, - name, - parentName - ); + + if (newChildrenIterable.entries === iteratorFn) { + if (!didWarnAboutMaps) { + error('Using Maps as children is not supported. ' + 'Use an array of keyed ReactElements instead.'); } - } - } - function warnOnSymbolType(returnFiber, invalidChild) { - { - var parentName = getComponentNameFromFiber(returnFiber) || "Component"; + didWarnAboutMaps = true; + } // First, validate keys. + // We'll get a different iterator later for the main pass. - if (ownerHasSymbolTypeWarning[parentName]) { - return; - } - ownerHasSymbolTypeWarning[parentName] = true; // eslint-disable-next-line react-internal/safe-string-coercion + var _newChildren = iteratorFn.call(newChildrenIterable); - var name = String(invalidChild); + if (_newChildren) { + var knownKeys = null; - if (returnFiber.tag === HostRoot) { - error( - "Symbols are not valid as a React child.\n" + " root.render(%s)", - name - ); - } else { - error( - "Symbols are not valid as a React child.\n" + " <%s>%s", - parentName, - name, - parentName - ); + var _step = _newChildren.next(); + + for (; !_step.done; _step = _newChildren.next()) { + var child = _step.value; + knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber); } } } - 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. + var newChildren = iteratorFn.call(newChildrenIterable); - function createChildReconciler(shouldTrackSideEffects) { - function deleteChild(returnFiber, childToDelete) { - if (!shouldTrackSideEffects) { - // Noop. - return; - } + if (newChildren == null) { + throw new Error('An iterable object provided no iterator.'); + } - var deletions = returnFiber.deletions; + var resultingFirstChild = null; + var previousNewFiber = null; + var oldFiber = currentFirstChild; + var lastPlacedIndex = 0; + var newIdx = 0; + var nextOldFiber = null; + var step = newChildren.next(); - if (deletions === null) { - returnFiber.deletions = [childToDelete]; - returnFiber.flags |= ChildDeletion; - } else { - deletions.push(childToDelete); - } + for (; oldFiber !== null && !step.done; newIdx++, step = newChildren.next()) { + if (oldFiber.index > newIdx) { + nextOldFiber = oldFiber; + oldFiber = null; + } else { + nextOldFiber = oldFiber.sibling; } - 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; + var newFiber = updateSlot(returnFiber, oldFiber, step.value, lanes, debugInfo); - while (childToDelete !== null) { - deleteChild(returnFiber, childToDelete); - childToDelete = childToDelete.sibling; + 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; } - return null; + break; } - function mapRemainingChildren(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; - - while (existingChild !== null) { - if (existingChild.key !== null) { - existingChildren.set(existingChild.key, existingChild); - } else { - existingChildren.set(existingChild.index, existingChild); - } - - existingChild = existingChild.sibling; + 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); } - - return existingChildren; } - 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; + lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); + + 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; } - function placeChild(newFiber, lastPlacedIndex, newIndex) { - newFiber.index = newIndex; + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } - 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 (step.done) { + // We've reached the end of the new children. We can delete the rest. + deleteRemainingChildren(returnFiber, oldFiber); - var current = newFiber.alternate; + return resultingFirstChild; + } - if (current !== null) { - var oldIndex = current.index; + 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, debugInfo); - 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; + if (_newFiber3 === null) { + continue; } - } - 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; + lastPlacedIndex = placeChild(_newFiber3, lastPlacedIndex, newIdx); + + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = _newFiber3; + } else { + previousNewFiber.sibling = _newFiber3; } - return newFiber; + previousNewFiber = _newFiber3; } - function updateTextNode( - returnFiber, - current, - textContent, - lanes, - debugInfo - ) { - if (current === null || current.tag !== HostText) { - // Insert - var created = createFiberFromText( - textContent, - returnFiber.mode, - lanes - ); - created.return = returnFiber; + return resultingFirstChild; + } // Add all children to a key map for quick lookups. - { - created._debugInfo = debugInfo; - } - return created; - } else { - // Update - var existing = useFiber(current, textContent); - existing.return = returnFiber; + var existingChildren = mapRemainingChildren(oldFiber); // Keep scanning and use the map to restore deleted items as moves. - { - existing._debugInfo = debugInfo; + for (; !step.done; newIdx++, step = newChildren.next()) { + var _newFiber4 = updateFromMap(existingChildren, returnFiber, newIdx, step.value, lanes, debugInfo); + + 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); } + } - return existing; + lastPlacedIndex = placeChild(_newFiber4, lastPlacedIndex, newIdx); + + if (previousNewFiber === null) { + resultingFirstChild = _newFiber4; + } else { + previousNewFiber.sibling = _newFiber4; } + + previousNewFiber = _newFiber4; } + } + + 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 updateElement(returnFiber, current, element, lanes, debugInfo) { + return resultingFirstChild; + } + + 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; + } + + function reconcileSingleElement(returnFiber, currentFirstChild, element, lanes, debugInfo) { + var key = element.key; + var child = currentFirstChild; + + 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 (elementType === REACT_FRAGMENT_TYPE) { - return updateFragment( - returnFiber, - current, - element.props.children, - lanes, - element.key, - debugInfo - ); - } - - 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); - coerceRef(returnFiber, current, existing, element); + if (child.tag === Fragment) { + deleteRemainingChildren(returnFiber, child.sibling); + var existing = useFiber(child, element.props.children); existing.return = returnFiber; { @@ -10001,13477 +9553,10258 @@ to return true:wantsResponderID| | return existing; } - } // Insert + } 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); - var created = createFiberFromElement(element, returnFiber.mode, lanes); - coerceRef(returnFiber, current, created, element); - created.return = returnFiber; + var _existing = useFiber(child, element.props); + + coerceRef(returnFiber, child, _existing, element); + _existing.return = returnFiber; + + { + _existing._debugOwner = element._owner; + _existing._debugInfo = debugInfo; + } + + return _existing; + } + } // Didn't match. - { - created._debugInfo = debugInfo; - } - return created; + deleteRemainingChildren(returnFiber, child); + break; + } else { + deleteChild(returnFiber, child); } - function updatePortal(returnFiber, current, portal, lanes, debugInfo) { - 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; + child = child.sibling; + } - { - created._debugInfo = debugInfo; - } + if (element.type === REACT_FRAGMENT_TYPE) { + var created = createFiberFromFragment(element.props.children, returnFiber.mode, lanes, element.key); + created.return = returnFiber; - return created; - } else { - // Update - var existing = useFiber(current, portal.children || []); - existing.return = returnFiber; + { + created._debugInfo = debugInfo; + } - { - existing._debugInfo = debugInfo; - } + return created; + } else { + var _created4 = createFiberFromElement(element, returnFiber.mode, lanes); + + coerceRef(returnFiber, currentFirstChild, _created4, element); + _created4.return = returnFiber; + + { + _created4._debugInfo = debugInfo; + } + + return _created4; + } + } + function reconcileSinglePortal(returnFiber, currentFirstChild, portal, lanes, debugInfo) { + var key = portal.key; + var child = currentFirstChild; + + 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 updateFragment( - returnFiber, - current, - fragment, - lanes, - key, - debugInfo - ) { - if (current === null || current.tag !== Fragment) { - // Insert - var created = createFiberFromFragment( - fragment, - returnFiber.mode, - lanes, - key - ); - created.return = returnFiber; + child = child.sibling; + } - { - created._debugInfo = debugInfo; - } + 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. - return created; - } else { - // Update - var existing = useFiber(current, fragment); - existing.return = returnFiber; - { - existing._debugInfo = debugInfo; - } + function reconcileChildFibersImpl(returnFiber, currentFirstChild, newChild, lanes, debugInfo) { + // This function is only recursive for Usables/Lazy and not nested arrays. + // That's so that using a Lazy wrapper is unobservable to the Fragment + // convention. + // 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. + // We don't use recursion here because a fragment inside a fragment + // is no longer considered "top level" for these purposes. + var isUnkeyedTopLevelFragment = typeof newChild === 'object' && newChild !== null && newChild.type === REACT_FRAGMENT_TYPE && newChild.key === null; - return existing; - } + if (isUnkeyedTopLevelFragment) { + newChild = newChild.props.children; + } // Handle object types + + + if (typeof newChild === 'object' && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return placeSingleChild(reconcileSingleElement(returnFiber, currentFirstChild, newChild, lanes, mergeDebugInfo(debugInfo, newChild._debugInfo))); + + case REACT_PORTAL_TYPE: + return placeSingleChild(reconcileSinglePortal(returnFiber, currentFirstChild, newChild, lanes)); + + case REACT_LAZY_TYPE: + var payload = newChild._payload; + var init = newChild._init; + return reconcileChildFibersImpl(returnFiber, currentFirstChild, init(payload), lanes, mergeDebugInfo(debugInfo, newChild._debugInfo)); + } + + if (isArray(newChild)) { + return reconcileChildrenArray(returnFiber, currentFirstChild, newChild, lanes, mergeDebugInfo(debugInfo, newChild._debugInfo)); } - function createChild(returnFiber, newChild, lanes, debugInfo) { - if ( - (typeof newChild === "string" && newChild !== "") || - typeof newChild === "number" || - typeof newChild === "bigint" - ) { - // 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( - // $FlowFixMe[unsafe-addition] Flow doesn't want us to use `+` operator with string and bigint - "" + newChild, - returnFiber.mode, - lanes - ); - created.return = returnFiber; + if (getIteratorFn(newChild)) { + return reconcileChildrenIterator(returnFiber, currentFirstChild, newChild, lanes, mergeDebugInfo(debugInfo, newChild._debugInfo)); + } // 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. - { - created._debugInfo = debugInfo; - } - return created; - } + if (typeof newChild.then === 'function') { + var thenable = newChild; + return reconcileChildFibersImpl(returnFiber, currentFirstChild, unwrapThenable(thenable), lanes, mergeDebugInfo(debugInfo, thenable._debugInfo)); + } - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: { - var _created = createFiberFromElement( - newChild, - returnFiber.mode, - lanes - ); + if (newChild.$$typeof === REACT_CONTEXT_TYPE) { + var context = newChild; + return reconcileChildFibersImpl(returnFiber, currentFirstChild, readContextDuringReconciliation(returnFiber, context, lanes), lanes, debugInfo); + } - coerceRef(returnFiber, null, _created, newChild); - _created.return = returnFiber; + throwOnInvalidObjectType(returnFiber, newChild); + } - { - _created._debugInfo = mergeDebugInfo( - debugInfo, - newChild._debugInfo - ); - } + if (typeof newChild === 'string' && newChild !== '' || typeof newChild === 'number' || typeof newChild === 'bigint') { + return placeSingleChild(reconcileSingleTextNode(returnFiber, currentFirstChild, // $FlowFixMe[unsafe-addition] Flow doesn't want us to use `+` operator with string and bigint + '' + newChild, lanes)); + } - return _created; - } + { + if (typeof newChild === 'function') { + warnOnFunctionType(returnFiber, newChild); + } - case REACT_PORTAL_TYPE: { - var _created2 = createFiberFromPortal( - newChild, - returnFiber.mode, - lanes - ); + if (typeof newChild === 'symbol') { + warnOnSymbolType(returnFiber, newChild); + } + } // Remaining cases are all treated as empty. - _created2.return = returnFiber; - { - _created2._debugInfo = debugInfo; - } + return deleteRemainingChildren(returnFiber, currentFirstChild); + } - return _created2; - } + 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, null // debugInfo + ); + thenableState$1 = null; // Don't bother to reset `thenableIndexCounter` to 0 because it always gets + // set at the beginning. - case REACT_LAZY_TYPE: { - var payload = newChild._payload; - var init = newChild._init; - return createChild( - returnFiber, - init(payload), - lanes, - mergeDebugInfo(debugInfo, newChild._debugInfo) // call merge after init - ); - } - } + return firstChildFiber; + } - if (isArray(newChild) || getIteratorFn(newChild)) { - var _created3 = createFiberFromFragment( - newChild, - returnFiber.mode, - lanes, - null - ); + return reconcileChildFibers; +} - _created3.return = returnFiber; +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 (workInProgress.child === null) { + return; + } + + var currentChild = workInProgress.child; + var newChild = createWorkInProgress(currentChild, currentChild.pendingProps); + workInProgress.child = newChild; + newChild.return = workInProgress; + + while (currentChild.sibling !== null) { + currentChild = currentChild.sibling; + newChild = newChild.sibling = createWorkInProgress(currentChild, currentChild.pendingProps); + newChild.return = workInProgress; + } + + newChild.sibling = null; +} // Reset a workInProgress child set to prepare it for a second pass. + +function resetChildFibers(workInProgress, lanes) { + var child = workInProgress.child; + + while (child !== null) { + resetWorkInProgress(child, lanes); + child = child.sibling; + } +} - { - _created3._debugInfo = mergeDebugInfo( - debugInfo, - newChild._debugInfo - ); - } +// 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 prevEntangledRenderLanesCursor = createCursor(NoLanes); +function pushHiddenContext(fiber, context) { + var prevEntangledRenderLanes = getEntangledRenderLanes(); + push(prevEntangledRenderLanesCursor, prevEntangledRenderLanes, 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. + + setEntangledRenderLanes(mergeLanes(prevEntangledRenderLanes, 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(prevEntangledRenderLanesCursor, getEntangledRenderLanes(), fiber); + push(currentTreeHiddenStackCursor, currentTreeHiddenStackCursor.current, fiber); +} +function popHiddenContext(fiber) { + // Restore the previous render lanes from the stack + setEntangledRenderLanes(prevEntangledRenderLanesCursor.current); + pop(currentTreeHiddenStackCursor, fiber); + pop(prevEntangledRenderLanesCursor, fiber); +} +function isCurrentTreeHidden() { + return currentTreeHiddenStackCursor.current !== null; +} + +// suspends, i.e. it's the nearest `catch` block on the stack. + +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 (shellBoundary !== null) ; else { + var current = fiber.alternate; + + 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; + } + } + } + } 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. + +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 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; - return _created3; - } // Usable node types - // - // Unwrap the inner value and recursively call this function again. - - if (typeof newChild.then === "function") { - var thenable = newChild; - return createChild( - returnFiber, - unwrapThenable(thenable), - lanes, - mergeDebugInfo(debugInfo, newChild._debugInfo) - ); - } + while (node !== null) { + if (node.tag === SuspenseComponent) { + var state = node.memoizedState; - if (newChild.$$typeof === REACT_CONTEXT_TYPE) { - var context = newChild; - return createChild( - returnFiber, - readContextDuringReconciliation(returnFiber, context, lanes), - lanes, - debugInfo - ); - } + if (state !== null) { + var dehydrated = state.dehydrated; - throwOnInvalidObjectType(returnFiber, newChild); + if (dehydrated === null || isSuspenseInstancePending() || isSuspenseInstanceFallback()) { + return node; } + } + } 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 (typeof newChild === "function") { - warnOnFunctionType(returnFiber, newChild); - } + if (didSuspend) { + return node; + } + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } - if (typeof newChild === "symbol") { - warnOnSymbolType(returnFiber, newChild); - } - } + if (node === row) { + return null; + } + while (node.sibling === null) { + if (node.return === null || node.return === row) { return null; } - function updateSlot(returnFiber, oldFiber, newChild, lanes, debugInfo) { - // Update the fiber if the keys match, otherwise return null. - var key = oldFiber !== null ? oldFiber.key : null; + node = node.return; + } - if ( - (typeof newChild === "string" && newChild !== "") || - typeof newChild === "number" || - typeof newChild === "bigint" - ) { - // 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.sibling.return = node.return; + node = node.sibling; + } - return updateTextNode( - returnFiber, - oldFiber, // $FlowFixMe[unsafe-addition] Flow doesn't want us to use `+` operator with string and bigint - "" + newChild, - lanes, - debugInfo - ); - } - - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: { - if (newChild.key === key) { - return updateElement( - returnFiber, - oldFiber, - newChild, - lanes, - mergeDebugInfo(debugInfo, newChild._debugInfo) - ); - } else { - return null; - } - } + return null; +} - case REACT_PORTAL_TYPE: { - if (newChild.key === key) { - return updatePortal( - returnFiber, - oldFiber, - newChild, - lanes, - debugInfo - ); - } else { - return null; - } - } +var NoFlags = +/* */ +0; // Represents whether effect should fire. + +var HasEffect = +/* */ +1; // Represents the phase in which the effect (not the clean-up) fires. + +var Insertion = +/* */ +2; +var Layout = +/* */ +4; +var Passive = +/* */ +8; + +var didWarnAboutMismatchedHooksForComponent; +var didWarnUncachedGetSnapshot; +var didWarnAboutUseWrappedInTryCatch; +var didWarnAboutAsyncClientComponent; +var didWarnAboutUseFormState; + +{ + didWarnAboutMismatchedHooksForComponent = new Set(); + didWarnAboutUseWrappedInTryCatch = new Set(); + didWarnAboutAsyncClientComponent = new Set(); + didWarnAboutUseFormState = new Set(); +} // The effect "instance" is a shared object that remains the same for the entire +// lifetime of an effect. In Rust terms, a RefCell. We use it to store the +// "destroy" function that is returned from an effect, because that is stateful. +// The field is `undefined` if the effect is unmounted, or if the effect ran +// but is not stateful. We don't explicitly track whether the effect is mounted +// or unmounted because that can be inferred by the hiddenness of the fiber in +// the tree, i.e. whether there is a hidden Offscreen fiber above it. +// +// It's unfortunate that this is stored on a separate object, because it adds +// more memory per effect instance, but it's conceptually sound. I think there's +// likely a better data structure we could use for effects; perhaps just one +// array of effect instances per fiber. But I think this is OK for now despite +// the additional memory and we can follow up with performance +// optimizations later. +// These are set right before calling the component. + + +var renderLanes = 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`. + +var didScheduleRenderPhaseUpdateDuringThisPass = false; +var shouldDoubleInvokeUserFnsInHooksDEV = false; // Counts the number of useId hooks in this component. + +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. + +var globalClientIdCounter = 0; +var RE_RENDER_LIMIT = 25; // In DEV, this is the name of the currently executing primitive hook + +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. + +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 { + hookTypesDev.push(hookName); + } + } +} - case REACT_LAZY_TYPE: { - var payload = newChild._payload; - var init = newChild._init; - return updateSlot( - returnFiber, - oldFiber, - init(payload), - lanes, - mergeDebugInfo(debugInfo, newChild._debugInfo) - ); - } - } +function updateHookTypesDev() { + { + var hookName = currentHookNameInDev; - if (isArray(newChild) || getIteratorFn(newChild)) { - if (key !== null) { - return null; - } + if (hookTypesDev !== null) { + hookTypesUpdateIndexDev++; - return updateFragment( - returnFiber, - oldFiber, - newChild, - lanes, - null, - mergeDebugInfo(debugInfo, newChild._debugInfo) - ); - } // 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, - debugInfo - ); - } + if (hookTypesDev[hookTypesUpdateIndexDev] !== hookName) { + warnOnHookMismatchInDev(hookName); + } + } + } +} - if (newChild.$$typeof === REACT_CONTEXT_TYPE) { - var context = newChild; - return updateSlot( - returnFiber, - oldFiber, - readContextDuringReconciliation(returnFiber, context, lanes), - lanes, - debugInfo - ); - } +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); + } + } +} - throwOnInvalidObjectType(returnFiber, newChild); - } +function warnOnHookMismatchInDev(currentHookName) { + { + var componentName = getComponentNameFromFiber(currentlyRenderingFiber$1); - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber, newChild); - } + if (!didWarnAboutMismatchedHooksForComponent.has(componentName)) { + didWarnAboutMismatchedHooksForComponent.add(componentName); - if (typeof newChild === "symbol") { - warnOnSymbolType(returnFiber, newChild); + if (hookTypesDev !== null) { + var table = ''; + var secondColumnStart = 30; + + 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 + + while (row.length < secondColumnStart) { + row += ' '; } + + row += newHookName + '\n'; + table += row; } - return null; + 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://react.dev/link/rules-of-hooks\n\n' + ' Previous render Next render\n' + ' ------------------------------------------------------\n' + '%s' + ' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n', componentName, table); } + } + } +} - function updateFromMap( - existingChildren, - returnFiber, - newIdx, - newChild, - lanes, - debugInfo - ) { - if ( - (typeof newChild === "string" && newChild !== "") || - typeof newChild === "number" || - typeof newChild === "bigint" - ) { - // 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, // $FlowFixMe[unsafe-addition] Flow doesn't want us to use `+` operator with string and bigint - "" + newChild, - lanes, - debugInfo - ); - } - - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: { - var _matchedFiber = - existingChildren.get( - newChild.key === null ? newIdx : newChild.key - ) || null; - - return updateElement( - returnFiber, - _matchedFiber, - newChild, - lanes, - mergeDebugInfo(debugInfo, newChild._debugInfo) - ); - } +function warnOnUseFormStateInDev() { + { + var componentName = getComponentNameFromFiber(currentlyRenderingFiber$1); - case REACT_PORTAL_TYPE: { - var _matchedFiber2 = - existingChildren.get( - newChild.key === null ? newIdx : newChild.key - ) || null; - - return updatePortal( - returnFiber, - _matchedFiber2, - newChild, - lanes, - debugInfo - ); - } + if (!didWarnAboutUseFormState.has(componentName)) { + didWarnAboutUseFormState.add(componentName); - case REACT_LAZY_TYPE: - var payload = newChild._payload; - var init = newChild._init; - return updateFromMap( - existingChildren, - returnFiber, - newIdx, - init(payload), - lanes, - mergeDebugInfo(debugInfo, newChild._debugInfo) - ); - } + error('ReactDOM.useFormState has been renamed to React.useActionState. ' + 'Please update %s to use React.useActionState.', componentName); + } + } +} - if (isArray(newChild) || getIteratorFn(newChild)) { - var _matchedFiber3 = existingChildren.get(newIdx) || null; +function warnIfAsyncClientComponent(Component) { + { + // This dev-only check only works for detecting native async functions, + // not transpiled ones. There's also a prod check that we use to prevent + // async client components from crashing the app; the prod one works even + // for transpiled async functions. Neither mechanism is completely + // bulletproof but together they cover the most common cases. + var isAsyncFunction = // $FlowIgnore[method-unbinding] + Object.prototype.toString.call(Component) === '[object AsyncFunction]'; - return updateFragment( - returnFiber, - _matchedFiber3, - newChild, - lanes, - null, - mergeDebugInfo(debugInfo, newChild._debugInfo) - ); - } // Usable node types - // - // Unwrap the inner value and recursively call this function again. - - if (typeof newChild.then === "function") { - var thenable = newChild; - return updateFromMap( - existingChildren, - returnFiber, - newIdx, - unwrapThenable(thenable), - lanes, - debugInfo - ); - } + if (isAsyncFunction) { + // Encountered an async Client Component. This is not yet supported. + var componentName = getComponentNameFromFiber(currentlyRenderingFiber$1); - if (newChild.$$typeof === REACT_CONTEXT_TYPE) { - var context = newChild; - return updateFromMap( - existingChildren, - returnFiber, - newIdx, - readContextDuringReconciliation(returnFiber, context, lanes), - lanes, - debugInfo - ); - } + if (!didWarnAboutAsyncClientComponent.has(componentName)) { + didWarnAboutAsyncClientComponent.add(componentName); - throwOnInvalidObjectType(returnFiber, newChild); - } + error('async/await is not yet supported in Client Components, only ' + 'Server Components. This error is often caused by accidentally ' + "adding `'use client'` to a module that was originally written " + 'for the server.'); + } + } + } +} - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber, newChild); - } +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://react.dev/link/invalid-hook-call for tips about how to debug and fix this problem.'); +} - if (typeof newChild === "symbol") { - warnOnSymbolType(returnFiber, newChild); - } - } +function areHookInputsEqual(nextDeps, prevDeps) { + { + if (ignorePreviousDependencies) { + // Only true when this component is being hot reloaded. + return false; + } + } - return null; - } - /** - * Warns if there is a duplicate or missing key - */ + if (prevDeps === null) { + { + 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); + } - function warnOnInvalidKey(child, knownKeys, returnFiber) { - { - if (typeof child !== "object" || child === null) { - return knownKeys; - } + return false; + } - switch (child.$$typeof) { - case REACT_ELEMENT_TYPE: - case REACT_PORTAL_TYPE: - warnForMissingKey(child, returnFiber); - var key = child.key; + { + // 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 - if (typeof key !== "string") { - break; - } - if (knownKeys === null) { - knownKeys = new Set(); - knownKeys.add(key); - break; - } + 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; + } - if (!knownKeys.has(key)) { - knownKeys.add(key); - break; - } + return false; + } - 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 - ); + return true; +} - break; +function renderWithHooks(current, workInProgress, Component, props, secondArg, nextRenderLanes) { + renderLanes = nextRenderLanes; + currentlyRenderingFiber$1 = workInProgress; + + { + hookTypesDev = current !== null ? current._debugHookTypes : null; + hookTypesUpdateIndexDev = -1; // Used for hot reloading: + + ignorePreviousDependencies = current !== null && current.type !== workInProgress.type; + warnIfAsyncClientComponent(Component); + } + + 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 (current !== null && current.memoizedState !== null) { + ReactSharedInternals.H = 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. + ReactSharedInternals.H = HooksDispatcherOnMountWithHookTypesInDEV; + } else { + ReactSharedInternals.H = 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. + + + var shouldDoubleRenderDEV = (workInProgress.mode & StrictLegacyMode) !== NoMode; + shouldDoubleInvokeUserFnsInHooksDEV = shouldDoubleRenderDEV; + var children = Component(props, secondArg); + shouldDoubleInvokeUserFnsInHooksDEV = false; // Check if there was a render phase update + + if (didScheduleRenderPhaseUpdateDuringThisPass) { + // Keep rendering until the component stabilizes (there are no more render + // phase updates). + children = renderWithHooksAgain(workInProgress, Component, props, secondArg); + } + + if (shouldDoubleRenderDEV) { + // In development, components are invoked twice to help detect side effects. + setIsStrictModeForDevtools(true); + + try { + children = renderWithHooksAgain(workInProgress, Component, props, secondArg); + } finally { + setIsStrictModeForDevtools(false); + } + } + + finishRenderingHooks(current, workInProgress); + return children; +} - case REACT_LAZY_TYPE: - var payload = child._payload; - var init = child._init; - warnOnInvalidKey(init(payload), knownKeys, returnFiber); - break; - } - } +function finishRenderingHooks(current, workInProgress, Component) { + { + workInProgress._debugHookTypes = hookTypesDev; + } // 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. - return knownKeys; - } - function reconcileChildrenArray( - returnFiber, - currentFirstChild, - newChildren, - lanes, - debugInfo - ) { - // 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; + ReactSharedInternals.H = ContextOnlyDispatcher; // 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. - for (var i = 0; i < newChildren.length; i++) { - var child = newChildren[i]; - knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber); - } - } + var didRenderTooFewHooks = currentHook !== null && currentHook.next !== null; + renderLanes = NoLanes; + currentlyRenderingFiber$1 = null; + currentHook = null; + workInProgressHook = null; - var resultingFirstChild = null; - var previousNewFiber = null; - var oldFiber = currentFirstChild; - var lastPlacedIndex = 0; - var newIdx = 0; - var nextOldFiber = null; + { + 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. - for (; oldFiber !== null && newIdx < newChildren.length; newIdx++) { - if (oldFiber.index > newIdx) { - nextOldFiber = oldFiber; - oldFiber = null; - } else { - nextOldFiber = oldFiber.sibling; - } + 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.'); + } + } - var newFiber = updateSlot( - returnFiber, - oldFiber, - newChildren[newIdx], - lanes, - debugInfo - ); - - 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; - } + didScheduleRenderPhaseUpdate = false; // This is reset by checkDidRenderIdHook + // localIdCounter = 0; - break; - } + thenableIndexCounter = 0; + thenableState = null; - 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); - } - } + if (didRenderTooFewHooks) { + throw new Error('Rendered fewer hooks than expected. This may be caused by an accidental ' + 'early return statement.'); + } - lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); + { + if (checkIfUseWrappedInTryCatch()) { + var componentName = getComponentNameFromFiber(workInProgress) || 'Unknown'; - 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 (!didWarnAboutUseWrappedInTryCatch.has(componentName) && // This warning also fires if you suspend with `use` inside an + // async component. Since we warn for that above, we'll silence this + // second warning by checking here. + !didWarnAboutAsyncClientComponent.has(componentName)) { + didWarnAboutUseWrappedInTryCatch.add(componentName); - previousNewFiber = newFiber; - oldFiber = nextOldFiber; - } + 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.'); + } + } + } +} - if (newIdx === newChildren.length) { - // We've reached the end of the new children. We can delete the rest. - deleteRemainingChildren(returnFiber, oldFiber); +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: + + ignorePreviousDependencies = current !== null && current.type !== workInProgress.type; + } + + var children = renderWithHooksAgain(workInProgress, Component, props, secondArg); + finishRenderingHooks(current, workInProgress); + return children; +} - return resultingFirstChild; - } +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. + currentlyRenderingFiber$1 = workInProgress; + 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; + } - 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, - debugInfo - ); + thenableIndexCounter = 0; + didScheduleRenderPhaseUpdateDuringThisPass = false; - if (_newFiber === null) { - continue; - } + if (numberOfReRenders >= RE_RENDER_LIMIT) { + throw new Error('Too many re-renders. React limits the number of renders to prevent ' + 'an infinite loop.'); + } - lastPlacedIndex = placeChild(_newFiber, lastPlacedIndex, newIdx); + numberOfReRenders += 1; - if (previousNewFiber === null) { - // TODO: Move out of the loop. This only happens for the first run. - resultingFirstChild = _newFiber; - } else { - previousNewFiber.sibling = _newFiber; - } + { + // 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 - previousNewFiber = _newFiber; - } - return resultingFirstChild; - } // Add all children to a key map for quick lookups. - - var existingChildren = mapRemainingChildren(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, - debugInfo - ); - - 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 - ); - } - } + currentHook = null; + workInProgressHook = null; + workInProgress.updateQueue = null; - lastPlacedIndex = placeChild(_newFiber2, lastPlacedIndex, newIdx); + { + // Also validate hook order for cascading updates. + hookTypesUpdateIndexDev = -1; + } - if (previousNewFiber === null) { - resultingFirstChild = _newFiber2; - } else { - previousNewFiber.sibling = _newFiber2; - } + ReactSharedInternals.H = HooksDispatcherOnRerenderInDEV ; + children = Component(props, secondArg); + } while (didScheduleRenderPhaseUpdateDuringThisPass); - previousNewFiber = _newFiber2; - } - } + return children; +} - 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 renderTransitionAwareHostComponentWithHooks(current, workInProgress, lanes) { + if (!enableAsyncActions) { + throw new Error('Not implemented.'); + } - return resultingFirstChild; - } + return renderWithHooks(current, workInProgress, TransitionAwareHostComponent, null, null, lanes); +} +function TransitionAwareHostComponent() { + if (!enableAsyncActions) { + throw new Error('Not implemented.'); + } - function reconcileChildrenIterator( - returnFiber, - currentFirstChild, - newChildrenIterable, - lanes, - debugInfo - ) { - // This is the same implementation as reconcileChildrenArray(), - // but using the iterator instead. - var iteratorFn = getIteratorFn(newChildrenIterable); + var dispatcher = ReactSharedInternals.H; - 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." - ); - } + var _dispatcher$useState = dispatcher.useState(), + maybeThenable = _dispatcher$useState[0]; - { - // We don't support rendering Generators because it's a mutation. - // See https://github.com/facebook/react/issues/12995 - if ( - typeof Symbol === "function" && // $FlowFixMe[prop-missing] 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." - ); - } + var nextState; - didWarnAboutGenerators = true; - } // Warn about using Maps as children + if (typeof maybeThenable.then === 'function') { + var thenable = maybeThenable; + nextState = useThenable(thenable); + } else { + var status = maybeThenable; + nextState = status; + } // The "reset state" is an object. If it changes, that means something + // requested that we reset the form. - if (newChildrenIterable.entries === iteratorFn) { - if (!didWarnAboutMaps) { - error( - "Using Maps as children is not supported. " + - "Use an array of keyed ReactElements instead." - ); - } - didWarnAboutMaps = true; - } // First, validate keys. - // We'll get a different iterator later for the main pass. + var _dispatcher$useState2 = dispatcher.useState(), + nextResetState = _dispatcher$useState2[0]; - var _newChildren = iteratorFn.call(newChildrenIterable); + var prevResetState = currentHook !== null ? currentHook.memoizedState : null; - if (_newChildren) { - var knownKeys = null; + if (prevResetState !== nextResetState) { + // Schedule a form reset + currentlyRenderingFiber$1.flags |= FormReset; + } - var _step = _newChildren.next(); + return nextState; +} +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). - for (; !_step.done; _step = _newChildren.next()) { - var child = _step.value; - knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber); - } - } - } + 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. + currentlyRenderingFiber$1 = null; // 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. + + ReactSharedInternals.H = ContextOnlyDispatcher; +} +function resetHooksOnUnwind(workInProgress) { + 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 = workInProgress.memoizedState; - if (newChildren == null) { - throw new Error("An iterable object provided no iterator."); - } + while (hook !== null) { + var queue = hook.queue; - var resultingFirstChild = null; - var previousNewFiber = null; - var oldFiber = currentFirstChild; - var lastPlacedIndex = 0; - var newIdx = 0; - var nextOldFiber = null; - var step = newChildren.next(); + if (queue !== null) { + queue.pending = null; + } - for ( - ; - oldFiber !== null && !step.done; - newIdx++, step = newChildren.next() - ) { - if (oldFiber.index > newIdx) { - nextOldFiber = oldFiber; - oldFiber = null; - } else { - nextOldFiber = oldFiber.sibling; - } + hook = hook.next; + } - var newFiber = updateSlot( - returnFiber, - oldFiber, - step.value, - lanes, - debugInfo - ); - - 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; - } + didScheduleRenderPhaseUpdate = false; + } - break; - } + renderLanes = NoLanes; + currentlyRenderingFiber$1 = null; + currentHook = null; + workInProgressHook = null; - 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); - } - } + { + hookTypesDev = null; + hookTypesUpdateIndexDev = -1; + currentHookNameInDev = null; + } - lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); + didScheduleRenderPhaseUpdateDuringThisPass = false; + thenableIndexCounter = 0; + thenableState = null; +} - 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; - } +function mountWorkInProgressHook() { + var hook = { + memoizedState: null, + baseState: null, + baseQueue: null, + queue: null, + next: null + }; + + 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; +} - previousNewFiber = newFiber; - oldFiber = nextOldFiber; - } +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; + + if (currentHook === null) { + var current = currentlyRenderingFiber$1.alternate; + + if (current !== null) { + nextCurrentHook = current.memoizedState; + } else { + nextCurrentHook = null; + } + } 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 (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.'); + } + } - if (step.done) { - // We've reached the end of the new children. We can delete the rest. - deleteRemainingChildren(returnFiber, oldFiber); + currentHook = nextCurrentHook; + var newHook = { + memoizedState: currentHook.memoizedState, + baseState: currentHook.baseState, + baseQueue: currentHook.baseQueue, + queue: currentHook.queue, + next: null + }; - return resultingFirstChild; - } + 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 (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, - debugInfo - ); + 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 (_newFiber3 === null) { - continue; - } - 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 useThenable(thenable) { + // Track the position of the thenable within this fiber. + var index = thenableIndexCounter; + thenableIndexCounter += 1; - return resultingFirstChild; - } // Add all children to a key map for quick lookups. - - var existingChildren = mapRemainingChildren(oldFiber); // Keep scanning and use the map to restore deleted items as moves. - - for (; !step.done; newIdx++, step = newChildren.next()) { - var _newFiber4 = updateFromMap( - existingChildren, - returnFiber, - newIdx, - step.value, - lanes, - debugInfo - ); - - 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 (thenableState === null) { + thenableState = createThenableState(); + } - lastPlacedIndex = placeChild(_newFiber4, lastPlacedIndex, newIdx); + var result = trackUsedThenable(thenableState, thenable, index); - if (previousNewFiber === null) { - resultingFirstChild = _newFiber4; - } else { - previousNewFiber.sibling = _newFiber4; - } + 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. + { + ReactSharedInternals.H = HooksDispatcherOnMountInDEV; + } + } - previousNewFiber = _newFiber4; - } - } + return result; +} - 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 use(usable) { + if (usable !== null && typeof usable === 'object') { + // $FlowFixMe[method-unbinding] + if (typeof usable.then === 'function') { + // This is a thenable. + var thenable = usable; + return useThenable(thenable); + } else if (usable.$$typeof === REACT_CONTEXT_TYPE) { + var context = usable; + return readContext(context); + } + } // eslint-disable-next-line react-internal/safe-string-coercion - return resultingFirstChild; - } - 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; - } - - function reconcileSingleElement( - returnFiber, - currentFirstChild, - element, - lanes, - debugInfo - ) { - var key = element.key; - var child = currentFirstChild; - - 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 (elementType === REACT_FRAGMENT_TYPE) { - if (child.tag === Fragment) { - deleteRemainingChildren(returnFiber, child.sibling); - var existing = useFiber(child, element.props.children); - existing.return = returnFiber; + throw new Error('An unsupported type was passed to use(): ' + String(usable)); +} - { - existing._debugOwner = element._owner; - existing._debugInfo = debugInfo; - } +function useMemoCache(size) { + var memoCache = null; // Fast-path, load memo cache from wip fiber if already prepared - 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); + var updateQueue = currentlyRenderingFiber$1.updateQueue; - var _existing = useFiber(child, element.props); + if (updateQueue !== null) { + memoCache = updateQueue.memoCache; + } // Otherwise clone from the current fiber - coerceRef(returnFiber, child, _existing, element); - _existing.return = returnFiber; - { - _existing._debugOwner = element._owner; - _existing._debugInfo = debugInfo; - } + if (memoCache == null) { + var current = currentlyRenderingFiber$1.alternate; - return _existing; - } - } // Didn't match. + if (current !== null) { + var currentUpdateQueue = current.updateQueue; - deleteRemainingChildren(returnFiber, child); - break; - } else { - deleteChild(returnFiber, child); - } + if (currentUpdateQueue !== null) { + var currentMemoCache = currentUpdateQueue.memoCache; - child = child.sibling; + 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 - if (element.type === REACT_FRAGMENT_TYPE) { - var created = createFiberFromFragment( - element.props.children, - returnFiber.mode, - lanes, - element.key - ); - created.return = returnFiber; - { - created._debugInfo = debugInfo; - } + if (memoCache == null) { + memoCache = { + data: [], + index: 0 + }; + } - return created; - } else { - var _created4 = createFiberFromElement( - element, - returnFiber.mode, - lanes - ); + if (updateQueue === null) { + updateQueue = createFunctionComponentUpdateQueue(); + currentlyRenderingFiber$1.updateQueue = updateQueue; + } - coerceRef(returnFiber, currentFirstChild, _created4, element); - _created4.return = returnFiber; + updateQueue.memoCache = memoCache; + var data = memoCache.data[memoCache.index]; - { - _created4._debugInfo = debugInfo; - } + if (data === undefined) { + data = memoCache.data[memoCache.index] = new Array(size); - return _created4; - } - } - - function reconcileSinglePortal( - returnFiber, - currentFirstChild, - portal, - lanes, - debugInfo - ) { - var key = portal.key; - var child = currentFirstChild; - - 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); - } + 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); + } + } - child = child.sibling; - } - - 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 reconcileChildFibersImpl( - returnFiber, - currentFirstChild, - newChild, - lanes, - debugInfo - ) { - // This function is only recursive for Usables/Lazy and not nested arrays. - // That's so that using a Lazy wrapper is unobservable to the Fragment - // convention. - // 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. - // We don't use recursion here because a fragment inside a fragment - // is no longer considered "top level" for these purposes. - var isUnkeyedTopLevelFragment = - typeof newChild === "object" && - newChild !== null && - newChild.type === REACT_FRAGMENT_TYPE && - newChild.key === null; - - if (isUnkeyedTopLevelFragment) { - newChild = newChild.props.children; - } // Handle object types - - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: - return placeSingleChild( - reconcileSingleElement( - returnFiber, - currentFirstChild, - newChild, - lanes, - mergeDebugInfo(debugInfo, newChild._debugInfo) - ) - ); - - case REACT_PORTAL_TYPE: - return placeSingleChild( - reconcileSinglePortal( - returnFiber, - currentFirstChild, - newChild, - lanes - ) - ); - - case REACT_LAZY_TYPE: - var payload = newChild._payload; - var init = newChild._init; - return reconcileChildFibersImpl( - returnFiber, - currentFirstChild, - init(payload), - lanes, - mergeDebugInfo(debugInfo, newChild._debugInfo) - ); - } + memoCache.index++; + return data; +} - if (isArray(newChild)) { - return reconcileChildrenArray( - returnFiber, - currentFirstChild, - newChild, - lanes, - mergeDebugInfo(debugInfo, newChild._debugInfo) - ); - } +function basicStateReducer(state, action) { + // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types + return typeof action === 'function' ? action(state) : action; +} - if (getIteratorFn(newChild)) { - return reconcileChildrenIterator( - returnFiber, - currentFirstChild, - newChild, - lanes, - mergeDebugInfo(debugInfo, newChild._debugInfo) - ); - } // 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 (typeof newChild.then === "function") { - var thenable = newChild; - return reconcileChildFibersImpl( - returnFiber, - currentFirstChild, - unwrapThenable(thenable), - lanes, - mergeDebugInfo(debugInfo, thenable._debugInfo) - ); - } +function mountReducer(reducer, initialArg, init) { + var hook = mountWorkInProgressHook(); + var initialState; + + if (init !== undefined) { + initialState = init(initialArg); + + if (shouldDoubleInvokeUserFnsInHooksDEV) { + setIsStrictModeForDevtools(true); + init(initialArg); + setIsStrictModeForDevtools(false); + } + } 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]; +} - if (newChild.$$typeof === REACT_CONTEXT_TYPE) { - var context = newChild; - return reconcileChildFibersImpl( - returnFiber, - currentFirstChild, - readContextDuringReconciliation(returnFiber, context, lanes), - lanes, - debugInfo - ); - } +function updateReducer(reducer, initialArg, init) { + var hook = updateWorkInProgressHook(); + return updateReducerImpl(hook, currentHook, reducer); +} - throwOnInvalidObjectType(returnFiber, newChild); - } +function updateReducerImpl(hook, current, reducer) { + var queue = hook.queue; - if ( - (typeof newChild === "string" && newChild !== "") || - typeof newChild === "number" || - typeof newChild === "bigint" - ) { - return placeSingleChild( - reconcileSingleTextNode( - returnFiber, - currentFirstChild, // $FlowFixMe[unsafe-addition] Flow doesn't want us to use `+` operator with string and bigint - "" + newChild, - lanes - ) - ); - } + if (queue === null) { + throw new Error('Should have a queue. This is likely a bug in React. Please file an issue.'); + } - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber, newChild); - } + queue.lastRenderedReducer = reducer; // The last rebase update that is NOT part of the base state. - if (typeof newChild === "symbol") { - warnOnSymbolType(returnFiber, newChild); - } - } // Remaining cases are all treated as empty. + var baseQueue = hook.baseQueue; // The last pending update that hasn't been processed yet. - return deleteRemainingChildren(returnFiber, currentFirstChild); - } + var pendingQueue = queue.pending; + + 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; + } - 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, - null // debugInfo - ); - thenableState$1 = null; // Don't bother to reset `thenableIndexCounter` to 0 because it always gets - // set at the beginning. + { + 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.'); + } + } + + current.baseQueue = baseQueue = pendingQueue; + queue.pending = null; + } + + var baseState = hook.baseState; + + if (baseQueue === null) { + // If there are no pending updates, then the memoized state should be the + // same as the base state. Currently these only diverge in the case of + // useOptimistic, because useOptimistic accepts a new baseState on + // every render. + hook.memoizedState = baseState; // We don't need to call markWorkInProgressReceivedUpdate because + // baseState is derived from other reactive values. + } else { + // We have a queue to process. + var first = baseQueue.next; + var newState = baseState; + var newBaseState = null; + var newBaseQueueFirst = null; + var newBaseQueueLast = null; + var update = first; + var didReadFromEntangledAsyncAction = false; + + 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); + + 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, + revertLane: update.revertLane, + action: update.action, + hasEagerState: update.hasEagerState, + eagerState: update.eagerState, + next: null + }; - return firstChildFiber; - } + 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. - return reconcileChildFibers; - } - 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."); - } + currentlyRenderingFiber$1.lanes = mergeLanes(currentlyRenderingFiber$1.lanes, updateLane); + markSkippedUpdateLanes(updateLane); + } else { + // This update does have sufficient priority. + // Check if this is an optimistic update. + var revertLane = update.revertLane; + + if (!enableAsyncActions || revertLane === NoLane) { + // This is not an optimistic update, and we're going to apply it now. + // But, if there were earlier updates that were skipped, we need to + // leave this update in the queue so it can be rebased later. + 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, + revertLane: NoLane, + action: update.action, + hasEagerState: update.hasEagerState, + eagerState: update.eagerState, + next: null + }; + newBaseQueueLast = newBaseQueueLast.next = _clone; + } // Check if this update is part of a pending async action. If so, + // we'll need to suspend until the action has finished, so that it's + // batched together with future updates in the same action. - if (workInProgress.child === null) { - return; - } - var currentChild = workInProgress.child; - var newChild = createWorkInProgress( - currentChild, - currentChild.pendingProps - ); - workInProgress.child = newChild; - newChild.return = workInProgress; + if (updateLane === peekEntangledActionLane()) { + didReadFromEntangledAsyncAction = true; + } + } else { + // This is an optimistic update. If the "revert" priority is + // sufficient, don't apply the update. Otherwise, apply the update, + // but leave it in the queue so it can be either reverted or + // rebased in a subsequent render. + if (isSubsetOfLanes(renderLanes, revertLane)) { + // The transition that this optimistic update is associated with + // has finished. Pretend the update doesn't exist by skipping + // over it. + update = update.next; // Check if this update is part of a pending async action. If so, + // we'll need to suspend until the action has finished, so that it's + // batched together with future updates in the same action. - while (currentChild.sibling !== null) { - currentChild = currentChild.sibling; - newChild = newChild.sibling = createWorkInProgress( - currentChild, - currentChild.pendingProps - ); - newChild.return = workInProgress; - } + if (revertLane === peekEntangledActionLane()) { + didReadFromEntangledAsyncAction = true; + } - newChild.sibling = null; - } // Reset a workInProgress child set to prepare it for a second pass. + continue; + } else { + var _clone2 = { + // Once we commit an optimistic update, we shouldn't uncommit it + // until the transition it is associated with has finished + // (represented by revertLane). Using NoLane here works because 0 + // is a subset of all bitmasks, so this will never be skipped by + // the check above. + lane: NoLane, + // Reuse the same revertLane so we know when the transition + // has finished. + revertLane: update.revertLane, + action: update.action, + hasEagerState: update.hasEagerState, + eagerState: update.eagerState, + next: null + }; - function resetChildFibers(workInProgress, lanes) { - var child = workInProgress.child; + if (newBaseQueueLast === null) { + newBaseQueueFirst = newBaseQueueLast = _clone2; + newBaseState = newState; + } else { + newBaseQueueLast = newBaseQueueLast.next = _clone2; + } // Update the remaining priority in the queue. + // TODO: Don't need to accumulate this. Instead, we can remove + // renderLanes from the original lanes. - while (child !== null) { - resetWorkInProgress(child, lanes); - child = child.sibling; - } - } - // TODO: This isn't being used yet, but it's intended to replace the - // InvisibleParentContext that is currently managed by SuspenseContext. + currentlyRenderingFiber$1.lanes = mergeLanes(currentlyRenderingFiber$1.lanes, revertLane); + markSkippedUpdateLanes(revertLane); + } + } // Process this update. - var currentTreeHiddenStackCursor = createCursor(null); - var prevEntangledRenderLanesCursor = createCursor(NoLanes); - function pushHiddenContext(fiber, context) { - var prevEntangledRenderLanes = getEntangledRenderLanes(); - push(prevEntangledRenderLanesCursor, prevEntangledRenderLanes, 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. - setEntangledRenderLanes( - mergeLanes(prevEntangledRenderLanes, 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(prevEntangledRenderLanesCursor, getEntangledRenderLanes(), fiber); - push( - currentTreeHiddenStackCursor, - currentTreeHiddenStackCursor.current, - fiber - ); - } - function popHiddenContext(fiber) { - // Restore the previous render lanes from the stack - setEntangledRenderLanes(prevEntangledRenderLanesCursor.current); - pop(currentTreeHiddenStackCursor, fiber); - pop(prevEntangledRenderLanesCursor, fiber); - } - function isCurrentTreeHidden() { - return currentTreeHiddenStackCursor.current !== null; - } + var action = update.action; - // suspends, i.e. it's the nearest `catch` block on the stack. + if (shouldDoubleInvokeUserFnsInHooksDEV) { + reducer(newState, action); + } - 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; + 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 { - var prevState = current.memoizedState; - - if (prevState !== null) { - // This boundary is showing a fallback in the current UI. - shellBoundary = handler; - } + newState = reducer(newState, action); } } - } - 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; + update = update.next; + } while (update !== null && update !== first); - if (current !== null) { - var prevState = current.memoizedState; + 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 (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; - } - } + + if (!objectIs(newState, hook.memoizedState)) { + markWorkInProgressReceivedUpdate(); // Check if this update is part of a pending async action. If so, we'll + // need to suspend until the action has finished, so that it's batched + // together with future updates in the same action. + // TODO: Once we support hooks inside useMemo (or an equivalent + // memoization boundary like Forget), hoist this logic so that it only + // suspends if the memo boundary produces a new value. + + if (didReadFromEntangledAsyncAction) { + var entangledActionThenable = peekEntangledActionThenable(); + + if (entangledActionThenable !== null) { + // TODO: Instead of the throwing the thenable directly, throw a + // special object like `use` does so we can detect if it's captured + // by userspace. + throw entangledActionThenable; } - } 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. + hook.memoizedState = newState; + hook.baseState = newBaseState; + hook.baseQueue = newBaseQueueLast; + queue.lastRenderedState = newState; + } - 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. + 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; + } - 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); - } + var dispatch = queue.dispatch; + return [hook.memoizedState, dispatch]; +} - // 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 rerenderReducer(reducer, initialArg, init) { + var hook = updateWorkInProgressHook(); + var queue = hook.queue; - function findFirstSuspended(row) { - var node = row; + if (queue === null) { + throw new Error('Should have a queue. This is likely a bug in React. Please file an issue.'); + } - while (node !== null) { - if (node.tag === SuspenseComponent) { - var state = node.memoizedState; + queue.lastRenderedReducer = reducer; // This is a re-render. Apply the new render phase updates to the previous + // work-in-progress hook. - if (state !== null) { - var dehydrated = state.dehydrated; + var dispatch = queue.dispatch; + var lastRenderPhaseUpdate = queue.pending; + var newState = hook.memoizedState; - if ( - dehydrated === null || - isSuspenseInstancePending() || - isSuspenseInstanceFallback() - ) { - return node; - } - } - } 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; - } - } else if (node.child !== null) { - node.child.return = node; - node = node.child; - continue; - } + if (lastRenderPhaseUpdate !== null) { + // The queue doesn't persist past this render pass. + queue.pending = null; + var firstRenderPhaseUpdate = lastRenderPhaseUpdate.next; + var update = firstRenderPhaseUpdate; - if (node === row) { - return null; - } + 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. - while (node.sibling === null) { - if (node.return === null || node.return === row) { - return null; - } - node = node.return; - } + if (!objectIs(newState, hook.memoizedState)) { + markWorkInProgressReceivedUpdate(); + } - node.sibling.return = node.return; - node = node.sibling; - } + 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. - return null; + if (hook.baseQueue === null) { + hook.baseState = newState; } - var NoFlags = - /* */ - 0; // Represents whether effect should fire. + queue.lastRenderedState = newState; + } - var HasEffect = - /* */ - 1; // Represents the phase in which the effect (not the clean-up) fires. + return [newState, dispatch]; +} - var Insertion = - /* */ - 2; - var Layout = - /* */ - 4; - var Passive = - /* */ - 8; +function mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) { + var fiber = currentlyRenderingFiber$1; + var hook = mountWorkInProgressHook(); + var nextSnapshot; - var didWarnAboutMismatchedHooksForComponent; - var didWarnUncachedGetSnapshot; - var didWarnAboutUseWrappedInTryCatch; - var didWarnAboutAsyncClientComponent; - var didWarnAboutUseFormState; + { + nextSnapshot = getSnapshot(); { - didWarnAboutMismatchedHooksForComponent = new Set(); - didWarnAboutUseWrappedInTryCatch = new Set(); - didWarnAboutAsyncClientComponent = new Set(); - didWarnAboutUseFormState = new Set(); - } // The effect "instance" is a shared object that remains the same for the entire - // lifetime of an effect. In Rust terms, a RefCell. We use it to store the - // "destroy" function that is returned from an effect, because that is stateful. - // The field is `undefined` if the effect is unmounted, or if the effect ran - // but is not stateful. We don't explicitly track whether the effect is mounted - // or unmounted because that can be inferred by the hiddenness of the fiber in - // the tree, i.e. whether there is a hidden Offscreen fiber above it. - // - // It's unfortunate that this is stored on a separate object, because it adds - // more memory per effect instance, but it's conceptually sound. I think there's - // likely a better data structure we could use for effects; perhaps just one - // array of effect instances per fiber. But I think this is OK for now despite - // the additional memory and we can follow up with performance - // optimizations later. - // These are set right before calling the component. - - var renderLanes = 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`. - - var didScheduleRenderPhaseUpdateDuringThisPass = false; - var shouldDoubleInvokeUserFnsInHooksDEV = false; // Counts the number of useId hooks in this component. - - 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. - - var globalClientIdCounter = 0; - var RE_RENDER_LIMIT = 25; // In DEV, this is the name of the currently executing primitive hook - - 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. - - 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 (!didWarnUncachedGetSnapshot) { + var cachedSnapshot = getSnapshot(); - if (hookTypesDev === null) { - hookTypesDev = [hookName]; - } else { - hookTypesDev.push(hookName); + if (!objectIs(nextSnapshot, cachedSnapshot)) { + error('The result of getSnapshot should be cached to avoid an infinite loop'); + + 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. - function updateHookTypesDev() { - { - var hookName = currentHookNameInDev; - if (hookTypesDev !== null) { - hookTypesUpdateIndexDev++; + var root = getWorkInProgressRoot(); - if (hookTypesDev[hookTypesUpdateIndexDev] !== hookName) { - warnOnHookMismatchInDev(hookName); - } - } - } + if (root === null) { + throw new Error('Expected a work-in-progress root. This is a bug in React. Please file an issue.'); } - 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 - ); - } - } + var rootRenderLanes = getWorkInProgressRootRenderLanes(); + + if (!includesBlockingLane(root, rootRenderLanes)) { + 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. - function warnOnHookMismatchInDev(currentHookName) { - { - var componentName = getComponentNameFromFiber( - currentlyRenderingFiber$1 - ); - - if (!didWarnAboutMismatchedHooksForComponent.has(componentName)) { - didWarnAboutMismatchedHooksForComponent.add(componentName); - - if (hookTypesDev !== null) { - var table = ""; - var secondColumnStart = 30; - - 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 - - while (row.length < secondColumnStart) { - row += " "; - } - row += newHookName + "\n"; - table += row; - } + hook.memoizedState = nextSnapshot; + var inst = { + value: nextSnapshot, + getSnapshot: getSnapshot + }; + hook.queue = inst; // Schedule an effect to subscribe to the store. - 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://react.dev/link/rules-of-hooks\n\n" + - " Previous render Next render\n" + - " ------------------------------------------------------\n" + - "%s" + - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - componentName, - table - ); - } - } - } - } + 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. - function warnOnUseFormStateInDev() { - { - var componentName = getComponentNameFromFiber( - currentlyRenderingFiber$1 - ); + fiber.flags |= Passive$1; + pushEffect(HasEffect | Passive, updateStoreInstance.bind(null, fiber, inst, nextSnapshot, getSnapshot), createEffectInstance(), null); + return nextSnapshot; +} - if (!didWarnAboutUseFormState.has(componentName)) { - didWarnAboutUseFormState.add(componentName); +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. - error( - "ReactDOM.useFormState has been renamed to React.useActionState. " + - "Please update %s to use React.useActionState.", - componentName - ); - } - } - } + var nextSnapshot; - function warnIfAsyncClientComponent(Component) { - { - // This dev-only check only works for detecting native async functions, - // not transpiled ones. There's also a prod check that we use to prevent - // async client components from crashing the app; the prod one works even - // for transpiled async functions. Neither mechanism is completely - // bulletproof but together they cover the most common cases. - var isAsyncFunction = // $FlowIgnore[method-unbinding] - Object.prototype.toString.call(Component) === - "[object AsyncFunction]"; - - if (isAsyncFunction) { - // Encountered an async Client Component. This is not yet supported. - var componentName = getComponentNameFromFiber( - currentlyRenderingFiber$1 - ); - - if (!didWarnAboutAsyncClientComponent.has(componentName)) { - didWarnAboutAsyncClientComponent.add(componentName); - - error( - "async/await is not yet supported in Client Components, only " + - "Server Components. This error is often caused by accidentally " + - "adding `'use client'` to a module that was originally written " + - "for the server." - ); - } - } - } - } + { + nextSnapshot = getSnapshot(); - 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://react.dev/link/invalid-hook-call for tips about how to debug and fix this problem." - ); - } + { + if (!didWarnUncachedGetSnapshot) { + var cachedSnapshot = getSnapshot(); - function areHookInputsEqual(nextDeps, prevDeps) { - { - if (ignorePreviousDependencies) { - // Only true when this component is being hot reloaded. - return false; + if (!objectIs(nextSnapshot, cachedSnapshot)) { + error('The result of getSnapshot should be cached to avoid an infinite loop'); + + didWarnUncachedGetSnapshot = true; } } + } + } - if (prevDeps === null) { - { - 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 - ); - } + var prevSnapshot = (currentHook || hook).memoizedState; + var snapshotChanged = !objectIs(prevSnapshot, nextSnapshot); - return false; - } + if (snapshotChanged) { + hook.memoizedState = nextSnapshot; + markWorkInProgressReceivedUpdate(); + } - { - // 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 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. - 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; - } + if (inst.getSnapshot !== getSnapshot || snapshotChanged || // Check if the subscribe 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), createEffectInstance(), 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. - return false; - } + var root = getWorkInProgressRoot(); - return true; + if (root === null) { + throw new Error('Expected a work-in-progress root. This is a bug in React. Please file an issue.'); } - function renderWithHooks( - current, - workInProgress, - Component, - props, - secondArg, - nextRenderLanes - ) { - renderLanes = nextRenderLanes; - currentlyRenderingFiber$1 = workInProgress; + if (!includesBlockingLane(root, renderLanes)) { + pushStoreConsistencyCheck(fiber, getSnapshot, nextSnapshot); + } + } - { - hookTypesDev = current !== null ? current._debugHookTypes : null; - hookTypesUpdateIndexDev = -1; // Used for hot reloading: + return nextSnapshot; +} - ignorePreviousDependencies = - current !== null && current.type !== workInProgress.type; - warnIfAsyncClientComponent(Component); - } +function pushStoreConsistencyCheck(fiber, getSnapshot, renderedSnapshot) { + fiber.flags |= StoreConsistency; + var check = { + getSnapshot: getSnapshot, + value: renderedSnapshot + }; + var componentUpdateQueue = currentlyRenderingFiber$1.updateQueue; + + if (componentUpdateQueue === null) { + componentUpdateQueue = createFunctionComponentUpdateQueue(); + currentlyRenderingFiber$1.updateQueue = componentUpdateQueue; + componentUpdateQueue.stores = [check]; + } else { + var stores = componentUpdateQueue.stores; + + if (stores === null) { + componentUpdateQueue.stores = [check]; + } else { + stores.push(check); + } + } +} - 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. +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. + + if (checkIfSnapshotChanged(inst)) { + // Force a re-render. + forceStoreRerender(fiber); + } +} - { - if (current !== null && current.memoizedState !== null) { - ReactSharedInternals.H = 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. - ReactSharedInternals.H = HooksDispatcherOnMountWithHookTypesInDEV; - } else { - ReactSharedInternals.H = 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. - - var shouldDoubleRenderDEV = - (workInProgress.mode & StrictLegacyMode) !== NoMode; - shouldDoubleInvokeUserFnsInHooksDEV = shouldDoubleRenderDEV; - var children = Component(props, secondArg); - shouldDoubleInvokeUserFnsInHooksDEV = false; // Check if there was a render phase update - - if (didScheduleRenderPhaseUpdateDuringThisPass) { - // Keep rendering until the component stabilizes (there are no more render - // phase updates). - children = renderWithHooksAgain( - workInProgress, - Component, - props, - secondArg - ); - } - - if (shouldDoubleRenderDEV) { - // In development, components are invoked twice to help detect side effects. - setIsStrictModeForDevtools(true); +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. - try { - children = renderWithHooksAgain( - workInProgress, - Component, - props, - secondArg - ); - } finally { - setIsStrictModeForDevtools(false); - } - } - finishRenderingHooks(current, workInProgress); - return children; - } + return subscribe(handleStoreChange); +} - function finishRenderingHooks(current, workInProgress, Component) { - { - workInProgress._debugHookTypes = hookTypesDev; - } // 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. +function checkIfSnapshotChanged(inst) { + var latestGetSnapshot = inst.getSnapshot; + var prevValue = inst.value; - ReactSharedInternals.H = ContextOnlyDispatcher; // 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. + try { + var nextValue = latestGetSnapshot(); + return !objectIs(prevValue, nextValue); + } catch (error) { + return true; + } +} - var didRenderTooFewHooks = - currentHook !== null && currentHook.next !== null; - renderLanes = NoLanes; - currentlyRenderingFiber$1 = null; - currentHook = null; - workInProgressHook = null; +function forceStoreRerender(fiber) { + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - { - 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( - "Internal React error: Expected static flag was missing. Please " + - "notify the React team." - ); - } - } - - didScheduleRenderPhaseUpdate = false; // This is reset by checkDidRenderIdHook - // localIdCounter = 0; - - thenableIndexCounter = 0; - thenableState = null; + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane); + } +} - if (didRenderTooFewHooks) { - throw new Error( - "Rendered fewer hooks than expected. This may be caused by an accidental " + - "early return statement." - ); - } +function mountStateImpl(initialState) { + var hook = mountWorkInProgressHook(); - { - if (checkIfUseWrappedInTryCatch()) { - var componentName = - getComponentNameFromFiber(workInProgress) || "Unknown"; - - if ( - !didWarnAboutUseWrappedInTryCatch.has(componentName) && // This warning also fires if you suspend with `use` inside an - // async component. Since we warn for that above, we'll silence this - // second warning by checking here. - !didWarnAboutAsyncClientComponent.has(componentName) - ) { - didWarnAboutUseWrappedInTryCatch.add(componentName); - - 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." - ); - } - } - } - } + if (typeof initialState === 'function') { + var initialStateInitializer = initialState; // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types - 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: + initialState = initialStateInitializer(); - ignorePreviousDependencies = - current !== null && current.type !== workInProgress.type; - } + if (shouldDoubleInvokeUserFnsInHooksDEV) { + setIsStrictModeForDevtools(true); // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types - var children = renderWithHooksAgain( - workInProgress, - Component, - props, - secondArg - ); - finishRenderingHooks(current, workInProgress); - return children; + initialStateInitializer(); + setIsStrictModeForDevtools(false); } + } - 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. - currentlyRenderingFiber$1 = workInProgress; - var numberOfReRenders = 0; - var children; + hook.memoizedState = hook.baseState = initialState; + var queue = { + pending: null, + lanes: NoLanes, + dispatch: null, + lastRenderedReducer: basicStateReducer, + lastRenderedState: initialState + }; + hook.queue = queue; + return hook; +} - 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; - } +function mountState(initialState) { + var hook = mountStateImpl(initialState); + var queue = hook.queue; + var dispatch = dispatchSetState.bind(null, currentlyRenderingFiber$1, queue); + queue.dispatch = dispatch; + return [hook.memoizedState, dispatch]; +} - thenableIndexCounter = 0; - didScheduleRenderPhaseUpdateDuringThisPass = false; +function updateState(initialState) { + return updateReducer(basicStateReducer); +} - if (numberOfReRenders >= RE_RENDER_LIMIT) { - throw new Error( - "Too many re-renders. React limits the number of renders to prevent " + - "an infinite loop." - ); - } +function rerenderState(initialState) { + return rerenderReducer(basicStateReducer); +} - numberOfReRenders += 1; +function mountOptimistic(passthrough, reducer) { + var hook = mountWorkInProgressHook(); + hook.memoizedState = hook.baseState = passthrough; + var queue = { + pending: null, + lanes: NoLanes, + dispatch: null, + // Optimistic state does not use the eager update optimization. + lastRenderedReducer: null, + lastRenderedState: null + }; + hook.queue = queue; // This is different than the normal setState function. + + var dispatch = dispatchOptimisticSetState.bind(null, currentlyRenderingFiber$1, true, queue); + queue.dispatch = dispatch; + return [passthrough, dispatch]; +} - { - // 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 updateOptimistic(passthrough, reducer) { + var hook = updateWorkInProgressHook(); + return updateOptimisticImpl(hook, currentHook, passthrough, reducer); +} - currentHook = null; - workInProgressHook = null; - workInProgress.updateQueue = null; +function updateOptimisticImpl(hook, current, passthrough, reducer) { + // Optimistic updates are always rebased on top of the latest value passed in + // as an argument. It's called a passthrough because if there are no pending + // updates, it will be returned as-is. + // + // Reset the base state to the passthrough. Future updates will be applied + // on top of this. + hook.baseState = passthrough; // If a reducer is not provided, default to the same one used by useState. + + var resolvedReducer = typeof reducer === 'function' ? reducer : basicStateReducer; + return updateReducerImpl(hook, currentHook, resolvedReducer); +} - { - // Also validate hook order for cascading updates. - hookTypesUpdateIndexDev = -1; - } +function rerenderOptimistic(passthrough, reducer) { + // Unlike useState, useOptimistic doesn't support render phase updates. + // Also unlike useState, we need to replay all pending updates again in case + // the passthrough value changed. + // + // So instead of a forked re-render implementation that knows how to handle + // render phase udpates, we can use the same implementation as during a + // regular mount or update. + var hook = updateWorkInProgressHook(); + + if (currentHook !== null) { + // This is an update. Process the update queue. + return updateOptimisticImpl(hook, currentHook, passthrough, reducer); + } // This is a mount. No updates to process. + // Reset the base state to the passthrough. Future updates will be applied + // on top of this. + + + hook.baseState = passthrough; + var dispatch = hook.queue.dispatch; + return [passthrough, dispatch]; +} // useActionState actions run sequentially, because each action receives the +// previous state as an argument. We store pending actions on a queue. + + +function dispatchActionState(fiber, actionQueue, setPendingState, setState, payload) { + if (isRenderPhaseUpdate(fiber)) { + throw new Error('Cannot update form state while rendering.'); + } + + var last = actionQueue.pending; + + if (last === null) { + // There are no pending actions; this is the first one. We can run + // it immediately. + var newLast = { + payload: payload, + next: null // circular - ReactSharedInternals.H = HooksDispatcherOnRerenderInDEV; - children = Component(props, secondArg); - } while (didScheduleRenderPhaseUpdateDuringThisPass); + }; + newLast.next = actionQueue.pending = newLast; + runActionStateAction(actionQueue, setPendingState, setState, payload); + } else { + // There's already an action running. Add to the queue. + var first = last.next; + var _newLast = { + payload: payload, + next: first + }; + actionQueue.pending = last.next = _newLast; + } +} - return children; - } +function runActionStateAction(actionQueue, setPendingState, setState, payload) { + var action = actionQueue.action; + var prevState = actionQueue.state; // This is a fork of startTransition - function renderTransitionAwareHostComponentWithHooks( - current, - workInProgress, - lanes - ) { - if (!enableAsyncActions) { - throw new Error("Not implemented."); - } + var prevTransition = ReactSharedInternals.T; + var currentTransition = { + _callbacks: new Set() + }; + ReactSharedInternals.T = currentTransition; - return renderWithHooks( - current, - workInProgress, - TransitionAwareHostComponent, - null, - null, - lanes - ); - } - function TransitionAwareHostComponent() { - if (!enableAsyncActions) { - throw new Error("Not implemented."); - } + { + ReactSharedInternals.T._updatedFibers = new Set(); + } // Optimistically update the pending state, similar to useTransition. + // This will be reverted automatically when all actions are finished. - var dispatcher = ReactSharedInternals.H; - var _dispatcher$useState = dispatcher.useState(), - maybeThenable = _dispatcher$useState[0]; + setPendingState(true); - var nextState; + try { + var returnValue = action(prevState, payload); - if (typeof maybeThenable.then === "function") { - var thenable = maybeThenable; - nextState = useThenable(thenable); - } else { - var status = maybeThenable; - nextState = status; - } // The "reset state" is an object. If it changes, that means something - // requested that we reset the form. + if (returnValue !== null && typeof returnValue === 'object' && // $FlowFixMe[method-unbinding] + typeof returnValue.then === 'function') { + var thenable = returnValue; + notifyTransitionCallbacks(currentTransition, thenable); // Attach a listener to read the return state of the action. As soon as + // this resolves, we can run the next action in the sequence. - var _dispatcher$useState2 = dispatcher.useState(), - nextResetState = _dispatcher$useState2[0]; + thenable.then(function (nextState) { + actionQueue.state = nextState; + finishRunningActionStateAction(actionQueue, setPendingState, setState); + }, function () { + return finishRunningActionStateAction(actionQueue, setPendingState, setState); + }); + setState(thenable); + } else { + setState(returnValue); + var nextState = returnValue; + actionQueue.state = nextState; + finishRunningActionStateAction(actionQueue, setPendingState, setState); + } + } catch (error) { + // This is a trick to get the `useActionState` hook to rethrow the error. + // When it unwraps the thenable with the `use` algorithm, the error + // will be thrown. + var rejectedThenable = { + then: function () {}, + status: 'rejected', + reason: error // $FlowFixMe: Not sure why this doesn't work - var prevResetState = - currentHook !== null ? currentHook.memoizedState : null; + }; + setState(rejectedThenable); + finishRunningActionStateAction(actionQueue, setPendingState, setState); + } finally { + ReactSharedInternals.T = prevTransition; - if (prevResetState !== nextResetState) { - // Schedule a form reset - currentlyRenderingFiber$1.flags |= FormReset; - } + { + if (prevTransition === null && currentTransition._updatedFibers) { + var updatedFibersCount = currentTransition._updatedFibers.size; - return nextState; - } - 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). + currentTransition._updatedFibers.clear(); - if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { - workInProgress.flags &= ~( - MountPassiveDev | - MountLayoutDev | - Passive$1 | - Update - ); - } else { - workInProgress.flags &= ~(Passive$1 | Update); + 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.'); + } } - - 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. - currentlyRenderingFiber$1 = null; // 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. - - ReactSharedInternals.H = ContextOnlyDispatcher; - } - function resetHooksOnUnwind(workInProgress) { - 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 = workInProgress.memoizedState; - - while (hook !== null) { - var queue = hook.queue; - - if (queue !== null) { - queue.pending = null; - } - - hook = hook.next; - } + } +} - didScheduleRenderPhaseUpdate = false; - } +function finishRunningActionStateAction(actionQueue, setPendingState, setState) { + // The action finished running. Pop it from the queue and run the next pending + // action, if there are any. + var last = actionQueue.pending; - renderLanes = NoLanes; - currentlyRenderingFiber$1 = null; - currentHook = null; - workInProgressHook = null; + if (last !== null) { + var first = last.next; - { - hookTypesDev = null; - hookTypesUpdateIndexDev = -1; - currentHookNameInDev = null; - } + if (first === last) { + // This was the last action in the queue. + actionQueue.pending = null; + } else { + // Remove the first node from the circular queue. + var next = first.next; + last.next = next; // Run the next action. - didScheduleRenderPhaseUpdateDuringThisPass = false; - thenableIndexCounter = 0; - thenableState = null; + runActionStateAction(actionQueue, setPendingState, setState, next.payload); } + } +} - function mountWorkInProgressHook() { - var hook = { - memoizedState: null, - baseState: null, - baseQueue: null, - queue: null, - next: null - }; +function actionStateReducer(oldState, newState) { + return newState; +} - 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; - } +function mountActionState(action, initialStateProp, permalink) { + var initialState = initialStateProp; + // the `use` algorithm during render. + + + var stateHook = mountWorkInProgressHook(); + stateHook.memoizedState = stateHook.baseState = initialState; // TODO: Typing this "correctly" results in recursion limit errors + // const stateQueue: UpdateQueue, S | Awaited> = { + + var stateQueue = { + pending: null, + lanes: NoLanes, + dispatch: null, + lastRenderedReducer: actionStateReducer, + lastRenderedState: initialState + }; + stateHook.queue = stateQueue; + var setState = dispatchSetState.bind(null, currentlyRenderingFiber$1, stateQueue); + stateQueue.dispatch = setState; // Pending state. This is used to store the pending state of the action. + // Tracked optimistically, like a transition pending state. + + var pendingStateHook = mountStateImpl(false); + var setPendingState = dispatchOptimisticSetState.bind(null, currentlyRenderingFiber$1, false, pendingStateHook.queue); // Action queue hook. This is used to queue pending actions. The queue is + // shared between all instances of the hook. Similar to a regular state queue, + // but different because the actions are run sequentially, and they run in + // an event instead of during render. + + var actionQueueHook = mountWorkInProgressHook(); + var actionQueue = { + state: initialState, + dispatch: null, + // circular + action: action, + pending: null + }; + actionQueueHook.queue = actionQueue; + var dispatch = dispatchActionState.bind(null, currentlyRenderingFiber$1, actionQueue, setPendingState, setState); + actionQueue.dispatch = dispatch; // Stash the action function on the memoized state of the hook. We'll use this + // to detect when the action function changes so we can update it in + // an effect. + + actionQueueHook.memoizedState = action; + return [initialState, dispatch, false]; +} - return workInProgressHook; - } +function updateActionState(action, initialState, permalink) { + var stateHook = updateWorkInProgressHook(); + var currentStateHook = currentHook; + return updateActionStateImpl(stateHook, currentStateHook, action); +} - 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 updateActionStateImpl(stateHook, currentStateHook, action, initialState, permalink) { + var _updateReducerImpl = updateReducerImpl(stateHook, currentStateHook, actionStateReducer), + actionResult = _updateReducerImpl[0]; - if (currentHook === null) { - var current = currentlyRenderingFiber$1.alternate; + var _updateState = updateState(), + isPending = _updateState[0]; // This will suspend until the action finishes. - if (current !== null) { - nextCurrentHook = current.memoizedState; - } else { - nextCurrentHook = null; - } - } else { - nextCurrentHook = currentHook.next; - } - var nextWorkInProgressHook; + var state = typeof actionResult === 'object' && actionResult !== null && // $FlowFixMe[method-unbinding] + typeof actionResult.then === 'function' ? useThenable(actionResult) : actionResult; + var actionQueueHook = updateWorkInProgressHook(); + var actionQueue = actionQueueHook.queue; + var dispatch = actionQueue.dispatch; // Check if a new action was passed. If so, update it in an effect. - if (workInProgressHook === null) { - nextWorkInProgressHook = currentlyRenderingFiber$1.memoizedState; - } else { - nextWorkInProgressHook = workInProgressHook.next; - } + var prevAction = actionQueueHook.memoizedState; - 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 (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." - ); - } - } + if (action !== prevAction) { + currentlyRenderingFiber$1.flags |= Passive$1; + pushEffect(HasEffect | Passive, actionStateActionEffect.bind(null, actionQueue, action), createEffectInstance(), null); + } + + return [state, dispatch, isPending]; +} - currentHook = nextCurrentHook; - var newHook = { - memoizedState: currentHook.memoizedState, - baseState: currentHook.baseState, - baseQueue: currentHook.baseQueue, - queue: currentHook.queue, - next: null - }; +function actionStateActionEffect(actionQueue, action) { + actionQueue.action = action; +} - 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; - } - } +function rerenderActionState(action, initialState, permalink) { + // Unlike useState, useActionState doesn't support render phase updates. + // Also unlike useState, we need to replay all pending updates again in case + // the passthrough value changed. + // + // So instead of a forked re-render implementation that knows how to handle + // render phase udpates, we can use the same implementation as during a + // regular mount or update. + var stateHook = updateWorkInProgressHook(); + var currentStateHook = currentHook; + + if (currentStateHook !== null) { + // This is an update. Process the update queue. + return updateActionStateImpl(stateHook, currentStateHook, action); + } + + updateWorkInProgressHook(); // State + // This is a mount. No updates to process. + + var state = stateHook.memoizedState; + var actionQueueHook = updateWorkInProgressHook(); + var actionQueue = actionQueueHook.queue; + var dispatch = actionQueue.dispatch; // This may have changed during the rerender. + + actionQueueHook.memoizedState = action; // For mount, pending is always false. + + return [state, dispatch, false]; +} - 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. +function pushEffect(tag, create, inst, deps) { + var effect = { + tag: tag, + create: create, + inst: inst, + 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; +} - var createFunctionComponentUpdateQueue; +function createEffectInstance() { + return { + destroy: undefined + }; +} - { - createFunctionComponentUpdateQueue = function () { - return { - lastEffect: null, - events: null, - stores: null, - memoCache: null - }; - }; - } +function mountRef(initialValue) { + var hook = mountWorkInProgressHook(); + var ref = { + current: initialValue + }; + hook.memoizedState = ref; + return ref; +} - function useThenable(thenable) { - // Track the position of the thenable within this fiber. - var index = thenableIndexCounter; - thenableIndexCounter += 1; +function updateRef(initialValue) { + var hook = updateWorkInProgressHook(); + return hook.memoizedState; +} - if (thenableState === null) { - thenableState = createThenableState(); - } +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, createEffectInstance(), nextDeps); +} - var result = trackUsedThenable(thenableState, thenable, index); +function updateEffectImpl(fiberFlags, hookFlags, create, deps) { + var hook = updateWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + var effect = hook.memoizedState; + var inst = effect.inst; // currentHook is null on initial mount when rerendering after a render phase + // state update or for strict mode. - 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. - { - ReactSharedInternals.H = HooksDispatcherOnMountInDEV; - } - } + if (currentHook !== null) { + if (nextDeps !== null) { + var prevEffect = currentHook.memoizedState; + var prevDeps = prevEffect.deps; - return result; + if (areHookInputsEqual(nextDeps, prevDeps)) { + hook.memoizedState = pushEffect(hookFlags, create, inst, nextDeps); + return; + } } + } - function use(usable) { - if (usable !== null && typeof usable === "object") { - // $FlowFixMe[method-unbinding] - if (typeof usable.then === "function") { - // This is a thenable. - var thenable = usable; - return useThenable(thenable); - } else if (usable.$$typeof === REACT_CONTEXT_TYPE) { - var context = usable; - return readContext(context); - } - } // eslint-disable-next-line react-internal/safe-string-coercion + currentlyRenderingFiber$1.flags |= fiberFlags; + hook.memoizedState = pushEffect(HasEffect | hookFlags, create, inst, nextDeps); +} - throw new Error( - "An unsupported type was passed to use(): " + String(usable) - ); - } +function mountEffect(create, deps) { + if ((currentlyRenderingFiber$1.mode & StrictEffectsMode) !== NoMode && (currentlyRenderingFiber$1.mode & NoStrictPassiveEffectsMode) === NoMode) { + mountEffectImpl(MountPassiveDev | Passive$1 | PassiveStatic, Passive, create, deps); + } else { + mountEffectImpl(Passive$1 | PassiveStatic, Passive, create, deps); + } +} - function useMemoCache(size) { - var memoCache = null; // Fast-path, load memo cache from wip fiber if already prepared +function updateEffect(create, deps) { + updateEffectImpl(Passive$1, Passive, create, deps); +} - var updateQueue = currentlyRenderingFiber$1.updateQueue; +function mountInsertionEffect(create, deps) { + mountEffectImpl(Update, Insertion, create, deps); +} - if (updateQueue !== null) { - memoCache = updateQueue.memoCache; - } // Otherwise clone from the current fiber +function updateInsertionEffect(create, deps) { + return updateEffectImpl(Update, Insertion, create, deps); +} - if (memoCache == null) { - var current = currentlyRenderingFiber$1.alternate; +function mountLayoutEffect(create, deps) { + var fiberFlags = Update | LayoutStatic; - if (current !== null) { - var currentUpdateQueue = current.updateQueue; + if ((currentlyRenderingFiber$1.mode & StrictEffectsMode) !== NoMode) { + fiberFlags |= MountLayoutDev; + } - if (currentUpdateQueue !== null) { - var currentMemoCache = currentUpdateQueue.memoCache; + return mountEffectImpl(fiberFlags, Layout, create, deps); +} - 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 +function updateLayoutEffect(create, deps) { + return updateEffectImpl(Update, Layout, create, deps); +} - if (memoCache == null) { - memoCache = { - data: [], - index: 0 - }; - } +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 (updateQueue === null) { - updateQueue = createFunctionComponentUpdateQueue(); - currentlyRenderingFiber$1.updateQueue = updateQueue; + { + 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(', ') + '}'); } + } - updateQueue.memoCache = memoCache; - var data = memoCache.data[memoCache.index]; - - if (data === undefined) { - data = memoCache.data[memoCache.index] = new Array(size); + var _inst = create(); - 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 - ); - } - } + refObject.current = _inst; + return function () { + refObject.current = null; + }; + } +} - memoCache.index++; - return data; +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? - function basicStateReducer(state, action) { - // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types - return typeof action === "function" ? action(state) : action; - } - function mountReducer(reducer, initialArg, init) { - var hook = mountWorkInProgressHook(); - var initialState; + var effectDeps = deps !== null && deps !== undefined ? deps.concat([ref]) : null; + var fiberFlags = Update | LayoutStatic; - if (init !== undefined) { - initialState = init(initialArg); + if ((currentlyRenderingFiber$1.mode & StrictEffectsMode) !== NoMode) { + fiberFlags |= MountLayoutDev; + } - if (shouldDoubleInvokeUserFnsInHooksDEV) { - setIsStrictModeForDevtools(true); - init(initialArg); - setIsStrictModeForDevtools(false); - } - } else { - initialState = initialArg; - } + mountEffectImpl(fiberFlags, Layout, imperativeHandleEffect.bind(null, create, ref), effectDeps); +} - 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]; +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? - function updateReducer(reducer, initialArg, init) { - var hook = updateWorkInProgressHook(); - return updateReducerImpl(hook, currentHook, reducer); - } - function updateReducerImpl(hook, current, reducer) { - var queue = hook.queue; + var effectDeps = deps !== null && deps !== undefined ? deps.concat([ref]) : null; + updateEffectImpl(Update, Layout, imperativeHandleEffect.bind(null, create, ref), effectDeps); +} - if (queue === null) { - throw new Error( - "Should have a queue. This is likely a bug in React. Please file an issue." - ); - } +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. +} - queue.lastRenderedReducer = reducer; // The last rebase update that is NOT part of the base state. +var updateDebugValue = mountDebugValue; - var baseQueue = hook.baseQueue; // The last pending update that hasn't been processed yet. +function mountCallback(callback, deps) { + var hook = mountWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + hook.memoizedState = [callback, nextDeps]; + return callback; +} - var pendingQueue = queue.pending; +function updateCallback(callback, deps) { + var hook = updateWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + var prevState = hook.memoizedState; - 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 (nextDeps !== null) { + var prevDeps = prevState[1]; - { - 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 (areHookInputsEqual(nextDeps, prevDeps)) { + return prevState[0]; + } + } - current.baseQueue = baseQueue = pendingQueue; - queue.pending = null; - } + hook.memoizedState = [callback, nextDeps]; + return callback; +} - var baseState = hook.baseState; +function mountMemo(nextCreate, deps) { + var hook = mountWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + var nextValue = nextCreate(); - if (baseQueue === null) { - // If there are no pending updates, then the memoized state should be the - // same as the base state. Currently these only diverge in the case of - // useOptimistic, because useOptimistic accepts a new baseState on - // every render. - hook.memoizedState = baseState; // We don't need to call markWorkInProgressReceivedUpdate because - // baseState is derived from other reactive values. - } else { - // We have a queue to process. - var first = baseQueue.next; - var newState = baseState; - var newBaseState = null; - var newBaseQueueFirst = null; - var newBaseQueueLast = null; - var update = first; - var didReadFromEntangledAsyncAction = false; + if (shouldDoubleInvokeUserFnsInHooksDEV) { + setIsStrictModeForDevtools(true); + nextCreate(); + setIsStrictModeForDevtools(false); + } - 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); - - 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, - revertLane: update.revertLane, - action: update.action, - hasEagerState: update.hasEagerState, - eagerState: update.eagerState, - next: null - }; + hook.memoizedState = [nextValue, nextDeps]; + return nextValue; +} - 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. +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. - currentlyRenderingFiber$1.lanes = mergeLanes( - currentlyRenderingFiber$1.lanes, - updateLane - ); - markSkippedUpdateLanes(updateLane); - } else { - // This update does have sufficient priority. - // Check if this is an optimistic update. - var revertLane = update.revertLane; - - if (!enableAsyncActions || revertLane === NoLane) { - // This is not an optimistic update, and we're going to apply it now. - // But, if there were earlier updates that were skipped, we need to - // leave this update in the queue so it can be rebased later. - 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, - revertLane: NoLane, - action: update.action, - hasEagerState: update.hasEagerState, - eagerState: update.eagerState, - next: null - }; - newBaseQueueLast = newBaseQueueLast.next = _clone; - } // Check if this update is part of a pending async action. If so, - // we'll need to suspend until the action has finished, so that it's - // batched together with future updates in the same action. - - if (updateLane === peekEntangledActionLane()) { - didReadFromEntangledAsyncAction = true; - } - } else { - // This is an optimistic update. If the "revert" priority is - // sufficient, don't apply the update. Otherwise, apply the update, - // but leave it in the queue so it can be either reverted or - // rebased in a subsequent render. - if (isSubsetOfLanes(renderLanes, revertLane)) { - // The transition that this optimistic update is associated with - // has finished. Pretend the update doesn't exist by skipping - // over it. - update = update.next; // Check if this update is part of a pending async action. If so, - // we'll need to suspend until the action has finished, so that it's - // batched together with future updates in the same action. - - if (revertLane === peekEntangledActionLane()) { - didReadFromEntangledAsyncAction = true; - } + if (nextDeps !== null) { + var prevDeps = prevState[1]; - continue; - } else { - var _clone2 = { - // Once we commit an optimistic update, we shouldn't uncommit it - // until the transition it is associated with has finished - // (represented by revertLane). Using NoLane here works because 0 - // is a subset of all bitmasks, so this will never be skipped by - // the check above. - lane: NoLane, - // Reuse the same revertLane so we know when the transition - // has finished. - revertLane: update.revertLane, - action: update.action, - hasEagerState: update.hasEagerState, - eagerState: update.eagerState, - next: null - }; - - if (newBaseQueueLast === null) { - newBaseQueueFirst = newBaseQueueLast = _clone2; - newBaseState = newState; - } else { - newBaseQueueLast = newBaseQueueLast.next = _clone2; - } // 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, - revertLane - ); - markSkippedUpdateLanes(revertLane); - } - } // Process this update. + if (areHookInputsEqual(nextDeps, prevDeps)) { + return prevState[0]; + } + } - var action = update.action; + var nextValue = nextCreate(); - if (shouldDoubleInvokeUserFnsInHooksDEV) { - reducer(newState, action); - } + if (shouldDoubleInvokeUserFnsInHooksDEV) { + setIsStrictModeForDevtools(true); + nextCreate(); + setIsStrictModeForDevtools(false); + } - 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); - } - } + hook.memoizedState = [nextValue, nextDeps]; + return nextValue; +} - update = update.next; - } while (update !== null && update !== first); +function mountDeferredValue(value, initialValue) { + var hook = mountWorkInProgressHook(); + return mountDeferredValueImpl(hook, value, initialValue); +} - 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(); // Check if this update is part of a pending async action. If so, we'll - // need to suspend until the action has finished, so that it's batched - // together with future updates in the same action. - // TODO: Once we support hooks inside useMemo (or an equivalent - // memoization boundary like Forget), hoist this logic so that it only - // suspends if the memo boundary produces a new value. - - if (didReadFromEntangledAsyncAction) { - var entangledActionThenable = peekEntangledActionThenable(); - - if (entangledActionThenable !== null) { - // TODO: Instead of the throwing the thenable directly, throw a - // special object like `use` does so we can detect if it's captured - // by userspace. - throw entangledActionThenable; - } - } - } +function updateDeferredValue(value, initialValue) { + var hook = updateWorkInProgressHook(); + var resolvedCurrentHook = currentHook; + var prevValue = resolvedCurrentHook.memoizedState; + return updateDeferredValueImpl(hook, prevValue, value, initialValue); +} - hook.memoizedState = newState; - hook.baseState = newBaseState; - hook.baseQueue = newBaseQueueLast; - queue.lastRenderedState = newState; - } +function rerenderDeferredValue(value, initialValue) { + var hook = updateWorkInProgressHook(); + + if (currentHook === null) { + // This is a rerender during a mount. + return mountDeferredValueImpl(hook, value, initialValue); + } else { + // This is a rerender during an update. + var prevValue = currentHook.memoizedState; + return updateDeferredValueImpl(hook, prevValue, value, initialValue); + } +} + +function mountDeferredValueImpl(hook, value, initialValue) { + if (// When `initialValue` is provided, we defer the initial render even if the + // current render is not synchronous. + initialValue !== undefined && // However, to avoid waterfalls, we do not defer if this render + // was itself spawned by an earlier useDeferredValue. Check if DeferredLane + // is part of the render lanes. + !includesSomeLane(renderLanes, DeferredLane)) { + // Render with the initial value + hook.memoizedState = initialValue; // Schedule a deferred render to switch to the final value. + + var deferredLane = requestDeferredLane(); + currentlyRenderingFiber$1.lanes = mergeLanes(currentlyRenderingFiber$1.lanes, deferredLane); + markSkippedUpdateLanes(deferredLane); + return initialValue; + } else { + hook.memoizedState = value; + return value; + } +} - 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; +function updateDeferredValueImpl(hook, prevValue, value, initialValue) { + if (objectIs(value, prevValue)) { + // The incoming value is referentially identical to the currently rendered + // value, so we can bail out quickly. + return value; + } else { + // Received a new value that's different from the current value. + // Check if we're inside a hidden tree + if (isCurrentTreeHidden()) { + // Revealing a prerendered tree is considered the same as mounting new + // one, so we reuse the "mount" path in this case. + var resultValue = mountDeferredValueImpl(hook, value, initialValue); // Unlike during an actual mount, we need to mark this as an update if + // the value changed. + + if (!objectIs(resultValue, prevValue)) { + markWorkInProgressReceivedUpdate(); } - var dispatch = queue.dispatch; - return [hook.memoizedState, dispatch]; + return resultValue; } - function rerenderReducer(reducer, initialArg, init) { - var hook = updateWorkInProgressHook(); - var queue = hook.queue; + var shouldDeferValue = !includesOnlyNonUrgentLanes(renderLanes); - if (queue === null) { - throw new Error( - "Should have a queue. This is likely a bug in React. Please file an issue." - ); - } + if (shouldDeferValue) { + // This is an urgent update. Since the value has changed, keep using the + // previous value and spawn a deferred render to update it later. + // Schedule a deferred render + var deferredLane = requestDeferredLane(); + currentlyRenderingFiber$1.lanes = mergeLanes(currentlyRenderingFiber$1.lanes, deferredLane); + markSkippedUpdateLanes(deferredLane); // Reuse the previous value. We do not need to mark this as an update, + // because we did not render a new value. - queue.lastRenderedReducer = reducer; // This is a re-render. Apply the new render phase updates to the previous - // work-in-progress hook. + 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. + // Mark this as an update to prevent the fiber from bailing out. + markWorkInProgressReceivedUpdate(); + hook.memoizedState = value; + return value; + } + } +} - var dispatch = queue.dispatch; - var lastRenderPhaseUpdate = queue.pending; - var newState = hook.memoizedState; +function startTransition(fiber, queue, pendingState, finishedState, callback, options) { + var previousPriority = getCurrentUpdatePriority(); + setCurrentUpdatePriority(higherEventPriority(previousPriority, ContinuousEventPriority)); + var prevTransition = ReactSharedInternals.T; + var currentTransition = { + _callbacks: new Set() + }; + + if (enableAsyncActions) { + // We don't really need to use an optimistic update here, because we + // schedule a second "revert" update below (which we use to suspend the + // transition until the async action scope has finished). But we'll use an + // optimistic update anyway to make it less likely the behavior accidentally + // diverges; for example, both an optimistic update and this one should + // share the same lane. + ReactSharedInternals.T = currentTransition; + dispatchOptimisticSetState(fiber, false, queue, pendingState); + } else { + ReactSharedInternals.T = null; + dispatchSetState(fiber, queue, pendingState); + ReactSharedInternals.T = currentTransition; + } + + { + currentTransition._updatedFibers = new Set(); + } + + try { + if (enableAsyncActions) { + var returnValue = callback(); // Check if we're inside an async action scope. If so, we'll entangle + // this new action with the existing scope. + // + // If we're not already inside an async action scope, and this action is + // async, then we'll create a new async scope. + // + // In the async case, the resulting render will suspend until the async + // action scope has finished. - if (lastRenderPhaseUpdate !== null) { - // The queue doesn't persist past this render pass. - queue.pending = null; - var firstRenderPhaseUpdate = lastRenderPhaseUpdate.next; - var update = firstRenderPhaseUpdate; + if (returnValue !== null && typeof returnValue === 'object' && typeof returnValue.then === 'function') { + var thenable = returnValue; + notifyTransitionCallbacks(currentTransition, thenable); // Create a thenable that resolves to `finishedState` once the async + // action has completed. - 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 thenableForFinishedState = chainThenableValue(thenable, finishedState); + dispatchSetState(fiber, queue, thenableForFinishedState); + } else { + dispatchSetState(fiber, queue, finishedState); + } + } else { + // Async actions are not enabled. + dispatchSetState(fiber, queue, finishedState); + callback(); + } + } catch (error) { + if (enableAsyncActions) { + // This is a trick to get the `useTransition` hook to rethrow the error. + // When it unwraps the thenable with the `use` algorithm, the error + // will be thrown. + var rejectedThenable = { + then: function () {}, + status: 'rejected', + reason: error + }; + dispatchSetState(fiber, queue, rejectedThenable); + } else { + // The error rethrowing behavior is only enabled when the async actions + // feature is on, even for sync actions. + throw error; + } + } finally { + setCurrentUpdatePriority(previousPriority); + ReactSharedInternals.T = prevTransition; - if (!objectIs(newState, hook.memoizedState)) { - markWorkInProgressReceivedUpdate(); - } + { + if (prevTransition === null && currentTransition._updatedFibers) { + var updatedFibersCount = currentTransition._updatedFibers.size; - 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. + currentTransition._updatedFibers.clear(); - if (hook.baseQueue === null) { - hook.baseState = newState; + 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.'); } - - queue.lastRenderedState = newState; } - - return [newState, dispatch]; } + } +} - function mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) { - var fiber = currentlyRenderingFiber$1; - var hook = mountWorkInProgressHook(); - var nextSnapshot; - - { - nextSnapshot = getSnapshot(); +function mountTransition() { + var stateHook = mountStateImpl(false); // The `start` method never changes. - { - if (!didWarnUncachedGetSnapshot) { - var cachedSnapshot = getSnapshot(); + var start = startTransition.bind(null, currentlyRenderingFiber$1, stateHook.queue, true, false); + var hook = mountWorkInProgressHook(); + hook.memoizedState = start; + return [false, start]; +} - if (!objectIs(nextSnapshot, cachedSnapshot)) { - error( - "The result of getSnapshot should be cached to avoid an infinite loop" - ); +function updateTransition() { + var _updateState2 = updateState(), + booleanOrThenable = _updateState2[0]; - 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 hook = updateWorkInProgressHook(); + var start = hook.memoizedState; + var isPending = typeof booleanOrThenable === 'boolean' ? booleanOrThenable : // This will suspend until the async action scope has finished. + useThenable(booleanOrThenable); + return [isPending, start]; +} - var root = getWorkInProgressRoot(); +function rerenderTransition() { + var _rerenderState = rerenderState(), + booleanOrThenable = _rerenderState[0]; - if (root === null) { - throw new Error( - "Expected a work-in-progress root. This is a bug in React. Please file an issue." - ); - } + var hook = updateWorkInProgressHook(); + var start = hook.memoizedState; + var isPending = typeof booleanOrThenable === 'boolean' ? booleanOrThenable : // This will suspend until the async action scope has finished. + useThenable(booleanOrThenable); + return [isPending, start]; +} - var rootRenderLanes = getWorkInProgressRootRenderLanes(); +function useHostTransitionStatus() { + if (!enableAsyncActions) { + throw new Error('Not implemented.'); + } - if (!includesBlockingLane(root, rootRenderLanes)) { - 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. + var status = readContext(HostTransitionContext); + return status !== null ? status : NotPendingTransition; +} - 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. - - fiber.flags |= Passive$1; - pushEffect( - HasEffect | Passive, - updateStoreInstance.bind(null, fiber, inst, nextSnapshot, getSnapshot), - createEffectInstance(), - 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; +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; + + { + // Use a lowercase r prefix for client-generated ids. + var globalClientId = globalClientIdCounter++; + id = ':' + identifierPrefix + 'r' + globalClientId.toString(32) + ':'; + } + + hook.memoizedState = id; + return id; +} - { - nextSnapshot = getSnapshot(); +function updateId() { + var hook = updateWorkInProgressHook(); + var id = hook.memoizedState; + return id; +} - { - if (!didWarnUncachedGetSnapshot) { - var cachedSnapshot = getSnapshot(); +function mountRefresh() { + var hook = mountWorkInProgressHook(); + var refresh = hook.memoizedState = refreshCache.bind(null, currentlyRenderingFiber$1); + return refresh; +} - if (!objectIs(nextSnapshot, cachedSnapshot)) { - error( - "The result of getSnapshot should be cached to avoid an infinite loop" - ); +function updateRefresh() { + var hook = updateWorkInProgressHook(); + return hook.memoizedState; +} - didWarnUncachedGetSnapshot = true; - } - } - } - } +function refreshCache(fiber, seedKey, seedValue) { + // TODO: Consider warning if the refresh is at discrete priority, or if we + // otherwise suspect that it wasn't batched properly. - var prevSnapshot = (currentHook || hook).memoizedState; - var snapshotChanged = !objectIs(prevSnapshot, nextSnapshot); - if (snapshotChanged) { - hook.memoizedState = nextSnapshot; - markWorkInProgressReceivedUpdate(); - } + var provider = fiber.return; - 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. - - if ( - inst.getSnapshot !== getSnapshot || - snapshotChanged || // Check if the subscribe 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 - ), - createEffectInstance(), - 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 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)) { - pushStoreConsistencyCheck(fiber, getSnapshot, nextSnapshot); - } - } - - return nextSnapshot; - } - - function pushStoreConsistencyCheck(fiber, getSnapshot, renderedSnapshot) { - fiber.flags |= StoreConsistency; - var check = { - getSnapshot: getSnapshot, - value: renderedSnapshot - }; - var componentUpdateQueue = currentlyRenderingFiber$1.updateQueue; + while (provider !== null) { + switch (provider.tag) { + case CacheComponent: + case HostRoot: + { + // Schedule an update on the cache boundary to trigger a refresh. + var lane = requestUpdateLane(provider); + var refreshUpdate = createUpdate(lane); + var root = enqueueUpdate(provider, refreshUpdate, lane); - if (componentUpdateQueue === null) { - componentUpdateQueue = createFunctionComponentUpdateQueue(); - currentlyRenderingFiber$1.updateQueue = componentUpdateQueue; - componentUpdateQueue.stores = [check]; - } else { - var stores = componentUpdateQueue.stores; + if (root !== null) { + scheduleUpdateOnFiber(root, provider, lane); + entangleTransitions(root, provider, lane); + } // TODO: If a refresh never commits, the new cache created here must be + // released. A simple case is start refreshing a cache boundary, but then + // unmount that boundary before the refresh completes. - if (stores === null) { - componentUpdateQueue.stores = [check]; - } else { - stores.push(check); - } - } - } - 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. + var seededCache = createCache(); - if (checkIfSnapshotChanged(inst)) { - // Force a re-render. - forceStoreRerender(fiber); - } - } + if (seedKey !== null && seedKey !== undefined && root !== null) { + { + { + error('The seed argument is not enabled outside experimental channels.'); + } + } + } - 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); + var payload = { + cache: seededCache + }; + refreshUpdate.payload = payload; + return; } - }; // Subscribe to the store and return a clean-up function. - - return subscribe(handleStoreChange); } - function checkIfSnapshotChanged(inst) { - var latestGetSnapshot = inst.getSnapshot; - var prevValue = inst.value; + provider = provider.return; + } // TODO: Warn if unmounted? - try { - var nextValue = latestGetSnapshot(); - return !objectIs(prevValue, nextValue); - } catch (error) { - return true; - } +} + +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().'); } + } - function forceStoreRerender(fiber) { - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + var lane = requestUpdateLane(fiber); + var update = { + lane: lane, + revertLane: NoLane, + action: action, + hasEagerState: false, + eagerState: null, + next: null + }; - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane); - } - } + if (isRenderPhaseUpdate(fiber)) { + enqueueRenderPhaseUpdate(queue, update); + } else { + var root = enqueueConcurrentHookUpdate(fiber, queue, update, lane); - function mountStateImpl(initialState) { - var hook = mountWorkInProgressHook(); + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, lane); + entangleTransitionUpdate(root, queue, lane); + } + } - if (typeof initialState === "function") { - var initialStateInitializer = initialState; // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types + markUpdateInDevTools(fiber, lane); +} - initialState = initialStateInitializer(); +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().'); + } + } + + var lane = requestUpdateLane(fiber); + var update = { + lane: lane, + revertLane: NoLane, + action: action, + hasEagerState: false, + eagerState: null, + next: null + }; + + if (isRenderPhaseUpdate(fiber)) { + enqueueRenderPhaseUpdate(queue, update); + } else { + var alternate = fiber.alternate; + + 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; + + if (lastRenderedReducer !== null) { + var prevDispatcher = null; - if (shouldDoubleInvokeUserFnsInHooksDEV) { - setIsStrictModeForDevtools(true); // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types + { + prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; + } - initialStateInitializer(); - setIsStrictModeForDevtools(false); + 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. + + update.hasEagerState = true; + update.eagerState = eagerState; + + 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 { + { + ReactSharedInternals.H = prevDispatcher; + } } } - - hook.memoizedState = hook.baseState = initialState; - var queue = { - pending: null, - lanes: NoLanes, - dispatch: null, - lastRenderedReducer: basicStateReducer, - lastRenderedState: initialState - }; - hook.queue = queue; - return hook; } - function mountState(initialState) { - var hook = mountStateImpl(initialState); - var queue = hook.queue; - var dispatch = dispatchSetState.bind( - null, - currentlyRenderingFiber$1, - queue - ); - queue.dispatch = dispatch; - return [hook.memoizedState, dispatch]; - } + var root = enqueueConcurrentHookUpdate(fiber, queue, update, lane); - function updateState(initialState) { - return updateReducer(basicStateReducer); + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, lane); + entangleTransitionUpdate(root, queue, lane); } + } - function rerenderState(initialState) { - return rerenderReducer(basicStateReducer); - } + markUpdateInDevTools(fiber, lane); +} - function mountOptimistic(passthrough, reducer) { - var hook = mountWorkInProgressHook(); - hook.memoizedState = hook.baseState = passthrough; - var queue = { - pending: null, - lanes: NoLanes, - dispatch: null, - // Optimistic state does not use the eager update optimization. - lastRenderedReducer: null, - lastRenderedState: null - }; - hook.queue = queue; // This is different than the normal setState function. +function dispatchOptimisticSetState(fiber, throwIfDuringRender, queue, action) { + var transition = requestCurrentTransition(); + + { + if (transition === null) { + // An optimistic update occurred, but startTransition is not on the stack. + // There are two likely scenarios. + // One possibility is that the optimistic update is triggered by a regular + // event handler (e.g. `onSubmit`) instead of an action. This is a mistake + // and we will warn. + // The other possibility is the optimistic update is inside an async + // action, but after an `await`. In this case, we can make it "just work" + // by associating the optimistic update with the pending async action. + // Technically it's possible that the optimistic update is unrelated to + // the pending action, but we don't have a way of knowing this for sure + // because browsers currently do not provide a way to track async scope. + // (The AsyncContext proposal, if it lands, will solve this in the + // future.) However, this is no different than the problem of unrelated + // transitions being grouped together — it's not wrong per se, but it's + // not ideal. + // Once AsyncContext starts landing in browsers, we will provide better + // warnings in development for these cases. + if (peekEntangledActionLane() !== NoLane) ; else { + // There's no pending async action. The most likely cause is that we're + // inside a regular event handler (e.g. onSubmit) instead of an action. + error('An optimistic state update occurred outside a transition or ' + 'action. To fix, move the update to an action, or wrap ' + 'with startTransition.'); + } + } + } + + var update = { + // An optimistic update commits synchronously. + lane: SyncLane, + // After committing, the optimistic update is "reverted" using the same + // lane as the transition it's associated with. + revertLane: requestTransitionLane(), + action: action, + hasEagerState: false, + eagerState: null, + next: null + }; + + if (isRenderPhaseUpdate(fiber)) { + // When calling startTransition during render, this warns instead of + // throwing because throwing would be a breaking change. setOptimisticState + // is a new API so it's OK to throw. + if (throwIfDuringRender) { + throw new Error('Cannot update optimistic state while rendering.'); + } else { + // startTransition was called during render. We don't need to do anything + // besides warn here because the render phase update would be overidden by + // the second update, anyway. We can remove this branch and make it throw + // in a future release. + { + error('Cannot call startTransition while rendering.'); + } + } + } else { + var root = enqueueConcurrentHookUpdate(fiber, queue, update, SyncLane); + + if (root !== null) { + // NOTE: The optimistic update implementation assumes that the transition + // will never be attempted before the optimistic update. This currently + // holds because the optimistic update is always synchronous. If we ever + // change that, we'll need to account for this. + scheduleUpdateOnFiber(root, fiber, SyncLane); // Optimistic updates are always synchronous, so we don't need to call + // entangleTransitionUpdate here. + } + } + + markUpdateInDevTools(fiber, SyncLane); +} - var dispatch = dispatchOptimisticSetState.bind( - null, - currentlyRenderingFiber$1, - true, - queue - ); - queue.dispatch = dispatch; - return [passthrough, dispatch]; - } +function isRenderPhaseUpdate(fiber) { + var alternate = fiber.alternate; + return fiber === currentlyRenderingFiber$1 || alternate !== null && alternate === currentlyRenderingFiber$1; +} - function updateOptimistic(passthrough, reducer) { - var hook = updateWorkInProgressHook(); - return updateOptimisticImpl(hook, currentHook, passthrough, reducer); - } +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 (pending === null) { + // This is the first update. Create a circular list. + update.next = update; + } else { + update.next = pending.next; + pending.next = update; + } + + queue.pending = update; +} // TODO: Move to ReactFiberConcurrentUpdates? + + +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. + + queueLanes = intersectLanes(queueLanes, root.pendingLanes); // Entangle the new transition lane with the other transition lanes. + + 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. + + markRootEntangled(root, newQueueLanes); + } +} - function updateOptimisticImpl(hook, current, passthrough, reducer) { - // Optimistic updates are always rebased on top of the latest value passed in - // as an argument. It's called a passthrough because if there are no pending - // updates, it will be returned as-is. - // - // Reset the base state to the passthrough. Future updates will be applied - // on top of this. - hook.baseState = passthrough; // If a reducer is not provided, default to the same one used by useState. +function markUpdateInDevTools(fiber, lane, action) { - var resolvedReducer = - typeof reducer === "function" ? reducer : basicStateReducer; - return updateReducerImpl(hook, currentHook, resolvedReducer); - } + { + markStateUpdateScheduled(fiber, lane); + } +} - function rerenderOptimistic(passthrough, reducer) { - // Unlike useState, useOptimistic doesn't support render phase updates. - // Also unlike useState, we need to replay all pending updates again in case - // the passthrough value changed. - // - // So instead of a forked re-render implementation that knows how to handle - // render phase udpates, we can use the same implementation as during a - // regular mount or update. - var hook = updateWorkInProgressHook(); - - if (currentHook !== null) { - // This is an update. Process the update queue. - return updateOptimisticImpl(hook, currentHook, passthrough, reducer); - } // This is a mount. No updates to process. - // Reset the base state to the passthrough. Future updates will be applied - // on top of this. - - hook.baseState = passthrough; - var dispatch = hook.queue.dispatch; - return [passthrough, dispatch]; - } // useActionState actions run sequentially, because each action receives the - // previous state as an argument. We store pending actions on a queue. - - function dispatchActionState( - fiber, - actionQueue, - setPendingState, - setState, - payload - ) { - if (isRenderPhaseUpdate(fiber)) { - throw new Error("Cannot update form state while rendering."); - } - - var last = actionQueue.pending; - - if (last === null) { - // There are no pending actions; this is the first one. We can run - // it immediately. - var newLast = { - payload: payload, - next: null // circular - }; - newLast.next = actionQueue.pending = newLast; - runActionStateAction(actionQueue, setPendingState, setState, payload); - } else { - // There's already an action running. Add to the queue. - var first = last.next; - var _newLast = { - payload: payload, - next: first - }; - actionQueue.pending = last.next = _newLast; - } - } +var ContextOnlyDispatcher = { + readContext: readContext, + use: use, + useCallback: throwInvalidHookError, + useContext: throwInvalidHookError, + useEffect: throwInvalidHookError, + useImperativeHandle: throwInvalidHookError, + useLayoutEffect: throwInvalidHookError, + useInsertionEffect: throwInvalidHookError, + useMemo: throwInvalidHookError, + useReducer: throwInvalidHookError, + useRef: throwInvalidHookError, + useState: throwInvalidHookError, + useDebugValue: throwInvalidHookError, + useDeferredValue: throwInvalidHookError, + useTransition: throwInvalidHookError, + useSyncExternalStore: throwInvalidHookError, + useId: throwInvalidHookError +}; + +{ + ContextOnlyDispatcher.useCacheRefresh = throwInvalidHookError; +} - function runActionStateAction( - actionQueue, - setPendingState, - setState, - payload - ) { - var action = actionQueue.action; - var prevState = actionQueue.state; // This is a fork of startTransition +{ + ContextOnlyDispatcher.useMemoCache = throwInvalidHookError; +} - var prevTransition = ReactSharedInternals.T; - var currentTransition = { - _callbacks: new Set() - }; - ReactSharedInternals.T = currentTransition; +if (enableAsyncActions) { + ContextOnlyDispatcher.useHostTransitionStatus = throwInvalidHookError; + ContextOnlyDispatcher.useFormState = throwInvalidHookError; + ContextOnlyDispatcher.useActionState = throwInvalidHookError; +} - { - ReactSharedInternals.T._updatedFibers = new Set(); - } // Optimistically update the pending state, similar to useTransition. - // This will be reverted automatically when all actions are finished. +if (enableAsyncActions) { + ContextOnlyDispatcher.useOptimistic = throwInvalidHookError; +} + +var HooksDispatcherOnMountInDEV = null; +var HooksDispatcherOnMountWithHookTypesInDEV = null; +var HooksDispatcherOnUpdateInDEV = null; +var HooksDispatcherOnRerenderInDEV = null; +var InvalidNestedHooksDispatcherOnMountInDEV = null; +var InvalidNestedHooksDispatcherOnUpdateInDEV = null; +var InvalidNestedHooksDispatcherOnRerenderInDEV = null; + +{ + 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().'); + }; + + 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://react.dev/link/rules-of-hooks'); + }; + + HooksDispatcherOnMountInDEV = { + readContext: function (context) { + return readContext(context); + }, + use: use, + 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 = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; - setPendingState(true); + try { + return mountMemo(create, deps); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useReducer: function (reducer, initialArg, init) { + currentHookNameInDev = 'useReducer'; + mountHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; try { - var returnValue = action(prevState, payload); - - if ( - returnValue !== null && - typeof returnValue === "object" && // $FlowFixMe[method-unbinding] - typeof returnValue.then === "function" - ) { - var thenable = returnValue; - notifyTransitionCallbacks(currentTransition, thenable); // Attach a listener to read the return state of the action. As soon as - // this resolves, we can run the next action in the sequence. - - thenable.then( - function (nextState) { - actionQueue.state = nextState; - finishRunningActionStateAction( - actionQueue, - setPendingState, - setState - ); - }, - function () { - return finishRunningActionStateAction( - actionQueue, - setPendingState, - setState - ); - } - ); - setState(thenable); - } else { - setState(returnValue); - var nextState = returnValue; - actionQueue.state = nextState; - finishRunningActionStateAction( - actionQueue, - setPendingState, - setState - ); - } - } catch (error) { - // This is a trick to get the `useActionState` hook to rethrow the error. - // When it unwraps the thenable with the `use` algorithm, the error - // will be thrown. - var rejectedThenable = { - then: function () {}, - status: "rejected", - reason: error // $FlowFixMe: Not sure why this doesn't work - }; - setState(rejectedThenable); - finishRunningActionStateAction(actionQueue, setPendingState, setState); + return mountReducer(reducer, initialArg, init); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useRef: function (initialValue) { + currentHookNameInDev = 'useRef'; + mountHookTypesDev(); + return mountRef(initialValue); + }, + useState: function (initialState) { + currentHookNameInDev = 'useState'; + mountHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; + + try { + return mountState(initialState); } finally { - ReactSharedInternals.T = prevTransition; - - { - if (prevTransition === null && currentTransition._updatedFibers) { - var updatedFibersCount = currentTransition._updatedFibers.size; + ReactSharedInternals.H = prevDispatcher; + } + }, + useDebugValue: function (value, formatterFn) { + currentHookNameInDev = 'useDebugValue'; + mountHookTypesDev(); + return mountDebugValue(); + }, + useDeferredValue: function (value, initialValue) { + currentHookNameInDev = 'useDeferredValue'; + mountHookTypesDev(); + return mountDeferredValue(value, initialValue); + }, + useTransition: function () { + currentHookNameInDev = 'useTransition'; + mountHookTypesDev(); + return mountTransition(); + }, + useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { + currentHookNameInDev = 'useSyncExternalStore'; + mountHookTypesDev(); + return mountSyncExternalStore(subscribe, getSnapshot); + }, + useId: function () { + currentHookNameInDev = 'useId'; + mountHookTypesDev(); + return mountId(); + } + }; + + { + HooksDispatcherOnMountInDEV.useCacheRefresh = function useCacheRefresh() { + currentHookNameInDev = 'useCacheRefresh'; + mountHookTypesDev(); + return mountRefresh(); + }; + } - currentTransition._updatedFibers.clear(); + { + HooksDispatcherOnMountInDEV.useMemoCache = useMemoCache; + } - 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 (enableAsyncActions) { + HooksDispatcherOnMountInDEV.useHostTransitionStatus = useHostTransitionStatus; - function finishRunningActionStateAction( - actionQueue, - setPendingState, - setState - ) { - // The action finished running. Pop it from the queue and run the next pending - // action, if there are any. - var last = actionQueue.pending; + HooksDispatcherOnMountInDEV.useFormState = function useFormState(action, initialState, permalink) { + currentHookNameInDev = 'useFormState'; + mountHookTypesDev(); + return mountActionState(action, initialState); + }; - if (last !== null) { - var first = last.next; + HooksDispatcherOnMountInDEV.useActionState = function useActionState(action, initialState, permalink) { + currentHookNameInDev = 'useActionState'; + mountHookTypesDev(); + return mountActionState(action, initialState); + }; + } - if (first === last) { - // This was the last action in the queue. - actionQueue.pending = null; - } else { - // Remove the first node from the circular queue. - var next = first.next; - last.next = next; // Run the next action. + if (enableAsyncActions) { + HooksDispatcherOnMountInDEV.useOptimistic = function useOptimistic(passthrough, reducer) { + currentHookNameInDev = 'useOptimistic'; + mountHookTypesDev(); + return mountOptimistic(passthrough); + }; + } + + HooksDispatcherOnMountWithHookTypesInDEV = { + readContext: function (context) { + return readContext(context); + }, + use: use, + 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 = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; - runActionStateAction( - actionQueue, - setPendingState, - setState, - next.payload - ); - } + try { + return mountMemo(create, deps); + } finally { + ReactSharedInternals.H = prevDispatcher; } - } + }, + useReducer: function (reducer, initialArg, init) { + currentHookNameInDev = 'useReducer'; + updateHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; - function actionStateReducer(oldState, newState) { - return newState; - } + try { + return mountReducer(reducer, initialArg, init); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useRef: function (initialValue) { + currentHookNameInDev = 'useRef'; + updateHookTypesDev(); + return mountRef(initialValue); + }, + useState: function (initialState) { + currentHookNameInDev = 'useState'; + updateHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; + + try { + return mountState(initialState); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useDebugValue: function (value, formatterFn) { + currentHookNameInDev = 'useDebugValue'; + updateHookTypesDev(); + return mountDebugValue(); + }, + useDeferredValue: function (value, initialValue) { + currentHookNameInDev = 'useDeferredValue'; + updateHookTypesDev(); + return mountDeferredValue(value, initialValue); + }, + useTransition: function () { + currentHookNameInDev = 'useTransition'; + updateHookTypesDev(); + return mountTransition(); + }, + useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { + currentHookNameInDev = 'useSyncExternalStore'; + updateHookTypesDev(); + return mountSyncExternalStore(subscribe, getSnapshot); + }, + useId: function () { + currentHookNameInDev = 'useId'; + updateHookTypesDev(); + return mountId(); + } + }; + + { + HooksDispatcherOnMountWithHookTypesInDEV.useCacheRefresh = function useCacheRefresh() { + currentHookNameInDev = 'useCacheRefresh'; + updateHookTypesDev(); + return mountRefresh(); + }; + } - function mountActionState(action, initialStateProp, permalink) { - var initialState = initialStateProp; - // the `use` algorithm during render. + { + HooksDispatcherOnMountWithHookTypesInDEV.useMemoCache = useMemoCache; + } - var stateHook = mountWorkInProgressHook(); - stateHook.memoizedState = stateHook.baseState = initialState; // TODO: Typing this "correctly" results in recursion limit errors - // const stateQueue: UpdateQueue, S | Awaited> = { + if (enableAsyncActions) { + HooksDispatcherOnMountWithHookTypesInDEV.useHostTransitionStatus = useHostTransitionStatus; - var stateQueue = { - pending: null, - lanes: NoLanes, - dispatch: null, - lastRenderedReducer: actionStateReducer, - lastRenderedState: initialState - }; - stateHook.queue = stateQueue; - var setState = dispatchSetState.bind( - null, - currentlyRenderingFiber$1, - stateQueue - ); - stateQueue.dispatch = setState; // Pending state. This is used to store the pending state of the action. - // Tracked optimistically, like a transition pending state. - - var pendingStateHook = mountStateImpl(false); - var setPendingState = dispatchOptimisticSetState.bind( - null, - currentlyRenderingFiber$1, - false, - pendingStateHook.queue - ); // Action queue hook. This is used to queue pending actions. The queue is - // shared between all instances of the hook. Similar to a regular state queue, - // but different because the actions are run sequentially, and they run in - // an event instead of during render. - - var actionQueueHook = mountWorkInProgressHook(); - var actionQueue = { - state: initialState, - dispatch: null, - // circular - action: action, - pending: null - }; - actionQueueHook.queue = actionQueue; - var dispatch = dispatchActionState.bind( - null, - currentlyRenderingFiber$1, - actionQueue, - setPendingState, - setState - ); - actionQueue.dispatch = dispatch; // Stash the action function on the memoized state of the hook. We'll use this - // to detect when the action function changes so we can update it in - // an effect. - - actionQueueHook.memoizedState = action; - return [initialState, dispatch, false]; - } - - function updateActionState(action, initialState, permalink) { - var stateHook = updateWorkInProgressHook(); - var currentStateHook = currentHook; - return updateActionStateImpl(stateHook, currentStateHook, action); - } - - function updateActionStateImpl( - stateHook, - currentStateHook, - action, - initialState, - permalink - ) { - var _updateReducerImpl = updateReducerImpl( - stateHook, - currentStateHook, - actionStateReducer - ), - actionResult = _updateReducerImpl[0]; - - var _updateState = updateState(), - isPending = _updateState[0]; // This will suspend until the action finishes. - - var state = - typeof actionResult === "object" && - actionResult !== null && // $FlowFixMe[method-unbinding] - typeof actionResult.then === "function" - ? useThenable(actionResult) - : actionResult; - var actionQueueHook = updateWorkInProgressHook(); - var actionQueue = actionQueueHook.queue; - var dispatch = actionQueue.dispatch; // Check if a new action was passed. If so, update it in an effect. - - var prevAction = actionQueueHook.memoizedState; - - if (action !== prevAction) { - currentlyRenderingFiber$1.flags |= Passive$1; - pushEffect( - HasEffect | Passive, - actionStateActionEffect.bind(null, actionQueue, action), - createEffectInstance(), - null - ); - } - - return [state, dispatch, isPending]; - } - - function actionStateActionEffect(actionQueue, action) { - actionQueue.action = action; - } - - function rerenderActionState(action, initialState, permalink) { - // Unlike useState, useActionState doesn't support render phase updates. - // Also unlike useState, we need to replay all pending updates again in case - // the passthrough value changed. - // - // So instead of a forked re-render implementation that knows how to handle - // render phase udpates, we can use the same implementation as during a - // regular mount or update. - var stateHook = updateWorkInProgressHook(); - var currentStateHook = currentHook; + HooksDispatcherOnMountWithHookTypesInDEV.useFormState = function useFormState(action, initialState, permalink) { + currentHookNameInDev = 'useFormState'; + updateHookTypesDev(); + warnOnUseFormStateInDev(); + return mountActionState(action, initialState); + }; + + HooksDispatcherOnMountWithHookTypesInDEV.useActionState = function useActionState(action, initialState, permalink) { + currentHookNameInDev = 'useActionState'; + updateHookTypesDev(); + return mountActionState(action, initialState); + }; + } + + if (enableAsyncActions) { + HooksDispatcherOnMountWithHookTypesInDEV.useOptimistic = function useOptimistic(passthrough, reducer) { + currentHookNameInDev = 'useOptimistic'; + updateHookTypesDev(); + return mountOptimistic(passthrough); + }; + } + + HooksDispatcherOnUpdateInDEV = { + readContext: function (context) { + return readContext(context); + }, + use: use, + 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 = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; - if (currentStateHook !== null) { - // This is an update. Process the update queue. - return updateActionStateImpl(stateHook, currentStateHook, action); + try { + return updateMemo(create, deps); + } finally { + ReactSharedInternals.H = prevDispatcher; } + }, + useReducer: function (reducer, initialArg, init) { + currentHookNameInDev = 'useReducer'; + updateHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; - updateWorkInProgressHook(); // State - // This is a mount. No updates to process. + try { + return updateReducer(reducer, initialArg, init); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useRef: function (initialValue) { + currentHookNameInDev = 'useRef'; + updateHookTypesDev(); + return updateRef(); + }, + useState: function (initialState) { + currentHookNameInDev = 'useState'; + updateHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; - var state = stateHook.memoizedState; - var actionQueueHook = updateWorkInProgressHook(); - var actionQueue = actionQueueHook.queue; - var dispatch = actionQueue.dispatch; // This may have changed during the rerender. + try { + return updateState(initialState); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useDebugValue: function (value, formatterFn) { + currentHookNameInDev = 'useDebugValue'; + updateHookTypesDev(); + return updateDebugValue(); + }, + useDeferredValue: function (value, initialValue) { + currentHookNameInDev = 'useDeferredValue'; + updateHookTypesDev(); + return updateDeferredValue(value, initialValue); + }, + useTransition: function () { + currentHookNameInDev = 'useTransition'; + updateHookTypesDev(); + return updateTransition(); + }, + useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { + currentHookNameInDev = 'useSyncExternalStore'; + updateHookTypesDev(); + return updateSyncExternalStore(subscribe, getSnapshot); + }, + useId: function () { + currentHookNameInDev = 'useId'; + updateHookTypesDev(); + return updateId(); + } + }; + + { + HooksDispatcherOnUpdateInDEV.useCacheRefresh = function useCacheRefresh() { + currentHookNameInDev = 'useCacheRefresh'; + updateHookTypesDev(); + return updateRefresh(); + }; + } - actionQueueHook.memoizedState = action; // For mount, pending is always false. + { + HooksDispatcherOnUpdateInDEV.useMemoCache = useMemoCache; + } - return [state, dispatch, false]; - } + if (enableAsyncActions) { + HooksDispatcherOnUpdateInDEV.useHostTransitionStatus = useHostTransitionStatus; - function pushEffect(tag, create, inst, deps) { - var effect = { - tag: tag, - create: create, - inst: inst, - deps: deps, - // Circular - next: null - }; - var componentUpdateQueue = currentlyRenderingFiber$1.updateQueue; + HooksDispatcherOnUpdateInDEV.useFormState = function useFormState(action, initialState, permalink) { + currentHookNameInDev = 'useFormState'; + updateHookTypesDev(); + warnOnUseFormStateInDev(); + return updateActionState(action); + }; - if (componentUpdateQueue === null) { - componentUpdateQueue = createFunctionComponentUpdateQueue(); - currentlyRenderingFiber$1.updateQueue = componentUpdateQueue; - componentUpdateQueue.lastEffect = effect.next = effect; - } else { - var lastEffect = componentUpdateQueue.lastEffect; + HooksDispatcherOnUpdateInDEV.useActionState = function useActionState(action, initialState, permalink) { + currentHookNameInDev = 'useActionState'; + updateHookTypesDev(); + return updateActionState(action); + }; + } - if (lastEffect === null) { - componentUpdateQueue.lastEffect = effect.next = effect; - } else { - var firstEffect = lastEffect.next; - lastEffect.next = effect; - effect.next = firstEffect; - componentUpdateQueue.lastEffect = effect; - } + if (enableAsyncActions) { + HooksDispatcherOnUpdateInDEV.useOptimistic = function useOptimistic(passthrough, reducer) { + currentHookNameInDev = 'useOptimistic'; + updateHookTypesDev(); + return updateOptimistic(passthrough, reducer); + }; + } + + HooksDispatcherOnRerenderInDEV = { + readContext: function (context) { + return readContext(context); + }, + use: use, + 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 = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnRerenderInDEV; + + try { + return updateMemo(create, deps); + } finally { + ReactSharedInternals.H = prevDispatcher; } + }, + useReducer: function (reducer, initialArg, init) { + currentHookNameInDev = 'useReducer'; + updateHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnRerenderInDEV; - return effect; - } + try { + return rerenderReducer(reducer, initialArg, init); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useRef: function (initialValue) { + currentHookNameInDev = 'useRef'; + updateHookTypesDev(); + return updateRef(); + }, + useState: function (initialState) { + currentHookNameInDev = 'useState'; + updateHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnRerenderInDEV; - function createEffectInstance() { - return { - destroy: undefined - }; - } + try { + return rerenderState(initialState); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useDebugValue: function (value, formatterFn) { + currentHookNameInDev = 'useDebugValue'; + updateHookTypesDev(); + return updateDebugValue(); + }, + useDeferredValue: function (value, initialValue) { + currentHookNameInDev = 'useDeferredValue'; + updateHookTypesDev(); + return rerenderDeferredValue(value, initialValue); + }, + useTransition: function () { + currentHookNameInDev = 'useTransition'; + updateHookTypesDev(); + return rerenderTransition(); + }, + useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { + currentHookNameInDev = 'useSyncExternalStore'; + updateHookTypesDev(); + return updateSyncExternalStore(subscribe, getSnapshot); + }, + useId: function () { + currentHookNameInDev = 'useId'; + updateHookTypesDev(); + return updateId(); + } + }; + + { + HooksDispatcherOnRerenderInDEV.useCacheRefresh = function useCacheRefresh() { + currentHookNameInDev = 'useCacheRefresh'; + updateHookTypesDev(); + return updateRefresh(); + }; + } - function mountRef(initialValue) { - var hook = mountWorkInProgressHook(); - var ref = { - current: initialValue - }; - hook.memoizedState = ref; - return ref; - } + { + HooksDispatcherOnRerenderInDEV.useMemoCache = useMemoCache; + } - function updateRef(initialValue) { - var hook = updateWorkInProgressHook(); - return hook.memoizedState; - } + if (enableAsyncActions) { + HooksDispatcherOnRerenderInDEV.useHostTransitionStatus = useHostTransitionStatus; - 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, - createEffectInstance(), - nextDeps - ); - } + HooksDispatcherOnRerenderInDEV.useFormState = function useFormState(action, initialState, permalink) { + currentHookNameInDev = 'useFormState'; + updateHookTypesDev(); + warnOnUseFormStateInDev(); + return rerenderActionState(action); + }; - function updateEffectImpl(fiberFlags, hookFlags, create, deps) { - var hook = updateWorkInProgressHook(); - var nextDeps = deps === undefined ? null : deps; - var effect = hook.memoizedState; - var inst = effect.inst; // currentHook is null on initial mount when rerendering after a render phase - // state update or for strict mode. + HooksDispatcherOnRerenderInDEV.useActionState = function useActionState(action, initialState, permalink) { + currentHookNameInDev = 'useActionState'; + updateHookTypesDev(); + return rerenderActionState(action); + }; + } - if (currentHook !== null) { - if (nextDeps !== null) { - var prevEffect = currentHook.memoizedState; - var prevDeps = prevEffect.deps; + if (enableAsyncActions) { + HooksDispatcherOnRerenderInDEV.useOptimistic = function useOptimistic(passthrough, reducer) { + currentHookNameInDev = 'useOptimistic'; + updateHookTypesDev(); + return rerenderOptimistic(passthrough, reducer); + }; + } + + InvalidNestedHooksDispatcherOnMountInDEV = { + readContext: function (context) { + warnInvalidContextAccess(); + return readContext(context); + }, + use: function (usable) { + warnInvalidHookAccess(); + return use(usable); + }, + 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 = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; - if (areHookInputsEqual(nextDeps, prevDeps)) { - hook.memoizedState = pushEffect(hookFlags, create, inst, nextDeps); - return; - } - } + try { + return mountMemo(create, deps); + } finally { + ReactSharedInternals.H = prevDispatcher; } + }, + useReducer: function (reducer, initialArg, init) { + currentHookNameInDev = 'useReducer'; + warnInvalidHookAccess(); + mountHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; - currentlyRenderingFiber$1.flags |= fiberFlags; - hook.memoizedState = pushEffect( - HasEffect | hookFlags, - create, - inst, - nextDeps - ); - } + try { + return mountReducer(reducer, initialArg, init); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useRef: function (initialValue) { + currentHookNameInDev = 'useRef'; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountRef(initialValue); + }, + useState: function (initialState) { + currentHookNameInDev = 'useState'; + warnInvalidHookAccess(); + mountHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; - function mountEffect(create, deps) { - if ( - (currentlyRenderingFiber$1.mode & StrictEffectsMode) !== NoMode && - (currentlyRenderingFiber$1.mode & NoStrictPassiveEffectsMode) === NoMode - ) { - mountEffectImpl( - MountPassiveDev | Passive$1 | PassiveStatic, - Passive, - create, - deps - ); - } else { - mountEffectImpl(Passive$1 | PassiveStatic, Passive, create, deps); - } - } + try { + return mountState(initialState); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useDebugValue: function (value, formatterFn) { + currentHookNameInDev = 'useDebugValue'; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountDebugValue(); + }, + useDeferredValue: function (value, initialValue) { + currentHookNameInDev = 'useDeferredValue'; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountDeferredValue(value, initialValue); + }, + useTransition: function () { + currentHookNameInDev = 'useTransition'; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountTransition(); + }, + useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { + currentHookNameInDev = 'useSyncExternalStore'; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountSyncExternalStore(subscribe, getSnapshot); + }, + useId: function () { + currentHookNameInDev = 'useId'; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountId(); + } + }; + + { + InvalidNestedHooksDispatcherOnMountInDEV.useCacheRefresh = function useCacheRefresh() { + currentHookNameInDev = 'useCacheRefresh'; + mountHookTypesDev(); + return mountRefresh(); + }; + } - function updateEffect(create, deps) { - updateEffectImpl(Passive$1, Passive, create, deps); - } + { + InvalidNestedHooksDispatcherOnMountInDEV.useMemoCache = function (size) { + warnInvalidHookAccess(); + return useMemoCache(size); + }; + } - function mountInsertionEffect(create, deps) { - mountEffectImpl(Update, Insertion, create, deps); - } + if (enableAsyncActions) { + InvalidNestedHooksDispatcherOnMountInDEV.useHostTransitionStatus = useHostTransitionStatus; - function updateInsertionEffect(create, deps) { - return updateEffectImpl(Update, Insertion, create, deps); - } + InvalidNestedHooksDispatcherOnMountInDEV.useFormState = function useFormState(action, initialState, permalink) { + currentHookNameInDev = 'useFormState'; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountActionState(action, initialState); + }; - function mountLayoutEffect(create, deps) { - var fiberFlags = Update | LayoutStatic; + InvalidNestedHooksDispatcherOnMountInDEV.useActionState = function useActionState(action, initialState, permalink) { + currentHookNameInDev = 'useActionState'; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountActionState(action, initialState); + }; + } + + if (enableAsyncActions) { + InvalidNestedHooksDispatcherOnMountInDEV.useOptimistic = function useOptimistic(passthrough, reducer) { + currentHookNameInDev = 'useOptimistic'; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountOptimistic(passthrough); + }; + } + + InvalidNestedHooksDispatcherOnUpdateInDEV = { + readContext: function (context) { + warnInvalidContextAccess(); + return readContext(context); + }, + use: function (usable) { + warnInvalidHookAccess(); + return use(usable); + }, + 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 = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; - if ((currentlyRenderingFiber$1.mode & StrictEffectsMode) !== NoMode) { - fiberFlags |= MountLayoutDev; + try { + return updateMemo(create, deps); + } finally { + ReactSharedInternals.H = prevDispatcher; } + }, + useReducer: function (reducer, initialArg, init) { + currentHookNameInDev = 'useReducer'; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; - return mountEffectImpl(fiberFlags, Layout, create, deps); - } - - function updateLayoutEffect(create, deps) { - return updateEffectImpl(Update, Layout, create, deps); - } - - 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; + try { + return updateReducer(reducer, initialArg, init); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useRef: function (initialValue) { + currentHookNameInDev = 'useRef'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateRef(); + }, + useState: function (initialState) { + currentHookNameInDev = 'useState'; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; - { - 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(", ") + "}" - ); - } - } + try { + return updateState(initialState); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useDebugValue: function (value, formatterFn) { + currentHookNameInDev = 'useDebugValue'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateDebugValue(); + }, + useDeferredValue: function (value, initialValue) { + currentHookNameInDev = 'useDeferredValue'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateDeferredValue(value, initialValue); + }, + useTransition: function () { + currentHookNameInDev = 'useTransition'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateTransition(); + }, + useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { + currentHookNameInDev = 'useSyncExternalStore'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateSyncExternalStore(subscribe, getSnapshot); + }, + useId: function () { + currentHookNameInDev = 'useId'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateId(); + } + }; + + { + InvalidNestedHooksDispatcherOnUpdateInDEV.useCacheRefresh = function useCacheRefresh() { + currentHookNameInDev = 'useCacheRefresh'; + updateHookTypesDev(); + return updateRefresh(); + }; + } - var _inst = create(); + { + InvalidNestedHooksDispatcherOnUpdateInDEV.useMemoCache = function (size) { + warnInvalidHookAccess(); + return useMemoCache(size); + }; + } - refObject.current = _inst; - return function () { - refObject.current = null; - }; - } - } + if (enableAsyncActions) { + InvalidNestedHooksDispatcherOnUpdateInDEV.useHostTransitionStatus = useHostTransitionStatus; - 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? + InvalidNestedHooksDispatcherOnUpdateInDEV.useFormState = function useFormState(action, initialState, permalink) { + currentHookNameInDev = 'useFormState'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateActionState(action); + }; - var effectDeps = - deps !== null && deps !== undefined ? deps.concat([ref]) : null; - var fiberFlags = Update | LayoutStatic; + InvalidNestedHooksDispatcherOnUpdateInDEV.useActionState = function useActionState(action, initialState, permalink) { + currentHookNameInDev = 'useActionState'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateActionState(action); + }; + } + + if (enableAsyncActions) { + InvalidNestedHooksDispatcherOnUpdateInDEV.useOptimistic = function useOptimistic(passthrough, reducer) { + currentHookNameInDev = 'useOptimistic'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateOptimistic(passthrough, reducer); + }; + } + + InvalidNestedHooksDispatcherOnRerenderInDEV = { + readContext: function (context) { + warnInvalidContextAccess(); + return readContext(context); + }, + use: function (usable) { + warnInvalidHookAccess(); + return use(usable); + }, + 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 = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; - if ((currentlyRenderingFiber$1.mode & StrictEffectsMode) !== NoMode) { - fiberFlags |= MountLayoutDev; + try { + return updateMemo(create, deps); + } finally { + ReactSharedInternals.H = prevDispatcher; } + }, + useReducer: function (reducer, initialArg, init) { + currentHookNameInDev = 'useReducer'; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; - mountEffectImpl( - fiberFlags, - Layout, - imperativeHandleEffect.bind(null, create, ref), - effectDeps - ); - } + try { + return rerenderReducer(reducer, initialArg, init); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useRef: function (initialValue) { + currentHookNameInDev = 'useRef'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateRef(); + }, + useState: function (initialState) { + currentHookNameInDev = 'useState'; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; - 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? + try { + return rerenderState(initialState); + } finally { + ReactSharedInternals.H = prevDispatcher; + } + }, + useDebugValue: function (value, formatterFn) { + currentHookNameInDev = 'useDebugValue'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateDebugValue(); + }, + useDeferredValue: function (value, initialValue) { + currentHookNameInDev = 'useDeferredValue'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return rerenderDeferredValue(value, initialValue); + }, + useTransition: function () { + currentHookNameInDev = 'useTransition'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return rerenderTransition(); + }, + useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { + currentHookNameInDev = 'useSyncExternalStore'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateSyncExternalStore(subscribe, getSnapshot); + }, + useId: function () { + currentHookNameInDev = 'useId'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateId(); + } + }; + + { + InvalidNestedHooksDispatcherOnRerenderInDEV.useCacheRefresh = function useCacheRefresh() { + currentHookNameInDev = 'useCacheRefresh'; + updateHookTypesDev(); + return updateRefresh(); + }; + } - var effectDeps = - deps !== null && deps !== undefined ? deps.concat([ref]) : null; - updateEffectImpl( - Update, - Layout, - imperativeHandleEffect.bind(null, create, ref), - effectDeps - ); - } + { + InvalidNestedHooksDispatcherOnRerenderInDEV.useMemoCache = function (size) { + warnInvalidHookAccess(); + return useMemoCache(size); + }; + } - 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. - } + if (enableAsyncActions) { + InvalidNestedHooksDispatcherOnRerenderInDEV.useHostTransitionStatus = useHostTransitionStatus; - var updateDebugValue = mountDebugValue; + InvalidNestedHooksDispatcherOnRerenderInDEV.useFormState = function useFormState(action, initialState, permalink) { + currentHookNameInDev = 'useFormState'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return rerenderActionState(action); + }; - function mountCallback(callback, deps) { - var hook = mountWorkInProgressHook(); - var nextDeps = deps === undefined ? null : deps; - hook.memoizedState = [callback, nextDeps]; - return callback; - } + InvalidNestedHooksDispatcherOnRerenderInDEV.useActionState = function useActionState(action, initialState, permalink) { + currentHookNameInDev = 'useActionState'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return rerenderActionState(action); + }; + } + + if (enableAsyncActions) { + InvalidNestedHooksDispatcherOnRerenderInDEV.useOptimistic = function useOptimistic(passthrough, reducer) { + currentHookNameInDev = 'useOptimistic'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return rerenderOptimistic(passthrough, reducer); + }; + } +} - function updateCallback(callback, deps) { - var hook = updateWorkInProgressHook(); - var nextDeps = deps === undefined ? null : deps; - var prevState = hook.memoizedState; +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. + */ - if (nextDeps !== null) { - var prevDeps = prevState[1]; +var currentUpdateIsNested = false; +var nestedUpdateScheduled = false; - if (areHookInputsEqual(nextDeps, prevDeps)) { - return prevState[0]; - } - } +function isCurrentUpdateNested() { + return currentUpdateIsNested; +} - hook.memoizedState = [callback, nextDeps]; - return callback; - } +function markNestedUpdateScheduled() { + { + nestedUpdateScheduled = true; + } +} - function mountMemo(nextCreate, deps) { - var hook = mountWorkInProgressHook(); - var nextDeps = deps === undefined ? null : deps; - var nextValue = nextCreate(); +function resetNestedUpdateFlag() { + { + currentUpdateIsNested = false; + nestedUpdateScheduled = false; + } +} - if (shouldDoubleInvokeUserFnsInHooksDEV) { - setIsStrictModeForDevtools(true); - nextCreate(); - setIsStrictModeForDevtools(false); - } +function syncNestedUpdateFlag() { + { + currentUpdateIsNested = nestedUpdateScheduled; + nestedUpdateScheduled = false; + } +} - hook.memoizedState = [nextValue, nextDeps]; - return nextValue; - } +function getCommitTime() { + return commitTime; +} - 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 recordCommitTime() { - if (nextDeps !== null) { - var prevDeps = prevState[1]; + commitTime = now(); +} - if (areHookInputsEqual(nextDeps, prevDeps)) { - return prevState[0]; - } - } +function startProfilerTimer(fiber) { - var nextValue = nextCreate(); + profilerStartTime = now(); - if (shouldDoubleInvokeUserFnsInHooksDEV) { - setIsStrictModeForDevtools(true); - nextCreate(); - setIsStrictModeForDevtools(false); - } + if (fiber.actualStartTime < 0) { + fiber.actualStartTime = now(); + } +} - hook.memoizedState = [nextValue, nextDeps]; - return nextValue; - } +function stopProfilerTimerIfRunning(fiber) { - function mountDeferredValue(value, initialValue) { - var hook = mountWorkInProgressHook(); - return mountDeferredValueImpl(hook, value, initialValue); - } + profilerStartTime = -1; +} - function updateDeferredValue(value, initialValue) { - var hook = updateWorkInProgressHook(); - var resolvedCurrentHook = currentHook; - var prevValue = resolvedCurrentHook.memoizedState; - return updateDeferredValueImpl(hook, prevValue, value, initialValue); - } +function stopProfilerTimerIfRunningAndRecordDelta(fiber, overrideBaseTime) { - function rerenderDeferredValue(value, initialValue) { - var hook = updateWorkInProgressHook(); + if (profilerStartTime >= 0) { + var elapsedTime = now() - profilerStartTime; + fiber.actualDuration += elapsedTime; - if (currentHook === null) { - // This is a rerender during a mount. - return mountDeferredValueImpl(hook, value, initialValue); - } else { - // This is a rerender during an update. - var prevValue = currentHook.memoizedState; - return updateDeferredValueImpl(hook, prevValue, value, initialValue); - } - } - - function mountDeferredValueImpl(hook, value, initialValue) { - if ( - // When `initialValue` is provided, we defer the initial render even if the - // current render is not synchronous. - initialValue !== undefined && // However, to avoid waterfalls, we do not defer if this render - // was itself spawned by an earlier useDeferredValue. Check if DeferredLane - // is part of the render lanes. - !includesSomeLane(renderLanes, DeferredLane) - ) { - // Render with the initial value - hook.memoizedState = initialValue; // Schedule a deferred render to switch to the final value. - - var deferredLane = requestDeferredLane(); - currentlyRenderingFiber$1.lanes = mergeLanes( - currentlyRenderingFiber$1.lanes, - deferredLane - ); - markSkippedUpdateLanes(deferredLane); - return initialValue; - } else { - hook.memoizedState = value; - return value; - } + if (overrideBaseTime) { + fiber.selfBaseDuration = elapsedTime; } - function updateDeferredValueImpl(hook, prevValue, value, initialValue) { - if (objectIs(value, prevValue)) { - // The incoming value is referentially identical to the currently rendered - // value, so we can bail out quickly. - return value; - } else { - // Received a new value that's different from the current value. - // Check if we're inside a hidden tree - if (isCurrentTreeHidden()) { - // Revealing a prerendered tree is considered the same as mounting new - // one, so we reuse the "mount" path in this case. - var resultValue = mountDeferredValueImpl(hook, value, initialValue); // Unlike during an actual mount, we need to mark this as an update if - // the value changed. - - if (!objectIs(resultValue, prevValue)) { - markWorkInProgressReceivedUpdate(); - } + profilerStartTime = -1; + } +} - return resultValue; - } +function recordLayoutEffectDuration(fiber) { - var shouldDeferValue = !includesOnlyNonUrgentLanes(renderLanes); + 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) - if (shouldDeferValue) { - // This is an urgent update. Since the value has changed, keep using the - // previous value and spawn a deferred render to update it later. - // Schedule a deferred render - var deferredLane = requestDeferredLane(); - currentlyRenderingFiber$1.lanes = mergeLanes( - currentlyRenderingFiber$1.lanes, - deferredLane - ); - markSkippedUpdateLanes(deferredLane); // Reuse the previous value. We do not need to mark this as an update, - // because we did not render a new value. + var parentFiber = fiber.return; - 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. - // Mark this as an update to prevent the fiber from bailing out. - markWorkInProgressReceivedUpdate(); - hook.memoizedState = value; - return value; - } - } - } - - function startTransition( - fiber, - queue, - pendingState, - finishedState, - callback, - options - ) { - var previousPriority = getCurrentUpdatePriority(); - setCurrentUpdatePriority( - higherEventPriority(previousPriority, ContinuousEventPriority) - ); - var prevTransition = ReactSharedInternals.T; - var currentTransition = { - _callbacks: new Set() - }; + while (parentFiber !== null) { + switch (parentFiber.tag) { + case HostRoot: + var root = parentFiber.stateNode; + root.effectDuration += elapsedTime; + return; - if (enableAsyncActions) { - // We don't really need to use an optimistic update here, because we - // schedule a second "revert" update below (which we use to suspend the - // transition until the async action scope has finished). But we'll use an - // optimistic update anyway to make it less likely the behavior accidentally - // diverges; for example, both an optimistic update and this one should - // share the same lane. - ReactSharedInternals.T = currentTransition; - dispatchOptimisticSetState(fiber, false, queue, pendingState); - } else { - ReactSharedInternals.T = null; - dispatchSetState(fiber, queue, pendingState); - ReactSharedInternals.T = currentTransition; + case Profiler: + var parentStateNode = parentFiber.stateNode; + parentStateNode.effectDuration += elapsedTime; + return; } - { - currentTransition._updatedFibers = new Set(); - } + parentFiber = parentFiber.return; + } + } +} - try { - if (enableAsyncActions) { - var returnValue = callback(); // Check if we're inside an async action scope. If so, we'll entangle - // this new action with the existing scope. - // - // If we're not already inside an async action scope, and this action is - // async, then we'll create a new async scope. - // - // In the async case, the resulting render will suspend until the async - // action scope has finished. - - if ( - returnValue !== null && - typeof returnValue === "object" && - typeof returnValue.then === "function" - ) { - var thenable = returnValue; - notifyTransitionCallbacks(currentTransition, thenable); // Create a thenable that resolves to `finishedState` once the async - // action has completed. - - var thenableForFinishedState = chainThenableValue( - thenable, - finishedState - ); - dispatchSetState(fiber, queue, thenableForFinishedState); - } else { - dispatchSetState(fiber, queue, finishedState); - } - } else { - // Async actions are not enabled. - dispatchSetState(fiber, queue, finishedState); - callback(); - } - } catch (error) { - if (enableAsyncActions) { - // This is a trick to get the `useTransition` hook to rethrow the error. - // When it unwraps the thenable with the `use` algorithm, the error - // will be thrown. - var rejectedThenable = { - then: function () {}, - status: "rejected", - reason: error - }; - dispatchSetState(fiber, queue, rejectedThenable); - } else { - // The error rethrowing behavior is only enabled when the async actions - // feature is on, even for sync actions. - throw error; - } - } finally { - setCurrentUpdatePriority(previousPriority); - ReactSharedInternals.T = prevTransition; +function recordPassiveEffectDuration(fiber) { - { - if (prevTransition === null && currentTransition._updatedFibers) { - var updatedFibersCount = currentTransition._updatedFibers.size; + 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) - currentTransition._updatedFibers.clear(); + var parentFiber = fiber.return; - 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." - ); - } - } - } - } - } + while (parentFiber !== null) { + switch (parentFiber.tag) { + case HostRoot: + var root = parentFiber.stateNode; - function mountTransition() { - var stateHook = mountStateImpl(false); // The `start` method never changes. + if (root !== null) { + root.passiveEffectDuration += elapsedTime; + } - var start = startTransition.bind( - null, - currentlyRenderingFiber$1, - stateHook.queue, - true, - false - ); - var hook = mountWorkInProgressHook(); - hook.memoizedState = start; - return [false, start]; - } + return; - function updateTransition() { - var _updateState2 = updateState(), - booleanOrThenable = _updateState2[0]; + case Profiler: + var parentStateNode = parentFiber.stateNode; - var hook = updateWorkInProgressHook(); - var start = hook.memoizedState; - var isPending = - typeof booleanOrThenable === "boolean" - ? booleanOrThenable // This will suspend until the async action scope has finished. - : useThenable(booleanOrThenable); - return [isPending, start]; - } + 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; + } - function rerenderTransition() { - var _rerenderState = rerenderState(), - booleanOrThenable = _rerenderState[0]; + return; + } - var hook = updateWorkInProgressHook(); - var start = hook.memoizedState; - var isPending = - typeof booleanOrThenable === "boolean" - ? booleanOrThenable // This will suspend until the async action scope has finished. - : useThenable(booleanOrThenable); - return [isPending, start]; + parentFiber = parentFiber.return; } + } +} - function useHostTransitionStatus() { - if (!enableAsyncActions) { - throw new Error("Not implemented."); - } +function startLayoutEffectTimer() { - var status = readContext(HostTransitionContext); - return status !== null ? status : NotPendingTransition; - } + layoutEffectStartTime = now(); +} - 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. +function startPassiveEffectTimer() { - var identifierPrefix = root.identifierPrefix; - var id; + passiveEffectStartTime = now(); +} - { - // Use a lowercase r prefix for client-generated ids. - var globalClientId = globalClientIdCounter++; - id = ":" + identifierPrefix + "r" + globalClientId.toString(32) + ":"; - } +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; + + while (child) { + // $FlowFixMe[unsafe-addition] addition with possible null/undefined value + fiber.actualDuration += child.actualDuration; + child = child.sibling; + } +} - hook.memoizedState = id; - return id; - } +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 updateId() { - var hook = updateWorkInProgressHook(); - var id = hook.memoizedState; - return id; - } +function warnOnInvalidCallback(callback) { + { + if (callback === null || typeof callback === 'function') { + return; + } // eslint-disable-next-line react-internal/safe-string-coercion - function mountRefresh() { - var hook = mountWorkInProgressHook(); - var refresh = (hook.memoizedState = refreshCache.bind( - null, - currentlyRenderingFiber$1 - )); - return refresh; - } - function updateRefresh() { - var hook = updateWorkInProgressHook(); - return hook.memoizedState; - } + var key = String(callback); - function refreshCache(fiber, seedKey, seedValue) { - // TODO: Consider warning if the refresh is at discrete priority, or if we - // otherwise suspect that it wasn't batched properly. + if (!didWarnOnInvalidCallback.has(key)) { + didWarnOnInvalidCallback.add(key); - var provider = fiber.return; + error('Expected the last optional `callback` argument to be a ' + 'function. Instead received: %s.', callback); + } + } +} - while (provider !== null) { - switch (provider.tag) { - case CacheComponent: - case HostRoot: { - // Schedule an update on the cache boundary to trigger a refresh. - var lane = requestUpdateLane(provider); - var refreshUpdate = createUpdate(lane); - var root = enqueueUpdate(provider, refreshUpdate, lane); +function warnOnUndefinedDerivedState(type, partialState) { + { + if (partialState === undefined) { + var componentName = getComponentNameFromType(type) || 'Component'; - if (root !== null) { - scheduleUpdateOnFiber(root, provider, lane); - entangleTransitions(root, provider, lane); - } // TODO: If a refresh never commits, the new cache created here must be - // released. A simple case is start refreshing a cache boundary, but then - // unmount that boundary before the refresh completes. + if (!didWarnAboutUndefinedDerivedState.has(componentName)) { + didWarnAboutUndefinedDerivedState.add(componentName); - var seededCache = createCache(); + error('%s.getDerivedStateFromProps(): A valid state object (or null) must be returned. ' + 'You have returned undefined.', componentName); + } + } + } +} - if (seedKey !== null && seedKey !== undefined && root !== null) { - { - { - error( - "The seed argument is not enabled outside experimental channels." - ); - } - } - } +function applyDerivedStateFromProps(workInProgress, ctor, getDerivedStateFromProps, nextProps) { + var prevState = workInProgress.memoizedState; + var partialState = getDerivedStateFromProps(nextProps, prevState); - var payload = { - cache: seededCache - }; - refreshUpdate.payload = payload; - return; - } - } + { + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); - provider = provider.return; - } // TODO: Warn if unmounted? + try { + // Invoke the function an extra time to help detect side-effects. + partialState = getDerivedStateFromProps(nextProps, prevState); + } finally { + setIsStrictModeForDevtools(false); + } } - 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()." - ); - } - } - - var lane = requestUpdateLane(fiber); - var update = { - lane: lane, - revertLane: NoLane, - action: action, - hasEagerState: false, - eagerState: null, - next: null - }; + warnOnUndefinedDerivedState(ctor, partialState); + } // Merge the partial state and the previous state. - if (isRenderPhaseUpdate(fiber)) { - enqueueRenderPhaseUpdate(queue, update); - } else { - var root = enqueueConcurrentHookUpdate(fiber, queue, update, lane); - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, lane); - entangleTransitionUpdate(root, queue, lane); - } - } + 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. - markUpdateInDevTools(fiber, lane); - } + if (workInProgress.lanes === NoLanes) { + // Queue is always non-null for classes + var updateQueue = workInProgress.updateQueue; + updateQueue.baseState = memoizedState; + } +} - function dispatchSetState(fiber, queue, action) { +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) { { - 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()." - ); - } - } - - var lane = requestUpdateLane(fiber); - var update = { - lane: lane, - revertLane: NoLane, - action: action, - hasEagerState: false, - eagerState: null, - next: null - }; + warnOnInvalidCallback(callback); + } - if (isRenderPhaseUpdate(fiber)) { - enqueueRenderPhaseUpdate(queue, update); - } else { - var alternate = fiber.alternate; + update.callback = callback; + } - 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; + var root = enqueueUpdate(fiber, update, lane); - if (lastRenderedReducer !== null) { - var prevDispatcher = null; + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, lane); + entangleTransitions(root, fiber, lane); + } - { - prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = - InvalidNestedHooksDispatcherOnUpdateInDEV; - } + { + 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; - 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. - - update.hasEagerState = true; - update.eagerState = eagerState; - - 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 { - { - ReactSharedInternals.H = prevDispatcher; - } - } - } - } + if (callback !== undefined && callback !== null) { + { + warnOnInvalidCallback(callback); + } - var root = enqueueConcurrentHookUpdate(fiber, queue, update, lane); + update.callback = callback; + } - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, lane); - entangleTransitionUpdate(root, queue, lane); - } - } + var root = enqueueUpdate(fiber, update, lane); - markUpdateInDevTools(fiber, lane); + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, lane); + entangleTransitions(root, fiber, lane); } - function dispatchOptimisticSetState( - fiber, - throwIfDuringRender, - queue, - action - ) { - var transition = requestCurrentTransition(); + { + 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 (callback !== undefined && callback !== null) { { - if (transition === null) { - // An optimistic update occurred, but startTransition is not on the stack. - // There are two likely scenarios. - // One possibility is that the optimistic update is triggered by a regular - // event handler (e.g. `onSubmit`) instead of an action. This is a mistake - // and we will warn. - // The other possibility is the optimistic update is inside an async - // action, but after an `await`. In this case, we can make it "just work" - // by associating the optimistic update with the pending async action. - // Technically it's possible that the optimistic update is unrelated to - // the pending action, but we don't have a way of knowing this for sure - // because browsers currently do not provide a way to track async scope. - // (The AsyncContext proposal, if it lands, will solve this in the - // future.) However, this is no different than the problem of unrelated - // transitions being grouped together — it's not wrong per se, but it's - // not ideal. - // Once AsyncContext starts landing in browsers, we will provide better - // warnings in development for these cases. - if (peekEntangledActionLane() !== NoLane); - else { - // There's no pending async action. The most likely cause is that we're - // inside a regular event handler (e.g. onSubmit) instead of an action. - error( - "An optimistic state update occurred outside a transition or " + - "action. To fix, move the update to an action, or wrap " + - "with startTransition." - ); - } - } + warnOnInvalidCallback(callback); } - var update = { - // An optimistic update commits synchronously. - lane: SyncLane, - // After committing, the optimistic update is "reverted" using the same - // lane as the transition it's associated with. - revertLane: requestTransitionLane(), - action: action, - hasEagerState: false, - eagerState: null, - next: null - }; - - if (isRenderPhaseUpdate(fiber)) { - // When calling startTransition during render, this warns instead of - // throwing because throwing would be a breaking change. setOptimisticState - // is a new API so it's OK to throw. - if (throwIfDuringRender) { - throw new Error("Cannot update optimistic state while rendering."); - } else { - // startTransition was called during render. We don't need to do anything - // besides warn here because the render phase update would be overidden by - // the second update, anyway. We can remove this branch and make it throw - // in a future release. - { - error("Cannot call startTransition while rendering."); - } - } - } else { - var root = enqueueConcurrentHookUpdate(fiber, queue, update, SyncLane); + update.callback = callback; + } - if (root !== null) { - // NOTE: The optimistic update implementation assumes that the transition - // will never be attempted before the optimistic update. This currently - // holds because the optimistic update is always synchronous. If we ever - // change that, we'll need to account for this. - scheduleUpdateOnFiber(root, fiber, SyncLane); // Optimistic updates are always synchronous, so we don't need to call - // entangleTransitionUpdate here. - } - } + var root = enqueueUpdate(fiber, update, lane); - markUpdateInDevTools(fiber, SyncLane); + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, lane); + entangleTransitions(root, fiber, lane); } - function isRenderPhaseUpdate(fiber) { - var alternate = fiber.alternate; - return ( - fiber === currentlyRenderingFiber$1 || - (alternate !== null && alternate === currentlyRenderingFiber$1) - ); + { + markForceUpdateScheduled(fiber, lane); } + } +}; - 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; +function checkShouldComponentUpdate(workInProgress, ctor, oldProps, newProps, oldState, newState, nextContext) { + var instance = workInProgress.stateNode; - if (pending === null) { - // This is the first update. Create a circular list. - update.next = update; - } else { - update.next = pending.next; - pending.next = update; + if (typeof instance.shouldComponentUpdate === 'function') { + var shouldUpdate = instance.shouldComponentUpdate(newProps, newState, nextContext); + + { + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); + + try { + // Invoke the function an extra time to help detect side-effects. + shouldUpdate = instance.shouldComponentUpdate(newProps, newState, nextContext); + } finally { + setIsStrictModeForDevtools(false); + } } - queue.pending = update; - } // TODO: Move to ReactFiberConcurrentUpdates? + if (shouldUpdate === undefined) { + error('%s.shouldComponentUpdate(): Returned undefined instead of a ' + 'boolean value. Make sure to return true or false.', getComponentNameFromType(ctor) || 'Component'); + } + } - 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. + return shouldUpdate; + } - queueLanes = intersectLanes(queueLanes, root.pendingLanes); // Entangle the new transition lane with the other transition lanes. + if (ctor.prototype && ctor.prototype.isPureReactComponent) { + return !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState); + } - 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. + return true; +} - markRootEntangled(root, newQueueLanes); - } - } +function checkClassInstance(workInProgress, ctor, newProps) { + var instance = workInProgress.stateNode; - function markUpdateInDevTools(fiber, lane, action) { - { - markStateUpdateScheduled(fiber, lane); - } - } - - var ContextOnlyDispatcher = { - readContext: readContext, - use: use, - useCallback: throwInvalidHookError, - useContext: throwInvalidHookError, - useEffect: throwInvalidHookError, - useImperativeHandle: throwInvalidHookError, - useLayoutEffect: throwInvalidHookError, - useInsertionEffect: throwInvalidHookError, - useMemo: throwInvalidHookError, - useReducer: throwInvalidHookError, - useRef: throwInvalidHookError, - useState: throwInvalidHookError, - useDebugValue: throwInvalidHookError, - useDeferredValue: throwInvalidHookError, - useTransition: throwInvalidHookError, - useSyncExternalStore: throwInvalidHookError, - useId: throwInvalidHookError - }; + { + var name = getComponentNameFromType(ctor) || 'Component'; + var renderPresent = instance.render; - { - ContextOnlyDispatcher.useCacheRefresh = throwInvalidHookError; + if (!renderPresent) { + if (ctor.prototype && typeof ctor.prototype.render === 'function') { + error('No `render` method found on the %s ' + 'instance: did you accidentally return an object from the constructor?', name); + } else { + error('No `render` method found on the %s ' + 'instance: you may have forgotten to define `render`.', name); + } } - { - ContextOnlyDispatcher.useMemoCache = throwInvalidHookError; + 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); } - if (enableAsyncActions) { - ContextOnlyDispatcher.useHostTransitionStatus = throwInvalidHookError; - ContextOnlyDispatcher.useFormState = throwInvalidHookError; - ContextOnlyDispatcher.useActionState = throwInvalidHookError; + 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); } - if (enableAsyncActions) { - ContextOnlyDispatcher.useOptimistic = throwInvalidHookError; + if (instance.propTypes) { + error('propTypes was defined as an instance property on %s. Use a static ' + 'property to define propTypes instead.', name); } - var HooksDispatcherOnMountInDEV = null; - var HooksDispatcherOnMountWithHookTypesInDEV = null; - var HooksDispatcherOnUpdateInDEV = null; - var HooksDispatcherOnRerenderInDEV = null; - var InvalidNestedHooksDispatcherOnMountInDEV = null; - var InvalidNestedHooksDispatcherOnUpdateInDEV = null; - var InvalidNestedHooksDispatcherOnRerenderInDEV = null; + if (instance.contextType) { + error('contextType was defined as an instance property on %s. Use a static ' + 'property to define contextType instead.', name); + } { - 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 (instance.contextTypes) { + error('contextTypes was defined as an instance property on %s. Use a static ' + 'property to define contextTypes instead.', name); + } - 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://react.dev/link/rules-of-hooks" - ); - }; + if (ctor.contextType && ctor.contextTypes && !didWarnAboutContextTypeAndContextTypes.has(ctor)) { + didWarnAboutContextTypeAndContextTypes.add(ctor); - HooksDispatcherOnMountInDEV = { - readContext: function (context) { - return readContext(context); - }, - use: use, - 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 = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; + error('%s declares both contextTypes and contextType static properties. ' + 'The legacy contextTypes property will be ignored.', name); + } + } - try { - return mountMemo(create, deps); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useReducer: function (reducer, initialArg, init) { - currentHookNameInDev = "useReducer"; - mountHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; + 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); + } - try { - return mountReducer(reducer, initialArg, init); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useRef: function (initialValue) { - currentHookNameInDev = "useRef"; - mountHookTypesDev(); - return mountRef(initialValue); - }, - useState: function (initialState) { - currentHookNameInDev = "useState"; - mountHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; + 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'); + } - try { - return mountState(initialState); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useDebugValue: function (value, formatterFn) { - currentHookNameInDev = "useDebugValue"; - mountHookTypesDev(); - return mountDebugValue(); - }, - useDeferredValue: function (value, initialValue) { - currentHookNameInDev = "useDeferredValue"; - mountHookTypesDev(); - return mountDeferredValue(value, initialValue); - }, - useTransition: function () { - currentHookNameInDev = "useTransition"; - mountHookTypesDev(); - return mountTransition(); - }, - useSyncExternalStore: function ( - subscribe, - getSnapshot, - getServerSnapshot - ) { - currentHookNameInDev = "useSyncExternalStore"; - mountHookTypesDev(); - return mountSyncExternalStore(subscribe, getSnapshot); - }, - useId: function () { - currentHookNameInDev = "useId"; - mountHookTypesDev(); - return mountId(); - } - }; + if (typeof instance.componentDidUnmount === 'function') { + error('%s has a method called ' + 'componentDidUnmount(). But there is no such lifecycle method. ' + 'Did you mean componentWillUnmount()?', name); + } - { - HooksDispatcherOnMountInDEV.useCacheRefresh = - function useCacheRefresh() { - currentHookNameInDev = "useCacheRefresh"; - mountHookTypesDev(); - return mountRefresh(); - }; - } + 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); + } - { - HooksDispatcherOnMountInDEV.useMemoCache = useMemoCache; - } + if (typeof instance.componentWillRecieveProps === 'function') { + error('%s has a method called ' + 'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?', name); + } - if (enableAsyncActions) { - HooksDispatcherOnMountInDEV.useHostTransitionStatus = - useHostTransitionStatus; + if (typeof instance.UNSAFE_componentWillRecieveProps === 'function') { + error('%s has a method called ' + 'UNSAFE_componentWillRecieveProps(). Did you mean UNSAFE_componentWillReceiveProps()?', name); + } - HooksDispatcherOnMountInDEV.useFormState = function useFormState( - action, - initialState, - permalink - ) { - currentHookNameInDev = "useFormState"; - mountHookTypesDev(); - return mountActionState(action, initialState); - }; + var hasMutatedProps = instance.props !== newProps; - HooksDispatcherOnMountInDEV.useActionState = function useActionState( - action, - initialState, - permalink - ) { - currentHookNameInDev = "useActionState"; - mountHookTypesDev(); - return mountActionState(action, initialState); - }; - } + if (instance.props !== undefined && hasMutatedProps) { + error('When calling super() in `%s`, make sure to pass ' + "up the same props that your component's constructor was passed.", name); + } - if (enableAsyncActions) { - HooksDispatcherOnMountInDEV.useOptimistic = function useOptimistic( - passthrough, - reducer - ) { - currentHookNameInDev = "useOptimistic"; - mountHookTypesDev(); - return mountOptimistic(passthrough); - }; - } + 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); + } - HooksDispatcherOnMountWithHookTypesInDEV = { - readContext: function (context) { - return readContext(context); - }, - use: use, - 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 = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; + if (typeof instance.getSnapshotBeforeUpdate === 'function' && typeof instance.componentDidUpdate !== 'function' && !didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.has(ctor)) { + didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.add(ctor); - try { - return mountMemo(create, deps); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useReducer: function (reducer, initialArg, init) { - currentHookNameInDev = "useReducer"; - updateHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; + error('%s: getSnapshotBeforeUpdate() should be used with componentDidUpdate(). ' + 'This component defines getSnapshotBeforeUpdate() only.', getComponentNameFromType(ctor)); + } - try { - return mountReducer(reducer, initialArg, init); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useRef: function (initialValue) { - currentHookNameInDev = "useRef"; - updateHookTypesDev(); - return mountRef(initialValue); - }, - useState: function (initialState) { - currentHookNameInDev = "useState"; - updateHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; + 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); + } - try { - return mountState(initialState); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useDebugValue: function (value, formatterFn) { - currentHookNameInDev = "useDebugValue"; - updateHookTypesDev(); - return mountDebugValue(); - }, - useDeferredValue: function (value, initialValue) { - currentHookNameInDev = "useDeferredValue"; - updateHookTypesDev(); - return mountDeferredValue(value, initialValue); - }, - useTransition: function () { - currentHookNameInDev = "useTransition"; - updateHookTypesDev(); - return mountTransition(); - }, - useSyncExternalStore: function ( - subscribe, - getSnapshot, - getServerSnapshot - ) { - currentHookNameInDev = "useSyncExternalStore"; - updateHookTypesDev(); - return mountSyncExternalStore(subscribe, getSnapshot); - }, - useId: function () { - currentHookNameInDev = "useId"; - updateHookTypesDev(); - return mountId(); - } - }; + 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); + } - { - HooksDispatcherOnMountWithHookTypesInDEV.useCacheRefresh = - function useCacheRefresh() { - currentHookNameInDev = "useCacheRefresh"; - updateHookTypesDev(); - return mountRefresh(); - }; - } + 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); + } - { - HooksDispatcherOnMountWithHookTypesInDEV.useMemoCache = useMemoCache; - } + var state = instance.state; - if (enableAsyncActions) { - HooksDispatcherOnMountWithHookTypesInDEV.useHostTransitionStatus = - useHostTransitionStatus; + if (state && (typeof state !== 'object' || isArray(state))) { + error('%s.state: must be set to an object or null', name); + } - HooksDispatcherOnMountWithHookTypesInDEV.useFormState = - function useFormState(action, initialState, permalink) { - currentHookNameInDev = "useFormState"; - updateHookTypesDev(); - warnOnUseFormStateInDev(); - return mountActionState(action, initialState); - }; + if (typeof instance.getChildContext === 'function' && typeof ctor.childContextTypes !== 'object') { + error('%s.getChildContext(): childContextTypes must be defined in order to ' + 'use getChildContext().', name); + } + } +} - HooksDispatcherOnMountWithHookTypesInDEV.useActionState = - function useActionState(action, initialState, permalink) { - currentHookNameInDev = "useActionState"; - updateHookTypesDev(); - return mountActionState(action, initialState); - }; - } +function constructClassInstance(workInProgress, ctor, props) { + var isLegacyContextConsumer = false; + var unmaskedContext = emptyContextObject; + var context = emptyContextObject; + var contextType = ctor.contextType; + + { + if ('contextType' in ctor) { + var isValid = // Allow null for conditional declaration + contextType === null || contextType !== undefined && contextType.$$typeof === REACT_CONTEXT_TYPE; + + if (!isValid && !didWarnAboutInvalidateContextType.has(ctor)) { + didWarnAboutInvalidateContextType.add(ctor); + var addendum = ''; + + 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_CONSUMER_TYPE) { + 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 (enableAsyncActions) { - HooksDispatcherOnMountWithHookTypesInDEV.useOptimistic = - function useOptimistic(passthrough, reducer) { - currentHookNameInDev = "useOptimistic"; - updateHookTypesDev(); - return mountOptimistic(passthrough); - }; + error('%s defines an invalid contextType. ' + 'contextType should point to the Context object returned by React.createContext().%s', getComponentNameFromType(ctor) || 'Component', addendum); } + } + } - HooksDispatcherOnUpdateInDEV = { - readContext: function (context) { - return readContext(context); - }, - use: use, - 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 = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; - - try { - return updateMemo(create, deps); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useReducer: function (reducer, initialArg, init) { - currentHookNameInDev = "useReducer"; - updateHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; + 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; + } - try { - return updateReducer(reducer, initialArg, init); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useRef: function (initialValue) { - currentHookNameInDev = "useRef"; - updateHookTypesDev(); - return updateRef(); - }, - useState: function (initialState) { - currentHookNameInDev = "useState"; - updateHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; + var instance = new ctor(props, context); // Instantiate twice to help detect side-effects. - try { - return updateState(initialState); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useDebugValue: function (value, formatterFn) { - currentHookNameInDev = "useDebugValue"; - updateHookTypesDev(); - return updateDebugValue(); - }, - useDeferredValue: function (value, initialValue) { - currentHookNameInDev = "useDeferredValue"; - updateHookTypesDev(); - return updateDeferredValue(value, initialValue); - }, - useTransition: function () { - currentHookNameInDev = "useTransition"; - updateHookTypesDev(); - return updateTransition(); - }, - useSyncExternalStore: function ( - subscribe, - getSnapshot, - getServerSnapshot - ) { - currentHookNameInDev = "useSyncExternalStore"; - updateHookTypesDev(); - return updateSyncExternalStore(subscribe, getSnapshot); - }, - useId: function () { - currentHookNameInDev = "useId"; - updateHookTypesDev(); - return updateId(); - } - }; + { + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); - { - HooksDispatcherOnUpdateInDEV.useCacheRefresh = - function useCacheRefresh() { - currentHookNameInDev = "useCacheRefresh"; - updateHookTypesDev(); - return updateRefresh(); - }; + try { + instance = new ctor(props, context); // eslint-disable-line no-new + } finally { + setIsStrictModeForDevtools(false); } + } + } - { - HooksDispatcherOnUpdateInDEV.useMemoCache = useMemoCache; - } - - if (enableAsyncActions) { - HooksDispatcherOnUpdateInDEV.useHostTransitionStatus = - useHostTransitionStatus; - - HooksDispatcherOnUpdateInDEV.useFormState = function useFormState( - action, - initialState, - permalink - ) { - currentHookNameInDev = "useFormState"; - updateHookTypesDev(); - warnOnUseFormStateInDev(); - return updateActionState(action); - }; + var state = workInProgress.memoizedState = instance.state !== null && instance.state !== undefined ? instance.state : null; + instance.updater = classComponentUpdater; + workInProgress.stateNode = instance; // The instance needs access to the fiber so that it can schedule updates - HooksDispatcherOnUpdateInDEV.useActionState = function useActionState( - action, - initialState, - permalink - ) { - currentHookNameInDev = "useActionState"; - updateHookTypesDev(); - return updateActionState(action); - }; - } + set(instance, workInProgress); - if (enableAsyncActions) { - HooksDispatcherOnUpdateInDEV.useOptimistic = function useOptimistic( - passthrough, - reducer - ) { - currentHookNameInDev = "useOptimistic"; - updateHookTypesDev(); - return updateOptimistic(passthrough, reducer); - }; - } + { + instance._reactInternalInstance = fakeInternalInstance; + } - HooksDispatcherOnRerenderInDEV = { - readContext: function (context) { - return readContext(context); - }, - use: use, - 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 = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnRerenderInDEV; + { + if (typeof ctor.getDerivedStateFromProps === 'function' && state === null) { + var componentName = getComponentNameFromType(ctor) || 'Component'; - try { - return updateMemo(create, deps); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useReducer: function (reducer, initialArg, init) { - currentHookNameInDev = "useReducer"; - updateHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnRerenderInDEV; + if (!didWarnAboutUninitializedState.has(componentName)) { + didWarnAboutUninitializedState.add(componentName); - try { - return rerenderReducer(reducer, initialArg, init); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useRef: function (initialValue) { - currentHookNameInDev = "useRef"; - updateHookTypesDev(); - return updateRef(); - }, - useState: function (initialState) { - currentHookNameInDev = "useState"; - updateHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnRerenderInDEV; + 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. - try { - return rerenderState(initialState); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useDebugValue: function (value, formatterFn) { - currentHookNameInDev = "useDebugValue"; - updateHookTypesDev(); - return updateDebugValue(); - }, - useDeferredValue: function (value, initialValue) { - currentHookNameInDev = "useDeferredValue"; - updateHookTypesDev(); - return rerenderDeferredValue(value, initialValue); - }, - useTransition: function () { - currentHookNameInDev = "useTransition"; - updateHookTypesDev(); - return rerenderTransition(); - }, - useSyncExternalStore: function ( - subscribe, - getSnapshot, - getServerSnapshot - ) { - currentHookNameInDev = "useSyncExternalStore"; - updateHookTypesDev(); - return updateSyncExternalStore(subscribe, getSnapshot); - }, - useId: function () { - currentHookNameInDev = "useId"; - updateHookTypesDev(); - return updateId(); - } - }; - { - HooksDispatcherOnRerenderInDEV.useCacheRefresh = - function useCacheRefresh() { - currentHookNameInDev = "useCacheRefresh"; - updateHookTypesDev(); - return updateRefresh(); - }; - } + if (typeof ctor.getDerivedStateFromProps === 'function' || typeof instance.getSnapshotBeforeUpdate === 'function') { + var foundWillMountName = null; + var foundWillReceivePropsName = null; + var foundWillUpdateName = null; - { - HooksDispatcherOnRerenderInDEV.useMemoCache = useMemoCache; - } - - if (enableAsyncActions) { - HooksDispatcherOnRerenderInDEV.useHostTransitionStatus = - useHostTransitionStatus; - - HooksDispatcherOnRerenderInDEV.useFormState = function useFormState( - action, - initialState, - permalink - ) { - currentHookNameInDev = "useFormState"; - updateHookTypesDev(); - warnOnUseFormStateInDev(); - return rerenderActionState(action); - }; + if (typeof instance.componentWillMount === 'function' && instance.componentWillMount.__suppressDeprecationWarning !== true) { + foundWillMountName = 'componentWillMount'; + } else if (typeof instance.UNSAFE_componentWillMount === 'function') { + foundWillMountName = 'UNSAFE_componentWillMount'; + } - HooksDispatcherOnRerenderInDEV.useActionState = function useActionState( - action, - initialState, - permalink - ) { - currentHookNameInDev = "useActionState"; - updateHookTypesDev(); - return rerenderActionState(action); - }; + if (typeof instance.componentWillReceiveProps === 'function' && instance.componentWillReceiveProps.__suppressDeprecationWarning !== true) { + foundWillReceivePropsName = 'componentWillReceiveProps'; + } else if (typeof instance.UNSAFE_componentWillReceiveProps === 'function') { + foundWillReceivePropsName = 'UNSAFE_componentWillReceiveProps'; } - if (enableAsyncActions) { - HooksDispatcherOnRerenderInDEV.useOptimistic = function useOptimistic( - passthrough, - reducer - ) { - currentHookNameInDev = "useOptimistic"; - updateHookTypesDev(); - return rerenderOptimistic(passthrough, reducer); - }; + if (typeof instance.componentWillUpdate === 'function' && instance.componentWillUpdate.__suppressDeprecationWarning !== true) { + foundWillUpdateName = 'componentWillUpdate'; + } else if (typeof instance.UNSAFE_componentWillUpdate === 'function') { + foundWillUpdateName = 'UNSAFE_componentWillUpdate'; } - InvalidNestedHooksDispatcherOnMountInDEV = { - readContext: function (context) { - warnInvalidContextAccess(); - return readContext(context); - }, - use: function (usable) { - warnInvalidHookAccess(); - return use(usable); - }, - 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 = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; + if (foundWillMountName !== null || foundWillReceivePropsName !== null || foundWillUpdateName !== null) { + var _componentName = getComponentNameFromType(ctor) || 'Component'; - try { - return mountMemo(create, deps); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useReducer: function (reducer, initialArg, init) { - currentHookNameInDev = "useReducer"; - warnInvalidHookAccess(); - mountHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; + var newApiName = typeof ctor.getDerivedStateFromProps === 'function' ? 'getDerivedStateFromProps()' : 'getSnapshotBeforeUpdate()'; - try { - return mountReducer(reducer, initialArg, init); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useRef: function (initialValue) { - currentHookNameInDev = "useRef"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountRef(initialValue); - }, - useState: function (initialState) { - currentHookNameInDev = "useState"; - warnInvalidHookAccess(); - mountHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV; + if (!didWarnAboutLegacyLifecyclesAndDerivedState.has(_componentName)) { + didWarnAboutLegacyLifecyclesAndDerivedState.add(_componentName); - try { - return mountState(initialState); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useDebugValue: function (value, formatterFn) { - currentHookNameInDev = "useDebugValue"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountDebugValue(); - }, - useDeferredValue: function (value, initialValue) { - currentHookNameInDev = "useDeferredValue"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountDeferredValue(value, initialValue); - }, - useTransition: function () { - currentHookNameInDev = "useTransition"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountTransition(); - }, - useSyncExternalStore: function ( - subscribe, - getSnapshot, - getServerSnapshot - ) { - currentHookNameInDev = "useSyncExternalStore"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountSyncExternalStore(subscribe, getSnapshot); - }, - useId: function () { - currentHookNameInDev = "useId"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountId(); + 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://react.dev/link/unsafe-component-lifecycles', _componentName, newApiName, foundWillMountName !== null ? "\n " + foundWillMountName : '', foundWillReceivePropsName !== null ? "\n " + foundWillReceivePropsName : '', foundWillUpdateName !== null ? "\n " + foundWillUpdateName : ''); } - }; - - { - InvalidNestedHooksDispatcherOnMountInDEV.useCacheRefresh = - function useCacheRefresh() { - currentHookNameInDev = "useCacheRefresh"; - mountHookTypesDev(); - return mountRefresh(); - }; } + } + } // Cache unmasked context so we can avoid recreating masked context unless necessary. + // ReactFiberContext usually updates this cache but can't for newly-created instances. - { - InvalidNestedHooksDispatcherOnMountInDEV.useMemoCache = function ( - size - ) { - warnInvalidHookAccess(); - return useMemoCache(size); - }; - } - if (enableAsyncActions) { - InvalidNestedHooksDispatcherOnMountInDEV.useHostTransitionStatus = - useHostTransitionStatus; + if (isLegacyContextConsumer) { + cacheContext(workInProgress, unmaskedContext, context); + } - InvalidNestedHooksDispatcherOnMountInDEV.useFormState = - function useFormState(action, initialState, permalink) { - currentHookNameInDev = "useFormState"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountActionState(action, initialState); - }; + return instance; +} - InvalidNestedHooksDispatcherOnMountInDEV.useActionState = - function useActionState(action, initialState, permalink) { - currentHookNameInDev = "useActionState"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountActionState(action, initialState); - }; - } +function callComponentWillMount(workInProgress, instance) { + var oldState = instance.state; - if (enableAsyncActions) { - InvalidNestedHooksDispatcherOnMountInDEV.useOptimistic = - function useOptimistic(passthrough, reducer) { - currentHookNameInDev = "useOptimistic"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountOptimistic(passthrough); - }; - } + if (typeof instance.componentWillMount === 'function') { + instance.componentWillMount(); + } - InvalidNestedHooksDispatcherOnUpdateInDEV = { - readContext: function (context) { - warnInvalidContextAccess(); - return readContext(context); - }, - use: function (usable) { - warnInvalidHookAccess(); - return use(usable); - }, - 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 = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; + if (typeof instance.UNSAFE_componentWillMount === 'function') { + instance.UNSAFE_componentWillMount(); + } - try { - return updateMemo(create, deps); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useReducer: function (reducer, initialArg, init) { - currentHookNameInDev = "useReducer"; - warnInvalidHookAccess(); - updateHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; + 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'); + } - try { - return updateReducer(reducer, initialArg, init); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useRef: function (initialValue) { - currentHookNameInDev = "useRef"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateRef(); - }, - useState: function (initialState) { - currentHookNameInDev = "useState"; - warnInvalidHookAccess(); - updateHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; + classComponentUpdater.enqueueReplaceState(instance, instance.state, null); + } +} - try { - return updateState(initialState); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useDebugValue: function (value, formatterFn) { - currentHookNameInDev = "useDebugValue"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateDebugValue(); - }, - useDeferredValue: function (value, initialValue) { - currentHookNameInDev = "useDeferredValue"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateDeferredValue(value, initialValue); - }, - useTransition: function () { - currentHookNameInDev = "useTransition"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateTransition(); - }, - useSyncExternalStore: function ( - subscribe, - getSnapshot, - getServerSnapshot - ) { - currentHookNameInDev = "useSyncExternalStore"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateSyncExternalStore(subscribe, getSnapshot); - }, - useId: function () { - currentHookNameInDev = "useId"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateId(); - } - }; +function callComponentWillReceiveProps(workInProgress, instance, newProps, nextContext) { + var oldState = instance.state; - { - InvalidNestedHooksDispatcherOnUpdateInDEV.useCacheRefresh = - function useCacheRefresh() { - currentHookNameInDev = "useCacheRefresh"; - updateHookTypesDev(); - return updateRefresh(); - }; - } + if (typeof instance.componentWillReceiveProps === 'function') { + instance.componentWillReceiveProps(newProps, nextContext); + } + + if (typeof instance.UNSAFE_componentWillReceiveProps === 'function') { + instance.UNSAFE_componentWillReceiveProps(newProps, nextContext); + } + + if (instance.state !== oldState) { + { + var componentName = getComponentNameFromFiber(workInProgress) || 'Component'; - { - InvalidNestedHooksDispatcherOnUpdateInDEV.useMemoCache = function ( - size - ) { - warnInvalidHookAccess(); - return useMemoCache(size); - }; + 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); } + } - if (enableAsyncActions) { - InvalidNestedHooksDispatcherOnUpdateInDEV.useHostTransitionStatus = - useHostTransitionStatus; + classComponentUpdater.enqueueReplaceState(instance, instance.state, null); + } +} // Invokes the mount life-cycles on a previously never rendered instance. - InvalidNestedHooksDispatcherOnUpdateInDEV.useFormState = - function useFormState(action, initialState, permalink) { - currentHookNameInDev = "useFormState"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateActionState(action); - }; - InvalidNestedHooksDispatcherOnUpdateInDEV.useActionState = - function useActionState(action, initialState, permalink) { - currentHookNameInDev = "useActionState"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateActionState(action); - }; - } +function mountClassInstance(workInProgress, ctor, newProps, renderLanes) { + { + checkClassInstance(workInProgress, ctor, newProps); + } - if (enableAsyncActions) { - InvalidNestedHooksDispatcherOnUpdateInDEV.useOptimistic = - function useOptimistic(passthrough, reducer) { - currentHookNameInDev = "useOptimistic"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateOptimistic(passthrough, reducer); - }; + 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); + } + + { + if (instance.state === newProps) { + var componentName = getComponentNameFromType(ctor) || 'Component'; + + 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); } + } - InvalidNestedHooksDispatcherOnRerenderInDEV = { - readContext: function (context) { - warnInvalidContextAccess(); - return readContext(context); - }, - use: function (usable) { - warnInvalidHookAccess(); - return use(usable); - }, - 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 = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; + if (workInProgress.mode & StrictLegacyMode) { + ReactStrictModeWarnings.recordLegacyContextWarning(workInProgress, instance); + } - try { - return updateMemo(create, deps); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useReducer: function (reducer, initialArg, init) { - currentHookNameInDev = "useReducer"; - warnInvalidHookAccess(); - updateHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; + ReactStrictModeWarnings.recordUnsafeLifecycleWarnings(workInProgress, instance); + } - try { - return rerenderReducer(reducer, initialArg, init); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useRef: function (initialValue) { - currentHookNameInDev = "useRef"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateRef(); - }, - useState: function (initialState) { - currentHookNameInDev = "useState"; - warnInvalidHookAccess(); - updateHookTypesDev(); - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV; + instance.state = workInProgress.memoizedState; + var getDerivedStateFromProps = ctor.getDerivedStateFromProps; - try { - return rerenderState(initialState); - } finally { - ReactSharedInternals.H = prevDispatcher; - } - }, - useDebugValue: function (value, formatterFn) { - currentHookNameInDev = "useDebugValue"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateDebugValue(); - }, - useDeferredValue: function (value, initialValue) { - currentHookNameInDev = "useDeferredValue"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return rerenderDeferredValue(value, initialValue); - }, - useTransition: function () { - currentHookNameInDev = "useTransition"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return rerenderTransition(); - }, - useSyncExternalStore: function ( - subscribe, - getSnapshot, - getServerSnapshot - ) { - currentHookNameInDev = "useSyncExternalStore"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateSyncExternalStore(subscribe, getSnapshot); - }, - useId: function () { - currentHookNameInDev = "useId"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateId(); - } - }; + 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. - { - InvalidNestedHooksDispatcherOnRerenderInDEV.useCacheRefresh = - function useCacheRefresh() { - currentHookNameInDev = "useCacheRefresh"; - updateHookTypesDev(); - return updateRefresh(); - }; - } - { - InvalidNestedHooksDispatcherOnRerenderInDEV.useMemoCache = function ( - size - ) { - warnInvalidHookAccess(); - return useMemoCache(size); - }; - } + 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 (enableAsyncActions) { - InvalidNestedHooksDispatcherOnRerenderInDEV.useHostTransitionStatus = - useHostTransitionStatus; + processUpdateQueue(workInProgress, newProps, instance, renderLanes); + suspendIfUpdateReadFromEntangledAsyncAction(); + instance.state = workInProgress.memoizedState; + } - InvalidNestedHooksDispatcherOnRerenderInDEV.useFormState = - function useFormState(action, initialState, permalink) { - currentHookNameInDev = "useFormState"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return rerenderActionState(action); - }; + if (typeof instance.componentDidMount === 'function') { + workInProgress.flags |= Update | LayoutStatic; + } - InvalidNestedHooksDispatcherOnRerenderInDEV.useActionState = - function useActionState(action, initialState, permalink) { - currentHookNameInDev = "useActionState"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return rerenderActionState(action); - }; + if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { + workInProgress.flags |= MountLayoutDev; + } +} + +function resumeMountClassInstance(workInProgress, ctor, newProps, renderLanes) { + var instance = workInProgress.stateNode; + var unresolvedOldProps = workInProgress.memoizedProps; + var oldProps = resolveClassComponentProps(ctor, unresolvedOldProps, workInProgress.type === workInProgress.elementType); + 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); + } + + var getDerivedStateFromProps = ctor.getDerivedStateFromProps; + var hasNewLifecycles = typeof getDerivedStateFromProps === 'function' || typeof instance.getSnapshotBeforeUpdate === 'function'; // When comparing whether props changed, we should compare using the + // unresolved props object that is stored on the fiber, rather than the + // one that gets assigned to the instance, because that object may have been + // cloned to resolve default props and/or remove `ref`. + + var unresolvedNewProps = workInProgress.pendingProps; + var didReceiveNewProps = unresolvedNewProps !== unresolvedOldProps; // 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 (didReceiveNewProps || oldContext !== nextContext) { + callComponentWillReceiveProps(workInProgress, instance, newProps, nextContext); + } + } + + resetHasForceUpdateBeforeProcessing(); + var oldState = workInProgress.memoizedState; + var newState = instance.state = oldState; + processUpdateQueue(workInProgress, newProps, instance, renderLanes); + suspendIfUpdateReadFromEntangledAsyncAction(); + newState = workInProgress.memoizedState; + + if (!didReceiveNewProps && 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') { + workInProgress.flags |= Update | LayoutStatic; + } + + if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { + workInProgress.flags |= MountLayoutDev; + } + + return false; + } + + if (typeof getDerivedStateFromProps === 'function') { + applyDerivedStateFromProps(workInProgress, ctor, getDerivedStateFromProps, newProps); + newState = workInProgress.memoizedState; + } + + 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 (enableAsyncActions) { - InvalidNestedHooksDispatcherOnRerenderInDEV.useOptimistic = - function useOptimistic(passthrough, reducer) { - currentHookNameInDev = "useOptimistic"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return rerenderOptimistic(passthrough, reducer); - }; + if (typeof instance.UNSAFE_componentWillMount === 'function') { + instance.UNSAFE_componentWillMount(); } } - 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; + if (typeof instance.componentDidMount === 'function') { + workInProgress.flags |= Update | LayoutStatic; + } - function isCurrentUpdateNested() { - return currentUpdateIsNested; + if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { + workInProgress.flags |= MountLayoutDev; + } + } 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') { + workInProgress.flags |= Update | LayoutStatic; } - function markNestedUpdateScheduled() { - { - nestedUpdateScheduled = true; - } + if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { + workInProgress.flags |= MountLayoutDev; + } // 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 = resolveClassComponentProps(ctor, unresolvedOldProps, workInProgress.type === workInProgress.elementType); + 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); } + } - function resetNestedUpdateFlag() { - { - currentUpdateIsNested = false; - nestedUpdateScheduled = false; + resetHasForceUpdateBeforeProcessing(); + var oldState = workInProgress.memoizedState; + var newState = instance.state = oldState; + processUpdateQueue(workInProgress, newProps, instance, renderLanes); + suspendIfUpdateReadFromEntangledAsyncAction(); + 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; } } - function syncNestedUpdateFlag() { - { - currentUpdateIsNested = nestedUpdateScheduled; - nestedUpdateScheduled = false; + if (typeof instance.getSnapshotBeforeUpdate === 'function') { + if (unresolvedOldProps !== current.memoizedProps || oldState !== current.memoizedState) { + workInProgress.flags |= Snapshot; } } - function getCommitTime() { - return commitTime; - } + return false; + } - function recordCommitTime() { - commitTime = now(); - } + if (typeof getDerivedStateFromProps === 'function') { + applyDerivedStateFromProps(workInProgress, ctor, getDerivedStateFromProps, newProps); + newState = workInProgress.memoizedState; + } - function startProfilerTimer(fiber) { - profilerStartTime = now(); + 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 (fiber.actualStartTime < 0) { - fiber.actualStartTime = now(); + 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); } - } - function stopProfilerTimerIfRunning(fiber) { - profilerStartTime = -1; + if (typeof instance.UNSAFE_componentWillUpdate === 'function') { + instance.UNSAFE_componentWillUpdate(newProps, newState, nextContext); + } } - function stopProfilerTimerIfRunningAndRecordDelta(fiber, overrideBaseTime) { - if (profilerStartTime >= 0) { - var elapsedTime = now() - profilerStartTime; - fiber.actualDuration += elapsedTime; - - if (overrideBaseTime) { - fiber.selfBaseDuration = elapsedTime; - } + if (typeof instance.componentDidUpdate === 'function') { + workInProgress.flags |= Update; + } - profilerStartTime = -1; + 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 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) + 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. - var parentFiber = fiber.return; - while (parentFiber !== null) { - switch (parentFiber.tag) { - case HostRoot: - var root = parentFiber.stateNode; - root.effectDuration += elapsedTime; - return; + workInProgress.memoizedProps = newProps; + workInProgress.memoizedState = newState; + } // Update the existing instance's state, props, and context pointers even + // if shouldComponentUpdate returns false. - case Profiler: - var parentStateNode = parentFiber.stateNode; - parentStateNode.effectDuration += elapsedTime; - return; - } - parentFiber = parentFiber.return; - } - } - } + instance.props = newProps; + instance.state = newState; + instance.context = nextContext; + return shouldUpdate; +} - 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) +function resolveClassComponentProps(Component, baseProps, // Only resolve default props if this is a lazy component. Otherwise, they +// would have already been resolved by the JSX runtime. +// TODO: We're going to remove default prop resolution from the JSX runtime +// and keep it only for class components. As part of that change, we should +// remove this extra check. +alreadyResolvedDefaultProps) { + var newProps = baseProps; - var parentFiber = fiber.return; - while (parentFiber !== null) { - switch (parentFiber.tag) { - case HostRoot: - var root = parentFiber.stateNode; + var defaultProps = Component.defaultProps; - if (root !== null) { - root.passiveEffectDuration += elapsedTime; - } + if (defaultProps && ( // If disableDefaultPropsExceptForClasses is true, we always resolve + // default props here in the reconciler, rather than in the JSX runtime. + disableDefaultPropsExceptForClasses || !alreadyResolvedDefaultProps)) { + // We may have already copied the props object above to remove ref. If so, + // we can modify that. Otherwise, copy the props object with Object.assign. + if (newProps === baseProps) { + newProps = assign({}, newProps); + } // Taken from old JSX runtime, where this used to live. - return; - case Profiler: - var parentStateNode = parentFiber.stateNode; + for (var _propName in defaultProps) { + if (newProps[_propName] === undefined) { + newProps[_propName] = defaultProps[_propName]; + } + } + } - 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; - } + return newProps; +} - return; - } +function resolveDefaultPropsOnNonClassComponent(Component, baseProps) { + if (disableDefaultPropsExceptForClasses) { + // Support for defaultProps is removed in React 19 for all types + // except classes. + return baseProps; + } - parentFiber = parentFiber.return; - } + if (Component && Component.defaultProps) { + // Resolve default props. Taken from ReactElement + var props = assign({}, baseProps); + var defaultProps = Component.defaultProps; + + for (var propName in defaultProps) { + if (props[propName] === undefined) { + props[propName] = defaultProps[propName]; } } - function startLayoutEffectTimer() { - layoutEffectStartTime = now(); - } + return props; + } + + return baseProps; +} - function startPassiveEffectTimer() { - passiveEffectStartTime = now(); +var reportGlobalError = typeof reportError === 'function' ? // In modern browsers, reportError will dispatch an error event, +// emulating an uncaught JavaScript error. +reportError : function (error) { + if (typeof window === 'object' && typeof window.ErrorEvent === 'function') { + // Browser Polyfill + var message = typeof error === 'object' && error !== null && typeof error.message === 'string' ? // eslint-disable-next-line react-internal/safe-string-coercion + String(error.message) : // eslint-disable-next-line react-internal/safe-string-coercion + String(error); + var event = new window.ErrorEvent('error', { + bubbles: true, + cancelable: true, + message: message, + error: error + }); + var shouldLog = window.dispatchEvent(event); + + if (!shouldLog) { + return; + } + } else if (typeof process === 'object' && // $FlowFixMe[method-unbinding] + typeof process.emit === 'function') { + // Node Polyfill + process.emit('uncaughtException', error); + return; + } // eslint-disable-next-line react-internal/no-production-logging + + + console['error'](error); +}; + +var componentName = null; +var errorBoundaryName = null; +function defaultOnUncaughtError(error, errorInfo) { + // Overriding this can silence these warnings e.g. for tests. + // See https://github.com/facebook/react/pull/13384 + // For uncaught root errors we report them as uncaught to the browser's + // onerror callback. This won't have component stacks and the error addendum. + // So we add those into a separate console.warn. + reportGlobalError(error); + + { + var componentStack = errorInfo.componentStack != null ? errorInfo.componentStack : ''; + var componentNameMessage = componentName ? "An error occurred in the <" + componentName + "> component:" : 'An error occurred in one of your React components:'; + console['warn']('%s\n%s\n\n%s', componentNameMessage, componentStack || '', 'Consider adding an error boundary to your tree to customize error handling behavior.\n' + 'Visit https://react.dev/link/error-boundaries to learn more about error boundaries.'); + } +} +function defaultOnCaughtError(error, errorInfo) { + // Overriding this can silence these warnings e.g. for tests. + // See https://github.com/facebook/react/pull/13384 + // Caught by error boundary + { + var componentStack = errorInfo.componentStack != null ? errorInfo.componentStack : ''; + var componentNameMessage = componentName ? "The above error occurred in the <" + componentName + "> component:" : 'The above error occurred in one of your React components:'; // In development, we provide our own message which includes the component stack + // in addition to the error. + // Don't transform to our wrapper + + console['error']('%o\n\n%s\n%s\n\n%s', error, componentNameMessage, componentStack, "React will try to recreate this component tree from scratch " + ("using the error boundary you provided, " + (errorBoundaryName || 'Anonymous') + ".")); + } +} +function defaultOnRecoverableError(error, errorInfo) { + reportGlobalError(error); +} +function logUncaughtError(root, errorInfo) { + try { + if (true) { + componentName = errorInfo.source ? getComponentNameFromFiber(errorInfo.source) : null; + errorBoundaryName = null; } - 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; + var error = errorInfo.value; - while (child) { - // $FlowFixMe[unsafe-addition] addition with possible null/undefined value - fiber.actualDuration += child.actualDuration; - child = child.sibling; - } + if (true && ReactSharedInternals.actQueue !== null) { + // For uncaught errors inside act, we track them on the act and then + // rethrow them into the test. + ReactSharedInternals.thrownErrors.push(error); + return; } - var fakeInternalInstance = {}; - var didWarnAboutStateAssignmentForComponent; - var didWarnAboutUninitializedState; - var didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate; - var didWarnAboutLegacyLifecyclesAndDerivedState; - var didWarnAboutUndefinedDerivedState; - var didWarnAboutDirectlyAssigningPropsToState; - var didWarnAboutContextTypeAndContextTypes; - var didWarnAboutInvalidateContextType; - var didWarnOnInvalidCallback; + var onUncaughtError = root.onUncaughtError; + onUncaughtError(error, { + componentStack: errorInfo.stack + }); + } 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 logCaughtError(root, boundary, errorInfo) { + try { + if (true) { + componentName = errorInfo.source ? getComponentNameFromFiber(errorInfo.source) : null; + errorBoundaryName = getComponentNameFromFiber(boundary); + } + + var error = errorInfo.value; + var onCaughtError = root.onCaughtError; + onCaughtError(error, { + componentStack: errorInfo.stack, + errorBoundary: boundary.tag === ClassComponent ? boundary.stateNode // This should always be the case as long as we only have class boundaries + : null + }); + } 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(root, errorInfo, lane) { + var update = createUpdate(lane); // Unmount the root by rendering null. - { - 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); - } + update.tag = CaptureUpdate; // Caution: React DevTools currently depends on this property + // being called "element". - function warnOnInvalidCallback(callback) { - { - if (callback === null || typeof callback === "function") { - return; - } // eslint-disable-next-line react-internal/safe-string-coercion + update.payload = { + element: null + }; - var key = String(callback); + update.callback = function () { + logUncaughtError(root, errorInfo); + }; - if (!didWarnOnInvalidCallback.has(key)) { - didWarnOnInvalidCallback.add(key); + return update; +} - error( - "Expected the last optional `callback` argument to be a " + - "function. Instead received: %s.", - callback - ); - } +function createClassErrorUpdate(lane) { + var update = createUpdate(lane); + update.tag = CaptureUpdate; + return update; +} + +function initializeClassErrorUpdate(update, root, fiber, errorInfo) { + var getDerivedStateFromError = fiber.type.getDerivedStateFromError; + + if (typeof getDerivedStateFromError === 'function') { + var error$1 = errorInfo.value; + + update.payload = function () { + return getDerivedStateFromError(error$1); + }; + + update.callback = function () { + { + markFailedErrorBoundaryForHotReloading(fiber); } - } - function warnOnUndefinedDerivedState(type, partialState) { + logCaughtError(root, fiber, errorInfo); + }; + } + + var inst = fiber.stateNode; + + if (inst !== null && typeof inst.componentDidCatch === 'function') { + // $FlowFixMe[missing-this-annot] + update.callback = function callback() { { - if (partialState === undefined) { - var componentName = getComponentNameFromType(type) || "Component"; + markFailedErrorBoundaryForHotReloading(fiber); + } - if (!didWarnAboutUndefinedDerivedState.has(componentName)) { - didWarnAboutUndefinedDerivedState.add(componentName); + logCaughtError(root, fiber, errorInfo); - error( - "%s.getDerivedStateFromProps(): A valid state object (or null) must be returned. " + - "You have returned undefined.", - componentName - ); - } - } + 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 applyDerivedStateFromProps( - workInProgress, - ctor, - getDerivedStateFromProps, - nextProps - ) { - var prevState = workInProgress.memoizedState; - var partialState = getDerivedStateFromProps(nextProps, prevState); + var error$1 = errorInfo.value; + var stack = errorInfo.stack; + this.componentDidCatch(error$1, { + componentStack: stack !== null ? stack : '' + }); { - 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 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'); } } + } + }; + } +} - warnOnUndefinedDerivedState(ctor, partialState); - } // Merge the partial state and the previous state. +function resetSuspendedComponent(sourceFiber, rootRenderLanes) { + // A legacy mode Suspense quirk, only relevant to hook components. - 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 tag = sourceFiber.tag; + + 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 { + sourceFiber.updateQueue = null; + sourceFiber.memoizedState = null; } + } +} - 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 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; + + 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); + } + } else if (sourceFiber.tag === FunctionComponent) { + var _currentSourceFiber = sourceFiber.alternate; + + if (_currentSourceFiber === null) { + // This is a new mount. Change the tag so it's not mistaken for a + // completed function component. + sourceFiber.tag = IncompleteFunctionComponent; + } + } // The source fiber did not complete. Mark it with Sync priority to + // indicate that it still has pending work. + + + sourceFiber.lanes = mergeLanes(sourceFiber.lanes, SyncLane); + } + + 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. + + + suspenseBoundary.flags |= ShouldCapture; // TODO: I think we can remove this, since we now use `DidCapture` in + // the begin phase to prevent an early bailout. + + suspenseBoundary.lanes = rootRenderLanes; + return suspenseBoundary; +} - if (callback !== undefined && callback !== null) { - { - warnOnInvalidCallback(callback); - } +function throwException(root, returnFiber, sourceFiber, value, rootRenderLanes) { + // The source fiber did not complete. + sourceFiber.flags |= Incomplete; - update.callback = callback; - } + { + if (isDevToolsPresent) { + // If we have pending work still, restore the original updaters + restorePendingUpdaters(root, rootRenderLanes); + } + } - var root = enqueueUpdate(fiber, update, lane); + if (value !== null && typeof value === 'object') { - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, lane); - entangleTransitions(root, fiber, lane); - } + if (typeof value.then === 'function') { + // This is a wakeable. The component suspended. + var wakeable = value; + resetSuspendedComponent(sourceFiber); - { - 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; - if (callback !== undefined && callback !== null) { - { - warnOnInvalidCallback(callback); - } + var suspenseBoundary = getSuspenseHandler(); - update.callback = callback; - } + 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 (current === null) { + renderDidSuspend(); + } + } + } - var root = enqueueUpdate(fiber, update, lane); + 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. + + var isSuspenseyResource = wakeable === noopSuspenseyCommitThenable; + + if (isSuspenseyResource) { + suspenseBoundary.flags |= ScheduleRetry; + } else { + var retryQueue = suspenseBoundary.updateQueue; - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, lane); - entangleTransitions(root, fiber, lane); - } + if (retryQueue === null) { + suspenseBoundary.updateQueue = new Set([wakeable]); + } else { + retryQueue.add(wakeable); + } // We only attach ping listeners in concurrent mode. Legacy + // Suspense always commits fallbacks synchronously, so there are + // no pings. - { - 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 (callback !== undefined && callback !== null) { - { - warnOnInvalidCallback(callback); - } + if (suspenseBoundary.mode & ConcurrentMode) { + attachPingListener(root, wakeable, rootRenderLanes); + } + } - update.callback = callback; - } + return false; + } - var root = enqueueUpdate(fiber, update, lane); + case OffscreenComponent: + { + if (suspenseBoundary.mode & ConcurrentMode) { + suspenseBoundary.flags |= ShouldCapture; - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, lane); - entangleTransitions(root, fiber, lane); - } + var _isSuspenseyResource = wakeable === noopSuspenseyCommitThenable; - { - markForceUpdateScheduled(fiber, lane); - } - } - }; + if (_isSuspenseyResource) { + suspenseBoundary.flags |= ScheduleRetry; + } else { + var offscreenQueue = suspenseBoundary.updateQueue; + + if (offscreenQueue === null) { + var newOffscreenQueue = { + transitions: null, + markerInstances: null, + retryQueue: new Set([wakeable]) + }; + suspenseBoundary.updateQueue = newOffscreenQueue; + } else { + var _retryQueue = offscreenQueue.retryQueue; - 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 (_retryQueue === null) { + offscreenQueue.retryQueue = new Set([wakeable]); + } else { + _retryQueue.add(wakeable); + } + } - { - if (workInProgress.mode & StrictLegacyMode) { - setIsStrictModeForDevtools(true); + attachPingListener(root, wakeable, rootRenderLanes); + } - try { - // Invoke the function an extra time to help detect side-effects. - shouldUpdate = instance.shouldComponentUpdate( - newProps, - newState, - nextContext - ); - } finally { - setIsStrictModeForDevtools(false); + return false; + } } - } - - if (shouldUpdate === undefined) { - error( - "%s.shouldComponentUpdate(): Returned undefined instead of a " + - "boolean value. Make sure to return true or false.", - getComponentNameFromType(ctor) || "Component" - ); - } } - return shouldUpdate; + throw new Error("Unexpected Suspense handler tag (" + suspenseBoundary.tag + "). This " + 'is a bug in React.'); + } 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 false; + } 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; + } } + } + } // This is a regular error, not a Suspense wakeable. - if (ctor.prototype && ctor.prototype.isPureReactComponent) { - return ( - !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState) - ); - } + var wrapperError = new Error('There was an error during concurrent rendering but React was able to recover by ' + 'instead synchronously rendering the entire root.', { + cause: value + }); + queueConcurrentError(createCapturedValueAtFiber(wrapperError, sourceFiber)); + renderDidError(); // 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. - return true; - } + if (returnFiber === null) { + // There's no return fiber, which means the root errored. This should never + // happen. Return `true` to trigger a fatal error (panic). + return true; + } - function checkClassInstance(workInProgress, ctor, newProps) { - var instance = workInProgress.stateNode; + var errorInfo = createCapturedValueAtFiber(value, sourceFiber); + var workInProgress = returnFiber; - { - var name = getComponentNameFromType(ctor) || "Component"; - var renderPresent = instance.render; - - if (!renderPresent) { - if (ctor.prototype && typeof ctor.prototype.render === "function") { - error( - "No `render` method found on the %s " + - "instance: did you accidentally return an object from the constructor?", - name - ); - } else { - error( - "No `render` method found on the %s " + - "instance: you may have forgotten to define `render`.", - name - ); - } - } + do { + switch (workInProgress.tag) { + case HostRoot: + { + workInProgress.flags |= ShouldCapture; - 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 - ); - } + var _lane = pickArbitraryLane(rootRenderLanes); - 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 - ); - } + workInProgress.lanes = mergeLanes(workInProgress.lanes, _lane); - if (instance.propTypes) { - error( - "propTypes was defined as an instance property on %s. Use a static " + - "property to define propTypes instead.", - name - ); - } + var _update = createRootErrorUpdate(workInProgress.stateNode, errorInfo, _lane); - if (instance.contextType) { - error( - "contextType was defined as an instance property on %s. Use a static " + - "property to define contextType instead.", - name - ); + enqueueCapturedUpdate(workInProgress, _update); + return false; } - { - if (instance.contextTypes) { - error( - "contextTypes was defined as an instance property on %s. Use a static " + - "property to define contextTypes instead.", - name - ); - } + case ClassComponent: + // Capture and retry + var ctor = workInProgress.type; + var instance = workInProgress.stateNode; - if ( - ctor.contextType && - ctor.contextTypes && - !didWarnAboutContextTypeAndContextTypes.has(ctor) - ) { - didWarnAboutContextTypeAndContextTypes.add(ctor); - - error( - "%s declares both contextTypes and contextType static properties. " + - "The legacy contextTypes property will be ignored.", - name - ); - } - } + if ((workInProgress.flags & DidCapture) === NoFlags$1 && (typeof ctor.getDerivedStateFromError === 'function' || instance !== null && typeof instance.componentDidCatch === 'function' && !isAlreadyFailedLegacyErrorBoundary(instance))) { + workInProgress.flags |= ShouldCapture; - 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 - ); - } - - 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 _lane2 = pickArbitraryLane(rootRenderLanes); - 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 - ); - } + workInProgress.lanes = mergeLanes(workInProgress.lanes, _lane2); // Schedule the error boundary to re-render using updated state - if (typeof instance.componentWillRecieveProps === "function") { - error( - "%s has a method called " + - "componentWillRecieveProps(). Did you mean componentWillReceiveProps()?", - name - ); - } + var _update2 = createClassErrorUpdate(_lane2); - if (typeof instance.UNSAFE_componentWillRecieveProps === "function") { - error( - "%s has a method called " + - "UNSAFE_componentWillRecieveProps(). Did you mean UNSAFE_componentWillReceiveProps()?", - name - ); + initializeClassErrorUpdate(_update2, root, workInProgress, errorInfo); + enqueueCapturedUpdate(workInProgress, _update2); + return false; } - var hasMutatedProps = instance.props !== newProps; + break; + } // $FlowFixMe[incompatible-type] we bail out when we get a null - if (instance.props !== undefined && hasMutatedProps) { - error( - "When calling super() in `%s`, make sure to pass " + - "up the same props that your component's constructor was passed.", - name - ); - } - 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 - ); - } + workInProgress = workInProgress.return; + } while (workInProgress !== null); - if ( - typeof instance.getSnapshotBeforeUpdate === "function" && - typeof instance.componentDidUpdate !== "function" && - !didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.has(ctor) - ) { - didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.add(ctor); + return false; +} - error( - "%s: getSnapshotBeforeUpdate() should be used with componentDidUpdate(). " + - "This component defines getSnapshotBeforeUpdate() only.", - getComponentNameFromType(ctor) - ); - } +// into a dehydrated boundary. + +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 didWarnAboutContextTypeOnFunctionComponent; +var didWarnAboutGetDerivedStateOnFunctionComponent; +var didWarnAboutFunctionRefs; +var didWarnAboutReassigningProps; +var didWarnAboutRevealOrder; +var didWarnAboutTailOptions; +var didWarnAboutDefaultPropsOnFunctionComponent; + +{ + didWarnAboutBadClass = {}; + 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 forceUnmountCurrentAndReconcile(current, workInProgress, nextChildren, renderLanes) { + // 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); +} + +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. + var render = Component.render; + var ref = workInProgress.ref; + var propsWithoutRef; - 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 - ); - } + { + propsWithoutRef = nextProps; + } // The rest is a fork of updateFunctionComponent - 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 (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 nextChildren; + prepareToReadContext(workInProgress, renderLanes); - var state = instance.state; + { + markComponentRenderStarted(workInProgress); + } - if (state && (typeof state !== "object" || isArray(state))) { - error("%s.state: must be set to an object or null", name); - } + { + ReactSharedInternals.owner = workInProgress; + setIsRendering(true); + nextChildren = renderWithHooks(current, workInProgress, render, propsWithoutRef, ref, renderLanes); + setIsRendering(false); + } - if ( - typeof instance.getChildContext === "function" && - typeof ctor.childContextTypes !== "object" - ) { - error( - "%s.getChildContext(): childContextTypes must be defined in order to " + - "use getChildContext().", - name - ); - } - } - } + { + markComponentRenderStopped(); + } - function constructClassInstance(workInProgress, ctor, props) { - var isLegacyContextConsumer = false; - var unmaskedContext = emptyContextObject; - var context = emptyContextObject; - var contextType = ctor.contextType; + if (current !== null && !didReceiveUpdate) { + bailoutHooks(current, workInProgress, renderLanes); + return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); + } - { - if ("contextType" in ctor) { - var isValid = // Allow null for conditional declaration - contextType === null || - (contextType !== undefined && - contextType.$$typeof === REACT_CONTEXT_TYPE); - - if (!isValid && !didWarnAboutInvalidateContextType.has(ctor)) { - didWarnAboutInvalidateContextType.add(ctor); - var addendum = ""; - - 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_CONSUMER_TYPE) { - addendum = - " Did you accidentally pass the Context.Consumer instead?"; - } else { - addendum = - " However, it is set to an object with keys {" + - Object.keys(contextType).join(", ") + - "}."; - } - error( - "%s defines an invalid contextType. " + - "contextType should point to the Context object returned by React.createContext().%s", - getComponentNameFromType(ctor) || "Component", - addendum - ); - } - } - } + workInProgress.flags |= PerformedWork; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} - 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; - } +function updateMemoComponent(current, workInProgress, Component, nextProps, renderLanes) { + if (current === null) { + var type = Component.type; - var instance = new ctor(props, context); // Instantiate twice to help detect side-effects. + if (isSimpleFunctionComponent(type) && Component.compare === null && ( // SimpleMemoComponent codepath doesn't resolve outer props either. + disableDefaultPropsExceptForClasses || Component.defaultProps === undefined)) { + var resolvedType = type; { - if (workInProgress.mode & StrictLegacyMode) { - setIsStrictModeForDevtools(true); - - try { - instance = new ctor(props, context); // eslint-disable-line no-new - } finally { - setIsStrictModeForDevtools(false); - } - } - } + 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. - var state = (workInProgress.memoizedState = - instance.state !== null && instance.state !== undefined - ? instance.state - : null); - instance.updater = classComponentUpdater; - workInProgress.stateNode = instance; // The instance needs access to the fiber so that it can schedule updates - set(instance, workInProgress); + workInProgress.tag = SimpleMemoComponent; + workInProgress.type = resolvedType; { - instance._reactInternalInstance = fakeInternalInstance; + validateFunctionComponentInDev(workInProgress, type); } - { - 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; - - if ( - typeof instance.componentWillMount === "function" && - instance.componentWillMount.__suppressDeprecationWarning !== true - ) { - foundWillMountName = "componentWillMount"; - } else if (typeof instance.UNSAFE_componentWillMount === "function") { - foundWillMountName = "UNSAFE_componentWillMount"; - } + return updateSimpleMemoComponent(current, workInProgress, resolvedType, nextProps, renderLanes); + } - if ( - typeof instance.componentWillReceiveProps === "function" && - instance.componentWillReceiveProps.__suppressDeprecationWarning !== - true - ) { - foundWillReceivePropsName = "componentWillReceiveProps"; - } else if ( - typeof instance.UNSAFE_componentWillReceiveProps === "function" - ) { - foundWillReceivePropsName = "UNSAFE_componentWillReceiveProps"; - } + if (!disableDefaultPropsExceptForClasses) { + { + if (Component.defaultProps !== undefined) { + var componentName = getComponentNameFromType(type) || 'Unknown'; - if ( - typeof instance.componentWillUpdate === "function" && - instance.componentWillUpdate.__suppressDeprecationWarning !== true - ) { - foundWillUpdateName = "componentWillUpdate"; - } else if ( - typeof instance.UNSAFE_componentWillUpdate === "function" - ) { - foundWillUpdateName = "UNSAFE_componentWillUpdate"; - } + 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 ( - foundWillMountName !== null || - foundWillReceivePropsName !== null || - foundWillUpdateName !== null - ) { - var _componentName = getComponentNameFromType(ctor) || "Component"; - - var newApiName = - typeof ctor.getDerivedStateFromProps === "function" - ? "getDerivedStateFromProps()" - : "getSnapshotBeforeUpdate()"; - - if ( - !didWarnAboutLegacyLifecyclesAndDerivedState.has(_componentName) - ) { - didWarnAboutLegacyLifecyclesAndDerivedState.add(_componentName); - - 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://react.dev/link/unsafe-component-lifecycles", - _componentName, - newApiName, - foundWillMountName !== null ? "\n " + foundWillMountName : "", - foundWillReceivePropsName !== null - ? "\n " + foundWillReceivePropsName - : "", - foundWillUpdateName !== null ? "\n " + foundWillUpdateName : "" - ); - } + didWarnAboutDefaultPropsOnFunctionComponent[componentName] = true; } } - } // Cache unmasked context so we can avoid recreating masked context unless necessary. - // ReactFiberContext usually updates this cache but can't for newly-created instances. - - if (isLegacyContextConsumer) { - cacheContext(workInProgress, unmaskedContext, context); } - - return instance; } - function callComponentWillMount(workInProgress, instance) { - var oldState = instance.state; + var child = createFiberFromTypeAndProps(Component.type, null, nextProps, workInProgress, workInProgress.mode, renderLanes); + child.ref = workInProgress.ref; + child.return = workInProgress; + workInProgress.child = child; + return child; + } - if (typeof instance.componentWillMount === "function") { - instance.componentWillMount(); - } + var currentChild = current.child; // This is always exactly one child - if (typeof instance.UNSAFE_componentWillMount === "function") { - instance.UNSAFE_componentWillMount(); - } + var hasScheduledUpdateOrContext = checkScheduledUpdateOrContext(current, 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" - ); - } + 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 - classComponentUpdater.enqueueReplaceState( - instance, - instance.state, - null - ); - } + 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. - function callComponentWillReceiveProps( - workInProgress, - instance, - newProps, - nextContext - ) { - var oldState = instance.state; - if (typeof instance.componentWillReceiveProps === "function") { - instance.componentWillReceiveProps(newProps, nextContext); - } + workInProgress.flags |= PerformedWork; + var newChild = createWorkInProgress(currentChild, nextProps); + newChild.ref = workInProgress.ref; + newChild.return = workInProgress; + workInProgress.child = newChild; + return newChild; +} - if (typeof instance.UNSAFE_componentWillReceiveProps === "function") { - instance.UNSAFE_componentWillReceiveProps(newProps, nextContext); +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 (current !== null) { + var prevProps = current.memoizedProps; + + 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. + + 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; } + } + } - if (instance.state !== oldState) { - { - var componentName = - getComponentNameFromFiber(workInProgress) || "Component"; - - 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. + return updateFunctionComponent(current, workInProgress, Component, nextProps, renderLanes); +} - function mountClassInstance(workInProgress, ctor, newProps, renderLanes) { - { - checkClassInstance(workInProgress, ctor, newProps); - } +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(current, workInProgress); - var instance = workInProgress.stateNode; - instance.props = newProps; - instance.state = workInProgress.memoizedState; - instance.refs = {}; - initializeUpdateQueue(workInProgress); - var contextType = ctor.contextType; + if (nextProps.mode === 'hidden' || enableLegacyHidden || nextIsDetached) { + // Rendering a hidden tree. + var didSuspend = (workInProgress.flags & DidCapture) !== NoFlags$1; - if (typeof contextType === "object" && contextType !== null) { - instance.context = readContext(contextType); - } else { - var unmaskedContext = getUnmaskedContext(workInProgress, ctor, true); - instance.context = getMaskedContext(workInProgress, unmaskedContext); - } + 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; - { - if (instance.state === newProps) { - var componentName = getComponentNameFromType(ctor) || "Component"; + 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 (!didWarnAboutDirectlyAssigningPropsToState.has(componentName)) { - didWarnAboutDirectlyAssigningPropsToState.add(componentName); + var currentChildLanes = NoLanes; - 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 - ); - } + while (currentChild !== null) { + currentChildLanes = mergeLanes(mergeLanes(currentChildLanes, currentChild.lanes), currentChild.childLanes); + currentChild = currentChild.sibling; } - if (workInProgress.mode & StrictLegacyMode) { - ReactStrictModeWarnings.recordLegacyContextWarning( - workInProgress, - instance - ); - } - - 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); - suspendIfUpdateReadFromEntangledAsyncAction(); - instance.state = workInProgress.memoizedState; - } - - if (typeof instance.componentDidMount === "function") { - workInProgress.flags |= Update | LayoutStatic; - } - - if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { - workInProgress.flags |= MountLayoutDev; - } - } - - function resumeMountClassInstance( - workInProgress, - ctor, - newProps, - renderLanes - ) { - var instance = workInProgress.stateNode; - var unresolvedOldProps = workInProgress.memoizedProps; - var oldProps = resolveClassComponentProps( - ctor, - unresolvedOldProps, - workInProgress.type === workInProgress.elementType - ); - instance.props = oldProps; - var oldContext = instance.context; - var contextType = ctor.contextType; - var nextContext = emptyContextObject; - - if (typeof contextType === "object" && contextType !== null) { - nextContext = readContext(contextType); + var lanesWeJustAttempted = nextBaseLanes; + var remainingChildLanes = removeLanes(currentChildLanes, lanesWeJustAttempted); + workInProgress.childLanes = remainingChildLanes; } else { - var nextLegacyUnmaskedContext = getUnmaskedContext( - workInProgress, - ctor, - true - ); - nextContext = getMaskedContext( - workInProgress, - nextLegacyUnmaskedContext - ); - } - - var getDerivedStateFromProps = ctor.getDerivedStateFromProps; - var hasNewLifecycles = - typeof getDerivedStateFromProps === "function" || - typeof instance.getSnapshotBeforeUpdate === "function"; // When comparing whether props changed, we should compare using the - // unresolved props object that is stored on the fiber, rather than the - // one that gets assigned to the instance, because that object may have been - // cloned to resolve default props and/or remove `ref`. - - var unresolvedNewProps = workInProgress.pendingProps; - var didReceiveNewProps = unresolvedNewProps !== unresolvedOldProps; // 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 (didReceiveNewProps || oldContext !== nextContext) { - callComponentWillReceiveProps( - workInProgress, - instance, - newProps, - nextContext - ); - } - } - - resetHasForceUpdateBeforeProcessing(); - var oldState = workInProgress.memoizedState; - var newState = (instance.state = oldState); - processUpdateQueue(workInProgress, newProps, instance, renderLanes); - suspendIfUpdateReadFromEntangledAsyncAction(); - newState = workInProgress.memoizedState; + workInProgress.childLanes = NoLanes; + workInProgress.child = null; + } - if ( - !didReceiveNewProps && - 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") { - workInProgress.flags |= Update | LayoutStatic; - } + return deferHiddenOffscreenComponent(current, workInProgress, nextBaseLanes); + } - if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { - workInProgress.flags |= MountLayoutDev; - } + 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; - return false; + { + // push the cache pool even though we're going to bail out + // because otherwise there'd be a context mismatch + if (current !== null) { + pushTransition(workInProgress, null); + } } - if (typeof getDerivedStateFromProps === "function") { - applyDerivedStateFromProps( - workInProgress, - ctor, - getDerivedStateFromProps, - newProps - ); - newState = workInProgress.memoizedState; - } - - var shouldUpdate = - checkHasForceUpdateAfterProcessing() || - checkShouldComponentUpdate( - workInProgress, - ctor, - oldProps, - newProps, - oldState, - newState, - nextContext - ); + 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 _nextBaseLanes = prevState !== null ? mergeLanes(prevState.baseLanes, renderLanes) : renderLanes; + + 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 (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 (current !== null) { + // If the render that spawned this one accessed the cache pool, resume + // using the same cache. Unless the parent changed, since that means + // there was a refresh. + var prevCachePool = prevState !== null ? prevState.cachePool : null; // TODO: Consider if and how Offscreen pre-rendering should + // be attributed to the transition that spawned it - if (typeof instance.UNSAFE_componentWillMount === "function") { - instance.UNSAFE_componentWillMount(); - } - } + pushTransition(workInProgress, prevCachePool); + } // Push the lanes that were skipped when we bailed out. - if (typeof instance.componentDidMount === "function") { - workInProgress.flags |= Update | LayoutStatic; - } - if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { - workInProgress.flags |= MountLayoutDev; - } - } 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") { - workInProgress.flags |= Update | LayoutStatic; - } - - if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { - workInProgress.flags |= MountLayoutDev; - } // 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 = resolveClassComponentProps( - ctor, - unresolvedOldProps, - workInProgress.type === workInProgress.elementType - ); - 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); + if (prevState !== null) { + pushHiddenContext(workInProgress, prevState); } 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); - suspendIfUpdateReadFromEntangledAsyncAction(); - 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; - } - } - - return false; + reuseHiddenContextOnStack(workInProgress); } - if (typeof getDerivedStateFromProps === "function") { - applyDerivedStateFromProps( - workInProgress, - ctor, - getDerivedStateFromProps, - newProps - ); - newState = workInProgress.memoizedState; - } - - 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; + pushOffscreenSuspenseHandler(workInProgress); + } + } else { + // Rendering a visible tree. + if (prevState !== null) { + // We're going from hidden -> visible. + var _prevCachePool = 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_componentWillUpdate === "function" || - typeof instance.componentWillUpdate === "function") - ) { - if (typeof instance.componentWillUpdate === "function") { - instance.componentWillUpdate(newProps, newState, nextContext); - } + { + // If the render that spawned this one accessed the cache pool, resume + // using the same cache. Unless the parent changed, since that means + // there was a refresh. + _prevCachePool = prevState.cachePool; + } - if (typeof instance.UNSAFE_componentWillUpdate === "function") { - instance.UNSAFE_componentWillUpdate( - newProps, - newState, - nextContext - ); - } - } + pushTransition(workInProgress, _prevCachePool); // Push the lanes that were skipped when we bailed out. - if (typeof instance.componentDidUpdate === "function") { - workInProgress.flags |= Update; - } + pushHiddenContext(workInProgress, prevState); + reuseSuspenseHandlerOnStack(workInProgress); // Since we're not hidden anymore, reset the state - 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; - } + workInProgress.memoizedState = null; + } else { + // We weren't previously hidden, and we still aren't, so there's nothing + // special to do. Need to push to the stack regardless, though, to avoid + // a push/pop misalignment. + { + // If the render that spawned this one accessed the cache pool, resume + // using the same cache. Unless the parent changed, since that means + // there was a refresh. + if (current !== null) { + pushTransition(workInProgress, null); } + } // We're about to bail out, but we need to push this to the stack anyway + // to avoid a push/pop misalignment. - 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. - - 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 resolveClassComponentProps( - Component, - baseProps, // Only resolve default props if this is a lazy component. Otherwise, they - // would have already been resolved by the JSX runtime. - // TODO: We're going to remove default prop resolution from the JSX runtime - // and keep it only for class components. As part of that change, we should - // remove this extra check. - alreadyResolvedDefaultProps - ) { - var newProps = baseProps; - - var defaultProps = Component.defaultProps; - - if ( - defaultProps && // If disableDefaultPropsExceptForClasses is true, we always resolve - // default props here in the reconciler, rather than in the JSX runtime. - (disableDefaultPropsExceptForClasses || !alreadyResolvedDefaultProps) - ) { - // We may have already copied the props object above to remove ref. If so, - // we can modify that. Otherwise, copy the props object with Object.assign. - if (newProps === baseProps) { - newProps = assign({}, newProps); - } // Taken from old JSX runtime, where this used to live. - - for (var _propName in defaultProps) { - if (newProps[_propName] === undefined) { - newProps[_propName] = defaultProps[_propName]; - } - } - } - return newProps; + reuseHiddenContextOnStack(workInProgress); + reuseSuspenseHandlerOnStack(workInProgress); } + } - function resolveDefaultPropsOnNonClassComponent(Component, baseProps) { - if (disableDefaultPropsExceptForClasses) { - // Support for defaultProps is removed in React 19 for all types - // except classes. - return baseProps; - } + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} - if (Component && Component.defaultProps) { - // Resolve default props. Taken from ReactElement - var props = assign({}, baseProps); - var defaultProps = Component.defaultProps; +function deferHiddenOffscreenComponent(current, workInProgress, nextBaseLanes, renderLanes) { + var nextState = { + baseLanes: nextBaseLanes, + // Save the cache pool so we can resume later. + cachePool: getOffscreenDeferredCache() + }; + workInProgress.memoizedState = nextState; - for (var propName in defaultProps) { - if (props[propName] === undefined) { - props[propName] = defaultProps[propName]; - } - } + { + // push the cache pool even though we're going to bail out + // because otherwise there'd be a context mismatch + if (current !== null) { + pushTransition(workInProgress, null); + } + } // We're about to bail out, but we need to push this to the stack anyway + // to avoid a push/pop misalignment. - return props; - } - - return baseProps; - } - - var reportGlobalError = - typeof reportError === "function" // In modern browsers, reportError will dispatch an error event, - ? // emulating an uncaught JavaScript error. - reportError - : function (error) { - if ( - typeof window === "object" && - typeof window.ErrorEvent === "function" - ) { - // Browser Polyfill - var message = - typeof error === "object" && - error !== null && - typeof error.message === "string" // eslint-disable-next-line react-internal/safe-string-coercion - ? String(error.message) // eslint-disable-next-line react-internal/safe-string-coercion - : String(error); - var event = new window.ErrorEvent("error", { - bubbles: true, - cancelable: true, - message: message, - error: error - }); - var shouldLog = window.dispatchEvent(event); - - if (!shouldLog) { - return; - } - } else if ( - typeof process === "object" && // $FlowFixMe[method-unbinding] - typeof process.emit === "function" - ) { - // Node Polyfill - process.emit("uncaughtException", error); - return; - } // eslint-disable-next-line react-internal/no-production-logging - - console["error"](error); - }; - var componentName = null; - var errorBoundaryName = null; - function defaultOnUncaughtError(error, errorInfo) { - // Overriding this can silence these warnings e.g. for tests. - // See https://github.com/facebook/react/pull/13384 - // For uncaught root errors we report them as uncaught to the browser's - // onerror callback. This won't have component stacks and the error addendum. - // So we add those into a separate console.warn. - reportGlobalError(error); + reuseHiddenContextOnStack(workInProgress); + pushOffscreenSuspenseHandler(workInProgress); - { - var componentStack = - errorInfo.componentStack != null ? errorInfo.componentStack : ""; - var componentNameMessage = componentName - ? "An error occurred in the <" + componentName + "> component:" - : "An error occurred in one of your React components:"; - console["warn"]( - "%s\n%s\n\n%s", - componentNameMessage, - componentStack || "", - "Consider adding an error boundary to your tree to customize error handling behavior.\n" + - "Visit https://react.dev/link/error-boundaries to learn more about error boundaries." - ); - } - } - function defaultOnCaughtError(error, errorInfo) { - // Overriding this can silence these warnings e.g. for tests. - // See https://github.com/facebook/react/pull/13384 - // Caught by error boundary - { - var componentStack = - errorInfo.componentStack != null ? errorInfo.componentStack : ""; - var componentNameMessage = componentName - ? "The above error occurred in the <" + componentName + "> component:" - : "The above error occurred in one of your React components:"; // In development, we provide our own message which includes the component stack - // in addition to the error. - // Don't transform to our wrapper - - console["error"]( - "%o\n\n%s\n%s\n\n%s", - error, - componentNameMessage, - componentStack, - "React will try to recreate this component tree from scratch " + - ("using the error boundary you provided, " + - (errorBoundaryName || "Anonymous") + - ".") - ); - } - } - function defaultOnRecoverableError(error, errorInfo) { - reportGlobalError(error); - } - function logUncaughtError(root, errorInfo) { - try { - if (true) { - componentName = errorInfo.source - ? getComponentNameFromFiber(errorInfo.source) - : null; - errorBoundaryName = null; - } + return null; +} // Note: These happen to have identical begin phases, for now. We shouldn't hold - var error = errorInfo.value; +function updateCacheComponent(current, workInProgress, renderLanes) { - if (true && ReactSharedInternals.actQueue !== null) { - // For uncaught errors inside act, we track them on the act and then - // rethrow them into the test. - ReactSharedInternals.thrownErrors.push(error); - return; - } + prepareToReadContext(workInProgress, renderLanes); + var parentCache = readContext(CacheContext); - var onUncaughtError = root.onUncaughtError; - onUncaughtError(error, { - componentStack: errorInfo.stack - }); - } 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 logCaughtError(root, boundary, errorInfo) { - try { - if (true) { - componentName = errorInfo.source - ? getComponentNameFromFiber(errorInfo.source) - : null; - errorBoundaryName = getComponentNameFromFiber(boundary); - } - - var error = errorInfo.value; - var onCaughtError = root.onCaughtError; - onCaughtError(error, { - componentStack: errorInfo.stack, - errorBoundary: - boundary.tag === ClassComponent - ? boundary.stateNode // This should always be the case as long as we only have class boundaries - : null - }); - } 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; - }); - } + if (current === null) { + // Initial mount. Request a fresh cache from the pool. + var freshCache = requestCacheFromPool(renderLanes); + var initialState = { + parent: parentCache, + cache: freshCache + }; + workInProgress.memoizedState = initialState; + initializeUpdateQueue(workInProgress); + pushCacheProvider(workInProgress, freshCache); + } else { + // Check for updates + if (includesSomeLane(current.lanes, renderLanes)) { + cloneUpdateQueue(current, workInProgress); + processUpdateQueue(workInProgress, null, null, renderLanes); + suspendIfUpdateReadFromEntangledAsyncAction(); } - function createRootErrorUpdate(root, errorInfo, lane) { - var update = createUpdate(lane); // Unmount the root by rendering null. + var prevState = current.memoizedState; + var nextState = workInProgress.memoizedState; // Compare the new parent cache to the previous to see detect there was + // a refresh. - update.tag = CaptureUpdate; // Caution: React DevTools currently depends on this property - // being called "element". + if (prevState.parent !== parentCache) { + // Refresh in parent. Update the parent. + var derivedState = { + parent: parentCache, + cache: parentCache + }; // Copied from getDerivedStateFromProps implementation. Once the update + // queue is empty, persist the derived state onto the base state. - update.payload = { - element: null - }; + workInProgress.memoizedState = derivedState; - update.callback = function () { - logUncaughtError(root, errorInfo); - }; + if (workInProgress.lanes === NoLanes) { + var updateQueue = workInProgress.updateQueue; + workInProgress.memoizedState = updateQueue.baseState = derivedState; + } - return update; - } + pushCacheProvider(workInProgress, parentCache); // No need to propagate a context change because the refreshed parent + // already did. + } else { + // The parent didn't refresh. Now check if this cache did. + var nextCache = nextState.cache; + pushCacheProvider(workInProgress, nextCache); - function createClassErrorUpdate(lane) { - var update = createUpdate(lane); - update.tag = CaptureUpdate; - return update; + if (nextCache !== prevState.cache) { + // This cache refreshed. Propagate a context change. + propagateContextChange(workInProgress, CacheContext, renderLanes); + } } + } - function initializeClassErrorUpdate(update, root, fiber, errorInfo) { - var getDerivedStateFromError = fiber.type.getDerivedStateFromError; - - if (typeof getDerivedStateFromError === "function") { - var error$1 = errorInfo.value; + var nextChildren = workInProgress.pendingProps.children; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} // This should only be called if the name changes - update.payload = function () { - return getDerivedStateFromError(error$1); - }; +function updateFragment(current, workInProgress, renderLanes) { + var nextChildren = workInProgress.pendingProps; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} - update.callback = function () { - { - markFailedErrorBoundaryForHotReloading(fiber); - } +function updateMode(current, workInProgress, renderLanes) { + var nextChildren = workInProgress.pendingProps.children; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} - logCaughtError(root, fiber, errorInfo); - }; - } +function updateProfiler(current, workInProgress, renderLanes) { + { + workInProgress.flags |= Update; - var inst = fiber.stateNode; + { + // 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 nextProps = workInProgress.pendingProps; + var nextChildren = nextProps.children; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} - if (inst !== null && typeof inst.componentDidCatch === "function") { - // $FlowFixMe[missing-this-annot] - update.callback = function callback() { - { - markFailedErrorBoundaryForHotReloading(fiber); - } +function markRef(current, workInProgress) { + // TODO: Check props.ref instead of fiber.ref when enableRefAsProp is on. + var ref = workInProgress.ref; - logCaughtError(root, fiber, errorInfo); + if (ref === null) { + if (current !== null && current.ref !== null) { + // Schedule a Ref effect + workInProgress.flags |= Ref | RefStatic; + } + } else { + if (typeof ref !== 'function' && typeof ref !== 'object') { + throw new Error('Expected ref to be a function, an object returned by React.createRef(), or undefined/null.'); + } - 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 (current === null || current.ref !== ref) { + if (current !== null) { + var oldRef = current.ref; + var newRef = ref; + + if (typeof oldRef === 'function' && typeof newRef === 'function' && typeof oldRef.__stringRef === 'string' && oldRef.__stringRef === newRef.__stringRef && oldRef.__stringRefType === newRef.__stringRefType && oldRef.__stringRefOwner === newRef.__stringRefOwner) { + // Although this is a different callback, it represents the same + // string ref. To avoid breaking old Meta code that relies on string + // refs only being attached once, reuse the old ref. This will + // prevent us from detaching and reattaching the ref on each update. + workInProgress.ref = oldRef; + return; + } + } // Schedule a Ref effect - var error$1 = errorInfo.value; - var stack = errorInfo.stack; - this.componentDidCatch(error$1, { - componentStack: stack !== null ? stack : "" - }); - { - 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" - ); - } - } - } - }; - } + workInProgress.flags |= Ref | RefStatic; } + } +} - function resetSuspendedComponent(sourceFiber, rootRenderLanes) { - // A legacy mode Suspense quirk, only relevant to hook components. +function mountIncompleteFunctionComponent(_current, workInProgress, Component, nextProps, renderLanes) { + resetSuspendedCurrentOnMountInLegacyMode(_current, workInProgress); + workInProgress.tag = FunctionComponent; + return updateFunctionComponent(null, workInProgress, Component, nextProps, renderLanes); +} - var tag = sourceFiber.tag; +function updateFunctionComponent(current, workInProgress, Component, nextProps, renderLanes) { + { + if (Component.prototype && typeof Component.prototype.render === 'function') { + var componentName = getComponentNameFromType(Component) || 'Unknown'; - if ( - (sourceFiber.mode & ConcurrentMode) === NoMode && - (tag === FunctionComponent || - tag === ForwardRef || - tag === SimpleMemoComponent) - ) { - var currentSource = sourceFiber.alternate; + 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); - if (currentSource) { - sourceFiber.updateQueue = currentSource.updateQueue; - sourceFiber.memoizedState = currentSource.memoizedState; - sourceFiber.lanes = currentSource.lanes; - } else { - sourceFiber.updateQueue = null; - sourceFiber.memoizedState = null; - } + didWarnAboutBadClass[componentName] = true; } } - 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. + if (workInProgress.mode & StrictLegacyMode) { + ReactStrictModeWarnings.recordLegacyContextWarning(workInProgress, null); + } - sourceFiber.flags &= ~(LifecycleEffectMask | Incomplete); + if (current === null) { + // Some validations were previously done in mountIndeterminateComponent however and are now run + // in updateFuntionComponent but only on mount + validateFunctionComponentInDev(workInProgress, workInProgress.type); + } + } - if (sourceFiber.tag === ClassComponent) { - var currentSourceFiber = sourceFiber.alternate; + var context; - 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); - } - } else if (sourceFiber.tag === FunctionComponent) { - var _currentSourceFiber = sourceFiber.alternate; + { + var unmaskedContext = getUnmaskedContext(workInProgress, Component, true); + context = getMaskedContext(workInProgress, unmaskedContext); + } - if (_currentSourceFiber === null) { - // This is a new mount. Change the tag so it's not mistaken for a - // completed function component. - sourceFiber.tag = IncompleteFunctionComponent; - } - } // The source fiber did not complete. Mark it with Sync priority to - // indicate that it still has pending work. + var nextChildren; + prepareToReadContext(workInProgress, renderLanes); - sourceFiber.lanes = mergeLanes(sourceFiber.lanes, SyncLane); - } + { + markComponentRenderStarted(workInProgress); + } - 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. + { + ReactSharedInternals.owner = workInProgress; + setIsRendering(true); + nextChildren = renderWithHooks(current, workInProgress, Component, nextProps, context, renderLanes); + setIsRendering(false); + } - suspenseBoundary.flags |= ShouldCapture; // TODO: I think we can remove this, since we now use `DidCapture` in - // the begin phase to prevent an early bailout. + { + markComponentRenderStopped(); + } - suspenseBoundary.lanes = rootRenderLanes; - return suspenseBoundary; - } + if (current !== null && !didReceiveUpdate) { + bailoutHooks(current, workInProgress, renderLanes); + return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); + } - function throwException( - root, - returnFiber, - sourceFiber, - value, - rootRenderLanes - ) { - // The source fiber did not complete. - sourceFiber.flags |= Incomplete; - { - if (isDevToolsPresent) { - // If we have pending work still, restore the original updaters - restorePendingUpdaters(root, rootRenderLanes); - } - } - - if (value !== null && typeof value === "object") { - if (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; - - if (current === null) { - renderDidSuspend(); - } - } - } + workInProgress.flags |= PerformedWork; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} - 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. - - var isSuspenseyResource = - wakeable === noopSuspenseyCommitThenable; - - if (isSuspenseyResource) { - suspenseBoundary.flags |= ScheduleRetry; - } else { - var retryQueue = suspenseBoundary.updateQueue; +function replayFunctionComponent(current, workInProgress, nextProps, Component, secondArg, renderLanes) { + // 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. + prepareToReadContext(workInProgress, renderLanes); - if (retryQueue === null) { - suspenseBoundary.updateQueue = new Set([wakeable]); - } else { - retryQueue.add(wakeable); - } // We only attach ping listeners in concurrent mode. Legacy - // Suspense always commits fallbacks synchronously, so there are - // no pings. + { + markComponentRenderStarted(workInProgress); + } - if (suspenseBoundary.mode & ConcurrentMode) { - attachPingListener(root, wakeable, rootRenderLanes); - } - } + var nextChildren = replaySuspendedComponentWithHooks(current, workInProgress, Component, nextProps, secondArg); - return false; - } + { + markComponentRenderStopped(); + } - case OffscreenComponent: { - if (suspenseBoundary.mode & ConcurrentMode) { - suspenseBoundary.flags |= ShouldCapture; + if (current !== null && !didReceiveUpdate) { + bailoutHooks(current, workInProgress, renderLanes); + return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); + } - var _isSuspenseyResource = - wakeable === noopSuspenseyCommitThenable; - if (_isSuspenseyResource) { - suspenseBoundary.flags |= ScheduleRetry; - } else { - var offscreenQueue = suspenseBoundary.updateQueue; - - if (offscreenQueue === null) { - var newOffscreenQueue = { - transitions: null, - markerInstances: null, - retryQueue: new Set([wakeable]) - }; - suspenseBoundary.updateQueue = newOffscreenQueue; - } else { - var _retryQueue = offscreenQueue.retryQueue; + workInProgress.flags |= PerformedWork; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} - if (_retryQueue === null) { - offscreenQueue.retryQueue = new Set([wakeable]); - } else { - _retryQueue.add(wakeable); - } - } +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? - attachPingListener(root, wakeable, rootRenderLanes); - } + var tempInstance = new ctor(workInProgress.memoizedProps, _instance.context); + var state = tempInstance.state; - return false; - } - } - } + _instance.updater.enqueueSetState(_instance, state, null); - throw new Error( - "Unexpected Suspense handler tag (" + - suspenseBoundary.tag + - "). This " + - "is a bug in React." - ); - } 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 false; - } 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; - } + break; + } + + case true: + { + workInProgress.flags |= DidCapture; + workInProgress.flags |= ShouldCapture; // eslint-disable-next-line react-internal/prod-error-codes + + 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 + + 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.'); } + + var update = createClassErrorUpdate(lane); + initializeClassErrorUpdate(update, root, workInProgress, createCapturedValueAtFiber(error$1, workInProgress)); + enqueueCapturedUpdate(workInProgress, update); + break; } - } // This is a regular error, not a Suspense wakeable. + } + } // 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; - var wrapperError = new Error( - "There was an error during concurrent rendering but React was able to recover by " + - "instead synchronously rendering the entire root.", - { - cause: value - } - ); - queueConcurrentError( - createCapturedValueAtFiber(wrapperError, sourceFiber) - ); - renderDidError(); // 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 (returnFiber === null) { - // There's no return fiber, which means the root errored. This should never - // happen. Return `true` to trigger a fatal error (panic). - return true; - } + if (isContextProvider(Component)) { + hasContext = true; + pushContextProvider(workInProgress); + } else { + hasContext = false; + } - var errorInfo = createCapturedValueAtFiber(value, sourceFiber); - var workInProgress = returnFiber; + prepareToReadContext(workInProgress, renderLanes); + var instance = workInProgress.stateNode; + var shouldUpdate; - do { - switch (workInProgress.tag) { - case HostRoot: { - workInProgress.flags |= ShouldCapture; + if (instance === null) { + resetSuspendedCurrentOnMountInLegacyMode(current, workInProgress); // In the initial pass we might need to construct the instance. - var _lane = pickArbitraryLane(rootRenderLanes); + 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); + } - workInProgress.lanes = mergeLanes(workInProgress.lanes, _lane); + var nextUnitOfWork = finishClassComponent(current, workInProgress, Component, shouldUpdate, hasContext, renderLanes); - var _update = createRootErrorUpdate( - workInProgress.stateNode, - errorInfo, - _lane - ); + { + var inst = workInProgress.stateNode; - enqueueCapturedUpdate(workInProgress, _update); - return false; - } + 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'); + } - case ClassComponent: - // Capture and retry - var ctor = workInProgress.type; - var instance = workInProgress.stateNode; - - if ( - (workInProgress.flags & DidCapture) === NoFlags$1 && - (typeof ctor.getDerivedStateFromError === "function" || - (instance !== null && - typeof instance.componentDidCatch === "function" && - !isAlreadyFailedLegacyErrorBoundary(instance))) - ) { - workInProgress.flags |= ShouldCapture; - - var _lane2 = pickArbitraryLane(rootRenderLanes); - - workInProgress.lanes = mergeLanes(workInProgress.lanes, _lane2); // Schedule the error boundary to re-render using updated state - - var _update2 = createClassErrorUpdate(_lane2); - - initializeClassErrorUpdate( - _update2, - root, - workInProgress, - errorInfo - ); - enqueueCapturedUpdate(workInProgress, _update2); - return false; - } + didWarnAboutReassigningProps = true; + } + } - break; - } // $FlowFixMe[incompatible-type] we bail out when we get a null + return nextUnitOfWork; +} - workInProgress = workInProgress.return; - } while (workInProgress !== null); +function finishClassComponent(current, workInProgress, Component, shouldUpdate, hasContext, renderLanes) { + // Refs should update even if shouldComponentUpdate returns false + markRef(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); } - // into a dehydrated boundary. + return bailoutOnAlreadyFinishedWork(current, workInProgress, 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 didWarnAboutContextTypeOnFunctionComponent; - var didWarnAboutGetDerivedStateOnFunctionComponent; - var didWarnAboutFunctionRefs; - var didWarnAboutReassigningProps; - var didWarnAboutRevealOrder; - var didWarnAboutTailOptions; - var didWarnAboutDefaultPropsOnFunctionComponent; + var instance = workInProgress.stateNode; // Rerender - { - didWarnAboutBadClass = {}; - 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 forceUnmountCurrentAndReconcile( - current, - workInProgress, - nextChildren, - renderLanes - ) { - // 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 - ); - } - - 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. - var render = Component.render; - var ref = workInProgress.ref; - var propsWithoutRef; + { + ReactSharedInternals.owner = workInProgress; + } - { - propsWithoutRef = nextProps; - } // The rest is a fork of updateFunctionComponent + var nextChildren; - var nextChildren; - prepareToReadContext(workInProgress, renderLanes); + 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; - { - markComponentRenderStarted(workInProgress); - } + { + stopProfilerTimerIfRunning(); + } + } else { + { + markComponentRenderStarted(workInProgress); + } - { - ReactSharedInternals.owner = workInProgress; - setIsRendering(true); - nextChildren = renderWithHooks( - current, - workInProgress, - render, - propsWithoutRef, - ref, - renderLanes - ); - setIsRendering(false); - } + { + setIsRendering(true); + nextChildren = instance.render(); - { - markComponentRenderStopped(); - } + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); - if (current !== null && !didReceiveUpdate) { - bailoutHooks(current, workInProgress, renderLanes); - return bailoutOnAlreadyFinishedWork( - current, - workInProgress, - renderLanes - ); + try { + instance.render(); + } finally { + setIsStrictModeForDevtools(false); + } } - workInProgress.flags |= PerformedWork; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; + setIsRendering(false); } - function updateMemoComponent( - current, - workInProgress, - Component, - nextProps, - renderLanes - ) { - if (current === null) { - var type = Component.type; + { + markComponentRenderStopped(); + } + } // React DevTools reads this flag. - if ( - isSimpleFunctionComponent(type) && - Component.compare === null && // SimpleMemoComponent codepath doesn't resolve outer props either. - (disableDefaultPropsExceptForClasses || - 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.flags |= PerformedWork; - workInProgress.tag = SimpleMemoComponent; - workInProgress.type = resolvedType; + 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. - { - validateFunctionComponentInDev(workInProgress, type); - } - return updateSimpleMemoComponent( - current, - workInProgress, - resolvedType, - nextProps, - renderLanes - ); - } + workInProgress.memoizedState = instance.state; // The context might have changed so we need to recalculate it. - if (!disableDefaultPropsExceptForClasses) { - { - 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 (hasContext) { + invalidateContextProvider(workInProgress, Component, true); + } - var child = createFiberFromTypeAndProps( - Component.type, - null, - nextProps, - workInProgress, - workInProgress.mode, - renderLanes - ); - child.ref = workInProgress.ref; - child.return = workInProgress; - workInProgress.child = child; - return child; - } - - 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 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 (current !== null) { - var prevProps = current.memoizedProps; - - 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. - - 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; - } - } - } + return workInProgress.child; +} - return updateFunctionComponent( - current, - workInProgress, - Component, - nextProps, - renderLanes - ); - } +function pushHostRootContext(workInProgress) { + var root = workInProgress.stateNode; - 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(current, workInProgress); + 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 (nextProps.mode === "hidden" || enableLegacyHidden || nextIsDetached) { - // Rendering a hidden tree. - var didSuspend = (workInProgress.flags & DidCapture) !== NoFlags$1; + pushHostContainer(workInProgress, root.containerInfo); +} - 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; +function updateHostRoot(current, workInProgress, renderLanes) { + pushHostRootContext(workInProgress); - 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. - - var currentChildLanes = NoLanes; - - while (currentChild !== null) { - currentChildLanes = mergeLanes( - mergeLanes(currentChildLanes, currentChild.lanes), - currentChild.childLanes - ); - currentChild = currentChild.sibling; - } + if (current === null) { + throw new Error('Should have a current fiber. This is a bug in React.'); + } - var lanesWeJustAttempted = nextBaseLanes; - var remainingChildLanes = removeLanes( - currentChildLanes, - lanesWeJustAttempted - ); - workInProgress.childLanes = remainingChildLanes; - } else { - workInProgress.childLanes = NoLanes; - workInProgress.child = null; - } + var nextProps = workInProgress.pendingProps; + var prevState = workInProgress.memoizedState; + var prevChildren = prevState.element; + cloneUpdateQueue(current, workInProgress); + processUpdateQueue(workInProgress, nextProps, null, renderLanes); + var nextState = workInProgress.memoizedState; - return deferHiddenOffscreenComponent( - current, - workInProgress, - nextBaseLanes - ); - } + { + var nextCache = nextState.cache; + pushCacheProvider(workInProgress, nextCache); - 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; + if (nextCache !== prevState.cache) { + // The root cache refreshed. + propagateContextChange(workInProgress, CacheContext, renderLanes); + } + } // This would ideally go inside processUpdateQueue, but because it suspends, + // it needs to happen after the `pushCacheProvider` call above to avoid a + // context stack mismatch. A bit unfortunate. - { - // push the cache pool even though we're going to bail out - // because otherwise there'd be a context mismatch - if (current !== null) { - pushTransition(workInProgress, null); - } - } - 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 _nextBaseLanes = - prevState !== null - ? mergeLanes(prevState.baseLanes, renderLanes) - : renderLanes; - - 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; + suspendIfUpdateReadFromEntangledAsyncAction(); // Caution: React DevTools currently depends on this property + // being called "element". - if (current !== null) { - // If the render that spawned this one accessed the cache pool, resume - // using the same cache. Unless the parent changed, since that means - // there was a refresh. - var prevCachePool = prevState !== null ? prevState.cachePool : null; // TODO: Consider if and how Offscreen pre-rendering should - // be attributed to the transition that spawned it + var nextChildren = nextState.element; - pushTransition(workInProgress, prevCachePool); - } // Push the lanes that were skipped when we bailed out. + { - if (prevState !== null) { - pushHiddenContext(workInProgress, prevState); - } else { - reuseHiddenContextOnStack(workInProgress); - } + if (nextChildren === prevChildren) { + return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); + } - pushOffscreenSuspenseHandler(workInProgress); - } - } else { - // Rendering a visible tree. - if (prevState !== null) { - // We're going from hidden -> visible. - var _prevCachePool = null; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + } - { - // If the render that spawned this one accessed the cache pool, resume - // using the same cache. Unless the parent changed, since that means - // there was a refresh. - _prevCachePool = prevState.cachePool; - } + return workInProgress.child; +} - pushTransition(workInProgress, _prevCachePool); // Push the lanes that were skipped when we bailed out. +function updateHostComponent$1(current, workInProgress, renderLanes) { - pushHiddenContext(workInProgress, prevState); - reuseSuspenseHandlerOnStack(workInProgress); // Since we're not hidden anymore, reset the state + pushHostContext(workInProgress); + var nextProps = workInProgress.pendingProps; + var prevProps = current !== null ? current.memoizedProps : null; + var nextChildren = nextProps.children; - workInProgress.memoizedState = null; - } else { - // We weren't previously hidden, and we still aren't, so there's nothing - // special to do. Need to push to the stack regardless, though, to avoid - // a push/pop misalignment. - { - // If the render that spawned this one accessed the cache pool, resume - // using the same cache. Unless the parent changed, since that means - // there was a refresh. - if (current !== null) { - pushTransition(workInProgress, null); - } - } // We're about to bail out, but we need to push this to the stack anyway - // to avoid a push/pop misalignment. + 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; + } - reuseHiddenContextOnStack(workInProgress); - reuseSuspenseHandlerOnStack(workInProgress); - } - } + if (enableAsyncActions) { + var memoizedState = workInProgress.memoizedState; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; - } + if (memoizedState !== null) { + // This fiber has been upgraded to a stateful component. The only way + // happens currently is for form actions. We use hooks to track the + // pending and error state of the form. + // + // Once a fiber is upgraded to be stateful, it remains stateful for the + // rest of its lifetime. + var newState = renderTransitionAwareHostComponentWithHooks(current, workInProgress, renderLanes); // If the transition state changed, propagate the change to all the + // descendents. We use Context as an implementation detail for this. + // + // This is intentionally set here instead of pushHostContext because + // pushHostContext gets called before we process the state hook, to avoid + // a state mismatch in the event that something suspends. + // + // NOTE: This assumes that there cannot be nested transition providers, + // because the only renderer that implements this feature is React DOM, + // and forms cannot be nested. If we did support nested providers, then + // we would need to push a context value even for host fibers that + // haven't been upgraded yet. - function deferHiddenOffscreenComponent( - current, - workInProgress, - nextBaseLanes, - renderLanes - ) { - var nextState = { - baseLanes: nextBaseLanes, - // Save the cache pool so we can resume later. - cachePool: getOffscreenDeferredCache() - }; - workInProgress.memoizedState = nextState; + { + HostTransitionContext._currentValue = newState; + } { - // push the cache pool even though we're going to bail out - // because otherwise there'd be a context mismatch - if (current !== null) { - pushTransition(workInProgress, null); + if (didReceiveUpdate) { + if (current !== null) { + var oldStateHook = current.memoizedState; + var oldState = oldStateHook.memoizedState; // This uses regular equality instead of Object.is because we assume + // that host transition state doesn't include NaN as a valid type. + + if (oldState !== newState) { + propagateContextChange(workInProgress, HostTransitionContext, renderLanes); + } + } } - } // We're about to bail out, but we need to push this to the stack anyway - // to avoid a push/pop misalignment. + } + } + } - reuseHiddenContextOnStack(workInProgress); - pushOffscreenSuspenseHandler(workInProgress); + markRef(current, workInProgress); + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} - return null; - } // Note: These happen to have identical begin phases, for now. We shouldn't hold +function updateHostText$1(current, workInProgress) { + // immediately after. - function updateCacheComponent(current, workInProgress, renderLanes) { - prepareToReadContext(workInProgress, renderLanes); - var parentCache = readContext(CacheContext); - if (current === null) { - // Initial mount. Request a fresh cache from the pool. - var freshCache = requestCacheFromPool(renderLanes); - var initialState = { - parent: parentCache, - cache: freshCache - }; - workInProgress.memoizedState = initialState; - initializeUpdateQueue(workInProgress); - pushCacheProvider(workInProgress, freshCache); - } else { - // Check for updates - if (includesSomeLane(current.lanes, renderLanes)) { - cloneUpdateQueue(current, workInProgress); - processUpdateQueue(workInProgress, null, null, renderLanes); - suspendIfUpdateReadFromEntangledAsyncAction(); - } + return null; +} - var prevState = current.memoizedState; - var nextState = workInProgress.memoizedState; // Compare the new parent cache to the previous to see detect there was - // a refresh. - - if (prevState.parent !== parentCache) { - // Refresh in parent. Update the parent. - var derivedState = { - parent: parentCache, - cache: parentCache - }; // Copied from getDerivedStateFromProps implementation. Once the update - // queue is empty, persist the derived state onto the base state. - - workInProgress.memoizedState = derivedState; - - if (workInProgress.lanes === NoLanes) { - var updateQueue = workInProgress.updateQueue; - workInProgress.memoizedState = updateQueue.baseState = derivedState; - } +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. - pushCacheProvider(workInProgress, parentCache); // No need to propagate a context change because the refreshed parent - // already did. - } else { - // The parent didn't refresh. Now check if this cache did. - var nextCache = nextState.cache; - pushCacheProvider(workInProgress, nextCache); + workInProgress.type = Component; - if (nextCache !== prevState.cache) { - // This cache refreshed. Propagate a context change. - propagateContextChange(workInProgress, CacheContext, renderLanes); - } - } + if (typeof Component === 'function') { + if (isFunctionClassComponent(Component)) { + var resolvedProps = resolveClassComponentProps(Component, props, false); + workInProgress.tag = ClassComponent; + + { + workInProgress.type = Component = resolveClassForHotReloading(Component); } - var nextChildren = workInProgress.pendingProps.children; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; - } // This should only be called if the name changes + return updateClassComponent(null, workInProgress, Component, resolvedProps, renderLanes); + } else { + var _resolvedProps = disableDefaultPropsExceptForClasses ? props : resolveDefaultPropsOnNonClassComponent(Component, props); - function updateFragment(current, workInProgress, renderLanes) { - var nextChildren = workInProgress.pendingProps; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; - } + workInProgress.tag = FunctionComponent; + + { + validateFunctionComponentInDev(workInProgress, Component); + workInProgress.type = Component = resolveFunctionForHotReloading(Component); + } - function updateMode(current, workInProgress, renderLanes) { - var nextChildren = workInProgress.pendingProps.children; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; + return updateFunctionComponent(null, workInProgress, Component, _resolvedProps, renderLanes); } + } else if (Component !== undefined && Component !== null) { + var $$typeof = Component.$$typeof; - function updateProfiler(current, workInProgress, renderLanes) { - { - workInProgress.flags |= Update; + if ($$typeof === REACT_FORWARD_REF_TYPE) { + var _resolvedProps2 = disableDefaultPropsExceptForClasses ? props : resolveDefaultPropsOnNonClassComponent(Component, props); - { - // 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; - } + workInProgress.tag = ForwardRef; + + { + workInProgress.type = Component = resolveForwardRefForHotReloading(Component); } - var nextProps = workInProgress.pendingProps; - var nextChildren = nextProps.children; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; + return updateForwardRef(null, workInProgress, Component, _resolvedProps2, renderLanes); + } else if ($$typeof === REACT_MEMO_TYPE) { + var _resolvedProps3 = disableDefaultPropsExceptForClasses ? props : resolveDefaultPropsOnNonClassComponent(Component, props); + + workInProgress.tag = MemoComponent; + return updateMemoComponent(null, workInProgress, Component, disableDefaultPropsExceptForClasses ? _resolvedProps3 : resolveDefaultPropsOnNonClassComponent(Component.type, _resolvedProps3), // The inner type can have defaults too + renderLanes); } + } - function markRef(current, workInProgress) { - // TODO: Check props.ref instead of fiber.ref when enableRefAsProp is on. - var ref = workInProgress.ref; + var hint = ''; - if (ref === null) { - if (current !== null && current.ref !== null) { - // Schedule a Ref effect - workInProgress.flags |= Ref | RefStatic; - } - } else { - if (typeof ref !== "function" && typeof ref !== "object") { - throw new Error( - "Expected ref to be a function, an object returned by React.createRef(), or undefined/null." - ); - } + { + 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. - if (current === null || current.ref !== ref) { - if (current !== null) { - var oldRef = current.ref; - var newRef = ref; - - if ( - typeof oldRef === "function" && - typeof newRef === "function" && - typeof oldRef.__stringRef === "string" && - oldRef.__stringRef === newRef.__stringRef && - oldRef.__stringRefType === newRef.__stringRefType && - oldRef.__stringRefOwner === newRef.__stringRefOwner - ) { - // Although this is a different callback, it represents the same - // string ref. To avoid breaking old Meta code that relies on string - // refs only being attached once, reuse the old ref. This will - // prevent us from detaching and reattaching the ref on each update. - workInProgress.ref = oldRef; - return; - } - } // Schedule a Ref effect - workInProgress.flags |= Ref | RefStatic; - } - } - } + 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)); +} - function mountIncompleteFunctionComponent( - _current, - workInProgress, - Component, - nextProps, - renderLanes - ) { - resetSuspendedCurrentOnMountInLegacyMode(_current, workInProgress); - workInProgress.tag = FunctionComponent; - return updateFunctionComponent( - null, - workInProgress, - Component, - nextProps, - renderLanes - ); - } - - function updateFunctionComponent( - current, - workInProgress, - Component, - nextProps, - renderLanes - ) { - { - 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 - ); +function mountIncompleteClassComponent(_current, workInProgress, Component, nextProps, renderLanes) { + resetSuspendedCurrentOnMountInLegacyMode(_current, workInProgress); // Promote the fiber to a class and try rendering again. - didWarnAboutBadClass[componentName] = true; - } - } + 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 (workInProgress.mode & StrictLegacyMode) { - ReactStrictModeWarnings.recordLegacyContextWarning( - workInProgress, - null - ); - } + var hasContext; - if (current === null) { - // Some validations were previously done in mountIndeterminateComponent however and are now run - // in updateFuntionComponent but only on mount - validateFunctionComponentInDev(workInProgress, workInProgress.type); - } - } + if (isContextProvider(Component)) { + hasContext = true; + pushContextProvider(workInProgress); + } else { + hasContext = false; + } - var context; + prepareToReadContext(workInProgress, renderLanes); + constructClassInstance(workInProgress, Component, nextProps); + mountClassInstance(workInProgress, Component, nextProps, renderLanes); + return finishClassComponent(null, workInProgress, Component, true, hasContext, renderLanes); +} - { - var unmaskedContext = getUnmaskedContext( - workInProgress, - Component, - true - ); - context = getMaskedContext(workInProgress, unmaskedContext); +function validateFunctionComponentInDev(workInProgress, Component) { + { + if (Component) { + if (Component.childContextTypes) { + error('childContextTypes cannot be defined on a function component.\n' + ' %s.childContextTypes = ...', Component.displayName || Component.name || 'Component'); } + } - var nextChildren; - prepareToReadContext(workInProgress, renderLanes); + if (workInProgress.ref !== null) { + var info = ''; + var componentName = getComponentNameFromType(Component) || 'Unknown'; + var ownerName = getCurrentFiberOwnerNameInDevOrNull(); - { - markComponentRenderStarted(workInProgress); + if (ownerName) { + info += '\n\nCheck the render method of `' + ownerName + '`.'; } - { - ReactSharedInternals.owner = workInProgress; - setIsRendering(true); - nextChildren = renderWithHooks( - current, - workInProgress, - Component, - nextProps, - context, - renderLanes - ); - setIsRendering(false); - } + var warningKey = componentName + '|' + (ownerName || ''); - { - markComponentRenderStopped(); - } + if (!didWarnAboutFunctionRefs[warningKey]) { + didWarnAboutFunctionRefs[warningKey] = true; - if (current !== null && !didReceiveUpdate) { - bailoutHooks(current, workInProgress, renderLanes); - return bailoutOnAlreadyFinishedWork( - current, - workInProgress, - renderLanes - ); + error('Function components cannot be given refs. ' + 'Attempts to access this ref will fail. ' + 'Did you mean to use React.forwardRef()?%s', info); } - - workInProgress.flags |= PerformedWork; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; } - function replayFunctionComponent( - current, - workInProgress, - nextProps, - Component, - secondArg, - renderLanes - ) { - // 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. - prepareToReadContext(workInProgress, renderLanes); + if (!disableDefaultPropsExceptForClasses && Component.defaultProps !== undefined) { + var _componentName = getComponentNameFromType(Component) || 'Unknown'; - { - markComponentRenderStarted(workInProgress); + 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); + + didWarnAboutDefaultPropsOnFunctionComponent[_componentName] = true; } + } - var nextChildren = replaySuspendedComponentWithHooks( - current, - workInProgress, - Component, - nextProps, - secondArg - ); + if (typeof Component.getDerivedStateFromProps === 'function') { + var _componentName2 = getComponentNameFromType(Component) || 'Unknown'; - { - markComponentRenderStopped(); - } + if (!didWarnAboutGetDerivedStateOnFunctionComponent[_componentName2]) { + error('%s: Function components do not support getDerivedStateFromProps.', _componentName2); - if (current !== null && !didReceiveUpdate) { - bailoutHooks(current, workInProgress, renderLanes); - return bailoutOnAlreadyFinishedWork( - current, - workInProgress, - renderLanes - ); + didWarnAboutGetDerivedStateOnFunctionComponent[_componentName2] = true; } + } - workInProgress.flags |= PerformedWork; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; + if (typeof Component.contextType === 'object' && Component.contextType !== null) { + var _componentName3 = getComponentNameFromType(Component) || 'Unknown'; + + if (!didWarnAboutContextTypeOnFunctionComponent[_componentName3]) { + error('%s: Function components do not support contextType.', _componentName3); + + didWarnAboutContextTypeOnFunctionComponent[_componentName3] = true; + } } + } +} - 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? - - var tempInstance = new ctor( - workInProgress.memoizedProps, - _instance.context - ); - var state = tempInstance.state; +var SUSPENDED_MARKER = { + dehydrated: null, + treeContext: null, + retryLane: NoLane +}; + +function mountSuspenseOffscreenState(renderLanes) { + return { + baseLanes: renderLanes, + cachePool: getSuspendedCache() + }; +} - _instance.updater.enqueueSetState(_instance, state, null); +function updateSuspenseOffscreenState(prevOffscreenState, renderLanes) { + var cachePool = null; - break; - } + { + var prevCachePool = prevOffscreenState.cachePool; - case true: { - workInProgress.flags |= DidCapture; - workInProgress.flags |= ShouldCapture; // eslint-disable-next-line react-internal/prod-error-codes + if (prevCachePool !== null) { + var parentCache = CacheContext._currentValue ; - 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 (prevCachePool.parent !== parentCache) { + // Detected a refresh in the parent. This overrides any previously + // suspended cache. + cachePool = { + parent: parentCache, + pool: parentCache + }; + } else { + // We can reuse the cache from last time. The only thing that would have + // overridden it is a parent refresh, which we checked for above. + cachePool = prevCachePool; + } + } else { + // If there's no previous cache pool, grab the current one. + cachePool = getSuspendedCache(); + } + } + + return { + baseLanes: mergeLanes(prevOffscreenState.baseLanes, renderLanes), + cachePool: cachePool + }; +} // TODO: Probably should inline this back + + +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 (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. - 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." - ); - } + var suspenseContext = suspenseStackCursor.current; + return hasSuspenseListContext(suspenseContext, ForceSuspenseFallback); +} - var update = createClassErrorUpdate(lane); - initializeClassErrorUpdate( - update, - root, - workInProgress, - createCapturedValueAtFiber(error$1, workInProgress) - ); - enqueueCapturedUpdate(workInProgress, update); - break; - } - } - } // 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 getRemainingWorkInPrimaryTree(current, primaryTreeDidDefer, renderLanes) { + var remainingLanes = current !== null ? removeLanes(current.childLanes, renderLanes) : NoLanes; - var hasContext; + if (primaryTreeDidDefer) { + // A useDeferredValue hook spawned a deferred task inside the primary tree. + // Ensure that we retry this component at the deferred priority. + // TODO: We could make this a per-subtree value instead of a global one. + // Would need to track it on the context stack somehow, similar to what + // we'd have to do for resumable contexts. + remainingLanes = mergeLanes(remainingLanes, peekDeferredLane()); + } - if (isContextProvider(Component)) { - hasContext = true; - pushContextProvider(workInProgress); - } else { - hasContext = false; - } - - 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 - ); + return remainingLanes; +} - { - 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" - ); - } +function updateSuspenseComponent(current, workInProgress, renderLanes) { + var nextProps = workInProgress.pendingProps; // This is used by DevTools to force a boundary to suspend. + + { + if (shouldSuspend(workInProgress)) { + workInProgress.flags |= DidCapture; + } + } + + var showFallback = false; + var didSuspend = (workInProgress.flags & DidCapture) !== NoFlags$1; + + if (didSuspend || shouldRemainOnFallback(current)) { + // Something in this boundary's subtree already suspended. Switch to + // rendering the fallback children. + showFallback = true; + workInProgress.flags &= ~DidCapture; + } // Check if the primary children spawned a deferred task (useDeferredValue) + // during the first pass. + + + var didPrimaryChildrenDefer = (workInProgress.flags & DidDefer) !== NoFlags$1; + workInProgress.flags &= ~DidDefer; // 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. + + if (current === null) { + + var nextPrimaryChildren = nextProps.children; + var nextFallbackChildren = nextProps.fallback; + + if (showFallback) { + pushFallbackTreeSuspenseHandler(workInProgress); + var fallbackFragment = mountSuspenseFallbackChildren(workInProgress, nextPrimaryChildren, nextFallbackChildren, renderLanes); + var primaryChildFragment = workInProgress.child; + primaryChildFragment.memoizedState = mountSuspenseOffscreenState(renderLanes); + primaryChildFragment.childLanes = getRemainingWorkInPrimaryTree(current, didPrimaryChildrenDefer, renderLanes); + workInProgress.memoizedState = SUSPENDED_MARKER; + + 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); + + var _fallbackFragment = mountSuspenseFallbackChildren(workInProgress, nextPrimaryChildren, nextFallbackChildren, renderLanes); + + var _primaryChildFragment = workInProgress.child; + _primaryChildFragment.memoizedState = mountSuspenseOffscreenState(renderLanes); + _primaryChildFragment.childLanes = getRemainingWorkInPrimaryTree(current, didPrimaryChildrenDefer, 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 = SomeRetryLane; + return _fallbackFragment; + } else { + pushPrimaryTreeSuspenseHandler(workInProgress); + return mountSuspensePrimaryChildren(workInProgress, nextPrimaryChildren); + } + } else { + // This is an update. + // Special path for hydration + var prevState = current.memoizedState; + + if (prevState !== null) { + var _dehydrated = prevState.dehydrated; + + if (_dehydrated !== null) { + return updateDehydratedSuspenseComponent(current, workInProgress, didSuspend, didPrimaryChildrenDefer, nextProps, _dehydrated, prevState, renderLanes); + } + } + + 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); + + _primaryChildFragment2.childLanes = getRemainingWorkInPrimaryTree(current, didPrimaryChildrenDefer, renderLanes); + workInProgress.memoizedState = SUSPENDED_MARKER; + return fallbackChildFragment; + } else { + pushPrimaryTreeSuspenseHandler(workInProgress); + var _nextPrimaryChildren2 = nextProps.children; - didWarnAboutReassigningProps = true; - } - } + var _primaryChildFragment3 = updateSuspensePrimaryChildren(current, workInProgress, _nextPrimaryChildren2, renderLanes); - return nextUnitOfWork; + workInProgress.memoizedState = null; + return _primaryChildFragment3; } + } +} - function finishClassComponent( - current, - workInProgress, - Component, - shouldUpdate, - hasContext, - renderLanes - ) { - // Refs should update even if shouldComponentUpdate returns false - markRef(current, workInProgress); - var didCaptureError = (workInProgress.flags & DidCapture) !== NoFlags$1; +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 (!shouldUpdate && !didCaptureError) { - // Context providers should defer to sCU for rendering - if (hasContext) { - invalidateContextProvider(workInProgress, Component, false); - } +function mountSuspenseFallbackChildren(workInProgress, primaryChildren, fallbackChildren, 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; + + 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; + } + + 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; +} - return bailoutOnAlreadyFinishedWork( - current, - workInProgress, - renderLanes - ); - } +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); +} - var instance = workInProgress.stateNode; // Rerender +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); +} - { - ReactSharedInternals.owner = workInProgress; - } +function updateSuspensePrimaryChildren(current, workInProgress, primaryChildren, renderLanes) { + var currentPrimaryChildFragment = current.child; + var currentFallbackChildFragment = currentPrimaryChildFragment.sibling; + var primaryChildFragment = updateWorkInProgressOffscreenFiber(currentPrimaryChildFragment, { + mode: 'visible', + children: primaryChildren + }); - var nextChildren; + if ((workInProgress.mode & ConcurrentMode) === NoMode) { + primaryChildFragment.lanes = renderLanes; + } - 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; + primaryChildFragment.return = workInProgress; + primaryChildFragment.sibling = null; - { - stopProfilerTimerIfRunning(); - } - } else { - { - markComponentRenderStarted(workInProgress); - } + if (currentFallbackChildFragment !== null) { + // Delete the fallback child fragment + var deletions = workInProgress.deletions; - { - setIsRendering(true); - nextChildren = instance.render(); + if (deletions === null) { + workInProgress.deletions = [currentFallbackChildFragment]; + workInProgress.flags |= ChildDeletion; + } else { + deletions.push(currentFallbackChildFragment); + } + } + + workInProgress.child = primaryChildFragment; + return primaryChildFragment; +} - if (workInProgress.mode & StrictLegacyMode) { - setIsStrictModeForDevtools(true); +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 ( // 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 (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 { + 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.) + + primaryChildFragment.subtreeFlags = currentPrimaryChildFragment.subtreeFlags & StaticMask; + } + + var fallbackChildFragment; + + 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. + + fallbackChildFragment.flags |= Placement; + } + + fallbackChildFragment.return = workInProgress; + primaryChildFragment.return = workInProgress; + primaryChildFragment.sibling = fallbackChildFragment; + workInProgress.child = primaryChildFragment; + return fallbackChildFragment; +} - try { - instance.render(); - } finally { - setIsStrictModeForDevtools(false); - } - } +function retrySuspenseComponentWithoutHydrating(current, workInProgress, renderLanes) { + // 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. + // 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; +} - setIsRendering(false); - } +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; + + 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); + } + + return fallbackChildFragment; +} - { - markComponentRenderStopped(); - } - } // React DevTools reads this flag. - - workInProgress.flags |= PerformedWork; - - 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. +function updateDehydratedSuspenseComponent(current, workInProgress, didSuspend, didPrimaryChildrenDefer, 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 (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; + var message; + var stack = null; + var componentStack = null; + + { + var _getSuspenseInstanceF = getSuspenseInstanceFallbackErrorDetails(); + + digest = _getSuspenseInstanceF.digest; + message = _getSuspenseInstanceF.message; + stack = _getSuspenseInstanceF.stack; + componentStack = _getSuspenseInstanceF.componentStack; + } // TODO: Figure out a better signal than encoding a magic digest value. + + + { + var error; + + 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.'); + } // Replace the stack with the server stack - workInProgress.memoizedState = instance.state; // The context might have changed so we need to recalculate it. - if (hasContext) { - invalidateContextProvider(workInProgress, Component, true); + error.stack = stack || ''; + error.digest = digest; + var capturedValue = createCapturedValueFromError(error, componentStack === undefined ? null : componentStack); + queueHydrationError(capturedValue); } - return workInProgress.child; + return retrySuspenseComponentWithoutHydrating(current, workInProgress, renderLanes); } + // any context has changed, we need to treat is as if the input might have changed. - function pushHostRootContext(workInProgress) { - var root = workInProgress.stateNode; - if (root.pendingContext) { - pushTopLevelContextObject( - workInProgress, - root.pendingContext, - root.pendingContext !== root.context - ); - } else if (root.context) { - // Should always be set - pushTopLevelContextObject(workInProgress, root.context, false); - } + var hasContextChanged = includesSomeLane(renderLanes, current.childLanes); + + 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(); + + if (root !== null) { + var attemptHydrationAtLane = getBumpedLaneForHydration(root, renderLanes); + + 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; + enqueueConcurrentRenderForLane(current, attemptHydrationAtLane); + scheduleUpdateOnFiber(root, current, attemptHydrationAtLane); // 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. - pushHostContainer(workInProgress, root.containerInfo); + 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. + + + if (isSuspenseInstancePending()) ; else { + renderDidSuspendDelayIfPossible(); + } + + return retrySuspenseComponentWithoutHydrating(current, workInProgress, renderLanes); + } 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. + + workInProgress.child = current.child; // Register a callback to retry this boundary once the server has sent the result. + + 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. + + 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. + // The error should've already been logged in throwException. + pushPrimaryTreeSuspenseHandler(workInProgress); + workInProgress.flags &= ~ForceClientRender; + return retrySuspenseComponentWithoutHydrating(current, workInProgress, renderLanes); + } 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. + + 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); + _primaryChildFragment4.childLanes = getRemainingWorkInPrimaryTree(current, didPrimaryChildrenDefer, renderLanes); + workInProgress.memoizedState = SUSPENDED_MARKER; + return fallbackChildFragment; } + } +} - function updateHostRoot(current, workInProgress, renderLanes) { - pushHostRootContext(workInProgress); - - if (current === null) { - throw new Error("Should have a current fiber. This is a bug in React."); - } - - var nextProps = workInProgress.pendingProps; - var prevState = workInProgress.memoizedState; - var prevChildren = prevState.element; - cloneUpdateQueue(current, workInProgress); - processUpdateQueue(workInProgress, nextProps, null, renderLanes); - var nextState = workInProgress.memoizedState; - - { - var nextCache = nextState.cache; - pushCacheProvider(workInProgress, nextCache); +function scheduleSuspenseWorkOnFiber(fiber, renderLanes, propagationRoot) { + fiber.lanes = mergeLanes(fiber.lanes, renderLanes); + var alternate = fiber.alternate; - if (nextCache !== prevState.cache) { - // The root cache refreshed. - propagateContextChange(workInProgress, CacheContext, renderLanes); - } - } // This would ideally go inside processUpdateQueue, but because it suspends, - // it needs to happen after the `pushCacheProvider` call above to avoid a - // context stack mismatch. A bit unfortunate. + if (alternate !== null) { + alternate.lanes = mergeLanes(alternate.lanes, renderLanes); + } - suspendIfUpdateReadFromEntangledAsyncAction(); // Caution: React DevTools currently depends on this property - // being called "element". + scheduleContextWorkOnParentPath(fiber.return, renderLanes, propagationRoot); +} - var nextChildren = nextState.element; +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; - { - if (nextChildren === prevChildren) { - return bailoutOnAlreadyFinishedWork( - current, - workInProgress, - renderLanes - ); - } + while (node !== null) { + if (node.tag === SuspenseComponent) { + var state = node.memoizedState; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); + if (state !== null) { + scheduleSuspenseWorkOnFiber(node, renderLanes, workInProgress); } - - return workInProgress.child; + } 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; } - function updateHostComponent$1(current, workInProgress, renderLanes) { - pushHostContext(workInProgress); - var nextProps = workInProgress.pendingProps; - var prevProps = current !== null ? current.memoizedProps : null; - var nextChildren = nextProps.children; + if (node === workInProgress) { + return; + } // $FlowFixMe[incompatible-use] found when upgrading Flow - 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; - } - if (enableAsyncActions) { - var memoizedState = workInProgress.memoizedState; + while (node.sibling === null) { + // $FlowFixMe[incompatible-use] found when upgrading Flow + if (node.return === null || node.return === workInProgress) { + return; + } - if (memoizedState !== null) { - // This fiber has been upgraded to a stateful component. The only way - // happens currently is for form actions. We use hooks to track the - // pending and error state of the form. - // - // Once a fiber is upgraded to be stateful, it remains stateful for the - // rest of its lifetime. - var newState = renderTransitionAwareHostComponentWithHooks( - current, - workInProgress, - renderLanes - ); // If the transition state changed, propagate the change to all the - // descendents. We use Context as an implementation detail for this. - // - // This is intentionally set here instead of pushHostContext because - // pushHostContext gets called before we process the state hook, to avoid - // a state mismatch in the event that something suspends. - // - // NOTE: This assumes that there cannot be nested transition providers, - // because the only renderer that implements this feature is React DOM, - // and forms cannot be nested. If we did support nested providers, then - // we would need to push a context value even for host fibers that - // haven't been upgraded yet. + node = node.return; + } // $FlowFixMe[incompatible-use] found when upgrading Flow - { - HostTransitionContext._currentValue = newState; - } - { - if (didReceiveUpdate) { - if (current !== null) { - var oldStateHook = current.memoizedState; - var oldState = oldStateHook.memoizedState; // This uses regular equality instead of Object.is because we assume - // that host transition state doesn't include NaN as a valid type. - - if (oldState !== newState) { - propagateContextChange( - workInProgress, - HostTransitionContext, - renderLanes - ); - } - } - } - } - } - } + node.sibling.return = node.return; + node = node.sibling; + } +} - markRef(current, workInProgress); - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; - } +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; - function updateHostText$1(current, workInProgress) { - // immediately after. + while (row !== null) { + var currentRow = row.alternate; // New rows can't be content rows. - return null; + if (currentRow !== null && findFirstSuspended(currentRow) === null) { + lastContentRow = row; } - 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. - - workInProgress.type = Component; - - if (typeof Component === "function") { - if (isFunctionClassComponent(Component)) { - var resolvedProps = resolveClassComponentProps( - Component, - props, - false - ); - workInProgress.tag = ClassComponent; - - { - workInProgress.type = Component = - resolveClassForHotReloading(Component); - } - - return updateClassComponent( - null, - workInProgress, - Component, - resolvedProps, - renderLanes - ); - } else { - var _resolvedProps = disableDefaultPropsExceptForClasses - ? props - : resolveDefaultPropsOnNonClassComponent(Component, props); + row = row.sibling; + } - workInProgress.tag = FunctionComponent; + return lastContentRow; +} - { - validateFunctionComponentInDev(workInProgress, Component); - workInProgress.type = Component = - resolveFunctionForHotReloading(Component); - } +function validateRevealOrder(revealOrder) { + { + if (revealOrder !== undefined && revealOrder !== 'forwards' && revealOrder !== 'backwards' && revealOrder !== 'together' && !didWarnAboutRevealOrder[revealOrder]) { + didWarnAboutRevealOrder[revealOrder] = true; - return updateFunctionComponent( - null, - workInProgress, - Component, - _resolvedProps, - renderLanes - ); - } - } else if (Component !== undefined && Component !== null) { - var $$typeof = Component.$$typeof; + 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()); - if ($$typeof === REACT_FORWARD_REF_TYPE) { - var _resolvedProps2 = disableDefaultPropsExceptForClasses - ? props - : resolveDefaultPropsOnNonClassComponent(Component, props); + break; + } - workInProgress.tag = ForwardRef; + 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()); - { - workInProgress.type = Component = - resolveForwardRefForHotReloading(Component); - } + break; + } - return updateForwardRef( - null, - workInProgress, - Component, - _resolvedProps2, - renderLanes - ); - } else if ($$typeof === REACT_MEMO_TYPE) { - var _resolvedProps3 = disableDefaultPropsExceptForClasses - ? props - : resolveDefaultPropsOnNonClassComponent(Component, props); - - workInProgress.tag = MemoComponent; - return updateMemoComponent( - null, - workInProgress, - Component, - disableDefaultPropsExceptForClasses - ? _resolvedProps3 - : resolveDefaultPropsOnNonClassComponent( - Component.type, - _resolvedProps3 - ), // The inner type can have defaults too - renderLanes - ); - } - } - - var hint = ""; + default: + error('"%s" is not a supported revealOrder on . ' + 'Did you mean "together", "forwards" or "backwards"?', revealOrder); - { - 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) - ); - } - - function mountIncompleteClassComponent( - _current, - workInProgress, - Component, - nextProps, - renderLanes - ) { - resetSuspendedCurrentOnMountInLegacyMode(_current, workInProgress); // Promote the fiber to a class and try rendering again. - - 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. - - var hasContext; - - if (isContextProvider(Component)) { - hasContext = true; - pushContextProvider(workInProgress); + break; + } } else { - hasContext = false; + error('%s is not a supported value for revealOrder on . ' + 'Did you mean "together", "forwards" or "backwards"?', revealOrder); } - - prepareToReadContext(workInProgress, renderLanes); - constructClassInstance(workInProgress, Component, nextProps); - mountClassInstance(workInProgress, Component, nextProps, renderLanes); - return finishClassComponent( - null, - workInProgress, - Component, - true, - hasContext, - renderLanes - ); } + } +} - function validateFunctionComponentInDev(workInProgress, Component) { - { - if (Component) { - if (Component.childContextTypes) { - error( - "childContextTypes cannot be defined on a function component.\n" + - " %s.childContextTypes = ...", - Component.displayName || Component.name || "Component" - ); - } - } +function validateTailOptions(tailMode, revealOrder) { + { + if (tailMode !== undefined && !didWarnAboutTailOptions[tailMode]) { + if (tailMode !== 'collapsed' && tailMode !== 'hidden') { + didWarnAboutTailOptions[tailMode] = true; - if (workInProgress.ref !== null) { - var info = ""; - var componentName = getComponentNameFromType(Component) || "Unknown"; - var ownerName = getCurrentFiberOwnerNameInDevOrNull(); + 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 (ownerName) { - info += "\n\nCheck the render method of `" + ownerName + "`."; - } + error(' is only valid if revealOrder is ' + '"forwards" or "backwards". ' + 'Did you mean to specify revealOrder="forwards"?', tailMode); + } + } + } +} - var warningKey = componentName + "|" + (ownerName || ""); +function validateSuspenseListNestedChild(childSlot, index) { + { + var isAnArray = isArray(childSlot); + var isIterable = !isAnArray && typeof getIteratorFn(childSlot) === 'function'; - if (!didWarnAboutFunctionRefs[warningKey]) { - didWarnAboutFunctionRefs[warningKey] = true; + if (isAnArray || isIterable) { + var type = isAnArray ? 'array' : 'iterable'; - error( - "Function components cannot be given refs. " + - "Attempts to access this ref will fail. " + - "Did you mean to use React.forwardRef()?%s", - info - ); - } - } + error('A nested %s was passed to row #%s in . Wrap it in ' + 'an additional SuspenseList to configure its revealOrder: ' + ' ... ' + '{%s} ... ' + '', type, index, type); - if ( - !disableDefaultPropsExceptForClasses && - Component.defaultProps !== undefined - ) { - var _componentName = getComponentNameFromType(Component) || "Unknown"; + return false; + } + } - 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 - ); + return true; +} - didWarnAboutDefaultPropsOnFunctionComponent[_componentName] = true; +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); - if (typeof Component.getDerivedStateFromProps === "function") { - var _componentName2 = - getComponentNameFromType(Component) || "Unknown"; - - if ( - !didWarnAboutGetDerivedStateOnFunctionComponent[_componentName2] - ) { - error( - "%s: Function components do not support getDerivedStateFromProps.", - _componentName2 - ); - - didWarnAboutGetDerivedStateOnFunctionComponent[_componentName2] = - true; - } - } + if (typeof iteratorFn === 'function') { + var childrenIterator = iteratorFn.call(children); - if ( - typeof Component.contextType === "object" && - Component.contextType !== null - ) { - var _componentName3 = - getComponentNameFromType(Component) || "Unknown"; + if (childrenIterator) { + var step = childrenIterator.next(); + var _i = 0; - if (!didWarnAboutContextTypeOnFunctionComponent[_componentName3]) { - error( - "%s: Function components do not support contextType.", - _componentName3 - ); + for (; !step.done; step = childrenIterator.next()) { + if (!validateSuspenseListNestedChild(step.value, _i)) { + return; + } - didWarnAboutContextTypeOnFunctionComponent[_componentName3] = true; + _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); } } } + } +} - var SUSPENDED_MARKER = { - dehydrated: null, - treeContext: null, - retryLane: NoLane +function initSuspenseListRenderState(workInProgress, isBackwards, tail, lastContentRow, tailMode) { + var renderState = workInProgress.memoizedState; + + 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. + + +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 (shouldForceFallback) { + suspenseContext = setShallowSuspenseListContext(suspenseContext, ForceSuspenseFallback); + workInProgress.flags |= DidCapture; + } else { + var didSuspendBefore = current !== null && (current.flags & DidCapture) !== NoFlags$1; + + 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); + } + + suspenseContext = setDefaultShallowSuspenseListContext(suspenseContext); + } + + 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; - function mountSuspenseOffscreenState(renderLanes) { - return { - baseLanes: renderLanes, - cachePool: getSuspendedCache() - }; - } + 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; + } - function updateSuspenseOffscreenState(prevOffscreenState, renderLanes) { - var cachePool = null; + initSuspenseListRenderState(workInProgress, false, // isBackwards + tail, lastContentRow, tailMode); + break; + } - { - var prevCachePool = prevOffscreenState.cachePool; + 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; + + while (row !== null) { + var currentRow = row.alternate; // New rows can't be content rows. + + if (currentRow !== null && findFirstSuspended(currentRow) === null) { + // This is the beginning of the main content. + workInProgress.child = row; + break; + } - if (prevCachePool !== null) { - var parentCache = CacheContext._currentValue; + var nextRow = row.sibling; + row.sibling = _tail; + _tail = row; + row = nextRow; + } // TODO: If workInProgress.child is null, we can continue on the tail immediately. - if (prevCachePool.parent !== parentCache) { - // Detected a refresh in the parent. This overrides any previously - // suspended cache. - cachePool = { - parent: parentCache, - pool: parentCache - }; - } else { - // We can reuse the cache from last time. The only thing that would have - // overridden it is a parent refresh, which we checked for above. - cachePool = prevCachePool; - } - } else { - // If there's no previous cache pool, grab the current one. - cachePool = getSuspendedCache(); - } - } - return { - baseLanes: mergeLanes(prevOffscreenState.baseLanes, renderLanes), - cachePool: cachePool - }; - } // TODO: Probably should inline this back - - 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; + initSuspenseListRenderState(workInProgress, true, // isBackwards + _tail, null, // last + tailMode); + 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; + case 'together': + { + initSuspenseListRenderState(workInProgress, false, // isBackwards + null, // tail + null, // last + undefined); + break; } - } // Not currently showing content. Consult the Suspense context. - var suspenseContext = suspenseStackCursor.current; - return hasSuspenseListContext(suspenseContext, ForceSuspenseFallback); + default: + { + // The default reveal order is the same as not having + // a boundary. + workInProgress.memoizedState = null; + } } + } - function getRemainingWorkInPrimaryTree( - current, - primaryTreeDidDefer, - renderLanes - ) { - var remainingLanes = - current !== null - ? removeLanes(current.childLanes, renderLanes) - : NoLanes; + return workInProgress.child; +} - if (primaryTreeDidDefer) { - // A useDeferredValue hook spawned a deferred task inside the primary tree. - // Ensure that we retry this component at the deferred priority. - // TODO: We could make this a per-subtree value instead of a global one. - // Would need to track it on the context stack somehow, similar to what - // we'd have to do for resumable contexts. - remainingLanes = mergeLanes(remainingLanes, peekDeferredLane()); - } +function updatePortalComponent(current, workInProgress, renderLanes) { + pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); + var nextChildren = workInProgress.pendingProps; + + 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); + } + + return workInProgress.child; +} - return remainingLanes; - } +var hasWarnedAboutUsingNoValuePropOnContextProvider = false; - function updateSuspenseComponent(current, workInProgress, renderLanes) { - var nextProps = workInProgress.pendingProps; // This is used by DevTools to force a boundary to suspend. +function updateContextProvider(current, workInProgress, renderLanes) { + var context; - { - if (shouldSuspend(workInProgress)) { - workInProgress.flags |= DidCapture; - } + if (enableRenderableContext) { + context = workInProgress.type; + } else { + context = workInProgress.type._context; + } + + var newProps = workInProgress.pendingProps; + var oldProps = workInProgress.memoizedProps; + var newValue = newProps.value; + + { + 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?'); } + } + } - var showFallback = false; - var didSuspend = (workInProgress.flags & DidCapture) !== NoFlags$1; + pushProvider(workInProgress, context, newValue); - if (didSuspend || shouldRemainOnFallback(current)) { - // Something in this boundary's subtree already suspended. Switch to - // rendering the fallback children. - showFallback = true; - workInProgress.flags &= ~DidCapture; - } // Check if the primary children spawned a deferred task (useDeferredValue) - // during the first pass. + { + if (oldProps !== null) { + var oldValue = oldProps.value; - var didPrimaryChildrenDefer = - (workInProgress.flags & DidDefer) !== NoFlags$1; - workInProgress.flags &= ~DidDefer; // 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. - - if (current === null) { - var nextPrimaryChildren = nextProps.children; - var nextFallbackChildren = nextProps.fallback; - - if (showFallback) { - pushFallbackTreeSuspenseHandler(workInProgress); - var fallbackFragment = mountSuspenseFallbackChildren( - workInProgress, - nextPrimaryChildren, - nextFallbackChildren, - renderLanes - ); - var primaryChildFragment = workInProgress.child; - primaryChildFragment.memoizedState = - mountSuspenseOffscreenState(renderLanes); - primaryChildFragment.childLanes = getRemainingWorkInPrimaryTree( - current, - didPrimaryChildrenDefer, - renderLanes - ); - workInProgress.memoizedState = SUSPENDED_MARKER; - - 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); - - var _fallbackFragment = mountSuspenseFallbackChildren( - workInProgress, - nextPrimaryChildren, - nextFallbackChildren, - renderLanes - ); - - var _primaryChildFragment = workInProgress.child; - _primaryChildFragment.memoizedState = - mountSuspenseOffscreenState(renderLanes); - _primaryChildFragment.childLanes = getRemainingWorkInPrimaryTree( - current, - didPrimaryChildrenDefer, - 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 = SomeRetryLane; - return _fallbackFragment; - } else { - pushPrimaryTreeSuspenseHandler(workInProgress); - return mountSuspensePrimaryChildren( - workInProgress, - nextPrimaryChildren - ); + 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 { - // This is an update. - // Special path for hydration - var prevState = current.memoizedState; + // The context value changed. Search for matching consumers and schedule + // them to update. + propagateContextChange(workInProgress, context, renderLanes); + } + } + } - if (prevState !== null) { - var _dehydrated = prevState.dehydrated; - - if (_dehydrated !== null) { - return updateDehydratedSuspenseComponent( - current, - workInProgress, - didSuspend, - didPrimaryChildrenDefer, - nextProps, - _dehydrated, - prevState, - renderLanes - ); - } - } + var newChildren = newProps.children; + reconcileChildren(current, workInProgress, newChildren, renderLanes); + return workInProgress.child; +} - 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); - - _primaryChildFragment2.childLanes = getRemainingWorkInPrimaryTree( - current, - didPrimaryChildrenDefer, - renderLanes - ); - workInProgress.memoizedState = SUSPENDED_MARKER; - return fallbackChildFragment; - } else { - pushPrimaryTreeSuspenseHandler(workInProgress); - var _nextPrimaryChildren2 = nextProps.children; +function updateContextConsumer(current, workInProgress, renderLanes) { + var context; - var _primaryChildFragment3 = updateSuspensePrimaryChildren( - current, - workInProgress, - _nextPrimaryChildren2, - renderLanes - ); + if (enableRenderableContext) { + var consumerType = workInProgress.type; + context = consumerType._context; + } else { + context = workInProgress.type; - workInProgress.memoizedState = null; - return _primaryChildFragment3; - } + { + if (context._context !== undefined) { + context = context._context; } } + } - 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; - } + var newProps = workInProgress.pendingProps; + var render = newProps.children; - function mountSuspenseFallbackChildren( - workInProgress, - primaryChildren, - fallbackChildren, - 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; - - 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; - } - - 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; + { + 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 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; - } - - primaryChildFragment.return = workInProgress; - primaryChildFragment.sibling = null; + prepareToReadContext(workInProgress, renderLanes); + var newValue = readContext(context); - if (currentFallbackChildFragment !== null) { - // Delete the fallback child fragment - var deletions = workInProgress.deletions; + { + markComponentRenderStarted(workInProgress); + } - if (deletions === null) { - workInProgress.deletions = [currentFallbackChildFragment]; - workInProgress.flags |= ChildDeletion; - } else { - deletions.push(currentFallbackChildFragment); - } - } + var newChildren; - workInProgress.child = primaryChildFragment; - return primaryChildFragment; - } + { + ReactSharedInternals.owner = workInProgress; + setIsRendering(true); + newChildren = render(newValue); + setIsRendering(false); + } - 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 ( - // 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 (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 { - 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.) + { + markComponentRenderStopped(); + } // React DevTools reads this flag. - primaryChildFragment.subtreeFlags = - currentPrimaryChildFragment.subtreeFlags & StaticMask; - } - var fallbackChildFragment; + workInProgress.flags |= PerformedWork; + reconcileChildren(current, workInProgress, newChildren, renderLanes); + return workInProgress.child; +} - 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. +function markWorkInProgressReceivedUpdate() { + didReceiveUpdate = true; +} - fallbackChildFragment.flags |= Placement; - } +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 - fallbackChildFragment.return = workInProgress; - primaryChildFragment.return = workInProgress; - primaryChildFragment.sibling = fallbackChildFragment; - workInProgress.child = primaryChildFragment; - return fallbackChildFragment; + workInProgress.flags |= Placement; } + } +} - function retrySuspenseComponentWithoutHydrating( - current, - workInProgress, - renderLanes - ) { - // 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. - // This will add the old fiber to the deletion list - reconcileChildFibers(workInProgress, current.child, null, renderLanes); // We're now not suspended nor dehydrated. +function bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes) { + if (current !== null) { + // Reuse previous dependencies + workInProgress.dependencies = current.dependencies; + } - 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. + { + // Don't update "base" render times for bailouts. + stopProfilerTimerIfRunning(); + } - primaryChildFragment.flags |= Placement; - workInProgress.memoizedState = null; - return primaryChildFragment; + markSkippedUpdateLanes(workInProgress.lanes); // Check if the children have any pending work. + + 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. - 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; - - 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); - } - return fallbackChildFragment; - } + cloneChildFibers(current, workInProgress); + return workInProgress.child; +} - function updateDehydratedSuspenseComponent( - current, - workInProgress, - didSuspend, - didPrimaryChildrenDefer, - 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 (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; - var message; - var stack = null; - var componentStack = null; +function remountFiber(current, oldWorkInProgress, newWorkInProgress) { + { + var returnFiber = oldWorkInProgress.return; - { - var _getSuspenseInstanceF = - getSuspenseInstanceFallbackErrorDetails(); + 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. - digest = _getSuspenseInstanceF.digest; - message = _getSuspenseInstanceF.message; - stack = _getSuspenseInstanceF.stack; - componentStack = _getSuspenseInstanceF.componentStack; - } // TODO: Figure out a better signal than encoding a magic digest value. - { - var error; + current.alternate = null; + oldWorkInProgress.alternate = null; // Connect to the new tree. - 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." - ); - } // Replace the stack with the server stack - - error.stack = stack || ""; - error.digest = digest; - var capturedValue = createCapturedValueFromError( - error, - componentStack === undefined ? null : componentStack - ); - queueHydrationError(capturedValue); - } + newWorkInProgress.index = oldWorkInProgress.index; + newWorkInProgress.sibling = oldWorkInProgress.sibling; + newWorkInProgress.return = oldWorkInProgress.return; + newWorkInProgress.ref = oldWorkInProgress.ref; - return retrySuspenseComponentWithoutHydrating( - current, - workInProgress, - renderLanes - ); - } - // any context has changed, we need to treat is as if the input might have changed. + { + newWorkInProgress._debugInfo = oldWorkInProgress._debugInfo; + } // Replace the child/sibling pointers above it. - var hasContextChanged = includesSomeLane( - renderLanes, - current.childLanes - ); - 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(); + if (oldWorkInProgress === returnFiber.child) { + returnFiber.child = newWorkInProgress; + } else { + var prevSibling = returnFiber.child; - if (root !== null) { - var attemptHydrationAtLane = getBumpedLaneForHydration( - root, - renderLanes - ); + 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 - 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; - enqueueConcurrentRenderForLane(current, attemptHydrationAtLane); - scheduleUpdateOnFiber(root, current, attemptHydrationAtLane); // 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. - 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. - - if (isSuspenseInstancePending()); - else { - renderDidSuspendDelayIfPossible(); - } + while (prevSibling.sibling !== oldWorkInProgress) { + // $FlowFixMe[incompatible-use] found when upgrading Flow + prevSibling = prevSibling.sibling; - return retrySuspenseComponentWithoutHydrating( - current, - workInProgress, - renderLanes - ); - } 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. - - workInProgress.child = current.child; // Register a callback to retry this boundary once the server has sent the result. - - 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. - - primaryChildFragment.flags |= Hydrating; - return primaryChildFragment; + if (prevSibling === null) { + // eslint-disable-next-line react-internal/prod-error-codes + throw new Error('Expected to find the previous sibling.'); } - } 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. - // The error should've already been logged in throwException. - pushPrimaryTreeSuspenseHandler(workInProgress); - workInProgress.flags &= ~ForceClientRender; - return retrySuspenseComponentWithoutHydrating( - current, - workInProgress, - renderLanes - ); - } 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. + } // $FlowFixMe[incompatible-use] found when upgrading Flow - 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); - _primaryChildFragment4.childLanes = getRemainingWorkInPrimaryTree( - current, - didPrimaryChildrenDefer, - renderLanes - ); - workInProgress.memoizedState = SUSPENDED_MARKER; - return fallbackChildFragment; - } - } - } - function scheduleSuspenseWorkOnFiber(fiber, renderLanes, propagationRoot) { - fiber.lanes = mergeLanes(fiber.lanes, renderLanes); - var alternate = fiber.alternate; + prevSibling.sibling = newWorkInProgress; + } // Delete the old fiber and place the new one. + // Since the old fiber is disconnected, we have to schedule it manually. - if (alternate !== null) { - alternate.lanes = mergeLanes(alternate.lanes, renderLanes); - } - scheduleContextWorkOnParentPath( - fiber.return, - renderLanes, - propagationRoot - ); + var deletions = returnFiber.deletions; + + if (deletions === null) { + returnFiber.deletions = [current]; + returnFiber.flags |= ChildDeletion; + } else { + deletions.push(current); } - 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; + newWorkInProgress.flags |= Placement; // Restart work from the new fiber. - while (node !== null) { - if (node.tag === SuspenseComponent) { - var state = node.memoizedState; + return newWorkInProgress; + } +} - 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; - } +function checkScheduledUpdateOrContext(current, renderLanes) { + // Before performing an early bailout, we must check if there are pending + // updates or context. + var updateLanes = current.lanes; - if (node === workInProgress) { - return; - } // $FlowFixMe[incompatible-use] found when upgrading Flow + if (includesSomeLane(updateLanes, renderLanes)) { + return true; + } // No pending update, but because context is propagated lazily, we need - while (node.sibling === null) { - // $FlowFixMe[incompatible-use] found when upgrading Flow - if (node.return === null || node.return === workInProgress) { - return; - } + return false; +} - node = node.return; - } // $FlowFixMe[incompatible-use] found when upgrading Flow +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); - node.sibling.return = node.return; - node = node.sibling; + { + var cache = current.memoizedState.cache; + pushCacheProvider(workInProgress, cache); } - } + break; - 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; + case HostSingleton: + case HostComponent: + pushHostContext(workInProgress); + break; - while (row !== null) { - var currentRow = row.alternate; // New rows can't be content rows. + case ClassComponent: + { + var Component = workInProgress.type; - if (currentRow !== null && findFirstSuspended(currentRow) === null) { - lastContentRow = row; + if (isContextProvider(Component)) { + pushContextProvider(workInProgress); } - row = row.sibling; + break; } - return lastContentRow; - } + case HostPortal: + pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); + break; - function validateRevealOrder(revealOrder) { + case ContextProvider: { - if ( - revealOrder !== undefined && - revealOrder !== "forwards" && - revealOrder !== "backwards" && - revealOrder !== "together" && - !didWarnAboutRevealOrder[revealOrder] - ) { - didWarnAboutRevealOrder[revealOrder] = true; - - 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; - } + var newValue = workInProgress.memoizedProps.value; + var context; - 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() - ); + if (enableRenderableContext) { + context = workInProgress.type; + } else { + context = workInProgress.type._context; + } - break; - } + pushProvider(workInProgress, context, newValue); + break; + } - default: - error( - '"%s" is not a supported revealOrder on . ' + - 'Did you mean "together", "forwards" or "backwards"?', - revealOrder - ); + case Profiler: + { + // Profiler should only call onRender when one of its descendants actually rendered. + var hasChildWork = includesSomeLane(renderLanes, workInProgress.childLanes); - break; - } - } else { - error( - "%s is not a supported value for revealOrder on . " + - 'Did you mean "together", "forwards" or "backwards"?', - revealOrder - ); - } + if (hasChildWork) { + workInProgress.flags |= Update; } - } - } - function validateTailOptions(tailMode, revealOrder) { - { - 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; - - error( - ' is only valid if revealOrder is ' + - '"forwards" or "backwards". ' + - 'Did you mean to specify revealOrder="forwards"?', - tailMode - ); - } + { + // 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; } } - } - function validateSuspenseListNestedChild(childSlot, index) { + break; + + case SuspenseComponent: { - var isAnArray = isArray(childSlot); - var isIterable = - !isAnArray && typeof getIteratorFn(childSlot) === "function"; - - if (isAnArray || isIterable) { - var type = isAnArray ? "array" : "iterable"; - - error( - "A nested %s was passed to row #%s in . Wrap it in " + - "an additional SuspenseList to configure its revealOrder: " + - " ... " + - "{%s} ... " + - "", - type, - index, - type - ); + var state = workInProgress.memoizedState; - return false; - } - } + 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. - return true; - } + workInProgress.flags |= DidCapture; // We should never render the children of a dehydrated boundary until we + // upgrade it. We return null instead of bailoutOnAlreadyFinishedWork. - 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); + 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. - if (typeof iteratorFn === "function") { - var childrenIterator = iteratorFn.call(children); - if (childrenIterator) { - var step = childrenIterator.next(); - var _i = 0; + var primaryChildFragment = workInProgress.child; + var primaryChildLanes = primaryChildFragment.childLanes; - for (; !step.done; step = childrenIterator.next()) { - if (!validateSuspenseListNestedChild(step.value, _i)) { - return; - } + 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. - _i++; - } - } + var child = bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); + + if (child !== null) { + // The fallback children have pending work. Skip over the + // primary children and work on the fallback. + return child.sibling; } 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 - ); + // 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); } + + break; } - } - function initSuspenseListRenderState( - workInProgress, - isBackwards, - tail, - lastContentRow, - tailMode - ) { - var renderState = workInProgress.memoizedState; + case SuspenseListComponent: + { + var didSuspendBefore = (current.flags & DidCapture) !== NoFlags$1; - 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. - - 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 (shouldForceFallback) { - suspenseContext = setShallowSuspenseListContext( - suspenseContext, - ForceSuspenseFallback - ); - workInProgress.flags |= DidCapture; - } else { - var didSuspendBefore = - current !== null && (current.flags & DidCapture) !== NoFlags$1; + var _hasChildWork = includesSomeLane(renderLanes, workInProgress.childLanes); 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 - ); - } - - suspenseContext = setDefaultShallowSuspenseListContext(suspenseContext); - } + 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. - 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; - } + 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. - initSuspenseListRenderState( - workInProgress, - false, // isBackwards - tail, - lastContentRow, - tailMode - ); - break; - } - 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; + var renderState = workInProgress.memoizedState; - while (row !== null) { - var currentRow = row.alternate; // New rows can't be content rows. + 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; + } - if ( - currentRow !== null && - findFirstSuspended(currentRow) === null - ) { - // This is the beginning of the main content. - workInProgress.child = row; - break; - } + pushSuspenseListContext(workInProgress, suspenseStackCursor.current); - var nextRow = row.sibling; - row.sibling = _tail; - _tail = row; - row = nextRow; - } // TODO: If workInProgress.child is null, we can continue on the tail immediately. - - initSuspenseListRenderState( - workInProgress, - true, // isBackwards - _tail, - null, // last - tailMode - ); - break; - } + 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; + } + } - case "together": { - initSuspenseListRenderState( - workInProgress, - false, // isBackwards - null, // tail - null, // last - undefined - ); - break; - } + 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); + } - default: { - // The default reveal order is the same as not having - // a boundary. - workInProgress.memoizedState = null; - } + case CacheComponent: + { + { + var _cache = current.memoizedState.cache; + pushCacheProvider(workInProgress, _cache); } + + break; } + } + + return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); +} - return workInProgress.child; +function beginWork(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)); } + } - function updatePortalComponent(current, workInProgress, renderLanes) { - pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); - var nextChildren = workInProgress.pendingProps; - - 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 (current !== null) { + var oldProps = current.memoizedProps; + var newProps = workInProgress.pendingProps; + + 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); + + 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); } - return workInProgress.child; + 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; + } } + } 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. - var hasWarnedAboutUsingNoValuePropOnContextProvider = false; - function updateContextProvider(current, workInProgress, renderLanes) { - var context; + workInProgress.lanes = NoLanes; - if (enableRenderableContext) { - context = workInProgress.type; - } else { - context = workInProgress.type._context; + switch (workInProgress.tag) { + case LazyComponent: + { + var elementType = workInProgress.elementType; + return mountLazyComponent(current, workInProgress, elementType, renderLanes); } - var newProps = workInProgress.pendingProps; - var oldProps = workInProgress.memoizedProps; - var newValue = newProps.value; + case FunctionComponent: + { + var Component = workInProgress.type; + var unresolvedProps = workInProgress.pendingProps; + var resolvedProps = disableDefaultPropsExceptForClasses || workInProgress.elementType === Component ? unresolvedProps : resolveDefaultPropsOnNonClassComponent(Component, unresolvedProps); + return updateFunctionComponent(current, workInProgress, Component, resolvedProps, renderLanes); + } + case ClassComponent: { - if (!("value" in newProps)) { - if (!hasWarnedAboutUsingNoValuePropOnContextProvider) { - hasWarnedAboutUsingNoValuePropOnContextProvider = true; + var _Component = workInProgress.type; + var _unresolvedProps = workInProgress.pendingProps; - error( - "The `value` prop is required for the ``. Did you misspell it or forget to pass it?" - ); - } - } + var _resolvedProps4 = resolveClassComponentProps(_Component, _unresolvedProps, workInProgress.elementType === _Component); + + return updateClassComponent(current, workInProgress, _Component, _resolvedProps4, renderLanes); } - pushProvider(workInProgress, context, newValue); + case HostRoot: + return updateHostRoot(current, workInProgress, renderLanes); - { - if (oldProps !== null) { - var oldValue = oldProps.value; - - 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); - } - } - } + case HostHoistable: - var newChildren = newProps.children; - reconcileChildren(current, workInProgress, newChildren, renderLanes); - return workInProgress.child; - } + // Fall through - function updateContextConsumer(current, workInProgress, renderLanes) { - var context; + case HostSingleton: - if (enableRenderableContext) { - var consumerType = workInProgress.type; - context = consumerType._context; - } else { - context = workInProgress.type; + // Fall through - { - if (context._context !== undefined) { - context = context._context; - } - } - } + case HostComponent: + return updateHostComponent$1(current, workInProgress, renderLanes); - var newProps = workInProgress.pendingProps; - var render = newProps.children; + case HostText: + return updateHostText$1(); - { - 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." - ); - } - } + case SuspenseComponent: + return updateSuspenseComponent(current, workInProgress, renderLanes); - prepareToReadContext(workInProgress, renderLanes); - var newValue = readContext(context); + case HostPortal: + return updatePortalComponent(current, workInProgress, renderLanes); + case ForwardRef: { - markComponentRenderStarted(workInProgress); - } + var type = workInProgress.type; + var _unresolvedProps2 = workInProgress.pendingProps; - var newChildren; + var _resolvedProps5 = disableDefaultPropsExceptForClasses || workInProgress.elementType === type ? _unresolvedProps2 : resolveDefaultPropsOnNonClassComponent(type, _unresolvedProps2); - { - ReactSharedInternals.owner = workInProgress; - setIsRendering(true); - newChildren = render(newValue); - setIsRendering(false); + return updateForwardRef(current, workInProgress, type, _resolvedProps5, renderLanes); } - { - markComponentRenderStopped(); - } // React DevTools reads this flag. + case Fragment: + return updateFragment(current, workInProgress, renderLanes); - workInProgress.flags |= PerformedWork; - reconcileChildren(current, workInProgress, newChildren, renderLanes); - return workInProgress.child; - } + case Mode: + return updateMode(current, workInProgress, renderLanes); - function markWorkInProgressReceivedUpdate() { - didReceiveUpdate = true; - } + case Profiler: + return updateProfiler(current, workInProgress, renderLanes); - 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 + case ContextProvider: + return updateContextProvider(current, workInProgress, renderLanes); - workInProgress.flags |= Placement; - } - } - } + case ContextConsumer: + return updateContextConsumer(current, workInProgress, renderLanes); - function bailoutOnAlreadyFinishedWork( - current, - workInProgress, - renderLanes - ) { - if (current !== null) { - // Reuse previous dependencies - workInProgress.dependencies = current.dependencies; + case MemoComponent: + { + var _type = workInProgress.type; + var _unresolvedProps3 = workInProgress.pendingProps; // Resolve outer props first, then resolve inner props. + + var _resolvedProps6 = disableDefaultPropsExceptForClasses ? _unresolvedProps3 : resolveDefaultPropsOnNonClassComponent(_type, _unresolvedProps3); + + _resolvedProps6 = disableDefaultPropsExceptForClasses ? _resolvedProps6 : resolveDefaultPropsOnNonClassComponent(_type.type, _resolvedProps6); + return updateMemoComponent(current, workInProgress, _type, _resolvedProps6, renderLanes); } + case SimpleMemoComponent: { - // Don't update "base" render times for bailouts. - stopProfilerTimerIfRunning(); + return updateSimpleMemoComponent(current, workInProgress, workInProgress.type, workInProgress.pendingProps, renderLanes); } - markSkippedUpdateLanes(workInProgress.lanes); // Check if the children have any pending work. + case IncompleteClassComponent: + { - 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. + var _Component2 = workInProgress.type; + var _unresolvedProps4 = workInProgress.pendingProps; - cloneChildFibers(current, workInProgress); - return workInProgress.child; - } + var _resolvedProps7 = resolveClassComponentProps(_Component2, _unresolvedProps4, workInProgress.elementType === _Component2); - function remountFiber(current, oldWorkInProgress, newWorkInProgress) { - { - var returnFiber = oldWorkInProgress.return; + return mountIncompleteClassComponent(current, workInProgress, _Component2, _resolvedProps7, renderLanes); + } - 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. + case IncompleteFunctionComponent: + { - current.alternate = null; - oldWorkInProgress.alternate = null; // Connect to the new tree. + var _Component3 = workInProgress.type; + var _unresolvedProps5 = workInProgress.pendingProps; - newWorkInProgress.index = oldWorkInProgress.index; - newWorkInProgress.sibling = oldWorkInProgress.sibling; - newWorkInProgress.return = oldWorkInProgress.return; - newWorkInProgress.ref = oldWorkInProgress.ref; + var _resolvedProps8 = resolveClassComponentProps(_Component3, _unresolvedProps5, workInProgress.elementType === _Component3); - { - newWorkInProgress._debugInfo = oldWorkInProgress._debugInfo; - } // Replace the child/sibling pointers above it. + return mountIncompleteFunctionComponent(current, workInProgress, _Component3, _resolvedProps8, renderLanes); + } - if (oldWorkInProgress === returnFiber.child) { - returnFiber.child = newWorkInProgress; - } else { - var prevSibling = returnFiber.child; + case SuspenseListComponent: + { + return updateSuspenseListComponent(current, workInProgress, renderLanes); + } - 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 + case ScopeComponent: + { - while (prevSibling.sibling !== oldWorkInProgress) { - // $FlowFixMe[incompatible-use] found when upgrading Flow - prevSibling = prevSibling.sibling; + break; + } - 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 + case OffscreenComponent: + { + return updateOffscreenComponent(current, workInProgress, renderLanes); + } - prevSibling.sibling = newWorkInProgress; - } // Delete the old fiber and place the new one. - // Since the old fiber is disconnected, we have to schedule it manually. + case LegacyHiddenComponent: + { - var deletions = returnFiber.deletions; + break; + } - if (deletions === null) { - returnFiber.deletions = [current]; - returnFiber.flags |= ChildDeletion; - } else { - deletions.push(current); + case CacheComponent: + { + { + return updateCacheComponent(current, workInProgress, renderLanes); } + } + } - newWorkInProgress.flags |= Placement; // Restart work from the new fiber. + throw new Error("Unknown unit of work tag (" + workInProgress.tag + "). This error is likely caused by a bug in " + 'React. Please file an issue.'); +} - return newWorkInProgress; - } - } +var valueCursor = createCursor(null); +var rendererCursorDEV; - function checkScheduledUpdateOrContext(current, renderLanes) { - // Before performing an early bailout, we must check if there are pending - // updates or context. - var updateLanes = current.lanes; +{ + rendererCursorDEV = createCursor(null); +} - if (includesSomeLane(updateLanes, renderLanes)) { - return true; - } // No pending update, but because context is propagated lazily, we need +var rendererSigil; - return false; - } +{ + // Use this to detect multiple renderers using the same context + rendererSigil = {}; +} - 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); +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; + + { + isDisallowedContextReadInDEV = false; + } +} +function enterDisallowedContextReadInDEV() { + { + isDisallowedContextReadInDEV = true; + } +} +function exitDisallowedContextReadInDEV() { + { + isDisallowedContextReadInDEV = false; + } +} +function pushProvider(providerFiber, context, nextValue) { + { + push(valueCursor, context._currentValue, providerFiber); + context._currentValue = nextValue; - { - var cache = current.memoizedState.cache; - pushCacheProvider(workInProgress, cache); - } - break; + { + push(rendererCursorDEV, context._currentRenderer, providerFiber); - case HostSingleton: - case HostComponent: - pushHostContext(workInProgress); - break; + if (context._currentRenderer !== undefined && context._currentRenderer !== null && context._currentRenderer !== rendererSigil) { + error('Detected multiple renderers concurrently rendering the ' + 'same context provider. This is currently unsupported.'); + } - case ClassComponent: { - var Component = workInProgress.type; + context._currentRenderer = rendererSigil; + } + } +} +function popProvider(context, providerFiber) { + var currentValue = valueCursor.current; - if (isContextProvider(Component)) { - pushContextProvider(workInProgress); - } + { + context._currentValue = currentValue; - break; - } + { + var currentRenderer = rendererCursorDEV.current; + pop(rendererCursorDEV, providerFiber); + context._currentRenderer = currentRenderer; + } + } - case HostPortal: - pushHostContainer( - workInProgress, - workInProgress.stateNode.containerInfo - ); - break; + pop(valueCursor, providerFiber); +} +function scheduleContextWorkOnParentPath(parent, renderLanes, propagationRoot) { + // Update the child lanes of all the ancestors, including the alternates. + var node = parent; - case ContextProvider: { - var newValue = workInProgress.memoizedProps.value; - var context; + while (node !== null) { + var alternate = node.alternate; - if (enableRenderableContext) { - context = workInProgress.type; - } else { - context = workInProgress.type._context; - } + if (!isSubsetOfLanes(node.childLanes, renderLanes)) { + node.childLanes = mergeLanes(node.childLanes, renderLanes); - pushProvider(workInProgress, context, newValue); - break; - } + if (alternate !== null) { + alternate.childLanes = mergeLanes(alternate.childLanes, renderLanes); + } + } else if (alternate !== null && !isSubsetOfLanes(alternate.childLanes, renderLanes)) { + alternate.childLanes = mergeLanes(alternate.childLanes, renderLanes); + } else ; - case Profiler: - { - // Profiler should only call onRender when one of its descendants actually rendered. - var hasChildWork = includesSomeLane( - renderLanes, - workInProgress.childLanes - ); + if (node === propagationRoot) { + break; + } - if (hasChildWork) { - workInProgress.flags |= Update; - } + node = node.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; - } - } + { + 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); + } +} - break; +function propagateContextChange_eager(workInProgress, context, renderLanes) { - case SuspenseComponent: { - var state = workInProgress.memoizedState; + var fiber = workInProgress.child; - 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 (fiber !== null) { + // Set the return pointer of the child to the work-in-progress fiber. + fiber.return = workInProgress; + } - workInProgress.flags |= DidCapture; // We should never render the children of a dehydrated boundary until we - // upgrade it. We return null instead of bailoutOnAlreadyFinishedWork. + while (fiber !== null) { + var nextFiber = void 0; // Visit this fiber. - 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 list = fiber.dependencies; - var primaryChildFragment = workInProgress.child; - var primaryChildLanes = primaryChildFragment.childLanes; - - 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. - - var child = bailoutOnAlreadyFinishedWork( - current, - workInProgress, - renderLanes - ); - - if (child !== null) { - // The fallback children have pending work. Skip over the - // primary children and work on the fallback. - return child.sibling; + if (list !== null) { + nextFiber = fiber.child; + var dependency = list.firstContext; + + 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 + + var updateQueue = fiber.updateQueue; + + if (updateQueue === null) ; else { + var sharedQueue = updateQueue.shared; + var pending = sharedQueue.pending; + + if (pending === null) { + // This is the first update. Create a circular list. + update.next = update; } 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; + update.next = pending.next; + pending.next = update; } - } - } else { - pushPrimaryTreeSuspenseHandler(workInProgress); - } - - break; - } - case SuspenseListComponent: { - var didSuspendBefore = (current.flags & DidCapture) !== NoFlags$1; - - var _hasChildWork = includesSomeLane( - renderLanes, - workInProgress.childLanes - ); - - 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. - - 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. - - var renderState = workInProgress.memoizedState; - - 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; + sharedQueue.pending = update; + } } - pushSuspenseListContext(workInProgress, suspenseStackCursor.current); + fiber.lanes = mergeLanes(fiber.lanes, renderLanes); + var alternate = fiber.alternate; - 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 (alternate !== null) { + alternate.lanes = mergeLanes(alternate.lanes, renderLanes); } - } - 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); - } + scheduleContextWorkOnParentPath(fiber.return, renderLanes, workInProgress); // Mark the updated lanes on the list, too. - case CacheComponent: { - { - var _cache = current.memoizedState.cache; - pushCacheProvider(workInProgress, _cache); - } + list.lanes = mergeLanes(list.lanes, renderLanes); // Since we already found a match, we can stop traversing the + // dependency list. break; } - } - - return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); - } - function beginWork(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 - ) - ); - } + 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 (current !== null) { - var oldProps = current.memoizedProps; - var newProps = workInProgress.pendingProps; - - 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 - ); - - 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 ((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; - } - } - } 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. - - workInProgress.lanes = NoLanes; - - switch (workInProgress.tag) { - case LazyComponent: { - var elementType = workInProgress.elementType; - return mountLazyComponent( - current, - workInProgress, - elementType, - renderLanes - ); - } - - case FunctionComponent: { - var Component = workInProgress.type; - var unresolvedProps = workInProgress.pendingProps; - var resolvedProps = - disableDefaultPropsExceptForClasses || - workInProgress.elementType === Component - ? unresolvedProps - : resolveDefaultPropsOnNonClassComponent( - Component, - unresolvedProps - ); - return updateFunctionComponent( - current, - workInProgress, - Component, - resolvedProps, - renderLanes - ); - } - - case ClassComponent: { - var _Component = workInProgress.type; - var _unresolvedProps = workInProgress.pendingProps; - - var _resolvedProps4 = resolveClassComponentProps( - _Component, - _unresolvedProps, - workInProgress.elementType === _Component - ); - - return updateClassComponent( - current, - workInProgress, - _Component, - _resolvedProps4, - renderLanes - ); - } - - case HostRoot: - return updateHostRoot(current, workInProgress, renderLanes); - - case HostHoistable: - - // Fall through - - case HostSingleton: - - // Fall through - - case HostComponent: - return updateHostComponent$1(current, workInProgress, renderLanes); - - case HostText: - return updateHostText$1(); - - 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 _resolvedProps5 = - disableDefaultPropsExceptForClasses || - workInProgress.elementType === type - ? _unresolvedProps2 - : resolveDefaultPropsOnNonClassComponent(type, _unresolvedProps2); + 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.'); + } - return updateForwardRef( - current, - workInProgress, - type, - _resolvedProps5, - renderLanes - ); - } + parentSuspense.lanes = mergeLanes(parentSuspense.lanes, renderLanes); + var _alternate = parentSuspense.alternate; - case Fragment: - return updateFragment(current, workInProgress, renderLanes); + 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 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); - - case MemoComponent: { - var _type = workInProgress.type; - var _unresolvedProps3 = workInProgress.pendingProps; // Resolve outer props first, then resolve inner props. - - var _resolvedProps6 = disableDefaultPropsExceptForClasses - ? _unresolvedProps3 - : resolveDefaultPropsOnNonClassComponent(_type, _unresolvedProps3); - - _resolvedProps6 = disableDefaultPropsExceptForClasses - ? _resolvedProps6 - : resolveDefaultPropsOnNonClassComponent( - _type.type, - _resolvedProps6 - ); - return updateMemoComponent( - current, - workInProgress, - _type, - _resolvedProps6, - renderLanes - ); - } - - case SimpleMemoComponent: { - return updateSimpleMemoComponent( - current, - workInProgress, - workInProgress.type, - workInProgress.pendingProps, - renderLanes - ); - } - - case IncompleteClassComponent: { - var _Component2 = workInProgress.type; - var _unresolvedProps4 = workInProgress.pendingProps; - - var _resolvedProps7 = resolveClassComponentProps( - _Component2, - _unresolvedProps4, - workInProgress.elementType === _Component2 - ); - - return mountIncompleteClassComponent( - current, - workInProgress, - _Component2, - _resolvedProps7, - renderLanes - ); - } - - case IncompleteFunctionComponent: { - var _Component3 = workInProgress.type; - var _unresolvedProps5 = workInProgress.pendingProps; - - var _resolvedProps8 = resolveClassComponentProps( - _Component3, - _unresolvedProps5, - workInProgress.elementType === _Component3 - ); - - return mountIncompleteFunctionComponent( - current, - workInProgress, - _Component3, - _resolvedProps8, - renderLanes - ); - } - - case SuspenseListComponent: { - return updateSuspenseListComponent( - current, - workInProgress, - renderLanes - ); - } - - case ScopeComponent: { - break; - } + scheduleContextWorkOnParentPath(parentSuspense, renderLanes, workInProgress); + nextFiber = fiber.sibling; + } else { + // Traverse down. + nextFiber = fiber.child; + } - case OffscreenComponent: { - return updateOffscreenComponent(current, workInProgress, renderLanes); - } + 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; - case LegacyHiddenComponent: { + while (nextFiber !== null) { + if (nextFiber === workInProgress) { + // We're back to the root of this subtree. Exit. + nextFiber = null; break; } - case CacheComponent: { - { - return updateCacheComponent(current, workInProgress, renderLanes); - } - } - } - - 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 sibling = nextFiber.sibling; - var valueCursor = createCursor(null); - var rendererCursorDEV; + 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. - { - rendererCursorDEV = createCursor(null); + + nextFiber = nextFiber.return; + } } - var rendererSigil; + fiber = nextFiber; + } +} +function prepareToReadContext(workInProgress, renderLanes) { + currentlyRenderingFiber = workInProgress; + lastContextDependency = null; + lastFullyObservedContext = null; + var dependencies = workInProgress.dependencies; + if (dependencies !== null) { { - // Use this to detect multiple renderers using the same context - rendererSigil = {}; - } + var firstContext = dependencies.firstContext; - 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; - - { - isDisallowedContextReadInDEV = false; - } - } - function enterDisallowedContextReadInDEV() { - { - isDisallowedContextReadInDEV = true; - } - } - function exitDisallowedContextReadInDEV() { - { - isDisallowedContextReadInDEV = false; - } - } - function pushProvider(providerFiber, context, nextValue) { - { - push(valueCursor, context._currentValue, providerFiber); - context._currentValue = nextValue; + 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 - { - push(rendererCursorDEV, context._currentRenderer, providerFiber); - - if ( - context._currentRenderer !== undefined && - context._currentRenderer !== null && - context._currentRenderer !== rendererSigil - ) { - error( - "Detected multiple renderers concurrently rendering the " + - "same context provider. This is currently unsupported." - ); - } - context._currentRenderer = rendererSigil; - } + dependencies.firstContext = null; } } - function popProvider(context, providerFiber) { - var currentValue = valueCursor.current; - - { - context._currentValue = currentValue; + } +} +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().'); + } + } - { - var currentRenderer = rendererCursorDEV.current; - pop(rendererCursorDEV, providerFiber); - context._currentRenderer = currentRenderer; - } - } + return readContextForConsumer(currentlyRenderingFiber, context); +} +function readContextDuringReconciliation(consumer, context, renderLanes) { + if (currentlyRenderingFiber === null) { + prepareToReadContext(consumer, renderLanes); + } - pop(valueCursor, providerFiber); - } - function scheduleContextWorkOnParentPath( - parent, - renderLanes, - propagationRoot - ) { - // Update the child lanes of all the ancestors, including the alternates. - var node = parent; + return readContextForConsumer(consumer, context); +} - while (node !== null) { - var alternate = node.alternate; +function readContextForConsumer(consumer, context) { + var value = context._currentValue ; - if (!isSubsetOfLanes(node.childLanes, renderLanes)) { - node.childLanes = mergeLanes(node.childLanes, renderLanes); + if (lastFullyObservedContext === context) ; else { + var contextItem = { + context: context, + memoizedValue: value, + next: 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 (node === propagationRoot) { - break; - } + 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. - node = node.return; - } - { - 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); - } + lastContextDependency = contextItem; + consumer.dependencies = { + lanes: NoLanes, + firstContext: contextItem + }; + } else { + // Append a new context item. + lastContextDependency = lastContextDependency.next = contextItem; } + } - function propagateContextChange_eager( - workInProgress, - context, - renderLanes - ) { - var fiber = workInProgress.child; + return value; +} - if (fiber !== null) { - // Set the return pointer of the child to the work-in-progress fiber. - fiber.return = workInProgress; - } +// replace it with a lightweight shim that only has the features we use. - while (fiber !== null) { - var nextFiber = void 0; // Visit this fiber. +var AbortControllerLocal = typeof AbortController !== 'undefined' ? AbortController : // $FlowFixMe[missing-this-annot] +// $FlowFixMe[prop-missing] +function AbortControllerShim() { + var listeners = []; + var signal = this.signal = { + aborted: false, + addEventListener: function (type, listener) { + listeners.push(listener); + } + }; - var list = fiber.dependencies; + this.abort = function () { + signal.aborted = true; + listeners.forEach(function (listener) { + return listener(); + }); + }; +} ; // Intentionally not named imports because Rollup would +// use dynamic dispatch for CommonJS interop named imports. + +var scheduleCallback$1 = Scheduler.unstable_scheduleCallback, + NormalPriority = Scheduler.unstable_NormalPriority; +var CacheContext = { + $$typeof: REACT_CONTEXT_TYPE, + // We don't use Consumer/Provider for Cache components. So we'll cheat. + Consumer: null, + Provider: null, + // We'll initialize these at the root. + _currentValue: null, + _currentValue2: null, + _threadCount: 0 +} ; + +{ + CacheContext._currentRenderer = null; + CacheContext._currentRenderer2 = null; +} // Creates a new empty Cache instance with a ref-count of 0. The caller is responsible +// for retaining the cache once it is in use (retainCache), and releasing the cache +// once it is no longer needed (releaseCache). + + +function createCache() { + + var cache = { + controller: new AbortControllerLocal(), + data: new Map(), + refCount: 0 + }; + return cache; +} +function retainCache(cache) { - if (list !== null) { - nextFiber = fiber.child; - var dependency = list.firstContext; + { + if (cache.controller.signal.aborted) { + warn('A cache instance was retained after it was already freed. ' + 'This likely indicates a bug in React.'); + } + } - 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 + cache.refCount++; +} // Cleanup a cache instance, potentially freeing it if there are no more references - var updateQueue = fiber.updateQueue; +function releaseCache(cache) { - if (updateQueue === null); - else { - var sharedQueue = updateQueue.shared; - var pending = sharedQueue.pending; + cache.refCount--; - if (pending === null) { - // This is the first update. Create a circular list. - update.next = update; - } else { - update.next = pending.next; - pending.next = update; - } + { + if (cache.refCount < 0) { + warn('A cache instance was released after it was already freed. ' + 'This likely indicates a bug in React.'); + } + } - sharedQueue.pending = update; - } - } + if (cache.refCount === 0) { + scheduleCallback$1(NormalPriority, function () { + cache.controller.abort(); + }); + } +} +function pushCacheProvider(workInProgress, cache) { - fiber.lanes = mergeLanes(fiber.lanes, renderLanes); - var alternate = fiber.alternate; + pushProvider(workInProgress, CacheContext, cache); +} +function popCacheProvider(workInProgress, cache) { - if (alternate !== null) { - alternate.lanes = mergeLanes(alternate.lanes, renderLanes); - } + popProvider(CacheContext, workInProgress); +} - scheduleContextWorkOnParentPath( - fiber.return, - renderLanes, - workInProgress - ); // Mark the updated lanes on the list, too. +function requestCurrentTransition() { + var transition = ReactSharedInternals.T; - list.lanes = mergeLanes(list.lanes, renderLanes); // Since we already found a match, we can stop traversing the - // dependency list. + if (transition !== null) { + // Whenever a transition update is scheduled, register a callback on the + // transition object so we can get the return value of the scope function. + transition._callbacks.add(handleAsyncAction); + } - break; - } + return transition; +} - 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." - ); - } +function handleAsyncAction(transition, thenable) { + if (enableAsyncActions) { + // This is an async action. + entangleAsyncAction(transition, thenable); + } +} - parentSuspense.lanes = mergeLanes(parentSuspense.lanes, renderLanes); - var _alternate = parentSuspense.alternate; - - 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. - - scheduleContextWorkOnParentPath( - parentSuspense, - renderLanes, - workInProgress - ); - nextFiber = fiber.sibling; - } else { - // Traverse down. - nextFiber = fiber.child; - } +function notifyTransitionCallbacks(transition, returnValue) { + var callbacks = transition._callbacks; + callbacks.forEach(function (callback) { + return callback(transition, returnValue); + }); +} // When retrying a Suspense/Offscreen boundary, we restore the cache that was +// used during the previous render by placing it here, on the stack. - 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; +var resumedCache = createCursor(null); // During the render/synchronous commit phase, we don't actually process the - while (nextFiber !== null) { - if (nextFiber === workInProgress) { - // We're back to the root of this subtree. Exit. - nextFiber = null; - break; - } +function peekCacheFromPool() { + // If we're rendering inside a Suspense boundary that is currently hidden, + // we should use the same cache that we used during the previous render, if + // one exists. - 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. + var cacheResumedFromPreviousRender = resumedCache.current; - nextFiber = nextFiber.return; - } - } + if (cacheResumedFromPreviousRender !== null) { + return cacheResumedFromPreviousRender; + } // Otherwise, check the root's cache pool. - fiber = nextFiber; - } - } - function prepareToReadContext(workInProgress, renderLanes) { - currentlyRenderingFiber = workInProgress; - lastContextDependency = null; - lastFullyObservedContext = null; - var dependencies = workInProgress.dependencies; - if (dependencies !== null) { - { - var firstContext = dependencies.firstContext; + var root = getWorkInProgressRoot(); + var cacheFromRootCachePool = root.pooledCache; + return cacheFromRootCachePool; +} - 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 +function requestCacheFromPool(renderLanes) { + // Similar to previous function, except if there's not already a cache in the + // pool, we allocate a new one. + var cacheFromPool = peekCacheFromPool(); + + if (cacheFromPool !== null) { + return cacheFromPool; + } // Create a fresh cache and add it to the root cache pool. A cache can have + // multiple owners: + // - A cache pool that lives on the FiberRoot. This is where all fresh caches + // are originally created (TODO: except during refreshes, until we implement + // this correctly). The root takes ownership immediately when the cache is + // created. Conceptually, root.pooledCache is an Option> (owned), + // and the return value of this function is a &Arc (borrowed). + // - One of several fiber types: host root, cache boundary, suspense + // component. These retain and release in the commit phase. + + + var root = getWorkInProgressRoot(); + var freshCache = createCache(); + root.pooledCache = freshCache; + retainCache(freshCache); + + if (freshCache !== null) { + root.pooledCacheLanes |= renderLanes; + } + + return freshCache; +} +function pushTransition(offscreenWorkInProgress, prevCachePool, newTransitions) { + { + if (prevCachePool === null) { + push(resumedCache, resumedCache.current, offscreenWorkInProgress); + } else { + push(resumedCache, prevCachePool.pool, offscreenWorkInProgress); + } + } +} +function popTransition(workInProgress, current) { + if (current !== null) { - dependencies.firstContext = null; - } - } - } + { + pop(resumedCache, workInProgress); } - 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()." - ); - } - } + } +} +function getSuspendedCache() { + // cache that would have been used to render fresh data during this render, + // if there was any, so that we can resume rendering with the same cache when + // we receive more data. - return readContextForConsumer(currentlyRenderingFiber, context); - } - function readContextDuringReconciliation(consumer, context, renderLanes) { - if (currentlyRenderingFiber === null) { - prepareToReadContext(consumer, renderLanes); - } - return readContextForConsumer(consumer, context); - } + var cacheFromPool = peekCacheFromPool(); - function readContextForConsumer(consumer, context) { - var value = context._currentValue; + if (cacheFromPool === null) { + return null; + } - if (lastFullyObservedContext === context); - else { - var contextItem = { - context: context, - memoizedValue: value, - next: null - }; + return { + // We must also save the parent, so that when we resume we can detect + // a refresh. + parent: CacheContext._currentValue , + pool: cacheFromPool + }; +} +function getOffscreenDeferredCache() { - 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. + var cacheFromPool = peekCacheFromPool(); - lastContextDependency = contextItem; - consumer.dependencies = { - lanes: NoLanes, - firstContext: contextItem - }; - } else { - // Append a new context item. - lastContextDependency = lastContextDependency.next = contextItem; - } - } + if (cacheFromPool === null) { + return null; + } - return value; - } + return { + // We must also store the parent, so that when we resume we can detect + // a refresh. + parent: CacheContext._currentValue , + pool: cacheFromPool + }; +} - // replace it with a lightweight shim that only has the features we use. +/** + * Tag the fiber with an update effect. This turns a Placement into + * a PlacementAndUpdate. + */ - var AbortControllerLocal = - typeof AbortController !== "undefined" - ? AbortController // $FlowFixMe[missing-this-annot] - : // $FlowFixMe[prop-missing] - function AbortControllerShim() { - var listeners = []; - var signal = (this.signal = { - aborted: false, - addEventListener: function (type, listener) { - listeners.push(listener); - } - }); +function markUpdate(workInProgress) { + workInProgress.flags |= Update; +} - this.abort = function () { - signal.aborted = true; - listeners.forEach(function (listener) { - return listener(); - }); - }; - }; // Intentionally not named imports because Rollup would - // use dynamic dispatch for CommonJS interop named imports. - - var scheduleCallback$1 = Scheduler.unstable_scheduleCallback, - NormalPriority = Scheduler.unstable_NormalPriority; - var CacheContext = { - $$typeof: REACT_CONTEXT_TYPE, - // We don't use Consumer/Provider for Cache components. So we'll cheat. - Consumer: null, - Provider: null, - // We'll initialize these at the root. - _currentValue: null, - _currentValue2: null, - _threadCount: 0 - }; +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; - { - CacheContext._currentRenderer = null; - CacheContext._currentRenderer2 = null; - } // Creates a new empty Cache instance with a ref-count of 0. The caller is responsible - // for retaining the cache once it is in use (retainCache), and releasing the cache - // once it is no longer needed (releaseCache). - - function createCache() { - var cache = { - controller: new AbortControllerLocal(), - data: new Map(), - refCount: 0 - }; - return cache; - } - function retainCache(cache) { - { - if (cache.controller.signal.aborted) { - warn( - "A cache instance was retained after it was already freed. " + - "This likely indicates a bug in React." - ); - } + while (node !== null) { + if (node.tag === HostComponent || node.tag === HostText) { + appendInitialChild(parent, node.stateNode); + } else if (node.tag === HostPortal || (false)) ; else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; } - cache.refCount++; - } // Cleanup a cache instance, potentially freeing it if there are no more references + if (node === workInProgress) { + return; + } // $FlowFixMe[incompatible-use] found when upgrading Flow - function releaseCache(cache) { - cache.refCount--; - { - if (cache.refCount < 0) { - warn( - "A cache instance was released after it was already freed. " + - "This likely indicates a bug in React." - ); + while (node.sibling === null) { + // $FlowFixMe[incompatible-use] found when upgrading Flow + if (node.return === null || node.return === workInProgress) { + return; } - } - if (cache.refCount === 0) { - scheduleCallback$1(NormalPriority, function () { - cache.controller.abort(); - }); - } - } - function pushCacheProvider(workInProgress, cache) { - pushProvider(workInProgress, CacheContext, cache); - } - function popCacheProvider(workInProgress, cache) { - popProvider(CacheContext, workInProgress); - } + node = node.return; + } // $FlowFixMe[incompatible-use] found when upgrading Flow - function requestCurrentTransition() { - var transition = ReactSharedInternals.T; - if (transition !== null) { - // Whenever a transition update is scheduled, register a callback on the - // transition object so we can get the return value of the scope function. - transition._callbacks.add(handleAsyncAction); - } + node.sibling.return = node.return; + node = node.sibling; + } + } +} // An unfortunate fork of appendAllChildren because we have two different parent types. + +function updateHostComponent(current, workInProgress, type, newProps, renderLanes) { + { + // If we have an alternate, that means this is an update and we need to + // schedule a side-effect to do the updates. + var oldProps = current.memoizedProps; + + if (oldProps === newProps) { + // In mutation mode, this is sufficient for a bailout because + // we won't touch this node even if children changed. + return; + } + + markUpdate(workInProgress); + } +} // This function must be called 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. +// 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. + + +function preloadInstanceAndSuspendIfNeeded(workInProgress, type, props, renderLanes) { + { + // 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 &= ~MaySuspendCommit; + return; + } // Mark this fiber with a flag. This gets set on all host instances +} - return transition; - } +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); + } + } +} - function handleAsyncAction(transition, thenable) { - if (enableAsyncActions) { - // This is an async action. - entangleAsyncAction(transition, thenable); - } +function updateHostText(current, workInProgress, oldText, newText) { + { + // If the text differs, mark it as an update. All the work in done in commitWork. + if (oldText !== newText) { + markUpdate(workInProgress); } + } +} - function notifyTransitionCallbacks(transition, returnValue) { - var callbacks = transition._callbacks; - callbacks.forEach(function (callback) { - return callback(transition, returnValue); - }); - } // When retrying a Suspense/Offscreen boundary, we restore the cache that was - // used during the previous render by placing it here, on the stack. - - var resumedCache = createCursor(null); // During the render/synchronous commit phase, we don't actually process the +function cutOffTailIfNeeded(renderState, hasRenderedATailFallback) { - function peekCacheFromPool() { - // If we're rendering inside a Suspense boundary that is currently hidden, - // we should use the same cache that we used during the previous render, if - // one exists. + 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; - var cacheResumedFromPreviousRender = resumedCache.current; + while (tailNode !== null) { + if (tailNode.alternate !== null) { + lastTailNode = tailNode; + } - if (cacheResumedFromPreviousRender !== null) { - return cacheResumedFromPreviousRender; - } // Otherwise, check the root's cache pool. + tailNode = tailNode.sibling; + } // Next we're simply going to delete all insertions after the + // last rendered item. - var root = getWorkInProgressRoot(); - var cacheFromRootCachePool = root.pooledCache; - return cacheFromRootCachePool; - } - - function requestCacheFromPool(renderLanes) { - // Similar to previous function, except if there's not already a cache in the - // pool, we allocate a new one. - var cacheFromPool = peekCacheFromPool(); - - if (cacheFromPool !== null) { - return cacheFromPool; - } // Create a fresh cache and add it to the root cache pool. A cache can have - // multiple owners: - // - A cache pool that lives on the FiberRoot. This is where all fresh caches - // are originally created (TODO: except during refreshes, until we implement - // this correctly). The root takes ownership immediately when the cache is - // created. Conceptually, root.pooledCache is an Option> (owned), - // and the return value of this function is a &Arc (borrowed). - // - One of several fiber types: host root, cache boundary, suspense - // component. These retain and release in the commit phase. - var root = getWorkInProgressRoot(); - var freshCache = createCache(); - root.pooledCache = freshCache; - retainCache(freshCache); + 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; + } - if (freshCache !== null) { - root.pooledCacheLanes |= renderLanes; + break; } - return freshCache; - } - function pushTransition( - offscreenWorkInProgress, - prevCachePool, - newTransitions - ) { + case 'collapsed': { - if (prevCachePool === null) { - push(resumedCache, resumedCache.current, offscreenWorkInProgress); - } else { - push(resumedCache, prevCachePool.pool, offscreenWorkInProgress); - } - } - } - function popTransition(workInProgress, current) { - if (current !== null) { - { - pop(resumedCache, workInProgress); - } - } - } - function getSuspendedCache() { - // cache that would have been used to render fresh data during this render, - // if there was any, so that we can resume rendering with the same cache when - // we receive more data. + // 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; - var cacheFromPool = peekCacheFromPool(); + while (_tailNode !== null) { + if (_tailNode.alternate !== null) { + _lastTailNode = _tailNode; + } - if (cacheFromPool === null) { - return null; - } + _tailNode = _tailNode.sibling; + } // Next we're simply going to delete all insertions after the + // last rendered item. - return { - // We must also save the parent, so that when we resume we can detect - // a refresh. - parent: CacheContext._currentValue, - pool: cacheFromPool - }; - } - function getOffscreenDeferredCache() { - var cacheFromPool = peekCacheFromPool(); - if (cacheFromPool === null) { - return null; + 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; + } + + break; } + } +} - return { - // We must also store the parent, so that when we resume we can detect - // a refresh. - parent: CacheContext._currentValue, - pool: cacheFromPool - }; - } +function bubbleProperties(completedWork) { + var didBailout = completedWork.alternate !== null && completedWork.alternate.child === completedWork.child; + var newChildLanes = NoLanes; + var subtreeFlags = NoFlags$1; - /** - * Tag the fiber with an update effect. This turns a Placement into - * a PlacementAndUpdate. - */ + 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; - function markUpdate(workInProgress) { - workInProgress.flags |= Update; - } + 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 - 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; - - while (node !== null) { - if (node.tag === HostComponent || node.tag === HostText) { - appendInitialChild(parent, node.stateNode); - } else if (node.tag === HostPortal || false); - else if (node.child !== null) { - node.child.return = node; - node = node.child; - continue; - } + actualDuration += child.actualDuration; // $FlowFixMe[unsafe-addition] addition with possible null/undefined value - if (node === workInProgress) { - return; - } // $FlowFixMe[incompatible-use] found when upgrading Flow + treeBaseDuration += child.treeBaseDuration; + child = child.sibling; + } - while (node.sibling === null) { - // $FlowFixMe[incompatible-use] found when upgrading Flow - if (node.return === null || node.return === workInProgress) { - return; - } + completedWork.actualDuration = actualDuration; + completedWork.treeBaseDuration = treeBaseDuration; + } else { + var _child = completedWork.child; - node = node.return; - } // $FlowFixMe[incompatible-use] found when upgrading Flow + 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. - node.sibling.return = node.return; - node = node.sibling; - } + _child.return = completedWork; + _child = _child.sibling; } - } // An unfortunate fork of appendAllChildren because we have two different parent types. + } - function updateHostComponent( - current, - workInProgress, - type, - newProps, - renderLanes - ) { - { - // If we have an alternate, that means this is an update and we need to - // schedule a side-effect to do the updates. - var oldProps = current.memoizedProps; + 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; - if (oldProps === newProps) { - // In mutation mode, this is sufficient for a bailout because - // we won't touch this node even if children changed. - return; - } + 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. + + subtreeFlags |= _child2.subtreeFlags & StaticMask; + subtreeFlags |= _child2.flags & StaticMask; // $FlowFixMe[unsafe-addition] addition with possible null/undefined value - markUpdate(workInProgress); + _treeBaseDuration += _child2.treeBaseDuration; + _child2 = _child2.sibling; } - } // This function must be called 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. - // 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. - function preloadInstanceAndSuspendIfNeeded( - workInProgress, - type, - props, - renderLanes - ) { - { - // 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 &= ~MaySuspendCommit; - return; - } // Mark this fiber with a flag. This gets set on all host instances - } + completedWork.treeBaseDuration = _treeBaseDuration; + } else { + var _child3 = completedWork.child; - function scheduleRetryEffect(workInProgress, retryQueue) { - var wakeables = retryQueue; + 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 (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); - } - } - } - - function updateHostText(current, workInProgress, oldText, newText) { - { - // If the text differs, mark it as an update. All the work in done in commitWork. - if (oldText !== newText) { - markUpdate(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. + + _child3.return = completedWork; + _child3 = _child3.sibling; } } - 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; - - while (tailNode !== null) { - if (tailNode.alternate !== null) { - lastTailNode = tailNode; - } + completedWork.subtreeFlags |= subtreeFlags; + } - tailNode = tailNode.sibling; - } // Next we're simply going to delete all insertions after the - // last rendered item. + completedWork.childLanes = newChildLanes; + return didBailout; +} - 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; - } +function completeDehydratedSuspenseBoundary(current, workInProgress, nextState) { + var wasHydrated = popHydrationState(); - break; - } + 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 "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; + prepareToHydrateHostSuspenseInstance(); + bubbleProperties(workInProgress); - while (_tailNode !== null) { - if (_tailNode.alternate !== null) { - _lastTailNode = _tailNode; - } + { + if ((workInProgress.mode & ProfileMode) !== NoMode) { + var isTimedOutSuspense = nextState !== null; - _tailNode = _tailNode.sibling; - } // Next we're simply going to delete all insertions after the - // last rendered item. + if (isTimedOutSuspense) { + // Don't count time spent in a timed out Suspense subtree as part of the base duration. + var primaryChildFragment = workInProgress.child; - 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; + if (primaryChildFragment !== null) { + // $FlowFixMe[unsafe-arithmetic] Flow doesn't support type casting in combination with the -= operator + workInProgress.treeBaseDuration -= primaryChildFragment.treeBaseDuration; } - } else { - // Detach the insertion after the last node that was already - // inserted. - _lastTailNode.sibling = null; } - - break; } } - } - - function bubbleProperties(completedWork) { - var didBailout = - completedWork.alternate !== null && - completedWork.alternate.child === completedWork.child; - var newChildLanes = NoLanes; - var subtreeFlags = NoFlags$1; - 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; + return false; + } else { + emitPendingHydrationWarnings(); // We might have reentered this boundary to hydrate it. If so, we need to reset the hydration - 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 - - actualDuration += child.actualDuration; // $FlowFixMe[unsafe-addition] addition with possible null/undefined value - - treeBaseDuration += child.treeBaseDuration; - child = child.sibling; - } + 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. - completedWork.actualDuration = actualDuration; - completedWork.treeBaseDuration = treeBaseDuration; - } else { - var _child = completedWork.child; - 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. + workInProgress.flags |= Update; + bubbleProperties(workInProgress); - _child.return = completedWork; - _child = _child.sibling; - } - } + { + if ((workInProgress.mode & ProfileMode) !== NoMode) { + var _isTimedOutSuspense = nextState !== null; - 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; - - 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. - - subtreeFlags |= _child2.subtreeFlags & StaticMask; - subtreeFlags |= _child2.flags & StaticMask; // $FlowFixMe[unsafe-addition] addition with possible null/undefined value - - _treeBaseDuration += _child2.treeBaseDuration; - _child2 = _child2.sibling; - } + if (_isTimedOutSuspense) { + // Don't count time spent in a timed out Suspense subtree as part of the base duration. + var _primaryChildFragment = workInProgress.child; - completedWork.treeBaseDuration = _treeBaseDuration; - } else { - var _child3 = completedWork.child; - - 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. - - 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. - - _child3.return = completedWork; - _child3 = _child3.sibling; + if (_primaryChildFragment !== null) { + // $FlowFixMe[unsafe-arithmetic] Flow doesn't support type casting in combination with the -= operator + workInProgress.treeBaseDuration -= _primaryChildFragment.treeBaseDuration; + } } } - - completedWork.subtreeFlags |= subtreeFlags; } - completedWork.childLanes = newChildLanes; - return didBailout; + 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 - function completeDehydratedSuspenseBoundary( - current, - workInProgress, - nextState - ) { - var wasHydrated = popHydrationState(); + return true; + } +} - 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." - ); - } +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 IncompleteFunctionComponent: + + case LazyComponent: + case SimpleMemoComponent: + case FunctionComponent: + case ForwardRef: + case Fragment: + case Mode: + case Profiler: + case ContextConsumer: + case MemoComponent: + bubbleProperties(workInProgress); + return null; - prepareToHydrateHostSuspenseInstance(); - bubbleProperties(workInProgress); + case ClassComponent: + { + var Component = workInProgress.type; - { - if ((workInProgress.mode & ProfileMode) !== NoMode) { - var isTimedOutSuspense = nextState !== null; + if (isContextProvider(Component)) { + popContext(workInProgress); + } - if (isTimedOutSuspense) { - // Don't count time spent in a timed out Suspense subtree as part of the base duration. - var primaryChildFragment = workInProgress.child; + bubbleProperties(workInProgress); + return null; + } - if (primaryChildFragment !== null) { - // $FlowFixMe[unsafe-arithmetic] Flow doesn't support type casting in combination with the -= operator - workInProgress.treeBaseDuration -= - primaryChildFragment.treeBaseDuration; - } - } - } + case HostRoot: + { + var fiberRoot = workInProgress.stateNode; + + { + var previousCache = null; + + if (current !== null) { + previousCache = current.memoizedState.cache; + } + + var cache = workInProgress.memoizedState.cache; + + if (cache !== previousCache) { + // Run passive effects to retain/release the cache. + workInProgress.flags |= Passive$1; } - return false; - } else { - emitPendingHydrationWarnings(); // We might have reentered this boundary to hydrate it. If so, we need to reset the hydration + popCacheProvider(workInProgress); + } + popHostContainer(workInProgress); + popTopLevelContextObject(workInProgress); - 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. + if (fiberRoot.pendingContext) { + fiberRoot.context = fiberRoot.pendingContext; + fiberRoot.pendingContext = null; + } - workInProgress.flags |= Update; - bubbleProperties(workInProgress); + 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 ((workInProgress.mode & ProfileMode) !== NoMode) { - var _isTimedOutSuspense = nextState !== null; + if (wasHydrated) { + emitPendingHydrationWarnings(); // If we hydrated, then we'll need to schedule an update for + // the commit side-effects on the root. - if (_isTimedOutSuspense) { - // Don't count time spent in a timed out Suspense subtree as part of the base duration. - var _primaryChildFragment = workInProgress.child; + markUpdate(workInProgress); + } else { + if (current !== null) { + var prevState = current.memoizedState; - if (_primaryChildFragment !== null) { - // $FlowFixMe[unsafe-arithmetic] Flow doesn't support type casting in combination with the -= operator - workInProgress.treeBaseDuration -= - _primaryChildFragment.treeBaseDuration; - } + 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. + + upgradeHydrationErrorsToRecoverable(); } } } - - 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 + bubbleProperties(workInProgress); - return true; + return null; } - } - - 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 IncompleteFunctionComponent: - - case LazyComponent: - case SimpleMemoComponent: - case FunctionComponent: - case ForwardRef: - case Fragment: - case Mode: - case Profiler: - case ContextConsumer: - case MemoComponent: - bubbleProperties(workInProgress); - return null; + case HostHoistable: - case ClassComponent: { - var Component = workInProgress.type; + case HostSingleton: - if (isContextProvider(Component)) { - popContext(workInProgress); - } + case HostComponent: + { + popHostContext(workInProgress); + var _type2 = workInProgress.type; - bubbleProperties(workInProgress); - return null; - } + if (current !== null && workInProgress.stateNode != null) { + updateHostComponent(current, workInProgress, _type2, newProps); + } 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. - case HostRoot: { - var fiberRoot = workInProgress.stateNode; - { - var previousCache = null; + bubbleProperties(workInProgress); + return null; + } - if (current !== null) { - previousCache = current.memoizedState.cache; - } + var _currentHostContext = 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. - var cache = workInProgress.memoizedState.cache; - if (cache !== previousCache) { - // Run passive effects to retain/release the cache. - workInProgress.flags |= Passive$1; - } + var _wasHydrated2 = popHydrationState(); - popCacheProvider(workInProgress); - } - popHostContainer(workInProgress); - popTopLevelContextObject(workInProgress); + if (_wasHydrated2) { + // TODO: Move this and createInstance step into the beginPhase + // to consolidate. + prepareToHydrateHostInstance(); + } else { + var _rootContainerInstance = getRootHostContainer(); - if (fiberRoot.pendingContext) { - fiberRoot.context = fiberRoot.pendingContext; - fiberRoot.pendingContext = null; - } + var _instance3 = createInstance(_type2, newProps, _rootContainerInstance, _currentHostContext, workInProgress); // TODO: For persistent renderers, we should pass children as part + // of the initial instance creation - 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 (wasHydrated) { - emitPendingHydrationWarnings(); // If we hydrated, then we'll need to schedule an update for - // the commit side-effects on the root. + appendAllChildren(_instance3, workInProgress); + workInProgress.stateNode = _instance3; // Certain renderers require commit-time effects for initial mount. + // (eg DOM renderer supports auto-focus for certain elements). + // Make sure such renderers get scheduled for later work. + if (finalizeInitialChildren(_instance3)) { markUpdate(workInProgress); - } else { - if (current !== null) { - var prevState = current.memoizedState; - - 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. - - upgradeHydrationErrorsToRecoverable(); - } - } } } - bubbleProperties(workInProgress); - - return null; } - case HostHoistable: - - case HostSingleton: + 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 HostComponent: { - popHostContext(workInProgress); - var _type2 = workInProgress.type; + preloadInstanceAndSuspendIfNeeded(workInProgress); + return null; + } - if (current !== null && workInProgress.stateNode != null) { - updateHostComponent(current, workInProgress, _type2, newProps); - } 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. - - bubbleProperties(workInProgress); - return null; - } + case HostText: + { + var newText = newProps; - var _currentHostContext = 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. + 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. - var _wasHydrated2 = popHydrationState(); + 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. - if (_wasHydrated2) { - // TODO: Move this and createInstance step into the beginPhase - // to consolidate. - prepareToHydrateHostInstance(); - } else { - var _rootContainerInstance = getRootHostContainer(); - - var _instance3 = createInstance( - _type2, - newProps, - _rootContainerInstance, - _currentHostContext, - workInProgress - ); // TODO: For persistent renderers, we should pass children as part - // of the initial instance creation - - appendAllChildren(_instance3, workInProgress); - workInProgress.stateNode = _instance3; // Certain renderers require commit-time effects for initial mount. - // (eg DOM renderer supports auto-focus for certain elements). - // Make sure such renderers get scheduled for later work. - - if (finalizeInitialChildren(_instance3)) { - markUpdate(workInProgress); - } - } } - 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. - - preloadInstanceAndSuspendIfNeeded(workInProgress); - return null; - } + var _rootContainerInstance2 = getRootHostContainer(); - case HostText: { - var newText = newProps; + var _currentHostContext2 = getHostContext(); - 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. + var _wasHydrated3 = popHydrationState(); - updateHostText(current, workInProgress, oldText, newText); + if (_wasHydrated3) { + prepareToHydrateHostTextInstance(); } 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. - } + workInProgress.stateNode = createTextInstance(newText, _rootContainerInstance2, _currentHostContext2, workInProgress); + } + } - var _rootContainerInstance2 = getRootHostContainer(); + bubbleProperties(workInProgress); + return null; + } + + case SuspenseComponent: + { + 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. - var _currentHostContext2 = getHostContext(); + if (current === null || current.memoizedState !== null && current.memoizedState.dehydrated !== null) { + var fallthroughToNormalSuspensePath = completeDehydratedSuspenseBoundary(current, workInProgress, nextState); - var _wasHydrated3 = popHydrationState(); + if (!fallthroughToNormalSuspensePath) { + if (workInProgress.flags & ForceClientRender) { + popSuspenseHandler(workInProgress); // Special case. There were remaining unhydrated nodes. We treat + // this as a mismatch. Revert to client rendering. - if (_wasHydrated3) { - prepareToHydrateHostTextInstance(); + return workInProgress; } else { - workInProgress.stateNode = createTextInstance( - newText, - _rootContainerInstance2, - _currentHostContext2, - workInProgress - ); + popSuspenseHandler(workInProgress); // Did not finish hydrating, either because this is the initial + // render or because something suspended. + + return null; } - } + } // Continue with the normal Suspense path. - bubbleProperties(workInProgress); - return null; } - case SuspenseComponent: { - 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. - - if ( - current === null || - (current.memoizedState !== null && - current.memoizedState.dehydrated !== null) - ) { - var fallthroughToNormalSuspensePath = - completeDehydratedSuspenseBoundary( - current, - workInProgress, - nextState - ); - - if (!fallthroughToNormalSuspensePath) { - if (workInProgress.flags & ForceClientRender) { - popSuspenseHandler(workInProgress); // Special case. There were remaining unhydrated nodes. We treat - // this as a mismatch. Revert to client rendering. - - return workInProgress; - } else { - popSuspenseHandler(workInProgress); // Did not finish hydrating, either because this is the initial - // render or because something suspended. - - return null; - } - } // Continue with the normal Suspense path. - } - - popSuspenseHandler(workInProgress); - - if ((workInProgress.flags & DidCapture) !== NoFlags$1) { - // Something suspended. Re-render with the fallback children. - workInProgress.lanes = renderLanes; // Do not reset the effect list. - - if ((workInProgress.mode & ProfileMode) !== NoMode) { - transferActualDuration(workInProgress); - } // Don't bubble properties in this case. + popSuspenseHandler(workInProgress); - return workInProgress; - } + if ((workInProgress.flags & DidCapture) !== NoFlags$1) { + // Something suspended. Re-render with the fallback children. + workInProgress.lanes = renderLanes; // Do not reset the effect list. - var nextDidTimeout = nextState !== null; - var prevDidTimeout = - current !== null && current.memoizedState !== null; + if ((workInProgress.mode & ProfileMode) !== NoMode) { + transferActualDuration(workInProgress); + } // Don't bubble properties in this case. - if (nextDidTimeout) { - var offscreenFiber = workInProgress.child; - var _previousCache = null; - - if ( - offscreenFiber.alternate !== null && - offscreenFiber.alternate.memoizedState !== null && - offscreenFiber.alternate.memoizedState.cachePool !== null - ) { - _previousCache = - offscreenFiber.alternate.memoizedState.cachePool.pool; - } - var _cache = null; + return workInProgress; + } - if ( - offscreenFiber.memoizedState !== null && - offscreenFiber.memoizedState.cachePool !== null - ) { - _cache = offscreenFiber.memoizedState.cachePool.pool; - } + var nextDidTimeout = nextState !== null; + var prevDidTimeout = current !== null && current.memoizedState !== null; - if (_cache !== _previousCache) { - // Run passive effects to retain/release the cache. - offscreenFiber.flags |= Passive$1; - } - } // If the suspended state of the boundary changes, we need to schedule - // a passive effect, which is when we process the transitions - - 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 (nextDidTimeout) { + var offscreenFiber = workInProgress.child; + var _previousCache = null; - if (nextDidTimeout) { - var _offscreenFiber2 = workInProgress.child; - _offscreenFiber2.flags |= Visibility; - } + if (offscreenFiber.alternate !== null && offscreenFiber.alternate.memoizedState !== null && offscreenFiber.alternate.memoizedState.cachePool !== null) { + _previousCache = offscreenFiber.alternate.memoizedState.cachePool.pool; } - var retryQueue = workInProgress.updateQueue; - scheduleRetryEffect(workInProgress, retryQueue); - - bubbleProperties(workInProgress); + var _cache = null; - { - 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[unsafe-arithmetic] Flow doesn't support type casting in combination with the -= operator - workInProgress.treeBaseDuration -= - primaryChildFragment.treeBaseDuration; - } - } - } + if (offscreenFiber.memoizedState !== null && offscreenFiber.memoizedState.cachePool !== null) { + _cache = offscreenFiber.memoizedState.cachePool.pool; } - return null; - } + if (_cache !== _previousCache) { + // Run passive effects to retain/release the cache. + offscreenFiber.flags |= Passive$1; + } + } // If the suspended state of the boundary changes, we need to schedule + // a passive effect, which is when we process the transitions - case HostPortal: - popHostContainer(workInProgress); - bubbleProperties(workInProgress); - return null; + 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. - case ContextProvider: - // Pop provider fiber - var context; - if (enableRenderableContext) { - context = workInProgress.type; - } else { - context = workInProgress.type._context; + if (nextDidTimeout) { + var _offscreenFiber2 = workInProgress.child; + _offscreenFiber2.flags |= Visibility; } + } - popProvider(context, workInProgress); - bubbleProperties(workInProgress); - return null; + var retryQueue = workInProgress.updateQueue; + scheduleRetryEffect(workInProgress, retryQueue); - case IncompleteClassComponent: { - // sequential to ensure this switch is compiled to a jump table. + bubbleProperties(workInProgress); - var _Component = workInProgress.type; + { + 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 (isContextProvider(_Component)) { - popContext(workInProgress); + if (primaryChildFragment !== null) { + // $FlowFixMe[unsafe-arithmetic] Flow doesn't support type casting in combination with the -= operator + workInProgress.treeBaseDuration -= primaryChildFragment.treeBaseDuration; + } + } } - - bubbleProperties(workInProgress); - return null; } - case SuspenseListComponent: { - popSuspenseListContext(workInProgress); - var renderState = workInProgress.memoizedState; + return null; + } - if (renderState === null) { - // We're running in the default, "independent" mode. - // We don't do anything in this mode. - bubbleProperties(workInProgress); - return null; - } + case HostPortal: + popHostContainer(workInProgress); - var didSuspendAlready = - (workInProgress.flags & DidCapture) !== NoFlags$1; - var renderedTail = renderState.rendering; - - 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 (!cannotBeSuspended) { - var row = workInProgress.child; - - while (row !== null) { - var suspended = findFirstSuspended(row); - - 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. - - 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; - } + bubbleProperties(workInProgress); + return null; - row = row.sibling; - } - } + case ContextProvider: + // Pop provider fiber + var context; - 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. - - 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 _retryQueue2 = _suspended.updateQueue; - workInProgress.updateQueue = _retryQueue2; - scheduleRetryEffect(workInProgress, _retryQueue2); - cutOffTailIfNeeded(renderState, true); // This might have been modified. - - 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. - - workInProgress.lanes = SomeRetryLane; - } - } + if (enableRenderableContext) { + context = workInProgress.type; + } else { + context = workInProgress.type._context; + } - 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; + popProvider(context, workInProgress); + bubbleProperties(workInProgress); + return null; - if (previousSibling !== null) { - previousSibling.sibling = renderedTail; - } else { - workInProgress.child = renderedTail; - } + case IncompleteClassComponent: + { + // sequential to ensure this switch is compiled to a jump table. - renderState.last = renderedTail; - } - } - 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. - - var suspenseContext = suspenseStackCursor.current; - - if (didSuspendAlready) { - suspenseContext = setShallowSuspenseListContext( - suspenseContext, - ForceSuspenseFallback - ); - } else { - suspenseContext = - setDefaultShallowSuspenseListContext(suspenseContext); - } + var _Component = workInProgress.type; - pushSuspenseListContext(workInProgress, suspenseContext); // Do a pass over the next row. - // Don't bubble properties in this case. + if (isContextProvider(_Component)) { + popContext(workInProgress); + } - return next; - } + bubbleProperties(workInProgress); + return null; + } + + case SuspenseListComponent: + { + popSuspenseListContext(workInProgress); + var renderState = workInProgress.memoizedState; + if (renderState === null) { + // We're running in the default, "independent" mode. + // We don't do anything in this mode. bubbleProperties(workInProgress); return null; } - case ScopeComponent: { - break; - } - - 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 (current !== null) { - var _prevState = current.memoizedState; - var prevIsHidden = _prevState !== null; + var didSuspendAlready = (workInProgress.flags & DidCapture) !== NoFlags$1; + var renderedTail = renderState.rendering; + + 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 (!cannotBeSuspended) { + var row = workInProgress.child; + + while (row !== null) { + var suspended = findFirstSuspended(row); + + 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. + + 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; + } - 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; + row = row.sibling; } } - } - 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.subtreeFlags & (Placement | Update)) { - workInProgress.flags |= Visibility; - } + 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. + + 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); - var offscreenQueue = workInProgress.updateQueue; + 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. - if (offscreenQueue !== null) { - var _retryQueue3 = offscreenQueue.retryQueue; - scheduleRetryEffect(workInProgress, _retryQueue3); - } + var _retryQueue2 = _suspended.updateQueue; + workInProgress.updateQueue = _retryQueue2; + scheduleRetryEffect(workInProgress, _retryQueue2); + cutOffTailIfNeeded(renderState, true); // This might have been modified. - { - var _previousCache2 = null; - - if ( - current !== null && - current.memoizedState !== null && - current.memoizedState.cachePool !== null - ) { - _previousCache2 = current.memoizedState.cachePool.pool; + 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. + + workInProgress.lanes = SomeRetryLane; } + } - var _cache2 = null; + 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; - if ( - workInProgress.memoizedState !== null && - workInProgress.memoizedState.cachePool !== null - ) { - _cache2 = workInProgress.memoizedState.cachePool.pool; + if (previousSibling !== null) { + previousSibling.sibling = renderedTail; + } else { + workInProgress.child = renderedTail; } - if (_cache2 !== _previousCache2) { - // Run passive effects to retain/release the cache. - workInProgress.flags |= Passive$1; - } + renderState.last = renderedTail; } - - popTransition(workInProgress, current); - return null; } - case CacheComponent: { - { - var _previousCache3 = null; - - if (current !== null) { - _previousCache3 = current.memoizedState.cache; - } + 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. - var _cache3 = workInProgress.memoizedState.cache; + var suspenseContext = suspenseStackCursor.current; - if (_cache3 !== _previousCache3) { - // Run passive effects to retain/release the cache. - workInProgress.flags |= Passive$1; - } - - popCacheProvider(workInProgress); - bubbleProperties(workInProgress); + if (didSuspendAlready) { + suspenseContext = setShallowSuspenseListContext(suspenseContext, ForceSuspenseFallback); + } else { + suspenseContext = setDefaultShallowSuspenseListContext(suspenseContext); } - return null; - } + pushSuspenseListContext(workInProgress, suspenseContext); // Do a pass over the next row. + // Don't bubble properties in this case. - case TracingMarkerComponent: { - return null; + return next; } - } - throw new Error( - "Unknown unit of work tag (" + - workInProgress.tag + - "). This error is likely caused by a bug in " + - "React. Please file an issue." - ); - } + bubbleProperties(workInProgress); + return null; + } - function unwindWork(current, workInProgress, renderLanes) { - switch (workInProgress.tag) { - case ClassComponent: { - var Component = workInProgress.type; + case ScopeComponent: + { - if (isContextProvider(Component)) { - popContext(workInProgress); - } + break; + } - var flags = workInProgress.flags; + 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 (flags & ShouldCapture) { - workInProgress.flags = (flags & ~ShouldCapture) | DidCapture; + { + if (current !== null) { + var _prevState = current.memoizedState; + var prevIsHidden = _prevState !== null; - if ((workInProgress.mode & ProfileMode) !== NoMode) { - transferActualDuration(workInProgress); + 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; } - - return workInProgress; } - - return null; } - case HostRoot: { - { - popCacheProvider(workInProgress); + 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.subtreeFlags & (Placement | Update)) { + workInProgress.flags |= Visibility; + } } - popHostContainer(workInProgress); - popTopLevelContextObject(workInProgress); - 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. - - return null; } - case HostHoistable: - case HostSingleton: - case HostComponent: { - // TODO: popHydrationState - popHostContext(workInProgress); - return null; + var offscreenQueue = workInProgress.updateQueue; + + if (offscreenQueue !== null) { + var _retryQueue3 = offscreenQueue.retryQueue; + scheduleRetryEffect(workInProgress, _retryQueue3); } - case SuspenseComponent: { - popSuspenseHandler(workInProgress); - var suspenseState = workInProgress.memoizedState; + { + var _previousCache2 = null; - 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 (current !== null && current.memoizedState !== null && current.memoizedState.cachePool !== null) { + _previousCache2 = current.memoizedState.cachePool.pool; } - var _flags2 = workInProgress.flags; - - if (_flags2 & ShouldCapture) { - workInProgress.flags = (_flags2 & ~ShouldCapture) | DidCapture; // Captured a suspense effect. Re-render the boundary. - - if ((workInProgress.mode & ProfileMode) !== NoMode) { - transferActualDuration(workInProgress); - } + var _cache2 = null; - return workInProgress; + if (workInProgress.memoizedState !== null && workInProgress.memoizedState.cachePool !== null) { + _cache2 = workInProgress.memoizedState.cachePool.pool; } - return null; + if (_cache2 !== _previousCache2) { + // Run passive effects to retain/release the cache. + workInProgress.flags |= Passive$1; + } } - 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. + popTransition(workInProgress, current); + return null; + } - return null; - } + case CacheComponent: + { + { + var _previousCache3 = null; - case HostPortal: - popHostContainer(workInProgress); - return null; + if (current !== null) { + _previousCache3 = current.memoizedState.cache; + } - case ContextProvider: - var context; + var _cache3 = workInProgress.memoizedState.cache; - if (enableRenderableContext) { - context = workInProgress.type; - } else { - context = workInProgress.type._context; + if (_cache3 !== _previousCache3) { + // Run passive effects to retain/release the cache. + workInProgress.flags |= Passive$1; } - popProvider(context, workInProgress); - return null; - - case OffscreenComponent: - case LegacyHiddenComponent: { - popSuspenseHandler(workInProgress); - popHiddenContext(workInProgress); - popTransition(workInProgress, current); - var _flags3 = workInProgress.flags; + popCacheProvider(workInProgress); + bubbleProperties(workInProgress); + } - if (_flags3 & ShouldCapture) { - workInProgress.flags = (_flags3 & ~ShouldCapture) | DidCapture; // Captured a suspense effect. Re-render the boundary. + return null; + } - if ((workInProgress.mode & ProfileMode) !== NoMode) { - transferActualDuration(workInProgress); - } + case TracingMarkerComponent: + { - return workInProgress; - } + return null; + } + } - 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.'); +} - case CacheComponent: - { - popCacheProvider(workInProgress); - } +function unwindWork(current, workInProgress, renderLanes) { - return null; + switch (workInProgress.tag) { + case ClassComponent: + { + var Component = workInProgress.type; - case TracingMarkerComponent: - return null; + if (isContextProvider(Component)) { + popContext(workInProgress); + } - default: - return null; - } - } + var flags = workInProgress.flags; - function unwindInterruptedWork(current, interruptedWork, renderLanes) { - switch (interruptedWork.tag) { - case ClassComponent: { - var childContextTypes = interruptedWork.type.childContextTypes; + if (flags & ShouldCapture) { + workInProgress.flags = flags & ~ShouldCapture | DidCapture; - if (childContextTypes !== null && childContextTypes !== undefined) { - popContext(interruptedWork); + if ((workInProgress.mode & ProfileMode) !== NoMode) { + transferActualDuration(workInProgress); } - break; + return workInProgress; } - case HostRoot: { - { - popCacheProvider(interruptedWork); - } - popHostContainer(interruptedWork); - popTopLevelContextObject(interruptedWork); - break; - } + return null; + } - case HostHoistable: - case HostSingleton: - case HostComponent: { - popHostContext(interruptedWork); - break; + case HostRoot: + { + + { + popCacheProvider(workInProgress); } + popHostContainer(workInProgress); + popTopLevelContextObject(workInProgress); + var _flags = workInProgress.flags; - case HostPortal: - popHostContainer(interruptedWork); - break; + 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. - case SuspenseComponent: - popSuspenseHandler(interruptedWork); - break; - case SuspenseListComponent: - popSuspenseListContext(interruptedWork); - break; + return null; + } + + case HostHoistable: + case HostSingleton: + case HostComponent: + { + // TODO: popHydrationState + popHostContext(workInProgress); + return null; + } - case ContextProvider: - var context; + case SuspenseComponent: + { + popSuspenseHandler(workInProgress); + var suspenseState = workInProgress.memoizedState; - if (enableRenderableContext) { - context = interruptedWork.type; - } else { - context = interruptedWork.type._context; + 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.'); } + } - popProvider(context, interruptedWork); - break; + var _flags2 = workInProgress.flags; - case OffscreenComponent: - case LegacyHiddenComponent: - popSuspenseHandler(interruptedWork); - popHiddenContext(interruptedWork); - popTransition(interruptedWork, current); - break; + if (_flags2 & ShouldCapture) { + workInProgress.flags = _flags2 & ~ShouldCapture | DidCapture; // Captured a suspense effect. Re-render the boundary. - case CacheComponent: - { - popCacheProvider(interruptedWork); + if ((workInProgress.mode & ProfileMode) !== NoMode) { + transferActualDuration(workInProgress); } - break; + return workInProgress; + } + + return null; } - } - var didWarnAboutUndefinedSnapshotBeforeUpdate = 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. - { - 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; // Used to track if a form needs to be reset at the end of the mutation phase. - var PossiblyWeakSet = typeof WeakSet === "function" ? WeakSet : Set; - var nextEffect = null; // Used for Profiling builds to track updaters. - - var inProgressLanes = null; - var inProgressRoot = null; - - function shouldProfile(current) { - return ( - (current.mode & ProfileMode) !== NoMode && - (getExecutionContext() & CommitContext) !== NoContext - ); - } - - function callComponentWillUnmountWithTimer(current, instance) { - instance.props = resolveClassComponentProps( - current.type, - current.memoizedProps, - current.elementType === current.type - ); - instance.state = current.memoizedState; - - if (shouldProfile(current)) { - try { - startLayoutEffectTimer(); - instance.componentWillUnmount(); - } finally { - recordLayoutEffectDuration(current); - } - } else { - instance.componentWillUnmount(); + return null; } - } // 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 HostPortal: + popHostContainer(workInProgress); + return null; - function safelyAttachRef(current, nearestMountedAncestor) { - try { - commitAttachRef(current); - } catch (error) { - captureCommitPhaseError(current, nearestMountedAncestor, error); + case ContextProvider: + var context; + + if (enableRenderableContext) { + context = workInProgress.type; + } else { + context = workInProgress.type._context; } - } - function safelyDetachRef(current, nearestMountedAncestor) { - var ref = current.ref; - var refCleanup = current.refCleanup; + popProvider(context, workInProgress); + return null; - if (ref !== null) { - 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; + case OffscreenComponent: + case LegacyHiddenComponent: + { + popSuspenseHandler(workInProgress); + popHiddenContext(workInProgress); + popTransition(workInProgress, current); + var _flags3 = workInProgress.flags; - if (finishedWork != null) { - finishedWork.refCleanup = null; - } - } - } else if (typeof ref === "function") { - var retVal; + if (_flags3 & ShouldCapture) { + workInProgress.flags = _flags3 & ~ShouldCapture | DidCapture; // Captured a suspense effect. Re-render the boundary. - try { - if (shouldProfile(current)) { - try { - startLayoutEffectTimer(); - retVal = ref(null); - } finally { - recordLayoutEffectDuration(current); - } - } else { - retVal = ref(null); - } - } catch (error) { - captureCommitPhaseError(current, nearestMountedAncestor, error); + if ((workInProgress.mode & ProfileMode) !== NoMode) { + transferActualDuration(workInProgress); } - { - 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[incompatible-use] unable to narrow type to RefObject - ref.current = null; + return workInProgress; } + + return null; } - } - function safelyCallDestroy(current, nearestMountedAncestor, destroy) { - try { - destroy(); - } catch (error) { - captureCommitPhaseError(current, nearestMountedAncestor, error); + case CacheComponent: + { + popCacheProvider(workInProgress); } - } - var shouldFireAfterActiveInstanceBlur = false; - function commitBeforeMutationEffects(root, firstChild) { - nextEffect = firstChild; - commitBeforeMutationEffects_begin(); // We no longer need to track the active instance fiber - var shouldFire = shouldFireAfterActiveInstanceBlur; - shouldFireAfterActiveInstanceBlur = false; - return shouldFire; - } + return null; - function commitBeforeMutationEffects_begin() { - while (nextEffect !== null) { - var fiber = nextEffect; // This phase is only used for beforeActiveInstanceBlur. + case TracingMarkerComponent: - var child = fiber.child; + return null; - if ( - (fiber.subtreeFlags & BeforeMutationMask) !== NoFlags$1 && - child !== null - ) { - child.return = fiber; - nextEffect = child; - } else { - commitBeforeMutationEffects_complete(); + default: + return null; + } +} + +function unwindInterruptedWork(current, interruptedWork, renderLanes) { + + switch (interruptedWork.tag) { + case ClassComponent: + { + var childContextTypes = interruptedWork.type.childContextTypes; + + if (childContextTypes !== null && childContextTypes !== undefined) { + popContext(interruptedWork); } + + break; } - } - function commitBeforeMutationEffects_complete() { - while (nextEffect !== null) { - var fiber = nextEffect; - setCurrentFiber(fiber); + case HostRoot: + { - try { - commitBeforeMutationEffectsOnFiber(fiber); - } catch (error) { - captureCommitPhaseError(fiber, fiber.return, error); + { + popCacheProvider(interruptedWork); } + popHostContainer(interruptedWork); + popTopLevelContextObject(interruptedWork); + break; + } - resetCurrentFiber(); - var sibling = fiber.sibling; + case HostHoistable: + case HostSingleton: + case HostComponent: + { + popHostContext(interruptedWork); + break; + } - if (sibling !== null) { - sibling.return = fiber.return; - nextEffect = sibling; - return; - } + case HostPortal: + popHostContainer(interruptedWork); + break; + + case SuspenseComponent: + popSuspenseHandler(interruptedWork); + break; - nextEffect = fiber.return; + case SuspenseListComponent: + popSuspenseListContext(interruptedWork); + break; + + case ContextProvider: + var context; + + if (enableRenderableContext) { + context = interruptedWork.type; + } else { + context = interruptedWork.type._context; } - } - function commitBeforeMutationEffectsOnFiber(finishedWork) { - var current = finishedWork.alternate; - var flags = finishedWork.flags; + popProvider(context, interruptedWork); + break; - if ((flags & Snapshot) !== NoFlags$1) { - setCurrentFiber(finishedWork); + case OffscreenComponent: + case LegacyHiddenComponent: + popSuspenseHandler(interruptedWork); + popHiddenContext(interruptedWork); + popTransition(interruptedWork, current); + break; + + case CacheComponent: + { + popCacheProvider(interruptedWork); } - switch (finishedWork.tag) { - case FunctionComponent: { - break; - } + break; + } +} - case ForwardRef: - case SimpleMemoComponent: { - break; - } +var didWarnAboutUndefinedSnapshotBeforeUpdate = 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. +{ + 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 ( - !finishedWork.type.defaultProps && - !("ref" in finishedWork.memoizedProps) && - !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 (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" - ); - } - } - } +var offscreenSubtreeIsHidden = false; +var offscreenSubtreeWasHidden = false; // Used to track if a form needs to be reset at the end of the mutation phase. +var PossiblyWeakSet = typeof WeakSet === 'function' ? WeakSet : Set; +var nextEffect = null; // Used for Profiling builds to track updaters. - var snapshot = instance.getSnapshotBeforeUpdate( - resolveClassComponentProps( - finishedWork.type, - prevProps, - finishedWork.elementType === finishedWork.type - ), - prevState - ); +var inProgressLanes = null; +var inProgressRoot = null; - { - var didWarnSet = didWarnAboutUndefinedSnapshotBeforeUpdate; - - 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) - ); - } - } +function shouldProfile(current) { + return (current.mode & ProfileMode) !== NoMode && (getExecutionContext() & CommitContext) !== NoContext; +} - instance.__reactInternalSnapshotBeforeUpdate = snapshot; - } - } +function callComponentWillUnmountWithTimer(current, instance) { + instance.props = resolveClassComponentProps(current.type, current.memoizedProps, current.elementType === current.type); + instance.state = current.memoizedState; + + if (shouldProfile(current)) { + try { + startLayoutEffectTimer(); + instance.componentWillUnmount(); + } finally { + recordLayoutEffectDuration(current); + } + } 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. + + +function safelyAttachRef(current, nearestMountedAncestor) { + try { + commitAttachRef(current); + } catch (error) { + captureCommitPhaseError(current, nearestMountedAncestor, error); + } +} - break; - } +function safelyDetachRef(current, nearestMountedAncestor) { + var ref = current.ref; + var refCleanup = current.refCleanup; - case HostRoot: { - break; + if (ref !== null) { + 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; - case HostComponent: - case HostHoistable: - case HostSingleton: - case HostText: - case HostPortal: - case IncompleteClassComponent: - // Nothing to do for these component types - break; + if (finishedWork != null) { + finishedWork.refCleanup = null; + } + } + } else if (typeof ref === 'function') { + var retVal; - 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." - ); + try { + if (shouldProfile(current)) { + try { + startLayoutEffectTimer(); + retVal = ref(null); + } finally { + recordLayoutEffectDuration(current); } + } else { + retVal = ref(null); } + } catch (error) { + captureCommitPhaseError(current, nearestMountedAncestor, error); } - if ((flags & Snapshot) !== NoFlags$1) { - resetCurrentFiber(); + { + 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[incompatible-use] unable to narrow type to RefObject + ref.current = null; } + } +} - function commitHookEffectListUnmount( - flags, - finishedWork, - nearestMountedAncestor - ) { - var updateQueue = finishedWork.updateQueue; - var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null; - - if (lastEffect !== null) { - var firstEffect = lastEffect.next; - var effect = firstEffect; - - do { - if ((effect.tag & flags) === flags) { - // Unmount - var inst = effect.inst; - var destroy = inst.destroy; +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 + + var shouldFire = shouldFireAfterActiveInstanceBlur; + shouldFireAfterActiveInstanceBlur = false; + return shouldFire; +} - if (destroy !== undefined) { - inst.destroy = undefined; +function commitBeforeMutationEffects_begin() { + while (nextEffect !== null) { + var fiber = nextEffect; // This phase is only used for beforeActiveInstanceBlur. - { - if ((flags & Passive) !== NoFlags) { - markComponentPassiveEffectUnmountStarted(finishedWork); - } else if ((flags & Layout) !== NoFlags) { - markComponentLayoutEffectUnmountStarted(finishedWork); - } - } + var child = fiber.child; - { - if ((flags & Insertion) !== NoFlags) { - setIsRunningInsertionEffect(true); - } - } + if ((fiber.subtreeFlags & BeforeMutationMask) !== NoFlags$1 && child !== null) { + child.return = fiber; + nextEffect = child; + } else { + commitBeforeMutationEffects_complete(); + } + } +} - safelyCallDestroy(finishedWork, nearestMountedAncestor, destroy); +function commitBeforeMutationEffects_complete() { + while (nextEffect !== null) { + var fiber = nextEffect; + setCurrentFiber(fiber); - { - if ((flags & Insertion) !== NoFlags) { - setIsRunningInsertionEffect(false); - } - } + try { + commitBeforeMutationEffectsOnFiber(fiber); + } catch (error) { + captureCommitPhaseError(fiber, fiber.return, error); + } - { - if ((flags & Passive) !== NoFlags) { - markComponentPassiveEffectUnmountStopped(); - } else if ((flags & Layout) !== NoFlags) { - markComponentLayoutEffectUnmountStopped(); - } - } - } - } + resetCurrentFiber(); + var sibling = fiber.sibling; - effect = effect.next; - } while (effect !== firstEffect); - } + if (sibling !== null) { + sibling.return = fiber.return; + nextEffect = sibling; + return; } - function commitHookEffectListMount(flags, finishedWork) { - var updateQueue = finishedWork.updateQueue; - var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null; - - if (lastEffect !== null) { - var firstEffect = lastEffect.next; - var effect = firstEffect; + nextEffect = fiber.return; + } +} - do { - if ((effect.tag & flags) === flags) { - { - if ((flags & Passive) !== NoFlags) { - markComponentPassiveEffectMountStarted(finishedWork); - } else if ((flags & Layout) !== NoFlags) { - markComponentLayoutEffectMountStarted(finishedWork); - } - } // Mount +function commitBeforeMutationEffectsOnFiber(finishedWork) { + var current = finishedWork.alternate; + var flags = finishedWork.flags; - var create = effect.create; + if ((flags & Snapshot) !== NoFlags$1) { + setCurrentFiber(finishedWork); + } - { - if ((flags & Insertion) !== NoFlags) { - setIsRunningInsertionEffect(true); - } - } + switch (finishedWork.tag) { + case FunctionComponent: + { - var inst = effect.inst; - var destroy = create(); - inst.destroy = destroy; + break; + } - { - if ((flags & Insertion) !== NoFlags) { - setIsRunningInsertionEffect(false); - } - } + case ForwardRef: + case SimpleMemoComponent: + { + break; + } - { - if ((flags & Passive) !== NoFlags) { - markComponentPassiveEffectMountStopped(); - } else if ((flags & Layout) !== NoFlags) { - markComponentLayoutEffectMountStopped(); - } - } + 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 (destroy !== undefined && typeof destroy !== "function") { - var hookName = void 0; - - if ((effect.tag & Layout) !== NoFlags$1) { - hookName = "useLayoutEffect"; - } else if ((effect.tag & Insertion) !== NoFlags$1) { - hookName = "useInsertionEffect"; - } else { - hookName = "useEffect"; + if (!finishedWork.type.defaultProps && !('ref' in finishedWork.memoizedProps) && !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'); } - var addendum = void 0; - - 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://react.dev/link/hooks-data-fetching"; - } else { - addendum = " You returned: " + destroy; + 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'); } - - error( - "%s must not return anything besides a function, " + - "which is used for clean-up.%s", - hookName, - addendum - ); } } - } - effect = effect.next; - } while (effect !== firstEffect); - } - } - - 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. - - var commitTime = getCommitTime(); - var phase = finishedWork.alternate === null ? "mount" : "update"; + var snapshot = instance.getSnapshotBeforeUpdate(resolveClassComponentProps(finishedWork.type, prevProps, finishedWork.elementType === finishedWork.type), prevState); - { - if (isCurrentUpdateNested()) { - phase = "nested-update"; - } - } + { + var didWarnSet = didWarnAboutUndefinedSnapshotBeforeUpdate; - 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; - } + if (snapshot === undefined && !didWarnSet.has(finishedWork.type)) { + didWarnSet.add(finishedWork.type); - parentFiber = parentFiber.return; + error('%s.getSnapshotBeforeUpdate(): A snapshot value (or null) ' + 'must be returned. You have returned undefined.', getComponentNameFromFiber(finishedWork)); } - - break; } + + instance.__reactInternalSnapshotBeforeUpdate = snapshot; } } + + break; } - } - 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); - } + case HostRoot: + { + + break; + } + + case HostComponent: + case HostHoistable: + case HostSingleton: + case HostText: + case HostPortal: + case IncompleteClassComponent: + // Nothing to do for these component types + break; - recordLayoutEffectDuration(finishedWork); - } else { - try { - commitHookEffectListMount(hookFlags, finishedWork); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); + 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.'); } } - } + } - function commitClassLayoutLifecycles(finishedWork, current) { - var instance = finishedWork.stateNode; + if ((flags & Snapshot) !== NoFlags$1) { + resetCurrentFiber(); + } +} - 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.defaultProps && - !("ref" in finishedWork.memoizedProps) && - !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" - ); - } +function commitHookEffectListUnmount(flags, finishedWork, nearestMountedAncestor) { + var updateQueue = finishedWork.updateQueue; + var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null; + + if (lastEffect !== null) { + var firstEffect = lastEffect.next; + var effect = firstEffect; - 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" - ); + do { + if ((effect.tag & flags) === flags) { + // Unmount + var inst = effect.inst; + var destroy = inst.destroy; + + if (destroy !== undefined) { + inst.destroy = undefined; + + { + if ((flags & Passive) !== NoFlags) { + markComponentPassiveEffectUnmountStarted(finishedWork); + } else if ((flags & Layout) !== NoFlags) { + markComponentLayoutEffectUnmountStarted(finishedWork); } } - } - if (shouldProfile(finishedWork)) { - try { - startLayoutEffectTimer(); - instance.componentDidMount(); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); + { + if ((flags & Insertion) !== NoFlags) { + setIsRunningInsertionEffect(true); + } } - recordLayoutEffectDuration(finishedWork); - } else { - try { - instance.componentDidMount(); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } - } - } else { - var prevProps = resolveClassComponentProps( - finishedWork.type, - current.memoizedProps, - finishedWork.elementType === finishedWork.type - ); - 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. + safelyCallDestroy(finishedWork, nearestMountedAncestor, destroy); - { - if ( - !finishedWork.type.defaultProps && - !("ref" in finishedWork.memoizedProps) && - !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 & Insertion) !== NoFlags) { + setIsRunningInsertionEffect(false); } + } - 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" - ); + { + if ((flags & Passive) !== NoFlags) { + markComponentPassiveEffectUnmountStopped(); + } else if ((flags & Layout) !== NoFlags) { + markComponentLayoutEffectUnmountStopped(); } } } + } - if (shouldProfile(finishedWork)) { - try { - startLayoutEffectTimer(); - instance.componentDidUpdate( - prevProps, - prevState, - instance.__reactInternalSnapshotBeforeUpdate - ); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); + effect = effect.next; + } while (effect !== firstEffect); + } +} + +function commitHookEffectListMount(flags, finishedWork) { + var updateQueue = finishedWork.updateQueue; + var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null; + + if (lastEffect !== null) { + var firstEffect = lastEffect.next; + var effect = firstEffect; + + do { + if ((effect.tag & flags) === flags) { + { + if ((flags & Passive) !== NoFlags) { + markComponentPassiveEffectMountStarted(finishedWork); + } else if ((flags & Layout) !== NoFlags) { + markComponentLayoutEffectMountStarted(finishedWork); } + } // Mount - recordLayoutEffectDuration(finishedWork); - } else { - try { - instance.componentDidUpdate( - prevProps, - prevState, - instance.__reactInternalSnapshotBeforeUpdate - ); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); + + var create = effect.create; + + { + if ((flags & Insertion) !== NoFlags) { + setIsRunningInsertionEffect(true); } } - } - } - 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; + var inst = effect.inst; + var destroy = create(); + inst.destroy = destroy; - if (updateQueue !== null) { - var instance = finishedWork.stateNode; + { + if ((flags & Insertion) !== NoFlags) { + setIsRunningInsertionEffect(false); + } + } + + { + if ((flags & Passive) !== NoFlags) { + markComponentPassiveEffectMountStopped(); + } else if ((flags & Layout) !== NoFlags) { + markComponentLayoutEffectMountStopped(); + } + } { - if ( - !finishedWork.type.defaultProps && - !("ref" in finishedWork.memoizedProps) && - !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 (destroy !== undefined && typeof destroy !== 'function') { + var hookName = void 0; + + if ((effect.tag & Layout) !== NoFlags$1) { + hookName = 'useLayoutEffect'; + } else if ((effect.tag & Insertion) !== NoFlags$1) { + hookName = 'useInsertionEffect'; + } else { + hookName = 'useEffect'; } - 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" - ); + var addendum = void 0; + + 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://react.dev/link/hooks-data-fetching'; + } else { + addendum = ' You returned: ' + destroy; } - } - } // 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); + error('%s must not return anything besides a function, ' + 'which is used for clean-up.%s', hookName, addendum); + } } } - } - function commitHostComponentMount(finishedWork) { - var type = finishedWork.type; - var props = finishedWork.memoizedProps; - var instance = finishedWork.stateNode; + effect = effect.next; + } while (effect !== firstEffect); + } +} - try { - commitMount(instance, type, props, finishedWork); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } - } +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. - 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"; + var commitTime = getCommitTime(); + var phase = finishedWork.alternate === null ? 'mount' : 'update'; + + { + if (isCurrentUpdateNested()) { + phase = 'nested-update'; + } } - } - if (typeof onRender === "function") { - onRender( - finishedWork.memoizedProps.id, - phase, - finishedWork.actualDuration, - finishedWork.treeBaseDuration, - finishedWork.actualStartTime, - commitTime - ); - } + 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. - 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. - - 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. var parentFiber = finishedWork.return; @@ -23479,4384 +19812,4097 @@ to return true:wantsResponderID| | switch (parentFiber.tag) { case HostRoot: var root = parentFiber.stateNode; - root.effectDuration += effectDuration; + root.passiveEffectDuration += passiveEffectDuration; break outer; case Profiler: var parentStateNode = parentFiber.stateNode; - parentStateNode.effectDuration += effectDuration; + parentStateNode.passiveEffectDuration += passiveEffectDuration; break outer; } parentFiber = parentFiber.return; } + + break; } - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); + } + } + } +} + +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); + } + } +} + +function commitClassLayoutLifecycles(finishedWork, current) { + var instance = finishedWork.stateNode; + + 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.defaultProps && !('ref' in finishedWork.memoizedProps) && !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 (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'); } } } - 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; + if (shouldProfile(finishedWork)) { + try { + startLayoutEffectTimer(); + instance.componentDidMount(); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } - switch (finishedWork.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); + recordLayoutEffectDuration(finishedWork); + } else { + try { + instance.componentDidMount(); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } + } + } else { + var prevProps = resolveClassComponentProps(finishedWork.type, current.memoizedProps, finishedWork.elementType === finishedWork.type); + 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 (flags & Update) { - commitHookLayoutEffects(finishedWork, Layout | HasEffect); - } + { + if (!finishedWork.type.defaultProps && !('ref' in finishedWork.memoizedProps) && !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'); + } - 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 ClassComponent: { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); + if (shouldProfile(finishedWork)) { + try { + startLayoutEffectTimer(); + instance.componentDidUpdate(prevProps, prevState, instance.__reactInternalSnapshotBeforeUpdate); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } - if (flags & Update) { - commitClassLayoutLifecycles(finishedWork, current); - } + recordLayoutEffectDuration(finishedWork); + } else { + try { + instance.componentDidUpdate(prevProps, prevState, instance.__reactInternalSnapshotBeforeUpdate); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } + } + } +} - if (flags & Callback) { - commitClassCallbacks(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 & Ref) { - safelyAttachRef(finishedWork, finishedWork.return); - } + if (updateQueue !== null) { + var instance = finishedWork.stateNode; - break; + { + if (!finishedWork.type.defaultProps && !('ref' in finishedWork.memoizedProps) && !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'); } - case HostRoot: { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); + 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. - 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; + try { + commitCallbacks(updateQueue, instance); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } + } +} - if (finishedWork.child !== null) { - switch (finishedWork.child.tag) { - case HostSingleton: - case HostComponent: - instance = getPublicInstance(finishedWork.child.stateNode); - break; +function commitHostComponentMount(finishedWork) { + var type = finishedWork.type; + var props = finishedWork.memoizedProps; + var instance = finishedWork.stateNode; - case ClassComponent: - instance = finishedWork.child.stateNode; - break; - } - } + try { + commitMount(instance, type, props, finishedWork); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } +} - try { - commitCallbacks(updateQueue, instance); - } 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'; - break; + if (enableProfilerNestedUpdatePhase) { + if (isCurrentUpdateNested()) { + phase = 'nested-update'; } + } - case HostHoistable: + if (typeof onRender === 'function') { + onRender(finishedWork.memoizedProps.id, phase, finishedWork.actualDuration, finishedWork.treeBaseDuration, finishedWork.actualStartTime, commitTime); + } - 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 (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 (flags & Ref) { - safelyAttachRef(finishedWork, finishedWork.return); + + 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. + + var parentFiber = finishedWork.return; + + 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; } - break; + parentFiber = parentFiber.return; + } + } + } 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; + + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: + { + recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); + + if (flags & Update) { + commitHookLayoutEffects(finishedWork, Layout | HasEffect); } - 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. + break; + } - if (flags & Update) { - commitProfilerUpdate(finishedWork, current); - } + case ClassComponent: + { + recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); - break; + if (flags & Update) { + commitClassLayoutLifecycles(finishedWork, current); } - case SuspenseComponent: { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); + if (flags & Callback) { + commitClassCallbacks(finishedWork); + } - break; + if (flags & Ref) { + safelyAttachRef(finishedWork, finishedWork.return); } - case OffscreenComponent: { - var isModernRoot = (finishedWork.mode & ConcurrentMode) !== NoMode; - - if (isModernRoot) { - var isHidden = finishedWork.memoizedState !== null; - var newOffscreenSubtreeIsHidden = - isHidden || offscreenSubtreeIsHidden; - - 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 (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); + 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; } + } - offscreenSubtreeIsHidden = prevOffscreenSubtreeIsHidden; - offscreenSubtreeWasHidden = prevOffscreenSubtreeWasHidden; + try { + commitCallbacks(updateQueue, instance); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); } - } else { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); } + } - if (flags & Ref) { - var props = finishedWork.memoizedProps; + break; + } - if (props.mode === "manual") { - safelyAttachRef(finishedWork, finishedWork.return); - } else { - safelyDetachRef(finishedWork, finishedWork.return); - } - } + case HostHoistable: - break; + 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); } - default: { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); - break; + if (flags & Ref) { + safelyAttachRef(finishedWork, finishedWork.return); } + + break; } - } - function hideOrUnhideAllChildren(finishedWork, isHidden) { - // Only hide or unhide the top-most host nodes. - var hostSubtreeRoot = null; + 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; + } + case SuspenseComponent: { - // We only have the top Fiber that was inserted but we need to recurse down its - // children to find all the terminal nodes. - var node = finishedWork; + recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); - while (true) { - if (node.tag === HostComponent || false || false) { - if (hostSubtreeRoot === null) { - hostSubtreeRoot = node; + break; + } - try { - var instance = node.stateNode; + case OffscreenComponent: + { + var isModernRoot = (finishedWork.mode & ConcurrentMode) !== NoMode; - if (isHidden) { - hideInstance(instance); - } else { - unhideInstance(node.stateNode, node.memoizedProps); - } - } catch (error) { - captureCommitPhaseError( - finishedWork, - finishedWork.return, - error - ); - } - } - } else if (node.tag === HostText) { - if (hostSubtreeRoot === null) { - try { - var _instance = node.stateNode; + if (isModernRoot) { + var isHidden = finishedWork.memoizedState !== null; + var newOffscreenSubtreeIsHidden = isHidden || offscreenSubtreeIsHidden; - if (isHidden) { - hideTextInstance(_instance); - } else { - unhideTextInstance(_instance, node.memoizedProps); - } - } catch (error) { - captureCommitPhaseError( - finishedWork, - finishedWork.return, - error - ); - } + 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 (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); } - } else if ( - (node.tag === OffscreenComponent || - node.tag === LegacyHiddenComponent) && - node.memoizedState !== null && - node !== finishedWork - ); - else if (node.child !== null) { - node.child.return = node; - node = node.child; - continue; - } - if (node === finishedWork) { - return; + offscreenSubtreeIsHidden = prevOffscreenSubtreeIsHidden; + offscreenSubtreeWasHidden = prevOffscreenSubtreeWasHidden; } + } else { + recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); + } - while (node.sibling === null) { - if (node.return === null || node.return === finishedWork) { - return; - } - - if (hostSubtreeRoot === node) { - hostSubtreeRoot = null; - } + if (flags & Ref) { + var props = finishedWork.memoizedProps; - node = node.return; + if (props.mode === 'manual') { + safelyAttachRef(finishedWork, finishedWork.return); + } else { + safelyDetachRef(finishedWork, finishedWork.return); } + } - if (hostSubtreeRoot === node) { - hostSubtreeRoot = null; - } + break; + } - node.sibling.return = node.return; - node = node.sibling; - } + default: + { + recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); + break; } - } + } +} - function commitAttachRef(finishedWork) { - var ref = finishedWork.ref; +function hideOrUnhideAllChildren(finishedWork, isHidden) { + // Only hide or unhide the top-most host nodes. + var hostSubtreeRoot = null; - if (ref !== null) { - var instance = finishedWork.stateNode; - var instanceToUse; + { + // We only have the top Fiber that was inserted but we need to recurse down its + // children to find all the terminal nodes. + var node = finishedWork; - switch (finishedWork.tag) { - case HostHoistable: - case HostSingleton: - case HostComponent: - instanceToUse = getPublicInstance(instance); - break; + while (true) { + if (node.tag === HostComponent || (false) || (false)) { + if (hostSubtreeRoot === null) { + hostSubtreeRoot = node; - default: - instanceToUse = instance; - } // Moved outside to ensure DCE works with this flag + try { + var instance = node.stateNode; - if (typeof ref === "function") { - if (shouldProfile(finishedWork)) { - try { - startLayoutEffectTimer(); - finishedWork.refCleanup = ref(instanceToUse); - } finally { - recordLayoutEffectDuration(finishedWork); + if (isHidden) { + hideInstance(instance); + } else { + unhideInstance(node.stateNode, node.memoizedProps); } - } else { - finishedWork.refCleanup = ref(instanceToUse); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); } - } else { - { - // TODO: We should move these warnings to happen during the render - // phase (markRef). - if (!ref.hasOwnProperty("current")) { - error( - "Unexpected ref object provided for %s. " + - "Use either a ref-setter function or React.createRef().", - getComponentNameFromFiber(finishedWork) - ); - } - } // $FlowFixMe[incompatible-use] unable to narrow type to the non-function case + } + } else if (node.tag === HostText) { + if (hostSubtreeRoot === null) { + try { + var _instance = node.stateNode; - ref.current = instanceToUse; + if (isHidden) { + hideTextInstance(_instance); + } else { + unhideTextInstance(_instance, node.memoizedProps); + } + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } } + } else if ((node.tag === OffscreenComponent || node.tag === LegacyHiddenComponent) && node.memoizedState !== null && node !== finishedWork) ; else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; } - } - 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 (node === finishedWork) { + return; + } - if (alternate !== null) { - alternate.return = null; + while (node.sibling === null) { + if (node.return === null || node.return === finishedWork) { + return; + } + + if (hostSubtreeRoot === node) { + hostSubtreeRoot = null; + } + + node = node.return; } - fiber.return = null; + if (hostSubtreeRoot === node) { + hostSubtreeRoot = null; + } + + node.sibling.return = node.return; + node = node.sibling; } + } +} - function detachFiberAfterEffects(fiber) { - var alternate = fiber.alternate; +function commitAttachRef(finishedWork) { + var ref = finishedWork.ref; - 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 (ref !== null) { + var instance = finishedWork.stateNode; + var instanceToUse; - fiber.child = null; - fiber.deletions = null; - fiber.sibling = null; // The `stateNode` is cyclical because on host nodes it points to the host + switch (finishedWork.tag) { + case HostHoistable: + case HostSingleton: + case HostComponent: + instanceToUse = getPublicInstance(instance); + break; - fiber.stateNode = null; + default: + instanceToUse = instance; + } // Moved outside to ensure DCE works with this flag + if (typeof ref === 'function') { + if (shouldProfile(finishedWork)) { + try { + startLayoutEffectTimer(); + finishedWork.refCleanup = ref(instanceToUse); + } finally { + recordLayoutEffectDuration(finishedWork); + } + } else { + finishedWork.refCleanup = ref(instanceToUse); + } + } else { { - 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. + // TODO: We should move these warnings to happen during the render + // phase (markRef). + if (!ref.hasOwnProperty('current')) { + error('Unexpected ref object provided for %s. ' + 'Use either a ref-setter function or React.createRef().', getComponentNameFromFiber(finishedWork)); + } + } // $FlowFixMe[incompatible-use] unable to narrow type to the non-function case - 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; + ref.current = instanceToUse; } + } +} - function getHostParentFiber(fiber) { - var parent = fiber.return; +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; + } + + fiber.return = null; +} - while (parent !== null) { - if (isHostParent(parent)) { - return parent; - } +function detachFiberAfterEffects(fiber) { + var alternate = fiber.alternate; - parent = parent.return; - } + 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. - throw new Error( - "Expected to find a host parent. This error is likely caused by a bug " + - "in React. Please file an issue." - ); - } - function isHostParent(fiber) { - return ( - fiber.tag === HostComponent || - fiber.tag === HostRoot || - false || - false || - fiber.tag === HostPortal - ); - } + fiber.child = null; + fiber.deletions = null; + fiber.sibling = null; // The `stateNode` is cyclical because on host nodes it points to the host - function getHostSibling(fiber) { - // We're going to search forward into the tree until we find a sibling host - // node. Unfortunately, if multiple insertions are done in a row we have to - // search past them. This leads to exponential search for the next sibling. - // TODO: Find a more efficient way to do this. - var node = fiber; + fiber.stateNode = null; - siblings: while (true) { - // If we didn't find anything, let's try the next sibling. - while (node.sibling === null) { - if (node.return === null || isHostParent(node.return)) { - // If we pop out of the root or hit the parent the fiber we are the - // last sibling. - return null; - } // $FlowFixMe[incompatible-type] found when upgrading Flow - - node = node.return; - } - - node.sibling.return = node.return; - node = node.sibling; - - while ( - node.tag !== HostComponent && - node.tag !== HostText && - true && - node.tag !== DehydratedFragment - ) { - // If it is not host node and, we might have a host node inside it. - // Try to search down until we find one. - if (node.flags & Placement) { - // If we don't have a child, try the siblings instead. - continue siblings; - } // If we don't have a child, try the siblings instead. - // We also skip portals because they are not part of this host tree. - - if (node.child === null || node.tag === HostPortal) { - continue siblings; - } else { - node.child.return = node; - node = node.child; - } - } // Check if this host node is stable or about to be placed. + { + 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. - if (!(node.flags & Placement)) { - // Found it! - return node.stateNode; - } - } - } - function commitPlacement(finishedWork) { - var parentFiber = getHostParentFiber(finishedWork); + fiber.return = null; + fiber.dependencies = null; + fiber.memoizedProps = null; + fiber.memoizedState = null; + fiber.pendingProps = null; + fiber.stateNode = null; // TODO: Move to `commitPassiveUnmountInsideDeletedTreeOnFiber` instead. - switch (parentFiber.tag) { - case HostSingleton: + fiber.updateQueue = null; +} - case HostComponent: { - var _parent = parentFiber.stateNode; +function getHostParentFiber(fiber) { + var parent = fiber.return; - if (parentFiber.flags & ContentReset) { - parentFiber.flags &= ~ContentReset; - } + while (parent !== null) { + if (isHostParent(parent)) { + return parent; + } - var _before = getHostSibling(finishedWork); // We only have the top Fiber that was inserted but we need to recurse down its - // children to find all the terminal nodes. + parent = parent.return; + } - insertOrAppendPlacementNode(finishedWork, _before, _parent); - break; - } + throw new Error('Expected to find a host parent. This error is likely caused by a bug ' + 'in React. Please file an issue.'); +} - case HostRoot: - case HostPortal: { - var _parent2 = parentFiber.stateNode.containerInfo; +function isHostParent(fiber) { + return fiber.tag === HostComponent || fiber.tag === HostRoot || (false) || (false) || fiber.tag === HostPortal; +} - var _before2 = getHostSibling(finishedWork); +function getHostSibling(fiber) { + // We're going to search forward into the tree until we find a sibling host + // node. Unfortunately, if multiple insertions are done in a row we have to + // search past them. This leads to exponential search for the next sibling. + // TODO: Find a more efficient way to do this. + var node = fiber; + + siblings: while (true) { + // If we didn't find anything, let's try the next sibling. + while (node.sibling === null) { + if (node.return === null || isHostParent(node.return)) { + // If we pop out of the root or hit the parent the fiber we are the + // last sibling. + return null; + } // $FlowFixMe[incompatible-type] found when upgrading Flow - insertOrAppendPlacementNodeIntoContainer( - finishedWork, - _before2, - _parent2 - ); - break; - } - default: - throw new Error( - "Invalid host parent fiber. This error is likely caused by a bug " + - "in React. Please file an issue." - ); - } + node = node.return; } - function insertOrAppendPlacementNodeIntoContainer(node, before, parent) { - var tag = node.tag; - var isHost = tag === HostComponent || tag === HostText; - - if (isHost) { - var stateNode = node.stateNode; + node.sibling.return = node.return; + node = node.sibling; - if (before) { - insertInContainerBefore(parent); - } else { - appendChildToContainer(parent, stateNode); - } - } else if (tag === HostPortal || false); - else { - var child = node.child; + while (node.tag !== HostComponent && node.tag !== HostText && (true ) && node.tag !== DehydratedFragment) { + // If it is not host node and, we might have a host node inside it. + // Try to search down until we find one. + if (node.flags & Placement) { + // If we don't have a child, try the siblings instead. + continue siblings; + } // If we don't have a child, try the siblings instead. + // We also skip portals because they are not part of this host tree. - if (child !== null) { - insertOrAppendPlacementNodeIntoContainer(child, before, parent); - var sibling = child.sibling; - while (sibling !== null) { - insertOrAppendPlacementNodeIntoContainer(sibling, before, parent); - sibling = sibling.sibling; - } - } + if (node.child === null || node.tag === HostPortal) { + continue siblings; + } else { + node.child.return = node; + node = node.child; } - } + } // Check if this host node is stable or about to be placed. - function insertOrAppendPlacementNode(node, before, parent) { - var tag = node.tag; - var isHost = tag === HostComponent || tag === HostText; - if (isHost) { - var stateNode = node.stateNode; + if (!(node.flags & Placement)) { + // Found it! + return node.stateNode; + } + } +} - if (before) { - insertBefore(parent, stateNode, before); - } else { - appendChild(parent, stateNode); - } - } else if (tag === HostPortal || false); - else { - var child = node.child; +function commitPlacement(finishedWork) { - if (child !== null) { - insertOrAppendPlacementNode(child, before, parent); - var sibling = child.sibling; - while (sibling !== null) { - insertOrAppendPlacementNode(sibling, before, parent); - sibling = sibling.sibling; - } - } - } - } // These are tracked on the stack as we recursively traverse a - // deleted subtree. - // TODO: Update these during the whole mutation phase, not just during - // a deletion. + var parentFiber = getHostParentFiber(finishedWork); - var hostParent = null; - var hostParentIsContainer = false; + switch (parentFiber.tag) { + case HostSingleton: - function commitDeletionEffects(root, returnFiber, deletedFiber) { + case HostComponent: { - // We only have the top Fiber that was deleted but we need to recurse down its - // children to find all the terminal nodes. - // Recursively delete all host nodes from the parent, detach refs, clean - // up mounted layout effects, and call componentWillUnmount. - // We only need to remove the topmost host child in each branch. But then we - // still need to keep traversing to unmount effects, refs, and cWU. TODO: We - // could split this into two separate traversals functions, where the second - // one doesn't include any removeChild logic. This is maybe the same - // function as "disappearLayoutEffects" (or whatever that turns into after - // the layout phase is refactored to use recursion). - // Before starting, find the nearest host parent on the stack so we know - // which instance/container to remove the children from. - // TODO: Instead of searching up the fiber return path on every deletion, we - // can track the nearest host component on the JS stack as we traverse the - // tree during the commit phase. This would make insertions faster, too. - var parent = returnFiber; - - findParent: while (parent !== null) { - switch (parent.tag) { - case HostSingleton: - case HostComponent: { - hostParent = parent.stateNode; - hostParentIsContainer = false; - break findParent; - } - - case HostRoot: { - hostParent = parent.stateNode.containerInfo; - hostParentIsContainer = true; - break findParent; - } + var _parent = parentFiber.stateNode; - case HostPortal: { - hostParent = parent.stateNode.containerInfo; - hostParentIsContainer = true; - break findParent; - } - } + if (parentFiber.flags & ContentReset) { - parent = parent.return; + parentFiber.flags &= ~ContentReset; } - if (hostParent === null) { - throw new Error( - "Expected to find a host parent. This error is likely caused by " + - "a bug in React. Please file an issue." - ); - } + var _before = getHostSibling(finishedWork); // We only have the top Fiber that was inserted but we need to recurse down its + // children to find all the terminal nodes. + - commitDeletionEffectsOnFiber(root, returnFiber, deletedFiber); - hostParent = null; - hostParentIsContainer = false; + insertOrAppendPlacementNode(finishedWork, _before, _parent); + break; } - detachFiberMutation(deletedFiber); - } + case HostRoot: + case HostPortal: + { + var _parent2 = parentFiber.stateNode.containerInfo; - function recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - parent - ) { - // TODO: Use a static flag to skip trees that don't have unmount effects - var child = parent.child; + var _before2 = getHostSibling(finishedWork); - while (child !== null) { - commitDeletionEffectsOnFiber( - finishedRoot, - nearestMountedAncestor, - child - ); - child = child.sibling; + insertOrAppendPlacementNodeIntoContainer(finishedWork, _before2, _parent2); + break; } - } - - 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: + default: + throw new Error('Invalid host parent fiber. This error is likely caused by a bug ' + 'in React. Please file an issue.'); + } +} - case HostSingleton: +function insertOrAppendPlacementNodeIntoContainer(node, before, parent) { + var tag = node.tag; + var isHost = tag === HostComponent || tag === HostText; - case HostComponent: { - if (!offscreenSubtreeWasHidden) { - safelyDetachRef(deletedFiber, nearestMountedAncestor); - } // Intentional fallthrough to next branch - } + if (isHost) { + var stateNode = node.stateNode; - 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. - { - var _prevHostParent = hostParent; - var _prevHostParentIsContainer = hostParentIsContainer; - hostParent = null; - recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - deletedFiber - ); - hostParent = _prevHostParent; - hostParentIsContainer = _prevHostParentIsContainer; - - if (hostParent !== null) { - // Now that all the child effects have unmounted, we can remove the - // node from the tree. - if (hostParentIsContainer) { - removeChildFromContainer(hostParent, deletedFiber.stateNode); - } else { - removeChild(hostParent, deletedFiber.stateNode); - } - } - } + if (before) { + insertInContainerBefore(parent); + } else { + appendChildToContainer(parent, stateNode); + } + } else if (tag === HostPortal || (false)) ; else { + var child = node.child; - return; - } + if (child !== null) { + insertOrAppendPlacementNodeIntoContainer(child, before, parent); + var sibling = child.sibling; - case DehydratedFragment: { - // Delete the dehydrated suspense boundary and all of its content. + while (sibling !== null) { + insertOrAppendPlacementNodeIntoContainer(sibling, before, parent); + sibling = sibling.sibling; + } + } + } +} +function insertOrAppendPlacementNode(node, before, parent) { + var tag = node.tag; + var isHost = tag === HostComponent || tag === HostText; + + if (isHost) { + var stateNode = node.stateNode; + + if (before) { + insertBefore(parent, stateNode, before); + } else { + appendChild(parent, stateNode); + } + } else if (tag === HostPortal || (false)) ; else { + var child = node.child; + + if (child !== null) { + insertOrAppendPlacementNode(child, before, parent); + var sibling = child.sibling; + + while (sibling !== null) { + insertOrAppendPlacementNode(sibling, before, parent); + sibling = sibling.sibling; + } + } + } +} // These are tracked on the stack as we recursively traverse a +// deleted subtree. +// TODO: Update these during the whole mutation phase, not just during +// a deletion. + + +var hostParent = null; +var hostParentIsContainer = false; + +function commitDeletionEffects(root, returnFiber, deletedFiber) { + { + // We only have the top Fiber that was deleted but we need to recurse down its + // children to find all the terminal nodes. + // Recursively delete all host nodes from the parent, detach refs, clean + // up mounted layout effects, and call componentWillUnmount. + // We only need to remove the topmost host child in each branch. But then we + // still need to keep traversing to unmount effects, refs, and cWU. TODO: We + // could split this into two separate traversals functions, where the second + // one doesn't include any removeChild logic. This is maybe the same + // function as "disappearLayoutEffects" (or whatever that turns into after + // the layout phase is refactored to use recursion). + // Before starting, find the nearest host parent on the stack so we know + // which instance/container to remove the children from. + // TODO: Instead of searching up the fiber return path on every deletion, we + // can track the nearest host component on the JS stack as we traverse the + // tree during the commit phase. This would make insertions faster, too. + var parent = returnFiber; + + findParent: while (parent !== null) { + switch (parent.tag) { + case HostSingleton: + case HostComponent: { - if (hostParent !== null) { - if (hostParentIsContainer) { - clearSuspenseBoundaryFromContainer(); - } else { - clearSuspenseBoundary(); - } - } + hostParent = parent.stateNode; + hostParentIsContainer = false; + break findParent; } - return; - } + case HostRoot: + { + hostParent = parent.stateNode.containerInfo; + hostParentIsContainer = true; + break findParent; + } - case HostPortal: { + case HostPortal: { - // When we go into a portal, it becomes the parent to remove from. - var _prevHostParent2 = hostParent; - var _prevHostParentIsContainer2 = hostParentIsContainer; - hostParent = deletedFiber.stateNode.containerInfo; + hostParent = parent.stateNode.containerInfo; hostParentIsContainer = true; - recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - deletedFiber - ); - hostParent = _prevHostParent2; - hostParentIsContainer = _prevHostParentIsContainer2; + break findParent; } + } - return; - } + parent = parent.return; + } - case FunctionComponent: - case ForwardRef: - case MemoComponent: - case SimpleMemoComponent: { - if (!offscreenSubtreeWasHidden) { - var updateQueue = deletedFiber.updateQueue; + if (hostParent === null) { + throw new Error('Expected to find a host parent. This error is likely caused by ' + 'a bug in React. Please file an issue.'); + } - if (updateQueue !== null) { - var lastEffect = updateQueue.lastEffect; + commitDeletionEffectsOnFiber(root, returnFiber, deletedFiber); + hostParent = null; + hostParentIsContainer = false; + } - if (lastEffect !== null) { - var firstEffect = lastEffect.next; - var effect = firstEffect; + detachFiberMutation(deletedFiber); +} - do { - var tag = effect.tag; - var inst = effect.inst; - var destroy = inst.destroy; +function recursivelyTraverseDeletionEffects(finishedRoot, nearestMountedAncestor, parent) { + // TODO: Use a static flag to skip trees that don't have unmount effects + var child = parent.child; - if (destroy !== undefined) { - if ((tag & Insertion) !== NoFlags) { - inst.destroy = undefined; - safelyCallDestroy( - deletedFiber, - nearestMountedAncestor, - destroy - ); - } else if ((tag & Layout) !== NoFlags) { - { - markComponentLayoutEffectUnmountStarted(deletedFiber); - } + while (child !== null) { + commitDeletionEffectsOnFiber(finishedRoot, nearestMountedAncestor, child); + child = child.sibling; + } +} - if (shouldProfile(deletedFiber)) { - startLayoutEffectTimer(); - inst.destroy = undefined; - safelyCallDestroy( - deletedFiber, - nearestMountedAncestor, - destroy - ); - recordLayoutEffectDuration(deletedFiber); - } else { - inst.destroy = undefined; - safelyCallDestroy( - deletedFiber, - nearestMountedAncestor, - destroy - ); - } +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. - { - markComponentLayoutEffectUnmountStopped(); - } - } - } + switch (deletedFiber.tag) { + case HostHoistable: - effect = effect.next; - } while (effect !== firstEffect); - } - } - } + case HostSingleton: - recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - deletedFiber - ); - return; - } + case HostComponent: + { + if (!offscreenSubtreeWasHidden) { + safelyDetachRef(deletedFiber, nearestMountedAncestor); + } // Intentional fallthrough to next branch - case ClassComponent: { - if (!offscreenSubtreeWasHidden) { - safelyDetachRef(deletedFiber, nearestMountedAncestor); - var instance = deletedFiber.stateNode; + } - if (typeof instance.componentWillUnmount === "function") { - safelyCallComponentWillUnmount( - deletedFiber, - nearestMountedAncestor, - instance - ); + 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. + { + var _prevHostParent = hostParent; + var _prevHostParentIsContainer = hostParentIsContainer; + hostParent = null; + recursivelyTraverseDeletionEffects(finishedRoot, nearestMountedAncestor, deletedFiber); + hostParent = _prevHostParent; + hostParentIsContainer = _prevHostParentIsContainer; + + if (hostParent !== null) { + // Now that all the child effects have unmounted, we can remove the + // node from the tree. + if (hostParentIsContainer) { + removeChildFromContainer(hostParent, deletedFiber.stateNode); + } else { + removeChild(hostParent, deletedFiber.stateNode); } } - - recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - deletedFiber - ); - return; } - case ScopeComponent: { - recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - deletedFiber - ); - return; - } + return; + } - case OffscreenComponent: { - safelyDetachRef(deletedFiber, nearestMountedAncestor); + case DehydratedFragment: + { + // Delete the dehydrated suspense boundary and all of its content. - 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 - ); - } - break; + { + if (hostParent !== null) { + if (hostParentIsContainer) { + clearSuspenseBoundaryFromContainer(); + } else { + clearSuspenseBoundary(); + } + } } - default: { - recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - deletedFiber - ); - return; - } + return; } - } - function commitSuspenseCallback(finishedWork) {} + case HostPortal: + { + { + // When we go into a portal, it becomes the parent to remove from. + var _prevHostParent2 = hostParent; + var _prevHostParentIsContainer2 = hostParentIsContainer; + hostParent = deletedFiber.stateNode.containerInfo; + hostParentIsContainer = true; + recursivelyTraverseDeletionEffects(finishedRoot, nearestMountedAncestor, deletedFiber); + hostParent = _prevHostParent2; + hostParentIsContainer = _prevHostParentIsContainer2; + } + + return; + } - 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; + case FunctionComponent: + case ForwardRef: + case MemoComponent: + case SimpleMemoComponent: + { + if (!offscreenSubtreeWasHidden) { + var updateQueue = deletedFiber.updateQueue; - if (retryCache === null) { - retryCache = finishedWork.stateNode = new PossiblyWeakSet(); - } + if (updateQueue !== null) { + var lastEffect = updateQueue.lastEffect; + + if (lastEffect !== null) { + var firstEffect = lastEffect.next; + var effect = firstEffect; + + do { + var tag = effect.tag; + var inst = effect.inst; + var destroy = inst.destroy; + + if (destroy !== undefined) { + if ((tag & Insertion) !== NoFlags) { + inst.destroy = undefined; + safelyCallDestroy(deletedFiber, nearestMountedAncestor, destroy); + } else if ((tag & Layout) !== NoFlags) { + { + markComponentLayoutEffectUnmountStarted(deletedFiber); + } - return retryCache; - } + if (shouldProfile(deletedFiber)) { + startLayoutEffectTimer(); + inst.destroy = undefined; + safelyCallDestroy(deletedFiber, nearestMountedAncestor, destroy); + recordLayoutEffectDuration(deletedFiber); + } else { + inst.destroy = undefined; + safelyCallDestroy(deletedFiber, nearestMountedAncestor, destroy); + } - case OffscreenComponent: { - var instance = finishedWork.stateNode; - var _retryCache = instance._retryCache; + { + markComponentLayoutEffectUnmountStopped(); + } + } + } - if (_retryCache === null) { - _retryCache = instance._retryCache = new PossiblyWeakSet(); + effect = effect.next; + } while (effect !== firstEffect); + } } - - return _retryCache; } - default: { - throw new Error( - "Unexpected Suspense handler tag (" + - finishedWork.tag + - "). This is a " + - "bug in React." - ); - } + recursivelyTraverseDeletionEffects(finishedRoot, nearestMountedAncestor, deletedFiber); + return; } - } - function detachOffscreenInstance(instance) { - var fiber = instance._current; + case ClassComponent: + { + if (!offscreenSubtreeWasHidden) { + safelyDetachRef(deletedFiber, nearestMountedAncestor); + var instance = deletedFiber.stateNode; - if (fiber === null) { - throw new Error( - "Calling Offscreen.detach before instance handle has been set." - ); - } + if (typeof instance.componentWillUnmount === 'function') { + safelyCallComponentWillUnmount(deletedFiber, nearestMountedAncestor, instance); + } + } - if ((instance._pendingVisibility & OffscreenDetached) !== NoFlags$1) { - // The instance is already detached, this is a noop. + recursivelyTraverseDeletionEffects(finishedRoot, nearestMountedAncestor, deletedFiber); return; - } // TODO: There is an opportunity to optimise this by not entering commit phase - // and unmounting effects directly. + } - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + case ScopeComponent: + { - if (root !== null) { - instance._pendingVisibility |= OffscreenDetached; - scheduleUpdateOnFiber(root, fiber, SyncLane); + recursivelyTraverseDeletionEffects(finishedRoot, nearestMountedAncestor, deletedFiber); + return; } - } - function attachOffscreenInstance(instance) { - var fiber = instance._current; - if (fiber === null) { - throw new Error( - "Calling Offscreen.detach before instance handle has been set." - ); + case OffscreenComponent: + { + safelyDetachRef(deletedFiber, nearestMountedAncestor); + + 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); + } + + break; } - if ((instance._pendingVisibility & OffscreenDetached) === NoFlags$1) { - // The instance is already attached, this is a noop. + default: + { + recursivelyTraverseDeletionEffects(finishedRoot, nearestMountedAncestor, deletedFiber); return; } + } +} - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); +function commitSuspenseCallback(finishedWork) { +} - if (root !== null) { - instance._pendingVisibility &= ~OffscreenDetached; - scheduleUpdateOnFiber(root, fiber, SyncLane); - } - } +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; - 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 === null) { + retryCache = finishedWork.stateNode = new PossiblyWeakSet(); + } - if (!retryCache.has(wakeable)) { - retryCache.add(wakeable); + return retryCache; + } - { - 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." - ); - } - } - } + case OffscreenComponent: + { + var instance = finishedWork.stateNode; + var _retryCache = instance._retryCache; - wakeable.then(retry, retry); + if (_retryCache === null) { + _retryCache = instance._retryCache = new PossiblyWeakSet(); } - }); - } // 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; - } - - 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; - - if (deletions !== null) { - for (var i = 0; i < deletions.length; i++) { - var childToDelete = deletions[i]; - try { - commitDeletionEffects(root, parentFiber, childToDelete); - } catch (error) { - captureCommitPhaseError(childToDelete, parentFiber, error); - } - } + return _retryCache; } - var prevDebugFiber = getCurrentFiber(); + default: + { + throw new Error("Unexpected Suspense handler tag (" + finishedWork.tag + "). This is a " + 'bug in React.'); + } + } +} - if (parentFiber.subtreeFlags & MutationMask) { - var child = parentFiber.child; +function detachOffscreenInstance(instance) { + var fiber = instance._current; - while (child !== null) { - setCurrentFiber(child); - commitMutationEffectsOnFiber(child, root); - child = child.sibling; - } - } + if (fiber === null) { + throw new Error('Calling Offscreen.detach before instance handle has been set.'); + } - setCurrentFiber(prevDebugFiber); - } + 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. - 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); + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - 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 (root !== null) { + instance._pendingVisibility |= OffscreenDetached; + scheduleUpdateOnFiber(root, fiber, SyncLane); + } +} +function attachOffscreenInstance(instance) { + var fiber = instance._current; - if (shouldProfile(finishedWork)) { - try { - startLayoutEffectTimer(); - commitHookEffectListUnmount( - Layout | HasEffect, - finishedWork, - finishedWork.return - ); - } catch (error) { - captureCommitPhaseError( - finishedWork, - finishedWork.return, - error - ); - } + if (fiber === null) { + throw new Error('Calling Offscreen.detach before instance handle has been set.'); + } - recordLayoutEffectDuration(finishedWork); - } else { - try { - commitHookEffectListUnmount( - Layout | HasEffect, - finishedWork, - finishedWork.return - ); - } catch (error) { - captureCommitPhaseError( - finishedWork, - finishedWork.return, - error - ); - } - } - } + if ((instance._pendingVisibility & OffscreenDetached) === NoFlags$1) { + // The instance is already attached, this is a noop. + return; + } - return; - } + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - case ClassComponent: { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); + if (root !== null) { + instance._pendingVisibility &= ~OffscreenDetached; + scheduleUpdateOnFiber(root, fiber, SyncLane); + } +} - if (flags & Ref) { - if (current !== null) { - safelyDetachRef(current, current.return); - } - } +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 (flags & Callback && offscreenSubtreeIsHidden) { - var updateQueue = finishedWork.updateQueue; + if (!retryCache.has(wakeable)) { + retryCache.add(wakeable); - if (updateQueue !== null) { - deferHiddenCallbacks(updateQueue); - } + { + 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.'); } - - return; } + } - case HostHoistable: + 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 HostSingleton: +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 HostComponent: { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); + if (deletions !== null) { + for (var i = 0; i < deletions.length; i++) { + var childToDelete = deletions[i]; - if (flags & Ref) { - if (current !== null) { - safelyDetachRef(current, current.return); - } - } + try { + commitDeletionEffects(root, parentFiber, childToDelete); + } catch (error) { + captureCommitPhaseError(childToDelete, parentFiber, error); + } + } + } - { - // TODO: ContentReset gets cleared by the children during the commit - // phase. This is a refactor hazard because it means we must read - // flags the flags after `commitReconciliationEffects` has already run; - // the order matters. We should refactor so that ContentReset does not - // rely on mutating the flag during commit. Like by setting a flag - // during the render phase instead. - if (finishedWork.flags & ContentReset) { - var instance = finishedWork.stateNode; + var prevDebugFiber = getCurrentFiber(); - try { - resetTextContent(instance); - } catch (error) { - captureCommitPhaseError( - finishedWork, - finishedWork.return, - error - ); - } - } + if (parentFiber.subtreeFlags & MutationMask) { + var child = parentFiber.child; - if (flags & Update) { - var _instance2 = finishedWork.stateNode; - - if (_instance2 != null) { - // Commit the work prepared earlier. - var newProps = finishedWork.memoizedProps; // For hydration we reuse the update path but we treat the oldProps - // as the newProps. The updatePayload will contain the real change in - // this case. - - var oldProps = - current !== null ? current.memoizedProps : newProps; - var type = finishedWork.type; // TODO: Type the updateQueue to be specific to host components. - - var _updatePayload = finishedWork.updateQueue; - finishedWork.updateQueue = null; - - try { - commitUpdate( - _instance2, - _updatePayload, - type, - oldProps, - newProps, - finishedWork - ); - } catch (error) { - captureCommitPhaseError( - finishedWork, - finishedWork.return, - error - ); - } - } - } + while (child !== null) { + setCurrentFiber(child); + commitMutationEffectsOnFiber(child, root); + child = child.sibling; + } + } - if (flags & FormReset) { - { - if (finishedWork.type !== "form") { - // Paranoid coding. In case we accidentally start using the - // FormReset bit for something else. - error( - "Unexpected host component type. Expected a form. This is a " + - "bug in React." - ); - } - } - } - } + setCurrentFiber(prevDebugFiber); +} - return; - } +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. - case HostText: { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case MemoComponent: + case SimpleMemoComponent: + { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); - if (flags & Update) { - { - if (finishedWork.stateNode === null) { - throw new Error( - "This should have a text node initialized. This error is likely " + - "caused by a bug in React. Please file an issue." - ); - } + 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. - var textInstance = finishedWork.stateNode; - var newText = finishedWork.memoizedProps; // For hydration we reuse the update path but we treat the oldProps - // as the newProps. The updatePayload will contain the real change in - // this case. - var oldText = current !== null ? current.memoizedProps : newText; + if (shouldProfile(finishedWork)) { + try { + startLayoutEffectTimer(); + commitHookEffectListUnmount(Layout | HasEffect, finishedWork, finishedWork.return); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } - try { - commitTextUpdate(textInstance, oldText, newText); - } catch (error) { - captureCommitPhaseError( - finishedWork, - finishedWork.return, - error - ); - } + recordLayoutEffectDuration(finishedWork); + } else { + try { + commitHookEffectListUnmount(Layout | HasEffect, finishedWork, finishedWork.return); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); } } - - return; } - case HostRoot: { - { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); - } + return; + } - return; - } + case ClassComponent: + { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); - case HostPortal: { - { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); + if (flags & Ref) { + if (current !== null) { + safelyDetachRef(current, current.return); } + } - return; + if (flags & Callback && offscreenSubtreeIsHidden) { + var updateQueue = finishedWork.updateQueue; + + if (updateQueue !== null) { + deferHiddenCallbacks(updateQueue); + } } - case SuspenseComponent: { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); // TODO: We should mark a flag on the Suspense fiber itself, rather than - // relying on the Offscreen fiber having a flag also being marked. The - // reason is that this offscreen fiber might not be part of the work-in- - // progress tree! It could have been reused from a previous render. This - // doesn't lead to incorrect behavior because we don't rely on the flag - // check alone; we also compare the states explicitly below. But for - // modeling purposes, we _should_ be able to rely on the flag check alone. - // So this is a bit fragile. - // - // Also, all this logic could/should move to the passive phase so it - // doesn't block paint. + return; + } - var offscreenFiber = finishedWork.child; + case HostHoistable: - if (offscreenFiber.flags & Visibility) { - // Throttle the appearance and disappearance of Suspense fallbacks. - var isShowingFallback = finishedWork.memoizedState !== null; - var wasShowingFallback = - current !== null && current.memoizedState !== null; + case HostSingleton: - if (alwaysThrottleRetries) { - if (isShowingFallback !== wasShowingFallback) { - // A fallback is either appearing or disappearing. - markCommitTimeOfFallback(); - } - } else { - if (isShowingFallback && !wasShowingFallback) { - // Old behavior. Only mark when a fallback appears, not when - // it disappears. - markCommitTimeOfFallback(); - } - } + case HostComponent: + { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); + + if (flags & Ref) { + if (current !== null) { + safelyDetachRef(current, current.return); } + } + + { + // TODO: ContentReset gets cleared by the children during the commit + // phase. This is a refactor hazard because it means we must read + // flags the flags after `commitReconciliationEffects` has already run; + // the order matters. We should refactor so that ContentReset does not + // rely on mutating the flag during commit. Like by setting a flag + // during the render phase instead. + if (finishedWork.flags & ContentReset) { + var instance = finishedWork.stateNode; - if (flags & Update) { try { - commitSuspenseCallback(finishedWork); + resetTextContent(instance); } catch (error) { captureCommitPhaseError(finishedWork, finishedWork.return, error); } + } - var retryQueue = finishedWork.updateQueue; + if (flags & Update) { + var _instance2 = finishedWork.stateNode; - if (retryQueue !== null) { - finishedWork.updateQueue = null; - attachSuspenseRetryListeners(finishedWork, retryQueue); - } - } + if (_instance2 != null) { + // Commit the work prepared earlier. + var newProps = finishedWork.memoizedProps; // For hydration we reuse the update path but we treat the oldProps + // as the newProps. The updatePayload will contain the real change in + // this case. - return; - } + var oldProps = current !== null ? current.memoizedProps : newProps; + var type = finishedWork.type; // TODO: Type the updateQueue to be specific to host components. - case OffscreenComponent: { - if (flags & Ref) { - if (current !== null) { - safelyDetachRef(current, current.return); + var _updatePayload = finishedWork.updateQueue; + finishedWork.updateQueue = null; + + try { + commitUpdate(_instance2, _updatePayload, type, oldProps, newProps, finishedWork); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } } } - var newState = finishedWork.memoizedState; - var isHidden = newState !== null; - var wasHidden = current !== null && current.memoizedState !== null; + if (flags & FormReset) { - 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 (finishedWork.type !== 'form') { + // Paranoid coding. In case we accidentally start using the + // FormReset bit for something else. + error('Unexpected host component type. Expected a form. This is a ' + 'bug in React.'); + } + } } + } - commitReconciliationEffects(finishedWork); - var offscreenInstance = finishedWork.stateNode; // TODO: Add explicit effect flag to set _current. - - offscreenInstance._current = finishedWork; // Offscreen stores pending changes to visibility in `_pendingVisibility`. This is - // to support batching of `attach` and `detach` calls. - - offscreenInstance._visibility &= ~OffscreenDetached; - offscreenInstance._visibility |= - offscreenInstance._pendingVisibility & OffscreenDetached; - - 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; - } + return; + } - 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 (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. + case HostText: + { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); - if (!isOffscreenManual(finishedWork)) { - // TODO: This needs to run whenever there's an insertion or update - // inside a hidden Offscreen tree. - hideOrUnhideAllChildren(finishedWork, isHidden); + if (flags & Update) { + { + if (finishedWork.stateNode === null) { + throw new Error('This should have a text node initialized. This error is likely ' + 'caused by a bug in React. Please file an issue.'); } - } // TODO: Move to passive phase - if (flags & Update) { - var offscreenQueue = finishedWork.updateQueue; + var textInstance = finishedWork.stateNode; + var newText = finishedWork.memoizedProps; // For hydration we reuse the update path but we treat the oldProps + // as the newProps. The updatePayload will contain the real change in + // this case. - if (offscreenQueue !== null) { - var _retryQueue = offscreenQueue.retryQueue; + var oldText = current !== null ? current.memoizedProps : newText; - if (_retryQueue !== null) { - offscreenQueue.retryQueue = null; - attachSuspenseRetryListeners(finishedWork, _retryQueue); - } + try { + commitTextUpdate(textInstance, oldText, newText); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); } } - - return; } - case SuspenseListComponent: { + return; + } + + case HostRoot: + { + { recursivelyTraverseMutationEffects(root, finishedWork); commitReconciliationEffects(finishedWork); - - if (flags & Update) { - var _retryQueue2 = finishedWork.updateQueue; - - if (_retryQueue2 !== null) { - finishedWork.updateQueue = null; - attachSuspenseRetryListeners(finishedWork, _retryQueue2); - } - } - - return; } - case ScopeComponent: { - return; - } + return; + } - default: { + case HostPortal: + { + { recursivelyTraverseMutationEffects(root, finishedWork); commitReconciliationEffects(finishedWork); - return; } - } - } - - 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; - 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. - - finishedWork.flags &= ~Placement; - } - - if (flags & Hydrating) { - finishedWork.flags &= ~Hydrating; + return; } - } - - 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(); - - if (parentFiber.subtreeFlags & LayoutMask) { - var child = parentFiber.child; + case SuspenseComponent: + { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); // TODO: We should mark a flag on the Suspense fiber itself, rather than + // relying on the Offscreen fiber having a flag also being marked. The + // reason is that this offscreen fiber might not be part of the work-in- + // progress tree! It could have been reused from a previous render. This + // doesn't lead to incorrect behavior because we don't rely on the flag + // check alone; we also compare the states explicitly below. But for + // modeling purposes, we _should_ be able to rely on the flag check alone. + // So this is a bit fragile. + // + // Also, all this logic could/should move to the passive phase so it + // doesn't block paint. - while (child !== null) { - setCurrentFiber(child); - var current = child.alternate; - commitLayoutEffectOnFiber(root, current, child); - child = child.sibling; - } - } + var offscreenFiber = finishedWork.child; - setCurrentFiber(prevDebugFiber); - } + if (offscreenFiber.flags & Visibility) { + // Throttle the appearance and disappearance of Suspense fallbacks. + var isShowingFallback = finishedWork.memoizedState !== null; + var wasShowingFallback = current !== null && current.memoizedState !== null; - function disappearLayoutEffects(finishedWork) { - switch (finishedWork.tag) { - case FunctionComponent: - case ForwardRef: - case MemoComponent: - case SimpleMemoComponent: { - // TODO (Offscreen) Check: flags & LayoutStatic - if (shouldProfile(finishedWork)) { - try { - startLayoutEffectTimer(); - commitHookEffectListUnmount( - Layout, - finishedWork, - finishedWork.return - ); - } finally { - recordLayoutEffectDuration(finishedWork); + if (alwaysThrottleRetries) { + if (isShowingFallback !== wasShowingFallback) { + // A fallback is either appearing or disappearing. + markCommitTimeOfFallback(); } } else { - commitHookEffectListUnmount( - Layout, - finishedWork, - finishedWork.return - ); + if (isShowingFallback && !wasShowingFallback) { + // Old behavior. Only mark when a fallback appears, not when + // it disappears. + markCommitTimeOfFallback(); + } } - - recursivelyTraverseDisappearLayoutEffects(finishedWork); - break; } - case ClassComponent: { - // TODO (Offscreen) Check: flags & RefStatic - safelyDetachRef(finishedWork, finishedWork.return); - var instance = finishedWork.stateNode; - - if (typeof instance.componentWillUnmount === "function") { - safelyCallComponentWillUnmount( - finishedWork, - finishedWork.return, - instance - ); + if (flags & Update) { + try { + commitSuspenseCallback(finishedWork); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); } - recursivelyTraverseDisappearLayoutEffects(finishedWork); - break; - } - - case HostHoistable: - case HostSingleton: - case HostComponent: { - // TODO (Offscreen) Check: flags & RefStatic - safelyDetachRef(finishedWork, finishedWork.return); - recursivelyTraverseDisappearLayoutEffects(finishedWork); - break; - } - - case OffscreenComponent: { - // TODO (Offscreen) Check: flags & RefStatic - safelyDetachRef(finishedWork, finishedWork.return); - var isHidden = finishedWork.memoizedState !== null; + var retryQueue = finishedWork.updateQueue; - if (isHidden); - else { - recursivelyTraverseDisappearLayoutEffects(finishedWork); + if (retryQueue !== null) { + finishedWork.updateQueue = null; + attachSuspenseRetryListeners(finishedWork, retryQueue); } - - break; } - default: { - recursivelyTraverseDisappearLayoutEffects(finishedWork); - break; - } + return; } - } - - function recursivelyTraverseDisappearLayoutEffects(parentFiber) { - // TODO (Offscreen) Check: flags & (RefStatic | LayoutStatic) - var child = parentFiber.child; - while (child !== null) { - disappearLayoutEffects(child); - child = child.sibling; - } - } + case OffscreenComponent: + { + if (flags & Ref) { + if (current !== null) { + safelyDetachRef(current, current.return); + } + } - 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; + var newState = finishedWork.memoizedState; + var isHidden = newState !== null; + var wasHidden = current !== null && current.memoizedState !== null; - switch (finishedWork.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - recursivelyTraverseReappearLayoutEffects( - finishedRoot, - finishedWork, - includeWorkInProgressEffects - ); // TODO: Check flags & LayoutStatic - - commitHookLayoutEffects(finishedWork, Layout); - break; + 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); } - case ClassComponent: { - recursivelyTraverseReappearLayoutEffects( - finishedRoot, - finishedWork, - includeWorkInProgressEffects - ); // TODO: Check for LayoutStatic flag + commitReconciliationEffects(finishedWork); + var offscreenInstance = finishedWork.stateNode; // TODO: Add explicit effect flag to set _current. + + offscreenInstance._current = finishedWork; // Offscreen stores pending changes to visibility in `_pendingVisibility`. This is + // to support batching of `attach` and `detach` calls. - var instance = finishedWork.stateNode; + offscreenInstance._visibility &= ~OffscreenDetached; + offscreenInstance._visibility |= offscreenInstance._pendingVisibility & OffscreenDetached; - if (typeof instance.componentDidMount === "function") { - try { - instance.componentDidMount(); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); + 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 (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 (isUpdate && !wasHidden && !wasHiddenByAncestorOffscreen) { + if ((finishedWork.mode & ConcurrentMode) !== NoMode) { + // Disappear the layout effects of all the children + recursivelyTraverseDisappearLayoutEffects(finishedWork); + } } - } // Commit any callbacks that would have fired while the component - // was hidden. + } // Offscreen with manual mode manages visibility manually. - var updateQueue = finishedWork.updateQueue; - if (updateQueue !== null) { - commitHiddenCallbacks(updateQueue, instance); - } // If this is newly finished work, check for setState callbacks + if (!isOffscreenManual(finishedWork)) { + // TODO: This needs to run whenever there's an insertion or update + // inside a hidden Offscreen tree. + hideOrUnhideAllChildren(finishedWork, isHidden); + } + } // TODO: Move to passive phase - 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: { - // ... - // } + if (flags & Update) { + var offscreenQueue = finishedWork.updateQueue; - 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. - - if ( - includeWorkInProgressEffects && - current === null && - flags & Update - ) { - commitHostComponentMount(finishedWork); - } // TODO: Check flags & Ref + if (offscreenQueue !== null) { + var _retryQueue = offscreenQueue.retryQueue; - safelyAttachRef(finishedWork, finishedWork.return); - break; + if (_retryQueue !== null) { + offscreenQueue.retryQueue = null; + attachSuspenseRetryListeners(finishedWork, _retryQueue); + } + } } - case Profiler: { - recursivelyTraverseReappearLayoutEffects( - finishedRoot, - finishedWork, - includeWorkInProgressEffects - ); // TODO: Figure out how Profiler updates should work with Offscreen - - if (includeWorkInProgressEffects && flags & Update) { - commitProfilerUpdate(finishedWork, current); - } + return; + } - break; - } + case SuspenseListComponent: + { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); - case SuspenseComponent: { - recursivelyTraverseReappearLayoutEffects( - finishedRoot, - finishedWork, - includeWorkInProgressEffects - ); // TODO: Figure out how Suspense hydration callbacks should work + if (flags & Update) { + var _retryQueue2 = finishedWork.updateQueue; - break; + if (_retryQueue2 !== null) { + finishedWork.updateQueue = null; + attachSuspenseRetryListeners(finishedWork, _retryQueue2); + } } - case OffscreenComponent: { - var offscreenState = finishedWork.memoizedState; - var isHidden = offscreenState !== null; + return; + } - if (isHidden); - else { - recursivelyTraverseReappearLayoutEffects( - finishedRoot, - finishedWork, - includeWorkInProgressEffects - ); - } // TODO: Check flags & Ref + case ScopeComponent: + { - safelyAttachRef(finishedWork, finishedWork.return); - break; - } + return; + } - default: { - recursivelyTraverseReappearLayoutEffects( - finishedRoot, - finishedWork, - includeWorkInProgressEffects - ); - break; - } + default: + { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); + return; } - } + } +} + +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; + + 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. + + + finishedWork.flags &= ~Placement; + } + + if (flags & Hydrating) { + finishedWork.flags &= ~Hydrating; + } +} - 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) +function commitLayoutEffects(finishedWork, root, committedLanes) { + inProgressLanes = committedLanes; + inProgressRoot = root; + var current = finishedWork.alternate; + commitLayoutEffectOnFiber(root, current, finishedWork); + inProgressLanes = null; + inProgressRoot = null; +} - var prevDebugFiber = getCurrentFiber(); - var child = parentFiber.child; +function recursivelyTraverseLayoutEffects(root, parentFiber, lanes) { + var prevDebugFiber = getCurrentFiber(); - while (child !== null) { - var current = child.alternate; - reappearLayoutEffects( - finishedRoot, - current, - child, - childShouldIncludeWorkInProgressEffects - ); - child = child.sibling; - } + if (parentFiber.subtreeFlags & LayoutMask) { + var child = parentFiber.child; - setCurrentFiber(prevDebugFiber); + while (child !== null) { + setCurrentFiber(child); + var current = child.alternate; + commitLayoutEffectOnFiber(root, current, child); + child = child.sibling; } + } - function commitHookPassiveMountEffects(finishedWork, hookFlags) { - if (shouldProfile(finishedWork)) { - startPassiveEffectTimer(); + setCurrentFiber(prevDebugFiber); +} - try { - commitHookEffectListMount(hookFlags, finishedWork); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); +function disappearLayoutEffects(finishedWork) { + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case MemoComponent: + case SimpleMemoComponent: + { + // TODO (Offscreen) Check: flags & LayoutStatic + if (shouldProfile(finishedWork)) { + try { + startLayoutEffectTimer(); + commitHookEffectListUnmount(Layout, finishedWork, finishedWork.return); + } finally { + recordLayoutEffectDuration(finishedWork); + } + } else { + commitHookEffectListUnmount(Layout, finishedWork, finishedWork.return); } - recordPassiveEffectDuration(finishedWork); - } else { - try { - commitHookEffectListMount(hookFlags, finishedWork); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } + recursivelyTraverseDisappearLayoutEffects(finishedWork); + break; } - } - function commitOffscreenPassiveMountEffects( - current, - finishedWork, - instance - ) { + case ClassComponent: { - var previousCache = null; - - if ( - current !== null && - current.memoizedState !== null && - current.memoizedState.cachePool !== null - ) { - previousCache = current.memoizedState.cachePool.pool; - } - - var nextCache = null; - - if ( - finishedWork.memoizedState !== null && - finishedWork.memoizedState.cachePool !== null - ) { - nextCache = finishedWork.memoizedState.cachePool.pool; - } // Retain/release the cache used for pending (suspended) nodes. - // Note that this is only reached in the non-suspended/visible case: - // when the content is suspended/hidden, the retain/release occurs - // via the parent Suspense component (see case above). - - if (nextCache !== previousCache) { - if (nextCache != null) { - retainCache(nextCache); - } + // TODO (Offscreen) Check: flags & RefStatic + safelyDetachRef(finishedWork, finishedWork.return); + var instance = finishedWork.stateNode; - if (previousCache != null) { - releaseCache(previousCache); - } + if (typeof instance.componentWillUnmount === 'function') { + safelyCallComponentWillUnmount(finishedWork, finishedWork.return, instance); } + + recursivelyTraverseDisappearLayoutEffects(finishedWork); + break; + } + + case HostHoistable: + case HostSingleton: + case HostComponent: + { + // TODO (Offscreen) Check: flags & RefStatic + safelyDetachRef(finishedWork, finishedWork.return); + recursivelyTraverseDisappearLayoutEffects(finishedWork); + break; } - } - function commitCachePassiveMountEffect(current, finishedWork) { + case OffscreenComponent: { - var previousCache = null; + // TODO (Offscreen) Check: flags & RefStatic + safelyDetachRef(finishedWork, finishedWork.return); + var isHidden = finishedWork.memoizedState !== null; - if (finishedWork.alternate !== null) { - previousCache = finishedWork.alternate.memoizedState.cache; + if (isHidden) ; else { + recursivelyTraverseDisappearLayoutEffects(finishedWork); } - var nextCache = finishedWork.memoizedState.cache; // Retain/release the cache. In theory the cache component - // could be "borrowing" a cache instance owned by some parent, - // in which case we could avoid retaining/releasing. But it - // is non-trivial to determine when that is the case, so we - // always retain/release. - - if (nextCache !== previousCache) { - retainCache(nextCache); + break; + } - if (previousCache != null) { - releaseCache(previousCache); - } - } + default: + { + recursivelyTraverseDisappearLayoutEffects(finishedWork); + break; } - } + } +} - function commitPassiveMountEffects( - root, - finishedWork, - committedLanes, - committedTransitions - ) { - setCurrentFiber(finishedWork); - commitPassiveMountOnFiber( - root, - finishedWork, - committedLanes, - committedTransitions - ); - resetCurrentFiber(); - } +function recursivelyTraverseDisappearLayoutEffects(parentFiber) { + // TODO (Offscreen) Check: flags & (RefStatic | LayoutStatic) + var child = parentFiber.child; - function recursivelyTraversePassiveMountEffects( - root, - parentFiber, - committedLanes, - committedTransitions - ) { - var prevDebugFiber = getCurrentFiber(); + while (child !== null) { + disappearLayoutEffects(child); + child = child.sibling; + } +} - if (parentFiber.subtreeFlags & PassiveMask) { - var child = parentFiber.child; +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; - while (child !== null) { - setCurrentFiber(child); - commitPassiveMountOnFiber( - root, - child, - committedLanes, - committedTransitions - ); - child = child.sibling; - } + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: + { + recursivelyTraverseReappearLayoutEffects(finishedRoot, finishedWork, includeWorkInProgressEffects); // TODO: Check flags & LayoutStatic + + commitHookLayoutEffects(finishedWork, Layout); + break; } - setCurrentFiber(prevDebugFiber); - } + case ClassComponent: + { + recursivelyTraverseReappearLayoutEffects(finishedRoot, finishedWork, includeWorkInProgressEffects); // TODO: Check for LayoutStatic flag - 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; + var instance = finishedWork.stateNode; - switch (finishedWork.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - recursivelyTraversePassiveMountEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions - ); - - if (flags & Passive$1) { - commitHookPassiveMountEffects(finishedWork, Passive | HasEffect); + 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. - break; - } - case HostRoot: { - recursivelyTraversePassiveMountEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions - ); + var updateQueue = finishedWork.updateQueue; - if (flags & Passive$1) { - { - var previousCache = null; + if (updateQueue !== null) { + commitHiddenCallbacks(updateQueue, instance); + } // If this is newly finished work, check for setState callbacks - if (finishedWork.alternate !== null) { - previousCache = finishedWork.alternate.memoizedState.cache; - } - var nextCache = finishedWork.memoizedState.cache; // Retain/release the root cache. - // Note that on initial mount, previousCache and nextCache will be the same - // and this retain won't occur. To counter this, we instead retain the HostRoot's - // initial cache when creating the root itself (see createFiberRoot() in - // ReactFiberRoot.js). Subsequent updates that change the cache are reflected - // here, such that previous/next caches are retained correctly. + if (includeWorkInProgressEffects && flags & Callback) { + commitClassCallbacks(finishedWork); + } // TODO: Check flags & RefStatic - if (nextCache !== previousCache) { - retainCache(nextCache); - if (previousCache != null) { - releaseCache(previousCache); - } - } - } - } + 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: { + // ... + // } - break; - } + 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. - case LegacyHiddenComponent: { - break; - } + if (includeWorkInProgressEffects && current === null && flags & Update) { + commitHostComponentMount(finishedWork); + } // TODO: Check flags & Ref - case OffscreenComponent: { - // TODO: Pass `current` as argument to this function - var _instance3 = finishedWork.stateNode; - var nextState = finishedWork.memoizedState; - var isHidden = nextState !== null; - if (isHidden) { - if (_instance3._visibility & OffscreenPassiveEffectsConnected) { - // The effects are currently connected. Update them. - recursivelyTraversePassiveMountEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions - ); - } else { - if (finishedWork.mode & ConcurrentMode) { - // The effects are currently disconnected. Since the tree is hidden, - // don't connect them. This also applies to the initial render. - { - // "Atomic" effects are ones that need to fire on every commit, - // even during pre-rendering. An example is updating the reference - // count on cache instances. - recursivelyTraverseAtomicPassiveEffects( - finishedRoot, - finishedWork - ); - } - } else { - // Legacy Mode: Fire the effects even if the tree is hidden. - _instance3._visibility |= OffscreenPassiveEffectsConnected; - recursivelyTraversePassiveMountEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions - ); - } - } - } else { - // Tree is visible - if (_instance3._visibility & OffscreenPassiveEffectsConnected) { - // The effects are currently connected. Update them. - recursivelyTraversePassiveMountEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions - ); - } 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; - var includeWorkInProgressEffects = - (finishedWork.subtreeFlags & PassiveMask) !== NoFlags$1; - recursivelyTraverseReconnectPassiveEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions, - includeWorkInProgressEffects - ); - } - } + safelyAttachRef(finishedWork, finishedWork.return); + break; + } - if (flags & Passive$1) { - var _current = finishedWork.alternate; - commitOffscreenPassiveMountEffects(_current, finishedWork); - } + case Profiler: + { + recursivelyTraverseReappearLayoutEffects(finishedRoot, finishedWork, includeWorkInProgressEffects); // TODO: Figure out how Profiler updates should work with Offscreen - break; + if (includeWorkInProgressEffects && flags & Update) { + commitProfilerUpdate(finishedWork, current); } - case CacheComponent: { - recursivelyTraversePassiveMountEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions - ); + break; + } - if (flags & Passive$1) { - // TODO: Pass `current` as argument to this function - var _current2 = finishedWork.alternate; - commitCachePassiveMountEffect(_current2, finishedWork); - } + case SuspenseComponent: + { + recursivelyTraverseReappearLayoutEffects(finishedRoot, finishedWork, includeWorkInProgressEffects); // TODO: Figure out how Suspense hydration callbacks should work - break; - } + break; + } - case TracingMarkerComponent: + case OffscreenComponent: + { + var offscreenState = finishedWork.memoizedState; + var isHidden = offscreenState !== null; - default: { - recursivelyTraversePassiveMountEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions - ); - break; - } - } - } + if (isHidden) ; else { + recursivelyTraverseReappearLayoutEffects(finishedRoot, finishedWork, includeWorkInProgressEffects); + } // TODO: Check flags & Ref - function recursivelyTraverseReconnectPassiveEffects( - finishedRoot, - parentFiber, - committedLanes, - committedTransitions, - 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 & PassiveMask) !== NoFlags$1; // TODO (Offscreen) Check: flags & (RefStatic | LayoutStatic) - var prevDebugFiber = getCurrentFiber(); - var child = parentFiber.child; + safelyAttachRef(finishedWork, finishedWork.return); + break; + } - while (child !== null) { - reconnectPassiveEffects( - finishedRoot, - child, - committedLanes, - committedTransitions, - childShouldIncludeWorkInProgressEffects - ); - child = child.sibling; + default: + { + recursivelyTraverseReappearLayoutEffects(finishedRoot, finishedWork, includeWorkInProgressEffects); + break; } + } +} - setCurrentFiber(prevDebugFiber); - } +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) - 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 - ) { - var flags = finishedWork.flags; + var prevDebugFiber = getCurrentFiber(); + var child = parentFiber.child; - switch (finishedWork.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - recursivelyTraverseReconnectPassiveEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions, - includeWorkInProgressEffects - ); // TODO: Check for PassiveStatic flag - - 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: { - // ... - // } + while (child !== null) { + var current = child.alternate; + reappearLayoutEffects(finishedRoot, current, child, childShouldIncludeWorkInProgressEffects); + child = child.sibling; + } - case LegacyHiddenComponent: { - break; - } + setCurrentFiber(prevDebugFiber); +} - case OffscreenComponent: { - var _instance4 = finishedWork.stateNode; - var nextState = finishedWork.memoizedState; - var isHidden = nextState !== null; +function commitHookPassiveMountEffects(finishedWork, hookFlags) { + if (shouldProfile(finishedWork)) { + startPassiveEffectTimer(); - if (isHidden) { - if (_instance4._visibility & OffscreenPassiveEffectsConnected) { - // The effects are currently connected. Update them. - recursivelyTraverseReconnectPassiveEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions, - includeWorkInProgressEffects - ); - } else { - if (finishedWork.mode & ConcurrentMode) { - // The effects are currently disconnected. Since the tree is hidden, - // don't connect them. This also applies to the initial render. - { - // "Atomic" effects are ones that need to fire on every commit, - // even during pre-rendering. An example is updating the reference - // count on cache instances. - recursivelyTraverseAtomicPassiveEffects( - finishedRoot, - finishedWork - ); - } - } else { - // Legacy Mode: Fire the effects even if the tree is hidden. - _instance4._visibility |= OffscreenPassiveEffectsConnected; - recursivelyTraverseReconnectPassiveEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions, - includeWorkInProgressEffects - ); - } - } - } 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, - committedLanes, - committedTransitions, - includeWorkInProgressEffects - ); - } + try { + commitHookEffectListMount(hookFlags, finishedWork); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } - if (includeWorkInProgressEffects && flags & Passive$1) { - // TODO: Pass `current` as argument to this function - var _current3 = finishedWork.alternate; - commitOffscreenPassiveMountEffects(_current3, finishedWork); - } + recordPassiveEffectDuration(finishedWork); + } else { + try { + commitHookEffectListMount(hookFlags, finishedWork); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } + } +} - break; - } +function commitOffscreenPassiveMountEffects(current, finishedWork, instance) { + { + var previousCache = null; - case CacheComponent: { - recursivelyTraverseReconnectPassiveEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions, - includeWorkInProgressEffects - ); + if (current !== null && current.memoizedState !== null && current.memoizedState.cachePool !== null) { + previousCache = current.memoizedState.cachePool.pool; + } - if (includeWorkInProgressEffects && flags & Passive$1) { - // TODO: Pass `current` as argument to this function - var _current4 = finishedWork.alternate; - commitCachePassiveMountEffect(_current4, finishedWork); - } + var nextCache = null; - break; - } + if (finishedWork.memoizedState !== null && finishedWork.memoizedState.cachePool !== null) { + nextCache = finishedWork.memoizedState.cachePool.pool; + } // Retain/release the cache used for pending (suspended) nodes. + // Note that this is only reached in the non-suspended/visible case: + // when the content is suspended/hidden, the retain/release occurs + // via the parent Suspense component (see case above). - case TracingMarkerComponent: - default: { - recursivelyTraverseReconnectPassiveEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions, - includeWorkInProgressEffects - ); - break; - } + if (nextCache !== previousCache) { + if (nextCache != null) { + retainCache(nextCache); } - } - - function recursivelyTraverseAtomicPassiveEffects( - finishedRoot, - parentFiber, - committedLanes, - committedTransitions - ) { - // "Atomic" effects are ones that need to fire on every commit, even during - // pre-rendering. We call this function when traversing a hidden tree whose - // regular effects are currently disconnected. - var prevDebugFiber = getCurrentFiber(); // TODO: Add special flag for atomic effects - - if (parentFiber.subtreeFlags & PassiveMask) { - var child = parentFiber.child; - while (child !== null) { - setCurrentFiber(child); - commitAtomicPassiveEffects(finishedRoot, child); - child = child.sibling; - } + if (previousCache != null) { + releaseCache(previousCache); } - - setCurrentFiber(prevDebugFiber); } + } +} - function commitAtomicPassiveEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions - ) { - // "Atomic" effects are ones that need to fire on every commit, even during - // pre-rendering. We call this function when traversing a hidden tree whose - // regular effects are currently disconnected. - var flags = finishedWork.flags; +function commitCachePassiveMountEffect(current, finishedWork) { + { + var previousCache = null; - switch (finishedWork.tag) { - case OffscreenComponent: { - recursivelyTraverseAtomicPassiveEffects(finishedRoot, finishedWork); + if (finishedWork.alternate !== null) { + previousCache = finishedWork.alternate.memoizedState.cache; + } - if (flags & Passive$1) { - // TODO: Pass `current` as argument to this function - var current = finishedWork.alternate; - commitOffscreenPassiveMountEffects(current, finishedWork); - } + var nextCache = finishedWork.memoizedState.cache; // Retain/release the cache. In theory the cache component + // could be "borrowing" a cache instance owned by some parent, + // in which case we could avoid retaining/releasing. But it + // is non-trivial to determine when that is the case, so we + // always retain/release. - break; - } + if (nextCache !== previousCache) { + retainCache(nextCache); - case CacheComponent: { - recursivelyTraverseAtomicPassiveEffects(finishedRoot, finishedWork); + if (previousCache != null) { + releaseCache(previousCache); + } + } + } +} - if (flags & Passive$1) { - // TODO: Pass `current` as argument to this function - var _current5 = finishedWork.alternate; - commitCachePassiveMountEffect(_current5, finishedWork); - } +function commitPassiveMountEffects(root, finishedWork, committedLanes, committedTransitions) { + setCurrentFiber(finishedWork); + commitPassiveMountOnFiber(root, finishedWork, committedLanes, committedTransitions); + resetCurrentFiber(); +} - break; - } +function recursivelyTraversePassiveMountEffects(root, parentFiber, committedLanes, committedTransitions) { + var prevDebugFiber = getCurrentFiber(); - default: { - recursivelyTraverseAtomicPassiveEffects(finishedRoot, finishedWork); - break; - } - } + if (parentFiber.subtreeFlags & PassiveMask) { + var child = parentFiber.child; + + while (child !== null) { + setCurrentFiber(child); + commitPassiveMountOnFiber(root, child, committedLanes, committedTransitions); + child = child.sibling; } + } - function commitPassiveUnmountEffects(finishedWork) { - setCurrentFiber(finishedWork); - commitPassiveUnmountOnFiber(finishedWork); - resetCurrentFiber(); - } // If we're inside a brand new tree, or a tree that was already visible, then we - // should only suspend host components that have a ShouldSuspendCommit flag. - // Components without it haven't changed since the last commit, so we can skip - // over those. - // - // When we enter a tree that is being revealed (going from hidden -> visible), - // we need to suspend _any_ component that _may_ suspend. Even if they're - // already in the "current" tree. Because their visibility has changed, the - // browser may not have prerendered them yet. So we check the MaySuspendCommit - // flag instead. + setCurrentFiber(prevDebugFiber); +} - var suspenseyCommitFlag = ShouldSuspendCommit; - function accumulateSuspenseyCommit(finishedWork) { - accumulateSuspenseyCommitOnFiber(finishedWork); - } +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 recursivelyAccumulateSuspenseyCommit(parentFiber) { - if (parentFiber.subtreeFlags & suspenseyCommitFlag) { - var child = parentFiber.child; + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: + { + recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork, committedLanes, committedTransitions); - while (child !== null) { - accumulateSuspenseyCommitOnFiber(child); - child = child.sibling; + if (flags & Passive$1) { + commitHookPassiveMountEffects(finishedWork, Passive | HasEffect); } + + break; } - } - function accumulateSuspenseyCommitOnFiber(fiber) { - switch (fiber.tag) { - case HostHoistable: { - recursivelyAccumulateSuspenseyCommit(fiber); + case HostRoot: + { + recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork, committedLanes, committedTransitions); + + if (flags & Passive$1) { + { + var previousCache = null; - if (fiber.flags & suspenseyCommitFlag) { - if (fiber.memoizedState !== null) { - suspendResource(); + if (finishedWork.alternate !== null) { + previousCache = finishedWork.alternate.memoizedState.cache; } - } - break; - } + var nextCache = finishedWork.memoizedState.cache; // Retain/release the root cache. + // Note that on initial mount, previousCache and nextCache will be the same + // and this retain won't occur. To counter this, we instead retain the HostRoot's + // initial cache when creating the root itself (see createFiberRoot() in + // ReactFiberRoot.js). Subsequent updates that change the cache are reflected + // here, such that previous/next caches are retained correctly. - case HostComponent: { - recursivelyAccumulateSuspenseyCommit(fiber); + if (nextCache !== previousCache) { + retainCache(nextCache); - break; + if (previousCache != null) { + releaseCache(previousCache); + } + } + } } - case HostRoot: - case HostPortal: { - { - recursivelyAccumulateSuspenseyCommit(fiber); - } + break; + } - break; - } + case LegacyHiddenComponent: + { - case OffscreenComponent: { - var isHidden = fiber.memoizedState !== null; + break; + } - if (isHidden); - else { - var current = fiber.alternate; - var wasHidden = current !== null && current.memoizedState !== null; + case OffscreenComponent: + { + // TODO: Pass `current` as argument to this function + var _instance3 = finishedWork.stateNode; + var nextState = finishedWork.memoizedState; + var isHidden = nextState !== null; - if (wasHidden) { - // This tree is being revealed. Visit all newly visible suspensey - // instances, even if they're in the current tree. - var prevFlags = suspenseyCommitFlag; - suspenseyCommitFlag = MaySuspendCommit; - recursivelyAccumulateSuspenseyCommit(fiber); - suspenseyCommitFlag = prevFlags; + if (isHidden) { + if (_instance3._visibility & OffscreenPassiveEffectsConnected) { + // The effects are currently connected. Update them. + recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork, committedLanes, committedTransitions); + } else { + if (finishedWork.mode & ConcurrentMode) { + // The effects are currently disconnected. Since the tree is hidden, + // don't connect them. This also applies to the initial render. + { + // "Atomic" effects are ones that need to fire on every commit, + // even during pre-rendering. An example is updating the reference + // count on cache instances. + recursivelyTraverseAtomicPassiveEffects(finishedRoot, finishedWork); + } } else { - recursivelyAccumulateSuspenseyCommit(fiber); + // Legacy Mode: Fire the effects even if the tree is hidden. + _instance3._visibility |= OffscreenPassiveEffectsConnected; + recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork, committedLanes, committedTransitions); } } - - break; + } else { + // Tree is visible + if (_instance3._visibility & OffscreenPassiveEffectsConnected) { + // The effects are currently connected. Update them. + recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork, committedLanes, committedTransitions); + } 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; + var includeWorkInProgressEffects = (finishedWork.subtreeFlags & PassiveMask) !== NoFlags$1; + recursivelyTraverseReconnectPassiveEffects(finishedRoot, finishedWork, committedLanes, committedTransitions, includeWorkInProgressEffects); + } } - default: { - recursivelyAccumulateSuspenseyCommit(fiber); + if (flags & Passive$1) { + var _current = finishedWork.alternate; + commitOffscreenPassiveMountEffects(_current, finishedWork); } - } - } - - 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; + break; + } - do { - // $FlowFixMe[incompatible-use] found when upgrading Flow - var detachedSibling = detachedChild.sibling; // $FlowFixMe[incompatible-use] found when upgrading Flow + case CacheComponent: + { + recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork, committedLanes, committedTransitions); - detachedChild.sibling = null; - detachedChild = detachedSibling; - } while (detachedChild !== null); + if (flags & Passive$1) { + // TODO: Pass `current` as argument to this function + var _current2 = finishedWork.alternate; + commitCachePassiveMountEffect(_current2, finishedWork); } + + break; } - } - function commitHookPassiveUnmountEffects( - finishedWork, - nearestMountedAncestor, - hookFlags - ) { - if (shouldProfile(finishedWork)) { - startPassiveEffectTimer(); - commitHookEffectListUnmount( - hookFlags, - finishedWork, - nearestMountedAncestor - ); - recordPassiveEffectDuration(finishedWork); - } else { - commitHookEffectListUnmount( - hookFlags, - finishedWork, - nearestMountedAncestor - ); + case TracingMarkerComponent: + + default: + { + recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork, committedLanes, committedTransitions); + break; } - } + } +} - 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; +function recursivelyTraverseReconnectPassiveEffects(finishedRoot, parentFiber, committedLanes, committedTransitions, 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 & PassiveMask) !== NoFlags$1; // TODO (Offscreen) Check: flags & (RefStatic | LayoutStatic) - 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 prevDebugFiber = getCurrentFiber(); + var child = parentFiber.child; - nextEffect = childToDelete; - commitPassiveUnmountEffectsInsideOfDeletedTree_begin( - childToDelete, - parentFiber - ); - } - } + while (child !== null) { + reconnectPassiveEffects(finishedRoot, child, committedLanes, committedTransitions, childShouldIncludeWorkInProgressEffects); + child = child.sibling; + } - detachAlternateSiblings(parentFiber); - } + setCurrentFiber(prevDebugFiber); +} - var prevDebugFiber = getCurrentFiber(); // TODO: Split PassiveMask into separate masks for mount and unmount? +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) { + var flags = finishedWork.flags; - if (parentFiber.subtreeFlags & PassiveMask) { - var child = parentFiber.child; + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: + { + recursivelyTraverseReconnectPassiveEffects(finishedRoot, finishedWork, committedLanes, committedTransitions, includeWorkInProgressEffects); // TODO: Check for PassiveStatic flag - while (child !== null) { - setCurrentFiber(child); - commitPassiveUnmountOnFiber(child); - child = child.sibling; - } + 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: { + // ... + // } - setCurrentFiber(prevDebugFiber); - } - - function commitPassiveUnmountOnFiber(finishedWork) { - switch (finishedWork.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - recursivelyTraversePassiveUnmountEffects(finishedWork); + case LegacyHiddenComponent: + { - if (finishedWork.flags & Passive$1) { - commitHookPassiveUnmountEffects( - finishedWork, - finishedWork.return, - Passive | HasEffect - ); - } + break; + } - break; - } + case OffscreenComponent: + { + var _instance4 = finishedWork.stateNode; + var nextState = finishedWork.memoizedState; + var isHidden = nextState !== null; - case OffscreenComponent: { - var instance = finishedWork.stateNode; - var nextState = finishedWork.memoizedState; - var isHidden = nextState !== null; - - 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); + if (isHidden) { + if (_instance4._visibility & OffscreenPassiveEffectsConnected) { + // The effects are currently connected. Update them. + recursivelyTraverseReconnectPassiveEffects(finishedRoot, finishedWork, committedLanes, committedTransitions, includeWorkInProgressEffects); } else { - recursivelyTraversePassiveUnmountEffects(finishedWork); + if (finishedWork.mode & ConcurrentMode) { + // The effects are currently disconnected. Since the tree is hidden, + // don't connect them. This also applies to the initial render. + { + // "Atomic" effects are ones that need to fire on every commit, + // even during pre-rendering. An example is updating the reference + // count on cache instances. + recursivelyTraverseAtomicPassiveEffects(finishedRoot, finishedWork); + } + } else { + // Legacy Mode: Fire the effects even if the tree is hidden. + _instance4._visibility |= OffscreenPassiveEffectsConnected; + recursivelyTraverseReconnectPassiveEffects(finishedRoot, finishedWork, committedLanes, committedTransitions, includeWorkInProgressEffects); + } } - - break; + } 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, committedLanes, committedTransitions, includeWorkInProgressEffects); } - default: { - recursivelyTraversePassiveUnmountEffects(finishedWork); - break; + if (includeWorkInProgressEffects && flags & Passive$1) { + // TODO: Pass `current` as argument to this function + var _current3 = finishedWork.alternate; + commitOffscreenPassiveMountEffects(_current3, finishedWork); } - } - } - 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; + break; + } - 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 + case CacheComponent: + { + recursivelyTraverseReconnectPassiveEffects(finishedRoot, finishedWork, committedLanes, committedTransitions, includeWorkInProgressEffects); - nextEffect = childToDelete; - commitPassiveUnmountEffectsInsideOfDeletedTree_begin( - childToDelete, - parentFiber - ); - } + if (includeWorkInProgressEffects && flags & Passive$1) { + // TODO: Pass `current` as argument to this function + var _current4 = finishedWork.alternate; + commitCachePassiveMountEffect(_current4, finishedWork); } - detachAlternateSiblings(parentFiber); + break; } - var prevDebugFiber = getCurrentFiber(); // TODO: Check PassiveStatic flag + case TracingMarkerComponent: - var child = parentFiber.child; - - while (child !== null) { - setCurrentFiber(child); - disconnectPassiveEffect(child); - child = child.sibling; + default: + { + recursivelyTraverseReconnectPassiveEffects(finishedRoot, finishedWork, committedLanes, committedTransitions, includeWorkInProgressEffects); + break; } + } +} - setCurrentFiber(prevDebugFiber); - } +function recursivelyTraverseAtomicPassiveEffects(finishedRoot, parentFiber, committedLanes, committedTransitions) { + // "Atomic" effects are ones that need to fire on every commit, even during + // pre-rendering. We call this function when traversing a hidden tree whose + // regular effects are currently disconnected. + var prevDebugFiber = getCurrentFiber(); // TODO: Add special flag for atomic effects - 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 (parentFiber.subtreeFlags & PassiveMask) { + var child = parentFiber.child; - recursivelyTraverseDisconnectPassiveEffects(finishedWork); - break; - } + while (child !== null) { + setCurrentFiber(child); + commitAtomicPassiveEffects(finishedRoot, child); + child = child.sibling; + } + } - case OffscreenComponent: { - var instance = finishedWork.stateNode; + setCurrentFiber(prevDebugFiber); +} - if (instance._visibility & OffscreenPassiveEffectsConnected) { - instance._visibility &= ~OffscreenPassiveEffectsConnected; - recursivelyTraverseDisconnectPassiveEffects(finishedWork); - } +function commitAtomicPassiveEffects(finishedRoot, finishedWork, committedLanes, committedTransitions) { + // "Atomic" effects are ones that need to fire on every commit, even during + // pre-rendering. We call this function when traversing a hidden tree whose + // regular effects are currently disconnected. + var flags = finishedWork.flags; - break; - } + switch (finishedWork.tag) { + case OffscreenComponent: + { + recursivelyTraverseAtomicPassiveEffects(finishedRoot, finishedWork); - default: { - recursivelyTraverseDisconnectPassiveEffects(finishedWork); - break; + if (flags & Passive$1) { + // TODO: Pass `current` as argument to this function + var current = finishedWork.alternate; + commitOffscreenPassiveMountEffects(current, 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 + break; + } - setCurrentFiber(fiber); - commitPassiveUnmountInsideDeletedTreeOnFiber( - fiber, - nearestMountedAncestor - ); - resetCurrentFiber(); - var child = fiber.child; // TODO: Only traverse subtree if it has a PassiveStatic flag. + case CacheComponent: + { + recursivelyTraverseAtomicPassiveEffects(finishedRoot, finishedWork); - if (child !== null) { - child.return = fiber; - nextEffect = child; - } else { - commitPassiveUnmountEffectsInsideOfDeletedTree_complete( - deletedSubtreeRoot - ); + if (flags & Passive$1) { + // TODO: Pass `current` as argument to this function + var _current5 = finishedWork.alternate; + commitCachePassiveMountEffect(_current5, finishedWork); } - } - } - 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. + break; + } - detachFiberAfterEffects(fiber); + default: + { + recursivelyTraverseAtomicPassiveEffects(finishedRoot, finishedWork); + break; + } + } +} - if (fiber === deletedSubtreeRoot) { - nextEffect = null; - return; - } +function commitPassiveUnmountEffects(finishedWork) { + setCurrentFiber(finishedWork); + commitPassiveUnmountOnFiber(finishedWork); + resetCurrentFiber(); +} // If we're inside a brand new tree, or a tree that was already visible, then we +// should only suspend host components that have a ShouldSuspendCommit flag. +// Components without it haven't changed since the last commit, so we can skip +// over those. +// +// When we enter a tree that is being revealed (going from hidden -> visible), +// we need to suspend _any_ component that _may_ suspend. Even if they're +// already in the "current" tree. Because their visibility has changed, the +// browser may not have prerendered them yet. So we check the MaySuspendCommit +// flag instead. + +var suspenseyCommitFlag = ShouldSuspendCommit; +function accumulateSuspenseyCommit(finishedWork) { + accumulateSuspenseyCommitOnFiber(finishedWork); +} - if (sibling !== null) { - sibling.return = returnFiber; - nextEffect = sibling; - return; - } +function recursivelyAccumulateSuspenseyCommit(parentFiber) { + if (parentFiber.subtreeFlags & suspenseyCommitFlag) { + var child = parentFiber.child; - nextEffect = returnFiber; - } + while (child !== null) { + accumulateSuspenseyCommitOnFiber(child); + child = child.sibling; } + } +} - function commitPassiveUnmountInsideDeletedTreeOnFiber( - current, - nearestMountedAncestor - ) { - switch (current.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - commitHookPassiveUnmountEffects( - current, - nearestMountedAncestor, - Passive - ); - break; - } - // TODO: run passive unmount effects when unmounting a root. - // Because passive unmount effects are not currently run, - // the cache instance owned by the root will never be freed. - // When effects are run, the cache should be freed here: - // case HostRoot: { - // if (enableCache) { - // const cache = current.memoizedState.cache; - // releaseCache(cache); - // } - // break; - // } - - case LegacyHiddenComponent: - case OffscreenComponent: { - { - if ( - current.memoizedState !== null && - current.memoizedState.cachePool !== null - ) { - var cache = current.memoizedState.cachePool.pool; // Retain/release the cache used for pending (suspended) nodes. - // Note that this is only reached in the non-suspended/visible case: - // when the content is suspended/hidden, the retain/release occurs - // via the parent Suspense component (see case above). - - if (cache != null) { - retainCache(cache); - } - } - } +function accumulateSuspenseyCommitOnFiber(fiber) { + switch (fiber.tag) { + case HostHoistable: + { + recursivelyAccumulateSuspenseyCommit(fiber); - break; + if (fiber.flags & suspenseyCommitFlag) { + if (fiber.memoizedState !== null) { + suspendResource(); + } } - case SuspenseComponent: { - break; - } + break; + } - case CacheComponent: { - { - var _cache = current.memoizedState.cache; - releaseCache(_cache); - } + case HostComponent: + { + recursivelyAccumulateSuspenseyCommit(fiber); - break; - } + break; } - } - function invokeLayoutEffectMountInDEV(fiber) { + case HostRoot: + case HostPortal: { - // 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); - } + { + recursivelyAccumulateSuspenseyCommit(fiber); + } - break; - } + break; + } - case ClassComponent: { - var instance = fiber.stateNode; + case OffscreenComponent: + { + var isHidden = fiber.memoizedState !== null; - if (typeof instance.componentDidMount === "function") { - try { - instance.componentDidMount(); - } catch (error) { - captureCommitPhaseError(fiber, fiber.return, error); - } - } + if (isHidden) ; else { + var current = fiber.alternate; + var wasHidden = current !== null && current.memoizedState !== null; - break; + if (wasHidden) { + // This tree is being revealed. Visit all newly visible suspensey + // instances, even if they're in the current tree. + var prevFlags = suspenseyCommitFlag; + suspenseyCommitFlag = MaySuspendCommit; + recursivelyAccumulateSuspenseyCommit(fiber); + suspenseyCommitFlag = prevFlags; + } else { + recursivelyAccumulateSuspenseyCommit(fiber); } } + + break; } - } - function invokePassiveEffectMountInDEV(fiber) { + default: { - // 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; - } - } + recursivelyAccumulateSuspenseyCommit(fiber); } - } + } +} - 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); - } +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; - break; - } + do { + // $FlowFixMe[incompatible-use] found when upgrading Flow + var detachedSibling = detachedChild.sibling; // $FlowFixMe[incompatible-use] found when upgrading Flow - case ClassComponent: { - var instance = fiber.stateNode; + detachedChild.sibling = null; + detachedChild = detachedSibling; + } while (detachedChild !== null); + } + } +} - if (typeof instance.componentWillUnmount === "function") { - safelyCallComponentWillUnmount(fiber, fiber.return, instance); - } +function commitHookPassiveUnmountEffects(finishedWork, nearestMountedAncestor, hookFlags) { + if (shouldProfile(finishedWork)) { + startPassiveEffectTimer(); + commitHookEffectListUnmount(hookFlags, finishedWork, nearestMountedAncestor); + recordPassiveEffectDuration(finishedWork); + } else { + commitHookEffectListUnmount(hookFlags, finishedWork, nearestMountedAncestor); + } +} - break; - } - } +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 ((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); } } - function invokePassiveEffectUnmountInDEV(fiber) { + detachAlternateSiblings(parentFiber); + } + + var prevDebugFiber = getCurrentFiber(); // TODO: Split PassiveMask into separate masks for mount and unmount? + + if (parentFiber.subtreeFlags & PassiveMask) { + var child = parentFiber.child; + + while (child !== null) { + setCurrentFiber(child); + commitPassiveUnmountOnFiber(child); + child = child.sibling; + } + } + + setCurrentFiber(prevDebugFiber); +} + +function commitPassiveUnmountOnFiber(finishedWork) { + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: { - // 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); - } - } + recursivelyTraversePassiveUnmountEffects(finishedWork); + + if (finishedWork.flags & Passive$1) { + commitHookPassiveUnmountEffects(finishedWork, finishedWork.return, Passive | HasEffect); } + + break; } - } - function getCacheForType(resourceType) { - var cache = readContext(CacheContext); - var cacheForType = cache.data.get(resourceType); + case OffscreenComponent: + { + var instance = finishedWork.stateNode; + var nextState = finishedWork.memoizedState; + var isHidden = nextState !== null; + + 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 (cacheForType === undefined) { - cacheForType = resourceType(); - cache.data.set(resourceType, cacheForType); + break; } - return cacheForType; - } - - var DefaultCacheDispatcher = { - getCacheForType: getCacheForType - }; + default: + { + recursivelyTraversePassiveUnmountEffects(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 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 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. - 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; // $FlowFixMe[cannot-resolve-name] - Flow doesn't know about jest + 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 jestIsDefined = typeof jest !== "undefined"; - return jestIsDefined && isReactActEnvironmentGlobal !== false; + nextEffect = childToDelete; + commitPassiveUnmountEffectsInsideOfDeletedTree_begin(childToDelete, parentFiber); } } - 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 && - ReactSharedInternals.actQueue !== null - ) { - // TODO: Include link to relevant documentation page. - error( - "The current testing environment is not configured to support " + - "act(...)" - ); - } - - return isReactActEnvironmentGlobal; - } - } - - var PossiblyWeakMap = typeof WeakMap === "function" ? WeakMap : Map; - 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 executionContext = NoContext; // The root we're working on - - var workInProgressRoot = null; // The fiber we're working on - - var workInProgress = null; // The lanes we're rendering - - 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 entangledRenderLanes. - var entangledRenderLanes = NoLanes; // Whether to root completed, errored, suspended, etc. + detachAlternateSiblings(parentFiber); + } - var workInProgressRootExitStatus = RootInProgress; // The work left over by components that were visited during this render. Only - // includes unprocessed updates, not work in bailed out children. + var prevDebugFiber = getCurrentFiber(); // TODO: Check PassiveStatic flag - var workInProgressRootSkippedLanes = NoLanes; // Lanes that were updated (in an interleaved event) during this render. + var child = parentFiber.child; - var workInProgressRootInterleavedUpdatedLanes = NoLanes; // Lanes that were updated during the render phase (*not* an interleaved event). + while (child !== null) { + setCurrentFiber(child); + disconnectPassiveEffect(child); + child = child.sibling; + } - var workInProgressRootPingedLanes = NoLanes; // If this lane scheduled deferred work, this is the lane of the deferred task. + setCurrentFiber(prevDebugFiber); +} - var workInProgressDeferredLane = NoLane; // Errors that are thrown during the render phase. +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 workInProgressRootConcurrentErrors = null; // These are errors that we recovered from without surfacing them to the UI. - // We will log them once the tree commits. + recursivelyTraverseDisconnectPassiveEffects(finishedWork); + break; + } - var workInProgressRootRecoverableErrors = null; // Tracks when an update occurs during the render phase. + case OffscreenComponent: + { + var instance = finishedWork.stateNode; - var workInProgressRootDidIncludeRecursiveRenderUpdate = false; // Thacks when an update occurs during the commit phase. It's a separate - // variable from the one for renders because the commit phase may run - // concurrently to a render phase. + if (instance._visibility & OffscreenPassiveEffectsConnected) { + instance._visibility &= ~OffscreenPassiveEffectsConnected; + recursivelyTraverseDisconnectPassiveEffects(finishedWork); + } - var didIncludeCommitPhaseUpdate = false; // The most recent time we either committed a fallback, or when a fallback was - // filled in with the resolved UI. This lets us throttle the appearance of new - // content as it streams in, to minimize jank. - // TODO: Think of a better name for this variable? + break; + } - var globalMostRecentFallbackTime = 0; - var FALLBACK_THROTTLE_MS = 300; // The absolute time for when we should start giving up on rendering - // more and prefer CPU suspense heuristics instead. + default: + { + recursivelyTraverseDisconnectPassiveEffects(finishedWork); + break; + } + } +} - 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. +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 - var RENDER_TIMEOUT_MS = 500; - var workInProgressTransitions = null; + setCurrentFiber(fiber); + commitPassiveUnmountInsideDeletedTreeOnFiber(fiber, nearestMountedAncestor); + resetCurrentFiber(); + var child = fiber.child; // TODO: Only traverse subtree if it has a PassiveStatic flag. - function resetRenderTimer() { - workInProgressRootRenderTargetTime = now$1() + RENDER_TIMEOUT_MS; + if (child !== null) { + child.return = fiber; + nextEffect = child; + } else { + commitPassiveUnmountEffectsInsideOfDeletedTree_complete(deletedSubtreeRoot); } + } +} - function getRenderTargetTime() { - return workInProgressRootRenderTargetTime; - } - var legacyErrorBoundariesThatAlreadyFailed = null; - var rootDoesHavePassiveEffects = false; - var rootWithPendingPassiveEffects = null; - var pendingPassiveEffectsLanes = NoLanes; - var pendingPassiveProfilerEffects = []; - var pendingPassiveEffectsRemainingLanes = NoLanes; - var pendingPassiveTransitions = null; // Use these to prevent an infinite loop of nested updates +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. - 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; - var isRunningInsertionEffect = false; - function getWorkInProgressRoot() { - return workInProgressRoot; - } - function getWorkInProgressRootRenderLanes() { - return workInProgressRootRenderLanes; - } - function isWorkLoopSuspendedOnData() { - return workInProgressSuspendedReason === SuspendedOnData; + detachFiberAfterEffects(fiber); + + if (fiber === deletedSubtreeRoot) { + nextEffect = null; + return; } - function requestUpdateLane(fiber) { - // Special cases - var mode = fiber.mode; - 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 (sibling !== null) { + sibling.return = returnFiber; + nextEffect = sibling; + return; + } - var transition = requestCurrentTransition(); + nextEffect = returnFiber; + } +} - if (transition !== null) { +function commitPassiveUnmountInsideDeletedTreeOnFiber(current, nearestMountedAncestor) { + switch (current.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: + { + commitHookPassiveUnmountEffects(current, nearestMountedAncestor, Passive); + break; + } + // TODO: run passive unmount effects when unmounting a root. + // Because passive unmount effects are not currently run, + // the cache instance owned by the root will never be freed. + // When effects are run, the cache should be freed here: + // case HostRoot: { + // if (enableCache) { + // const cache = current.memoizedState.cache; + // releaseCache(cache); + // } + // break; + // } + + case LegacyHiddenComponent: + case OffscreenComponent: + { { - if (!transition._updatedFibers) { - transition._updatedFibers = new Set(); + if (current.memoizedState !== null && current.memoizedState.cachePool !== null) { + var cache = current.memoizedState.cachePool.pool; // Retain/release the cache used for pending (suspended) nodes. + // Note that this is only reached in the non-suspended/visible case: + // when the content is suspended/hidden, the retain/release occurs + // via the parent Suspense component (see case above). + + if (cache != null) { + retainCache(cache); + } } - - transition._updatedFibers.add(fiber); } - var actionScopeLane = peekEntangledActionLane(); - return actionScopeLane !== NoLane // We're inside an async action scope. Reuse the same lane. - ? actionScopeLane // We may or may not be inside an async action scope. If we are, this - : // is the first update in that scope. Either way, we need to get a - // fresh transition lane. - requestTransitionLane(); + break; } - return eventPriorityToLane(resolveUpdatePriority()); - } - - 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; + case SuspenseComponent: + { - if ((mode & ConcurrentMode) === NoMode) { - return SyncLane; + break; } - return claimNextRetryLane(); - } + case CacheComponent: + { + { + var _cache = current.memoizedState.cache; + releaseCache(_cache); + } + + break; + } + } +} - function requestDeferredLane() { - if (workInProgressDeferredLane === NoLane) { - // If there are multiple useDeferredValue hooks in the same render, the - // tasks that they spawn should all be batched together, so they should all - // receive the same lane. - // Check the priority of the current render to decide the priority of the - // deferred task. - // OffscreenLane is used for prerendering, but we also use OffscreenLane - // for incremental hydration. It's given the lowest priority because the - // initial HTML is the same as the final UI. But useDeferredValue during - // hydration is an exception — we need to upgrade the UI to the final - // value. So if we're currently hydrating, we treat it like a transition. - var isPrerendering = - includesSomeLane(workInProgressRootRenderLanes, OffscreenLane) && - !getIsHydrating(); +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 (isPrerendering) { - // There's only one OffscreenLane, so if it contains deferred work, we - // should just reschedule using the same lane. - workInProgressDeferredLane = OffscreenLane; - } else { - // Everything else is spawned as a transition. - workInProgressDeferredLane = claimNextTransitionLane(); + break; } - } // Mark the parent Suspense boundary so it knows to spawn the deferred lane. - var suspenseHandler = getSuspenseHandler(); + case ClassComponent: + { + var instance = fiber.stateNode; - if (suspenseHandler !== null) { - // TODO: As an optimization, we shouldn't entangle the lanes at the root; we - // can entangle them using the baseLanes of the Suspense boundary instead. - // We only need to do something special if there's no Suspense boundary. - suspenseHandler.flags |= DidDefer; - } + if (typeof instance.componentDidMount === 'function') { + try { + instance.componentDidMount(); + } catch (error) { + captureCommitPhaseError(fiber, fiber.return, error); + } + } - return workInProgressDeferredLane; - } - function peekDeferredLane() { - return workInProgressDeferredLane; + break; + } } - function scheduleUpdateOnFiber(root, fiber, lane) { - { - if (isRunningInsertionEffect) { - error("useInsertionEffect must not schedule updates."); + } +} + +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; } - } + } + } +} - { - if (isFlushingPassiveEffects) { - didScheduleUpdateDuringPassiveEffects = true; - } - } // Check if the work loop is currently suspended and waiting for data to - // finish loading. - - if ( - // Suspended render phase - (root === workInProgressRoot && - workInProgressSuspendedReason === SuspendedOnData) || // Suspended commit phase - root.cancelPendingCommit !== null - ) { - // The incoming update might unblock the current render. Interrupt the - // current attempt and restart from the top. - prepareFreshStack(root, NoLanes); - markRootSuspended( - root, - workInProgressRootRenderLanes, - workInProgressDeferredLane - ); - } // Mark that the root has a pending update. - - markRootUpdated(root, lane); - - 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. +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: { - if (isDevToolsPresent) { - addFiberToLanesMap(root, fiber, lane); + try { + commitHookEffectListUnmount(Layout | HasEffect, fiber, fiber.return); + } catch (error) { + captureCommitPhaseError(fiber, fiber.return, error); } + + break; } - warnIfUpdatesNotWrappedWithActDEV(fiber); + case ClassComponent: + { + var instance = fiber.stateNode; - 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. - if ((executionContext & RenderContext) === NoContext) { - workInProgressRootInterleavedUpdatedLanes = mergeLanes( - workInProgressRootInterleavedUpdatedLanes, - lane - ); + if (typeof instance.componentWillUnmount === 'function') { + safelyCallComponentWillUnmount(fiber, fiber.return, instance); } - 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, - workInProgressDeferredLane - ); - } + break; } + } + } +} - ensureRootIsScheduled(root); - - if ( - lane === SyncLane && - executionContext === NoContext && - !disableLegacyMode && - (fiber.mode & ConcurrentMode) === NoMode - ) { - if (ReactSharedInternals.isBatchingLegacy); - else { - // 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(); - flushSyncWorkOnLegacyRootsOnly(); +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 isUnsafeClassRenderPhaseUpdate(fiber) { - // Check if this is a render phase update. Only called by class components, - // which special (deprecated) behavior for UNSAFE_componentWillReceive props. - return (executionContext & RenderContext) !== NoContext; - } // This is the entry point for every concurrent task, i.e. anything that - // goes through Scheduler. + } +} - function performConcurrentWorkOnRoot(root, didTimeout) { - { - resetNestedUpdateFlag(); - } +function getCacheForType(resourceType) { - 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 cache = readContext(CacheContext); + var cacheForType = cache.data.get(resourceType); - var originalCallbackNode = root.callbackNode; - var didFlushPassiveEffects = flushPassiveEffects(); + if (cacheForType === undefined) { + cacheForType = resourceType(); + cache.data.set(resourceType, cacheForType); + } - 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. - // TODO: This was already computed in the caller. Pass it as an argument. + return cacheForType; +} - var lanes = getNextLanes( - root, - root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes - ); +var DefaultCacheDispatcher = { + getCacheForType: getCacheForType +}; + +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'); +} - 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. - - var shouldTimeSlice = - !includesBlockingLane(root, lanes) && - !includesExpiredLane(root, lanes) && - !didTimeout; - var exitStatus = shouldTimeSlice - ? renderRootConcurrent(root, lanes) - : renderRootSync(root, lanes); - - if (exitStatus !== RootInProgress) { - var renderWasConcurrent = shouldTimeSlice; +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. + 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; // $FlowFixMe[cannot-resolve-name] - Flow doesn't know about jest + + var jestIsDefined = typeof jest !== 'undefined'; + return jestIsDefined && isReactActEnvironmentGlobal !== false; + } +} +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; - do { - 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, NoLane); - } 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 finishedWork = root.current.alternate; - - if ( - renderWasConcurrent && - !isRenderConsistentWithExternalStores(finishedWork) - ) { - // A store was mutated in an interleaved event. Render again, - // synchronously, to block further mutations. - exitStatus = renderRootSync(root, lanes); // We assume the tree is now consistent because we didn't yield to any - // concurrent events. - - renderWasConcurrent = false; // Need to check the exit status again. + if (!isReactActEnvironmentGlobal && ReactSharedInternals.actQueue !== null) { + // TODO: Include link to relevant documentation page. + error('The current testing environment is not configured to support ' + 'act(...)'); + } - continue; - } // Check if something threw - - if (exitStatus === RootErrored) { - var lanesThatJustErrored = lanes; - var errorRetryLanes = getLanesToRetrySynchronouslyOnError( - root, - lanesThatJustErrored - ); - - if (errorRetryLanes !== NoLanes) { - lanes = errorRetryLanes; - exitStatus = recoverFromConcurrentError( - root, - lanesThatJustErrored, - errorRetryLanes - ); - renderWasConcurrent = false; // Need to check the exit status again. - - if (exitStatus !== RootErrored) { - // The root did not error this time. Restart the exit algorithm - // from the beginning. - // TODO: Refactor the exit algorithm to be less confusing. Maybe - // more branches + recursion instead of a loop. I think the only - // thing that causes it to be a loop is the RootDidNotComplete - // check. If that's true, then we don't need a loop/recursion - // at all. - continue; - } - } - } + return isReactActEnvironmentGlobal; + } +} - if (exitStatus === RootFatalErrored) { - prepareFreshStack(root, NoLanes); - markRootSuspended(root, lanes, NoLane); - break; - } // 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. +var PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map; +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 executionContext = NoContext; // The root we're working on + +var workInProgressRoot = null; // The fiber we're working on + +var workInProgress = null; // The lanes we're rendering + +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 entangledRenderLanes. + +var entangledRenderLanes = NoLanes; // Whether to root completed, errored, suspended, etc. + +var workInProgressRootExitStatus = RootInProgress; // The work left over by components that were visited during this render. Only +// includes unprocessed updates, not work in bailed out children. + +var workInProgressRootSkippedLanes = NoLanes; // Lanes that were updated (in an interleaved event) during this render. + +var workInProgressRootInterleavedUpdatedLanes = NoLanes; // Lanes that were updated during the render phase (*not* an interleaved event). + +var workInProgressRootPingedLanes = NoLanes; // If this lane scheduled deferred work, this is the lane of the deferred task. + +var workInProgressDeferredLane = NoLane; // Errors that are thrown during the render phase. + +var workInProgressRootConcurrentErrors = null; // These are errors that we recovered from without surfacing them to the UI. +// We will log them once the tree commits. + +var workInProgressRootRecoverableErrors = null; // Tracks when an update occurs during the render phase. + +var workInProgressRootDidIncludeRecursiveRenderUpdate = false; // Thacks when an update occurs during the commit phase. It's a separate +// variable from the one for renders because the commit phase may run +// concurrently to a render phase. + +var didIncludeCommitPhaseUpdate = false; // The most recent time we either committed a fallback, or when a fallback was +// filled in with the resolved UI. This lets us throttle the appearance of new +// content as it streams in, to minimize jank. +// TODO: Think of a better name for this variable? + +var globalMostRecentFallbackTime = 0; +var FALLBACK_THROTTLE_MS = 300; // The absolute time for when we should start giving up on rendering +// more and prefer CPU suspense heuristics instead. + +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 RENDER_TIMEOUT_MS = 500; +var workInProgressTransitions = null; + +function resetRenderTimer() { + workInProgressRootRenderTargetTime = now$1() + RENDER_TIMEOUT_MS; +} - root.finishedWork = finishedWork; - root.finishedLanes = lanes; - finishConcurrentRender(root, exitStatus, finishedWork, lanes); - } +function getRenderTargetTime() { + return workInProgressRootRenderTargetTime; +} +var legacyErrorBoundariesThatAlreadyFailed = null; +var rootDoesHavePassiveEffects = false; +var rootWithPendingPassiveEffects = null; +var pendingPassiveEffectsLanes = NoLanes; +var pendingPassiveProfilerEffects = []; +var pendingPassiveEffectsRemainingLanes = NoLanes; +var pendingPassiveTransitions = null; // Use these to prevent an infinite loop of nested updates + +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; +var isRunningInsertionEffect = false; +function getWorkInProgressRoot() { + return workInProgressRoot; +} +function getWorkInProgressRootRenderLanes() { + return workInProgressRootRenderLanes; +} +function isWorkLoopSuspendedOnData() { + return workInProgressSuspendedReason === SuspendedOnData; +} +function requestUpdateLane(fiber) { + // Special cases + var mode = fiber.mode; + + 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); + } + + var transition = requestCurrentTransition(); + + if (transition !== null) { + { + if (!transition._updatedFibers) { + transition._updatedFibers = new Set(); + } - break; - } while (true); - } - - ensureRootIsScheduled(root); - return getContinuationForRoot(root, originalCallbackNode); - } - - 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 = supportsHydration; - - var exitStatus = renderRootSync(root, errorRetryLanes); - - 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. + transition._updatedFibers.add(fiber); + } - 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. + var actionScopeLane = peekEntangledActionLane(); + return actionScopeLane !== NoLane ? // We're inside an async action scope. Reuse the same lane. + actionScopeLane : // We may or may not be inside an async action scope. If we are, this + // is the first update in that scope. Either way, we need to get a + // fresh transition lane. + requestTransitionLane(); + } - 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. + return eventPriorityToLane(resolveUpdatePriority()); +} - if (errorsFromSecondAttempt !== null) { - queueRecoverableErrors(errorsFromSecondAttempt); - } - } +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; - return exitStatus; + if ((mode & ConcurrentMode) === NoMode) { + return SyncLane; + } + + return claimNextRetryLane(); +} + +function requestDeferredLane() { + if (workInProgressDeferredLane === NoLane) { + // If there are multiple useDeferredValue hooks in the same render, the + // tasks that they spawn should all be batched together, so they should all + // receive the same lane. + // Check the priority of the current render to decide the priority of the + // deferred task. + // OffscreenLane is used for prerendering, but we also use OffscreenLane + // for incremental hydration. It's given the lowest priority because the + // initial HTML is the same as the final UI. But useDeferredValue during + // hydration is an exception — we need to upgrade the UI to the final + // value. So if we're currently hydrating, we treat it like a transition. + var isPrerendering = includesSomeLane(workInProgressRootRenderLanes, OffscreenLane) && !getIsHydrating(); + + if (isPrerendering) { + // There's only one OffscreenLane, so if it contains deferred work, we + // should just reschedule using the same lane. + workInProgressDeferredLane = OffscreenLane; + } else { + // Everything else is spawned as a transition. + workInProgressDeferredLane = claimNextTransitionLane(); + } + } // Mark the parent Suspense boundary so it knows to spawn the deferred lane. + + + var suspenseHandler = getSuspenseHandler(); + + if (suspenseHandler !== null) { + // TODO: As an optimization, we shouldn't entangle the lanes at the root; we + // can entangle them using the baseLanes of the Suspense boundary instead. + // We only need to do something special if there's no Suspense boundary. + suspenseHandler.flags |= DidDefer; + } + + return workInProgressDeferredLane; +} +function peekDeferredLane() { + return workInProgressDeferredLane; +} +function scheduleUpdateOnFiber(root, fiber, lane) { + { + if (isRunningInsertionEffect) { + error('useInsertionEffect must not schedule updates.'); + } + } + + { + if (isFlushingPassiveEffects) { + didScheduleUpdateDuringPassiveEffects = true; + } + } // Check if the work loop is currently suspended and waiting for data to + // finish loading. + + + if ( // Suspended render phase + root === workInProgressRoot && workInProgressSuspendedReason === SuspendedOnData || // Suspended commit phase + root.cancelPendingCommit !== null) { + // The incoming update might unblock the current render. Interrupt the + // current attempt and restart from the top. + prepareFreshStack(root, NoLanes); + markRootSuspended(root, workInProgressRootRenderLanes, workInProgressDeferredLane); + } // Mark that the root has a pending update. + + + markRootUpdated(root, lane); + + 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 queueRecoverableErrors(errors) { - if (workInProgressRootRecoverableErrors === null) { - workInProgressRootRecoverableErrors = errors; - } else { - // $FlowFixMe[method-unbinding] - workInProgressRootRecoverableErrors.push.apply( - workInProgressRootRecoverableErrors, - errors - ); - } - } - - function finishConcurrentRender(root, exitStatus, finishedWork, lanes) { - // TODO: The fact that most of these branches are identical suggests that some - // of the exit statuses are not best modeled as exit statuses and should be - // tracked orthogonally. - switch (exitStatus) { - case RootInProgress: - case RootFatalErrored: { - throw new Error("Root did not complete. This is a bug in React."); - } - - case RootSuspendedWithDelay: { - 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. - markRootSuspended(root, lanes, workInProgressDeferredLane); - return; - } // Commit the placeholder. + warnIfUpdatesNotWrappedWithActDEV(fiber); - break; - } + 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. + if ((executionContext & RenderContext) === NoContext) { + workInProgressRootInterleavedUpdatedLanes = mergeLanes(workInProgressRootInterleavedUpdatedLanes, lane); + } - case RootErrored: { - // This render errored. Ignore any recoverable errors because we weren't actually - // able to recover. Instead, whatever the final errors were is the ones we log. - // This ensures that we only log the actual client side error if it's just a plain - // error thrown from a component on the server and the client. - workInProgressRootRecoverableErrors = null; - break; - } + 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, workInProgressDeferredLane); + } + } - case RootSuspended: - case RootCompleted: { - break; - } + ensureRootIsScheduled(root); - default: { - throw new Error("Unknown root exit status."); - } + if (lane === SyncLane && executionContext === NoContext && !disableLegacyMode && (fiber.mode & ConcurrentMode) === NoMode) { + if (ReactSharedInternals.isBatchingLegacy) ; else { + // 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(); + flushSyncWorkOnLegacyRootsOnly(); } + } + } +} +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 (executionContext & RenderContext) !== NoContext; +} // This is the entry point for every concurrent task, i.e. anything that +// goes through Scheduler. + +function performConcurrentWorkOnRoot(root, didTimeout) { + { + resetNestedUpdateFlag(); + } + + 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 originalCallbackNode = root.callbackNode; + var didFlushPassiveEffects = flushPassiveEffects(); + + 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. + // TODO: This was already computed in the caller. Pass it as an argument. - if (shouldForceFlushFallbacksInDEV()) { - // We're inside an `act` scope. Commit immediately. - commitRoot( - root, - workInProgressRootRecoverableErrors, - workInProgressTransitions, - workInProgressRootDidIncludeRecursiveRenderUpdate, - workInProgressDeferredLane - ); - } else { - if ( - includesOnlyRetries(lanes) && - (alwaysThrottleRetries || exitStatus === RootSuspended) - ) { - // 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. - - if (msUntilTimeout > 10) { - markRootSuspended(root, lanes, workInProgressDeferredLane); - var nextLanes = getNextLanes(root, NoLanes); - - if (nextLanes !== NoLanes) { - // There's additional work we can do on this root. We might as well - // attempt to work on that while we're suspended. - return; - } // 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. - // TODO: Combine retry throttling with Suspensey commits. Right now they - // run one after the other. - - root.timeoutHandle = scheduleTimeout( - commitRootWhenReady.bind( - null, - root, - finishedWork, - workInProgressRootRecoverableErrors, - workInProgressTransitions, - workInProgressRootDidIncludeRecursiveRenderUpdate, - lanes, - workInProgressDeferredLane - ), - msUntilTimeout - ); - return; - } - } - commitRootWhenReady( - root, - finishedWork, - workInProgressRootRecoverableErrors, - workInProgressTransitions, - workInProgressRootDidIncludeRecursiveRenderUpdate, - lanes, - workInProgressDeferredLane - ); - } - } - - function commitRootWhenReady( - root, - finishedWork, - recoverableErrors, - transitions, - didIncludeRenderPhaseUpdate, - lanes, - spawnedLane - ) { - // TODO: Combine retry throttling with Suspensey commits. Right now they run - // one after the other. - if (includesOnlyNonUrgentLanes(lanes)) { - // the suspensey resources. The renderer is responsible for accumulating - // all the load events. This all happens in a single synchronous - // transaction, so it track state in its own module scope. - - accumulateSuspenseyCommit(finishedWork); // At the end, ask the renderer if it's ready to commit, or if we should - // suspend. If it's not ready, it will return a callback to subscribe to - // a ready event. - - var schedulePendingCommit = waitForCommitToBeReady(); - - 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, - recoverableErrors, - transitions, - didIncludeRenderPhaseUpdate - ) - ); - markRootSuspended(root, lanes, spawnedLane); - return; - } - } // Otherwise, commit immediately. + var lanes = getNextLanes(root, root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes); - commitRoot( - root, - recoverableErrors, - transitions, - didIncludeRenderPhaseUpdate, - spawnedLane - ); - } + 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 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; - while (true) { - if (node.flags & StoreConsistency) { - var updateQueue = node.updateQueue; + var shouldTimeSlice = !includesBlockingLane(root, lanes) && !includesExpiredLane(root, lanes) && (!didTimeout); + var exitStatus = shouldTimeSlice ? renderRootConcurrent(root, lanes) : renderRootSync(root, lanes); - if (updateQueue !== null) { - var checks = updateQueue.stores; - - if (checks !== null) { - for (var i = 0; i < checks.length; i++) { - var check = checks[i]; - var getSnapshot = check.getSnapshot; - var renderedValue = check.value; - - 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 (exitStatus !== RootInProgress) { + var renderWasConcurrent = shouldTimeSlice; + + do { + 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, NoLane); + } 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 finishedWork = root.current.alternate; + + if (renderWasConcurrent && !isRenderConsistentWithExternalStores(finishedWork)) { + // A store was mutated in an interleaved event. Render again, + // synchronously, to block further mutations. + exitStatus = renderRootSync(root, lanes); // We assume the tree is now consistent because we didn't yield to any + // concurrent events. + + renderWasConcurrent = false; // Need to check the exit status again. + + continue; + } // Check if something threw + + + if (exitStatus === RootErrored) { + var lanesThatJustErrored = lanes; + var errorRetryLanes = getLanesToRetrySynchronouslyOnError(root, lanesThatJustErrored); + + if (errorRetryLanes !== NoLanes) { + lanes = errorRetryLanes; + exitStatus = recoverFromConcurrentError(root, lanesThatJustErrored, errorRetryLanes); + renderWasConcurrent = false; // Need to check the exit status again. + + if (exitStatus !== RootErrored) { + // The root did not error this time. Restart the exit algorithm + // from the beginning. + // TODO: Refactor the exit algorithm to be less confusing. Maybe + // more branches + recursion instead of a loop. I think the only + // thing that causes it to be a loop is the RootDidNotComplete + // check. If that's true, then we don't need a loop/recursion + // at all. + continue; } } } - var child = node.child; + if (exitStatus === RootFatalErrored) { + prepareFreshStack(root, NoLanes); + markRootSuspended(root, lanes, NoLane); + break; + } // 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. - if (node.subtreeFlags & StoreConsistency && child !== null) { - child.return = node; - node = child; - continue; - } - if (node === finishedWork) { - return true; - } + root.finishedWork = finishedWork; + root.finishedLanes = lanes; + finishConcurrentRender(root, exitStatus, finishedWork, lanes); + } - while (node.sibling === null) { - if (node.return === null || node.return === finishedWork) { - return true; - } + break; + } while (true); + } - node = node.return; - } + ensureRootIsScheduled(root); + return getContinuationForRoot(root, originalCallbackNode); +} - node.sibling.return = node.return; - node = node.sibling; - } // Flow doesn't know this is unreachable, but eslint does - // eslint-disable-next-line no-unreachable +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 = supportsHydration ; + + var exitStatus = renderRootSync(root, errorRetryLanes); + + 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. - return true; - } // The extra indirections around markRootUpdated and markRootSuspended is - // needed to avoid a circular dependency between this module and - // ReactFiberLane. There's probably a better way to split up these modules and - // avoid this problem. Perhaps all the root-marking functions should move into - // the work loop. + 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. - function markRootUpdated(root, updatedLanes) { - markRootUpdated$1(root, updatedLanes); - if (enableInfiniteRenderLoopDetection) { - // Check for recursive updates - if (executionContext & RenderContext) { - workInProgressRootDidIncludeRecursiveRenderUpdate = true; - } else if (executionContext & CommitContext) { - didIncludeCommitPhaseUpdate = true; - } + 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. - throwIfInfiniteUpdateLoopDetected(); - } + if (errorsFromSecondAttempt !== null) { + queueRecoverableErrors(errorsFromSecondAttempt); } + } - function markRootPinged(root, pingedLanes) { - markRootPinged$1(root, pingedLanes); + return exitStatus; +} - if (enableInfiniteRenderLoopDetection) { - // Check for recursive pings. Pings are conceptually different from updates in - // other contexts but we call it an "update" in this context because - // repeatedly pinging a suspended render can cause a recursive render loop. - // The relevant property is that it can result in a new render attempt - // being scheduled. - if (executionContext & RenderContext) { - workInProgressRootDidIncludeRecursiveRenderUpdate = true; - } else if (executionContext & CommitContext) { - didIncludeCommitPhaseUpdate = true; - } +function queueRecoverableErrors(errors) { + if (workInProgressRootRecoverableErrors === null) { + workInProgressRootRecoverableErrors = errors; + } else { + // $FlowFixMe[method-unbinding] + workInProgressRootRecoverableErrors.push.apply(workInProgressRootRecoverableErrors, errors); + } +} - throwIfInfiniteUpdateLoopDetected(); +function finishConcurrentRender(root, exitStatus, finishedWork, lanes) { + // TODO: The fact that most of these branches are identical suggests that some + // of the exit statuses are not best modeled as exit statuses and should be + // tracked orthogonally. + switch (exitStatus) { + case RootInProgress: + case RootFatalErrored: + { + throw new Error('Root did not complete. This is a bug in React.'); } - } - function markRootSuspended(root, suspendedLanes, spawnedLane) { - // When suspending, we should always exclude lanes that were pinged or (more - // rarely, since we try to avoid it) updated during the render phase. - suspendedLanes = removeLanes( - suspendedLanes, - workInProgressRootPingedLanes - ); - suspendedLanes = removeLanes( - suspendedLanes, - workInProgressRootInterleavedUpdatedLanes - ); + case RootSuspendedWithDelay: + { + 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. + markRootSuspended(root, lanes, workInProgressDeferredLane); + return; + } // Commit the placeholder. - markRootSuspended$1(root, suspendedLanes, spawnedLane); - } // This is the entry point for synchronous tasks that don't go - // through Scheduler - function performSyncWorkOnRoot(root, lanes) { - if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { - throw new Error("Should not already be working."); + break; } - var didFlushPassiveEffects = flushPassiveEffects(); + case RootErrored: + { + // This render errored. Ignore any recoverable errors because we weren't actually + // able to recover. Instead, whatever the final errors were is the ones we log. + // This ensures that we only log the actual client side error if it's just a plain + // error thrown from a component on the server and the client. + workInProgressRootRecoverableErrors = null; + break; + } - if (didFlushPassiveEffects) { - // If passive effects were flushed, exit to the outer work loop in the root - // scheduler, so we can recompute the priority. - // TODO: We don't actually need this `ensureRootIsScheduled` call because - // this path is only reachable if the root is already part of the schedule. - // I'm including it only for consistency with the other exit points from - // this function. Can address in a subsequent refactor. - ensureRootIsScheduled(root); - return null; + case RootSuspended: + case RootCompleted: + { + break; } + default: { - syncNestedUpdateFlag(); + throw new Error('Unknown root exit status.'); } + } - var exitStatus = renderRootSync(root, lanes); + if (shouldForceFlushFallbacksInDEV()) { + // We're inside an `act` scope. Commit immediately. + commitRoot(root, workInProgressRootRecoverableErrors, workInProgressTransitions, workInProgressRootDidIncludeRecursiveRenderUpdate, workInProgressDeferredLane); + } else { + if (includesOnlyRetries(lanes) && (alwaysThrottleRetries || exitStatus === RootSuspended)) { + // 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. - 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 (msUntilTimeout > 10) { + markRootSuspended(root, lanes, workInProgressDeferredLane); + var nextLanes = getNextLanes(root, NoLanes); - if (errorRetryLanes !== NoLanes) { - lanes = errorRetryLanes; - exitStatus = recoverFromConcurrentError( - root, - originallyAttemptedLanes, - errorRetryLanes - ); - } - } + if (nextLanes !== NoLanes) { + // There's additional work we can do on this root. We might as well + // attempt to work on that while we're suspended. + return; + } // 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. + // TODO: Combine retry throttling with Suspensey commits. Right now they + // run one after the other. - if (exitStatus === RootFatalErrored) { - prepareFreshStack(root, NoLanes); - markRootSuspended(root, lanes, NoLane); - ensureRootIsScheduled(root); - return null; - } - 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, workInProgressDeferredLane); - ensureRootIsScheduled(root); - 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, - workInProgressRootDidIncludeRecursiveRenderUpdate, - workInProgressDeferredLane - ); // Before exiting, make sure there's a callback scheduled for the next - // pending level. - - ensureRootIsScheduled(root); - return null; + root.timeoutHandle = scheduleTimeout(commitRootWhenReady.bind(null, root, finishedWork, workInProgressRootRecoverableErrors, workInProgressTransitions, workInProgressRootDidIncludeRecursiveRenderUpdate, lanes, workInProgressDeferredLane), msUntilTimeout); + return; + } } - function getExecutionContext() { - return executionContext; + + commitRootWhenReady(root, finishedWork, workInProgressRootRecoverableErrors, workInProgressTransitions, workInProgressRootDidIncludeRecursiveRenderUpdate, lanes, workInProgressDeferredLane); + } +} + +function commitRootWhenReady(root, finishedWork, recoverableErrors, transitions, didIncludeRenderPhaseUpdate, lanes, spawnedLane) { + // TODO: Combine retry throttling with Suspensey commits. Right now they run + // one after the other. + if (includesOnlyNonUrgentLanes(lanes)) { + // the suspensey resources. The renderer is responsible for accumulating + // all the load events. This all happens in a single synchronous + // transaction, so it track state in its own module scope. + + accumulateSuspenseyCommit(finishedWork); // At the end, ask the renderer if it's ready to commit, or if we should + // suspend. If it's not ready, it will return a callback to subscribe to + // a ready event. + + var schedulePendingCommit = waitForCommitToBeReady(); + + 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, recoverableErrors, transitions, didIncludeRenderPhaseUpdate)); + markRootSuspended(root, lanes, spawnedLane); + return; } - function batchedUpdates(fn, a) { - { - var prevExecutionContext = executionContext; - executionContext |= BatchedContext; + } // Otherwise, commit immediately. - 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 ( - executionContext === NoContext && // Treat `act` as if it's inside `batchedUpdates`, even in legacy mode. - !ReactSharedInternals.isBatchingLegacy - ) { - resetRenderTimer(); - flushSyncWorkOnLegacyRootsOnly(); + + commitRoot(root, recoverableErrors, transitions, didIncludeRenderPhaseUpdate, spawnedLane); +} + +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; + + while (true) { + if (node.flags & StoreConsistency) { + var updateQueue = node.updateQueue; + + if (updateQueue !== null) { + var checks = updateQueue.stores; + + if (checks !== null) { + for (var i = 0; i < checks.length; i++) { + var check = checks[i]; + var getSnapshot = check.getSnapshot; + var renderedValue = check.value; + + 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; + } } } } } - // Returns whether the the call was during a render or not - function flushSyncWork() { - if ((executionContext & (RenderContext | CommitContext)) === NoContext) { - flushSyncWorkOnAllRoots(); - return false; - } + var child = node.child; - return true; + if (node.subtreeFlags & StoreConsistency && child !== null) { + child.return = node; + node = child; + continue; } - // 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 setEntangledRenderLanes(newEntangledRenderLanes) { - entangledRenderLanes = newEntangledRenderLanes; - } - function getEntangledRenderLanes() { - return entangledRenderLanes; + if (node === finishedWork) { + return true; } - 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(workInProgress); - interruptedWork = workInProgress; - } - - while (interruptedWork !== null) { - var current = interruptedWork.alternate; - unwindInterruptedWork(current, interruptedWork); - interruptedWork = interruptedWork.return; + while (node.sibling === null) { + if (node.return === null || node.return === finishedWork) { + return true; } - workInProgress = null; + node = node.return; } - function prepareFreshStack(root, lanes) { - root.finishedWork = null; - root.finishedLanes = NoLanes; - var timeoutHandle = root.timeoutHandle; + node.sibling.return = node.return; + node = node.sibling; + } // Flow doesn't know this is unreachable, but eslint does + // eslint-disable-next-line no-unreachable - 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[incompatible-call] Complains noTimeout is not a TimeoutID, despite the check above - - cancelTimeout(timeoutHandle); - } - var cancelPendingCommit = root.cancelPendingCommit; + return true; +} // The extra indirections around markRootUpdated and markRootSuspended is +// needed to avoid a circular dependency between this module and +// ReactFiberLane. There's probably a better way to split up these modules and +// avoid this problem. Perhaps all the root-marking functions should move into +// the work loop. - if (cancelPendingCommit !== null) { - root.cancelPendingCommit = null; - cancelPendingCommit(); - } - resetWorkInProgressStack(); - workInProgressRoot = root; - var rootWorkInProgress = createWorkInProgress(root.current, null); - workInProgress = rootWorkInProgress; - workInProgressRootRenderLanes = lanes; - workInProgressSuspendedReason = NotSuspended; - workInProgressThrownValue = null; - workInProgressRootDidAttachPingListener = false; - workInProgressRootExitStatus = RootInProgress; - workInProgressRootSkippedLanes = NoLanes; - workInProgressRootInterleavedUpdatedLanes = NoLanes; - workInProgressRootPingedLanes = NoLanes; - workInProgressDeferredLane = NoLane; - workInProgressRootConcurrentErrors = null; - workInProgressRootRecoverableErrors = null; - workInProgressRootDidIncludeRecursiveRenderUpdate = false; // Get the lanes that are entangled with whatever we're about to render. We - // track these separately so we can distinguish the priority of the render - // task from the priority of the lanes it is entangled with. For example, a - // transition may not be allowed to finish unless it includes the Sync lane, - // which is currently suspended. We should be able to render the Transition - // and Sync lane in the same batch, but at Transition priority, because the - // Sync lane already suspended. +function markRootUpdated(root, updatedLanes) { + markRootUpdated$1(root, updatedLanes); - entangledRenderLanes = getEntangledLanes(root, lanes); - finishQueueingConcurrentUpdates(); + if (enableInfiniteRenderLoopDetection) { + // Check for recursive updates + if (executionContext & RenderContext) { + workInProgressRootDidIncludeRecursiveRenderUpdate = true; + } else if (executionContext & CommitContext) { + didIncludeCommitPhaseUpdate = true; + } - { - ReactStrictModeWarnings.discardPendingWarnings(); - } + throwIfInfiniteUpdateLoopDetected(); + } +} - return rootWorkInProgress; - } +function markRootPinged(root, pingedLanes) { + markRootPinged$1(root, pingedLanes); - function resetSuspendedWorkLoopOnUnwind(fiber) { - // Reset module-level state that was set during the render phase. - resetContextDependencies(); - resetHooksOnUnwind(fiber); - resetChildReconcilerOnUnwind(); + if (enableInfiniteRenderLoopDetection) { + // Check for recursive pings. Pings are conceptually different from updates in + // other contexts but we call it an "update" in this context because + // repeatedly pinging a suspended render can cause a recursive render loop. + // The relevant property is that it can result in a new render attempt + // being scheduled. + if (executionContext & RenderContext) { + workInProgressRootDidIncludeRecursiveRenderUpdate = true; + } else if (executionContext & CommitContext) { + didIncludeCommitPhaseUpdate = true; } - 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(); + throwIfInfiniteUpdateLoopDetected(); + } +} - { - ReactSharedInternals.owner = null; - } - - 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; - } - - workInProgressThrownValue = thrownValue; - var erroredWork = workInProgress; - - if (erroredWork === null) { - // This is a fatal error - workInProgressRootExitStatus = RootFatalErrored; - logUncaughtError( - root, - createCapturedValueAtFiber(thrownValue, root.current) - ); - return; +function markRootSuspended(root, suspendedLanes, spawnedLane) { + // When suspending, we should always exclude lanes that were pinged or (more + // rarely, since we try to avoid it) updated during the render phase. + suspendedLanes = removeLanes(suspendedLanes, workInProgressRootPingedLanes); + suspendedLanes = removeLanes(suspendedLanes, workInProgressRootInterleavedUpdatedLanes); + + markRootSuspended$1(root, suspendedLanes, spawnedLane); +} // This is the entry point for synchronous tasks that don't go +// through Scheduler + + +function performSyncWorkOnRoot(root, lanes) { + if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { + throw new Error('Should not already be working.'); + } + + var didFlushPassiveEffects = flushPassiveEffects(); + + if (didFlushPassiveEffects) { + // If passive effects were flushed, exit to the outer work loop in the root + // scheduler, so we can recompute the priority. + // TODO: We don't actually need this `ensureRootIsScheduled` call because + // this path is only reachable if the root is already part of the schedule. + // I'm including it only for consistency with the other exit points from + // this function. Can address in a subsequent refactor. + ensureRootIsScheduled(root); + return null; + } + + { + syncNestedUpdateFlag(); + } + + 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 (exitStatus === RootFatalErrored) { + prepareFreshStack(root, NoLanes); + markRootSuspended(root, lanes, NoLane); + ensureRootIsScheduled(root); + return null; + } + + 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, workInProgressDeferredLane); + ensureRootIsScheduled(root); + 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, workInProgressRootDidIncludeRecursiveRenderUpdate, workInProgressDeferredLane); // Before exiting, make sure there's a callback scheduled for the next + // pending level. + + ensureRootIsScheduled(root); + return null; +} +function getExecutionContext() { + return executionContext; +} +function batchedUpdates(fn, a) { + { + var prevExecutionContext = executionContext; + executionContext |= BatchedContext; + + 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 (executionContext === NoContext && // Treat `act` as if it's inside `batchedUpdates`, even in legacy mode. + !(ReactSharedInternals.isBatchingLegacy)) { + resetRenderTimer(); + flushSyncWorkOnLegacyRootsOnly(); } + } + } +} +// Returns whether the the call was during a render or not - 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 flushSyncWork() { + if ((executionContext & (RenderContext | CommitContext)) === NoContext) { + flushSyncWorkOnAllRoots(); + return false; + } - { - markComponentRenderStopped(); + return true; +} +// 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 - switch (workInProgressSuspendedReason) { - case SuspendedOnError: { - markComponentErrored( - erroredWork, - thrownValue, - workInProgressRootRenderLanes - ); - break; - } +function setEntangledRenderLanes(newEntangledRenderLanes) { + entangledRenderLanes = newEntangledRenderLanes; +} +function getEntangledRenderLanes() { + return entangledRenderLanes; +} - case SuspendedOnData: - case SuspendedOnImmediate: - case SuspendedOnDeprecatedThrowPromise: - case SuspendedAndReadyToContinue: { - var wakeable = thrownValue; - markComponentSuspended( - erroredWork, - wakeable, - workInProgressRootRenderLanes - ); - break; - } - } - } - } +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(workInProgress); + interruptedWork = workInProgress; + } + + while (interruptedWork !== null) { + var current = interruptedWork.alternate; + unwindInterruptedWork(current, interruptedWork); + interruptedWork = interruptedWork.return; + } + + workInProgress = null; +} - 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. - var handler = getSuspenseHandler(); +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[incompatible-call] Complains noTimeout is not a TimeoutID, despite the check above + + cancelTimeout(timeoutHandle); + } + + var cancelPendingCommit = root.cancelPendingCommit; + + if (cancelPendingCommit !== null) { + root.cancelPendingCommit = null; + cancelPendingCommit(); + } + + resetWorkInProgressStack(); + workInProgressRoot = root; + var rootWorkInProgress = createWorkInProgress(root.current, null); + workInProgress = rootWorkInProgress; + workInProgressRootRenderLanes = lanes; + workInProgressSuspendedReason = NotSuspended; + workInProgressThrownValue = null; + workInProgressRootDidAttachPingListener = false; + workInProgressRootExitStatus = RootInProgress; + workInProgressRootSkippedLanes = NoLanes; + workInProgressRootInterleavedUpdatedLanes = NoLanes; + workInProgressRootPingedLanes = NoLanes; + workInProgressDeferredLane = NoLane; + workInProgressRootConcurrentErrors = null; + workInProgressRootRecoverableErrors = null; + workInProgressRootDidIncludeRecursiveRenderUpdate = false; // Get the lanes that are entangled with whatever we're about to render. We + // track these separately so we can distinguish the priority of the render + // task from the priority of the lanes it is entangled with. For example, a + // transition may not be allowed to finish unless it includes the Sync lane, + // which is currently suspended. We should be able to render the Transition + // and Sync lane in the same batch, but at Transition priority, because the + // Sync lane already suspended. + + entangledRenderLanes = getEntangledLanes(root, lanes); + finishQueueingConcurrentUpdates(); + + { + ReactStrictModeWarnings.discardPendingWarnings(); + } + + return rootWorkInProgress; +} - if (handler === null) { - // There's no Suspense boundary that can provide a fallback. We have no - // choice but to remain on the previous screen. - // NOTE: We do this even for sync updates, for lack of any better option. In - // the future, we may change how we handle this, like by putting the whole - // root into a "detached" mode. - return true; - } // 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; +function resetSuspendedWorkLoopOnUnwind(fiber) { + // Reset module-level state that was set during the render phase. + resetContextDependencies(); + resetHooksOnUnwind(fiber); + resetChildReconcilerOnUnwind(); +} + +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(); + + { + ReactSharedInternals.owner = null; + } + + 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; + } + + workInProgressThrownValue = thrownValue; + var erroredWork = workInProgress; + + if (erroredWork === null) { + // This is a fatal error + workInProgressRootExitStatus = RootFatalErrored; + logUncaughtError(root, createCapturedValueAtFiber(thrownValue, root.current)); + 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); + } + + { + markComponentRenderStopped(); + + switch (workInProgressSuspendedReason) { + case SuspendedOnError: + { + markComponentErrored(erroredWork, thrownValue, workInProgressRootRenderLanes); + break; } - } - if ( - includesOnlyRetries(workInProgressRootRenderLanes) || // In this context, an OffscreenLane counts as a Retry - // TODO: It's become increasingly clear that Retries and Offscreen are - // deeply connected. They probably can be unified further. - includesSomeLane(workInProgressRootRenderLanes, OffscreenLane) - ) { - // 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. - // - // The reason we must check if this is a retry is because it guarantees - // that suspending the work loop won't block an actual update, because - // retries don't "update" anything; they fill in fallbacks that were left - // behind by a previous transition. - return handler === getShellBoundary(); - } // For all other Lanes besides Transitions and Retries, we should not wait - // for the data to load. + case SuspendedOnData: + case SuspendedOnImmediate: + case SuspendedOnDeprecatedThrowPromise: + case SuspendedAndReadyToContinue: + { + var wakeable = thrownValue; + markComponentSuspended(erroredWork, wakeable, workInProgressRootRenderLanes); + break; + } + } + } +} +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. + var handler = getSuspenseHandler(); + + if (handler === null) { + // There's no Suspense boundary that can provide a fallback. We have no + // choice but to remain on the previous screen. + // NOTE: We do this even for sync updates, for lack of any better option. In + // the future, we may change how we handle this, like by putting the whole + // root into a "detached" mode. + return true; + } // 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; } + } - function pushDispatcher(container) { - var prevDispatcher = ReactSharedInternals.H; - ReactSharedInternals.H = ContextOnlyDispatcher; + if (includesOnlyRetries(workInProgressRootRenderLanes) || // In this context, an OffscreenLane counts as a Retry + // TODO: It's become increasingly clear that Retries and Offscreen are + // deeply connected. They probably can be unified further. + includesSomeLane(workInProgressRootRenderLanes, OffscreenLane)) { + // 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. + // + // The reason we must check if this is a retry is because it guarantees + // that suspending the work loop won't block an actual update, because + // retries don't "update" anything; they fill in fallbacks that were left + // behind by a previous transition. + return handler === getShellBoundary(); + } // For all other Lanes besides Transitions and Retries, we should not wait + // for the data to load. - 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; + + return false; +} + +function pushDispatcher(container) { + var prevDispatcher = ReactSharedInternals.H; + ReactSharedInternals.H = ContextOnlyDispatcher; + + 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; + } +} + +function popDispatcher(prevDispatcher) { + ReactSharedInternals.H = prevDispatcher; +} + +function pushCacheDispatcher() { + { + var prevCacheDispatcher = ReactSharedInternals.C; + ReactSharedInternals.C = DefaultCacheDispatcher; + return prevCacheDispatcher; + } +} + +function popCacheDispatcher(prevCacheDispatcher) { + { + ReactSharedInternals.C = prevCacheDispatcher; + } +} + +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. + + if ((includesNonIdleWork(workInProgressRootSkippedLanes) || includesNonIdleWork(workInProgressRootInterleavedUpdatedLanes)) && workInProgressRoot !== null) { + // 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. + markRootSuspended(workInProgressRoot, workInProgressRootRenderLanes, workInProgressDeferredLane); + } +} +function renderDidError() { + if (workInProgressRootExitStatus !== RootSuspendedWithDelay) { + workInProgressRootExitStatus = RootErrored; + } +} +function queueConcurrentError(error) { + 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. + +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. + +function renderRootSync(root, lanes) { + var prevExecutionContext = executionContext; + executionContext |= RenderContext; + var prevDispatcher = pushDispatcher(); + var prevCacheDispatcher = pushCacheDispatcher(); // If the root or lanes have changed, throw out the existing stack + // and prepare a fresh one. Otherwise we'll continue where we left off. + + if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) { + { + 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); } } - function popDispatcher(prevDispatcher) { - ReactSharedInternals.H = prevDispatcher; - } + workInProgressTransitions = getTransitionsForLanes(); + prepareFreshStack(root, lanes); + } + + { + markRenderStarted(lanes); + } + + var didSuspendInShell = false; + + 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; + + 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; + } + + case SuspendedOnImmediate: + case SuspendedOnData: + { + if (!didSuspendInShell && getSuspenseHandler() === null) { + didSuspendInShell = true; + } // Intentional fallthrough - function pushCacheDispatcher() { - { - var prevCacheDispatcher = ReactSharedInternals.C; - ReactSharedInternals.C = DefaultCacheDispatcher; - return prevCacheDispatcher; - } - } + } - function popCacheDispatcher(prevCacheDispatcher) { - { - ReactSharedInternals.C = prevCacheDispatcher; + default: + { + // Unwind then continue with the normal work loop. + workInProgressSuspendedReason = NotSuspended; + workInProgressThrownValue = null; + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); + break; + } + } } - } - function markCommitTimeOfFallback() { - globalMostRecentFallbackTime = now$1(); - } - function markSkippedUpdateLanes(lane) { - workInProgressRootSkippedLanes = mergeLanes( - lane, - workInProgressRootSkippedLanes - ); - } - function renderDidSuspend() { - if (workInProgressRootExitStatus === RootInProgress) { - workInProgressRootExitStatus = RootSuspended; - } + workLoopSync(); + break; + } catch (thrownValue) { + handleThrow(root, thrownValue); } - function renderDidSuspendDelayIfPossible() { - workInProgressRootExitStatus = RootSuspendedWithDelay; // Check if there are updates that we skipped tree that might have unblocked - // this render. + } while (true); // Check if something suspended in the shell. We use this to detect an + // infinite ping loop caused by an uncached promise. + // + // Only increment this counter once per synchronous render attempt across the + // whole tree. Even if there are many sibling components that suspend, this + // counter only gets incremented once. - if ( - (includesNonIdleWork(workInProgressRootSkippedLanes) || - includesNonIdleWork(workInProgressRootInterleavedUpdatedLanes)) && - workInProgressRoot !== null - ) { - // 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. - markRootSuspended( - workInProgressRoot, - workInProgressRootRenderLanes, - workInProgressDeferredLane - ); - } - } - function renderDidError() { - if (workInProgressRootExitStatus !== RootSuspendedWithDelay) { - workInProgressRootExitStatus = RootErrored; - } - } - function queueConcurrentError(error) { - 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. - - 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. - - function renderRootSync(root, lanes) { - var prevExecutionContext = executionContext; - executionContext |= RenderContext; - var prevDispatcher = pushDispatcher(); - var prevCacheDispatcher = pushCacheDispatcher(); // If the root or lanes have changed, throw out the existing stack - // and prepare a fresh one. Otherwise we'll continue where we left off. - - if ( - workInProgressRoot !== root || - workInProgressRootRenderLanes !== lanes - ) { - { - 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(); - prepareFreshStack(root, lanes); - } + if (didSuspendInShell) { + root.shellSuspendCounter++; + } - { - markRenderStarted(lanes); - } + resetContextDependencies(); + executionContext = prevExecutionContext; + popDispatcher(prevDispatcher); + popCacheDispatcher(prevCacheDispatcher); - var didSuspendInShell = false; + 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.'); + } - 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; - - 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; - } + { + markRenderStopped(); + } // Set this to null to indicate there's no in-progress render. - case SuspendedOnImmediate: - case SuspendedOnData: { - if (!didSuspendInShell && getSuspenseHandler() === null) { - didSuspendInShell = true; - } // Intentional fallthrough - } - default: { - // Unwind then continue with the normal work loop. - workInProgressSuspendedReason = NotSuspended; - workInProgressThrownValue = null; - throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); - break; - } - } - } + workInProgressRoot = null; + workInProgressRootRenderLanes = NoLanes; // It's safe to process the queue now that the render phase is complete. - workLoopSync(); - break; - } catch (thrownValue) { - handleThrow(root, thrownValue); - } - } while (true); // Check if something suspended in the shell. We use this to detect an - // infinite ping loop caused by an uncached promise. - // - // Only increment this counter once per synchronous render attempt across the - // whole tree. Even if there are many sibling components that suspend, this - // counter only gets incremented once. + finishQueueingConcurrentUpdates(); + return workInProgressRootExitStatus; +} // The work loop is an extremely hot path. Tell Closure not to inline it. - if (didSuspendInShell) { - root.shellSuspendCounter++; - } +/** @noinline */ - resetContextDependencies(); - executionContext = prevExecutionContext; - popDispatcher(prevDispatcher); - popCacheDispatcher(prevCacheDispatcher); - 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." - ); - } +function workLoopSync() { + // Perform work without checking if we need to yield between fiber. + while (workInProgress !== null) { + performUnitOfWork(workInProgress); + } +} - { - markRenderStopped(); - } // Set this to null to indicate there's no in-progress render. +function renderRootConcurrent(root, lanes) { + var prevExecutionContext = executionContext; + executionContext |= RenderContext; + var prevDispatcher = pushDispatcher(); + var prevCacheDispatcher = pushCacheDispatcher(); // If the root or lanes have changed, throw out the existing stack + // and prepare a fresh one. Otherwise we'll continue where we left off. - workInProgressRoot = null; - workInProgressRootRenderLanes = NoLanes; // It's safe to process the queue now that the render phase is complete. + if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) { + { + if (isDevToolsPresent) { + var memoizedUpdaters = root.memoizedUpdaters; - finishQueueingConcurrentUpdates(); - return workInProgressRootExitStatus; - } // The work loop is an extremely hot path. Tell Closure not to inline it. + 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. - /** @noinline */ - function workLoopSync() { - // Perform work without checking if we need to yield between fiber. - while (workInProgress !== null) { - performUnitOfWork(workInProgress); + movePendingFibersToMemoized(root, lanes); } } - function renderRootConcurrent(root, lanes) { - var prevExecutionContext = executionContext; - executionContext |= RenderContext; - var prevDispatcher = pushDispatcher(); - var prevCacheDispatcher = pushCacheDispatcher(); // If the root or lanes have changed, throw out the existing stack - // and prepare a fresh one. Otherwise we'll continue where we left off. + workInProgressTransitions = getTransitionsForLanes(); + resetRenderTimer(); + prepareFreshStack(root, lanes); + } - if ( - workInProgressRoot !== root || - workInProgressRootRenderLanes !== lanes - ) { - { - 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); - } - } + { + markRenderStarted(lanes); + } - workInProgressTransitions = getTransitionsForLanes(); - resetRenderTimer(); - prepareFreshStack(root, lanes); - } + 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; - { - markRenderStarted(lanes); - } + resumeOrUnwind: switch (workInProgressSuspendedReason) { + case SuspendedOnError: + { + // Unwind then continue with the normal work loop. + workInProgressSuspendedReason = NotSuspended; + workInProgressThrownValue = null; + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); + break; + } - 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; - - resumeOrUnwind: switch (workInProgressSuspendedReason) { - case SuspendedOnError: { - // Unwind then continue with the normal work loop. + case SuspendedOnData: + { + var thenable = thrownValue; + + if (isThenableResolved(thenable)) { + // The data resolved. Try rendering the component again. workInProgressSuspendedReason = NotSuspended; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); + 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. - case SuspendedOnData: { - var thenable = thrownValue; - 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. - - 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. - - ensureRootIsScheduled(root); - }; - - thenable.then(onResolution, onResolution); - break outer; - } + 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. - 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; - } + ensureRootIsScheduled(root); + }; - case SuspendedAndReadyToContinue: { - var _thenable = thrownValue; + thenable.then(onResolution, onResolution); + break outer; + } - 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(root, unitOfWork, thrownValue); - } + 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; + } - break; + 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(root, unitOfWork, thrownValue); } - case SuspendedOnInstanceAndReadyToContinue: { - switch (workInProgress.tag) { - case HostComponent: - case HostHoistable: - case HostSingleton: { + 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. @@ -27895,4153 +23941,3584 @@ to return true:wantsResponderID| | break; } - default: { + 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." - ); + error('Unexpected type of fiber triggered a suspensey commit. ' + 'This is a bug in React.'); } break; } - } // Otherwise, unwind then continue with the normal work loop. - - workInProgressSuspendedReason = NotSuspended; - workInProgressThrownValue = null; - throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); - break; - } - - 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(root, unitOfWork, thrownValue); - break; - } + } // Otherwise, unwind then continue with the normal work loop. - 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; - } - default: { - throw new Error( - "Unexpected SuspendedReason. This is a bug in React." - ); - } + workInProgressSuspendedReason = NotSuspended; + workInProgressThrownValue = null; + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); + break; } - } - - if (true && ReactSharedInternals.actQueue !== 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(); - } - break; - } catch (thrownValue) { - handleThrow(root, thrownValue); - } - } while (true); + 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(root, unitOfWork, thrownValue); + break; + } - resetContextDependencies(); - popDispatcher(prevDispatcher); - popCacheDispatcher(prevCacheDispatcher); - executionContext = prevExecutionContext; + 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 (workInProgress !== null) { - // Still work remaining. - { - markRenderYielded(); + default: + { + throw new Error('Unexpected SuspendedReason. This is a bug in React.'); + } } + } - return RootInProgress; + if (true && ReactSharedInternals.actQueue !== 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 { - // Completed the tree. - { - 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. - - finishQueueingConcurrentUpdates(); // Return the final exit status. - - return workInProgressRootExitStatus; + workLoopConcurrent(); } - } - /** @noinline */ - function workLoopConcurrent() { - // Perform work until Scheduler asks us to yield - while (workInProgress !== null && !shouldYield()) { - // $FlowFixMe[incompatible-call] found when upgrading Flow - performUnitOfWork(workInProgress); - } + break; + } catch (thrownValue) { + handleThrow(root, thrownValue); } + } while (true); - 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; + resetContextDependencies(); + popDispatcher(prevDispatcher); + popCacheDispatcher(prevCacheDispatcher); + executionContext = prevExecutionContext; - if ((unitOfWork.mode & ProfileMode) !== NoMode) { - startProfilerTimer(unitOfWork); - next = beginWork(current, unitOfWork, entangledRenderLanes); - stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true); - } else { - next = beginWork(current, unitOfWork, entangledRenderLanes); - } - resetCurrentFiber(); - unitOfWork.memoizedProps = unitOfWork.pendingProps; + if (workInProgress !== null) { + // Still work remaining. + { + markRenderYielded(); + } - if (next === null) { - // If this doesn't spawn new work, complete the current work. - completeUnitOfWork(unitOfWork); - } else { - workInProgress = next; - } + return RootInProgress; + } else { + // Completed the tree. + { + markRenderStopped(); + } // Set this to null to indicate there's no in-progress render. - { - ReactSharedInternals.owner = null; - } - } - 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; + workInProgressRoot = null; + workInProgressRootRenderLanes = NoLanes; // It's safe to process the queue now that the render phase is complete. - if (isProfilingMode) { - startProfilerTimer(unitOfWork); - } + finishQueueingConcurrentUpdates(); // Return the final exit status. - switch (unitOfWork.tag) { - case SimpleMemoComponent: - case FunctionComponent: { - // 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 = - disableDefaultPropsExceptForClasses || - unitOfWork.elementType === Component - ? unresolvedProps - : resolveDefaultPropsOnNonClassComponent( - Component, - unresolvedProps - ); - var context; + return workInProgressRootExitStatus; + } +} +/** @noinline */ - { - var unmaskedContext = getUnmaskedContext( - unitOfWork, - Component, - true - ); - context = getMaskedContext(unitOfWork, unmaskedContext); - } - next = replayFunctionComponent( - current, - unitOfWork, - resolvedProps, - Component, - context, - workInProgressRootRenderLanes - ); - break; - } +function workLoopConcurrent() { + // Perform work until Scheduler asks us to yield + while (workInProgress !== null && !shouldYield()) { + // $FlowFixMe[incompatible-call] found when upgrading Flow + performUnitOfWork(workInProgress); + } +} - 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.render; - var _unresolvedProps = unitOfWork.pendingProps; - - var _resolvedProps = - disableDefaultPropsExceptForClasses || - unitOfWork.elementType === _Component - ? _unresolvedProps - : resolveDefaultPropsOnNonClassComponent( - _Component, - _unresolvedProps - ); - - next = replayFunctionComponent( - current, - unitOfWork, - _resolvedProps, - _Component, - unitOfWork.ref, - workInProgressRootRenderLanes - ); - break; - } +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; + + if ((unitOfWork.mode & ProfileMode) !== NoMode) { + startProfilerTimer(unitOfWork); + next = beginWork(current, unitOfWork, entangledRenderLanes); + stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true); + } else { + next = beginWork(current, unitOfWork, entangledRenderLanes); + } + + resetCurrentFiber(); + unitOfWork.memoizedProps = unitOfWork.pendingProps; + + if (next === null) { + // If this doesn't spawn new work, complete the current work. + completeUnitOfWork(unitOfWork); + } else { + workInProgress = next; + } + + { + ReactSharedInternals.owner = null; + } +} - case HostComponent: { - // Some host components are stateful (that's how we implement form - // actions) but we don't bother to reuse the memoized state because it's - // not worth the extra code. The main reason to reuse the previous hooks - // is to reuse uncached promises, but we happen to know that the only - // promises that a host component might suspend on are definitely cached - // because they are controlled by us. So don't bother. - resetHooksOnUnwind(unitOfWork); // Fallthrough to the next branch. - } +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; + + if (isProfilingMode) { + startProfilerTimer(unitOfWork); + } + + switch (unitOfWork.tag) { + case SimpleMemoComponent: + case FunctionComponent: + { + // 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 = disableDefaultPropsExceptForClasses || unitOfWork.elementType === Component ? unresolvedProps : resolveDefaultPropsOnNonClassComponent(Component, unresolvedProps); + var context; - 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, - entangledRenderLanes - ); - next = beginWork(current, unitOfWork, entangledRenderLanes); - break; + { + var unmaskedContext = getUnmaskedContext(unitOfWork, Component, true); + context = getMaskedContext(unitOfWork, unmaskedContext); } + + next = replayFunctionComponent(current, unitOfWork, resolvedProps, Component, context, workInProgressRootRenderLanes); + break; } - if (isProfilingMode) { - stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true); - } // The begin phase finished successfully without suspending. Return to the - // normal work loop. + 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.render; + var _unresolvedProps = unitOfWork.pendingProps; - resetCurrentFiber(); - unitOfWork.memoizedProps = unitOfWork.pendingProps; + var _resolvedProps = disableDefaultPropsExceptForClasses || unitOfWork.elementType === _Component ? _unresolvedProps : resolveDefaultPropsOnNonClassComponent(_Component, _unresolvedProps); - if (next === null) { - // If this doesn't spawn new work, complete the current work. - completeUnitOfWork(unitOfWork); - } else { - workInProgress = next; + next = replayFunctionComponent(current, unitOfWork, _resolvedProps, _Component, unitOfWork.ref, workInProgressRootRenderLanes); + break; } + case HostComponent: { - ReactSharedInternals.owner = null; - } - } - - function throwAndUnwindWorkLoop(root, 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(unitOfWork); - var returnFiber = unitOfWork.return; - - try { - // Find and mark the nearest Suspense or error boundary that can handle - // this "exception". - var didFatal = throwException( - root, - returnFiber, - unitOfWork, - thrownValue, - workInProgressRootRenderLanes - ); - - if (didFatal) { - panicOnRootError(root, thrownValue); - return; - } - } 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. - if (returnFiber !== null) { - workInProgress = returnFiber; - throw error; - } else { - panicOnRootError(root, thrownValue); - return; - } + // Some host components are stateful (that's how we implement form + // actions) but we don't bother to reuse the memoized state because it's + // not worth the extra code. The main reason to reuse the previous hooks + // is to reuse uncached promises, but we happen to know that the only + // promises that a host component might suspend on are definitely cached + // because they are controlled by us. So don't bother. + resetHooksOnUnwind(unitOfWork); // Fallthrough to the next branch. } - 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. + 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. // - // 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); + // 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, entangledRenderLanes); + next = beginWork(current, unitOfWork, entangledRenderLanes); + break; } - } - - function panicOnRootError(root, error) { - // There's no ancestor that can handle this exception. This should never - // happen because the root is supposed to capture all errors that weren't - // caught by an error boundary. This is a fatal error, or panic condition, - // because we've run out of ways to recover. - workInProgressRootExitStatus = RootFatalErrored; - logUncaughtError(root, createCapturedValueAtFiber(error, root.current)); // 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. - - workInProgress = null; - } - - 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; - - 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." - ); - } - } // 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; - - if ((completedWork.mode & ProfileMode) === NoMode) { - next = completeWork(current, completedWork, entangledRenderLanes); - } else { - startProfilerTimer(completedWork); - next = completeWork(current, completedWork, entangledRenderLanes); // Update render duration assuming we didn't error. + if (isProfilingMode) { + stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true); + } // The begin phase finished successfully without suspending. Return to the + // normal work loop. - stopProfilerTimerIfRunningAndRecordDelta(completedWork, false); - } - resetCurrentFiber(); + resetCurrentFiber(); + unitOfWork.memoizedProps = unitOfWork.pendingProps; - if (next !== null) { - // Completing this fiber spawned new work. Work on that next. - workInProgress = next; - return; - } + if (next === null) { + // If this doesn't spawn new work, complete the current work. + completeUnitOfWork(unitOfWork); + } else { + workInProgress = next; + } - var siblingFiber = completedWork.sibling; + { + ReactSharedInternals.owner = null; + } +} - 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 throwAndUnwindWorkLoop(root, 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(unitOfWork); + var returnFiber = unitOfWork.return; + + try { + // Find and mark the nearest Suspense or error boundary that can handle + // this "exception". + var didFatal = throwException(root, returnFiber, unitOfWork, thrownValue, workInProgressRootRenderLanes); + + if (didFatal) { + panicOnRootError(root, thrownValue); + return; + } + } 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. + if (returnFiber !== null) { + workInProgress = returnFiber; + throw error; + } else { + panicOnRootError(root, 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); + } +} - completedWork = returnFiber; // Update the next thing we're working on in case something throws. +function panicOnRootError(root, error) { + // There's no ancestor that can handle this exception. This should never + // happen because the root is supposed to capture all errors that weren't + // caught by an error boundary. This is a fatal error, or panic condition, + // because we've run out of ways to recover. + workInProgressRootExitStatus = RootFatalErrored; + logUncaughtError(root, createCapturedValueAtFiber(error, root.current)); // 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. + + workInProgress = null; +} - workInProgress = completedWork; - } while (completedWork !== null); // We've reached the root. +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 (workInProgressRootExitStatus === RootInProgress) { - workInProgressRootExitStatus = RootCompleted; + 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."); } - } - - function unwindUnitOfWork(unitOfWork) { - var incompleteWork = 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. - 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. - - var next = unwindWork(current, incompleteWork); // Because this fiber did not complete, don't reset its lanes. - - 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. - - 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. - var actualDuration = incompleteWork.actualDuration; - var child = incompleteWork.child; + var current = completedWork.alternate; + var returnFiber = completedWork.return; + setCurrentFiber(completedWork); + var next = void 0; - while (child !== null) { - // $FlowFixMe[unsafe-addition] addition with possible null/undefined value - actualDuration += child.actualDuration; - child = child.sibling; - } - - 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; - - 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; - } // NOTE: If we re-enable sibling prerendering in some cases, here we - // would switch to the normal completion path: check if a sibling - // exists, and if so, begin work on it. - // Otherwise, return to the parent - // $FlowFixMe[incompatible-type] we bail out when we get a null - - incompleteWork = returnFiber; // Update the next thing we're working on in case something throws. - - workInProgress = incompleteWork; - } while (incompleteWork !== null); // We've unwound all the way to the root. - - workInProgressRootExitStatus = RootDidNotComplete; - workInProgress = null; - } - - function commitRoot( - root, - recoverableErrors, - transitions, - didIncludeRenderPhaseUpdate, - spawnedLane - ) { - // TODO: This no longer makes any sense. We already wrap the mutation and - // layout phases. Should be able to remove. - var prevTransition = ReactSharedInternals.T; - var previousUpdateLanePriority = getCurrentUpdatePriority(); - - try { - setCurrentUpdatePriority(DiscreteEventPriority); - ReactSharedInternals.T = null; - commitRootImpl( - root, - recoverableErrors, - transitions, - didIncludeRenderPhaseUpdate, - previousUpdateLanePriority, - spawnedLane - ); - } finally { - ReactSharedInternals.T = prevTransition; - setCurrentUpdatePriority(previousUpdateLanePriority); - } + if ((completedWork.mode & ProfileMode) === NoMode) { + next = completeWork(current, completedWork, entangledRenderLanes); + } else { + startProfilerTimer(completedWork); + next = completeWork(current, completedWork, entangledRenderLanes); // Update render duration assuming we didn't error. - return null; + stopProfilerTimerIfRunningAndRecordDelta(completedWork, false); } - function commitRootImpl( - root, - recoverableErrors, - transitions, - didIncludeRenderPhaseUpdate, - renderPriorityLevel, - spawnedLane - ) { - 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); + resetCurrentFiber(); - flushRenderPhaseStrictModeWarningsInDEV(); + if (next !== null) { + // Completing this fiber spawned new work. Work on that next. + workInProgress = next; + return; + } - if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { - throw new Error("Should not already be working."); - } + var siblingFiber = completedWork.sibling; - var finishedWork = root.finishedWork; - var lanes = root.finishedLanes; + 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 - { - markCommitStarted(lanes); - } - if (finishedWork === null) { - { - markCommitStopped(); - } + completedWork = returnFiber; // Update the next thing we're working on in case something throws. - return null; - } else { - { - if (lanes === NoLanes) { - error( - "root.finishedLanes should not be empty during a commit. This is a " + - "bug in React." - ); - } - } - } + workInProgress = completedWork; + } while (completedWork !== null); // We've reached the root. - root.finishedWork = null; - root.finishedLanes = NoLanes; - - 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. - - 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. - - 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. - - var concurrentlyUpdatedLanes = getConcurrentlyUpdatedLanes(); - remainingLanes = mergeLanes(remainingLanes, concurrentlyUpdatedLanes); - markRootFinished(root, remainingLanes, spawnedLane); // Reset this before firing side effects so we can detect recursive updates. - - didIncludeCommitPhaseUpdate = false; - - 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. - - if ( - (finishedWork.subtreeFlags & PassiveMask) !== NoFlags$1 || - (finishedWork.flags & PassiveMask) !== NoFlags$1 - ) { - if (!rootDoesHavePassiveEffects) { - rootDoesHavePassiveEffects = true; - pendingPassiveEffectsRemainingLanes = remainingLanes; // workInProgressTransitions might be overwritten, so we want - // to store it in pendingPassiveTransitions until they get processed - // We need to pass this through as an argument to commitRoot - // because workInProgressTransitions might have changed between - // the previous render and commit if we throttle the commit - // with setTimeout - - pendingPassiveTransitions = transitions; - scheduleCallback(NormalPriority$1, 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) - 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. - - var subtreeHasEffects = - (finishedWork.subtreeFlags & - (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !== - NoFlags$1; - var rootHasEffect = - (finishedWork.flags & - (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !== - NoFlags$1; - - if (subtreeHasEffects || rootHasEffect) { - var prevTransition = ReactSharedInternals.T; - ReactSharedInternals.T = null; - var previousPriority = getCurrentUpdatePriority(); - setCurrentUpdatePriority(DiscreteEventPriority); - var prevExecutionContext = executionContext; - executionContext |= CommitContext; // Reset this to null before calling lifecycles + if (workInProgressRootExitStatus === RootInProgress) { + workInProgressRootExitStatus = RootCompleted; + } +} - { - ReactSharedInternals.owner = 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. +function unwindUnitOfWork(unitOfWork) { + var incompleteWork = unitOfWork; - commitBeforeMutationEffects(root, finishedWork); + 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. - { - // Mark the current commit time to be shared by all Profilers in this - // batch. This enables them to be grouped later. - recordCommitTime(); - } // The next phase is the mutation phase, where we mutate the host tree. + var next = unwindWork(current, incompleteWork); // Because this fiber did not complete, don't reset its lanes. - 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 (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. - root.current = finishedWork; // The next phase is the layout phase, where we call effects that read - { - markLayoutEffectsStarted(lanes); - } + 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. - commitLayoutEffects(finishedWork, root, lanes); + var actualDuration = incompleteWork.actualDuration; + var child = incompleteWork.child; - { - markLayoutEffectsStopped(); - } // Tell Scheduler to yield at the end of the frame, so the browser has an - // opportunity to paint. + while (child !== null) { + // $FlowFixMe[unsafe-addition] addition with possible null/undefined value + actualDuration += child.actualDuration; + child = child.sibling; + } - requestPaint(); - executionContext = prevExecutionContext; // Reset the priority to the previous non-sync value. + 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. - setCurrentUpdatePriority(previousPriority); - ReactSharedInternals.T = 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(); - } - } + var returnFiber = incompleteWork.return; - var rootDidHavePassiveEffects = rootDoesHavePassiveEffects; + 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; + } // NOTE: If we re-enable sibling prerendering in some cases, here we + // would switch to the normal completion path: check if a sibling + // exists, and if so, begin work on it. + // Otherwise, return to the parent + // $FlowFixMe[incompatible-type] we bail out when we get a null - 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 { - // There were no passive effects, so we can immediately release the cache - // pool for this render. - releaseRootPooledCache(root, remainingLanes); - { - nestedPassiveUpdateCount = 0; - rootWithPassiveNestedUpdates = null; - } - } // Read this again, since an effect might have updated it + incompleteWork = returnFiber; // Update the next thing we're working on in case something throws. - 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. + workInProgress = incompleteWork; + } while (incompleteWork !== null); // We've unwound all the way to the root. - if (remainingLanes === NoLanes) { - // If there's no remaining work, we can clear the set of already failed - // error boundaries. - legacyErrorBoundariesThatAlreadyFailed = null; - } - { - if (!rootDidHavePassiveEffects) { - commitDoubleInvokeEffectsInDEV(root, false); - } - } + workInProgressRootExitStatus = RootDidNotComplete; + workInProgress = null; +} - onCommitRoot(finishedWork.stateNode, renderPriorityLevel); +function commitRoot(root, recoverableErrors, transitions, didIncludeRenderPhaseUpdate, spawnedLane) { + // TODO: This no longer makes any sense. We already wrap the mutation and + // layout phases. Should be able to remove. + var prevTransition = ReactSharedInternals.T; + var previousUpdateLanePriority = getCurrentUpdatePriority(); + + try { + setCurrentUpdatePriority(DiscreteEventPriority); + ReactSharedInternals.T = null; + commitRootImpl(root, recoverableErrors, transitions, didIncludeRenderPhaseUpdate, previousUpdateLanePriority, spawnedLane); + } finally { + ReactSharedInternals.T = prevTransition; + setCurrentUpdatePriority(previousUpdateLanePriority); + } + + return null; +} - { - if (isDevToolsPresent) { - root.memoizedUpdaters.clear(); - } - } - // additional work on this root is scheduled. +function commitRootImpl(root, recoverableErrors, transitions, didIncludeRenderPhaseUpdate, renderPriorityLevel, spawnedLane) { + 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); - ensureRootIsScheduled(root); + flushRenderPhaseStrictModeWarningsInDEV(); - 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 ((executionContext & (RenderContext | CommitContext)) !== NoContext) { + throw new Error('Should not already be working.'); + } - for (var i = 0; i < recoverableErrors.length; i++) { - var recoverableError = recoverableErrors[i]; - var errorInfo = makeErrorInfo(recoverableError.stack); - onRecoverableError(recoverableError.value, errorInfo); - } - } // 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. + var finishedWork = root.finishedWork; + var lanes = root.finishedLanes; - if ( - includesSyncLane(pendingPassiveEffectsLanes) && - root.tag !== LegacyRoot - ) { - flushPassiveEffects(); - } // Read this again, since a passive effect might have updated it - - remainingLanes = root.pendingLanes; // Check if this render scheduled a cascading synchronous update. This is a - // heurstic to detect infinite update loops. We are intentionally excluding - // hydration lanes in this check, because render triggered by selective - // hydration is conceptually not an update. - - if ( - // Check if there was a recursive update spawned by this render, in either - // the render phase or the commit phase. We track these explicitly because - // we can't infer from the remaining lanes alone. - (enableInfiniteRenderLoopDetection && - (didIncludeRenderPhaseUpdate || didIncludeCommitPhaseUpdate)) || // Was the finished render the result of an update (not hydration)? - (includesSomeLane(lanes, UpdateLanes) && // Did it schedule a sync update? - includesSomeLane(remainingLanes, SyncUpdateLanes)) - ) { - { - markNestedUpdateScheduled(); - } // Count the number of times the root synchronously re-renders without - // finishing. If there are too many, it indicates an infinite update loop. + { + markCommitStarted(lanes); + } - if (root === rootWithNestedUpdates) { - nestedUpdateCount++; - } else { - nestedUpdateCount = 0; - rootWithNestedUpdates = root; - } - } else { - nestedUpdateCount = 0; - } // If layout work was scheduled, flush it now. + if (finishedWork === null) { - flushSyncWorkOnAllRoots(); + { + markCommitStopped(); + } - { - markCommitStopped(); + return null; + } else { + { + if (lanes === NoLanes) { + error('root.finishedLanes should not be empty during a commit. This is a ' + 'bug in React.'); } - - return null; } + } - function makeErrorInfo(componentStack) { - var errorInfo = { - componentStack: componentStack - }; + root.finishedWork = null; + root.finishedLanes = NoLanes; - { - Object.defineProperty(errorInfo, "digest", { - get: function () { - error( - 'You are accessing "digest" from the errorInfo object passed to onRecoverableError.' + - " This property is no longer provided as part of errorInfo but can be accessed as a property" + - " of the Error instance itself." - ); - } - }); - } + 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. - return errorInfo; - } - function releaseRootPooledCache(root, remainingLanes) { - { - var pooledCacheLanes = (root.pooledCacheLanes &= remainingLanes); + 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 (pooledCacheLanes === NoLanes) { - // None of the remaining work relies on the cache pool. Clear it so - // subsequent requests get a new cache - var pooledCache = root.pooledCache; + 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. - if (pooledCache != null) { - root.pooledCache = null; - releaseCache(pooledCache); - } - } - } - } + var concurrentlyUpdatedLanes = getConcurrentlyUpdatedLanes(); + remainingLanes = mergeLanes(remainingLanes, concurrentlyUpdatedLanes); + markRootFinished(root, remainingLanes, spawnedLane); // Reset this before firing side effects so we can detect recursive updates. - 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) { - // Cache the root since rootWithPendingPassiveEffects is cleared in - // flushPassiveEffectsImpl - var root = rootWithPendingPassiveEffects; // Cache and clear the remaining lanes flag; it must be reset since this - // method can be called from various places, not always from commitRoot - // where the remaining lanes are known + didIncludeCommitPhaseUpdate = false; - var remainingLanes = pendingPassiveEffectsRemainingLanes; - pendingPassiveEffectsRemainingLanes = NoLanes; - var renderPriority = lanesToEventPriority(pendingPassiveEffectsLanes); - var priority = lowerEventPriority(DefaultEventPriority, renderPriority); - var prevTransition = ReactSharedInternals.T; - var previousPriority = getCurrentUpdatePriority(); + 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. - try { - setCurrentUpdatePriority(priority); - ReactSharedInternals.T = null; - return flushPassiveEffectsImpl(); - } finally { - setCurrentUpdatePriority(previousPriority); - ReactSharedInternals.T = prevTransition; // Once passive effects have run for the tree - giving components a - // chance to retain cache instances they use - release the pooled - // cache at the root (if there is one) - releaseRootPooledCache(root, remainingLanes); - } - } + if ((finishedWork.subtreeFlags & PassiveMask) !== NoFlags$1 || (finishedWork.flags & PassiveMask) !== NoFlags$1) { + if (!rootDoesHavePassiveEffects) { + rootDoesHavePassiveEffects = true; + pendingPassiveEffectsRemainingLanes = remainingLanes; // workInProgressTransitions might be overwritten, so we want + // to store it in pendingPassiveTransitions until they get processed + // We need to pass this through as an argument to commitRoot + // because workInProgressTransitions might have changed between + // the previous render and commit if we throttle the commit + // with setTimeout - return false; - } - function enqueuePendingPassiveProfilerEffect(fiber) { - { - pendingPassiveProfilerEffects.push(fiber); + pendingPassiveTransitions = transitions; + scheduleCallback(NormalPriority$1, 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) - if (!rootDoesHavePassiveEffects) { - rootDoesHavePassiveEffects = true; - scheduleCallback(NormalPriority$1, function () { - flushPassiveEffects(); - return null; - }); - } - } + 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. - function flushPassiveEffectsImpl() { - if (rootWithPendingPassiveEffects === null) { - return false; - } // Cache and clear the transitions flag - var transitions = pendingPassiveTransitions; - pendingPassiveTransitions = null; - 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. + var subtreeHasEffects = (finishedWork.subtreeFlags & (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !== NoFlags$1; + var rootHasEffect = (finishedWork.flags & (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !== NoFlags$1; - pendingPassiveEffectsLanes = NoLanes; + if (subtreeHasEffects || rootHasEffect) { + var prevTransition = ReactSharedInternals.T; + ReactSharedInternals.T = null; + var previousPriority = getCurrentUpdatePriority(); + setCurrentUpdatePriority(DiscreteEventPriority); + var prevExecutionContext = executionContext; + executionContext |= CommitContext; // Reset this to null before calling lifecycles - if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { - throw new Error( - "Cannot flush passive effects while already rendering." - ); - } + { + ReactSharedInternals.owner = 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. - { - isFlushingPassiveEffects = true; - didScheduleUpdateDuringPassiveEffects = false; - } - { - markPassiveEffectsStarted(lanes); - } + commitBeforeMutationEffects(root, finishedWork); - var prevExecutionContext = executionContext; - executionContext |= CommitContext; - commitPassiveUnmountEffects(root.current); - commitPassiveMountEffects(root, root.current, lanes, transitions); // TODO: Move to commitPassiveMountEffects + { + // Mark the current commit time to be shared by all Profilers in this + // batch. This enables them to be grouped later. + recordCommitTime(); + } // The next phase is the mutation phase, where we mutate the host tree. - { - var profilerEffects = pendingPassiveProfilerEffects; - pendingPassiveProfilerEffects = []; - for (var i = 0; i < profilerEffects.length; i++) { - var fiber = profilerEffects[i]; - commitPassiveEffectDurations(root, fiber); - } - } + 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. - { - markPassiveEffectsStopped(); - } + root.current = finishedWork; // The next phase is the layout phase, where we call effects that read - { - commitDoubleInvokeEffectsInDEV(root, true); - } + { + markLayoutEffectsStarted(lanes); + } - executionContext = prevExecutionContext; - flushSyncWorkOnAllRoots(); + commitLayoutEffects(finishedWork, root, lanes); - { - // 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 { - nestedPassiveUpdateCount = 0; - } + { + markLayoutEffectsStopped(); + } // Tell Scheduler to yield at the end of the frame, so the browser has an + // opportunity to paint. - isFlushingPassiveEffects = false; - didScheduleUpdateDuringPassiveEffects = false; - } // TODO: Move to commitPassiveMountEffects - onPostCommitRoot(root); + requestPaint(); + executionContext = prevExecutionContext; // Reset the priority to the previous non-sync value. - { - var stateNode = root.current.stateNode; - stateNode.effectDuration = 0; - stateNode.passiveEffectDuration = 0; - } + setCurrentUpdatePriority(previousPriority); + ReactSharedInternals.T = 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. - return true; + { + recordCommitTime(); } + } - function isAlreadyFailedLegacyErrorBoundary(instance) { - return ( - legacyErrorBoundariesThatAlreadyFailed !== null && - legacyErrorBoundariesThatAlreadyFailed.has(instance) - ); - } - function markLegacyErrorBoundaryAsFailed(instance) { - if (legacyErrorBoundariesThatAlreadyFailed === null) { - legacyErrorBoundariesThatAlreadyFailed = new Set([instance]); - } else { - legacyErrorBoundariesThatAlreadyFailed.add(instance); - } + 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 { + // There were no passive effects, so we can immediately release the cache + // pool for this render. + releaseRootPooledCache(root, remainingLanes); + + { + nestedPassiveUpdateCount = 0; + rootWithPassiveNestedUpdates = null; } + } // Read this again, since an effect might have updated it - function captureCommitPhaseErrorOnRoot(rootFiber, sourceFiber, error) { - var errorInfo = createCapturedValueAtFiber(error, sourceFiber); - var update = createRootErrorUpdate( - rootFiber.stateNode, - errorInfo, - SyncLane - ); - var root = enqueueUpdate(rootFiber, update, SyncLane); - if (root !== null) { - markRootUpdated(root, SyncLane); - ensureRootIsScheduled(root); - } + 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; + } + + { + if (!rootDidHavePassiveEffects) { + commitDoubleInvokeEffectsInDEV(root, false); } + } - function captureCommitPhaseError( - sourceFiber, - nearestMountedAncestor, - error$1 - ) { - { - setIsRunningInsertionEffect(false); - } + onCommitRoot(finishedWork.stateNode, renderPriorityLevel); - 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 (isDevToolsPresent) { + root.memoizedUpdaters.clear(); + } + } + // additional work on this root is scheduled. - var fiber = nearestMountedAncestor; - 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; + ensureRootIsScheduled(root); - if ( - typeof ctor.getDerivedStateFromError === "function" || - (typeof instance.componentDidCatch === "function" && - !isAlreadyFailedLegacyErrorBoundary(instance)) - ) { - var errorInfo = createCapturedValueAtFiber(error$1, sourceFiber); - var update = createClassErrorUpdate(SyncLane); - var root = enqueueUpdate(fiber, update, SyncLane); - - if (root !== null) { - initializeClassErrorUpdate(update, root, fiber, errorInfo); - markRootUpdated(root, SyncLane); - ensureRootIsScheduled(root); - } + 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; - return; - } - } + for (var i = 0; i < recoverableErrors.length; i++) { + var recoverableError = recoverableErrors[i]; + var errorInfo = makeErrorInfo(recoverableError.stack); + onRecoverableError(recoverableError.value, errorInfo); + } + } // 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. - fiber = fiber.return; - } - { - error( - "Internal React error: Attempted to capture a commit phase error " + - "inside a detached tree. This indicates a bug in React. Potential " + - "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; - - if (pingCache === null) { - pingCache = root.pingCache = new PossiblyWeakMap(); - threadIDs = new Set(); - pingCache.set(wakeable, threadIDs); - } else { - threadIDs = pingCache.get(wakeable); + if (includesSyncLane(pendingPassiveEffectsLanes) && (root.tag !== LegacyRoot)) { + flushPassiveEffects(); + } // Read this again, since a passive effect might have updated it - if (threadIDs === undefined) { - threadIDs = new Set(); - pingCache.set(wakeable, threadIDs); - } - } - if (!threadIDs.has(lanes)) { - workInProgressRootDidAttachPingListener = true; // Memoize using the thread ID to prevent redundant listeners. + remainingLanes = root.pendingLanes; // Check if this render scheduled a cascading synchronous update. This is a + // heurstic to detect infinite update loops. We are intentionally excluding + // hydration lanes in this check, because render triggered by selective + // hydration is conceptually not an update. - threadIDs.add(lanes); - var ping = pingSuspendedRoot.bind(null, root, wakeable, lanes); + if ( // Check if there was a recursive update spawned by this render, in either + // the render phase or the commit phase. We track these explicitly because + // we can't infer from the remaining lanes alone. + enableInfiniteRenderLoopDetection && (didIncludeRenderPhaseUpdate || didIncludeCommitPhaseUpdate) || // Was the finished render the result of an update (not hydration)? + includesSomeLane(lanes, UpdateLanes) && // Did it schedule a sync update? + includesSomeLane(remainingLanes, SyncUpdateLanes)) { + { + markNestedUpdateScheduled(); + } // Count the number of times the root synchronously re-renders without + // finishing. If there are too many, it indicates an infinite update loop. - { - if (isDevToolsPresent) { - // If we have pending work still, restore the original updaters - restorePendingUpdaters(root, lanes); - } - } - wakeable.then(ping, ping); - } + if (root === rootWithNestedUpdates) { + nestedUpdateCount++; + } else { + nestedUpdateCount = 0; + rootWithNestedUpdates = root; } + } else { + nestedUpdateCount = 0; + } // If layout work was scheduled, flush it now. - function pingSuspendedRoot(root, wakeable, pingedLanes) { - var pingCache = root.pingCache; - if (pingCache !== null) { - // The wakeable resolved, so we no longer need to memoize, because it will - // never be thrown again. - pingCache.delete(wakeable); - } + flushSyncWorkOnAllRoots(); - markRootPinged(root, pingedLanes); - warnIfSuspenseResolutionNotWrappedWithActDEV(root); + { + markCommitStopped(); + } - 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 null; +} + +function makeErrorInfo(componentStack) { + var errorInfo = { + componentStack: componentStack + }; + + { + Object.defineProperty(errorInfo, 'digest', { + get: function () { + error('You are accessing "digest" from the errorInfo object passed to onRecoverableError.' + ' This property is no longer provided as part of errorInfo but can be accessed as a property' + ' of the Error instance itself.'); } + }); + } - ensureRootIsScheduled(root); - } + return errorInfo; +} - 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? +function releaseRootPooledCache(root, remainingLanes) { + { + var pooledCacheLanes = root.pooledCacheLanes &= remainingLanes; - var root = enqueueConcurrentRenderForLane(boundaryFiber, retryLane); + if (pooledCacheLanes === NoLanes) { + // None of the remaining work relies on the cache pool. Clear it so + // subsequent requests get a new cache + var pooledCache = root.pooledCache; - if (root !== null) { - markRootUpdated(root, retryLane); - ensureRootIsScheduled(root); + if (pooledCache != null) { + root.pooledCache = null; + releaseCache(pooledCache); } } + } +} - function retryDehydratedSuspenseBoundary(boundaryFiber) { - var suspenseState = boundaryFiber.memoizedState; - var retryLane = NoLane; - - if (suspenseState !== null) { - retryLane = suspenseState.retryLane; - } +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) { + // Cache the root since rootWithPendingPassiveEffects is cleared in + // flushPassiveEffectsImpl + var root = rootWithPendingPassiveEffects; // Cache and clear the remaining lanes flag; it must be reset since this + // method can be called from various places, not always from commitRoot + // where the remaining lanes are known + + var remainingLanes = pendingPassiveEffectsRemainingLanes; + pendingPassiveEffectsRemainingLanes = NoLanes; + var renderPriority = lanesToEventPriority(pendingPassiveEffectsLanes); + var priority = lowerEventPriority(DefaultEventPriority, renderPriority); + var prevTransition = ReactSharedInternals.T; + var previousPriority = getCurrentUpdatePriority(); + + try { + setCurrentUpdatePriority(priority); + ReactSharedInternals.T = null; + return flushPassiveEffectsImpl(); + } finally { + setCurrentUpdatePriority(previousPriority); + ReactSharedInternals.T = prevTransition; // Once passive effects have run for the tree - giving components a + // chance to retain cache instances they use - release the pooled + // cache at the root (if there is one) + + releaseRootPooledCache(root, remainingLanes); + } + } + + return false; +} +function enqueuePendingPassiveProfilerEffect(fiber) { + { + pendingPassiveProfilerEffects.push(fiber); - retryTimedOutBoundary(boundaryFiber, retryLane); + if (!rootDoesHavePassiveEffects) { + rootDoesHavePassiveEffects = true; + scheduleCallback(NormalPriority$1, function () { + flushPassiveEffects(); + return null; + }); } - function resolveRetryWakeable(boundaryFiber, wakeable) { - var retryLane = NoLane; // Default + } +} - var retryCache; +function flushPassiveEffectsImpl() { + if (rootWithPendingPassiveEffects === null) { + return false; + } // Cache and clear the transitions flag - switch (boundaryFiber.tag) { - case SuspenseComponent: - retryCache = boundaryFiber.stateNode; - var suspenseState = boundaryFiber.memoizedState; - if (suspenseState !== null) { - retryLane = suspenseState.retryLane; - } + var transitions = pendingPassiveTransitions; + pendingPassiveTransitions = null; + 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. - break; + pendingPassiveEffectsLanes = NoLanes; - case SuspenseListComponent: - retryCache = boundaryFiber.stateNode; - break; + if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { + throw new Error('Cannot flush passive effects while already rendering.'); + } - case OffscreenComponent: { - var instance = boundaryFiber.stateNode; - retryCache = instance._retryCache; - break; - } + { + isFlushingPassiveEffects = true; + didScheduleUpdateDuringPassiveEffects = false; + } - default: - throw new Error( - "Pinged unknown suspense boundary type. " + - "This is probably a bug in React." - ); - } + { + markPassiveEffectsStarted(lanes); + } - if (retryCache !== null) { - // The wakeable resolved, so we no longer need to memoize, because it will - // never be thrown again. - retryCache.delete(wakeable); - } + var prevExecutionContext = executionContext; + executionContext |= CommitContext; + commitPassiveUnmountEffects(root.current); + commitPassiveMountEffects(root, root.current, lanes, transitions); // TODO: Move to commitPassiveMountEffects - retryTimedOutBoundary(boundaryFiber, retryLane); + { + var profilerEffects = pendingPassiveProfilerEffects; + pendingPassiveProfilerEffects = []; + + for (var i = 0; i < profilerEffects.length; i++) { + var fiber = profilerEffects[i]; + commitPassiveEffectDurations(root, fiber); } - function throwIfInfiniteUpdateLoopDetected() { - if (nestedUpdateCount > NESTED_UPDATE_LIMIT) { - nestedUpdateCount = 0; - nestedPassiveUpdateCount = 0; - rootWithNestedUpdates = null; - rootWithPassiveNestedUpdates = null; - - if (enableInfiniteRenderLoopDetection) { - if (executionContext & RenderContext && workInProgressRoot !== null) { - // We're in the render phase. Disable the concurrent error recovery - // mechanism to ensure that the error we're about to throw gets handled. - // We need it to trigger the nearest error boundary so that the infinite - // update loop is broken. - workInProgressRoot.errorRecoveryDisabledLanes = mergeLanes( - workInProgressRoot.errorRecoveryDisabledLanes, - workInProgressRootRenderLanes - ); - } - } + } - 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." - ); - } + { + markPassiveEffectsStopped(); + } - { - if (nestedPassiveUpdateCount > NESTED_PASSIVE_UPDATE_LIMIT) { - nestedPassiveUpdateCount = 0; - rootWithPassiveNestedUpdates = null; + { + commitDoubleInvokeEffectsInDEV(root, true); + } - 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." - ); - } - } - } + executionContext = prevExecutionContext; + flushSyncWorkOnAllRoots(); - function flushRenderPhaseStrictModeWarningsInDEV() { - { - ReactStrictModeWarnings.flushLegacyContextWarning(); - ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings(); - } - } - - function recursivelyTraverseAndDoubleInvokeEffectsInDEV( - root, - parentFiber, - isInStrictMode - ) { - if ( - (parentFiber.subtreeFlags & (PlacementDEV | Visibility)) === - NoFlags$1 - ) { - // Parent's descendants have already had effects double invoked. - // Early exit to avoid unnecessary tree traversal. - 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 { + nestedPassiveUpdateCount = 0; + } - var child = parentFiber.child; + isFlushingPassiveEffects = false; + didScheduleUpdateDuringPassiveEffects = false; + } // TODO: Move to commitPassiveMountEffects - while (child !== null) { - doubleInvokeEffectsInDEVIfNecessary(root, child, isInStrictMode); - child = child.sibling; - } - } // Unconditionally disconnects and connects passive and layout effects. - function doubleInvokeEffectsOnFiber(root, fiber) { - var shouldDoubleInvokePassiveEffects = - arguments.length > 2 && arguments[2] !== undefined - ? arguments[2] - : true; - disappearLayoutEffects(fiber); + onPostCommitRoot(root); - if (shouldDoubleInvokePassiveEffects) { - disconnectPassiveEffect(fiber); - } + { + var stateNode = root.current.stateNode; + stateNode.effectDuration = 0; + stateNode.passiveEffectDuration = 0; + } - reappearLayoutEffects(root, fiber.alternate, fiber, false); + return true; +} - if (shouldDoubleInvokePassiveEffects) { - reconnectPassiveEffects(root, fiber, NoLanes, null, false); - } - } +function isAlreadyFailedLegacyErrorBoundary(instance) { + return legacyErrorBoundariesThatAlreadyFailed !== null && legacyErrorBoundariesThatAlreadyFailed.has(instance); +} +function markLegacyErrorBoundaryAsFailed(instance) { + if (legacyErrorBoundariesThatAlreadyFailed === null) { + legacyErrorBoundariesThatAlreadyFailed = new Set([instance]); + } else { + legacyErrorBoundariesThatAlreadyFailed.add(instance); + } +} - function doubleInvokeEffectsInDEVIfNecessary( - root, - fiber, - parentIsInStrictMode - ) { - var isStrictModeFiber = fiber.type === REACT_STRICT_MODE_TYPE; - var isInStrictMode = parentIsInStrictMode || isStrictModeFiber; // First case: the fiber **is not** of type OffscreenComponent. No - // special rules apply to double invoking effects. +function captureCommitPhaseErrorOnRoot(rootFiber, sourceFiber, error) { + var errorInfo = createCapturedValueAtFiber(error, sourceFiber); + var update = createRootErrorUpdate(rootFiber.stateNode, errorInfo, SyncLane); + var root = enqueueUpdate(rootFiber, update, SyncLane); - if (fiber.tag !== OffscreenComponent) { - if (fiber.flags & PlacementDEV) { - setCurrentFiber(fiber); + if (root !== null) { + markRootUpdated(root, SyncLane); + ensureRootIsScheduled(root); + } +} - if (isInStrictMode) { - doubleInvokeEffectsOnFiber( - root, - fiber, - (fiber.mode & NoStrictPassiveEffectsMode) === NoMode - ); - } +function captureCommitPhaseError(sourceFiber, nearestMountedAncestor, 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; + } + + var fiber = nearestMountedAncestor; + + 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 (typeof ctor.getDerivedStateFromError === 'function' || typeof instance.componentDidCatch === 'function' && !isAlreadyFailedLegacyErrorBoundary(instance)) { + var errorInfo = createCapturedValueAtFiber(error$1, sourceFiber); + var update = createClassErrorUpdate(SyncLane); + var root = enqueueUpdate(fiber, update, SyncLane); - resetCurrentFiber(); - } else { - recursivelyTraverseAndDoubleInvokeEffectsInDEV( - root, - fiber, - isInStrictMode - ); + if (root !== null) { + initializeClassErrorUpdate(update, root, fiber, errorInfo); + markRootUpdated(root, SyncLane); + ensureRootIsScheduled(root); } return; - } // Second case: the fiber **is** of type OffscreenComponent. - // This branch contains cases specific to Offscreen. + } + } - if (fiber.memoizedState === null) { - // Only consider Offscreen that is visible. - // TODO (Offscreen) Handle manual mode. - setCurrentFiber(fiber); + fiber = fiber.return; + } - if (isInStrictMode && fiber.flags & Visibility) { - // Double invoke effects on Offscreen's subtree only - // if it is visible and its visibility has changed. - doubleInvokeEffectsOnFiber(root, fiber); - } else if (fiber.subtreeFlags & PlacementDEV) { - // Something in the subtree could have been suspended. - // We need to continue traversal and find newly inserted fibers. - recursivelyTraverseAndDoubleInvokeEffectsInDEV( - root, - fiber, - isInStrictMode - ); - } + { + error('Internal React error: Attempted to capture a commit phase error ' + 'inside a detached tree. This indicates a bug in React. Potential ' + '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; + + if (pingCache === null) { + pingCache = root.pingCache = new PossiblyWeakMap(); + threadIDs = new Set(); + pingCache.set(wakeable, threadIDs); + } else { + threadIDs = pingCache.get(wakeable); + + if (threadIDs === undefined) { + threadIDs = new Set(); + pingCache.set(wakeable, threadIDs); + } + } + + if (!threadIDs.has(lanes)) { + workInProgressRootDidAttachPingListener = true; // Memoize using the thread ID to prevent redundant listeners. + + threadIDs.add(lanes); + var ping = pingSuspendedRoot.bind(null, root, wakeable, lanes); - resetCurrentFiber(); + { + if (isDevToolsPresent) { + // If we have pending work still, restore the original updaters + restorePendingUpdaters(root, lanes); } } - function commitDoubleInvokeEffectsInDEV(root, hasPassiveEffects) { - { - if (useModernStrictMode && root.tag !== LegacyRoot) { - var doubleInvokeEffects = true; - - if ( - root.tag === ConcurrentRoot && - !(root.current.mode & (StrictLegacyMode | StrictEffectsMode)) - ) { - doubleInvokeEffects = false; - } + wakeable.then(ping, ping); + } +} - recursivelyTraverseAndDoubleInvokeEffectsInDEV( - root, - root.current, - doubleInvokeEffects - ); - } else { - legacyCommitDoubleInvokeEffectsInDEV(root.current, hasPassiveEffects); - } +function pingSuspendedRoot(root, wakeable, pingedLanes) { + var pingCache = root.pingCache; + + if (pingCache !== null) { + // The wakeable resolved, so we no longer need to memoize, because it will + // never be thrown again. + pingCache.delete(wakeable); + } + + markRootPinged(root, pingedLanes); + warnIfSuspenseResolutionNotWrappedWithActDEV(root); + + 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); } + } - 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 - ); - } + ensureRootIsScheduled(root); +} - invokeEffectsInDev(fiber, MountLayoutDev, invokeLayoutEffectMountInDEV); +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 (hasPassiveEffects) { - invokeEffectsInDev( - fiber, - MountPassiveDev, - invokePassiveEffectMountInDEV - ); - } - resetCurrentFiber(); - } + var root = enqueueConcurrentRenderForLane(boundaryFiber, retryLane); - function invokeEffectsInDev(firstChild, fiberFlags, invokeEffectFn) { - var current = firstChild; - var subtreeRoot = null; + if (root !== null) { + markRootUpdated(root, retryLane); + ensureRootIsScheduled(root); + } +} - while (current != null) { - var primarySubtreeFlag = current.subtreeFlags & fiberFlags; +function retryDehydratedSuspenseBoundary(boundaryFiber) { + var suspenseState = boundaryFiber.memoizedState; + var retryLane = NoLane; - if ( - current !== subtreeRoot && - current.child != null && - primarySubtreeFlag !== NoFlags$1 - ) { - current = current.child; - } else { - if ((current.flags & fiberFlags) !== NoFlags$1) { - invokeEffectFn(current); - } + if (suspenseState !== null) { + retryLane = suspenseState.retryLane; + } - if (current.sibling !== null) { - current = current.sibling; - } else { - current = subtreeRoot = current.return; - } - } - } - } + retryTimedOutBoundary(boundaryFiber, retryLane); +} +function resolveRetryWakeable(boundaryFiber, wakeable) { + var retryLane = NoLane; // Default - var didWarnStateUpdateForNotYetMountedComponent = null; - function warnAboutUpdateOnNotYetMountedFiberInDEV(fiber) { - { - if ((executionContext & RenderContext) !== NoContext) { - // We let the other warning about render phase updates deal with this one. - return; - } + var retryCache; - if (!(fiber.mode & ConcurrentMode)) { - return; - } + switch (boundaryFiber.tag) { + case SuspenseComponent: + retryCache = boundaryFiber.stateNode; + var suspenseState = boundaryFiber.memoizedState; - var tag = fiber.tag; + if (suspenseState !== null) { + retryLane = suspenseState.retryLane; + } - if ( - 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. + break; - var componentName = - getComponentNameFromFiber(fiber) || "ReactComponent"; + case SuspenseListComponent: + retryCache = boundaryFiber.stateNode; + break; - if (didWarnStateUpdateForNotYetMountedComponent !== null) { - if (didWarnStateUpdateForNotYetMountedComponent.has(componentName)) { - return; - } // $FlowFixMe[incompatible-use] found when upgrading Flow + case OffscreenComponent: + { + var instance = boundaryFiber.stateNode; + retryCache = instance._retryCache; + break; + } - didWarnStateUpdateForNotYetMountedComponent.add(componentName); - } else { - didWarnStateUpdateForNotYetMountedComponent = new Set([ - componentName - ]); - } + default: + throw new Error('Pinged unknown suspense boundary type. ' + 'This is probably a bug in React.'); + } - var previousFiber = current; + if (retryCache !== null) { + // The wakeable resolved, so we no longer need to memoize, because it will + // never be thrown again. + retryCache.delete(wakeable); + } - try { - setCurrentFiber(fiber); + retryTimedOutBoundary(boundaryFiber, retryLane); +} +function throwIfInfiniteUpdateLoopDetected() { + if (nestedUpdateCount > NESTED_UPDATE_LIMIT) { + nestedUpdateCount = 0; + nestedPassiveUpdateCount = 0; + rootWithNestedUpdates = null; + rootWithPassiveNestedUpdates = null; - 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(); - } - } + if (enableInfiniteRenderLoopDetection) { + if (executionContext & RenderContext && workInProgressRoot !== null) { + // We're in the render phase. Disable the concurrent error recovery + // mechanism to ensure that the error we're about to throw gets handled. + // We need it to trigger the nearest error boundary so that the infinite + // update loop is broken. + workInProgressRoot.errorRecoveryDisabledLanes = mergeLanes(workInProgressRoot.errorRecoveryDisabledLanes, workInProgressRootRenderLanes); } } - var didWarnAboutUpdateInRender = false; - var didWarnAboutUpdateInRenderForAnotherComponent; - { - didWarnAboutUpdateInRenderForAnotherComponent = new Set(); + 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 (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.'); } + } +} - 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. - - var dedupeKey = renderingComponentName; - - 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://react.dev/link/setstate-in-render", - setStateComponentName, - renderingComponentName, - renderingComponentName - ); - } +function flushRenderPhaseStrictModeWarningsInDEV() { + { + ReactStrictModeWarnings.flushLegacyContextWarning(); + ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings(); + } +} - break; - } +function recursivelyTraverseAndDoubleInvokeEffectsInDEV(root, parentFiber, isInStrictMode) { + if ((parentFiber.subtreeFlags & (PlacementDEV | Visibility)) === NoFlags$1) { + // Parent's descendants have already had effects double invoked. + // Early exit to avoid unnecessary tree traversal. + return; + } - 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." - ); + var child = parentFiber.child; - didWarnAboutUpdateInRender = true; - } + while (child !== null) { + doubleInvokeEffectsInDEVIfNecessary(root, child, isInStrictMode); + child = child.sibling; + } +} // Unconditionally disconnects and connects passive and layout effects. - break; - } - } - } + +function doubleInvokeEffectsOnFiber(root, fiber) { + var shouldDoubleInvokePassiveEffects = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true; + disappearLayoutEffects(fiber); + + if (shouldDoubleInvokePassiveEffects) { + disconnectPassiveEffect(fiber); + } + + reappearLayoutEffects(root, fiber.alternate, fiber, false); + + if (shouldDoubleInvokePassiveEffects) { + reconnectPassiveEffects(root, fiber, NoLanes, null, false); + } +} + +function doubleInvokeEffectsInDEVIfNecessary(root, fiber, parentIsInStrictMode) { + var isStrictModeFiber = fiber.type === REACT_STRICT_MODE_TYPE; + var isInStrictMode = parentIsInStrictMode || isStrictModeFiber; // First case: the fiber **is not** of type OffscreenComponent. No + // special rules apply to double invoking effects. + + if (fiber.tag !== OffscreenComponent) { + if (fiber.flags & PlacementDEV) { + setCurrentFiber(fiber); + + if (isInStrictMode) { + doubleInvokeEffectsOnFiber(root, fiber, (fiber.mode & NoStrictPassiveEffectsMode) === NoMode); } + + resetCurrentFiber(); + } else { + recursivelyTraverseAndDoubleInvokeEffectsInDEV(root, fiber, isInStrictMode); } - 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). - } - } + return; + } // Second case: the fiber **is** of type OffscreenComponent. + // This branch contains cases specific to Offscreen. + + + if (fiber.memoizedState === null) { + // Only consider Offscreen that is visible. + // TODO (Offscreen) Handle manual mode. + setCurrentFiber(fiber); + + if (isInStrictMode && fiber.flags & Visibility) { + // Double invoke effects on Offscreen's subtree only + // if it is visible and its visibility has changed. + doubleInvokeEffectsOnFiber(root, fiber); + } else if (fiber.subtreeFlags & PlacementDEV) { + // Something in the subtree could have been suspended. + // We need to continue traversal and find newly inserted fibers. + recursivelyTraverseAndDoubleInvokeEffectsInDEV(root, fiber, isInStrictMode); } - var fakeActCallbackNode = {}; // $FlowFixMe[missing-local-annot] - function scheduleCallback(priorityLevel, callback) { - { - // If we're currently inside an `act` scope, bypass Scheduler and push to - // the `act` queue instead. - var actQueue = ReactSharedInternals.actQueue; + resetCurrentFiber(); + } +} - if (actQueue !== null) { - actQueue.push(callback); - return fakeActCallbackNode; - } else { - return scheduleCallback$3(priorityLevel, callback); - } +function commitDoubleInvokeEffectsInDEV(root, hasPassiveEffects) { + { + if (useModernStrictMode && (root.tag !== LegacyRoot)) { + var doubleInvokeEffects = true; + + if ((root.tag === ConcurrentRoot) && !(root.current.mode & (StrictLegacyMode | StrictEffectsMode))) { + doubleInvokeEffects = false; } - } - function shouldForceFlushFallbacksInDEV() { - // Never force flush in production. This function should get stripped out. - return ReactSharedInternals.actQueue !== null; + recursivelyTraverseAndDoubleInvokeEffectsInDEV(root, root.current, doubleInvokeEffects); + } else { + legacyCommitDoubleInvokeEffectsInDEV(root.current, hasPassiveEffects); } + } +} - 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; - } +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 (executionContext !== NoContext) { - // Legacy mode doesn't warn if the update is batched, i.e. - // batchedUpdates or flushSync. - return; - } + if (hasPassiveEffects) { + invokeEffectsInDev(fiber, MountPassiveDev, invokePassiveEffectUnmountInDEV); + } - 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; - } - } + invokeEffectsInDev(fiber, MountLayoutDev, invokeLayoutEffectMountInDEV); - if (ReactSharedInternals.actQueue === null) { - var previousFiber = current; + if (hasPassiveEffects) { + invokeEffectsInDev(fiber, MountPassiveDev, invokePassiveEffectMountInDEV); + } - try { - setCurrentFiber(fiber); - - 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://react.dev/link/wrap-tests-with-act", - getComponentNameFromFiber(fiber) - ); - } finally { - if (previousFiber) { - setCurrentFiber(fiber); - } else { - resetCurrentFiber(); - } - } - } + resetCurrentFiber(); +} + +function invokeEffectsInDev(firstChild, fiberFlags, invokeEffectFn) { + var current = firstChild; + var subtreeRoot = null; + + while (current != null) { + var primarySubtreeFlag = current.subtreeFlags & fiberFlags; + + if (current !== subtreeRoot && current.child != null && primarySubtreeFlag !== NoFlags$1) { + current = current.child; + } else { + if ((current.flags & fiberFlags) !== NoFlags$1) { + invokeEffectFn(current); } - } - function warnIfSuspenseResolutionNotWrappedWithActDEV(root) { - { - if ( - root.tag !== LegacyRoot && - isConcurrentActEnvironment() && - ReactSharedInternals.actQueue === 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://react.dev/link/wrap-tests-with-act" - ); - } - } - } - - function setIsRunningInsertionEffect(isRunning) { - { - isRunningInsertionEffect = isRunning; + if (current.sibling !== null) { + current = current.sibling; + } else { + current = subtreeRoot = current.return; } } + } +} - /* eslint-disable react-internal/prod-error-codes */ - // Used by React Refresh runtime through DevTools Global Hook. +var didWarnStateUpdateForNotYetMountedComponent = null; +function warnAboutUpdateOnNotYetMountedFiberInDEV(fiber) { + { + if ((executionContext & RenderContext) !== NoContext) { + // We let the other warning about render phase updates deal with this one. + return; + } - var resolveFamily = null; - var failedBoundaries = null; - var setRefreshHandler = function (handler) { - { - resolveFamily = handler; - } - }; - function resolveFunctionForHotReloading(type) { - { - if (resolveFamily === null) { - // Hot reloading is disabled. - return type; - } + if (!(fiber.mode & ConcurrentMode)) { + return; + } - var family = resolveFamily(type); + var tag = fiber.tag; - if (family === undefined) { - return type; - } // Use the latest known implementation. + if (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. - return family.current; - } - } - function resolveClassForHotReloading(type) { - // No implementation differences. - return resolveFunctionForHotReloading(type); - } - function resolveForwardRefForHotReloading(type) { - { - if (resolveFamily === null) { - // Hot reloading is disabled. - return type; - } - - var family = resolveFamily(type); - - 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 (type.render !== currentRender) { - var syntheticType = { - $$typeof: REACT_FORWARD_REF_TYPE, - render: currentRender - }; - if (type.displayName !== undefined) { - syntheticType.displayName = type.displayName; - } + var componentName = getComponentNameFromFiber(fiber) || 'ReactComponent'; - return syntheticType; - } - } + if (didWarnStateUpdateForNotYetMountedComponent !== null) { + if (didWarnStateUpdateForNotYetMountedComponent.has(componentName)) { + return; + } // $FlowFixMe[incompatible-use] found when upgrading Flow - return type; - } // Use the latest known implementation. - return family.current; - } + didWarnStateUpdateForNotYetMountedComponent.add(componentName); + } else { + didWarnStateUpdateForNotYetMountedComponent = new Set([componentName]); } - 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 previousFiber = current; - var needsCompareFamilies = false; - var $$typeofNextType = - typeof nextType === "object" && nextType !== null - ? nextType.$$typeof - : null; + try { + setCurrentFiber(fiber); - switch (fiber.tag) { - case ClassComponent: { - if (typeof nextType === "function") { - needsCompareFamilies = true; - } + 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 didWarnAboutUpdateInRender = false; +var didWarnAboutUpdateInRenderForAnotherComponent; - break; - } +{ + didWarnAboutUpdateInRenderForAnotherComponent = new Set(); +} - 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; - } +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. - break; - } + var dedupeKey = renderingComponentName; + + if (!didWarnAboutUpdateInRenderForAnotherComponent.has(dedupeKey)) { + didWarnAboutUpdateInRenderForAnotherComponent.add(dedupeKey); + var setStateComponentName = getComponentNameFromFiber(fiber) || 'Unknown'; - case ForwardRef: { - if ($$typeofNextType === REACT_FORWARD_REF_TYPE) { - needsCompareFamilies = true; - } else if ($$typeofNextType === REACT_LAZY_TYPE) { - needsCompareFamilies = true; + 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://react.dev/link/setstate-in-render', setStateComponentName, renderingComponentName, renderingComponentName); } break; } - 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 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.'); + + didWarnAboutUpdateInRender = true; } break; } - - default: - return false; - } // Check if both types have a family and it's the same one. - - 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 - - if ( - prevFamily !== undefined && - prevFamily === resolveFamily(nextType) - ) { - return true; - } - } - - return false; } } - function markFailedErrorBoundaryForHotReloading(fiber) { - { - if (resolveFamily === null) { - // Hot reloading is disabled. - return; - } + } +} - if (typeof WeakSet !== "function") { - return; - } +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). + } + } +} +var fakeActCallbackNode = {}; // $FlowFixMe[missing-local-annot] - if (failedBoundaries === null) { - failedBoundaries = new WeakSet(); - } +function scheduleCallback(priorityLevel, callback) { + { + // If we're currently inside an `act` scope, bypass Scheduler and push to + // the `act` queue instead. + var actQueue = ReactSharedInternals.actQueue; - failedBoundaries.add(fiber); - } + if (actQueue !== null) { + actQueue.push(callback); + return fakeActCallbackNode; + } else { + return scheduleCallback$3(priorityLevel, callback); } - var scheduleRefresh = function (root, update) { - { - if (resolveFamily === null) { - // Hot reloading is disabled. - return; - } + } +} - var staleFamilies = update.staleFamilies, - updatedFamilies = update.updatedFamilies; - flushPassiveEffects(); - scheduleFibersWithFamiliesRecursively( - root.current, - updatedFamilies, - staleFamilies - ); - flushSyncWork(); - } - }; - 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 shouldForceFlushFallbacksInDEV() { + // Never force flush in production. This function should get stripped out. + return ReactSharedInternals.actQueue !== null; +} - updateContainerSync(element, root, null, null); - flushSyncWork(); +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; } - }; - - function scheduleFibersWithFamiliesRecursively( - fiber, - updatedFamilies, - staleFamilies - ) { - { - var alternate = fiber.alternate, - 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; - } - - if (resolveFamily === null) { - throw new Error( - "Expected resolveFamily to be set during hot reload." - ); - } - var needsRender = false; - var needsRemount = false; + if (executionContext !== NoContext) { + // Legacy mode doesn't warn if the update is batched, i.e. + // batchedUpdates or flushSync. + return; + } - if (candidateType !== null) { - var family = resolveFamily(candidateType); + 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; + } + } - if (family !== undefined) { - if (staleFamilies.has(family)) { - needsRemount = true; - } else if (updatedFamilies.has(family)) { - if (tag === ClassComponent) { - needsRemount = true; - } else { - needsRender = true; - } - } - } - } + if (ReactSharedInternals.actQueue === null) { + var previousFiber = current; - if (failedBoundaries !== null) { - if ( - failedBoundaries.has(fiber) || // $FlowFixMe[incompatible-use] found when upgrading Flow - (alternate !== null && failedBoundaries.has(alternate)) - ) { - needsRemount = true; - } - } + try { + setCurrentFiber(fiber); - if (needsRemount) { - fiber._debugNeedsRemount = true; + 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://react.dev/link/wrap-tests-with-act', getComponentNameFromFiber(fiber)); + } finally { + if (previousFiber) { + setCurrentFiber(fiber); + } else { + resetCurrentFiber(); } + } + } + } +} - if (needsRemount || needsRender) { - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); +function warnIfSuspenseResolutionNotWrappedWithActDEV(root) { + { + if ((root.tag !== LegacyRoot) && isConcurrentActEnvironment() && ReactSharedInternals.actQueue === 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://react.dev/link/wrap-tests-with-act'); + } + } +} - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane); - } - } +function setIsRunningInsertionEffect(isRunning) { + { + isRunningInsertionEffect = isRunning; + } +} - if (child !== null && !needsRemount) { - scheduleFibersWithFamiliesRecursively( - child, - updatedFamilies, - staleFamilies - ); - } +/* eslint-disable react-internal/prod-error-codes */ +// Used by React Refresh runtime through DevTools Global Hook. - if (sibling !== null) { - scheduleFibersWithFamiliesRecursively( - sibling, - updatedFamilies, - staleFamilies - ); - } - } +var resolveFamily = null; +var failedBoundaries = null; +var setRefreshHandler = function (handler) { + { + resolveFamily = handler; + } +}; +function resolveFunctionForHotReloading(type) { + { + if (resolveFamily === null) { + // Hot reloading is disabled. + return type; } - 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; + var family = resolveFamily(type); - case ForwardRef: - candidateType = type.render; - break; - } + if (family === undefined) { + return type; + } // Use the latest known implementation. - var didMatch = false; - if (candidateType !== null) { - if (types.has(candidateType)) { - didMatch = true; - } - } + return family.current; + } +} +function resolveClassForHotReloading(type) { + // No implementation differences. + return resolveFunctionForHotReloading(type); +} +function resolveForwardRefForHotReloading(type) { + { + if (resolveFamily === null) { + // Hot reloading is disabled. + return type; + } + + var family = resolveFamily(type); + + 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 (type.render !== currentRender) { + var syntheticType = { + $$typeof: REACT_FORWARD_REF_TYPE, + render: currentRender + }; - 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 - ); + if (type.displayName !== undefined) { + syntheticType.displayName = type.displayName; } - } - if (sibling !== null) { - findHostInstancesForMatchingFibersRecursively( - sibling, - types, - hostInstances - ); + return syntheticType; } } - } - - function findHostInstancesForFiberShallowly(fiber, hostInstances) { - { - var foundHostInstances = findChildHostInstancesForFiberShallowly( - fiber, - hostInstances - ); - if (foundHostInstances) { - return; - } // If we didn't find any host children, fallback to closest host parent. + return type; + } // Use the latest known implementation. - var node = fiber; - while (true) { - switch (node.tag) { - case HostSingleton: - case HostComponent: - hostInstances.add(node.stateNode); - return; + return family.current; + } +} +function isCompatibleFamilyForHotReloading(fiber, element) { + { + if (resolveFamily === null) { + // Hot reloading is disabled. + return false; + } - case HostPortal: - hostInstances.add(node.stateNode.containerInfo); - return; + var prevType = fiber.elementType; + var nextType = element.type; // If we got here, we know types aren't === equal. - case HostRoot: - hostInstances.add(node.stateNode.containerInfo); - return; - } + var needsCompareFamilies = false; + var $$typeofNextType = typeof nextType === 'object' && nextType !== null ? nextType.$$typeof : null; - if (node.return === null) { - throw new Error("Expected to reach root first."); + switch (fiber.tag) { + case ClassComponent: + { + if (typeof nextType === 'function') { + needsCompareFamilies = true; } - node = node.return; + break; } - } - } - function findChildHostInstancesForFiberShallowly(fiber, hostInstances) { - { - var node = fiber; - var foundHostInstances = false; - - 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; + 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 (node === fiber) { - return foundHostInstances; + break; + } + + case ForwardRef: + { + if ($$typeofNextType === REACT_FORWARD_REF_TYPE) { + needsCompareFamilies = true; + } else if ($$typeofNextType === REACT_LAZY_TYPE) { + needsCompareFamilies = true; } - while (node.sibling === null) { - if (node.return === null || node.return === fiber) { - return foundHostInstances; - } + break; + } - node = node.return; + 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; } - node.sibling.return = node.return; - node = node.sibling; + break; } - } - - return false; - } - var hasBadMapPolyfill; + default: + return false; + } // Check if both types have a family and it's the same one. - { - hasBadMapPolyfill = false; - try { - var nonExtensibleObject = Object.preventExtensions({}); - /* eslint-disable no-new */ - - new Map([[nonExtensibleObject, null]]); - new Set([nonExtensibleObject]); - /* eslint-enable no-new */ - } catch (e) { - // TODO: Consider warning about bad polyfills - hasBadMapPolyfill = true; - } - } - - function FiberNode(tag, pendingProps, key, mode) { - // Instance - this.tag = tag; - this.key = key; - this.elementType = null; - this.type = null; - this.stateNode = null; // Fiber - - 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.flags = NoFlags$1; - this.subtreeFlags = NoFlags$1; - this.deletions = null; - this.lanes = NoLanes; - this.childLanes = NoLanes; - this.alternate = null; + 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 - { - // 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). - - this.actualDuration = 0; - this.actualStartTime = -1; - this.selfBaseDuration = 0; - this.treeBaseDuration = 0; + if (prevFamily !== undefined && prevFamily === resolveFamily(nextType)) { + return true; } + } - { - // This isn't directly used but is handy for debugging internals: - this._debugInfo = null; - this._debugOwner = null; - this._debugNeedsRemount = false; - this._debugHookTypes = null; - - 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[invalid-constructor]: the shapes are exact here but Flow doesn't like constructors - return new FiberNode(tag, pendingProps, key, mode); - } - - function shouldConstruct(Component) { - var prototype = Component.prototype; - return !!(prototype && prototype.isReactComponent); - } - - function isSimpleFunctionComponent(type) { - return ( - typeof type === "function" && - !shouldConstruct(type) && - type.defaultProps === undefined - ); - } - function isFunctionClassComponent(type) { - return shouldConstruct(type); - } // This is used to create an alternate fiber to do work on. - - function createWorkInProgress(current, pendingProps) { - var workInProgress = current.alternate; - - 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; - - { - // DEV-only fields - workInProgress._debugOwner = current._debugOwner; - workInProgress._debugHookTypes = current._debugHookTypes; - } - - workInProgress.alternate = current; - current.alternate = workInProgress; - } else { - workInProgress.pendingProps = pendingProps; // Needed because Blocks store data on type. + return false; + } +} +function markFailedErrorBoundaryForHotReloading(fiber) { + { + if (resolveFamily === null) { + // Hot reloading is disabled. + return; + } - workInProgress.type = current.type; // We already have an alternate. - // Reset the effect tag. + if (typeof WeakSet !== 'function') { + return; + } - workInProgress.flags = NoFlags$1; // The effects are no longer valid. + if (failedBoundaries === null) { + failedBoundaries = new WeakSet(); + } - workInProgress.subtreeFlags = NoFlags$1; - workInProgress.deletions = null; + failedBoundaries.add(fiber); + } +} +var scheduleRefresh = function (root, update) { + { + if (resolveFamily === null) { + // Hot reloading is disabled. + return; + } + + var staleFamilies = update.staleFamilies, + updatedFamilies = update.updatedFamilies; + flushPassiveEffects(); + scheduleFibersWithFamiliesRecursively(root.current, updatedFamilies, staleFamilies); + flushSyncWork(); + } +}; +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; + } + + updateContainerSync(element, root, null, null); + flushSyncWork(); + } +}; + +function scheduleFibersWithFamiliesRecursively(fiber, updatedFamilies, staleFamilies) { + { + var alternate = fiber.alternate, + child = fiber.child, + sibling = fiber.sibling, + tag = fiber.tag, + type = fiber.type; + var candidateType = 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. - - 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 - - workInProgress.sibling = current.sibling; - workInProgress.index = current.index; - workInProgress.ref = current.ref; - workInProgress.refCleanup = current.refCleanup; + switch (tag) { + case FunctionComponent: + case SimpleMemoComponent: + case ClassComponent: + candidateType = type; + break; - { - workInProgress.selfBaseDuration = current.selfBaseDuration; - workInProgress.treeBaseDuration = current.treeBaseDuration; - } + case ForwardRef: + candidateType = type.render; + break; + } - { - workInProgress._debugInfo = current._debugInfo; - workInProgress._debugNeedsRemount = current._debugNeedsRemount; + if (resolveFamily === null) { + throw new Error('Expected resolveFamily to be set during hot reload.'); + } - switch (workInProgress.tag) { - case FunctionComponent: - case SimpleMemoComponent: - workInProgress.type = resolveFunctionForHotReloading(current.type); - break; + var needsRender = false; + var needsRemount = false; - case ClassComponent: - workInProgress.type = resolveClassForHotReloading(current.type); - break; + if (candidateType !== null) { + var family = resolveFamily(candidateType); - case ForwardRef: - workInProgress.type = resolveForwardRefForHotReloading( - current.type - ); - break; + if (family !== undefined) { + if (staleFamilies.has(family)) { + needsRemount = true; + } else if (updatedFamilies.has(family)) { + if (tag === ClassComponent) { + needsRemount = true; + } else { + needsRender = true; + } } } + } - return workInProgress; - } // Used to reuse a Fiber for a second pass. + if (failedBoundaries !== null) { + if (failedBoundaries.has(fiber) || // $FlowFixMe[incompatible-use] found when upgrading Flow + alternate !== null && failedBoundaries.has(alternate)) { + needsRemount = true; + } + } - 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 (needsRemount) { + fiber._debugNeedsRemount = true; + } - var current = workInProgress.alternate; + if (needsRemount || needsRender) { + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - 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 (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane); + } + } - { - // 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. - - workInProgress.type = current.type; // 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 - }; + if (child !== null && !needsRemount) { + scheduleFibersWithFamiliesRecursively(child, updatedFamilies, staleFamilies); + } - { - // 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; - } - } + if (sibling !== null) { + scheduleFibersWithFamiliesRecursively(sibling, updatedFamilies, staleFamilies); + } + } +} + +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; - return workInProgress; + case ForwardRef: + candidateType = type.render; + break; } - function createHostRootFiber( - tag, - isStrictMode, - concurrentUpdatesByDefaultOverride - ) { - var mode; - if (tag === ConcurrentRoot) { - mode = ConcurrentMode; + var didMatch = false; - if (isStrictMode === true) { - mode |= StrictLegacyMode | StrictEffectsMode; - } - } else { - mode = NoMode; + if (candidateType !== null) { + if (types.has(candidateType)) { + didMatch = true; } + } - 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; + 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); } + } - return createFiber(HostRoot, null, null, mode); + if (sibling !== null) { + findHostInstancesForMatchingFibersRecursively(sibling, types, hostInstances); } - function createFiberFromTypeAndProps( - type, // React$ElementType - key, - pendingProps, - owner, - mode, - lanes - ) { - var fiberTag = FunctionComponent; // The resolved type is set if we know what the final type will be. I.e. it's not lazy. + } +} - var resolvedType = type; +function findHostInstancesForFiberShallowly(fiber, hostInstances) { + { + var foundHostInstances = findChildHostInstancesForFiberShallowly(fiber, hostInstances); - if (typeof type === "function") { - if (shouldConstruct(type)) { - fiberTag = ClassComponent; + if (foundHostInstances) { + return; + } // If we didn't find any host children, fallback to closest host parent. - { - 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 - ); - case REACT_STRICT_MODE_TYPE: - fiberTag = Mode; - mode |= StrictLegacyMode; + var node = fiber; - if ((mode & ConcurrentMode) !== NoMode) { - // Strict effects should never run on legacy roots - mode |= StrictEffectsMode; - } + while (true) { + switch (node.tag) { + case HostSingleton: + case HostComponent: + hostInstances.add(node.stateNode); + return; - break; + case HostPortal: + hostInstances.add(node.stateNode.containerInfo); + return; - case REACT_PROFILER_TYPE: - return createFiberFromProfiler(pendingProps, mode, lanes, key); + case HostRoot: + hostInstances.add(node.stateNode.containerInfo); + return; + } + + if (node.return === null) { + throw new Error('Expected to reach root first.'); + } - case REACT_SUSPENSE_TYPE: - return createFiberFromSuspense(pendingProps, mode, lanes, key); + node = node.return; + } + } +} - case REACT_SUSPENSE_LIST_TYPE: - return createFiberFromSuspenseList(pendingProps, mode, lanes, key); +function findChildHostInstancesForFiberShallowly(fiber, hostInstances) { + { + var node = fiber; + var foundHostInstances = false; - case REACT_OFFSCREEN_TYPE: - return createFiberFromOffscreen(pendingProps, mode, lanes, key); + 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; + } - case REACT_LEGACY_HIDDEN_TYPE: + if (node === fiber) { + return foundHostInstances; + } - // Fall through + while (node.sibling === null) { + if (node.return === null || node.return === fiber) { + return foundHostInstances; + } - case REACT_SCOPE_TYPE: + node = node.return; + } - // Fall through + node.sibling.return = node.return; + node = node.sibling; + } + } - case REACT_TRACING_MARKER_TYPE: + return false; +} - // Fall through +var hasBadMapPolyfill; - case REACT_DEBUG_TRACING_MODE_TYPE: +{ + hasBadMapPolyfill = false; - // Fall through + try { + var nonExtensibleObject = Object.preventExtensions({}); + /* eslint-disable no-new */ - default: { - if (typeof type === "object" && type !== null) { - switch (type.$$typeof) { - case REACT_PROVIDER_TYPE: - if (!enableRenderableContext) { - fiberTag = ContextProvider; - break getTag; - } + new Map([[nonExtensibleObject, null]]); + new Set([nonExtensibleObject]); + /* eslint-enable no-new */ + } catch (e) { + // TODO: Consider warning about bad polyfills + hasBadMapPolyfill = true; + } +} - // Fall through +function FiberNode(tag, pendingProps, key, mode) { + // Instance + this.tag = tag; + this.key = key; + this.elementType = null; + this.type = null; + this.stateNode = null; // Fiber + + 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.flags = NoFlags$1; + this.subtreeFlags = NoFlags$1; + this.deletions = null; + this.lanes = NoLanes; + this.childLanes = NoLanes; + this.alternate = null; + + { + // 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). + + this.actualDuration = 0; + this.actualStartTime = -1; + this.selfBaseDuration = 0; + this.treeBaseDuration = 0; + } + + { + // This isn't directly used but is handy for debugging internals: + this._debugInfo = null; + this._debugOwner = null; + this._debugNeedsRemount = false; + this._debugHookTypes = null; + + 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[invalid-constructor]: the shapes are exact here but Flow doesn't like constructors + return new FiberNode(tag, pendingProps, key, mode); +} - case REACT_CONTEXT_TYPE: - if (enableRenderableContext) { - fiberTag = ContextProvider; - break getTag; - } else { - fiberTag = ContextConsumer; - break getTag; - } +function shouldConstruct(Component) { + var prototype = Component.prototype; + return !!(prototype && prototype.isReactComponent); +} - case REACT_CONSUMER_TYPE: - if (enableRenderableContext) { - fiberTag = ContextConsumer; - break getTag; - } +function isSimpleFunctionComponent(type) { + return typeof type === 'function' && !shouldConstruct(type) && type.defaultProps === undefined; +} +function isFunctionClassComponent(type) { + return shouldConstruct(type); +} // This is used to create an alternate fiber to do work on. + +function createWorkInProgress(current, pendingProps) { + var workInProgress = current.alternate; + + 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; - // Fall through + { + // DEV-only fields + workInProgress._debugOwner = current._debugOwner; + workInProgress._debugHookTypes = current._debugHookTypes; + } - case REACT_FORWARD_REF_TYPE: - fiberTag = ForwardRef; + workInProgress.alternate = current; + current.alternate = workInProgress; + } else { + workInProgress.pendingProps = pendingProps; // Needed because Blocks store data on type. - { - resolvedType = - resolveForwardRefForHotReloading(resolvedType); - } + workInProgress.type = current.type; // We already have an alternate. + // Reset the effect tag. - break getTag; + workInProgress.flags = NoFlags$1; // The effects are no longer valid. - case REACT_MEMO_TYPE: - fiberTag = MemoComponent; - break getTag; + workInProgress.subtreeFlags = NoFlags$1; + workInProgress.deletions = null; - case REACT_LAZY_TYPE: - fiberTag = LazyComponent; - resolvedType = null; - break getTag; - } - } + { + // 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. + + + 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 + + workInProgress.sibling = current.sibling; + workInProgress.index = current.index; + workInProgress.ref = current.ref; + workInProgress.refCleanup = current.refCleanup; + + { + workInProgress.selfBaseDuration = current.selfBaseDuration; + workInProgress.treeBaseDuration = current.treeBaseDuration; + } + + { + workInProgress._debugInfo = current._debugInfo; + workInProgress._debugNeedsRemount = current._debugNeedsRemount; + + switch (workInProgress.tag) { + case FunctionComponent: + case SimpleMemoComponent: + workInProgress.type = resolveFunctionForHotReloading(current.type); + break; + + case ClassComponent: + workInProgress.type = resolveClassForHotReloading(current.type); + break; + + case ForwardRef: + workInProgress.type = resolveForwardRefForHotReloading(current.type); + break; + } + } + + 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 current = workInProgress.alternate; + + 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; - var info = ""; + { + // 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. + + workInProgress.type = current.type; // 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 + }; - { - 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."; - } + { + // 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; + } + } - var ownerName = owner ? getComponentNameFromOwner(owner) : null; + return workInProgress; +} +function createHostRootFiber(tag, isStrictMode, concurrentUpdatesByDefaultOverride) { + var mode; - if (ownerName) { - info += "\n\nCheck the render method of `" + ownerName + "`."; - } - } + if (tag === ConcurrentRoot) { + mode = ConcurrentMode; - 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 (isStrictMode === true) { + mode |= StrictLegacyMode | StrictEffectsMode; + } + } else { + mode = NoMode; + } - var fiber = createFiber(fiberTag, pendingProps, key, mode); - fiber.elementType = type; - fiber.type = resolvedType; - fiber.lanes = lanes; + 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; + } - { - fiber._debugOwner = owner; - } + return createFiber(HostRoot, null, null, mode); +} +function createFiberFromTypeAndProps(type, // React$ElementType +key, pendingProps, owner, mode, lanes) { + var fiberTag = FunctionComponent; // The resolved type is set if we know what the final type will be. I.e. it's not lazy. - return fiber; - } - function createFiberFromElement(element, mode, lanes) { - var owner = null; + var resolvedType = type; + + if (typeof type === 'function') { + if (shouldConstruct(type)) { + fiberTag = ClassComponent; { - owner = element._owner; + resolvedType = resolveClassForHotReloading(resolvedType); } - - var type = element.type; - var key = element.key; - var pendingProps = element.props; - var fiber = createFiberFromTypeAndProps( - type, - key, - pendingProps, - owner, - mode, - lanes - ); - + } else { { - fiber._debugOwner = element._owner; + resolvedType = resolveFunctionForHotReloading(resolvedType); } - - return fiber; } - function createFiberFromFragment(elements, mode, lanes, key) { - var fiber = createFiber(Fragment, elements, key, mode); - fiber.lanes = lanes; - return fiber; + } else if (typeof type === 'string') { + { + fiberTag = HostComponent; } + } else { + getTag: switch (type) { + case REACT_FRAGMENT_TYPE: + return createFiberFromFragment(pendingProps.children, mode, lanes, key); - 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 REACT_STRICT_MODE_TYPE: + fiberTag = Mode; + mode |= StrictLegacyMode; + + if ((mode & ConcurrentMode) !== NoMode) { + // Strict effects should never run on legacy roots + mode |= StrictEffectsMode; } - } - var fiber = createFiber(Profiler, pendingProps, key, mode | ProfileMode); - fiber.elementType = REACT_PROFILER_TYPE; - fiber.lanes = lanes; + break; - { - fiber.stateNode = { - effectDuration: 0, - passiveEffectDuration: 0 - }; - } + case REACT_PROFILER_TYPE: + return createFiberFromProfiler(pendingProps, mode, lanes, key); - return fiber; - } - - 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 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; - } - - function FiberRootNode( - containerInfo, // $FlowFixMe[missing-local-annot] - tag, - hydrate, - identifierPrefix, - onUncaughtError, - onCaughtError, - onRecoverableError, - formState - ) { - 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.next = null; - this.callbackNode = null; - this.callbackPriority = NoLane; - this.expirationTimes = createLaneMap(NoTimestamp); - this.pendingLanes = NoLanes; - this.suspendedLanes = NoLanes; - this.pingedLanes = NoLanes; - this.expiredLanes = NoLanes; - this.finishedLanes = NoLanes; - this.errorRecoveryDisabledLanes = NoLanes; - this.shellSuspendCounter = 0; - this.entangledLanes = NoLanes; - this.entanglements = createLaneMap(NoLanes); - this.hiddenUpdates = createLaneMap(null); - this.identifierPrefix = identifierPrefix; - this.onUncaughtError = onUncaughtError; - this.onCaughtError = onCaughtError; - this.onRecoverableError = onRecoverableError; + case REACT_SUSPENSE_TYPE: + return createFiberFromSuspense(pendingProps, mode, lanes, key); - { - this.pooledCache = null; - this.pooledCacheLanes = NoLanes; - } + case REACT_SUSPENSE_LIST_TYPE: + return createFiberFromSuspenseList(pendingProps, mode, lanes, key); - this.formState = formState; - this.incompleteTransitions = new Map(); + case REACT_OFFSCREEN_TYPE: + return createFiberFromOffscreen(pendingProps, mode, lanes, key); - { - this.effectDuration = 0; - this.passiveEffectDuration = 0; - } + case REACT_LEGACY_HIDDEN_TYPE: - { - this.memoizedUpdaters = new Set(); - var pendingUpdatersLaneMap = (this.pendingUpdatersLaneMap = []); + // Fall through - for (var _i = 0; _i < TotalLanes; _i++) { - pendingUpdatersLaneMap.push(new Set()); - } - } + case REACT_SCOPE_TYPE: - { + // Fall through + + case REACT_TRACING_MARKER_TYPE: + + // Fall through + + case REACT_DEBUG_TRACING_MODE_TYPE: + + // Fall through + + default: { - switch (tag) { - case ConcurrentRoot: - this._debugRootType = hydrate ? "hydrateRoot()" : "createRoot()"; - break; + if (typeof type === 'object' && type !== null) { + switch (type.$$typeof) { + case REACT_PROVIDER_TYPE: + if (!enableRenderableContext) { + fiberTag = ContextProvider; + break getTag; + } - case LegacyRoot: - this._debugRootType = hydrate ? "hydrate()" : "render()"; - break; - } - } - } - } + // Fall through - 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, - onUncaughtError, - onCaughtError, - onRecoverableError, - transitionCallbacks, - formState - ) { - // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions - var root = new FiberRootNode( - containerInfo, - tag, - hydrate, - identifierPrefix, - onUncaughtError, - onCaughtError, - onRecoverableError, - formState - ); - // stateNode is any. - - var uninitializedFiber = createHostRootFiber(tag, isStrictMode); - root.current = uninitializedFiber; - uninitializedFiber.stateNode = root; + case REACT_CONTEXT_TYPE: + if (enableRenderableContext) { + fiberTag = ContextProvider; + break getTag; + } else { + fiberTag = ContextConsumer; + break getTag; + } - { - var initialCache = createCache(); - retainCache(initialCache); // The pooledCache is a fresh cache instance that is used temporarily - // for newly mounted boundaries during a render. In general, the - // pooledCache is always cleared from the root at the end of a render: - // it is either released when render commits, or moved to an Offscreen - // component if rendering suspends. Because the lifetime of the pooled - // cache is distinct from the main memoizedState.cache, it must be - // retained separately. - - root.pooledCache = initialCache; - retainCache(initialCache); - var initialState = { - element: initialChildren, - isDehydrated: hydrate, - cache: initialCache - }; - uninitializedFiber.memoizedState = initialState; - } + case REACT_CONSUMER_TYPE: + if (enableRenderableContext) { + fiberTag = ContextConsumer; + break getTag; + } - initializeUpdateQueue(uninitializedFiber); - return root; - } + // Fall through - var ReactVersion = "19.0.0-canary-ad24d706"; + case REACT_FORWARD_REF_TYPE: + fiberTag = ForwardRef; - /* - * 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[incompatible-return] 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[incompatible-return] + { + resolvedType = resolveForwardRefForHotReloading(resolvedType); + } - return type; - } - } // $FlowFixMe[incompatible-return] only called in DEV, so void return is not possible. + break getTag; - function willCoercionThrow(value) { - { - try { - testStringCoercion(value); - return false; - } catch (e) { - return true; - } - } - } + case REACT_MEMO_TYPE: + fiberTag = MemoComponent; + break getTag; - 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 using it here.", - typeName(value) - ); + case REACT_LAZY_TYPE: + fiberTag = LazyComponent; + resolvedType = null; + break getTag; + } + } + + var info = ''; - return testStringCoercion(value); // throw (to help callers find troubleshooting comments) + { + 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 ownerName = owner ? getComponentNameFromOwner(owner) : null; + + if (ownerName) { + info += '\n\nCheck the render method of `' + ownerName + '`.'; + } + } + + 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)); } - } } + } - 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; + var fiber = createFiber(fiberTag, pendingProps, key, mode); + fiber.elementType = type; + fiber.type = resolvedType; + fiber.lanes = lanes; - { - checkKeyStringCoercion(key); - } + { + fiber._debugOwner = owner; + } - 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 - }; + return fiber; +} +function createFiberFromElement(element, mode, lanes) { + var owner = null; + + { + owner = element._owner; + } + + var type = element.type; + var key = element.key; + var pendingProps = element.props; + var fiber = createFiberFromTypeAndProps(type, key, pendingProps, owner, mode, lanes); + + { + fiber._debugOwner = element._owner; + } + + return fiber; +} +function createFiberFromFragment(elements, mode, lanes, key) { + var fiber = createFiber(Fragment, elements, key, mode); + fiber.lanes = lanes; + return fiber; +} + +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); } + } - // Might add PROFILE later. + var fiber = createFiber(Profiler, pendingProps, key, mode | ProfileMode); + fiber.elementType = REACT_PROFILER_TYPE; + fiber.lanes = lanes; + + { + fiber.stateNode = { + effectDuration: 0, + passiveEffectDuration: 0 + }; + } + + return fiber; +} - var didWarnAboutNestedUpdates; - var didWarnAboutFindNodeInStrictMode; +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 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; +} +function FiberRootNode(containerInfo, // $FlowFixMe[missing-local-annot] +tag, hydrate, identifierPrefix, onUncaughtError, onCaughtError, onRecoverableError, formState) { + 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.next = null; + this.callbackNode = null; + this.callbackPriority = NoLane; + this.expirationTimes = createLaneMap(NoTimestamp); + this.pendingLanes = NoLanes; + this.suspendedLanes = NoLanes; + this.pingedLanes = NoLanes; + this.expiredLanes = NoLanes; + this.finishedLanes = NoLanes; + this.errorRecoveryDisabledLanes = NoLanes; + this.shellSuspendCounter = 0; + this.entangledLanes = NoLanes; + this.entanglements = createLaneMap(NoLanes); + this.hiddenUpdates = createLaneMap(null); + this.identifierPrefix = identifierPrefix; + this.onUncaughtError = onUncaughtError; + this.onCaughtError = onCaughtError; + this.onRecoverableError = onRecoverableError; + + { + this.pooledCache = null; + this.pooledCacheLanes = NoLanes; + } + + this.formState = formState; + this.incompleteTransitions = new Map(); + + { + this.effectDuration = 0; + this.passiveEffectDuration = 0; + } + + { + this.memoizedUpdaters = new Set(); + var pendingUpdatersLaneMap = this.pendingUpdatersLaneMap = []; + + for (var _i = 0; _i < TotalLanes; _i++) { + pendingUpdatersLaneMap.push(new Set()); + } + } + + { { - didWarnAboutNestedUpdates = false; - didWarnAboutFindNodeInStrictMode = {}; - } + switch (tag) { + case ConcurrentRoot: + this._debugRootType = hydrate ? 'hydrateRoot()' : 'createRoot()'; + break; - function getContextForSubtree(parentComponent) { - if (!parentComponent) { - return emptyContextObject; + case LegacyRoot: + this._debugRootType = hydrate ? 'hydrate()' : 'render()'; + break; } + } + } +} - var fiber = get(parentComponent); - var parentContext = findCurrentUnmaskedContext(fiber); +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, onUncaughtError, onCaughtError, onRecoverableError, transitionCallbacks, formState) { + // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions + var root = new FiberRootNode(containerInfo, tag, hydrate, identifierPrefix, onUncaughtError, onCaughtError, onRecoverableError, formState); + // stateNode is any. + + + var uninitializedFiber = createHostRootFiber(tag, isStrictMode); + root.current = uninitializedFiber; + uninitializedFiber.stateNode = root; + + { + var initialCache = createCache(); + retainCache(initialCache); // The pooledCache is a fresh cache instance that is used temporarily + // for newly mounted boundaries during a render. In general, the + // pooledCache is always cleared from the root at the end of a render: + // it is either released when render commits, or moved to an Offscreen + // component if rendering suspends. Because the lifetime of the pooled + // cache is distinct from the main memoizedState.cache, it must be + // retained separately. + + root.pooledCache = initialCache; + retainCache(initialCache); + var initialState = { + element: initialChildren, + isDehydrated: hydrate, + cache: initialCache + }; + uninitializedFiber.memoizedState = initialState; + } - if (fiber.tag === ClassComponent) { - var Component = fiber.type; + initializeUpdateQueue(uninitializedFiber); + return root; +} - if (isContextProvider(Component)) { - return processChildContext(fiber, Component, parentContext); - } - } +var ReactVersion = '19.0.0-canary-4c1bc958'; - return parentContext; +/* + * 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[incompatible-return] 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[incompatible-return] + + return type; + } +} // $FlowFixMe[incompatible-return] only called in DEV, so void return is not possible. + + +function willCoercionThrow(value) { + { + try { + testStringCoercion(value); + return false; + } catch (e) { + return true; } + } +} - function findHostInstanceWithWarning(component, methodName) { - { - var fiber = get(component); +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 using it here.', typeName(value)); - 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 - ); - } - } + return testStringCoercion(value); // throw (to help callers find troubleshooting comments) + } + } +} - var hostFiber = findCurrentHostFiber(fiber); +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 { + // 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 + }; +} - if (hostFiber === null) { - return null; - } +// Might add PROFILE later. - if (hostFiber.mode & StrictLegacyMode) { - var componentName = getComponentNameFromFiber(fiber) || "Component"; +var didWarnAboutNestedUpdates; +var didWarnAboutFindNodeInStrictMode; - if (!didWarnAboutFindNodeInStrictMode[componentName]) { - didWarnAboutFindNodeInStrictMode[componentName] = true; - var previousFiber = current; +{ + didWarnAboutNestedUpdates = false; + didWarnAboutFindNodeInStrictMode = {}; +} - try { - setCurrentFiber(hostFiber); - - 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://react.dev/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://react.dev/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(); - } - } - } - } +function getContextForSubtree(parentComponent) { + if (!parentComponent) { + return emptyContextObject; + } - return getPublicInstance(hostFiber.stateNode); - } - } - - function createContainer( - containerInfo, - tag, - hydrationCallbacks, - isStrictMode, - concurrentUpdatesByDefaultOverride, - identifierPrefix, - onUncaughtError, - onCaughtError, - onRecoverableError, - transitionCallbacks - ) { - var hydrate = false; - var initialChildren = null; - return createFiberRoot( - containerInfo, - tag, - hydrate, - initialChildren, - hydrationCallbacks, - isStrictMode, - concurrentUpdatesByDefaultOverride, - identifierPrefix, - onUncaughtError, - onCaughtError, - onRecoverableError, - transitionCallbacks, - null - ); - } - function updateContainer(element, container, parentComponent, callback) { - var current = container.current; - var lane = requestUpdateLane(current); - updateContainerImpl( - current, - lane, - element, - container, - parentComponent, - callback - ); - return lane; - } - function updateContainerSync( - element, - container, - parentComponent, - callback - ) { - if (container.tag === LegacyRoot) { - flushPassiveEffects(); - } + var fiber = get(parentComponent); + var parentContext = findCurrentUnmaskedContext(fiber); - var current = container.current; - updateContainerImpl( - current, - SyncLane, - element, - container, - parentComponent, - callback - ); - return SyncLane; - } + if (fiber.tag === ClassComponent) { + var Component = fiber.type; - function updateContainerImpl( - rootFiber, - lane, - element, - container, - parentComponent, - callback - ) { - { - onScheduleRoot(container, element); - } + if (isContextProvider(Component)) { + return processChildContext(fiber, Component, parentContext); + } + } - { - markRenderScheduled(lane); - } + return parentContext; +} - var context = getContextForSubtree(parentComponent); +function findHostInstanceWithWarning(component, methodName) { + { + var fiber = get(component); - if (container.context === null) { - container.context = context; + if (fiber === undefined) { + if (typeof component.render === 'function') { + throw new Error('Unable to find node on an unmounted component.'); } else { - container.pendingContext = context; + var keys = Object.keys(component).join(','); + throw new Error("Argument appears to not be a ReactComponent. Keys: " + keys); } + } - { - if (isRendering && current !== null && !didWarnAboutNestedUpdates) { - didWarnAboutNestedUpdates = true; + var hostFiber = findCurrentHostFiber(fiber); - 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 (hostFiber === null) { + return null; + } - var update = createUpdate(lane); // Caution: React DevTools currently depends on this property - // being called "element". + if (hostFiber.mode & StrictLegacyMode) { + var componentName = getComponentNameFromFiber(fiber) || 'Component'; - update.payload = { - element: element - }; - callback = callback === undefined ? null : callback; + if (!didWarnAboutFindNodeInStrictMode[componentName]) { + didWarnAboutFindNodeInStrictMode[componentName] = true; + var previousFiber = current; - if (callback !== null) { - { - if (typeof callback !== "function") { - error( - "Expected the last optional `callback` argument to be a " + - "function. Instead received: %s.", - callback - ); + try { + setCurrentFiber(hostFiber); + + 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://react.dev/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://react.dev/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(); } } - - update.callback = callback; } + } - var root = enqueueUpdate(rootFiber, update, lane); + return getPublicInstance(hostFiber.stateNode); + } +} - if (root !== null) { - scheduleUpdateOnFiber(root, rootFiber, lane); - entangleTransitions(root, rootFiber, lane); - } - } - function getPublicRootInstance(container) { - var containerFiber = container.current; +function createContainer(containerInfo, tag, hydrationCallbacks, isStrictMode, concurrentUpdatesByDefaultOverride, identifierPrefix, onUncaughtError, onCaughtError, onRecoverableError, transitionCallbacks) { + var hydrate = false; + var initialChildren = null; + return createFiberRoot(containerInfo, tag, hydrate, initialChildren, hydrationCallbacks, isStrictMode, concurrentUpdatesByDefaultOverride, identifierPrefix, onUncaughtError, onCaughtError, onRecoverableError, transitionCallbacks, null); +} +function updateContainer(element, container, parentComponent, callback) { + var current = container.current; + var lane = requestUpdateLane(current); + updateContainerImpl(current, lane, element, container, parentComponent, callback); + return lane; +} +function updateContainerSync(element, container, parentComponent, callback) { + if (container.tag === LegacyRoot) { + flushPassiveEffects(); + } + + var current = container.current; + updateContainerImpl(current, SyncLane, element, container, parentComponent, callback); + return SyncLane; +} - if (!containerFiber.child) { - return null; - } +function updateContainerImpl(rootFiber, lane, element, container, parentComponent, callback) { + { + onScheduleRoot(container, element); + } - switch (containerFiber.child.tag) { - case HostSingleton: - case HostComponent: - return getPublicInstance(containerFiber.child.stateNode); + { + markRenderScheduled(lane); + } - default: - return containerFiber.child.stateNode; - } - } + var context = getContextForSubtree(parentComponent); - var shouldErrorImpl = function (fiber) { - return null; - }; + if (container.context === null) { + container.context = context; + } else { + container.pendingContext = context; + } + + { + if (isRendering && current !== null && !didWarnAboutNestedUpdates) { + didWarnAboutNestedUpdates = true; - function shouldError(fiber) { - return shouldErrorImpl(fiber); + 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'); } + } - var shouldSuspendImpl = function (fiber) { - return false; - }; + var update = createUpdate(lane); // Caution: React DevTools currently depends on this property + // being called "element". - 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; + update.payload = { + element: element + }; + callback = callback === undefined ? null : callback; + if (callback !== null) { { - var copyWithDeleteImpl = function (obj, path, index) { - var key = path[index]; - var updated = isArray(obj) ? obj.slice() : assign({}, obj); + if (typeof callback !== 'function') { + error('Expected the last optional `callback` argument to be a ' + 'function. Instead received: %s.', callback); + } + } - if (index + 1 === path.length) { - if (isArray(updated)) { - updated.splice(key, 1); - } else { - delete updated[key]; - } + update.callback = callback; + } - return updated; - } // $FlowFixMe[incompatible-use] number or string is fine here + var root = enqueueUpdate(rootFiber, update, lane); - updated[key] = copyWithDeleteImpl(obj[key], path, index + 1); - return updated; - }; + if (root !== null) { + scheduleUpdateOnFiber(root, rootFiber, lane); + entangleTransitions(root, rootFiber, lane); + } +} +function getPublicRootInstance(container) { + var containerFiber = container.current; - var copyWithDelete = function (obj, path) { - return copyWithDeleteImpl(obj, path, 0); - }; + if (!containerFiber.child) { + return null; + } - var copyWithRenameImpl = function (obj, oldPath, newPath, index) { - var oldKey = oldPath[index]; - var updated = isArray(obj) ? obj.slice() : assign({}, obj); + switch (containerFiber.child.tag) { + case HostSingleton: + case HostComponent: + return getPublicInstance(containerFiber.child.stateNode); - if (index + 1 === oldPath.length) { - var newKey = newPath[index]; // $FlowFixMe[incompatible-use] number or string is fine here + default: + return containerFiber.child.stateNode; + } +} - updated[newKey] = updated[oldKey]; +var shouldErrorImpl = function (fiber) { + return null; +}; - if (isArray(updated)) { - updated.splice(oldKey, 1); - } else { - delete updated[oldKey]; - } - } else { - // $FlowFixMe[incompatible-use] number or string is fine here - updated[oldKey] = copyWithRenameImpl( - // $FlowFixMe[incompatible-use] number or string is fine here - obj[oldKey], - oldPath, - newPath, - index + 1 - ); - } +function shouldError(fiber) { + return shouldErrorImpl(fiber); +} - return updated; - }; +var shouldSuspendImpl = function (fiber) { + return false; +}; - var copyWithRename = function (obj, oldPath, newPath) { - if (oldPath.length !== newPath.length) { - warn("copyWithRename() expects paths of the same length"); +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; + +{ + var copyWithDeleteImpl = function (obj, path, index) { + var key = path[index]; + var updated = isArray(obj) ? obj.slice() : assign({}, obj); + + if (index + 1 === path.length) { + if (isArray(updated)) { + updated.splice(key, 1); + } else { + delete updated[key]; + } - 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" - ); + return updated; + } // $FlowFixMe[incompatible-use] number or string is fine here - return; - } - } - } - return copyWithRenameImpl(obj, oldPath, newPath, 0); - }; + updated[key] = copyWithDeleteImpl(obj[key], path, index + 1); + return updated; + }; - var copyWithSetImpl = function (obj, path, index, value) { - if (index >= path.length) { - return value; - } + var copyWithDelete = function (obj, path) { + return copyWithDeleteImpl(obj, path, 0); + }; - var key = path[index]; - var updated = isArray(obj) ? obj.slice() : assign({}, obj); // $FlowFixMe[incompatible-use] number or string is fine here + var copyWithRenameImpl = function (obj, oldPath, newPath, index) { + var oldKey = oldPath[index]; + var updated = isArray(obj) ? obj.slice() : assign({}, obj); - updated[key] = copyWithSetImpl(obj[key], path, index + 1, value); - return updated; - }; + if (index + 1 === oldPath.length) { + var newKey = newPath[index]; // $FlowFixMe[incompatible-use] number or string is fine here - var copyWithSet = function (obj, path, value) { - return copyWithSetImpl(obj, path, 0, value); - }; + updated[newKey] = updated[oldKey]; - 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 (isArray(updated)) { + updated.splice(oldKey, 1); + } else { + delete updated[oldKey]; + } + } else { + // $FlowFixMe[incompatible-use] number or string is fine here + updated[oldKey] = copyWithRenameImpl( // $FlowFixMe[incompatible-use] number or string is fine here + obj[oldKey], oldPath, newPath, index + 1); + } - while (currentHook !== null && id > 0) { - currentHook = currentHook.next; - id--; - } + return updated; + }; - return currentHook; - }; // Support DevTools editable values for useState and useReducer. + var copyWithRename = function (obj, oldPath, newPath) { + if (oldPath.length !== newPath.length) { + warn('copyWithRename() expects paths of the same length'); - overrideHookState = function (fiber, id, path, value) { - var hook = findHook(fiber, id); + 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'); - 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. + return; + } + } + } - fiber.memoizedProps = assign({}, fiber.memoizedProps); - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + return copyWithRenameImpl(obj, oldPath, newPath, 0); + }; - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane); - } - } - }; + var copyWithSetImpl = function (obj, path, index, value) { + if (index >= path.length) { + return value; + } - overrideHookStateDeletePath = function (fiber, id, path) { - var hook = findHook(fiber, id); + var key = path[index]; + var updated = isArray(obj) ? obj.slice() : assign({}, obj); // $FlowFixMe[incompatible-use] number or string is fine here - 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. + updated[key] = copyWithSetImpl(obj[key], path, index + 1, value); + return updated; + }; - fiber.memoizedProps = assign({}, fiber.memoizedProps); - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + var copyWithSet = function (obj, path, value) { + return copyWithSetImpl(obj, path, 0, value); + }; - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane); - } - } - }; + 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; - overrideHookStateRenamePath = function (fiber, id, oldPath, newPath) { - var hook = findHook(fiber, id); + while (currentHook !== null && id > 0) { + currentHook = currentHook.next; + id--; + } - 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. + return currentHook; + }; // Support DevTools editable values for useState and useReducer. - fiber.memoizedProps = assign({}, fiber.memoizedProps); - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane); - } - } - }; // Support DevTools props for function components, forwardRef, memo, host components, etc. + overrideHookState = function (fiber, id, path, value) { + var hook = findHook(fiber, id); - overrideProps = function (fiber, path, value) { - fiber.pendingProps = copyWithSet(fiber.memoizedProps, path, value); + 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. - if (fiber.alternate) { - fiber.alternate.pendingProps = fiber.pendingProps; - } + fiber.memoizedProps = assign({}, fiber.memoizedProps); + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane); + } + } + }; - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane); - } - }; + overrideHookStateDeletePath = function (fiber, id, path) { + var hook = findHook(fiber, id); - overridePropsDeletePath = function (fiber, path) { - fiber.pendingProps = copyWithDelete(fiber.memoizedProps, path); + 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 (fiber.alternate) { - fiber.alternate.pendingProps = fiber.pendingProps; - } + fiber.memoizedProps = assign({}, fiber.memoizedProps); + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane); + } + } + }; - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane); - } - }; + overrideHookStateRenamePath = function (fiber, id, oldPath, newPath) { + var hook = findHook(fiber, id); - overridePropsRenamePath = function (fiber, oldPath, newPath) { - fiber.pendingProps = copyWithRename( - fiber.memoizedProps, - oldPath, - newPath - ); + 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 (fiber.alternate) { - fiber.alternate.pendingProps = fiber.pendingProps; - } + fiber.memoizedProps = assign({}, fiber.memoizedProps); + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane); + } + } + }; // Support DevTools props for function components, forwardRef, memo, host components, etc. - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane); - } - }; - scheduleUpdate = function (fiber) { - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + overrideProps = function (fiber, path, value) { + fiber.pendingProps = copyWithSet(fiber.memoizedProps, path, value); - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane); - } - }; + if (fiber.alternate) { + fiber.alternate.pendingProps = fiber.pendingProps; + } - setErrorHandler = function (newShouldErrorImpl) { - shouldErrorImpl = newShouldErrorImpl; - }; + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - setSuspenseHandler = function (newShouldSuspendImpl) { - shouldSuspendImpl = newShouldSuspendImpl; - }; + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane); } + }; - function findHostInstanceByFiber(fiber) { - var hostFiber = findCurrentHostFiber(fiber); + overridePropsDeletePath = function (fiber, path) { + fiber.pendingProps = copyWithDelete(fiber.memoizedProps, path); - if (hostFiber === null) { - return null; - } + if (fiber.alternate) { + fiber.alternate.pendingProps = fiber.pendingProps; + } + + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - return hostFiber.stateNode; + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane); } + }; - function emptyFindFiberByHostInstance(instance) { - return null; + overridePropsRenamePath = function (fiber, oldPath, newPath) { + fiber.pendingProps = copyWithRename(fiber.memoizedProps, oldPath, newPath); + + if (fiber.alternate) { + fiber.alternate.pendingProps = fiber.pendingProps; } - function getCurrentFiberForDevTools() { - return current; + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane); } + }; - function injectIntoDevTools(devToolsConfig) { - var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; - 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: ReactSharedInternals, - 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 - }); + scheduleUpdate = function (fiber) { + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane); } + }; - function findHostInstance_DEPRECATED(componentOrHandle) { - { - var owner = ReactSharedInternals.owner; - - 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" - ); - } + setErrorHandler = function (newShouldErrorImpl) { + shouldErrorImpl = newShouldErrorImpl; + }; - owner.stateNode._warnedAboutRefsInRender = true; - } - } + setSuspenseHandler = function (newShouldSuspendImpl) { + shouldSuspendImpl = newShouldSuspendImpl; + }; +} - if (componentOrHandle == null) { - return null; - } // For compatibility with Fabric instances +function findHostInstanceByFiber(fiber) { + var hostFiber = findCurrentHostFiber(fiber); - 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 (hostFiber === null) { + return null; + } - if (componentOrHandle._nativeTag) { - // $FlowFixMe[incompatible-exact] Necessary when running Flow on Fabric - // $FlowFixMe[incompatible-return] - return componentOrHandle; - } + return hostFiber.stateNode; +} - var hostInstance; +function emptyFindFiberByHostInstance(instance) { + return null; +} - { - 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] +function getCurrentFiberForDevTools() { + return current; +} - return hostInstance; - } - function findNodeHandle(componentOrHandle) { - { - var owner = ReactSharedInternals.owner; - - 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" - ); - } +function injectIntoDevTools(devToolsConfig) { + var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; + 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: ReactSharedInternals, + 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 + }); +} - owner.stateNode._warnedAboutRefsInRender = true; - } - } +function findHostInstance_DEPRECATED(componentOrHandle) { + { + var owner = ReactSharedInternals.owner; - if (componentOrHandle == null) { - return null; + 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 (typeof componentOrHandle === "number") { - // Already a node handle - return componentOrHandle; - } // For compatibility with legacy renderer instances + owner.stateNode._warnedAboutRefsInRender = true; + } + } - if (componentOrHandle._nativeTag) { - return componentOrHandle._nativeTag; - } // For compatibility with Fabric instances + if (componentOrHandle == null) { + return null; + } // 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 = - ReactNativePrivateInterface.getNativeTagFromPublicInstance( - componentOrHandle - ); + 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 (nativeTag) { - return nativeTag; - } - var hostInstance; + if (componentOrHandle._nativeTag) { + // $FlowFixMe[incompatible-exact] Necessary when running Flow on Fabric + // $FlowFixMe[incompatible-return] + return componentOrHandle; + } - { - hostInstance = findHostInstanceWithWarning( - componentOrHandle, - "findNodeHandle" - ); - } + 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] - if (hostInstance == null) { - // $FlowFixMe[incompatible-return] Flow limitation in refining an opaque type - return hostInstance; - } - if (hostInstance._nativeTag != null) { - // $FlowFixMe[incompatible-return] For compatibility with legacy renderer instances - return hostInstance._nativeTag; - } // $FlowFixMe[incompatible-call] Necessary when running Flow on the legacy renderer + return hostInstance; +} +function findNodeHandle(componentOrHandle) { + { + var owner = ReactSharedInternals.owner; + + 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'); + } - return ReactNativePrivateInterface.getNativeTagFromPublicInstance( - hostInstance - ); + owner.stateNode._warnedAboutRefsInRender = true; } - function dispatchCommand(handle, command, args) { - var nativeTag = - handle._nativeTag != null - ? handle._nativeTag - : ReactNativePrivateInterface.getNativeTagFromPublicInstance(handle); + } - 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 (componentOrHandle == null) { + return null; + } - return; - } + if (typeof componentOrHandle === 'number') { + // Already a node handle + return componentOrHandle; + } // For compatibility with legacy renderer instances - 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 (componentOrHandle._nativeTag) { + return componentOrHandle._nativeTag; + } // For compatibility with Fabric instances - 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" - ); - } - return; - } + if (componentOrHandle.canonical != null && componentOrHandle.canonical.nativeTag != null) { + return componentOrHandle.canonical.nativeTag; + } // For compatibility with Fabric public instances - var node = ReactNativePrivateInterface.getNodeFromPublicInstance(handle); - 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 - ); - } // Should have been PublicInstance from ReactFiberConfigFabric - // Should have been PublicInstance from ReactFiberConfigNative - // Remove this once Paper is no longer supported and DOM Node API are enabled by default in RN. - - function isChildPublicInstance(parentInstance, childInstance) { - { - // Paper - if ( - // $FlowExpectedError[incompatible-type] - // $FlowExpectedError[prop-missing] Don't check via `instanceof ReactNativeFiberHostComponent`, so it won't be leaked to Fabric. - parentInstance._internalFiberInstanceHandleDEV && // $FlowExpectedError[incompatible-type] - // $FlowExpectedError[prop-missing] Don't check via `instanceof ReactNativeFiberHostComponent`, so it won't be leaked to Fabric. - childInstance._internalFiberInstanceHandleDEV - ) { - return doesFiberContain( - // $FlowExpectedError[incompatible-call] - parentInstance._internalFiberInstanceHandleDEV, // $FlowExpectedError[incompatible-call] - childInstance._internalFiberInstanceHandleDEV - ); - } - - var parentInternalInstanceHandle = // $FlowExpectedError[incompatible-call] Type for parentInstance should have been PublicInstance from ReactFiberConfigFabric. - ReactNativePrivateInterface.getInternalInstanceHandleFromPublicInstance( - parentInstance - ); - var childInternalInstanceHandle = // $FlowExpectedError[incompatible-call] Type for childInstance should have been PublicInstance from ReactFiberConfigFabric. - ReactNativePrivateInterface.getInternalInstanceHandleFromPublicInstance( - childInstance - ); // Fabric - - if ( - parentInternalInstanceHandle != null && - childInternalInstanceHandle != null - ) { - return doesFiberContain( - parentInternalInstanceHandle, - childInternalInstanceHandle - ); - } // Means that one instance is from Fabric and other is from Paper. + var nativeTag = ReactNativePrivateInterface.getNativeTagFromPublicInstance(componentOrHandle); - return false; - } - } + if (nativeTag) { + return nativeTag; + } - var emptyObject = {}; + var hostInstance; - { - Object.freeze(emptyObject); - } // $FlowFixMe[missing-local-annot] + { + hostInstance = findHostInstanceWithWarning(componentOrHandle, 'findNodeHandle'); + } - function createHierarchy(fiberHierarchy) { - return fiberHierarchy.map(function (fiber) { - return { - name: getComponentNameFromType(fiber.type), - getInspectorData: function (findNodeHandle) { - return { - props: getHostProps(fiber), - measure: function (callback) { - // If this is Fabric, we'll find a shadow node and use that to measure. - var hostFiber = findCurrentHostFiber(fiber); - var node = - hostFiber != null && - hostFiber.stateNode !== null && - hostFiber.stateNode.node; - - if (node) { - nativeFabricUIManager.measure(node, callback); - } else { - return ReactNativePrivateInterface.UIManager.measure( - getHostNode(fiber, findNodeHandle), - callback - ); - } - } - }; - } - }; - }); - } // $FlowFixMe[missing-local-annot] + if (hostInstance == null) { + // $FlowFixMe[incompatible-return] Flow limitation in refining an opaque type + return hostInstance; + } - function getHostNode(fiber, findNodeHandle) { - { - var hostNode; // look for children first for the hostNode - // as composite fibers do not have a hostNode + if (hostInstance._nativeTag != null) { + // $FlowFixMe[incompatible-return] For compatibility with legacy renderer instances + return hostInstance._nativeTag; + } // $FlowFixMe[incompatible-call] Necessary when running Flow on the legacy renderer - while (fiber) { - if (fiber.stateNode !== null && fiber.tag === HostComponent) { - hostNode = findNodeHandle(fiber.stateNode); - } - if (hostNode) { - return hostNode; - } + return ReactNativePrivateInterface.getNativeTagFromPublicInstance(hostInstance); +} +function dispatchCommand(handle, command, args) { + var nativeTag = handle._nativeTag != null ? handle._nativeTag : ReactNativePrivateInterface.getNativeTagFromPublicInstance(handle); - fiber = fiber.child; - } + 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'); + } - return null; - } - } // $FlowFixMe[missing-local-annot] + return; + } - function getHostProps(fiber) { - var host = findCurrentHostFiber(fiber); + var node = ReactNativePrivateInterface.getNodeFromPublicInstance(handle); - if (host) { - return host.memoizedProps || emptyObject; - } + 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); - return emptyObject; + 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'); } - function getInspectorDataForInstance(closestInstance) { - { - // Handle case where user clicks outside of ReactNative - if (!closestInstance) { - return { - hierarchy: [], - props: emptyObject, - selectedIndex: null, - componentStack: "" - }; - } + return; + } - var fiber = findCurrentFiberUsingSlowPath(closestInstance); + var node = ReactNativePrivateInterface.getNodeFromPublicInstance(handle); - if (fiber === null) { - // Might not be currently mounted. - return { - hierarchy: [], - props: emptyObject, - selectedIndex: null, - componentStack: "" - }; - } + 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 + ); +} // Should have been PublicInstance from ReactFiberConfigFabric +// Should have been PublicInstance from ReactFiberConfigNative +// Remove this once Paper is no longer supported and DOM Node API are enabled by default in RN. + +function isChildPublicInstance(parentInstance, childInstance) { + { + // Paper + if ( // $FlowExpectedError[incompatible-type] + // $FlowExpectedError[prop-missing] Don't check via `instanceof ReactNativeFiberHostComponent`, so it won't be leaked to Fabric. + parentInstance._internalFiberInstanceHandleDEV && // $FlowExpectedError[incompatible-type] + // $FlowExpectedError[prop-missing] Don't check via `instanceof ReactNativeFiberHostComponent`, so it won't be leaked to Fabric. + childInstance._internalFiberInstanceHandleDEV) { + return doesFiberContain( // $FlowExpectedError[incompatible-call] + parentInstance._internalFiberInstanceHandleDEV, // $FlowExpectedError[incompatible-call] + childInstance._internalFiberInstanceHandleDEV); + } + + var parentInternalInstanceHandle = // $FlowExpectedError[incompatible-call] Type for parentInstance should have been PublicInstance from ReactFiberConfigFabric. + ReactNativePrivateInterface.getInternalInstanceHandleFromPublicInstance(parentInstance); + var childInternalInstanceHandle = // $FlowExpectedError[incompatible-call] Type for childInstance should have been PublicInstance from ReactFiberConfigFabric. + ReactNativePrivateInterface.getInternalInstanceHandleFromPublicInstance(childInstance); // Fabric + + if (parentInternalInstanceHandle != null && childInternalInstanceHandle != null) { + return doesFiberContain(parentInternalInstanceHandle, childInternalInstanceHandle); + } // Means that one instance is from Fabric and other is from Paper. + + + return false; + } +} + +var emptyObject = {}; - var fiberHierarchy = getOwnerHierarchy(fiber); - var instance = lastNonHostInstance(fiberHierarchy); - var hierarchy = createHierarchy(fiberHierarchy); - var props = getHostProps(instance); - var selectedIndex = fiberHierarchy.indexOf(instance); - var componentStack = getStackByFiberInDevAndProd(fiber); +{ + Object.freeze(emptyObject); +} // $FlowFixMe[missing-local-annot] + + +function createHierarchy(fiberHierarchy) { + return fiberHierarchy.map(function (fiber) { + return { + name: getComponentNameFromType(fiber.type), + getInspectorData: function (findNodeHandle) { return { - closestInstance: instance, - hierarchy: hierarchy, - props: props, - selectedIndex: selectedIndex, - componentStack: componentStack + props: getHostProps(fiber), + measure: function (callback) { + // If this is Fabric, we'll find a shadow node and use that to measure. + var hostFiber = findCurrentHostFiber(fiber); + var node = hostFiber != null && hostFiber.stateNode !== null && hostFiber.stateNode.node; + + if (node) { + nativeFabricUIManager.measure(node, callback); + } else { + return ReactNativePrivateInterface.UIManager.measure(getHostNode(fiber, findNodeHandle), callback); + } + } }; } - } + }; + }); +} // $FlowFixMe[missing-local-annot] - function getOwnerHierarchy(instance) { - var hierarchy = []; - traverseOwnerTreeUp(hierarchy, instance); - return hierarchy; - } // $FlowFixMe[missing-local-annot] - function lastNonHostInstance(hierarchy) { - for (var i = hierarchy.length - 1; i > 1; i--) { - var instance = hierarchy[i]; +function getHostNode(fiber, findNodeHandle) { + { + var hostNode; // look for children first for the hostNode + // as composite fibers do not have a hostNode - if (instance.tag !== HostComponent) { - return instance; - } + while (fiber) { + if (fiber.stateNode !== null && fiber.tag === HostComponent) { + hostNode = findNodeHandle(fiber.stateNode); } - return hierarchy[0]; + if (hostNode) { + return hostNode; + } + + fiber = fiber.child; } - function traverseOwnerTreeUp(hierarchy, instance) { - { - hierarchy.unshift(instance); - var owner = instance._debugOwner; + return null; + } +} // $FlowFixMe[missing-local-annot] - if (owner != null && typeof owner.tag === "number") { - traverseOwnerTreeUp(hierarchy, owner); - } - } - } - function getInspectorDataForViewTag(viewTag) { - { - var closestInstance = getInstanceFromTag(viewTag); - return getInspectorDataForInstance(closestInstance); - } - } +function getHostProps(fiber) { + var host = findCurrentHostFiber(fiber); - function getInspectorDataForViewAtPoint( - findNodeHandle, - inspectedView, - locationX, - locationY, - callback - ) { - { - var closestInstance = null; - var fabricNode = - ReactNativePrivateInterface.getNodeFromPublicInstance(inspectedView); - - if (fabricNode) { - // For Fabric we can look up the instance handle directly and measure it. - nativeFabricUIManager.findNodeAtPoint( - fabricNode, - locationX, - locationY, - function (internalInstanceHandle) { - var node = - internalInstanceHandle != null - ? getNodeFromInternalInstanceHandle(internalInstanceHandle) - : null; - - if (internalInstanceHandle == null || node == null) { - callback( - assign( - { - pointerY: locationY, - frame: { - left: 0, - top: 0, - width: 0, - height: 0 - } - }, - getInspectorDataForInstance(closestInstance) - ) - ); - return; - } + if (host) { + return host.memoizedProps || emptyObject; + } - closestInstance = - internalInstanceHandle.stateNode.canonical - .internalInstanceHandle; // Note: this is deprecated and we want to remove it ASAP. Keeping it here for React DevTools compatibility for now. - - var nativeViewTag = - internalInstanceHandle.stateNode.canonical.nativeTag; - nativeFabricUIManager.measure( - node, - function (x, y, width, height, pageX, pageY) { - var inspectorData = - getInspectorDataForInstance(closestInstance); - callback( - assign({}, inspectorData, { - pointerY: locationY, - frame: { - left: pageX, - top: pageY, - width: width, - height: height - }, - touchedViewTag: nativeViewTag - }) - ); - } - ); - } - ); - } else if (inspectedView._internalFiberInstanceHandleDEV != null) { - // For Paper we fall back to the old strategy using the React tag. - ReactNativePrivateInterface.UIManager.findSubviewIn( - findNodeHandle(inspectedView), - [locationX, locationY], - function (nativeViewTag, left, top, width, height) { - var inspectorData = getInspectorDataForInstance( - getInstanceFromTag(nativeViewTag) - ); - callback( - assign({}, inspectorData, { - pointerY: locationY, - frame: { - left: left, - top: top, - width: width, - height: height - }, - touchedViewTag: nativeViewTag - }) - ); - } - ); - } else { - error( - "getInspectorDataForViewAtPoint expects to receive a host component" - ); + return emptyObject; +} - return; - } - } +function getInspectorDataForInstance(closestInstance) { + { + // Handle case where user clicks outside of ReactNative + if (!closestInstance) { + return { + hierarchy: [], + props: emptyObject, + selectedIndex: null, + componentStack: '' + }; } - if ( - typeof ReactNativePrivateInterface.ReactFiberErrorDialog - .showErrorDialog !== "function" - ) { - throw new Error( - "Expected ReactFiberErrorDialog.showErrorDialog to be a function." - ); - } + var fiber = findCurrentFiberUsingSlowPath(closestInstance); - function nativeOnUncaughtError(error, errorInfo) { - var componentStack = - errorInfo.componentStack != null ? errorInfo.componentStack : ""; - var logError = - ReactNativePrivateInterface.ReactFiberErrorDialog.showErrorDialog({ - errorBoundary: null, - error: error, - componentStack: componentStack - }); // Allow injected showErrorDialog() to prevent default console.error logging. - // This enables renderers like ReactNative to better manage redbox behavior. + if (fiber === null) { + // Might not be currently mounted. + return { + hierarchy: [], + props: emptyObject, + selectedIndex: null, + componentStack: '' + }; + } - if (logError === false) { - return; - } + var fiberHierarchy = getOwnerHierarchy(fiber); + var instance = lastNonHostInstance(fiberHierarchy); + var hierarchy = createHierarchy(fiberHierarchy); + var props = getHostProps(instance); + var selectedIndex = fiberHierarchy.indexOf(instance); + var componentStack = getStackByFiberInDevAndProd(fiber); + return { + closestInstance: instance, + hierarchy: hierarchy, + props: props, + selectedIndex: selectedIndex, + componentStack: componentStack + }; + } +} - defaultOnUncaughtError(error, errorInfo); - } +function getOwnerHierarchy(instance) { + var hierarchy = []; + traverseOwnerTreeUp(hierarchy, instance); + return hierarchy; +} // $FlowFixMe[missing-local-annot] - function nativeOnCaughtError(error, errorInfo) { - var errorBoundary = errorInfo.errorBoundary; - var componentStack = - errorInfo.componentStack != null ? errorInfo.componentStack : ""; - var logError = - ReactNativePrivateInterface.ReactFiberErrorDialog.showErrorDialog({ - errorBoundary: errorBoundary, - error: error, - componentStack: componentStack - }); // Allow injected showErrorDialog() to prevent default console.error logging. - // This enables renderers like ReactNative to better manage redbox behavior. - if (logError === false) { - return; - } +function lastNonHostInstance(hierarchy) { + for (var i = hierarchy.length - 1; i > 1; i--) { + var instance = hierarchy[i]; - defaultOnCaughtError(error, errorInfo); + if (instance.tag !== HostComponent) { + return instance; } + } - function render(element, containerTag, callback, options) { - var root = roots.get(containerTag); + return hierarchy[0]; +} - if (!root) { - // TODO: these defaults are for backwards compatibility. - // Once RN implements these options internally, - // we can remove the defaults and ReactFiberErrorDialog. - var onUncaughtError = nativeOnUncaughtError; - var onCaughtError = nativeOnCaughtError; - var onRecoverableError = defaultOnRecoverableError; +function traverseOwnerTreeUp(hierarchy, instance) { + { + hierarchy.unshift(instance); + var owner = instance._debugOwner; - if (options && options.onUncaughtError !== undefined) { - onUncaughtError = options.onUncaughtError; - } + if (owner != null && typeof owner.tag === 'number') { + traverseOwnerTreeUp(hierarchy, owner); + } + } +} - if (options && options.onCaughtError !== undefined) { - onCaughtError = options.onCaughtError; +function getInspectorDataForViewTag(viewTag) { + { + var closestInstance = getInstanceFromTag(viewTag); + return getInspectorDataForInstance(closestInstance); + } +} + +function getInspectorDataForViewAtPoint(findNodeHandle, inspectedView, locationX, locationY, callback) { + { + var closestInstance = null; + var fabricNode = ReactNativePrivateInterface.getNodeFromPublicInstance(inspectedView); + + if (fabricNode) { + // For Fabric we can look up the instance handle directly and measure it. + nativeFabricUIManager.findNodeAtPoint(fabricNode, locationX, locationY, function (internalInstanceHandle) { + var node = internalInstanceHandle != null ? getNodeFromInternalInstanceHandle(internalInstanceHandle) : null; + + if (internalInstanceHandle == null || node == null) { + callback(assign({ + pointerY: locationY, + frame: { + left: 0, + top: 0, + width: 0, + height: 0 + } + }, getInspectorDataForInstance(closestInstance))); + return; } - if (options && options.onRecoverableError !== undefined) { - onRecoverableError = options.onRecoverableError; - } // TODO (bvaughn): If we decide to keep the wrapper component, - // We could create a wrapper for containerTag as well to reduce special casing. + closestInstance = internalInstanceHandle.stateNode.canonical.internalInstanceHandle; // Note: this is deprecated and we want to remove it ASAP. Keeping it here for React DevTools compatibility for now. - root = createContainer( - containerTag, - LegacyRoot, - null, - false, - null, - "", - onUncaughtError, - onCaughtError, - onRecoverableError, - null - ); - roots.set(containerTag, root); - } + var nativeViewTag = internalInstanceHandle.stateNode.canonical.nativeTag; + nativeFabricUIManager.measure(node, function (x, y, width, height, pageX, pageY) { + var inspectorData = getInspectorDataForInstance(closestInstance); + callback(assign({}, inspectorData, { + pointerY: locationY, + frame: { + left: pageX, + top: pageY, + width: width, + height: height + }, + touchedViewTag: nativeViewTag + })); + }); + }); + } else if (inspectedView._internalFiberInstanceHandleDEV != null) { + // For Paper we fall back to the old strategy using the React tag. + ReactNativePrivateInterface.UIManager.findSubviewIn(findNodeHandle(inspectedView), [locationX, locationY], function (nativeViewTag, left, top, width, height) { + var inspectorData = getInspectorDataForInstance(getInstanceFromTag(nativeViewTag)); + callback(assign({}, inspectorData, { + pointerY: locationY, + frame: { + left: left, + top: top, + width: width, + height: height + }, + touchedViewTag: nativeViewTag + })); + }); + } else { + error('getInspectorDataForViewAtPoint expects to receive a host component'); - updateContainer(element, root, null, callback); - return getPublicRootInstance(root); + return; } + } +} - function unmountComponentAtNode(containerTag) { - var root = roots.get(containerTag); +if (typeof ReactNativePrivateInterface.ReactFiberErrorDialog.showErrorDialog !== 'function') { + throw new Error('Expected ReactFiberErrorDialog.showErrorDialog to be a function.'); +} - if (root) { - // TODO: Is it safe to reset this now or should I wait since this unmount could be deferred? - updateContainer(null, root, null, function () { - roots.delete(containerTag); - }); - } - } +function nativeOnUncaughtError(error, errorInfo) { + var componentStack = errorInfo.componentStack != null ? errorInfo.componentStack : ''; + var logError = ReactNativePrivateInterface.ReactFiberErrorDialog.showErrorDialog({ + errorBoundary: null, + error: error, + componentStack: componentStack + }); // Allow injected showErrorDialog() to prevent default console.error logging. + // This enables renderers like ReactNative to better manage redbox behavior. + + if (logError === false) { + return; + } + + defaultOnUncaughtError(error, errorInfo); +} + +function nativeOnCaughtError(error, errorInfo) { + var errorBoundary = errorInfo.errorBoundary; + var componentStack = errorInfo.componentStack != null ? errorInfo.componentStack : ''; + var logError = ReactNativePrivateInterface.ReactFiberErrorDialog.showErrorDialog({ + errorBoundary: errorBoundary, + error: error, + componentStack: componentStack + }); // Allow injected showErrorDialog() to prevent default console.error logging. + // This enables renderers like ReactNative to better manage redbox behavior. + + if (logError === false) { + return; + } + + defaultOnCaughtError(error, errorInfo); +} + +function render(element, containerTag, callback, options) { - function unmountComponentAtNodeAndRemoveContainer(containerTag) { - unmountComponentAtNode(containerTag); // Call back into native to remove all of the subviews from this container + var root = roots.get(containerTag); - ReactNativePrivateInterface.UIManager.removeRootView(containerTag); + if (!root) { + // TODO: these defaults are for backwards compatibility. + // Once RN implements these options internally, + // we can remove the defaults and ReactFiberErrorDialog. + var onUncaughtError = nativeOnUncaughtError; + var onCaughtError = nativeOnCaughtError; + var onRecoverableError = defaultOnRecoverableError; + + if (options && options.onUncaughtError !== undefined) { + onUncaughtError = options.onUncaughtError; } - function createPortal(children, containerTag) { - var key = - arguments.length > 2 && arguments[2] !== undefined - ? arguments[2] - : null; - return createPortal$1(children, containerTag, null, key); + if (options && options.onCaughtError !== undefined) { + onCaughtError = options.onCaughtError; } - setBatchingImplementation(batchedUpdates); + if (options && options.onRecoverableError !== undefined) { + onRecoverableError = options.onRecoverableError; + } // TODO (bvaughn): If we decide to keep the wrapper component, + // We could create a wrapper for containerTag as well to reduce special casing. - function computeComponentStackForErrorReporting(reactTag) { - var fiber = getInstanceFromTag(reactTag); - if (!fiber) { - return ""; - } + root = createContainer(containerTag, LegacyRoot, null, false, null, '', onUncaughtError, onCaughtError, onRecoverableError, null); + roots.set(containerTag, root); + } - return getStackByFiberInDevAndProd(fiber); - } + updateContainer(element, root, null, callback); + return getPublicRootInstance(root); +} - var roots = new Map(); - var Internals = { - computeComponentStackForErrorReporting: - computeComponentStackForErrorReporting - }; - injectIntoDevTools({ - findFiberByHostInstance: getInstanceFromTag, - bundleType: 1, - version: ReactVersion, - rendererPackageName: "react-native-renderer", - rendererConfig: { - getInspectorDataForInstance: getInspectorDataForInstance, - getInspectorDataForViewTag: getInspectorDataForViewTag, - getInspectorDataForViewAtPoint: getInspectorDataForViewAtPoint.bind( - null, - findNodeHandle - ) - } +function unmountComponentAtNode(containerTag) { + var root = roots.get(containerTag); + + if (root) { + // TODO: Is it safe to reset this now or should I wait since this unmount could be deferred? + updateContainer(null, root, null, function () { + roots.delete(containerTag); }); + } +} - exports.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = Internals; - exports.createPortal = createPortal; - exports.dispatchCommand = dispatchCommand; - exports.findHostInstance_DEPRECATED = findHostInstance_DEPRECATED; - exports.findNodeHandle = findNodeHandle; - exports.getInspectorDataForInstance = getInspectorDataForInstance; - exports.isChildPublicInstance = isChildPublicInstance; - exports.render = render; - exports.sendAccessibilityEvent = sendAccessibilityEvent; - exports.unmountComponentAtNode = unmountComponentAtNode; - exports.unmountComponentAtNodeAndRemoveContainer = - unmountComponentAtNodeAndRemoveContainer; - exports.unstable_batchedUpdates = batchedUpdates$1; - /* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */ - if ( - typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== "undefined" && - typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop === - "function" - ) { - __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(new Error()); - } +function unmountComponentAtNodeAndRemoveContainer(containerTag) { + unmountComponentAtNode(containerTag); // Call back into native to remove all of the subviews from this container + + ReactNativePrivateInterface.UIManager.removeRootView(containerTag); +} + +function createPortal(children, containerTag) { + var key = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; + return createPortal$1(children, containerTag, null, key); +} + +setBatchingImplementation(batchedUpdates); + +function computeComponentStackForErrorReporting(reactTag) { + var fiber = getInstanceFromTag(reactTag); + + if (!fiber) { + return ''; + } + + return getStackByFiberInDevAndProd(fiber); +} + +var roots = new Map(); +var Internals = { + computeComponentStackForErrorReporting: computeComponentStackForErrorReporting +}; +injectIntoDevTools({ + findFiberByHostInstance: getInstanceFromTag, + bundleType: 1 , + version: ReactVersion, + rendererPackageName: 'react-native-renderer', + rendererConfig: { + getInspectorDataForInstance: getInspectorDataForInstance, + getInspectorDataForViewTag: getInspectorDataForViewTag, + getInspectorDataForViewAtPoint: getInspectorDataForViewAtPoint.bind(null, findNodeHandle) + } +}); + +exports.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = Internals; +exports.createPortal = createPortal; +exports.dispatchCommand = dispatchCommand; +exports.findHostInstance_DEPRECATED = findHostInstance_DEPRECATED; +exports.findNodeHandle = findNodeHandle; +exports.getInspectorDataForInstance = getInspectorDataForInstance; +exports.isChildPublicInstance = isChildPublicInstance; +exports.render = render; +exports.sendAccessibilityEvent = sendAccessibilityEvent; +exports.unmountComponentAtNode = unmountComponentAtNode; +exports.unmountComponentAtNodeAndRemoveContainer = unmountComponentAtNodeAndRemoveContainer; +exports.unstable_batchedUpdates = batchedUpdates$1; + /* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */ +if ( + typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' && + typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop === + 'function' +) { + __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(new Error()); +} + })(); }