/** @license React v16.8.6 * react-test-renderer.production.min.js * * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require("resource://devtools/client/shared/vendor/react.js")) : typeof define === 'function' && define.amd ? define(['devtools/client/shared/vendor/react'], factory) : (global.ReactTestRenderer = factory(global.React)); }(this, (function (React) { 'use strict'; /** * Use invariant() to assert state which your program assumes to be true. * * Provide sprintf-style format (only %s is supported) and arguments * to provide information about what broke and what you were * expecting. * * The invariant message will be stripped in production, but the invariant * will remain to ensure logic does not differ in production. */ function invariant(condition, format, a, b, c, d, e, f) { if (!condition) { var error = void 0; if (format === undefined) { error = new Error('Minified exception occurred; use the non-minified dev environment ' + 'for the full error message and additional helpful warnings.'); } else { var args = [a, b, c, d, e, f]; var argIndex = 0; error = new Error(format.replace(/%s/g, function () { return args[argIndex++]; })); error.name = 'Invariant Violation'; } error.framesToPop = 1; // we don't care about invariant's own frame throw error; } } // Relying on the `invariant()` implementation lets us // preserve the format and params in the www builds. /** * WARNING: DO NOT manually require this module. * This is a replacement for `invariant(...)` used by the error code system * and will _only_ be required by the corresponding babel pass. * It always throws. */ function reactProdInvariant(code) { var argCount = arguments.length - 1; var url = 'https://reactjs.org/docs/error-decoder.html?invariant=' + code; for (var argIdx = 0; argIdx < argCount; argIdx++) { url += '&args[]=' + encodeURIComponent(arguments[argIdx + 1]); } // Rename it so that our build transform doesn't attempt // to replace this invariant() call with reactProdInvariant(). var i = invariant; i(false, // The error code is intentionally part of the message (and // not the format argument) so that we could deduplicate // different errors in logs based on the code. 'Minified React error #' + code + '; visit %s ' + 'for the full message or use the non-minified dev environment ' + 'for full errors and additional helpful warnings. ', url); } var ReactInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; var _assign = ReactInternals.assign; /** * Similar to invariant but only logs a warning if the condition is not met. * This can be used to log issues in development environments in critical * paths. Removing the logging code for production environments will keep the * same logic and follow the same code paths. */ /** * `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. */ /** * This API should be called `delete` but we'd have to make sure to always * transform these to strings for IE support. When this transform is fully * supported we can rename it. */ function get(key) { return key._reactInternalFiber; } function set(key, value) { key._reactInternalFiber = value; } var ReactSharedInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; // Prevent newer renderers from RTE when used with older react package versions. // Current owner and dispatcher used to share the same ref, // but PR #14548 split them out to better support the react-debug-tools package. if (!ReactSharedInternals.hasOwnProperty('ReactCurrentDispatcher')) { ReactSharedInternals.ReactCurrentDispatcher = { current: null }; } // The Symbol used to tag the ReactElement-like types. If there is no native Symbol // nor polyfill, then a plain number is used for performance. var hasSymbol = typeof Symbol === 'function' && Symbol.for; var REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for('react.element') : 0xeac7; var REACT_PORTAL_TYPE = hasSymbol ? Symbol.for('react.portal') : 0xeaca; var REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for('react.fragment') : 0xeacb; var REACT_STRICT_MODE_TYPE = hasSymbol ? Symbol.for('react.strict_mode') : 0xeacc; var REACT_PROFILER_TYPE = hasSymbol ? Symbol.for('react.profiler') : 0xead2; var REACT_PROVIDER_TYPE = hasSymbol ? Symbol.for('react.provider') : 0xeacd; var REACT_CONTEXT_TYPE = hasSymbol ? Symbol.for('react.context') : 0xeace; var REACT_CONCURRENT_MODE_TYPE = hasSymbol ? Symbol.for('react.concurrent_mode') : 0xeacf; var REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0; var REACT_SUSPENSE_TYPE = hasSymbol ? Symbol.for('react.suspense') : 0xead1; var REACT_MEMO_TYPE = hasSymbol ? Symbol.for('react.memo') : 0xead3; var REACT_LAZY_TYPE = hasSymbol ? Symbol.for('react.lazy') : 0xead4; var MAYBE_ITERATOR_SYMBOL = typeof Symbol === 'function' && 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 Pending = 0; var Resolved = 1; var Rejected = 2; function refineResolvedLazyComponent(lazyComponent) { return lazyComponent._status === Resolved ? lazyComponent._result : null; } function getWrappedName(outerType, innerType, wrapperName) { var functionName = innerType.displayName || innerType.name || ''; return outerType.displayName || (functionName !== '' ? wrapperName + '(' + functionName + ')' : wrapperName); } function getComponentName(type) { if (type == null) { // Host root, text node or just invalid type. return null; } if (typeof type === 'function') { return type.displayName || type.name || null; } if (typeof type === 'string') { return type; } switch (type) { case REACT_CONCURRENT_MODE_TYPE: return 'ConcurrentMode'; 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'; } if (typeof type === 'object') { switch (type.$$typeof) { case REACT_CONTEXT_TYPE: return 'Context.Consumer'; case REACT_PROVIDER_TYPE: return 'Context.Provider'; case REACT_FORWARD_REF_TYPE: return getWrappedName(type, type.render, 'ForwardRef'); case REACT_MEMO_TYPE: return getComponentName(type.type); case REACT_LAZY_TYPE: { var thenable = type; var resolvedThenable = refineResolvedLazyComponent(thenable); if (resolvedThenable) { return getComponentName(resolvedThenable); } } } } return null; } var FunctionComponent = 0; var ClassComponent = 1; var IndeterminateComponent = 2; // Before we know whether it is function or class 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 DehydratedSuspenseComponent = 18; // Don't change these two values. They're used by React Dev Tools. var NoEffect = /* */0; var PerformedWork = /* */1; // You can change the rest (and add more). var Placement = /* */2; var Update = /* */4; var PlacementAndUpdate = /* */6; var Deletion = /* */8; var ContentReset = /* */16; var Callback = /* */32; var DidCapture = /* */64; var Ref = /* */128; var Snapshot = /* */256; var Passive = /* */512; // Passive & Update & Callback & Ref & Snapshot var LifecycleEffectMask = /* */932; // Union of all host effects var HostEffectMask = /* */1023; var Incomplete = /* */1024; var ShouldCapture = /* */2048; var ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner; var MOUNTING = 1; var MOUNTED = 2; var UNMOUNTED = 3; function isFiberMountedImpl(fiber) { var node = 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. if ((node.effectTag & Placement) !== NoEffect) { return MOUNTING; } while (node.return) { node = node.return; if ((node.effectTag & Placement) !== NoEffect) { return MOUNTING; } } } else { while (node.return) { node = node.return; } } if (node.tag === HostRoot) { // TODO: Check if this was a nested HostRoot when used with // renderContainerIntoSubtree. return MOUNTED; } // If we didn't hit the root, that means that we're in an disconnected tree // that has been unmounted. return UNMOUNTED; } function isFiberMounted(fiber) { return isFiberMountedImpl(fiber) === MOUNTED; } function isMounted(component) { var fiber = get(component); if (!fiber) { return false; } return isFiberMountedImpl(fiber) === MOUNTED; } function assertIsMounted(fiber) { !(isFiberMountedImpl(fiber) === MOUNTED) ? reactProdInvariant('188') : void 0; } function findCurrentFiberUsingSlowPath(fiber) { var alternate = fiber.alternate; if (!alternate) { // If there is no alternate, then we only need to check if it is mounted. var state = isFiberMountedImpl(fiber); !(state !== UNMOUNTED) ? reactProdInvariant('188') : void 0; if (state === MOUNTING) { return null; } return fiber; } // If we have two possible branches, we'll walk backwards up to the root // to see what path the root points to. On the way we may hit one of the // special cases and we'll deal with them. var a = fiber; var b = alternate; while (true) { var parentA = a.return; var parentB = parentA ? parentA.alternate : null; if (!parentA || !parentB) { // We're at the root. break; } // If both copies of the parent fiber point to the same child, we can // assume that the child is current. This happens when we bailout on low // priority: the bailed out fiber's child reuses the current child. if (parentA.child === parentB.child) { var child = parentA.child; while (child) { if (child === a) { // We've determined that A is the current branch. assertIsMounted(parentA); return fiber; } if (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. reactProdInvariant('188'); } if (a.return !== b.return) { // The return pointer of A and the return pointer of B point to different // fibers. We assume that return pointers never criss-cross, so A must // belong to the child set of A.return, and B must belong to the child // set of B.return. a = parentA; b = parentB; } else { // The return pointers point to the same fiber. We'll have to use the // default, slow path: scan the child sets of each parent alternate to see // which child belongs to which set. // // Search parent A's child set var didFindChild = false; var _child = parentA.child; while (_child) { if (_child === a) { didFindChild = true; a = parentA; b = parentB; break; } if (_child === b) { didFindChild = true; b = parentA; a = parentB; break; } _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; } _child = _child.sibling; } !didFindChild ? reactProdInvariant('189') : void 0; } } !(a.alternate === b) ? reactProdInvariant('190') : void 0; } // If the root is not a host container, we're in a disconnected tree. I.e. // unmounted. !(a.tag === HostRoot) ? reactProdInvariant('188') : void 0; 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); if (!currentParent) { return null; } // Next we'll drill down this component to find the first HostComponent/Text. var node = currentParent; while (true) { if (node.tag === HostComponent || node.tag === HostText) { return node; } else if (node.child) { node.child.return = node; node = node.child; continue; } if (node === currentParent) { return null; } while (!node.sibling) { if (!node.return || node.return === currentParent) { return null; } node = node.return; } node.sibling.return = node.return; node = node.sibling; } // Flow needs the return null here, but ESLint complains about it. // eslint-disable-next-line no-unreachable return null; } // Current virtual time var nowImplementation = function () { return 0; }; var scheduledCallback = null; var yieldedValues = []; var didStop = false; var expectedNumberOfYields = -1; function scheduleDeferredCallback$1(callback, options) { scheduledCallback = callback; var fakeCallbackId = 0; return fakeCallbackId; } function cancelDeferredCallback$1(timeoutID) { scheduledCallback = null; } function setNowImplementation(implementation) { nowImplementation = implementation; } function shouldYield$1() { if (expectedNumberOfYields !== -1 && yieldedValues.length >= expectedNumberOfYields) { // We yielded at least as many values as expected. Stop rendering. didStop = true; return true; } // Keep rendering. return false; } function flushAll() { yieldedValues = []; while (scheduledCallback !== null) { var cb = scheduledCallback; scheduledCallback = null; cb(); } var values = yieldedValues; yieldedValues = []; return values; } function flushNumberOfYields(count) { expectedNumberOfYields = count; didStop = false; yieldedValues = []; try { while (scheduledCallback !== null && !didStop) { var cb = scheduledCallback; scheduledCallback = null; cb(); } return yieldedValues; } finally { expectedNumberOfYields = -1; didStop = false; yieldedValues = []; } } function yieldValue(value) { yieldedValues.push(value); } function clearYields() { var values = yieldedValues; yieldedValues = []; return values; } // Renderers that don't support persistence // can re-export everything from this module. function shim() { reactProdInvariant('270'); } // Persistence (when unsupported) var supportsPersistence = false; var cloneInstance = shim; var createContainerChildSet = shim; var appendChildToContainerChildSet = shim; var finalizeContainerChildren = shim; var replaceContainerChildren = shim; var cloneHiddenInstance = shim; var cloneUnhiddenInstance = shim; var createHiddenTextInstance = shim; // Renderers that don't support hydration // can re-export everything from this module. function shim$1() { reactProdInvariant('305'); } // Hydration (when unsupported) var supportsHydration = false; var canHydrateInstance = shim$1; var canHydrateTextInstance = shim$1; var canHydrateSuspenseInstance = shim$1; var getNextHydratableSibling = shim$1; var getFirstHydratableChild = shim$1; var hydrateInstance = shim$1; var hydrateTextInstance = shim$1; var getNextHydratableInstanceAfterSuspenseInstance = shim$1; var clearSuspenseBoundary = shim$1; var clearSuspenseBoundaryFromContainer = shim$1; var NO_CONTEXT = {}; var UPDATE_SIGNAL = {}; function getPublicInstance(inst) { switch (inst.tag) { case 'INSTANCE': var _createNodeMock = inst.rootContainerInstance.createNodeMock; return _createNodeMock({ type: inst.type, props: inst.props }); default: return inst; } } function appendChild(parentInstance, child) { var index = parentInstance.children.indexOf(child); if (index !== -1) { parentInstance.children.splice(index, 1); } parentInstance.children.push(child); } function insertBefore(parentInstance, child, beforeChild) { var index = parentInstance.children.indexOf(child); if (index !== -1) { parentInstance.children.splice(index, 1); } 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 getRootHostContext(rootContainerInstance) { return NO_CONTEXT; } function getChildHostContext(parentHostContext, type, rootContainerInstance) { return NO_CONTEXT; } function prepareForCommit(containerInfo) { // noop } function resetAfterCommit(containerInfo) { // noop } function createInstance(type, props, rootContainerInstance, hostContext, internalInstanceHandle) { return { type: type, props: props, isHidden: false, children: [], rootContainerInstance: rootContainerInstance, tag: 'INSTANCE' }; } function appendInitialChild(parentInstance, child) { var index = parentInstance.children.indexOf(child); if (index !== -1) { parentInstance.children.splice(index, 1); } parentInstance.children.push(child); } function finalizeInitialChildren(testElement, type, props, rootContainerInstance, hostContext) { return false; } function prepareUpdate(testElement, type, oldProps, newProps, rootContainerInstance, hostContext) { return UPDATE_SIGNAL; } function shouldSetTextContent(type, props) { return false; } function shouldDeprioritizeSubtree(type, props) { return false; } function createTextInstance(text, rootContainerInstance, hostContext, internalInstanceHandle) { return { text: text, isHidden: false, tag: 'TEXT' }; } var isPrimaryRenderer = false; // This approach enables `now` to be mocked by tests, // Even after the reconciler has initialized and read host config values. var now = function () { return nowImplementation(); }; var scheduleDeferredCallback$$1 = scheduleDeferredCallback$1; var cancelDeferredCallback$$1 = cancelDeferredCallback$1; var shouldYield$$1 = shouldYield$1; var scheduleTimeout = setTimeout; var cancelTimeout = clearTimeout; var noTimeout = -1; var schedulePassiveEffects = scheduleDeferredCallback$$1; var cancelPassiveEffects = cancelDeferredCallback$$1; // ------------------- // Mutation // ------------------- var supportsMutation = true; function commitUpdate(instance, updatePayload, type, oldProps, newProps, internalInstanceHandle) { instance.type = type; instance.props = newProps; } 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; } /** * Copyright (c) 2013-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ var BEFORE_SLASH_RE = /^(.*)[\\\/]/; var describeComponentFrame = function (name, source, ownerName) { var sourceInfo = ''; if (source) { var path = source.fileName; var fileName = path.replace(BEFORE_SLASH_RE, ''); sourceInfo = ' (at ' + fileName + ':' + source.lineNumber + ')'; } else if (ownerName) { sourceInfo = ' (created by ' + ownerName + ')'; } return '\n in ' + (name || 'Unknown') + sourceInfo; }; var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; function describeFiber(fiber) { switch (fiber.tag) { case HostRoot: case HostPortal: case HostText: case Fragment: case ContextProvider: case ContextConsumer: return ''; default: var owner = fiber._debugOwner; var source = fiber._debugSource; var name = getComponentName(fiber.type); var ownerName = null; if (owner) { ownerName = getComponentName(owner.type); } return describeComponentFrame(name, source, ownerName); } } function getStackByFiberInDevAndProd(workInProgress) { var info = ''; var node = workInProgress; do { info += describeFiber(node); node = node.return; } while (node); return info; } var enableUserTimingAPI = false; var enableProfilerTimer = false; var enableSchedulerTracing = false; var enableSuspenseServerRenderer = false; // Only used in www builds. // Prefix measurements so that it's possible to filter them. // Longer prefixes are hard to read in DevTools. var reactEmoji = '\u269B'; var warningEmoji = '\u26D4'; var supportsUserTiming = typeof performance !== 'undefined' && typeof performance.mark === 'function' && typeof performance.clearMarks === 'function' && typeof performance.measure === 'function' && typeof performance.clearMeasures === 'function'; // Keep track of current fiber so that we know the path to unwind on pause. // TODO: this looks the same as nextUnitOfWork in scheduler. Can we unify them? var currentFiber = null; // If we're in the middle of user code, which fiber and method is it? // Reusing `currentFiber` would be confusing for this because user code fiber // can change during commit phase too, but we don't need to unwind it (since // lifecycles in the commit phase don't resemble a tree). var currentPhase = null; var currentPhaseFiber = null; // Did lifecycle hook schedule an update? This is often a performance problem, // so we will keep track of it, and include it in the report. // Track commits caused by cascading updates. var isCommitting = false; var hasScheduledUpdateInCurrentCommit = false; var hasScheduledUpdateInCurrentPhase = false; var commitCountInCurrentWorkLoop = 0; var effectCountInCurrentCommit = 0; var isWaitingForCallback = false; // During commits, we only show a measurement once per method name // to avoid stretch the commit phase with measurement overhead. var labelsInCurrentCommit = new Set(); var formatMarkName = function (markName) { return reactEmoji + ' ' + markName; }; var formatLabel = function (label, warning) { var prefix = warning ? warningEmoji + ' ' : reactEmoji + ' '; var suffix = warning ? ' Warning: ' + warning : ''; return '' + prefix + label + suffix; }; var beginMark = function (markName) { performance.mark(formatMarkName(markName)); }; var clearMark = function (markName) { performance.clearMarks(formatMarkName(markName)); }; var endMark = function (label, markName, warning) { var formattedMarkName = formatMarkName(markName); var formattedLabel = formatLabel(label, warning); try { performance.measure(formattedLabel, formattedMarkName); } catch (err) {} // If previous mark was missing for some reason, this will throw. // This could only happen if React crashed in an unexpected place earlier. // Don't pile on with more errors. // Clear marks immediately to avoid growing buffer. performance.clearMarks(formattedMarkName); performance.clearMeasures(formattedLabel); }; var getFiberMarkName = function (label, debugID) { return label + ' (#' + debugID + ')'; }; var getFiberLabel = function (componentName, isMounted, phase) { if (phase === null) { // These are composite component total time measurements. return componentName + ' [' + (isMounted ? 'update' : 'mount') + ']'; } else { // Composite component methods. return componentName + '.' + phase; } }; var beginFiberMark = function (fiber, phase) { var componentName = getComponentName(fiber.type) || 'Unknown'; var debugID = fiber._debugID; var isMounted = fiber.alternate !== null; var label = getFiberLabel(componentName, isMounted, phase); if (isCommitting && labelsInCurrentCommit.has(label)) { // During the commit phase, we don't show duplicate labels because // there is a fixed overhead for every measurement, and we don't // want to stretch the commit phase beyond necessary. return false; } labelsInCurrentCommit.add(label); var markName = getFiberMarkName(label, debugID); beginMark(markName); return true; }; var clearFiberMark = function (fiber, phase) { var componentName = getComponentName(fiber.type) || 'Unknown'; var debugID = fiber._debugID; var isMounted = fiber.alternate !== null; var label = getFiberLabel(componentName, isMounted, phase); var markName = getFiberMarkName(label, debugID); clearMark(markName); }; var endFiberMark = function (fiber, phase, warning) { var componentName = getComponentName(fiber.type) || 'Unknown'; var debugID = fiber._debugID; var isMounted = fiber.alternate !== null; var label = getFiberLabel(componentName, isMounted, phase); var markName = getFiberMarkName(label, debugID); endMark(label, markName, warning); }; var shouldIgnoreFiber = function (fiber) { // Host components should be skipped in the timeline. // We could check typeof fiber.type, but does this work with RN? switch (fiber.tag) { case HostRoot: case HostComponent: case HostText: case HostPortal: case Fragment: case ContextProvider: case ContextConsumer: case Mode: return true; default: return false; } }; var clearPendingPhaseMeasurement = function () { if (currentPhase !== null && currentPhaseFiber !== null) { clearFiberMark(currentPhaseFiber, currentPhase); } currentPhaseFiber = null; currentPhase = null; hasScheduledUpdateInCurrentPhase = false; }; var pauseTimers = function () { // Stops all currently active measurements so that they can be resumed // if we continue in a later deferred loop from the same unit of work. var fiber = currentFiber; while (fiber) { if (fiber._debugIsCurrentlyTiming) { endFiberMark(fiber, null, null); } fiber = fiber.return; } }; var resumeTimersRecursively = function (fiber) { if (fiber.return !== null) { resumeTimersRecursively(fiber.return); } if (fiber._debugIsCurrentlyTiming) { beginFiberMark(fiber, null); } }; var resumeTimers = function () { // Resumes all measurements that were active during the last deferred loop. if (currentFiber !== null) { resumeTimersRecursively(currentFiber); } }; function recordEffect() { if (enableUserTimingAPI) { effectCountInCurrentCommit++; } } function recordScheduleUpdate() { if (enableUserTimingAPI) { if (isCommitting) { hasScheduledUpdateInCurrentCommit = true; } if (currentPhase !== null && currentPhase !== 'componentWillMount' && currentPhase !== 'componentWillReceiveProps') { hasScheduledUpdateInCurrentPhase = true; } } } function startRequestCallbackTimer() { if (enableUserTimingAPI) { if (supportsUserTiming && !isWaitingForCallback) { isWaitingForCallback = true; beginMark('(Waiting for async callback...)'); } } } function stopRequestCallbackTimer(didExpire, expirationTime) { if (enableUserTimingAPI) { if (supportsUserTiming) { isWaitingForCallback = false; var warning = didExpire ? 'React was blocked by main thread' : null; endMark('(Waiting for async callback... will force flush in ' + expirationTime + ' ms)', '(Waiting for async callback...)', warning); } } } function startWorkTimer(fiber) { if (enableUserTimingAPI) { if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { return; } // If we pause, this is the fiber to unwind from. currentFiber = fiber; if (!beginFiberMark(fiber, null)) { return; } fiber._debugIsCurrentlyTiming = true; } } function cancelWorkTimer(fiber) { if (enableUserTimingAPI) { if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { return; } // Remember we shouldn't complete measurement for this fiber. // Otherwise flamechart will be deep even for small updates. fiber._debugIsCurrentlyTiming = false; clearFiberMark(fiber, null); } } function stopWorkTimer(fiber) { if (enableUserTimingAPI) { if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { return; } // If we pause, its parent is the fiber to unwind from. currentFiber = fiber.return; if (!fiber._debugIsCurrentlyTiming) { return; } fiber._debugIsCurrentlyTiming = false; endFiberMark(fiber, null, null); } } function stopFailedWorkTimer(fiber) { if (enableUserTimingAPI) { if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { return; } // If we pause, its parent is the fiber to unwind from. currentFiber = fiber.return; if (!fiber._debugIsCurrentlyTiming) { return; } fiber._debugIsCurrentlyTiming = false; var warning = fiber.tag === SuspenseComponent || fiber.tag === DehydratedSuspenseComponent ? 'Rendering was suspended' : 'An error was thrown inside this error boundary'; endFiberMark(fiber, null, warning); } } function startPhaseTimer(fiber, phase) { if (enableUserTimingAPI) { if (!supportsUserTiming) { return; } clearPendingPhaseMeasurement(); if (!beginFiberMark(fiber, phase)) { return; } currentPhaseFiber = fiber; currentPhase = phase; } } function stopPhaseTimer() { if (enableUserTimingAPI) { if (!supportsUserTiming) { return; } if (currentPhase !== null && currentPhaseFiber !== null) { var warning = hasScheduledUpdateInCurrentPhase ? 'Scheduled a cascading update' : null; endFiberMark(currentPhaseFiber, currentPhase, warning); } currentPhase = null; currentPhaseFiber = null; } } function startWorkLoopTimer(nextUnitOfWork) { if (enableUserTimingAPI) { currentFiber = nextUnitOfWork; if (!supportsUserTiming) { return; } commitCountInCurrentWorkLoop = 0; // This is top level call. // Any other measurements are performed within. beginMark('(React Tree Reconciliation)'); // Resume any measurements that were in progress during the last loop. resumeTimers(); } } function stopWorkLoopTimer(interruptedBy, didCompleteRoot) { if (enableUserTimingAPI) { if (!supportsUserTiming) { return; } var warning = null; if (interruptedBy !== null) { if (interruptedBy.tag === HostRoot) { warning = 'A top-level update interrupted the previous render'; } else { var componentName = getComponentName(interruptedBy.type) || 'Unknown'; warning = 'An update to ' + componentName + ' interrupted the previous render'; } } else if (commitCountInCurrentWorkLoop > 1) { warning = 'There were cascading updates'; } commitCountInCurrentWorkLoop = 0; var label = didCompleteRoot ? '(React Tree Reconciliation: Completed Root)' : '(React Tree Reconciliation: Yielded)'; // Pause any measurements until the next loop. pauseTimers(); endMark(label, '(React Tree Reconciliation)', warning); } } function startCommitTimer() { if (enableUserTimingAPI) { if (!supportsUserTiming) { return; } isCommitting = true; hasScheduledUpdateInCurrentCommit = false; labelsInCurrentCommit.clear(); beginMark('(Committing Changes)'); } } function stopCommitTimer() { if (enableUserTimingAPI) { if (!supportsUserTiming) { return; } var warning = null; if (hasScheduledUpdateInCurrentCommit) { warning = 'Lifecycle hook scheduled a cascading update'; } else if (commitCountInCurrentWorkLoop > 0) { warning = 'Caused by a cascading update in earlier commit'; } hasScheduledUpdateInCurrentCommit = false; commitCountInCurrentWorkLoop++; isCommitting = false; labelsInCurrentCommit.clear(); endMark('(Committing Changes)', '(Committing Changes)', warning); } } function startCommitSnapshotEffectsTimer() { if (enableUserTimingAPI) { if (!supportsUserTiming) { return; } effectCountInCurrentCommit = 0; beginMark('(Committing Snapshot Effects)'); } } function stopCommitSnapshotEffectsTimer() { if (enableUserTimingAPI) { if (!supportsUserTiming) { return; } var count = effectCountInCurrentCommit; effectCountInCurrentCommit = 0; endMark('(Committing Snapshot Effects: ' + count + ' Total)', '(Committing Snapshot Effects)', null); } } function startCommitHostEffectsTimer() { if (enableUserTimingAPI) { if (!supportsUserTiming) { return; } effectCountInCurrentCommit = 0; beginMark('(Committing Host Effects)'); } } function stopCommitHostEffectsTimer() { if (enableUserTimingAPI) { if (!supportsUserTiming) { return; } var count = effectCountInCurrentCommit; effectCountInCurrentCommit = 0; endMark('(Committing Host Effects: ' + count + ' Total)', '(Committing Host Effects)', null); } } function startCommitLifeCyclesTimer() { if (enableUserTimingAPI) { if (!supportsUserTiming) { return; } effectCountInCurrentCommit = 0; beginMark('(Calling Lifecycle Methods)'); } } function stopCommitLifeCyclesTimer() { if (enableUserTimingAPI) { if (!supportsUserTiming) { return; } var count = effectCountInCurrentCommit; effectCountInCurrentCommit = 0; endMark('(Calling Lifecycle Methods: ' + count + ' Total)', '(Calling Lifecycle Methods)', null); } } var valueStack = []; var index = -1; function createCursor(defaultValue) { return { current: defaultValue }; } function pop(cursor, fiber) { if (index < 0) { return; } cursor.current = valueStack[index]; valueStack[index] = null; index--; } function push(cursor, value, fiber) { index++; valueStack[index] = cursor.current; cursor.current = value; } var emptyContextObject = {}; // A cursor to the current merged context object on the stack. var contextStackCursor = createCursor(emptyContextObject); // A cursor to a boolean indicating whether the context has changed. var didPerformWorkStackCursor = createCursor(false); // Keep track of the previous context object that was on the stack. // We use this to get access to the parent context after we have already // pushed the next context provider, and now need to merge their contexts. var previousContext = emptyContextObject; function getUnmaskedContext(workInProgress, Component, didPushOwnContextIfProvider) { if (didPushOwnContextIfProvider && isContextProvider(Component)) { // If the fiber is a context provider itself, when we read its context // we may have already pushed its own child context on the stack. A context // provider should not "see" its own child context. Therefore we read the // previous (parent) context instead for a context provider. return previousContext; } return contextStackCursor.current; } function cacheContext(workInProgress, unmaskedContext, maskedContext) { var instance = workInProgress.stateNode; instance.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext; instance.__reactInternalMemoizedMaskedChildContext = maskedContext; } function getMaskedContext(workInProgress, unmaskedContext) { var type = workInProgress.type; var contextTypes = type.contextTypes; if (!contextTypes) { return emptyContextObject; } // Avoid recreating masked context unless unmasked context has changed. // Failing to do this will result in unnecessary calls to componentWillReceiveProps. // This may trigger infinite loops if componentWillReceiveProps calls setState. var instance = workInProgress.stateNode; if (instance && instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext) { return instance.__reactInternalMemoizedMaskedChildContext; } var context = {}; for (var key in contextTypes) { context[key] = unmaskedContext[key]; } if (instance) { cacheContext(workInProgress, unmaskedContext, context); } return context; } function hasContextChanged() { return didPerformWorkStackCursor.current; } function isContextProvider(type) { var childContextTypes = type.childContextTypes; return childContextTypes !== null && childContextTypes !== undefined; } function popContext(fiber) { pop(didPerformWorkStackCursor, fiber); pop(contextStackCursor, fiber); } function popTopLevelContextObject(fiber) { pop(didPerformWorkStackCursor, fiber); pop(contextStackCursor, fiber); } function pushTopLevelContextObject(fiber, context, didChange) { !(contextStackCursor.current === emptyContextObject) ? reactProdInvariant('168') : void 0; push(contextStackCursor, 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') { return parentContext; } var childContext = void 0; startPhaseTimer(fiber, 'getChildContext'); childContext = instance.getChildContext(); stopPhaseTimer(); for (var contextKey in childContext) { !(contextKey in childContextTypes) ? reactProdInvariant('108', getComponentName(type) || 'Unknown', contextKey) : void 0; } return _assign({}, parentContext, childContext); } 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.current; push(contextStackCursor, memoizedMergedChildContext, workInProgress); push(didPerformWorkStackCursor, didPerformWorkStackCursor.current, workInProgress); return true; } function invalidateContextProvider(workInProgress, type, didChange) { var instance = workInProgress.stateNode; !instance ? reactProdInvariant('169') : void 0; 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, workInProgress); // Now push the new context and mark that it has changed. push(contextStackCursor, mergedContext, workInProgress); push(didPerformWorkStackCursor, didChange, workInProgress); } else { pop(didPerformWorkStackCursor, workInProgress); push(didPerformWorkStackCursor, didChange, workInProgress); } } function findCurrentUnmaskedContext(fiber) { // Currently this is only used with renderSubtreeIntoContainer; not sure if it // makes sense elsewhere !(isFiberMounted(fiber) && fiber.tag === ClassComponent) ? reactProdInvariant('170') : void 0; var node = fiber; do { switch (node.tag) { case HostRoot: return node.stateNode.context; case ClassComponent: { var Component = node.type; if (isContextProvider(Component)) { return node.stateNode.__reactInternalMemoizedMergedChildContext; } break; } } node = node.return; } while (node !== null); reactProdInvariant('171'); } var onCommitFiberRoot = null; var onCommitFiberUnmount = null; function catchErrors(fn) { return function (arg) { try { return fn(arg); } catch (err) { } }; } 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) { return true; } try { var rendererID = hook.inject(internals); // We have successfully injected, so now it is safe to set up hooks. onCommitFiberRoot = catchErrors(function (root) { return hook.onCommitFiberRoot(rendererID, root); }); onCommitFiberUnmount = catchErrors(function (fiber) { return hook.onCommitFiberUnmount(rendererID, fiber); }); } catch (err) { // Catch all errors because it is unsafe to throw during initialization. } // DevTools exists return true; } function onCommitRoot(root) { if (typeof onCommitFiberRoot === 'function') { onCommitFiberRoot(root); } } function onCommitUnmount(fiber) { if (typeof onCommitFiberUnmount === 'function') { onCommitFiberUnmount(fiber); } } // Max 31 bit integer. The max integer size in V8 for 32-bit systems. // Math.pow(2, 30) - 1 // 0b111111111111111111111111111111 var maxSigned31BitInt = 1073741823; var NoWork = 0; var Never = 1; var Sync = maxSigned31BitInt; var UNIT_SIZE = 10; var MAGIC_NUMBER_OFFSET = maxSigned31BitInt - 1; // 1 unit of expiration time represents 10ms. function msToExpirationTime(ms) { // Always add an offset so that we don't clash with the magic number for NoWork. return MAGIC_NUMBER_OFFSET - (ms / UNIT_SIZE | 0); } function expirationTimeToMs(expirationTime) { return (MAGIC_NUMBER_OFFSET - expirationTime) * UNIT_SIZE; } function ceiling(num, precision) { return ((num / precision | 0) + 1) * precision; } function computeExpirationBucket(currentTime, expirationInMs, bucketSizeMs) { return MAGIC_NUMBER_OFFSET - ceiling(MAGIC_NUMBER_OFFSET - currentTime + expirationInMs / UNIT_SIZE, bucketSizeMs / UNIT_SIZE); } var LOW_PRIORITY_EXPIRATION = 5000; var LOW_PRIORITY_BATCH_SIZE = 250; function computeAsyncExpiration(currentTime) { return computeExpirationBucket(currentTime, LOW_PRIORITY_EXPIRATION, LOW_PRIORITY_BATCH_SIZE); } // We intentionally set a higher expiration time for interactive updates in // dev than in production. // // If the main thread is being blocked so long that you hit the expiration, // it's a problem that could be solved with better scheduling. // // People will be more likely to notice this and fix it with the long // expiration time in development. // // In production we opt for better UX at the risk of masking scheduling // problems, by expiring fast. var HIGH_PRIORITY_EXPIRATION = 150; var HIGH_PRIORITY_BATCH_SIZE = 100; function computeInteractiveExpiration(currentTime) { return computeExpirationBucket(currentTime, HIGH_PRIORITY_EXPIRATION, HIGH_PRIORITY_BATCH_SIZE); } var NoContext = 0; var ConcurrentMode = 1; var StrictMode = 2; var ProfileMode = 4; 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.pendingProps = pendingProps; this.memoizedProps = null; this.updateQueue = null; this.memoizedState = null; this.contextDependencies = null; this.mode = mode; // Effects this.effectTag = NoEffect; this.nextEffect = null; this.firstEffect = null; this.lastEffect = null; this.expirationTime = NoWork; this.childExpirationTime = NoWork; this.alternate = null; if (enableProfilerTimer) { // 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 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. var createFiber = function (tag, pendingProps, key, mode) { // $FlowFixMe: 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 resolveLazyComponentTag(Component) { if (typeof Component === 'function') { return shouldConstruct(Component) ? ClassComponent : FunctionComponent; } else if (Component !== undefined && Component !== null) { var $$typeof = Component.$$typeof; if ($$typeof === REACT_FORWARD_REF_TYPE) { return ForwardRef; } if ($$typeof === REACT_MEMO_TYPE) { return MemoComponent; } } return IndeterminateComponent; } // This is used to create an alternate fiber to do work on. function createWorkInProgress(current, pendingProps, expirationTime) { 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.alternate = current; current.alternate = workInProgress; } else { workInProgress.pendingProps = pendingProps; // We already have an alternate. // Reset the effect tag. workInProgress.effectTag = NoEffect; // The effect list is no longer valid. workInProgress.nextEffect = null; workInProgress.firstEffect = null; workInProgress.lastEffect = null; if (enableProfilerTimer) { // 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; } } workInProgress.childExpirationTime = current.childExpirationTime; workInProgress.expirationTime = current.expirationTime; workInProgress.child = current.child; workInProgress.memoizedProps = current.memoizedProps; workInProgress.memoizedState = current.memoizedState; workInProgress.updateQueue = current.updateQueue; workInProgress.contextDependencies = current.contextDependencies; // These will be overridden during the parent's reconciliation workInProgress.sibling = current.sibling; workInProgress.index = current.index; workInProgress.ref = current.ref; if (enableProfilerTimer) { workInProgress.selfBaseDuration = current.selfBaseDuration; workInProgress.treeBaseDuration = current.treeBaseDuration; } return workInProgress; } function createHostRootFiber(isConcurrent) { var mode = isConcurrent ? ConcurrentMode | StrictMode : NoContext; if (enableProfilerTimer && 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 createFiber(HostRoot, null, null, mode); } function createFiberFromTypeAndProps(type, // React$ElementType key, pendingProps, owner, mode, expirationTime) { var fiber = void 0; var fiberTag = IndeterminateComponent; // The resolved type is set if we know what the final type will be. I.e. it's not lazy. var resolvedType = type; if (typeof type === 'function') { if (shouldConstruct(type)) { fiberTag = ClassComponent; } } else if (typeof type === 'string') { fiberTag = HostComponent; } else { getTag: switch (type) { case REACT_FRAGMENT_TYPE: return createFiberFromFragment(pendingProps.children, mode, expirationTime, key); case REACT_CONCURRENT_MODE_TYPE: return createFiberFromMode(pendingProps, mode | ConcurrentMode | StrictMode, expirationTime, key); case REACT_STRICT_MODE_TYPE: return createFiberFromMode(pendingProps, mode | StrictMode, expirationTime, key); case REACT_PROFILER_TYPE: return createFiberFromProfiler(pendingProps, mode, expirationTime, key); case REACT_SUSPENSE_TYPE: return createFiberFromSuspense(pendingProps, mode, expirationTime, key); default: { if (typeof type === 'object' && type !== null) { switch (type.$$typeof) { case REACT_PROVIDER_TYPE: fiberTag = ContextProvider; break getTag; case REACT_CONTEXT_TYPE: // This is a consumer fiberTag = ContextConsumer; break getTag; case REACT_FORWARD_REF_TYPE: fiberTag = ForwardRef; break getTag; case REACT_MEMO_TYPE: fiberTag = MemoComponent; break getTag; case REACT_LAZY_TYPE: fiberTag = LazyComponent; resolvedType = null; break getTag; } } var info = ''; reactProdInvariant('130', type == null ? type : typeof type, info); } } } fiber = createFiber(fiberTag, pendingProps, key, mode); fiber.elementType = type; fiber.type = resolvedType; fiber.expirationTime = expirationTime; return fiber; } function createFiberFromElement(element, mode, expirationTime) { var owner = null; var type = element.type; var key = element.key; var pendingProps = element.props; var fiber = createFiberFromTypeAndProps(type, key, pendingProps, owner, mode, expirationTime); return fiber; } function createFiberFromFragment(elements, mode, expirationTime, key) { var fiber = createFiber(Fragment, elements, key, mode); fiber.expirationTime = expirationTime; return fiber; } function createFiberFromProfiler(pendingProps, mode, expirationTime, key) { var fiber = createFiber(Profiler, pendingProps, key, mode | ProfileMode); // TODO: The Profiler fiber shouldn't have a type. It has a tag. fiber.elementType = REACT_PROFILER_TYPE; fiber.type = REACT_PROFILER_TYPE; fiber.expirationTime = expirationTime; return fiber; } function createFiberFromMode(pendingProps, mode, expirationTime, key) { var fiber = createFiber(Mode, pendingProps, key, mode); // TODO: The Mode fiber shouldn't have a type. It has a tag. var type = (mode & ConcurrentMode) === NoContext ? REACT_STRICT_MODE_TYPE : REACT_CONCURRENT_MODE_TYPE; fiber.elementType = type; fiber.type = type; fiber.expirationTime = expirationTime; return fiber; } function createFiberFromSuspense(pendingProps, mode, expirationTime, key) { var fiber = createFiber(SuspenseComponent, pendingProps, key, mode); // TODO: The SuspenseComponent fiber shouldn't have a type. It has a tag. var type = REACT_SUSPENSE_TYPE; fiber.elementType = type; fiber.type = type; fiber.expirationTime = expirationTime; return fiber; } function createFiberFromText(content, mode, expirationTime) { var fiber = createFiber(HostText, content, null, mode); fiber.expirationTime = expirationTime; return fiber; } function createFiberFromHostInstanceForDeletion() { var fiber = createFiber(HostComponent, null, null, NoContext); // TODO: These should not need a type. fiber.elementType = 'DELETED'; fiber.type = 'DELETED'; return fiber; } function createFiberFromPortal(portal, mode, expirationTime) { var pendingProps = portal.children !== null ? portal.children : []; var fiber = createFiber(HostPortal, pendingProps, portal.key, mode); fiber.expirationTime = expirationTime; fiber.stateNode = { containerInfo: portal.containerInfo, pendingChildren: null, // Used by persistent updates implementation: portal.implementation }; return fiber; } // Used for stashing WIP properties to replay failed work in DEV. var ReactInternals$1 = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; var _ReactInternals$Sched = ReactInternals$1.SchedulerTracing; var __interactionsRef = _ReactInternals$Sched.__interactionsRef; var __subscriberRef = _ReactInternals$Sched.__subscriberRef; var unstable_clear = _ReactInternals$Sched.unstable_clear; var unstable_getCurrent = _ReactInternals$Sched.unstable_getCurrent; var unstable_getThreadID = _ReactInternals$Sched.unstable_getThreadID; var unstable_subscribe = _ReactInternals$Sched.unstable_subscribe; var unstable_trace = _ReactInternals$Sched.unstable_trace; var unstable_unsubscribe = _ReactInternals$Sched.unstable_unsubscribe; var unstable_wrap = _ReactInternals$Sched.unstable_wrap; // TODO: This should be lifted into the renderer. // The following attributes are only used by interaction tracing builds. // They enable interactions to be associated with their async work, // And expose interaction metadata to the React DevTools Profiler plugin. // Note that these attributes are only defined when the enableSchedulerTracing flag is enabled. // Exported FiberRoot type includes all properties, // To avoid requiring potentially error-prone :any casts throughout the project. // Profiling properties are only safe to access in profiling builds (when enableSchedulerTracing is true). // The types are defined separately within this file to ensure they stay in sync. // (We don't have to use an inline :any cast when enableSchedulerTracing is disabled.) function createFiberRoot(containerInfo, isConcurrent, hydrate) { // Cyclic construction. This cheats the type system right now because // stateNode is any. var uninitializedFiber = createHostRootFiber(isConcurrent); var root = void 0; if (enableSchedulerTracing) { root = { current: uninitializedFiber, containerInfo: containerInfo, pendingChildren: null, earliestPendingTime: NoWork, latestPendingTime: NoWork, earliestSuspendedTime: NoWork, latestSuspendedTime: NoWork, latestPingedTime: NoWork, pingCache: null, didError: false, pendingCommitExpirationTime: NoWork, finishedWork: null, timeoutHandle: noTimeout, context: null, pendingContext: null, hydrate: hydrate, nextExpirationTimeToWorkOn: NoWork, expirationTime: NoWork, firstBatch: null, nextScheduledRoot: null, interactionThreadID: unstable_getThreadID(), memoizedInteractions: new Set(), pendingInteractionMap: new Map() }; } else { root = { current: uninitializedFiber, containerInfo: containerInfo, pendingChildren: null, pingCache: null, earliestPendingTime: NoWork, latestPendingTime: NoWork, earliestSuspendedTime: NoWork, latestSuspendedTime: NoWork, latestPingedTime: NoWork, didError: false, pendingCommitExpirationTime: NoWork, finishedWork: null, timeoutHandle: noTimeout, context: null, pendingContext: null, hydrate: hydrate, nextExpirationTimeToWorkOn: NoWork, expirationTime: NoWork, firstBatch: null, nextScheduledRoot: null }; } uninitializedFiber.stateNode = root; // The reason for the way the Flow types are structured in this file, // Is to avoid needing :any casts everywhere interaction tracing fields are used. // Unfortunately that requires an :any cast for non-interaction tracing capable builds. // $FlowFixMe Remove this :any cast and replace it with something better. return root; } var ReactInternals$2 = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; var _ReactInternals$Sched$1 = ReactInternals$2.Scheduler; var unstable_cancelCallback = _ReactInternals$Sched$1.unstable_cancelCallback; var unstable_now = _ReactInternals$Sched$1.unstable_now; var unstable_scheduleCallback = _ReactInternals$Sched$1.unstable_scheduleCallback; var unstable_shouldYield = _ReactInternals$Sched$1.unstable_shouldYield; var unstable_getFirstCallbackNode = _ReactInternals$Sched$1.unstable_getFirstCallbackNode; var unstable_runWithPriority = _ReactInternals$Sched$1.unstable_runWithPriority; var unstable_next = _ReactInternals$Sched$1.unstable_next; var unstable_continueExecution = _ReactInternals$Sched$1.unstable_continueExecution; var unstable_pauseExecution = _ReactInternals$Sched$1.unstable_pauseExecution; var unstable_getCurrentPriorityLevel = _ReactInternals$Sched$1.unstable_getCurrentPriorityLevel; var unstable_ImmediatePriority = _ReactInternals$Sched$1.unstable_ImmediatePriority; var unstable_UserBlockingPriority = _ReactInternals$Sched$1.unstable_UserBlockingPriority; var unstable_NormalPriority = _ReactInternals$Sched$1.unstable_NormalPriority; var unstable_LowPriority = _ReactInternals$Sched$1.unstable_LowPriority; var unstable_IdlePriority = _ReactInternals$Sched$1.unstable_IdlePriority; /** * Call a function while guarding against errors that happens within it. * Returns an error if it throws, otherwise null. * * In production, this is implemented using a try-catch. The reason we don't * use a try-catch directly is so that we can swap out a different * implementation in DEV mode. * * @param {String} name of the guard to use for logging or debugging * @param {Function} func The function to invoke * @param {*} context The context to use when calling the function * @param {...*} args Arguments for function */ /** * Same as invokeGuardedCallback, but instead of returning an error, it stores * it in a global so it can be rethrown by `rethrowCaughtError` later. * TODO: See if caughtError and rethrowError can be unified. * * @param {String} name of the guard to use for logging or debugging * @param {Function} func The function to invoke * @param {*} context The context to use when calling the function * @param {...*} args Arguments for function */ /** * During execution of guarded functions we will capture the first error which * we will rethrow to be handled by the top level error handler. */ /** * Forked from fbjs/warning: * https://github.com/facebook/fbjs/blob/e66ba20ad5be433eb54423f2b097d829324d9de6/packages/fbjs/src/__forks__/warning.js * * Only change is we use console.warn instead of console.error, * and do nothing when 'console' is not supported. * This really simplifies the code. * --- * Similar to invariant but only logs a warning if the condition is not met. * This can be used to log issues in development environments in critical * paths. Removing the logging code for production environments will keep the * same logic and follow the same code paths. */ // This lets us hook into Fiber to debug what it's doing. // See https://github.com/facebook/react/pull/8033. // This is not part of the public API, not even for React DevTools. // You may only inject a debugTool if you work on React Fiber itself. // TODO: Offscreen updates should never suspend. However, a promise that // suspended inside an offscreen subtree should be able to ping at the priority // of the outer render. function markPendingPriorityLevel(root, expirationTime) { // If there's a gap between completing a failed root and retrying it, // additional updates may be scheduled. Clear `didError`, in case the update // is sufficient to fix the error. root.didError = false; // Update the latest and earliest pending times var earliestPendingTime = root.earliestPendingTime; if (earliestPendingTime === NoWork) { // No other pending updates. root.earliestPendingTime = root.latestPendingTime = expirationTime; } else { if (earliestPendingTime < expirationTime) { // This is the earliest pending update. root.earliestPendingTime = expirationTime; } else { var latestPendingTime = root.latestPendingTime; if (latestPendingTime > expirationTime) { // This is the latest pending update root.latestPendingTime = expirationTime; } } } findNextExpirationTimeToWorkOn(expirationTime, root); } function markCommittedPriorityLevels(root, earliestRemainingTime) { root.didError = false; if (earliestRemainingTime === NoWork) { // Fast path. There's no remaining work. Clear everything. root.earliestPendingTime = NoWork; root.latestPendingTime = NoWork; root.earliestSuspendedTime = NoWork; root.latestSuspendedTime = NoWork; root.latestPingedTime = NoWork; findNextExpirationTimeToWorkOn(NoWork, root); return; } if (earliestRemainingTime < root.latestPingedTime) { root.latestPingedTime = NoWork; } // Let's see if the previous latest known pending level was just flushed. var latestPendingTime = root.latestPendingTime; if (latestPendingTime !== NoWork) { if (latestPendingTime > earliestRemainingTime) { // We've flushed all the known pending levels. root.earliestPendingTime = root.latestPendingTime = NoWork; } else { var earliestPendingTime = root.earliestPendingTime; if (earliestPendingTime > earliestRemainingTime) { // We've flushed the earliest known pending level. Set this to the // latest pending time. root.earliestPendingTime = root.latestPendingTime; } } } // Now let's handle the earliest remaining level in the whole tree. We need to // decide whether to treat it as a pending level or as suspended. Check // it falls within the range of known suspended levels. var earliestSuspendedTime = root.earliestSuspendedTime; if (earliestSuspendedTime === NoWork) { // There's no suspended work. Treat the earliest remaining level as a // pending level. markPendingPriorityLevel(root, earliestRemainingTime); findNextExpirationTimeToWorkOn(NoWork, root); return; } var latestSuspendedTime = root.latestSuspendedTime; if (earliestRemainingTime < latestSuspendedTime) { // The earliest remaining level is later than all the suspended work. That // means we've flushed all the suspended work. root.earliestSuspendedTime = NoWork; root.latestSuspendedTime = NoWork; root.latestPingedTime = NoWork; // There's no suspended work. Treat the earliest remaining level as a // pending level. markPendingPriorityLevel(root, earliestRemainingTime); findNextExpirationTimeToWorkOn(NoWork, root); return; } if (earliestRemainingTime > earliestSuspendedTime) { // The earliest remaining time is earlier than all the suspended work. // Treat it as a pending update. markPendingPriorityLevel(root, earliestRemainingTime); findNextExpirationTimeToWorkOn(NoWork, root); return; } // The earliest remaining time falls within the range of known suspended // levels. We should treat this as suspended work. findNextExpirationTimeToWorkOn(NoWork, root); } function hasLowerPriorityWork(root, erroredExpirationTime) { var latestPendingTime = root.latestPendingTime; var latestSuspendedTime = root.latestSuspendedTime; var latestPingedTime = root.latestPingedTime; return latestPendingTime !== NoWork && latestPendingTime < erroredExpirationTime || latestSuspendedTime !== NoWork && latestSuspendedTime < erroredExpirationTime || latestPingedTime !== NoWork && latestPingedTime < erroredExpirationTime; } function isPriorityLevelSuspended(root, expirationTime) { var earliestSuspendedTime = root.earliestSuspendedTime; var latestSuspendedTime = root.latestSuspendedTime; return earliestSuspendedTime !== NoWork && expirationTime <= earliestSuspendedTime && expirationTime >= latestSuspendedTime; } function markSuspendedPriorityLevel(root, suspendedTime) { root.didError = false; clearPing(root, suspendedTime); // First, check the known pending levels and update them if needed. var earliestPendingTime = root.earliestPendingTime; var latestPendingTime = root.latestPendingTime; if (earliestPendingTime === suspendedTime) { if (latestPendingTime === suspendedTime) { // Both known pending levels were suspended. Clear them. root.earliestPendingTime = root.latestPendingTime = NoWork; } else { // The earliest pending level was suspended. Clear by setting it to the // latest pending level. root.earliestPendingTime = latestPendingTime; } } else if (latestPendingTime === suspendedTime) { // The latest pending level was suspended. Clear by setting it to the // latest pending level. root.latestPendingTime = earliestPendingTime; } // Finally, update the known suspended levels. var earliestSuspendedTime = root.earliestSuspendedTime; var latestSuspendedTime = root.latestSuspendedTime; if (earliestSuspendedTime === NoWork) { // No other suspended levels. root.earliestSuspendedTime = root.latestSuspendedTime = suspendedTime; } else { if (earliestSuspendedTime < suspendedTime) { // This is the earliest suspended level. root.earliestSuspendedTime = suspendedTime; } else if (latestSuspendedTime > suspendedTime) { // This is the latest suspended level root.latestSuspendedTime = suspendedTime; } } findNextExpirationTimeToWorkOn(suspendedTime, root); } function markPingedPriorityLevel(root, pingedTime) { root.didError = false; // TODO: When we add back resuming, we need to ensure the progressed work // is thrown out and not reused during the restarted render. One way to // invalidate the progressed work is to restart at expirationTime + 1. var latestPingedTime = root.latestPingedTime; if (latestPingedTime === NoWork || latestPingedTime > pingedTime) { root.latestPingedTime = pingedTime; } findNextExpirationTimeToWorkOn(pingedTime, root); } function clearPing(root, completedTime) { var latestPingedTime = root.latestPingedTime; if (latestPingedTime >= completedTime) { root.latestPingedTime = NoWork; } } function findEarliestOutstandingPriorityLevel(root, renderExpirationTime) { var earliestExpirationTime = renderExpirationTime; var earliestPendingTime = root.earliestPendingTime; var earliestSuspendedTime = root.earliestSuspendedTime; if (earliestPendingTime > earliestExpirationTime) { earliestExpirationTime = earliestPendingTime; } if (earliestSuspendedTime > earliestExpirationTime) { earliestExpirationTime = earliestSuspendedTime; } return earliestExpirationTime; } function didExpireAtExpirationTime(root, currentTime) { var expirationTime = root.expirationTime; if (expirationTime !== NoWork && currentTime <= expirationTime) { // The root has expired. Flush all work up to the current time. root.nextExpirationTimeToWorkOn = currentTime; } } function findNextExpirationTimeToWorkOn(completedExpirationTime, root) { var earliestSuspendedTime = root.earliestSuspendedTime; var latestSuspendedTime = root.latestSuspendedTime; var earliestPendingTime = root.earliestPendingTime; var latestPingedTime = root.latestPingedTime; // Work on the earliest pending time. Failing that, work on the latest // pinged time. var nextExpirationTimeToWorkOn = earliestPendingTime !== NoWork ? earliestPendingTime : latestPingedTime; // If there is no pending or pinged work, check if there's suspended work // that's lower priority than what we just completed. if (nextExpirationTimeToWorkOn === NoWork && (completedExpirationTime === NoWork || latestSuspendedTime < completedExpirationTime)) { // The lowest priority suspended work is the work most likely to be // committed next. Let's start rendering it again, so that if it times out, // it's ready to commit. nextExpirationTimeToWorkOn = latestSuspendedTime; } var expirationTime = nextExpirationTimeToWorkOn; if (expirationTime !== NoWork && earliestSuspendedTime > expirationTime) { // Expire using the earliest known expiration time. expirationTime = earliestSuspendedTime; } root.nextExpirationTimeToWorkOn = nextExpirationTimeToWorkOn; root.expirationTime = expirationTime; } /** * 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 hasOwnProperty = Object.prototype.hasOwnProperty; /** * 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 shallowEqual(objA, objB) { if (is(objA, objB)) { return true; } if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) { return false; } var keysA = Object.keys(objA); var keysB = Object.keys(objB); if (keysA.length !== keysB.length) { return false; } // Test for A's keys different from B. for (var i = 0; i < keysA.length; i++) { if (!hasOwnProperty.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) { return false; } } return true; } function resolveDefaultProps(Component, baseProps) { 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]; } } return props; } return baseProps; } function readLazyComponentType(lazyComponent) { var status = lazyComponent._status; var result = lazyComponent._result; switch (status) { case Resolved: { var Component = result; return Component; } case Rejected: { var error = result; throw error; } case Pending: { var thenable = result; throw thenable; } default: { lazyComponent._status = Pending; var ctor = lazyComponent._ctor; var _thenable = ctor(); _thenable.then(function (moduleObject) { if (lazyComponent._status === Pending) { var defaultExport = moduleObject.default; lazyComponent._status = Resolved; lazyComponent._result = defaultExport; } }, function (error) { if (lazyComponent._status === Pending) { lazyComponent._status = Rejected; lazyComponent._result = error; } }); // Handle synchronous thenables. switch (lazyComponent._status) { case Resolved: return lazyComponent._result; case Rejected: throw lazyComponent._result; } lazyComponent._result = _thenable; throw _thenable; } } } // React.Component uses a shared frozen object by default. // We'll use it to determine whether we need to initialize legacy refs. var emptyRefsObject = new React.Component().refs; function applyDerivedStateFromProps(workInProgress, ctor, getDerivedStateFromProps, nextProps) { var prevState = workInProgress.memoizedState; var partialState = getDerivedStateFromProps(nextProps, prevState); var memoizedState = partialState === null || partialState === undefined ? prevState : _assign({}, prevState, partialState); workInProgress.memoizedState = memoizedState; // Once the update queue is empty, persist the derived state onto the // base state. var updateQueue = workInProgress.updateQueue; if (updateQueue !== null && workInProgress.expirationTime === NoWork) { updateQueue.baseState = memoizedState; } } var classComponentUpdater = { isMounted: isMounted, enqueueSetState: function (inst, payload, callback) { var fiber = get(inst); var currentTime = requestCurrentTime(); var expirationTime = computeExpirationForFiber(currentTime, fiber); var update = createUpdate(expirationTime); update.payload = payload; if (callback !== undefined && callback !== null) { update.callback = callback; } flushPassiveEffects$1(); enqueueUpdate(fiber, update); scheduleWork(fiber, expirationTime); }, enqueueReplaceState: function (inst, payload, callback) { var fiber = get(inst); var currentTime = requestCurrentTime(); var expirationTime = computeExpirationForFiber(currentTime, fiber); var update = createUpdate(expirationTime); update.tag = ReplaceState; update.payload = payload; if (callback !== undefined && callback !== null) { update.callback = callback; } flushPassiveEffects$1(); enqueueUpdate(fiber, update); scheduleWork(fiber, expirationTime); }, enqueueForceUpdate: function (inst, callback) { var fiber = get(inst); var currentTime = requestCurrentTime(); var expirationTime = computeExpirationForFiber(currentTime, fiber); var update = createUpdate(expirationTime); update.tag = ForceUpdate; if (callback !== undefined && callback !== null) { update.callback = callback; } flushPassiveEffects$1(); enqueueUpdate(fiber, update); scheduleWork(fiber, expirationTime); } }; function checkShouldComponentUpdate(workInProgress, ctor, oldProps, newProps, oldState, newState, nextContext) { var instance = workInProgress.stateNode; if (typeof instance.shouldComponentUpdate === 'function') { startPhaseTimer(workInProgress, 'shouldComponentUpdate'); var shouldUpdate = instance.shouldComponentUpdate(newProps, newState, nextContext); stopPhaseTimer(); return shouldUpdate; } if (ctor.prototype && ctor.prototype.isPureReactComponent) { return !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState); } return true; } function adoptClassInstance(workInProgress, instance) { instance.updater = classComponentUpdater; workInProgress.stateNode = instance; // The instance needs access to the fiber so that it can schedule updates set(instance, workInProgress); } function constructClassInstance(workInProgress, ctor, props, renderExpirationTime) { var isLegacyContextConsumer = false; var unmaskedContext = emptyContextObject; var context = null; var contextType = ctor.contextType; 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; } // Instantiate twice to help detect side-effects. var instance = new ctor(props, context); var state = workInProgress.memoizedState = instance.state !== null && instance.state !== undefined ? instance.state : null; adoptClassInstance(workInProgress, instance); if (isLegacyContextConsumer) { cacheContext(workInProgress, unmaskedContext, context); } return instance; } function callComponentWillMount(workInProgress, instance) { startPhaseTimer(workInProgress, 'componentWillMount'); var oldState = instance.state; if (typeof instance.componentWillMount === 'function') { instance.componentWillMount(); } if (typeof instance.UNSAFE_componentWillMount === 'function') { instance.UNSAFE_componentWillMount(); } stopPhaseTimer(); if (oldState !== instance.state) { classComponentUpdater.enqueueReplaceState(instance, instance.state, null); } } function callComponentWillReceiveProps(workInProgress, instance, newProps, nextContext) { var oldState = instance.state; startPhaseTimer(workInProgress, 'componentWillReceiveProps'); if (typeof instance.componentWillReceiveProps === 'function') { instance.componentWillReceiveProps(newProps, nextContext); } if (typeof instance.UNSAFE_componentWillReceiveProps === 'function') { instance.UNSAFE_componentWillReceiveProps(newProps, nextContext); } stopPhaseTimer(); if (instance.state !== oldState) { classComponentUpdater.enqueueReplaceState(instance, instance.state, null); } } // Invokes the mount life-cycles on a previously never rendered instance. function mountClassInstance(workInProgress, ctor, newProps, renderExpirationTime) { var instance = workInProgress.stateNode; instance.props = newProps; instance.state = workInProgress.memoizedState; instance.refs = emptyRefsObject; 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); } var updateQueue = workInProgress.updateQueue; if (updateQueue !== null) { processUpdateQueue(workInProgress, updateQueue, newProps, instance, renderExpirationTime); 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. updateQueue = workInProgress.updateQueue; if (updateQueue !== null) { processUpdateQueue(workInProgress, updateQueue, newProps, instance, renderExpirationTime); instance.state = workInProgress.memoizedState; } } if (typeof instance.componentDidMount === 'function') { workInProgress.effectTag |= Update; } } function resumeMountClassInstance(workInProgress, ctor, newProps, renderExpirationTime) { var instance = workInProgress.stateNode; var oldProps = workInProgress.memoizedProps; instance.props = oldProps; var oldContext = instance.context; var contextType = ctor.contextType; var nextContext = void 0; 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'; // Note: During these life-cycles, instance.props/instance.state are what // ever the previously attempted to render - not the "current". However, // during componentDidUpdate we pass the "current" props. // In order to support react-lifecycles-compat polyfilled components, // Unsafe lifecycles should not be invoked for components using the new APIs. if (!hasNewLifecycles && (typeof instance.UNSAFE_componentWillReceiveProps === 'function' || typeof instance.componentWillReceiveProps === 'function')) { if (oldProps !== newProps || oldContext !== nextContext) { callComponentWillReceiveProps(workInProgress, instance, newProps, nextContext); } } resetHasForceUpdateBeforeProcessing(); var oldState = workInProgress.memoizedState; var newState = instance.state = oldState; var updateQueue = workInProgress.updateQueue; if (updateQueue !== null) { processUpdateQueue(workInProgress, updateQueue, newProps, instance, renderExpirationTime); newState = workInProgress.memoizedState; } if (oldProps === newProps && oldState === newState && !hasContextChanged() && !checkHasForceUpdateAfterProcessing()) { // If an update was already in progress, we should schedule an Update // effect even though we're bailing out, so that cWU/cDU are called. if (typeof instance.componentDidMount === 'function') { workInProgress.effectTag |= Update; } 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')) { startPhaseTimer(workInProgress, 'componentWillMount'); if (typeof instance.componentWillMount === 'function') { instance.componentWillMount(); } if (typeof instance.UNSAFE_componentWillMount === 'function') { instance.UNSAFE_componentWillMount(); } stopPhaseTimer(); } if (typeof instance.componentDidMount === 'function') { workInProgress.effectTag |= Update; } } 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.effectTag |= Update; } // 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, renderExpirationTime) { var instance = workInProgress.stateNode; var oldProps = workInProgress.memoizedProps; instance.props = workInProgress.type === workInProgress.elementType ? oldProps : resolveDefaultProps(workInProgress.type, oldProps); var oldContext = instance.context; var contextType = ctor.contextType; var nextContext = void 0; 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 (oldProps !== newProps || oldContext !== nextContext) { callComponentWillReceiveProps(workInProgress, instance, newProps, nextContext); } } resetHasForceUpdateBeforeProcessing(); var oldState = workInProgress.memoizedState; var newState = instance.state = oldState; var updateQueue = workInProgress.updateQueue; if (updateQueue !== null) { processUpdateQueue(workInProgress, updateQueue, newProps, instance, renderExpirationTime); newState = workInProgress.memoizedState; } if (oldProps === newProps && oldState === newState && !hasContextChanged() && !checkHasForceUpdateAfterProcessing()) { // If an update was already in progress, we should schedule an Update // effect even though we're bailing out, so that cWU/cDU are called. if (typeof instance.componentDidUpdate === 'function') { if (oldProps !== current.memoizedProps || oldState !== current.memoizedState) { workInProgress.effectTag |= Update; } } if (typeof instance.getSnapshotBeforeUpdate === 'function') { if (oldProps !== current.memoizedProps || oldState !== current.memoizedState) { workInProgress.effectTag |= Snapshot; } } 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_componentWillUpdate === 'function' || typeof instance.componentWillUpdate === 'function')) { startPhaseTimer(workInProgress, 'componentWillUpdate'); if (typeof instance.componentWillUpdate === 'function') { instance.componentWillUpdate(newProps, newState, nextContext); } if (typeof instance.UNSAFE_componentWillUpdate === 'function') { instance.UNSAFE_componentWillUpdate(newProps, newState, nextContext); } stopPhaseTimer(); } if (typeof instance.componentDidUpdate === 'function') { workInProgress.effectTag |= Update; } if (typeof instance.getSnapshotBeforeUpdate === 'function') { workInProgress.effectTag |= 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 (oldProps !== current.memoizedProps || oldState !== current.memoizedState) { workInProgress.effectTag |= Update; } } if (typeof instance.getSnapshotBeforeUpdate === 'function') { if (oldProps !== current.memoizedProps || oldState !== current.memoizedState) { workInProgress.effectTag |= 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; } var isArray = Array.isArray; function coerceRef(returnFiber, current$$1, element) { var mixedRef = element.ref; if (mixedRef !== null && typeof mixedRef !== 'function' && typeof mixedRef !== 'object') { if (element._owner) { var owner = element._owner; var inst = void 0; if (owner) { var ownerFiber = owner; !(ownerFiber.tag === ClassComponent) ? reactProdInvariant('309') : void 0; inst = ownerFiber.stateNode; } !inst ? reactProdInvariant('147', mixedRef) : void 0; var stringRef = '' + mixedRef; // Check if previous string ref matches new string ref if (current$$1 !== null && current$$1.ref !== null && typeof current$$1.ref === 'function' && current$$1.ref._stringRef === stringRef) { return current$$1.ref; } var ref = function (value) { var refs = inst.refs; if (refs === emptyRefsObject) { // This is a lazy pooled frozen object, so we need to initialize. refs = inst.refs = {}; } if (value === null) { delete refs[stringRef]; } else { refs[stringRef] = value; } }; ref._stringRef = stringRef; return ref; } else { !(typeof mixedRef === 'string') ? reactProdInvariant('284') : void 0; !element._owner ? reactProdInvariant('290', mixedRef) : void 0; } } return mixedRef; } function throwOnInvalidObjectType(returnFiber, newChild) { if (returnFiber.type !== 'textarea') { var addendum = ''; reactProdInvariant('31', Object.prototype.toString.call(newChild) === '[object Object]' ? 'object with keys {' + Object.keys(newChild).join(', ') + '}' : newChild, addendum); } } // 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 ChildReconciler(shouldTrackSideEffects) { function deleteChild(returnFiber, childToDelete) { if (!shouldTrackSideEffects) { // Noop. return; } // Deletions are added in reversed order so we add it to the front. // At this point, the return fiber's effect list is empty except for // deletions, so we can just append the deletion to the list. The remaining // effects aren't added until the complete phase. Once we implement // resuming, this may not be true. var last = returnFiber.lastEffect; if (last !== null) { last.nextEffect = childToDelete; returnFiber.lastEffect = childToDelete; } else { returnFiber.firstEffect = returnFiber.lastEffect = childToDelete; } childToDelete.nextEffect = null; childToDelete.effectTag = Deletion; } 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; while (childToDelete !== null) { deleteChild(returnFiber, childToDelete); childToDelete = childToDelete.sibling; } return null; } function mapRemainingChildren(returnFiber, currentFirstChild) { // Add the remaining children to a temporary map so that we can find them by // keys quickly. Implicit (null) keys get added to this set with their index 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; } return existingChildren; } function useFiber(fiber, pendingProps, expirationTime) { // 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, expirationTime); clone.index = 0; clone.sibling = null; return clone; } function placeChild(newFiber, lastPlacedIndex, newIndex) { newFiber.index = newIndex; if (!shouldTrackSideEffects) { // Noop. return lastPlacedIndex; } var current$$1 = newFiber.alternate; if (current$$1 !== null) { var oldIndex = current$$1.index; if (oldIndex < lastPlacedIndex) { // This is a move. newFiber.effectTag = Placement; return lastPlacedIndex; } else { // This item can stay in place. return oldIndex; } } else { // This is an insertion. newFiber.effectTag = Placement; return lastPlacedIndex; } } 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.effectTag = Placement; } return newFiber; } function updateTextNode(returnFiber, current$$1, textContent, expirationTime) { if (current$$1 === null || current$$1.tag !== HostText) { // Insert var created = createFiberFromText(textContent, returnFiber.mode, expirationTime); created.return = returnFiber; return created; } else { // Update var existing = useFiber(current$$1, textContent, expirationTime); existing.return = returnFiber; return existing; } } function updateElement(returnFiber, current$$1, element, expirationTime) { if (current$$1 !== null && current$$1.elementType === element.type) { // Move based on index var existing = useFiber(current$$1, element.props, expirationTime); existing.ref = coerceRef(returnFiber, current$$1, element); existing.return = returnFiber; return existing; } else { // Insert var created = createFiberFromElement(element, returnFiber.mode, expirationTime); created.ref = coerceRef(returnFiber, current$$1, element); created.return = returnFiber; return created; } } function updatePortal(returnFiber, current$$1, portal, expirationTime) { if (current$$1 === null || current$$1.tag !== HostPortal || current$$1.stateNode.containerInfo !== portal.containerInfo || current$$1.stateNode.implementation !== portal.implementation) { // Insert var created = createFiberFromPortal(portal, returnFiber.mode, expirationTime); created.return = returnFiber; return created; } else { // Update var existing = useFiber(current$$1, portal.children || [], expirationTime); existing.return = returnFiber; return existing; } } function updateFragment(returnFiber, current$$1, fragment, expirationTime, key) { if (current$$1 === null || current$$1.tag !== Fragment) { // Insert var created = createFiberFromFragment(fragment, returnFiber.mode, expirationTime, key); created.return = returnFiber; return created; } else { // Update var existing = useFiber(current$$1, fragment, expirationTime); existing.return = returnFiber; return existing; } } function createChild(returnFiber, newChild, expirationTime) { if (typeof newChild === 'string' || typeof newChild === 'number') { // Text nodes don't have keys. If the previous node is implicitly keyed // we can continue to replace it without aborting even if it is not a text // node. var created = createFiberFromText('' + newChild, returnFiber.mode, expirationTime); created.return = returnFiber; return created; } if (typeof newChild === 'object' && newChild !== null) { switch (newChild.$$typeof) { case REACT_ELEMENT_TYPE: { var _created = createFiberFromElement(newChild, returnFiber.mode, expirationTime); _created.ref = coerceRef(returnFiber, null, newChild); _created.return = returnFiber; return _created; } case REACT_PORTAL_TYPE: { var _created2 = createFiberFromPortal(newChild, returnFiber.mode, expirationTime); _created2.return = returnFiber; return _created2; } } if (isArray(newChild) || getIteratorFn(newChild)) { var _created3 = createFiberFromFragment(newChild, returnFiber.mode, expirationTime, null); _created3.return = returnFiber; return _created3; } throwOnInvalidObjectType(returnFiber, newChild); } return null; } function updateSlot(returnFiber, oldFiber, newChild, expirationTime) { // Update the fiber if the keys match, otherwise return null. var key = oldFiber !== null ? oldFiber.key : null; if (typeof newChild === 'string' || typeof newChild === 'number') { // Text nodes don't have keys. If the previous node is implicitly keyed // we can continue to replace it without aborting even if it is not a text // node. if (key !== null) { return null; } return updateTextNode(returnFiber, oldFiber, '' + newChild, expirationTime); } if (typeof newChild === 'object' && newChild !== null) { switch (newChild.$$typeof) { case REACT_ELEMENT_TYPE: { if (newChild.key === key) { if (newChild.type === REACT_FRAGMENT_TYPE) { return updateFragment(returnFiber, oldFiber, newChild.props.children, expirationTime, key); } return updateElement(returnFiber, oldFiber, newChild, expirationTime); } else { return null; } } case REACT_PORTAL_TYPE: { if (newChild.key === key) { return updatePortal(returnFiber, oldFiber, newChild, expirationTime); } else { return null; } } } if (isArray(newChild) || getIteratorFn(newChild)) { if (key !== null) { return null; } return updateFragment(returnFiber, oldFiber, newChild, expirationTime, null); } throwOnInvalidObjectType(returnFiber, newChild); } return null; } function updateFromMap(existingChildren, returnFiber, newIdx, newChild, expirationTime) { if (typeof newChild === 'string' || typeof newChild === 'number') { // Text nodes don't have keys, so we neither have to check the old nor // new node for the key. If both are text nodes, they match. var matchedFiber = existingChildren.get(newIdx) || null; return updateTextNode(returnFiber, matchedFiber, '' + newChild, expirationTime); } 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 (newChild.type === REACT_FRAGMENT_TYPE) { return updateFragment(returnFiber, _matchedFiber, newChild.props.children, expirationTime, newChild.key); } return updateElement(returnFiber, _matchedFiber, newChild, expirationTime); } case REACT_PORTAL_TYPE: { var _matchedFiber2 = existingChildren.get(newChild.key === null ? newIdx : newChild.key) || null; return updatePortal(returnFiber, _matchedFiber2, newChild, expirationTime); } } if (isArray(newChild) || getIteratorFn(newChild)) { var _matchedFiber3 = existingChildren.get(newIdx) || null; return updateFragment(returnFiber, _matchedFiber3, newChild, expirationTime, null); } throwOnInvalidObjectType(returnFiber, newChild); } return null; } /** * Warns if there is a duplicate or missing key */ function reconcileChildrenArray(returnFiber, currentFirstChild, newChildren, expirationTime) { // 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. 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 newFiber = updateSlot(returnFiber, oldFiber, newChildren[newIdx], expirationTime); 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; } 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); } } 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; } previousNewFiber = newFiber; oldFiber = nextOldFiber; } if (newIdx === newChildren.length) { // We've reached the end of the new children. We can delete the rest. deleteRemainingChildren(returnFiber, oldFiber); return resultingFirstChild; } 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], expirationTime); if (!_newFiber) { continue; } lastPlacedIndex = placeChild(_newFiber, lastPlacedIndex, newIdx); if (previousNewFiber === null) { // TODO: Move out of the loop. This only happens for the first run. resultingFirstChild = _newFiber; } else { previousNewFiber.sibling = _newFiber; } previousNewFiber = _newFiber; } return resultingFirstChild; } // Add all children to a key map for quick lookups. var existingChildren = mapRemainingChildren(returnFiber, oldFiber); // Keep scanning and use the map to restore deleted items as moves. for (; newIdx < newChildren.length; newIdx++) { var _newFiber2 = updateFromMap(existingChildren, returnFiber, newIdx, newChildren[newIdx], expirationTime); if (_newFiber2) { 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); if (previousNewFiber === null) { resultingFirstChild = _newFiber2; } else { previousNewFiber.sibling = _newFiber2; } previousNewFiber = _newFiber2; } } 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); }); } return resultingFirstChild; } function reconcileChildrenIterator(returnFiber, currentFirstChild, newChildrenIterable, expirationTime) { // This is the same implementation as reconcileChildrenArray(), // but using the iterator instead. var iteratorFn = getIteratorFn(newChildrenIterable); !(typeof iteratorFn === 'function') ? reactProdInvariant('150') : void 0; var newChildren = iteratorFn.call(newChildrenIterable); !(newChildren != null) ? reactProdInvariant('151') : void 0; 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, expirationTime); 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) { oldFiber = nextOldFiber; } 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); } } 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; } previousNewFiber = newFiber; oldFiber = nextOldFiber; } if (step.done) { // We've reached the end of the new children. We can delete the rest. deleteRemainingChildren(returnFiber, oldFiber); return resultingFirstChild; } 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, expirationTime); if (_newFiber3 === null) { continue; } 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; } previousNewFiber = _newFiber3; } return resultingFirstChild; } // Add all children to a key map for quick lookups. var existingChildren = mapRemainingChildren(returnFiber, oldFiber); // Keep scanning and use the map to restore deleted items as moves. for (; !step.done; newIdx++, step = newChildren.next()) { var _newFiber4 = updateFromMap(existingChildren, returnFiber, newIdx, step.value, expirationTime); 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); } } 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); }); } return resultingFirstChild; } function reconcileSingleTextNode(returnFiber, currentFirstChild, textContent, expirationTime) { // 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, expirationTime); 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, expirationTime); created.return = returnFiber; return created; } function reconcileSingleElement(returnFiber, currentFirstChild, element, expirationTime) { 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) { if (child.tag === Fragment ? element.type === REACT_FRAGMENT_TYPE : child.elementType === element.type) { deleteRemainingChildren(returnFiber, child.sibling); var existing = useFiber(child, element.type === REACT_FRAGMENT_TYPE ? element.props.children : element.props, expirationTime); existing.ref = coerceRef(returnFiber, child, element); existing.return = returnFiber; return existing; } else { deleteRemainingChildren(returnFiber, child); break; } } else { deleteChild(returnFiber, child); } child = child.sibling; } if (element.type === REACT_FRAGMENT_TYPE) { var created = createFiberFromFragment(element.props.children, returnFiber.mode, expirationTime, element.key); created.return = returnFiber; return created; } else { var _created4 = createFiberFromElement(element, returnFiber.mode, expirationTime); _created4.ref = coerceRef(returnFiber, currentFirstChild, element); _created4.return = returnFiber; return _created4; } } function reconcileSinglePortal(returnFiber, currentFirstChild, portal, expirationTime) { 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 || [], expirationTime); existing.return = returnFiber; return existing; } else { deleteRemainingChildren(returnFiber, child); break; } } else { deleteChild(returnFiber, child); } child = child.sibling; } var created = createFiberFromPortal(portal, returnFiber.mode, expirationTime); 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 reconcileChildFibers(returnFiber, currentFirstChild, newChild, expirationTime) { // This function is not recursive. // If the top level item is an array, we treat it as a set of children, // not as a fragment. Nested arrays on the other hand will be treated as // fragment nodes. Recursion happens at the normal flow. // Handle top level unkeyed fragments as if they were arrays. // This leads to an ambiguity between <>{[...]} and <>.... // We treat the ambiguous cases above the same. var isUnkeyedTopLevelFragment = typeof newChild === 'object' && newChild !== null && newChild.type === REACT_FRAGMENT_TYPE && newChild.key === null; if (isUnkeyedTopLevelFragment) { newChild = newChild.props.children; } // Handle object types var isObject = typeof newChild === 'object' && newChild !== null; if (isObject) { switch (newChild.$$typeof) { case REACT_ELEMENT_TYPE: return placeSingleChild(reconcileSingleElement(returnFiber, currentFirstChild, newChild, expirationTime)); case REACT_PORTAL_TYPE: return placeSingleChild(reconcileSinglePortal(returnFiber, currentFirstChild, newChild, expirationTime)); } } if (typeof newChild === 'string' || typeof newChild === 'number') { return placeSingleChild(reconcileSingleTextNode(returnFiber, currentFirstChild, '' + newChild, expirationTime)); } if (isArray(newChild)) { return reconcileChildrenArray(returnFiber, currentFirstChild, newChild, expirationTime); } if (getIteratorFn(newChild)) { return reconcileChildrenIterator(returnFiber, currentFirstChild, newChild, expirationTime); } if (isObject) { throwOnInvalidObjectType(returnFiber, newChild); } if (typeof newChild === 'undefined' && !isUnkeyedTopLevelFragment) { // If the new child is undefined, and the return fiber is a composite // component, throw an error. If Fiber return types are disabled, // we already threw above. switch (returnFiber.tag) { case ClassComponent: { } // Intentionally fall through to the next case, which handles both // functions and classes // eslint-disable-next-lined no-fallthrough case FunctionComponent: { var Component = returnFiber.type; reactProdInvariant('152', Component.displayName || Component.name || 'Component'); } } } // Remaining cases are all treated as empty. return deleteRemainingChildren(returnFiber, currentFirstChild); } return reconcileChildFibers; } var reconcileChildFibers = ChildReconciler(true); var mountChildFibers = ChildReconciler(false); function cloneChildFibers(current$$1, workInProgress) { !(current$$1 === null || workInProgress.child === current$$1.child) ? reactProdInvariant('153') : void 0; if (workInProgress.child === null) { return; } var currentChild = workInProgress.child; var newChild = createWorkInProgress(currentChild, currentChild.pendingProps, currentChild.expirationTime); workInProgress.child = newChild; newChild.return = workInProgress; while (currentChild.sibling !== null) { currentChild = currentChild.sibling; newChild = newChild.sibling = createWorkInProgress(currentChild, currentChild.pendingProps, currentChild.expirationTime); newChild.return = workInProgress; } newChild.sibling = null; } var NO_CONTEXT$1 = {}; var contextStackCursor$1 = createCursor(NO_CONTEXT$1); var contextFiberStackCursor = createCursor(NO_CONTEXT$1); var rootInstanceStackCursor = createCursor(NO_CONTEXT$1); function requiredContext(c) { !(c !== NO_CONTEXT$1) ? reactProdInvariant('174') : void 0; return c; } function getRootHostContainer() { var rootInstance = requiredContext(rootInstanceStackCursor.current); return rootInstance; } 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. 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. push(contextStackCursor$1, NO_CONTEXT$1, fiber); var nextRootContext = getRootHostContext(nextRootInstance); // Now that we know this function doesn't throw, replace it. pop(contextStackCursor$1, fiber); push(contextStackCursor$1, nextRootContext, fiber); } function popHostContainer(fiber) { pop(contextStackCursor$1, fiber); pop(contextFiberStackCursor, fiber); pop(rootInstanceStackCursor, fiber); } function getHostContext() { var context = requiredContext(contextStackCursor$1.current); return context; } function pushHostContext(fiber) { var rootInstance = requiredContext(rootInstanceStackCursor.current); var context = requiredContext(contextStackCursor$1.current); var nextContext = getChildHostContext(context, fiber.type, rootInstance); // Don't push this Fiber's context unless it's unique. if (context === nextContext) { return; } // Track the context and the Fiber that provided it. // This enables us to pop only Fibers that provide unique contexts. push(contextFiberStackCursor, fiber, fiber); push(contextStackCursor$1, nextContext, fiber); } function popHostContext(fiber) { // Do not pop unless this Fiber provided the current context. // pushHostContext() only pushes Fibers that provide unique contexts. if (contextFiberStackCursor.current !== fiber) { return; } pop(contextStackCursor$1, fiber); pop(contextFiberStackCursor, fiber); } var NoEffect$1 = /* */0; var UnmountSnapshot = /* */2; var UnmountMutation = /* */4; var MountMutation = /* */8; var UnmountLayout = /* */16; var MountLayout = /* */32; var MountPassive = /* */64; var UnmountPassive = /* */128; var ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher; // These are set right before calling the component. var renderExpirationTime = NoWork; // 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 nextCurrentHook = null; var firstWorkInProgressHook = null; var workInProgressHook = null; var nextWorkInProgressHook = null; var remainingExpirationTime = NoWork; var componentUpdateQueue = null; var sideEffectTag = 0; // Updates scheduled during render will trigger an immediate re-render at the // end of the current pass. We can't store these updates on the normal queue, // because if the work is aborted, they should be discarded. Because this is // a relatively rare case, we also don't want to add an additional field to // either the hook or queue object types. So we store them in a lazily create // map of queue -> render-phase updates, which are discarded once the component // completes without re-rendering. // Whether an update was scheduled during the currently executing render pass. var didScheduleRenderPhaseUpdate = false; // Lazily created map of render-phase updates var renderPhaseUpdates = null; // Counter to prevent infinite loops. var numberOfReRenders = 0; var RE_RENDER_LIMIT = 25; function throwInvalidHookError() { reactProdInvariant('321'); } function areHookInputsEqual(nextDeps, prevDeps) { if (prevDeps === null) { return false; } for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++) { if (is(nextDeps[i], prevDeps[i])) { continue; } return false; } return true; } function renderWithHooks(current, workInProgress, Component, props, refOrContext, nextRenderExpirationTime) { renderExpirationTime = nextRenderExpirationTime; currentlyRenderingFiber$1 = workInProgress; nextCurrentHook = current !== null ? current.memoizedState : null; { ReactCurrentDispatcher$1.current = nextCurrentHook === null ? HooksDispatcherOnMount : HooksDispatcherOnUpdate; } var children = Component(props, refOrContext); if (didScheduleRenderPhaseUpdate) { do { didScheduleRenderPhaseUpdate = false; numberOfReRenders += 1; // Start over from the beginning of the list nextCurrentHook = current !== null ? current.memoizedState : null; nextWorkInProgressHook = firstWorkInProgressHook; currentHook = null; workInProgressHook = null; componentUpdateQueue = null; ReactCurrentDispatcher$1.current = HooksDispatcherOnUpdate; children = Component(props, refOrContext); } while (didScheduleRenderPhaseUpdate); renderPhaseUpdates = null; numberOfReRenders = 0; } // 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-entrancy. ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; var renderedWork = currentlyRenderingFiber$1; renderedWork.memoizedState = firstWorkInProgressHook; renderedWork.expirationTime = remainingExpirationTime; renderedWork.updateQueue = componentUpdateQueue; renderedWork.effectTag |= sideEffectTag; var didRenderTooFewHooks = currentHook !== null && currentHook.next !== null; renderExpirationTime = NoWork; currentlyRenderingFiber$1 = null; currentHook = null; nextCurrentHook = null; firstWorkInProgressHook = null; workInProgressHook = null; nextWorkInProgressHook = null; remainingExpirationTime = NoWork; componentUpdateQueue = null; sideEffectTag = 0; // These were reset above // didScheduleRenderPhaseUpdate = false; // renderPhaseUpdates = null; // numberOfReRenders = 0; !!didRenderTooFewHooks ? reactProdInvariant('300') : void 0; return children; } function bailoutHooks(current, workInProgress, expirationTime) { workInProgress.updateQueue = current.updateQueue; workInProgress.effectTag &= ~(Passive | Update); if (current.expirationTime <= expirationTime) { current.expirationTime = NoWork; } } function resetHooks() { // 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-entrancy. ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; // This is used to reset the state of this module when a component throws. // It's also called inside mountIndeterminateComponent if we determine the // component is a module-style component. renderExpirationTime = NoWork; currentlyRenderingFiber$1 = null; currentHook = null; nextCurrentHook = null; firstWorkInProgressHook = null; workInProgressHook = null; nextWorkInProgressHook = null; remainingExpirationTime = NoWork; componentUpdateQueue = null; sideEffectTag = 0; didScheduleRenderPhaseUpdate = false; renderPhaseUpdates = null; numberOfReRenders = 0; } function mountWorkInProgressHook() { var hook = { memoizedState: null, baseState: null, queue: null, baseUpdate: null, next: null }; if (workInProgressHook === null) { // This is the first hook in the list firstWorkInProgressHook = workInProgressHook = hook; } else { // Append to the end of the list workInProgressHook = workInProgressHook.next = hook; } return workInProgressHook; } 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. When we reach the end of the base list, we must switch to // the dispatcher used for mounts. if (nextWorkInProgressHook !== null) { // There's already a work-in-progress. Reuse it. workInProgressHook = nextWorkInProgressHook; nextWorkInProgressHook = workInProgressHook.next; currentHook = nextCurrentHook; nextCurrentHook = currentHook !== null ? currentHook.next : null; } else { // Clone from the current hook. !(nextCurrentHook !== null) ? reactProdInvariant('310') : void 0; currentHook = nextCurrentHook; var newHook = { memoizedState: currentHook.memoizedState, baseState: currentHook.baseState, queue: currentHook.queue, baseUpdate: currentHook.baseUpdate, next: null }; if (workInProgressHook === null) { // This is the first hook in the list. workInProgressHook = firstWorkInProgressHook = newHook; } else { // Append to the end of the list. workInProgressHook = workInProgressHook.next = newHook; } nextCurrentHook = currentHook.next; } return workInProgressHook; } function createFunctionComponentUpdateQueue() { return { lastEffect: null }; } function basicStateReducer(state, action) { return typeof action === 'function' ? action(state) : action; } function mountReducer(reducer, initialArg, init) { var hook = mountWorkInProgressHook(); var initialState = void 0; if (init !== undefined) { initialState = init(initialArg); } else { initialState = initialArg; } hook.memoizedState = hook.baseState = initialState; var queue = hook.queue = { last: null, dispatch: null, lastRenderedReducer: reducer, lastRenderedState: initialState }; var dispatch = queue.dispatch = dispatchAction.bind(null, // Flow doesn't know this is non-null, but we do. currentlyRenderingFiber$1, queue); return [hook.memoizedState, dispatch]; } function updateReducer(reducer, initialArg, init) { var hook = updateWorkInProgressHook(); var queue = hook.queue; !(queue !== null) ? reactProdInvariant('311') : void 0; queue.lastRenderedReducer = reducer; if (numberOfReRenders > 0) { // This is a re-render. Apply the new render phase updates to the previous var _dispatch = queue.dispatch; if (renderPhaseUpdates !== null) { // Render phase updates are stored in a map of queue -> linked list var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue); if (firstRenderPhaseUpdate !== undefined) { renderPhaseUpdates.delete(queue); var newState = hook.memoizedState; var update = firstRenderPhaseUpdate; do { // Process this render phase update. We don't have to check the // priority because it will always be the same as the current // render's. var _action = update.action; newState = reducer(newState, _action); update = update.next; } while (update !== null); // Mark that the fiber performed work, but only if the new state is // different from the current state. if (!is(newState, hook.memoizedState)) { markWorkInProgressReceivedUpdate(); } hook.memoizedState = newState; // Don't persist the state accumlated from the render phase updates to // the base state unless the queue is empty. // TODO: Not sure if this is the desired semantics, but it's what we // do for gDSFP. I can't remember why. if (hook.baseUpdate === queue.last) { hook.baseState = newState; } queue.lastRenderedState = newState; return [newState, _dispatch]; } } return [hook.memoizedState, _dispatch]; } // The last update in the entire queue var last = queue.last; // The last update that is part of the base state. var baseUpdate = hook.baseUpdate; var baseState = hook.baseState; // Find the first unprocessed update. var first = void 0; if (baseUpdate !== null) { if (last !== null) { // For the first update, the queue is a circular linked list where // `queue.last.next = queue.first`. Once the first update commits, and // the `baseUpdate` is no longer empty, we can unravel the list. last.next = null; } first = baseUpdate.next; } else { first = last !== null ? last.next : null; } if (first !== null) { var _newState = baseState; var newBaseState = null; var newBaseUpdate = null; var prevUpdate = baseUpdate; var _update = first; var didSkip = false; do { var updateExpirationTime = _update.expirationTime; if (updateExpirationTime < renderExpirationTime) { // Priority is insufficient. Skip this update. If this is the first // skipped update, the previous update/state is the new base // update/state. if (!didSkip) { didSkip = true; newBaseUpdate = prevUpdate; newBaseState = _newState; } // Update the remaining priority in the queue. if (updateExpirationTime > remainingExpirationTime) { remainingExpirationTime = updateExpirationTime; } } else { // Process this update. if (_update.eagerReducer === reducer) { // If this update was processed eagerly, and its reducer matches the // current reducer, we can use the eagerly computed state. _newState = _update.eagerState; } else { var _action2 = _update.action; _newState = reducer(_newState, _action2); } } prevUpdate = _update; _update = _update.next; } while (_update !== null && _update !== first); if (!didSkip) { newBaseUpdate = prevUpdate; newBaseState = _newState; } // Mark that the fiber performed work, but only if the new state is // different from the current state. if (!is(_newState, hook.memoizedState)) { markWorkInProgressReceivedUpdate(); } hook.memoizedState = _newState; hook.baseUpdate = newBaseUpdate; hook.baseState = newBaseState; queue.lastRenderedState = _newState; } var dispatch = queue.dispatch; return [hook.memoizedState, dispatch]; } function mountState(initialState) { var hook = mountWorkInProgressHook(); if (typeof initialState === 'function') { initialState = initialState(); } hook.memoizedState = hook.baseState = initialState; var queue = hook.queue = { last: null, dispatch: null, lastRenderedReducer: basicStateReducer, lastRenderedState: initialState }; var dispatch = queue.dispatch = dispatchAction.bind(null, // Flow doesn't know this is non-null, but we do. currentlyRenderingFiber$1, queue); return [hook.memoizedState, dispatch]; } function updateState(initialState) { return updateReducer(basicStateReducer, initialState); } function pushEffect(tag, create, destroy, deps) { var effect = { tag: tag, create: create, destroy: destroy, deps: deps, // Circular next: null }; if (componentUpdateQueue === null) { componentUpdateQueue = createFunctionComponentUpdateQueue(); componentUpdateQueue.lastEffect = effect.next = effect; } else { var _lastEffect = componentUpdateQueue.lastEffect; if (_lastEffect === null) { componentUpdateQueue.lastEffect = effect.next = effect; } else { var firstEffect = _lastEffect.next; _lastEffect.next = effect; effect.next = firstEffect; componentUpdateQueue.lastEffect = effect; } } return effect; } function mountRef(initialValue) { var hook = mountWorkInProgressHook(); var ref = { current: initialValue }; hook.memoizedState = ref; return ref; } function updateRef(initialValue) { var hook = updateWorkInProgressHook(); return hook.memoizedState; } function mountEffectImpl(fiberEffectTag, hookEffectTag, create, deps) { var hook = mountWorkInProgressHook(); var nextDeps = deps === undefined ? null : deps; sideEffectTag |= fiberEffectTag; hook.memoizedState = pushEffect(hookEffectTag, create, undefined, nextDeps); } function updateEffectImpl(fiberEffectTag, hookEffectTag, create, deps) { var hook = updateWorkInProgressHook(); var nextDeps = deps === undefined ? null : deps; var destroy = undefined; if (currentHook !== null) { var prevEffect = currentHook.memoizedState; destroy = prevEffect.destroy; if (nextDeps !== null) { var prevDeps = prevEffect.deps; if (areHookInputsEqual(nextDeps, prevDeps)) { pushEffect(NoEffect$1, create, destroy, nextDeps); return; } } } sideEffectTag |= fiberEffectTag; hook.memoizedState = pushEffect(hookEffectTag, create, destroy, nextDeps); } function mountEffect(create, deps) { return mountEffectImpl(Update | Passive, UnmountPassive | MountPassive, create, deps); } function updateEffect(create, deps) { return updateEffectImpl(Update | Passive, UnmountPassive | MountPassive, create, deps); } function mountLayoutEffect(create, deps) { return mountEffectImpl(Update, UnmountMutation | MountLayout, create, deps); } function updateLayoutEffect(create, deps) { return updateEffectImpl(Update, UnmountMutation | MountLayout, 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; var _inst2 = create(); refObject.current = _inst2; return function () { refObject.current = null; }; } } function mountImperativeHandle(ref, create, deps) { var effectDeps = deps !== null && deps !== undefined ? deps.concat([ref]) : null; return mountEffectImpl(Update, UnmountMutation | MountLayout, imperativeHandleEffect.bind(null, create, ref), effectDeps); } function updateImperativeHandle(ref, create, deps) { var effectDeps = deps !== null && deps !== undefined ? deps.concat([ref]) : null; return updateEffectImpl(Update, UnmountMutation | MountLayout, imperativeHandleEffect.bind(null, create, ref), effectDeps); } function mountDebugValue(value, formatterFn) { // This hook is normally a no-op. // The react-debug-hooks package injects its own implementation // so that e.g. DevTools can display custom hook values. } var updateDebugValue = mountDebugValue; function mountCallback(callback, deps) { var hook = mountWorkInProgressHook(); var nextDeps = deps === undefined ? null : deps; hook.memoizedState = [callback, nextDeps]; return callback; } function updateCallback(callback, deps) { var hook = updateWorkInProgressHook(); var nextDeps = deps === undefined ? null : deps; var prevState = hook.memoizedState; if (prevState !== null) { if (nextDeps !== null) { var prevDeps = prevState[1]; if (areHookInputsEqual(nextDeps, prevDeps)) { return prevState[0]; } } } hook.memoizedState = [callback, nextDeps]; return callback; } function mountMemo(nextCreate, deps) { var hook = mountWorkInProgressHook(); var nextDeps = deps === undefined ? null : deps; var nextValue = nextCreate(); hook.memoizedState = [nextValue, nextDeps]; return nextValue; } function updateMemo(nextCreate, deps) { var hook = updateWorkInProgressHook(); var nextDeps = deps === undefined ? null : deps; var prevState = hook.memoizedState; if (prevState !== null) { // Assume these are defined. If they're not, areHookInputsEqual will warn. if (nextDeps !== null) { var prevDeps = prevState[1]; if (areHookInputsEqual(nextDeps, prevDeps)) { return prevState[0]; } } } var nextValue = nextCreate(); hook.memoizedState = [nextValue, nextDeps]; return nextValue; } function dispatchAction(fiber, queue, action) { !(numberOfReRenders < RE_RENDER_LIMIT) ? reactProdInvariant('301') : void 0; var alternate = fiber.alternate; if (fiber === currentlyRenderingFiber$1 || alternate !== null && alternate === currentlyRenderingFiber$1) { // 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. didScheduleRenderPhaseUpdate = true; var update = { expirationTime: renderExpirationTime, action: action, eagerReducer: null, eagerState: null, next: null }; if (renderPhaseUpdates === null) { renderPhaseUpdates = new Map(); } var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue); if (firstRenderPhaseUpdate === undefined) { renderPhaseUpdates.set(queue, update); } else { // Append the update to the end of the list. var lastRenderPhaseUpdate = firstRenderPhaseUpdate; while (lastRenderPhaseUpdate.next !== null) { lastRenderPhaseUpdate = lastRenderPhaseUpdate.next; } lastRenderPhaseUpdate.next = update; } } else { flushPassiveEffects$1(); var currentTime = requestCurrentTime(); var _expirationTime = computeExpirationForFiber(currentTime, fiber); var _update2 = { expirationTime: _expirationTime, action: action, eagerReducer: null, eagerState: null, next: null }; // Append the update to the end of the list. var _last = queue.last; if (_last === null) { // This is the first update. Create a circular list. _update2.next = _update2; } else { var first = _last.next; if (first !== null) { // Still circular. _update2.next = first; } _last.next = _update2; } queue.last = _update2; if (fiber.expirationTime === NoWork && (alternate === null || alternate.expirationTime === NoWork)) { // 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) { 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. _update2.eagerReducer = _lastRenderedReducer; _update2.eagerState = _eagerState; if (is(_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. return; } } catch (error) { // Suppress the error. It will throw again in the render phase. } finally { } } } scheduleWork(fiber, _expirationTime); } } var ContextOnlyDispatcher = { readContext: readContext, useCallback: throwInvalidHookError, useContext: throwInvalidHookError, useEffect: throwInvalidHookError, useImperativeHandle: throwInvalidHookError, useLayoutEffect: throwInvalidHookError, useMemo: throwInvalidHookError, useReducer: throwInvalidHookError, useRef: throwInvalidHookError, useState: throwInvalidHookError, useDebugValue: throwInvalidHookError }; var HooksDispatcherOnMount = { readContext: readContext, useCallback: mountCallback, useContext: readContext, useEffect: mountEffect, useImperativeHandle: mountImperativeHandle, useLayoutEffect: mountLayoutEffect, useMemo: mountMemo, useReducer: mountReducer, useRef: mountRef, useState: mountState, useDebugValue: mountDebugValue }; var HooksDispatcherOnUpdate = { readContext: readContext, useCallback: updateCallback, useContext: readContext, useEffect: updateEffect, useImperativeHandle: updateImperativeHandle, useLayoutEffect: updateLayoutEffect, useMemo: updateMemo, useReducer: updateReducer, useRef: updateRef, useState: updateState, useDebugValue: updateDebugValue }; var commitTime = 0; var profilerStartTime = -1; function getCommitTime() { return commitTime; } function recordCommitTime() { if (!enableProfilerTimer) { return; } commitTime = now(); } function startProfilerTimer(fiber) { if (!enableProfilerTimer) { return; } profilerStartTime = now(); if (fiber.actualStartTime < 0) { fiber.actualStartTime = now(); } } function stopProfilerTimerIfRunning(fiber) { if (!enableProfilerTimer) { return; } profilerStartTime = -1; } function stopProfilerTimerIfRunningAndRecordDelta(fiber, overrideBaseTime) { if (!enableProfilerTimer) { return; } if (profilerStartTime >= 0) { var elapsedTime = now() - profilerStartTime; fiber.actualDuration += elapsedTime; if (overrideBaseTime) { fiber.selfBaseDuration = elapsedTime; } profilerStartTime = -1; } } // The deepest Fiber on the stack involved in a hydration context. // This may have been an insertion or a hydration. var hydrationParentFiber = null; var nextHydratableInstance = null; var isHydrating = false; function enterHydrationState(fiber) { if (!supportsHydration) { return false; } var parentInstance = fiber.stateNode.containerInfo; nextHydratableInstance = getFirstHydratableChild(parentInstance); hydrationParentFiber = fiber; isHydrating = true; return true; } function reenterHydrationStateFromDehydratedSuspenseInstance(fiber) { if (!supportsHydration) { return false; } var suspenseInstance = fiber.stateNode; nextHydratableInstance = getNextHydratableSibling(suspenseInstance); popToNextHostParent(fiber); isHydrating = true; return true; } function deleteHydratableInstance(returnFiber, instance) { var childToDelete = createFiberFromHostInstanceForDeletion(); childToDelete.stateNode = instance; childToDelete.return = returnFiber; childToDelete.effectTag = Deletion; // This might seem like it belongs on progressedFirstDeletion. However, // these children are not part of the reconciliation list of children. // Even if we abort and rereconcile the children, that will try to hydrate // again and the nodes are still in the host tree so these will be // recreated. if (returnFiber.lastEffect !== null) { returnFiber.lastEffect.nextEffect = childToDelete; returnFiber.lastEffect = childToDelete; } else { returnFiber.firstEffect = returnFiber.lastEffect = childToDelete; } } function insertNonHydratedInstance(returnFiber, fiber) { fiber.effectTag |= Placement; } function tryHydrate(fiber, nextInstance) { switch (fiber.tag) { case HostComponent: { var type = fiber.type; var props = fiber.pendingProps; var instance = canHydrateInstance(nextInstance, type, props); if (instance !== null) { fiber.stateNode = instance; return true; } return false; } case HostText: { var text = fiber.pendingProps; var textInstance = canHydrateTextInstance(nextInstance, text); if (textInstance !== null) { fiber.stateNode = textInstance; return true; } return false; } case SuspenseComponent: { if (enableSuspenseServerRenderer) { var suspenseInstance = canHydrateSuspenseInstance(nextInstance); if (suspenseInstance !== null) { // Downgrade the tag to a dehydrated component until we've hydrated it. fiber.tag = DehydratedSuspenseComponent; fiber.stateNode = suspenseInstance; return true; } } return false; } default: return false; } } function tryToClaimNextHydratableInstance(fiber) { if (!isHydrating) { return; } var nextInstance = nextHydratableInstance; if (!nextInstance) { // Nothing to hydrate. Make it an insertion. insertNonHydratedInstance(hydrationParentFiber, fiber); isHydrating = false; hydrationParentFiber = fiber; return; } var firstAttemptedInstance = nextInstance; if (!tryHydrate(fiber, nextInstance)) { // If we can't hydrate this instance let's try the next one. // We use this as a heuristic. It's based on intuition and not data so it // might be flawed or unnecessary. nextInstance = getNextHydratableSibling(firstAttemptedInstance); if (!nextInstance || !tryHydrate(fiber, nextInstance)) { // Nothing to hydrate. Make it an insertion. insertNonHydratedInstance(hydrationParentFiber, fiber); isHydrating = false; hydrationParentFiber = fiber; return; } // We matched the next one, we'll now assume that the first one was // superfluous and we'll delete it. Since we can't eagerly delete it // we'll have to schedule a deletion. To do that, this node needs a dummy // fiber associated with it. deleteHydratableInstance(hydrationParentFiber, firstAttemptedInstance); } hydrationParentFiber = fiber; nextHydratableInstance = getFirstHydratableChild(nextInstance); } function prepareToHydrateHostInstance(fiber, rootContainerInstance, hostContext) { if (!supportsHydration) { reactProdInvariant('175'); } var instance = fiber.stateNode; var updatePayload = hydrateInstance(instance, fiber.type, fiber.memoizedProps, rootContainerInstance, hostContext, fiber); // TODO: Type this specific to this type of component. fiber.updateQueue = updatePayload; // If the update payload indicates that there is a change or if there // is a new ref we mark this as an update. if (updatePayload !== null) { return true; } return false; } function prepareToHydrateHostTextInstance(fiber) { if (!supportsHydration) { reactProdInvariant('176'); } var textInstance = fiber.stateNode; var textContent = fiber.memoizedProps; var shouldUpdate = hydrateTextInstance(textInstance, textContent, fiber); return shouldUpdate; } function skipPastDehydratedSuspenseInstance(fiber) { if (!supportsHydration) { reactProdInvariant('316'); } var suspenseInstance = fiber.stateNode; !suspenseInstance ? reactProdInvariant('317') : void 0; nextHydratableInstance = getNextHydratableInstanceAfterSuspenseInstance(suspenseInstance); } function popToNextHostParent(fiber) { var parent = fiber.return; while (parent !== null && parent.tag !== HostComponent && parent.tag !== HostRoot && parent.tag !== DehydratedSuspenseComponent) { parent = parent.return; } hydrationParentFiber = parent; } function popHydrationState(fiber) { if (!supportsHydration) { return false; } if (fiber !== hydrationParentFiber) { // We're deeper than the current hydration context, inside an inserted // tree. return false; } if (!isHydrating) { // If we're not currently hydrating but we're in a hydration context, then // we were an insertion and now need to pop up reenter hydration of our // siblings. popToNextHostParent(fiber); isHydrating = true; return false; } var type = fiber.type; // If we have any remaining hydratable nodes, we need to delete them now. // We only do this deeper than head and body since they tend to have random // other nodes in them. We also ignore components with pure text content in // side of them. // TODO: Better heuristic. if (fiber.tag !== HostComponent || type !== 'head' && type !== 'body' && !shouldSetTextContent(type, fiber.memoizedProps)) { var nextInstance = nextHydratableInstance; while (nextInstance) { deleteHydratableInstance(fiber, nextInstance); nextInstance = getNextHydratableSibling(nextInstance); } } popToNextHostParent(fiber); nextHydratableInstance = hydrationParentFiber ? getNextHydratableSibling(fiber.stateNode) : null; return true; } function resetHydrationState() { if (!supportsHydration) { return; } hydrationParentFiber = null; nextHydratableInstance = null; isHydrating = false; } var ReactCurrentOwner$2 = ReactSharedInternals.ReactCurrentOwner; var didReceiveUpdate = false; function reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime) { if (current$$1 === 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, renderExpirationTime); } 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$$1.child, nextChildren, renderExpirationTime); } } function forceUnmountCurrentAndReconcile(current$$1, workInProgress, nextChildren, renderExpirationTime) { // 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$$1.child, null, renderExpirationTime); // 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 their // identity matches. workInProgress.child = reconcileChildFibers(workInProgress, null, nextChildren, renderExpirationTime); } function updateForwardRef(current$$1, workInProgress, Component, nextProps, renderExpirationTime) { // 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; // The rest is a fork of updateFunctionComponent var nextChildren = void 0; prepareToReadContext(workInProgress, renderExpirationTime); { nextChildren = renderWithHooks(current$$1, workInProgress, render, nextProps, ref, renderExpirationTime); } if (current$$1 !== null && !didReceiveUpdate) { bailoutHooks(current$$1, workInProgress, renderExpirationTime); return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); } // React DevTools reads this flag. workInProgress.effectTag |= PerformedWork; reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); return workInProgress.child; } function updateMemoComponent(current$$1, workInProgress, Component, nextProps, updateExpirationTime, renderExpirationTime) { if (current$$1 === null) { var type = Component.type; if (isSimpleFunctionComponent(type) && Component.compare === null && // SimpleMemoComponent codepath doesn't resolve outer props either. Component.defaultProps === undefined) { // If this is a plain function component without default props, // and with only the default shallow comparison, we upgrade it // to a SimpleMemoComponent to allow fast path updates. workInProgress.tag = SimpleMemoComponent; workInProgress.type = type; return updateSimpleMemoComponent(current$$1, workInProgress, type, nextProps, updateExpirationTime, renderExpirationTime); } var child = createFiberFromTypeAndProps(Component.type, null, nextProps, null, workInProgress.mode, renderExpirationTime); child.ref = workInProgress.ref; child.return = workInProgress; workInProgress.child = child; return child; } var currentChild = current$$1.child; // This is always exactly one child if (updateExpirationTime < renderExpirationTime) { // 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$$1.ref === workInProgress.ref) { return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); } } // React DevTools reads this flag. workInProgress.effectTag |= PerformedWork; var newChild = createWorkInProgress(currentChild, nextProps, renderExpirationTime); newChild.ref = workInProgress.ref; newChild.return = workInProgress; workInProgress.child = newChild; return newChild; } function updateSimpleMemoComponent(current$$1, workInProgress, Component, nextProps, updateExpirationTime, renderExpirationTime) { // 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$$1 !== null) { var prevProps = current$$1.memoizedProps; if (shallowEqual(prevProps, nextProps) && current$$1.ref === workInProgress.ref) { didReceiveUpdate = false; if (updateExpirationTime < renderExpirationTime) { return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); } } } return updateFunctionComponent(current$$1, workInProgress, Component, nextProps, renderExpirationTime); } function updateFragment(current$$1, workInProgress, renderExpirationTime) { var nextChildren = workInProgress.pendingProps; reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); return workInProgress.child; } function updateMode(current$$1, workInProgress, renderExpirationTime) { var nextChildren = workInProgress.pendingProps.children; reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); return workInProgress.child; } function updateProfiler(current$$1, workInProgress, renderExpirationTime) { if (enableProfilerTimer) { workInProgress.effectTag |= Update; } var nextProps = workInProgress.pendingProps; var nextChildren = nextProps.children; reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); return workInProgress.child; } function markRef(current$$1, workInProgress) { var ref = workInProgress.ref; if (current$$1 === null && ref !== null || current$$1 !== null && current$$1.ref !== ref) { // Schedule a Ref effect workInProgress.effectTag |= Ref; } } function updateFunctionComponent(current$$1, workInProgress, Component, nextProps, renderExpirationTime) { var unmaskedContext = getUnmaskedContext(workInProgress, Component, true); var context = getMaskedContext(workInProgress, unmaskedContext); var nextChildren = void 0; prepareToReadContext(workInProgress, renderExpirationTime); { nextChildren = renderWithHooks(current$$1, workInProgress, Component, nextProps, context, renderExpirationTime); } if (current$$1 !== null && !didReceiveUpdate) { bailoutHooks(current$$1, workInProgress, renderExpirationTime); return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); } // React DevTools reads this flag. workInProgress.effectTag |= PerformedWork; reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); return workInProgress.child; } function updateClassComponent(current$$1, workInProgress, Component, nextProps, renderExpirationTime) { var hasContext = void 0; if (isContextProvider(Component)) { hasContext = true; pushContextProvider(workInProgress); } else { hasContext = false; } prepareToReadContext(workInProgress, renderExpirationTime); var instance = workInProgress.stateNode; var shouldUpdate = void 0; if (instance === null) { if (current$$1 !== null) { // An class component without an instance only mounts if it suspended // inside a non- concurrent tree, in an inconsistent state. We want to // tree it like a new mount, even though an empty version of it already // committed. Disconnect the alternate pointers. current$$1.alternate = null; workInProgress.alternate = null; // Since this is conceptually a new fiber, schedule a Placement effect workInProgress.effectTag |= Placement; } // In the initial pass we might need to construct the instance. constructClassInstance(workInProgress, Component, nextProps, renderExpirationTime); mountClassInstance(workInProgress, Component, nextProps, renderExpirationTime); shouldUpdate = true; } else if (current$$1 === null) { // In a resume, we'll already have an instance we can reuse. shouldUpdate = resumeMountClassInstance(workInProgress, Component, nextProps, renderExpirationTime); } else { shouldUpdate = updateClassInstance(current$$1, workInProgress, Component, nextProps, renderExpirationTime); } var nextUnitOfWork = finishClassComponent(current$$1, workInProgress, Component, shouldUpdate, hasContext, renderExpirationTime); return nextUnitOfWork; } function finishClassComponent(current$$1, workInProgress, Component, shouldUpdate, hasContext, renderExpirationTime) { // Refs should update even if shouldComponentUpdate returns false markRef(current$$1, workInProgress); var didCaptureError = (workInProgress.effectTag & DidCapture) !== NoEffect; if (!shouldUpdate && !didCaptureError) { // Context providers should defer to sCU for rendering if (hasContext) { invalidateContextProvider(workInProgress, Component, false); } return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); } var instance = workInProgress.stateNode; // Rerender ReactCurrentOwner$2.current = workInProgress; var nextChildren = void 0; if (didCaptureError && typeof Component.getDerivedStateFromError !== 'function') { // If we captured an error, but getDerivedStateFrom catch is not defined, // unmount all the children. componentDidCatch will schedule an update to // re-render a fallback. This is temporary until we migrate everyone to // the new API. // TODO: Warn in a future release. nextChildren = null; if (enableProfilerTimer) { stopProfilerTimerIfRunning(workInProgress); } } else { { nextChildren = instance.render(); } } // React DevTools reads this flag. workInProgress.effectTag |= PerformedWork; if (current$$1 !== 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$$1, workInProgress, nextChildren, renderExpirationTime); } else { reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); } // Memoize state using the values we just used to render. // TODO: Restructure so we never read values from the instance. workInProgress.memoizedState = instance.state; // The context might have changed so we need to recalculate it. if (hasContext) { invalidateContextProvider(workInProgress, Component, true); } return workInProgress.child; } 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); } pushHostContainer(workInProgress, root.containerInfo); } function updateHostRoot(current$$1, workInProgress, renderExpirationTime) { pushHostRootContext(workInProgress); var updateQueue = workInProgress.updateQueue; !(updateQueue !== null) ? reactProdInvariant('282') : void 0; var nextProps = workInProgress.pendingProps; var prevState = workInProgress.memoizedState; var prevChildren = prevState !== null ? prevState.element : null; processUpdateQueue(workInProgress, updateQueue, nextProps, null, renderExpirationTime); var nextState = workInProgress.memoizedState; // Caution: React DevTools currently depends on this property // being called "element". var nextChildren = nextState.element; if (nextChildren === prevChildren) { // If the state is the same as before, that's a bailout because we had // no work that expires at this time. resetHydrationState(); return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); } var root = workInProgress.stateNode; if ((current$$1 === null || current$$1.child === null) && root.hydrate && enterHydrationState(workInProgress)) { // If we don't have any current children this might be the first pass. // We always try to hydrate. If this isn't a hydration pass there won't // be any children to hydrate which is effectively the same thing as // not hydrating. // This is a bit of a hack. We track the host root as a placement to // know that we're currently in a mounting state. That way isMounted // works as expected. We must reset this before committing. // TODO: Delete this when we delete isMounted and findDOMNode. workInProgress.effectTag |= Placement; // Ensure that children mount into this root without tracking // side-effects. This ensures that we don't store Placement effects on // nodes that will be hydrated. workInProgress.child = mountChildFibers(workInProgress, null, nextChildren, renderExpirationTime); } else { // Otherwise reset hydration state in case we aborted and resumed another // root. reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); resetHydrationState(); } return workInProgress.child; } function updateHostComponent(current$$1, workInProgress, renderExpirationTime) { pushHostContext(workInProgress); if (current$$1 === null) { tryToClaimNextHydratableInstance(workInProgress); } var type = workInProgress.type; var nextProps = workInProgress.pendingProps; var prevProps = current$$1 !== null ? current$$1.memoizedProps : null; var nextChildren = nextProps.children; var isDirectTextChild = shouldSetTextContent(type, nextProps); if (isDirectTextChild) { // We special case a direct text child of a host node. This is a common // case. We won't handle it as a reified child. We will instead handle // this in the host environment that also have access to this prop. That // avoids allocating another HostText fiber and traversing it. nextChildren = null; } else if (prevProps !== null && shouldSetTextContent(type, prevProps)) { // 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.effectTag |= ContentReset; } markRef(current$$1, workInProgress); // Check the host config to see if the children are offscreen/hidden. if (renderExpirationTime !== Never && workInProgress.mode & ConcurrentMode && shouldDeprioritizeSubtree(type, nextProps)) { // Schedule this fiber to re-render at offscreen priority. Then bailout. workInProgress.expirationTime = workInProgress.childExpirationTime = Never; return null; } reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); return workInProgress.child; } function updateHostText(current$$1, workInProgress) { if (current$$1 === null) { tryToClaimNextHydratableInstance(workInProgress); } // Nothing to do here. This is terminal. We'll do the completion step // immediately after. return null; } function mountLazyComponent(_current, workInProgress, elementType, updateExpirationTime, renderExpirationTime) { if (_current !== null) { // An 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.effectTag |= Placement; } var props = workInProgress.pendingProps; // We can't start a User Timing measurement with correct label yet. // Cancel and resume right after we know the tag. cancelWorkTimer(workInProgress); var Component = readLazyComponentType(elementType); // Store the unwrapped component in the type. workInProgress.type = Component; var resolvedTag = workInProgress.tag = resolveLazyComponentTag(Component); startWorkTimer(workInProgress); var resolvedProps = resolveDefaultProps(Component, props); var child = void 0; switch (resolvedTag) { case FunctionComponent: { child = updateFunctionComponent(null, workInProgress, Component, resolvedProps, renderExpirationTime); break; } case ClassComponent: { child = updateClassComponent(null, workInProgress, Component, resolvedProps, renderExpirationTime); break; } case ForwardRef: { child = updateForwardRef(null, workInProgress, Component, resolvedProps, renderExpirationTime); break; } case MemoComponent: { child = updateMemoComponent(null, workInProgress, Component, resolveDefaultProps(Component.type, resolvedProps), // The inner type can have defaults too updateExpirationTime, renderExpirationTime); break; } default: { var hint = ''; reactProdInvariant('306', Component, hint); } } return child; } function mountIncompleteClassComponent(_current, workInProgress, Component, nextProps, renderExpirationTime) { if (_current !== null) { // An incomplete 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.effectTag |= Placement; } // 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 = void 0; if (isContextProvider(Component)) { hasContext = true; pushContextProvider(workInProgress); } else { hasContext = false; } prepareToReadContext(workInProgress, renderExpirationTime); constructClassInstance(workInProgress, Component, nextProps, renderExpirationTime); mountClassInstance(workInProgress, Component, nextProps, renderExpirationTime); return finishClassComponent(null, workInProgress, Component, true, hasContext, renderExpirationTime); } function mountIndeterminateComponent(_current, workInProgress, Component, renderExpirationTime) { if (_current !== null) { // An indeterminate 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.effectTag |= Placement; } var props = workInProgress.pendingProps; var unmaskedContext = getUnmaskedContext(workInProgress, Component, false); var context = getMaskedContext(workInProgress, unmaskedContext); prepareToReadContext(workInProgress, renderExpirationTime); var value = void 0; { value = renderWithHooks(null, workInProgress, Component, props, context, renderExpirationTime); } // React DevTools reads this flag. workInProgress.effectTag |= PerformedWork; if (typeof value === 'object' && value !== null && typeof value.render === 'function' && value.$$typeof === undefined) { // Proceed under the assumption that this is a class instance workInProgress.tag = ClassComponent; // Throw out any hooks that were used. resetHooks(); // Push context providers early to prevent context stack mismatches. // During mounting we don't know the child context yet as the instance doesn't exist. // We will invalidate the child context in finishClassComponent() right after rendering. var hasContext = false; if (isContextProvider(Component)) { hasContext = true; pushContextProvider(workInProgress); } else { hasContext = false; } workInProgress.memoizedState = value.state !== null && value.state !== undefined ? value.state : null; var getDerivedStateFromProps = Component.getDerivedStateFromProps; if (typeof getDerivedStateFromProps === 'function') { applyDerivedStateFromProps(workInProgress, Component, getDerivedStateFromProps, props); } adoptClassInstance(workInProgress, value); mountClassInstance(workInProgress, Component, props, renderExpirationTime); return finishClassComponent(null, workInProgress, Component, true, hasContext, renderExpirationTime); } else { // Proceed under the assumption that this is a function component workInProgress.tag = FunctionComponent; reconcileChildren(null, workInProgress, value, renderExpirationTime); return workInProgress.child; } } function updateSuspenseComponent(current$$1, workInProgress, renderExpirationTime) { var mode = workInProgress.mode; var nextProps = workInProgress.pendingProps; // We should attempt to render the primary children unless this boundary // already suspended during this render (`alreadyCaptured` is true). var nextState = workInProgress.memoizedState; var nextDidTimeout = void 0; if ((workInProgress.effectTag & DidCapture) === NoEffect) { // This is the first attempt. nextState = null; nextDidTimeout = false; } else { // Something in this boundary's subtree already suspended. Switch to // rendering the fallback children. nextState = { timedOutAt: nextState !== null ? nextState.timedOutAt : NoWork }; nextDidTimeout = true; workInProgress.effectTag &= ~DidCapture; } // This next part is a bit confusing. If the children timeout, we switch to // showing the fallback children in place of the "primary" children. // However, we don't want to delete the primary children because then their // state will be lost (both the React state and the host state, e.g. // uncontrolled form inputs). Instead we keep them mounted and hide them. // Both the fallback children AND the primary children are rendered at the // same time. Once the primary children are un-suspended, we can delete // the fallback children — don't need to preserve their state. // // The two sets of children are siblings in the host environment, but // semantically, for purposes of reconciliation, they are two separate sets. // So we store them using two fragment fibers. // // However, we want to avoid allocating extra fibers for every placeholder. // They're only necessary when the children time out, because that's the // only time when both sets are mounted. // // So, the extra fragment fibers are only used if the children time out. // Otherwise, we render the primary children directly. This requires some // custom reconciliation logic to preserve the state of the primary // children. It's essentially a very basic form of re-parenting. // `child` points to the child fiber. In the normal case, this is the first // fiber of the primary children set. In the timed-out case, it's a // a fragment fiber containing the primary children. var child = void 0; // `next` points to the next fiber React should render. In the normal case, // it's the same as `child`: the first fiber of the primary children set. // In the timed-out case, it's a fragment fiber containing the *fallback* // children -- we skip over the primary children entirely. var next = void 0; if (current$$1 === null) { if (enableSuspenseServerRenderer) { // If we're currently hydrating, try to hydrate this boundary. // But only if this has a fallback. if (nextProps.fallback !== undefined) { tryToClaimNextHydratableInstance(workInProgress); // This could've changed the tag if this was a dehydrated suspense component. if (workInProgress.tag === DehydratedSuspenseComponent) { return updateDehydratedSuspenseComponent(null, workInProgress, renderExpirationTime); } } } // This is the initial mount. This branch is pretty simple because there's // no previous state that needs to be preserved. if (nextDidTimeout) { // Mount separate fragments for primary and fallback children. var nextFallbackChildren = nextProps.fallback; var primaryChildFragment = createFiberFromFragment(null, mode, NoWork, null); if ((workInProgress.mode & ConcurrentMode) === NoContext) { // Outside of concurrent mode, we commit the effects from the var progressedState = workInProgress.memoizedState; var progressedPrimaryChild = progressedState !== null ? workInProgress.child.child : workInProgress.child; primaryChildFragment.child = progressedPrimaryChild; } var fallbackChildFragment = createFiberFromFragment(nextFallbackChildren, mode, renderExpirationTime, null); primaryChildFragment.sibling = fallbackChildFragment; child = primaryChildFragment; // Skip the primary children, and continue working on the // fallback children. next = fallbackChildFragment; child.return = next.return = workInProgress; } else { // Mount the primary children without an intermediate fragment fiber. var nextPrimaryChildren = nextProps.children; child = next = mountChildFibers(workInProgress, null, nextPrimaryChildren, renderExpirationTime); } } else { // This is an update. This branch is more complicated because we need to // ensure the state of the primary children is preserved. var prevState = current$$1.memoizedState; var prevDidTimeout = prevState !== null; if (prevDidTimeout) { // The current tree already timed out. That means each child set is var currentPrimaryChildFragment = current$$1.child; var currentFallbackChildFragment = currentPrimaryChildFragment.sibling; if (nextDidTimeout) { // Still timed out. Reuse the current primary children by cloning // its fragment. We're going to skip over these entirely. var _nextFallbackChildren = nextProps.fallback; var _primaryChildFragment = createWorkInProgress(currentPrimaryChildFragment, currentPrimaryChildFragment.pendingProps, NoWork); if ((workInProgress.mode & ConcurrentMode) === NoContext) { // Outside of concurrent mode, we commit the effects from the var _progressedState = workInProgress.memoizedState; var _progressedPrimaryChild = _progressedState !== null ? workInProgress.child.child : workInProgress.child; if (_progressedPrimaryChild !== currentPrimaryChildFragment.child) { _primaryChildFragment.child = _progressedPrimaryChild; } } // Because primaryChildFragment is a new fiber that we're inserting as the // parent of a new tree, we need to set its treeBaseDuration. if (enableProfilerTimer && workInProgress.mode & ProfileMode) { // treeBaseDuration is the sum of all the child tree base durations. var treeBaseDuration = 0; var hiddenChild = _primaryChildFragment.child; while (hiddenChild !== null) { treeBaseDuration += hiddenChild.treeBaseDuration; hiddenChild = hiddenChild.sibling; } _primaryChildFragment.treeBaseDuration = treeBaseDuration; } // Clone the fallback child fragment, too. These we'll continue // working on. var _fallbackChildFragment = _primaryChildFragment.sibling = createWorkInProgress(currentFallbackChildFragment, _nextFallbackChildren, currentFallbackChildFragment.expirationTime); child = _primaryChildFragment; _primaryChildFragment.childExpirationTime = NoWork; // Skip the primary children, and continue working on the // fallback children. next = _fallbackChildFragment; child.return = next.return = workInProgress; } else { // No longer suspended. Switch back to showing the primary children, // and remove the intermediate fragment fiber. var _nextPrimaryChildren = nextProps.children; var currentPrimaryChild = currentPrimaryChildFragment.child; var primaryChild = reconcileChildFibers(workInProgress, currentPrimaryChild, _nextPrimaryChildren, renderExpirationTime); // If this render doesn't suspend, we need to delete the fallback // children. Wait until the complete phase, after we've confirmed the // fallback is no longer needed. // TODO: Would it be better to store the fallback fragment on // the stateNode? // Continue rendering the children, like we normally do. child = next = primaryChild; } } else { // The current tree has not already timed out. That means the primary // children are not wrapped in a fragment fiber. var _currentPrimaryChild = current$$1.child; if (nextDidTimeout) { // Timed out. Wrap the children in a fragment fiber to keep them // separate from the fallback children. var _nextFallbackChildren2 = nextProps.fallback; var _primaryChildFragment2 = createFiberFromFragment( // It shouldn't matter what the pending props are because we aren't // going to render this fragment. null, mode, NoWork, null); _primaryChildFragment2.child = _currentPrimaryChild; // Even though we're creating a new fiber, there are no new children, // because we're reusing an already mounted tree. So we don't need to // schedule a placement. // primaryChildFragment.effectTag |= Placement; if ((workInProgress.mode & ConcurrentMode) === NoContext) { // Outside of concurrent mode, we commit the effects from the var _progressedState2 = workInProgress.memoizedState; var _progressedPrimaryChild2 = _progressedState2 !== null ? workInProgress.child.child : workInProgress.child; _primaryChildFragment2.child = _progressedPrimaryChild2; } // Because primaryChildFragment is a new fiber that we're inserting as the // parent of a new tree, we need to set its treeBaseDuration. if (enableProfilerTimer && workInProgress.mode & ProfileMode) { // treeBaseDuration is the sum of all the child tree base durations. var _treeBaseDuration = 0; var _hiddenChild = _primaryChildFragment2.child; while (_hiddenChild !== null) { _treeBaseDuration += _hiddenChild.treeBaseDuration; _hiddenChild = _hiddenChild.sibling; } _primaryChildFragment2.treeBaseDuration = _treeBaseDuration; } // Create a fragment from the fallback children, too. var _fallbackChildFragment2 = _primaryChildFragment2.sibling = createFiberFromFragment(_nextFallbackChildren2, mode, renderExpirationTime, null); _fallbackChildFragment2.effectTag |= Placement; child = _primaryChildFragment2; _primaryChildFragment2.childExpirationTime = NoWork; // Skip the primary children, and continue working on the // fallback children. next = _fallbackChildFragment2; child.return = next.return = workInProgress; } else { // Still haven't timed out. Continue rendering the children, like we // normally do. var _nextPrimaryChildren2 = nextProps.children; next = child = reconcileChildFibers(workInProgress, _currentPrimaryChild, _nextPrimaryChildren2, renderExpirationTime); } } workInProgress.stateNode = current$$1.stateNode; } workInProgress.memoizedState = nextState; workInProgress.child = child; return next; } function updateDehydratedSuspenseComponent(current$$1, workInProgress, renderExpirationTime) { if (current$$1 === null) { // During the first pass, we'll bail out and not drill into the children. // Instead, we'll leave the content in place and try to hydrate it later. workInProgress.expirationTime = Never; return null; } // We use childExpirationTime to indicate that a child might depend on context, so if // any context has changed, we need to treat is as if the input might have changed. var hasContextChanged$$1 = current$$1.childExpirationTime >= renderExpirationTime; if (didReceiveUpdate || hasContextChanged$$1) { // 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 an earlier expiration time but // during this render we can't. Instead, we're going to delete the whole subtree and // instead inject a new real Suspense boundary to take its place, which may render content // or fallback. The real Suspense boundary will suspend for a while so we have some time // to ensure it can produce real content, but all state and pending events will be lost. // Detach from the current dehydrated boundary. current$$1.alternate = null; workInProgress.alternate = null; // Insert a deletion in the effect list. var returnFiber = workInProgress.return; !(returnFiber !== null) ? reactProdInvariant('315') : void 0; var last = returnFiber.lastEffect; if (last !== null) { last.nextEffect = current$$1; returnFiber.lastEffect = current$$1; } else { returnFiber.firstEffect = returnFiber.lastEffect = current$$1; } current$$1.nextEffect = null; current$$1.effectTag = Deletion; // Upgrade this work in progress to a real Suspense component. workInProgress.tag = SuspenseComponent; workInProgress.stateNode = null; workInProgress.memoizedState = null; // This is now an insertion. workInProgress.effectTag |= Placement; // Retry as a real Suspense component. return updateSuspenseComponent(null, workInProgress, renderExpirationTime); } if ((workInProgress.effectTag & DidCapture) === NoEffect) { // This is the first attempt. reenterHydrationStateFromDehydratedSuspenseInstance(workInProgress); var nextProps = workInProgress.pendingProps; var nextChildren = nextProps.children; workInProgress.child = mountChildFibers(workInProgress, null, nextChildren, renderExpirationTime); return workInProgress.child; } else { // Something suspended. Leave the existing children in place. // TODO: In non-concurrent mode, should we commit the nodes we have hydrated so far? workInProgress.child = null; return null; } } function updatePortalComponent(current$$1, workInProgress, renderExpirationTime) { pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); var nextChildren = workInProgress.pendingProps; if (current$$1 === 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, renderExpirationTime); } else { reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); } return workInProgress.child; } function updateContextProvider(current$$1, workInProgress, renderExpirationTime) { var providerType = workInProgress.type; var context = providerType._context; var newProps = workInProgress.pendingProps; var oldProps = workInProgress.memoizedProps; var newValue = newProps.value; pushProvider(workInProgress, newValue); if (oldProps !== null) { var oldValue = oldProps.value; var changedBits = calculateChangedBits(context, newValue, oldValue); if (changedBits === 0) { // No change. Bailout early if children are the same. if (oldProps.children === newProps.children && !hasContextChanged()) { return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); } } else { // The context value changed. Search for matching consumers and schedule // them to update. propagateContextChange(workInProgress, context, changedBits, renderExpirationTime); } } var newChildren = newProps.children; reconcileChildren(current$$1, workInProgress, newChildren, renderExpirationTime); return workInProgress.child; } function updateContextConsumer(current$$1, workInProgress, renderExpirationTime) { var context = workInProgress.type; // The logic below for Context differs depending on PROD or DEV mode. In // DEV mode, we create a separate object for Context.Consumer that acts // like a proxy to Context. This proxy object adds unnecessary code in PROD // so we use the old behaviour (Context.Consumer references Context) to // reduce size and overhead. The separate object references context via // a property called "_context", which also gives us the ability to check // in DEV mode if this property exists or not and warn if it does not. var newProps = workInProgress.pendingProps; var render = newProps.children; prepareToReadContext(workInProgress, renderExpirationTime); var newValue = readContext(context, newProps.unstable_observedBits); var newChildren = void 0; { newChildren = render(newValue); } // React DevTools reads this flag. workInProgress.effectTag |= PerformedWork; reconcileChildren(current$$1, workInProgress, newChildren, renderExpirationTime); return workInProgress.child; } function markWorkInProgressReceivedUpdate() { didReceiveUpdate = true; } function bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime) { cancelWorkTimer(workInProgress); if (current$$1 !== null) { // Reuse previous context list workInProgress.contextDependencies = current$$1.contextDependencies; } if (enableProfilerTimer) { // Don't update "base" render times for bailouts. stopProfilerTimerIfRunning(workInProgress); } // Check if the children have any pending work. var childExpirationTime = workInProgress.childExpirationTime; if (childExpirationTime < renderExpirationTime) { // 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; } else { // This fiber doesn't have work, but its subtree does. Clone the child // fibers and continue. cloneChildFibers(current$$1, workInProgress); return workInProgress.child; } } function beginWork(current$$1, workInProgress, renderExpirationTime) { var updateExpirationTime = workInProgress.expirationTime; if (current$$1 !== null) { var oldProps = current$$1.memoizedProps; var newProps = workInProgress.pendingProps; if (oldProps !== newProps || hasContextChanged()) { // 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 if (updateExpirationTime < renderExpirationTime) { didReceiveUpdate = false; // 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); resetHydrationState(); break; case HostComponent: pushHostContext(workInProgress); break; case ClassComponent: { var Component = workInProgress.type; if (isContextProvider(Component)) { pushContextProvider(workInProgress); } break; } case HostPortal: pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); break; case ContextProvider: { var newValue = workInProgress.memoizedProps.value; pushProvider(workInProgress, newValue); break; } case Profiler: if (enableProfilerTimer) { workInProgress.effectTag |= Update; } break; case SuspenseComponent: { var state = workInProgress.memoizedState; var didTimeout = state !== null; if (didTimeout) { // 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 var primaryChildFragment = workInProgress.child; var primaryChildExpirationTime = primaryChildFragment.childExpirationTime; if (primaryChildExpirationTime !== NoWork && primaryChildExpirationTime >= renderExpirationTime) { // The primary children have pending work. Use the normal path // to attempt to render the primary children again. return updateSuspenseComponent(current$$1, workInProgress, renderExpirationTime); } else { // The primary children do not have pending work with sufficient // priority. Bailout. var child = bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); if (child !== null) { // The fallback children have pending work. Skip over the // primary children and work on the fallback. return child.sibling; } else { return null; } } } break; } case DehydratedSuspenseComponent: { if (enableSuspenseServerRenderer) { // We know that this component will suspend again because if it has // been unsuspended it has committed as a regular Suspense component. // If it needs to be retried, it should have work scheduled on it. workInProgress.effectTag |= DidCapture; break; } } } return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); } } else { didReceiveUpdate = false; } // Before entering the begin phase, clear the expiration time. workInProgress.expirationTime = NoWork; switch (workInProgress.tag) { case IndeterminateComponent: { var elementType = workInProgress.elementType; return mountIndeterminateComponent(current$$1, workInProgress, elementType, renderExpirationTime); } case LazyComponent: { var _elementType = workInProgress.elementType; return mountLazyComponent(current$$1, workInProgress, _elementType, updateExpirationTime, renderExpirationTime); } case FunctionComponent: { var _Component = workInProgress.type; var unresolvedProps = workInProgress.pendingProps; var resolvedProps = workInProgress.elementType === _Component ? unresolvedProps : resolveDefaultProps(_Component, unresolvedProps); return updateFunctionComponent(current$$1, workInProgress, _Component, resolvedProps, renderExpirationTime); } case ClassComponent: { var _Component2 = workInProgress.type; var _unresolvedProps = workInProgress.pendingProps; var _resolvedProps = workInProgress.elementType === _Component2 ? _unresolvedProps : resolveDefaultProps(_Component2, _unresolvedProps); return updateClassComponent(current$$1, workInProgress, _Component2, _resolvedProps, renderExpirationTime); } case HostRoot: return updateHostRoot(current$$1, workInProgress, renderExpirationTime); case HostComponent: return updateHostComponent(current$$1, workInProgress, renderExpirationTime); case HostText: return updateHostText(current$$1, workInProgress); case SuspenseComponent: return updateSuspenseComponent(current$$1, workInProgress, renderExpirationTime); case HostPortal: return updatePortalComponent(current$$1, workInProgress, renderExpirationTime); case ForwardRef: { var type = workInProgress.type; var _unresolvedProps2 = workInProgress.pendingProps; var _resolvedProps2 = workInProgress.elementType === type ? _unresolvedProps2 : resolveDefaultProps(type, _unresolvedProps2); return updateForwardRef(current$$1, workInProgress, type, _resolvedProps2, renderExpirationTime); } case Fragment: return updateFragment(current$$1, workInProgress, renderExpirationTime); case Mode: return updateMode(current$$1, workInProgress, renderExpirationTime); case Profiler: return updateProfiler(current$$1, workInProgress, renderExpirationTime); case ContextProvider: return updateContextProvider(current$$1, workInProgress, renderExpirationTime); case ContextConsumer: return updateContextConsumer(current$$1, workInProgress, renderExpirationTime); case MemoComponent: { var _type2 = workInProgress.type; var _unresolvedProps3 = workInProgress.pendingProps; // Resolve outer props first, then resolve inner props. var _resolvedProps3 = resolveDefaultProps(_type2, _unresolvedProps3); _resolvedProps3 = resolveDefaultProps(_type2.type, _resolvedProps3); return updateMemoComponent(current$$1, workInProgress, _type2, _resolvedProps3, updateExpirationTime, renderExpirationTime); } case SimpleMemoComponent: { return updateSimpleMemoComponent(current$$1, workInProgress, workInProgress.type, workInProgress.pendingProps, updateExpirationTime, renderExpirationTime); } case IncompleteClassComponent: { var _Component3 = workInProgress.type; var _unresolvedProps4 = workInProgress.pendingProps; var _resolvedProps4 = workInProgress.elementType === _Component3 ? _unresolvedProps4 : resolveDefaultProps(_Component3, _unresolvedProps4); return mountIncompleteClassComponent(current$$1, workInProgress, _Component3, _resolvedProps4, renderExpirationTime); } case DehydratedSuspenseComponent: { if (enableSuspenseServerRenderer) { return updateDehydratedSuspenseComponent(current$$1, workInProgress, renderExpirationTime); } break; } } reactProdInvariant('156'); } var valueCursor = createCursor(null); var currentlyRenderingFiber = null; var lastContextDependency = null; var lastContextWithAllBitsObserved = null; function resetContextDependences() { // This is called right before React yields execution, to ensure `readContext` // cannot be called outside the render phase. currentlyRenderingFiber = null; lastContextDependency = null; lastContextWithAllBitsObserved = null; } function pushProvider(providerFiber, nextValue) { var context = providerFiber.type._context; if (isPrimaryRenderer) { push(valueCursor, context._currentValue, providerFiber); context._currentValue = nextValue; } else { push(valueCursor, context._currentValue2, providerFiber); context._currentValue2 = nextValue; } } function popProvider(providerFiber) { var currentValue = valueCursor.current; pop(valueCursor, providerFiber); var context = providerFiber.type._context; if (isPrimaryRenderer) { context._currentValue = currentValue; } else { context._currentValue2 = currentValue; } } function calculateChangedBits(context, newValue, oldValue) { if (is(oldValue, newValue)) { // No change return 0; } else { var changedBits = typeof context._calculateChangedBits === 'function' ? context._calculateChangedBits(oldValue, newValue) : maxSigned31BitInt; return changedBits | 0; } } function scheduleWorkOnParentPath(parent, renderExpirationTime) { // Update the child expiration time of all the ancestors, including // the alternates. var node = parent; while (node !== null) { var alternate = node.alternate; if (node.childExpirationTime < renderExpirationTime) { node.childExpirationTime = renderExpirationTime; if (alternate !== null && alternate.childExpirationTime < renderExpirationTime) { alternate.childExpirationTime = renderExpirationTime; } } else if (alternate !== null && alternate.childExpirationTime < renderExpirationTime) { alternate.childExpirationTime = renderExpirationTime; } else { // Neither alternate was updated, which means the rest of the // ancestor path already has sufficient priority. break; } node = node.return; } } function propagateContextChange(workInProgress, context, changedBits, renderExpirationTime) { var fiber = workInProgress.child; 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.contextDependencies; if (list !== null) { nextFiber = fiber.child; var dependency = list.first; while (dependency !== null) { // Check if the context matches. if (dependency.context === context && (dependency.observedBits & changedBits) !== 0) { // Match! Schedule an update on this fiber. if (fiber.tag === ClassComponent) { // Schedule a force update on the work-in-progress. var update = createUpdate(renderExpirationTime); 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. enqueueUpdate(fiber, update); } if (fiber.expirationTime < renderExpirationTime) { fiber.expirationTime = renderExpirationTime; } var alternate = fiber.alternate; if (alternate !== null && alternate.expirationTime < renderExpirationTime) { alternate.expirationTime = renderExpirationTime; } scheduleWorkOnParentPath(fiber.return, renderExpirationTime); // Mark the expiration time on the list, too. if (list.expirationTime < renderExpirationTime) { list.expirationTime = renderExpirationTime; } // Since we already found a match, we can stop traversing the // dependency 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 (enableSuspenseServerRenderer && fiber.tag === DehydratedSuspenseComponent) { // If a dehydrated suspense component 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 on its children. if (fiber.expirationTime < renderExpirationTime) { fiber.expirationTime = renderExpirationTime; } var _alternate = fiber.alternate; if (_alternate !== null && _alternate.expirationTime < renderExpirationTime) { _alternate.expirationTime = renderExpirationTime; } // 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 childExpirationTime on // this fiber to indicate that a context has changed. scheduleWorkOnParentPath(fiber, renderExpirationTime); 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; while (nextFiber !== null) { if (nextFiber === workInProgress) { // We're back to the root of this subtree. Exit. nextFiber = null; break; } var sibling = nextFiber.sibling; if (sibling !== null) { // Set the return pointer of the sibling to the work-in-progress fiber. sibling.return = nextFiber.return; nextFiber = sibling; break; } // No more siblings. Traverse up. nextFiber = nextFiber.return; } } fiber = nextFiber; } } function prepareToReadContext(workInProgress, renderExpirationTime) { currentlyRenderingFiber = workInProgress; lastContextDependency = null; lastContextWithAllBitsObserved = null; var currentDependencies = workInProgress.contextDependencies; if (currentDependencies !== null && currentDependencies.expirationTime >= renderExpirationTime) { // Context list has a pending update. Mark that this fiber performed work. markWorkInProgressReceivedUpdate(); } // Reset the work-in-progress list workInProgress.contextDependencies = null; } function readContext(context, observedBits) { if (lastContextWithAllBitsObserved === context) { // Nothing to do. We already observe everything in this context. } else if (observedBits === false || observedBits === 0) { // Do not observe any updates. } else { var resolvedObservedBits = void 0; // Avoid deopting on observable arguments or heterogeneous types. if (typeof observedBits !== 'number' || observedBits === maxSigned31BitInt) { // Observe all updates. lastContextWithAllBitsObserved = context; resolvedObservedBits = maxSigned31BitInt; } else { resolvedObservedBits = observedBits; } var contextItem = { context: context, observedBits: resolvedObservedBits, next: null }; if (lastContextDependency === null) { !(currentlyRenderingFiber !== null) ? reactProdInvariant('308') : void 0; // This is the first dependency for this component. Create a new list. lastContextDependency = contextItem; currentlyRenderingFiber.contextDependencies = { first: contextItem, expirationTime: NoWork }; } else { // Append a new context item. lastContextDependency = lastContextDependency.next = contextItem; } } return isPrimaryRenderer ? context._currentValue : context._currentValue2; } // UpdateQueue is a linked list of prioritized updates. // // Like fibers, update queues come in pairs: a current queue, which represents // the visible state of the screen, and a work-in-progress queue, which can be // mutated and processed asynchronously before it is committed — a form of // double buffering. If a work-in-progress render is discarded before finishing, // we create a new work-in-progress by cloning the current queue. // // Both queues share a persistent, singly-linked list structure. To schedule an // update, we append it to the end of both queues. Each queue maintains a // pointer to first update in the persistent list that hasn't been processed. // The work-in-progress pointer always has a position equal to or greater than // the current queue, since we always work on that one. The current queue's // pointer is only updated during the commit phase, when we swap in the // work-in-progress. // // For example: // // Current pointer: A - B - C - D - E - F // Work-in-progress pointer: D - E - F // ^ // The work-in-progress queue has // processed more updates than current. // // The reason we append to both queues is because otherwise we might drop // updates without ever processing them. For example, if we only add updates to // the work-in-progress queue, some updates could be lost whenever a work-in // -progress render restarts by cloning from current. Similarly, if we only add // updates to the current queue, the updates will be lost whenever an already // in-progress queue commits and swaps with the current queue. However, by // adding to both queues, we guarantee that the update will be part of the next // work-in-progress. (And because the work-in-progress queue becomes the // current queue once it commits, there's no danger of applying the same // update twice.) // // Prioritization // -------------- // // Updates are not sorted by priority, but by insertion; new updates are always // appended to the end of the list. // // The priority is still important, though. When processing the update queue // during the render phase, only the updates with sufficient priority are // included in the result. If we skip an update because it has insufficient // priority, it remains in the queue to be processed later, during a lower // priority render. Crucially, all updates subsequent to a skipped update also // remain in the queue *regardless of their priority*. That means high priority // updates are sometimes processed twice, at two separate priorities. We also // keep track of a base state, that represents the state before the first // update in the queue is applied. // // For example: // // Given a base state of '', and the following queue of updates // // A1 - B2 - C1 - D2 // // where the number indicates the priority, and the update is applied to the // previous state by appending a letter, React will process these updates as // two separate renders, one per distinct priority level: // // First render, at priority 1: // Base state: '' // Updates: [A1, C1] // Result state: 'AC' // // Second render, at priority 2: // Base state: 'A' <- The base state does not include C1, // because B2 was skipped. // Updates: [B2, C1, D2] <- C1 was rebased on top of B2 // Result state: 'ABCD' // // Because we process updates in insertion order, and rebase high priority // updates when preceding updates are skipped, the final result is deterministic // regardless of priority. Intermediate state may vary according to system // resources, but the final state is always the same. 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; function createUpdateQueue(baseState) { var queue = { baseState: baseState, firstUpdate: null, lastUpdate: null, firstCapturedUpdate: null, lastCapturedUpdate: null, firstEffect: null, lastEffect: null, firstCapturedEffect: null, lastCapturedEffect: null }; return queue; } function cloneUpdateQueue(currentQueue) { var queue = { baseState: currentQueue.baseState, firstUpdate: currentQueue.firstUpdate, lastUpdate: currentQueue.lastUpdate, // TODO: With resuming, if we bail out and resuse the child tree, we should // keep these effects. firstCapturedUpdate: null, lastCapturedUpdate: null, firstEffect: null, lastEffect: null, firstCapturedEffect: null, lastCapturedEffect: null }; return queue; } function createUpdate(expirationTime) { return { expirationTime: expirationTime, tag: UpdateState, payload: null, callback: null, next: null, nextEffect: null }; } function appendUpdateToQueue(queue, update) { // Append the update to the end of the list. if (queue.lastUpdate === null) { // Queue is empty queue.firstUpdate = queue.lastUpdate = update; } else { queue.lastUpdate.next = update; queue.lastUpdate = update; } } function enqueueUpdate(fiber, update) { // Update queues are created lazily. var alternate = fiber.alternate; var queue1 = void 0; var queue2 = void 0; if (alternate === null) { // There's only one fiber. queue1 = fiber.updateQueue; queue2 = null; if (queue1 === null) { queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState); } } else { // There are two owners. queue1 = fiber.updateQueue; queue2 = alternate.updateQueue; if (queue1 === null) { if (queue2 === null) { // Neither fiber has an update queue. Create new ones. queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState); queue2 = alternate.updateQueue = createUpdateQueue(alternate.memoizedState); } else { // Only one fiber has an update queue. Clone to create a new one. queue1 = fiber.updateQueue = cloneUpdateQueue(queue2); } } else { if (queue2 === null) { // Only one fiber has an update queue. Clone to create a new one. queue2 = alternate.updateQueue = cloneUpdateQueue(queue1); } else { // Both owners have an update queue. } } } if (queue2 === null || queue1 === queue2) { // There's only a single queue. appendUpdateToQueue(queue1, update); } else { // There are two queues. We need to append the update to both queues, // while accounting for the persistent structure of the list — we don't // want the same update to be added multiple times. if (queue1.lastUpdate === null || queue2.lastUpdate === null) { // One of the queues is not empty. We must add the update to both queues. appendUpdateToQueue(queue1, update); appendUpdateToQueue(queue2, update); } else { // Both queues are non-empty. The last update is the same in both lists, // because of structural sharing. So, only append to one of the lists. appendUpdateToQueue(queue1, update); // But we still need to update the `lastUpdate` pointer of queue2. queue2.lastUpdate = update; } } } function enqueueCapturedUpdate(workInProgress, update) { // Captured updates go into a separate list, and only on the work-in- // progress queue. var workInProgressQueue = workInProgress.updateQueue; if (workInProgressQueue === null) { workInProgressQueue = workInProgress.updateQueue = createUpdateQueue(workInProgress.memoizedState); } else { // TODO: I put this here rather than createWorkInProgress so that we don't // clone the queue unnecessarily. There's probably a better way to // structure this. workInProgressQueue = ensureWorkInProgressQueueIsAClone(workInProgress, workInProgressQueue); } // Append the update to the end of the list. if (workInProgressQueue.lastCapturedUpdate === null) { // This is the first render phase update workInProgressQueue.firstCapturedUpdate = workInProgressQueue.lastCapturedUpdate = update; } else { workInProgressQueue.lastCapturedUpdate.next = update; workInProgressQueue.lastCapturedUpdate = update; } } function ensureWorkInProgressQueueIsAClone(workInProgress, queue) { var current = workInProgress.alternate; if (current !== null) { // If the work-in-progress queue is equal to the current queue, // we need to clone it first. if (queue === current.updateQueue) { queue = workInProgress.updateQueue = cloneUpdateQueue(queue); } } return queue; } function getStateFromUpdate(workInProgress, queue, update, prevState, nextProps, instance) { switch (update.tag) { case ReplaceState: { var _payload = update.payload; if (typeof _payload === 'function') { // Updater function var nextState = _payload.call(instance, prevState, nextProps); return nextState; } // State object return _payload; } case CaptureUpdate: { workInProgress.effectTag = workInProgress.effectTag & ~ShouldCapture | DidCapture; } // Intentional fallthrough case UpdateState: { var _payload2 = update.payload; var partialState = void 0; if (typeof _payload2 === 'function') { // Updater function partialState = _payload2.call(instance, prevState, nextProps); } else { // Partial state object partialState = _payload2; } if (partialState === null || partialState === undefined) { // Null and undefined are treated as no-ops. return prevState; } // Merge the partial state and the previous state. return _assign({}, prevState, partialState); } case ForceUpdate: { hasForceUpdate = true; return prevState; } } return prevState; } function processUpdateQueue(workInProgress, queue, props, instance, renderExpirationTime) { hasForceUpdate = false; queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue); var newBaseState = queue.baseState; var newFirstUpdate = null; var newExpirationTime = NoWork; // Iterate through the list of updates to compute the result. var update = queue.firstUpdate; var resultState = newBaseState; while (update !== null) { var updateExpirationTime = update.expirationTime; if (updateExpirationTime < renderExpirationTime) { // This update does not have sufficient priority. Skip it. if (newFirstUpdate === null) { // This is the first skipped update. It will be the first update in // the new list. newFirstUpdate = update; // Since this is the first update that was skipped, the current result // is the new base state. newBaseState = resultState; } // Since this update will remain in the list, update the remaining // expiration time. if (newExpirationTime < updateExpirationTime) { newExpirationTime = updateExpirationTime; } } else { // This update does have sufficient priority. Process it and compute // a new result. resultState = getStateFromUpdate(workInProgress, queue, update, resultState, props, instance); var _callback = update.callback; if (_callback !== null) { workInProgress.effectTag |= Callback; // Set this to null, in case it was mutated during an aborted render. update.nextEffect = null; if (queue.lastEffect === null) { queue.firstEffect = queue.lastEffect = update; } else { queue.lastEffect.nextEffect = update; queue.lastEffect = update; } } } // Continue to the next update. update = update.next; } // Separately, iterate though the list of captured updates. var newFirstCapturedUpdate = null; update = queue.firstCapturedUpdate; while (update !== null) { var _updateExpirationTime = update.expirationTime; if (_updateExpirationTime < renderExpirationTime) { // This update does not have sufficient priority. Skip it. if (newFirstCapturedUpdate === null) { // This is the first skipped captured update. It will be the first // update in the new list. newFirstCapturedUpdate = update; // If this is the first update that was skipped, the current result is // the new base state. if (newFirstUpdate === null) { newBaseState = resultState; } } // Since this update will remain in the list, update the remaining // expiration time. if (newExpirationTime < _updateExpirationTime) { newExpirationTime = _updateExpirationTime; } } else { // This update does have sufficient priority. Process it and compute // a new result. resultState = getStateFromUpdate(workInProgress, queue, update, resultState, props, instance); var _callback2 = update.callback; if (_callback2 !== null) { workInProgress.effectTag |= Callback; // Set this to null, in case it was mutated during an aborted render. update.nextEffect = null; if (queue.lastCapturedEffect === null) { queue.firstCapturedEffect = queue.lastCapturedEffect = update; } else { queue.lastCapturedEffect.nextEffect = update; queue.lastCapturedEffect = update; } } } update = update.next; } if (newFirstUpdate === null) { queue.lastUpdate = null; } if (newFirstCapturedUpdate === null) { queue.lastCapturedUpdate = null; } else { workInProgress.effectTag |= Callback; } if (newFirstUpdate === null && newFirstCapturedUpdate === null) { // We processed every update, without skipping. That means the new base // state is the same as the result state. newBaseState = resultState; } queue.baseState = newBaseState; queue.firstUpdate = newFirstUpdate; queue.firstCapturedUpdate = newFirstCapturedUpdate; // 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. workInProgress.expirationTime = newExpirationTime; workInProgress.memoizedState = resultState; } function callCallback(callback, context) { !(typeof callback === 'function') ? reactProdInvariant('191', callback) : void 0; callback.call(context); } function resetHasForceUpdateBeforeProcessing() { hasForceUpdate = false; } function checkHasForceUpdateAfterProcessing() { return hasForceUpdate; } function commitUpdateQueue(finishedWork, finishedQueue, instance, renderExpirationTime) { // If the finished render included captured updates, and there are still // lower priority updates left over, we need to keep the captured updates // in the queue so that they are rebased and not dropped once we process the // queue again at the lower priority. if (finishedQueue.firstCapturedUpdate !== null) { // Join the captured update list to the end of the normal list. if (finishedQueue.lastUpdate !== null) { finishedQueue.lastUpdate.next = finishedQueue.firstCapturedUpdate; finishedQueue.lastUpdate = finishedQueue.lastCapturedUpdate; } // Clear the list of captured updates. finishedQueue.firstCapturedUpdate = finishedQueue.lastCapturedUpdate = null; } // Commit the effects commitUpdateEffects(finishedQueue.firstEffect, instance); finishedQueue.firstEffect = finishedQueue.lastEffect = null; commitUpdateEffects(finishedQueue.firstCapturedEffect, instance); finishedQueue.firstCapturedEffect = finishedQueue.lastCapturedEffect = null; } function commitUpdateEffects(effect, instance) { while (effect !== null) { var _callback3 = effect.callback; if (_callback3 !== null) { effect.callback = null; callCallback(_callback3, instance); } effect = effect.nextEffect; } } function createCapturedValue(value, source) { // If the value is an error, call this function immediately after it is thrown // so the stack is accurate. return { value: value, source: source, stack: getStackByFiberInDevAndProd(source) }; } function markUpdate(workInProgress) { // Tag the fiber with an update effect. This turns a Placement into // a PlacementAndUpdate. workInProgress.effectTag |= Update; } function markRef$1(workInProgress) { workInProgress.effectTag |= Ref; } var appendAllChildren = void 0; var updateHostContainer = void 0; var updateHostComponent$1 = void 0; var updateHostText$1 = void 0; if (supportsMutation) { // Mutation mode appendAllChildren = function (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) { // If we have a portal child, then we don't want to traverse // down its children. Instead, we'll get insertions from each child in // the portal directly. } else if (node.child !== null) { node.child.return = node; node = node.child; continue; } if (node === workInProgress) { return; } while (node.sibling === null) { if (node.return === null || node.return === workInProgress) { return; } node = node.return; } node.sibling.return = node.return; node = node.sibling; } }; updateHostContainer = function (workInProgress) { // Noop }; updateHostComponent$1 = function (current, workInProgress, type, newProps, rootContainerInstance) { // 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; } // If we get updated because one of our children updated, we don't // have newProps so we'll have to reuse them. // TODO: Split the update API as separate for the props vs. children. // Even better would be if children weren't special cased at all tho. var instance = workInProgress.stateNode; var currentHostContext = getHostContext(); // TODO: Experiencing an error where oldProps is null. Suggests a host // component is hitting the resume path. Figure out why. Possibly // related to `hidden`. var updatePayload = prepareUpdate(instance, type, oldProps, newProps, rootContainerInstance, currentHostContext); // TODO: Type this specific to this type of component. workInProgress.updateQueue = updatePayload; // If the update payload indicates that there is a change or if there // is a new ref we mark this as an update. All the work is done in commitWork. if (updatePayload) { markUpdate(workInProgress); } }; updateHostText$1 = function (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); } }; } else if (supportsPersistence) { // Persistent host tree mode appendAllChildren = function (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) { // eslint-disable-next-line no-labels branches: if (node.tag === HostComponent) { var instance = node.stateNode; if (needsVisibilityToggle) { var props = node.memoizedProps; var type = node.type; if (isHidden) { // This child is inside a timed out tree. Hide it. instance = cloneHiddenInstance(instance, type, props, node); } else { // This child was previously inside a timed out tree. If it was not // updated during this render, it may need to be unhidden. Clone // again to be sure. instance = cloneUnhiddenInstance(instance, type, props, node); } node.stateNode = instance; } appendInitialChild(parent, instance); } else if (node.tag === HostText) { var _instance = node.stateNode; if (needsVisibilityToggle) { var text = node.memoizedProps; var rootContainerInstance = getRootHostContainer(); var currentHostContext = getHostContext(); if (isHidden) { _instance = createHiddenTextInstance(text, rootContainerInstance, currentHostContext, workInProgress); } else { _instance = createTextInstance(text, rootContainerInstance, currentHostContext, workInProgress); } node.stateNode = _instance; } appendInitialChild(parent, _instance); } else if (node.tag === HostPortal) { // If we have a portal child, then we don't want to traverse // down its children. Instead, we'll get insertions from each child in // the portal directly. } else if (node.tag === SuspenseComponent) { var current = node.alternate; if (current !== null) { var oldState = current.memoizedState; var newState = node.memoizedState; var oldIsHidden = oldState !== null; var newIsHidden = newState !== null; if (oldIsHidden !== newIsHidden) { // The placeholder either just timed out or switched back to the normal // children after having previously timed out. Toggle the visibility of // the direct host children. var primaryChildParent = newIsHidden ? node.child : node; if (primaryChildParent !== null) { appendAllChildren(parent, primaryChildParent, true, newIsHidden); } // eslint-disable-next-line no-labels break branches; } } if (node.child !== null) { // Continue traversing like normal node.child.return = node; node = node.child; continue; } } else if (node.child !== null) { node.child.return = node; node = node.child; continue; } // $FlowFixMe This is correct but Flow is confused by the labeled break. node = node; if (node === workInProgress) { return; } while (node.sibling === null) { if (node.return === null || node.return === workInProgress) { return; } node = node.return; } node.sibling.return = node.return; node = node.sibling; } }; // An unfortunate fork of appendAllChildren because we have two different parent types. var appendAllChildrenToContainer = function (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; while (node !== null) { // eslint-disable-next-line no-labels branches: if (node.tag === HostComponent) { var instance = node.stateNode; if (needsVisibilityToggle) { var props = node.memoizedProps; var type = node.type; if (isHidden) { // This child is inside a timed out tree. Hide it. instance = cloneHiddenInstance(instance, type, props, node); } else { // This child was previously inside a timed out tree. If it was not // updated during this render, it may need to be unhidden. Clone // again to be sure. instance = cloneUnhiddenInstance(instance, type, props, node); } node.stateNode = instance; } appendChildToContainerChildSet(containerChildSet, instance); } else if (node.tag === HostText) { var _instance2 = node.stateNode; if (needsVisibilityToggle) { var text = node.memoizedProps; var rootContainerInstance = getRootHostContainer(); var currentHostContext = getHostContext(); if (isHidden) { _instance2 = createHiddenTextInstance(text, rootContainerInstance, currentHostContext, workInProgress); } else { _instance2 = createTextInstance(text, rootContainerInstance, currentHostContext, workInProgress); } node.stateNode = _instance2; } appendChildToContainerChildSet(containerChildSet, _instance2); } else if (node.tag === HostPortal) { // If we have a portal child, then we don't want to traverse // down its children. Instead, we'll get insertions from each child in // the portal directly. } else if (node.tag === SuspenseComponent) { var current = node.alternate; if (current !== null) { var oldState = current.memoizedState; var newState = node.memoizedState; var oldIsHidden = oldState !== null; var newIsHidden = newState !== null; if (oldIsHidden !== newIsHidden) { // The placeholder either just timed out or switched back to the normal // children after having previously timed out. Toggle the visibility of // the direct host children. var primaryChildParent = newIsHidden ? node.child : node; if (primaryChildParent !== null) { appendAllChildrenToContainer(containerChildSet, primaryChildParent, true, newIsHidden); } // eslint-disable-next-line no-labels break branches; } } if (node.child !== null) { // Continue traversing like normal node.child.return = node; node = node.child; continue; } } else if (node.child !== null) { node.child.return = node; node = node.child; continue; } // $FlowFixMe This is correct but Flow is confused by the labeled break. node = node; if (node === workInProgress) { return; } while (node.sibling === null) { if (node.return === null || node.return === workInProgress) { return; } node = node.return; } node.sibling.return = node.return; node = node.sibling; } }; updateHostContainer = function (workInProgress) { var portalOrRoot = workInProgress.stateNode; var childrenUnchanged = workInProgress.firstEffect === null; if (childrenUnchanged) { // No changes, just reuse the existing instance. } else { var container = portalOrRoot.containerInfo; var newChildSet = createContainerChildSet(container); // If children might have changed, we have to add them all to the set. appendAllChildrenToContainer(newChildSet, workInProgress, false, false); portalOrRoot.pendingChildren = newChildSet; // Schedule an update on the container to swap out the container. markUpdate(workInProgress); finalizeContainerChildren(container, newChildSet); } }; updateHostComponent$1 = function (current, workInProgress, type, newProps, rootContainerInstance) { 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 childrenUnchanged = workInProgress.firstEffect === null; if (childrenUnchanged && oldProps === newProps) { // No changes, just reuse the existing instance. // Note that this might release a previous clone. workInProgress.stateNode = currentInstance; return; } var recyclableInstance = workInProgress.stateNode; var currentHostContext = getHostContext(); var updatePayload = null; if (oldProps !== newProps) { updatePayload = prepareUpdate(recyclableInstance, type, oldProps, newProps, rootContainerInstance, currentHostContext); } if (childrenUnchanged && updatePayload === null) { // No changes, just reuse the existing instance. // Note that this might release a previous clone. workInProgress.stateNode = currentInstance; return; } var newInstance = cloneInstance(currentInstance, updatePayload, type, oldProps, newProps, workInProgress, childrenUnchanged, recyclableInstance); if (finalizeInitialChildren(newInstance, type, newProps, rootContainerInstance, currentHostContext)) { markUpdate(workInProgress); } workInProgress.stateNode = newInstance; if (childrenUnchanged) { // If there are no other effects in this tree, we need to flag this node as having one. // Even though we're not going to use it for anything. // Otherwise parents won't know that there are new children to propagate upwards. markUpdate(workInProgress); } else { // If children might have changed, we have to add them all to the set. appendAllChildren(newInstance, workInProgress, false, false); } }; updateHostText$1 = function (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 { // No host operations updateHostContainer = function (workInProgress) { // Noop }; updateHostComponent$1 = function (current, workInProgress, type, newProps, rootContainerInstance) { // Noop }; updateHostText$1 = function (current, workInProgress, oldText, newText) { // Noop }; } function completeWork(current, workInProgress, renderExpirationTime) { var newProps = workInProgress.pendingProps; switch (workInProgress.tag) { case IndeterminateComponent: break; case LazyComponent: break; case SimpleMemoComponent: case FunctionComponent: break; case ClassComponent: { var Component = workInProgress.type; if (isContextProvider(Component)) { popContext(workInProgress); } break; } case HostRoot: { popHostContainer(workInProgress); popTopLevelContextObject(workInProgress); var fiberRoot = workInProgress.stateNode; if (fiberRoot.pendingContext) { fiberRoot.context = fiberRoot.pendingContext; fiberRoot.pendingContext = null; } if (current === null || current.child === null) { // If we hydrated, pop so that we can delete any remaining children // that weren't hydrated. popHydrationState(workInProgress); // This resets the hacky state to fix isMounted before committing. // TODO: Delete this when we delete isMounted and findDOMNode. workInProgress.effectTag &= ~Placement; } updateHostContainer(workInProgress); break; } case HostComponent: { popHostContext(workInProgress); var rootContainerInstance = getRootHostContainer(); var type = workInProgress.type; if (current !== null && workInProgress.stateNode != null) { updateHostComponent$1(current, workInProgress, type, newProps, rootContainerInstance); if (current.ref !== workInProgress.ref) { markRef$1(workInProgress); } } else { if (!newProps) { !(workInProgress.stateNode !== null) ? reactProdInvariant('166') : void 0; // This can happen when we abort work. break; } 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 we want to add then top->down or // bottom->up. Top->down is faster in IE11. var wasHydrated = popHydrationState(workInProgress); if (wasHydrated) { // TODO: Move this and createInstance step into the beginPhase // to consolidate. if (prepareToHydrateHostInstance(workInProgress, rootContainerInstance, currentHostContext)) { // If changes to the hydrated node needs to be applied at the // commit-phase we mark this as such. markUpdate(workInProgress); } } else { var instance = createInstance(type, newProps, rootContainerInstance, currentHostContext, workInProgress); appendAllChildren(instance, workInProgress, false, false); // 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(instance, type, newProps, rootContainerInstance, currentHostContext)) { markUpdate(workInProgress); } workInProgress.stateNode = instance; } if (workInProgress.ref !== null) { // If there is a ref on a host node we need to schedule a callback markRef$1(workInProgress); } } break; } case HostText: { var newText = newProps; 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$1(current, workInProgress, oldText, newText); } else { if (typeof newText !== 'string') { !(workInProgress.stateNode !== null) ? reactProdInvariant('166') : void 0; // This can happen when we abort work. } var _rootContainerInstance = getRootHostContainer(); var _currentHostContext = getHostContext(); var _wasHydrated = popHydrationState(workInProgress); if (_wasHydrated) { if (prepareToHydrateHostTextInstance(workInProgress)) { markUpdate(workInProgress); } } else { workInProgress.stateNode = createTextInstance(newText, _rootContainerInstance, _currentHostContext, workInProgress); } } break; } case ForwardRef: break; case SuspenseComponent: { var nextState = workInProgress.memoizedState; if ((workInProgress.effectTag & DidCapture) !== NoEffect) { // Something suspended. Re-render with the fallback children. workInProgress.expirationTime = renderExpirationTime; // Do not reset the effect list. return workInProgress; } var nextDidTimeout = nextState !== null; var prevDidTimeout = current !== null && current.memoizedState !== null; if (current !== null && !nextDidTimeout && prevDidTimeout) { // We just switched from the fallback to the normal children. Delete // the fallback. // TODO: Would it be better to store the fallback fragment on var currentFallbackChild = current.child.sibling; if (currentFallbackChild !== null) { // Deletions go at the beginning of the return fiber's effect list var first = workInProgress.firstEffect; if (first !== null) { workInProgress.firstEffect = currentFallbackChild; currentFallbackChild.nextEffect = first; } else { workInProgress.firstEffect = workInProgress.lastEffect = currentFallbackChild; currentFallbackChild.nextEffect = null; } currentFallbackChild.effectTag = Deletion; } } if (nextDidTimeout || prevDidTimeout) { // If the children are hidden, or if they were previous hidden, schedule // an effect to toggle their visibility. This is also used to attach a // retry listener to the promise. workInProgress.effectTag |= Update; } break; } case Fragment: break; case Mode: break; case Profiler: break; case HostPortal: popHostContainer(workInProgress); updateHostContainer(workInProgress); break; case ContextProvider: // Pop provider fiber popProvider(workInProgress); break; case ContextConsumer: break; case MemoComponent: break; case IncompleteClassComponent: { // Same as class component case. I put it down here so that the tags are // sequential to ensure this switch is compiled to a jump table. var _Component = workInProgress.type; if (isContextProvider(_Component)) { popContext(workInProgress); } break; } case DehydratedSuspenseComponent: { if (enableSuspenseServerRenderer) { if (current === null) { var _wasHydrated2 = popHydrationState(workInProgress); !_wasHydrated2 ? reactProdInvariant('318') : void 0; skipPastDehydratedSuspenseInstance(workInProgress); } else if ((workInProgress.effectTag & DidCapture) === NoEffect) { // This boundary did not suspend so it's now hydrated. // To handle any future suspense cases, we're going to now upgrade it // to a Suspense component. We detach it from the existing current fiber. current.alternate = null; workInProgress.alternate = null; workInProgress.tag = SuspenseComponent; workInProgress.memoizedState = null; workInProgress.stateNode = null; } } break; } default: reactProdInvariant('156'); } return null; } function shouldCaptureSuspense(workInProgress) { // In order to capture, the Suspense component must have a fallback prop. if (workInProgress.memoizedProps.fallback === undefined) { return false; } // If it was the primary children that just suspended, capture and render the // fallback. Otherwise, don't capture and bubble to the next boundary. var nextState = workInProgress.memoizedState; return nextState === null; } // This module is forked in different environments. // By default, return `true` to log errors to the console. // Forks can return `false` if this isn't desirable. function showErrorDialog(capturedError) { return true; } function logCapturedError(capturedError) { var logError = showErrorDialog(capturedError); // Allow injected showErrorDialog() to prevent default console.error logging. // This enables renderers like ReactNative to better manage redbox behavior. if (logError === false) { return; } var error = capturedError.error; { // In production, we print the error directly. // This will include the message, the JS stack, and anything the browser wants to show. // We pass the error object instead of custom message so that the browser displays the error natively. console.error(error); } } var PossiblyWeakSet$1 = typeof WeakSet === 'function' ? WeakSet : Set; function logError(boundary, errorInfo) { var source = errorInfo.source; var stack = errorInfo.stack; if (stack === null && source !== null) { stack = getStackByFiberInDevAndProd(source); } var capturedError = { componentName: source !== null ? getComponentName(source.type) : null, componentStack: stack !== null ? stack : '', error: errorInfo.value, errorBoundary: null, errorBoundaryName: null, errorBoundaryFound: false, willRetry: false }; if (boundary !== null && boundary.tag === ClassComponent) { capturedError.errorBoundary = boundary.stateNode; capturedError.errorBoundaryName = getComponentName(boundary.type); capturedError.errorBoundaryFound = true; capturedError.willRetry = true; } try { logCapturedError(capturedError); } 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; }); } } var callComponentWillUnmountWithTimer = function (current$$1, instance) { startPhaseTimer(current$$1, 'componentWillUnmount'); instance.props = current$$1.memoizedProps; instance.state = current$$1.memoizedState; instance.componentWillUnmount(); stopPhaseTimer(); }; // Capture errors so they don't interrupt unmounting. function safelyCallComponentWillUnmount(current$$1, instance) { { try { callComponentWillUnmountWithTimer(current$$1, instance); } catch (unmountError) { captureCommitPhaseError(current$$1, unmountError); } } } function safelyDetachRef(current$$1) { var ref = current$$1.ref; if (ref !== null) { if (typeof ref === 'function') { { try { ref(null); } catch (refError) { captureCommitPhaseError(current$$1, refError); } } } else { ref.current = null; } } } function safelyCallDestroy(current$$1, destroy) { { try { destroy(); } catch (error) { captureCommitPhaseError(current$$1, error); } } } function commitBeforeMutationLifeCycles(current$$1, finishedWork) { switch (finishedWork.tag) { case FunctionComponent: case ForwardRef: case SimpleMemoComponent: { commitHookEffectList(UnmountSnapshot, NoEffect$1, finishedWork); return; } case ClassComponent: { if (finishedWork.effectTag & Snapshot) { if (current$$1 !== null) { var prevProps = current$$1.memoizedProps; var prevState = current$$1.memoizedState; startPhaseTimer(finishedWork, 'getSnapshotBeforeUpdate'); 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 snapshot = instance.getSnapshotBeforeUpdate(finishedWork.elementType === finishedWork.type ? prevProps : resolveDefaultProps(finishedWork.type, prevProps), prevState); instance.__reactInternalSnapshotBeforeUpdate = snapshot; stopPhaseTimer(); } } return; } case HostRoot: case HostComponent: case HostText: case HostPortal: case IncompleteClassComponent: // Nothing to do for these component types return; default: { reactProdInvariant('163'); } } } function commitHookEffectList(unmountTag, mountTag, 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 & unmountTag) !== NoEffect$1) { // Unmount var destroy = effect.destroy; effect.destroy = undefined; if (destroy !== undefined) { destroy(); } } if ((effect.tag & mountTag) !== NoEffect$1) { // Mount var create = effect.create; effect.destroy = create(); } effect = effect.next; } while (effect !== firstEffect); } } function commitPassiveHookEffects(finishedWork) { commitHookEffectList(UnmountPassive, NoEffect$1, finishedWork); commitHookEffectList(NoEffect$1, MountPassive, finishedWork); } function commitLifeCycles(finishedRoot, current$$1, finishedWork, committedExpirationTime) { switch (finishedWork.tag) { case FunctionComponent: case ForwardRef: case SimpleMemoComponent: { commitHookEffectList(UnmountLayout, MountLayout, finishedWork); break; } case ClassComponent: { var instance = finishedWork.stateNode; if (finishedWork.effectTag & Update) { if (current$$1 === null) { startPhaseTimer(finishedWork, 'componentDidMount'); // 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. instance.componentDidMount(); stopPhaseTimer(); } else { var prevProps = finishedWork.elementType === finishedWork.type ? current$$1.memoizedProps : resolveDefaultProps(finishedWork.type, current$$1.memoizedProps); var prevState = current$$1.memoizedState; startPhaseTimer(finishedWork, 'componentDidUpdate'); // 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. instance.componentDidUpdate(prevProps, prevState, instance.__reactInternalSnapshotBeforeUpdate); stopPhaseTimer(); } } var updateQueue = finishedWork.updateQueue; if (updateQueue !== null) { commitUpdateQueue(finishedWork, updateQueue, instance, committedExpirationTime); } return; } case HostRoot: { var _updateQueue = finishedWork.updateQueue; if (_updateQueue !== null) { var _instance = null; if (finishedWork.child !== null) { switch (finishedWork.child.tag) { case HostComponent: _instance = getPublicInstance(finishedWork.child.stateNode); break; case ClassComponent: _instance = finishedWork.child.stateNode; break; } } commitUpdateQueue(finishedWork, _updateQueue, _instance, committedExpirationTime); } return; } case HostComponent: { var _instance2 = finishedWork.stateNode; // 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$$1 === null && finishedWork.effectTag & Update) { var type = finishedWork.type; var props = finishedWork.memoizedProps; } return; } case HostText: { // We have no life-cycles associated with text. return; } case HostPortal: { // We have no life-cycles associated with portals. return; } case Profiler: { if (enableProfilerTimer) { var onRender = finishedWork.memoizedProps.onRender; if (enableSchedulerTracing) { onRender(finishedWork.memoizedProps.id, current$$1 === null ? 'mount' : 'update', finishedWork.actualDuration, finishedWork.treeBaseDuration, finishedWork.actualStartTime, getCommitTime(), finishedRoot.memoizedInteractions); } else { onRender(finishedWork.memoizedProps.id, current$$1 === null ? 'mount' : 'update', finishedWork.actualDuration, finishedWork.treeBaseDuration, finishedWork.actualStartTime, getCommitTime()); } } return; } case SuspenseComponent: break; case IncompleteClassComponent: break; default: { reactProdInvariant('163'); } } } function hideOrUnhideAllChildren(finishedWork, isHidden) { if (supportsMutation) { // We only have the top Fiber that was inserted but we need to recurse down its var node = finishedWork; while (true) { if (node.tag === HostComponent) { var instance = node.stateNode; if (isHidden) { hideInstance(instance); } else { unhideInstance(node.stateNode, node.memoizedProps); } } else if (node.tag === HostText) { var _instance3 = node.stateNode; if (isHidden) { hideTextInstance(_instance3); } else { unhideTextInstance(_instance3, node.memoizedProps); } } else if (node.tag === SuspenseComponent && node.memoizedState !== null) { // Found a nested Suspense component that timed out. Skip over the var fallbackChildFragment = node.child.sibling; fallbackChildFragment.return = node; node = fallbackChildFragment; continue; } else if (node.child !== null) { node.child.return = node; node = node.child; continue; } if (node === finishedWork) { return; } while (node.sibling === null) { if (node.return === null || node.return === finishedWork) { return; } node = node.return; } node.sibling.return = node.return; node = node.sibling; } } } function commitAttachRef(finishedWork) { var ref = finishedWork.ref; if (ref !== null) { var instance = finishedWork.stateNode; var instanceToUse = void 0; switch (finishedWork.tag) { case HostComponent: instanceToUse = getPublicInstance(instance); break; default: instanceToUse = instance; } if (typeof ref === 'function') { ref(instanceToUse); } else { ref.current = instanceToUse; } } } function commitDetachRef(current$$1) { var currentRef = current$$1.ref; if (currentRef !== null) { if (typeof currentRef === 'function') { currentRef(null); } else { currentRef.current = null; } } } // User-originating errors (lifecycles and refs) should not interrupt // deletion, so don't let them throw. Host-originating errors should // interrupt deletion, so it's okay function commitUnmount(current$$1) { onCommitUnmount(current$$1); switch (current$$1.tag) { case FunctionComponent: case ForwardRef: case MemoComponent: case SimpleMemoComponent: { var updateQueue = current$$1.updateQueue; if (updateQueue !== null) { var lastEffect = updateQueue.lastEffect; if (lastEffect !== null) { var firstEffect = lastEffect.next; var effect = firstEffect; do { var destroy = effect.destroy; if (destroy !== undefined) { safelyCallDestroy(current$$1, destroy); } effect = effect.next; } while (effect !== firstEffect); } } break; } case ClassComponent: { safelyDetachRef(current$$1); var instance = current$$1.stateNode; if (typeof instance.componentWillUnmount === 'function') { safelyCallComponentWillUnmount(current$$1, instance); } return; } case HostComponent: { safelyDetachRef(current$$1); return; } case HostPortal: { // TODO: this is recursive. // We are also not using this parent because // the portal will get pushed immediately. if (supportsMutation) { unmountHostComponents(current$$1); } else if (supportsPersistence) { emptyPortalContainer(current$$1); } return; } } } function commitNestedUnmounts(root) { // While we're inside a removed host node we don't want to call // removeChild on the inner nodes because they're removed by the top // call anyway. We also want to call componentWillUnmount on all // composites before this host node is removed from the tree. Therefore var node = root; while (true) { commitUnmount(node); // Visit children because they may contain more composite or host nodes. // Skip portals because commitUnmount() currently visits them recursively. if (node.child !== null && ( // If we use mutation we drill down into portals using commitUnmount above. // If we don't use mutation we drill down into portals here instead. !supportsMutation || node.tag !== HostPortal)) { node.child.return = node; node = node.child; continue; } if (node === root) { return; } while (node.sibling === null) { if (node.return === null || node.return === root) { return; } node = node.return; } node.sibling.return = node.return; node = node.sibling; } } function detachFiber(current$$1) { // Cut off the return pointers to disconnect it from the tree. Ideally, we // should 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. current$$1.return = null; current$$1.child = null; current$$1.memoizedState = null; current$$1.updateQueue = null; var alternate = current$$1.alternate; if (alternate !== null) { alternate.return = null; alternate.child = null; alternate.memoizedState = null; alternate.updateQueue = null; } } function emptyPortalContainer(current$$1) { if (!supportsPersistence) { return; } var portal = current$$1.stateNode; var containerInfo = portal.containerInfo; var emptyChildSet = createContainerChildSet(containerInfo); replaceContainerChildren(containerInfo, emptyChildSet); } function commitContainer(finishedWork) { if (!supportsPersistence) { return; } switch (finishedWork.tag) { case ClassComponent: { return; } case HostComponent: { return; } case HostText: { return; } case HostRoot: case HostPortal: { var portalOrRoot = finishedWork.stateNode; var containerInfo = portalOrRoot.containerInfo, _pendingChildren = portalOrRoot.pendingChildren; replaceContainerChildren(containerInfo, _pendingChildren); return; } default: { reactProdInvariant('163'); } } } function getHostParentFiber(fiber) { var parent = fiber.return; while (parent !== null) { if (isHostParent(parent)) { return parent; } parent = parent.return; } reactProdInvariant('160'); } function isHostParent(fiber) { return fiber.tag === HostComponent || fiber.tag === HostRoot || fiber.tag === HostPortal; } 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. 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; } node = node.return; } node.sibling.return = node.return; node = node.sibling; while (node.tag !== HostComponent && node.tag !== HostText && node.tag !== DehydratedSuspenseComponent) { // 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.effectTag & 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. if (!(node.effectTag & Placement)) { // Found it! return node.stateNode; } } } function commitPlacement(finishedWork) { if (!supportsMutation) { return; } // Recursively insert all host nodes into the parent. var parentFiber = getHostParentFiber(finishedWork); // Note: these two variables *must* always be updated together. var parent = void 0; var isContainer = void 0; switch (parentFiber.tag) { case HostComponent: parent = parentFiber.stateNode; isContainer = false; break; case HostRoot: parent = parentFiber.stateNode.containerInfo; isContainer = true; break; case HostPortal: parent = parentFiber.stateNode.containerInfo; isContainer = true; break; default: reactProdInvariant('161'); } if (parentFiber.effectTag & ContentReset) { // Reset the text content of the parent before doing any insertions parentFiber.effectTag &= ~ContentReset; } 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. var node = finishedWork; while (true) { if (node.tag === HostComponent || node.tag === HostText) { if (before) { if (isContainer) { insertInContainerBefore(parent, node.stateNode, before); } else { insertBefore(parent, node.stateNode, before); } } else { if (isContainer) { appendChildToContainer(parent, node.stateNode); } else { appendChild(parent, node.stateNode); } } } else if (node.tag === HostPortal) { // If the insertion itself is a portal, then we don't want to traverse // down its children. Instead, we'll get insertions from each child in // the portal directly. } else if (node.child !== null) { node.child.return = node; node = node.child; continue; } if (node === finishedWork) { return; } while (node.sibling === null) { if (node.return === null || node.return === finishedWork) { return; } node = node.return; } node.sibling.return = node.return; node = node.sibling; } } function unmountHostComponents(current$$1) { // We only have the top Fiber that was deleted but we need to recurse down its var node = current$$1; // Each iteration, currentParent is populated with node's host parent if not // currentParentIsValid. var currentParentIsValid = false; // Note: these two variables *must* always be updated together. var currentParent = void 0; var currentParentIsContainer = void 0; while (true) { if (!currentParentIsValid) { var parent = node.return; findParent: while (true) { !(parent !== null) ? reactProdInvariant('160') : void 0; switch (parent.tag) { case HostComponent: currentParent = parent.stateNode; currentParentIsContainer = false; break findParent; case HostRoot: currentParent = parent.stateNode.containerInfo; currentParentIsContainer = true; break findParent; case HostPortal: currentParent = parent.stateNode.containerInfo; currentParentIsContainer = true; break findParent; } parent = parent.return; } currentParentIsValid = true; } if (node.tag === HostComponent || node.tag === HostText) { commitNestedUnmounts(node); // After all the children have unmounted, it is now safe to remove the // node from the tree. if (currentParentIsContainer) { removeChildFromContainer(currentParent, node.stateNode); } else { removeChild(currentParent, node.stateNode); } // Don't visit children because we already visited them. } else if (enableSuspenseServerRenderer && node.tag === DehydratedSuspenseComponent) { // Delete the dehydrated suspense boundary and all of its content. if (currentParentIsContainer) { clearSuspenseBoundaryFromContainer(currentParent, node.stateNode); } else { clearSuspenseBoundary(currentParent, node.stateNode); } } else if (node.tag === HostPortal) { if (node.child !== null) { // When we go into a portal, it becomes the parent to remove from. // We will reassign it back when we pop the portal on the way up. currentParent = node.stateNode.containerInfo; currentParentIsContainer = true; // Visit children because portals might contain host components. node.child.return = node; node = node.child; continue; } } else { commitUnmount(node); // Visit children because we may find more host components below. if (node.child !== null) { node.child.return = node; node = node.child; continue; } } if (node === current$$1) { return; } while (node.sibling === null) { if (node.return === null || node.return === current$$1) { return; } node = node.return; if (node.tag === HostPortal) { // When we go out of the portal, we need to restore the parent. // Since we don't keep a stack of them, we will search for it. currentParentIsValid = false; } } node.sibling.return = node.return; node = node.sibling; } } function commitDeletion(current$$1) { if (supportsMutation) { // Recursively delete all host nodes from the parent. // Detach refs and call componentWillUnmount() on the whole subtree. unmountHostComponents(current$$1); } else { // Detach refs and call componentWillUnmount() on the whole subtree. commitNestedUnmounts(current$$1); } detachFiber(current$$1); } function commitWork(current$$1, finishedWork) { if (!supportsMutation) { switch (finishedWork.tag) { case FunctionComponent: case ForwardRef: case MemoComponent: case SimpleMemoComponent: { // Note: We currently never use MountMutation, but useLayout uses // UnmountMutation. commitHookEffectList(UnmountMutation, MountMutation, finishedWork); return; } } commitContainer(finishedWork); return; } switch (finishedWork.tag) { case FunctionComponent: case ForwardRef: case MemoComponent: case SimpleMemoComponent: { // Note: We currently never use MountMutation, but useLayout uses // UnmountMutation. commitHookEffectList(UnmountMutation, MountMutation, finishedWork); return; } case ClassComponent: { return; } case HostComponent: { var instance = finishedWork.stateNode; if (instance != 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$$1 !== null ? current$$1.memoizedProps : newProps; var type = finishedWork.type; // TODO: Type the updateQueue to be specific to host components. var updatePayload = finishedWork.updateQueue; finishedWork.updateQueue = null; if (updatePayload !== null) { commitUpdate(instance, updatePayload, type, oldProps, newProps, finishedWork); } } return; } case HostText: { !(finishedWork.stateNode !== null) ? reactProdInvariant('162') : void 0; 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$$1 !== null ? current$$1.memoizedProps : newText; commitTextUpdate(textInstance, oldText, newText); return; } case HostRoot: { return; } case Profiler: { return; } case SuspenseComponent: { var newState = finishedWork.memoizedState; var newDidTimeout = void 0; var primaryChildParent = finishedWork; if (newState === null) { newDidTimeout = false; } else { newDidTimeout = true; primaryChildParent = finishedWork.child; if (newState.timedOutAt === NoWork) { // If the children had not already timed out, record the time. // This is used to compute the elapsed time during subsequent // attempts to render the children. newState.timedOutAt = requestCurrentTime(); } } if (primaryChildParent !== null) { hideOrUnhideAllChildren(primaryChildParent, newDidTimeout); } // If this boundary just timed out, then it will have a set of thenables. // For each thenable, attach a listener so that when it resolves, React // attempts to re-render the boundary in the primary (pre-timeout) state. var thenables = finishedWork.updateQueue; if (thenables !== null) { finishedWork.updateQueue = null; var retryCache = finishedWork.stateNode; if (retryCache === null) { retryCache = finishedWork.stateNode = new PossiblyWeakSet$1(); } thenables.forEach(function (thenable) { // Memoize using the boundary fiber to prevent redundant listeners. var retry = retryTimedOutBoundary.bind(null, finishedWork, thenable); if (enableSchedulerTracing) { retry = unstable_wrap(retry); } if (!retryCache.has(thenable)) { retryCache.add(thenable); thenable.then(retry, retry); } }); } return; } case IncompleteClassComponent: { return; } default: { reactProdInvariant('163'); } } } function commitResetTextContent(current$$1) { if (!supportsMutation) { return; } resetTextContent(current$$1.stateNode); } var PossiblyWeakSet = typeof WeakSet === 'function' ? WeakSet : Set; var PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map; function createRootErrorUpdate(fiber, errorInfo, expirationTime) { var update = createUpdate(expirationTime); // Unmount the root by rendering null. update.tag = CaptureUpdate; // Caution: React DevTools currently depends on this property // being called "element". update.payload = { element: null }; var error = errorInfo.value; update.callback = function () { onUncaughtError(error); logError(fiber, errorInfo); }; return update; } function createClassErrorUpdate(fiber, errorInfo, expirationTime) { var update = createUpdate(expirationTime); update.tag = CaptureUpdate; var getDerivedStateFromError = fiber.type.getDerivedStateFromError; if (typeof getDerivedStateFromError === 'function') { var error = errorInfo.value; update.payload = function () { return getDerivedStateFromError(error); }; } var inst = fiber.stateNode; if (inst !== null && typeof inst.componentDidCatch === 'function') { update.callback = function callback() { 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); } var error = errorInfo.value; var stack = errorInfo.stack; logError(fiber, errorInfo); this.componentDidCatch(error, { componentStack: stack !== null ? stack : '' }); }; } return update; } function attachPingListener(root, renderExpirationTime, thenable) { // Attach a listener to the promise to "ping" the root and retry. But // only if one does not already exist for the current render expiration // time (which acts like a "thread ID" here). var pingCache = root.pingCache; var threadIDs = void 0; if (pingCache === null) { pingCache = root.pingCache = new PossiblyWeakMap(); threadIDs = new Set(); pingCache.set(thenable, threadIDs); } else { threadIDs = pingCache.get(thenable); if (threadIDs === undefined) { threadIDs = new Set(); pingCache.set(thenable, threadIDs); } } if (!threadIDs.has(renderExpirationTime)) { // Memoize using the thread ID to prevent redundant listeners. threadIDs.add(renderExpirationTime); var ping = pingSuspendedRoot.bind(null, root, thenable, renderExpirationTime); if (enableSchedulerTracing) { ping = unstable_wrap(ping); } thenable.then(ping, ping); } } function throwException(root, returnFiber, sourceFiber, value, renderExpirationTime) { // The source fiber did not complete. sourceFiber.effectTag |= Incomplete; // Its effect list is no longer valid. sourceFiber.firstEffect = sourceFiber.lastEffect = null; if (value !== null && typeof value === 'object' && typeof value.then === 'function') { // This is a thenable. var thenable = value; // Find the earliest timeout threshold of all the placeholders in the // ancestor path. We could avoid this traversal by storing the thresholds on // the stack, but we choose not to because we only hit this path if we're // IO-bound (i.e. if something suspends). Whereas the stack is used even in // the non-IO- bound case. var _workInProgress = returnFiber; var earliestTimeoutMs = -1; var startTimeMs = -1; do { if (_workInProgress.tag === SuspenseComponent) { var current$$1 = _workInProgress.alternate; if (current$$1 !== null) { var currentState = current$$1.memoizedState; if (currentState !== null) { // Reached a boundary that already timed out. Do not search // any further. var timedOutAt = currentState.timedOutAt; startTimeMs = expirationTimeToMs(timedOutAt); // Do not search any further. break; } } var timeoutPropMs = _workInProgress.pendingProps.maxDuration; if (typeof timeoutPropMs === 'number') { if (timeoutPropMs <= 0) { earliestTimeoutMs = 0; } else if (earliestTimeoutMs === -1 || timeoutPropMs < earliestTimeoutMs) { earliestTimeoutMs = timeoutPropMs; } } } // If there is a DehydratedSuspenseComponent we don't have to do anything because // if something suspends inside it, we will simply leave that as dehydrated. It // will never timeout. _workInProgress = _workInProgress.return; } while (_workInProgress !== null); // Schedule the nearest Suspense to re-render the timed out view. _workInProgress = returnFiber; do { if (_workInProgress.tag === SuspenseComponent && shouldCaptureSuspense(_workInProgress)) { // Found the nearest boundary. // Stash the promise on the boundary fiber. If the boundary times out, we'll var thenables = _workInProgress.updateQueue; if (thenables === null) { var updateQueue = new Set(); updateQueue.add(thenable); _workInProgress.updateQueue = updateQueue; } else { thenables.add(thenable); } // If the boundary is outside of concurrent mode, we should *not* // suspend the commit. Pretend as if the suspended component rendered // null and keep rendering. In the commit phase, we'll schedule a // subsequent synchronous update to re-render the Suspense. // // Note: It doesn't matter whether the component that suspended was // inside a concurrent mode tree. If the Suspense is outside of it, we // should *not* suspend the commit. if ((_workInProgress.mode & ConcurrentMode) === NoEffect) { _workInProgress.effectTag |= DidCapture; // 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.effectTag &= ~(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 updte to // prevent a bail out. var update = createUpdate(Sync); update.tag = ForceUpdate; enqueueUpdate(sourceFiber, update); } } // The source fiber did not complete. Mark it with Sync priority to // indicate that it still has pending work. sourceFiber.expirationTime = Sync; // Exit without suspending. return; } // Confirmed that the boundary is in a concurrent mode tree. Continue // with the normal suspend path. attachPingListener(root, renderExpirationTime, thenable); var absoluteTimeoutMs = void 0; if (earliestTimeoutMs === -1) { // If no explicit threshold is given, default to an arbitrarily large // value. The actual size doesn't matter because the threshold for the // whole tree will be clamped to the expiration time. absoluteTimeoutMs = maxSigned31BitInt; } else { if (startTimeMs === -1) { // This suspend happened outside of any already timed-out // placeholders. We don't know exactly when the update was // scheduled, but we can infer an approximate start time from the // expiration time. First, find the earliest uncommitted expiration // time in the tree, including work that is suspended. Then subtract // the offset used to compute an async update's expiration time. // This will cause high priority (interactive) work to expire // earlier than necessary, but we can account for this by adjusting // for the Just Noticeable Difference. var earliestExpirationTime = findEarliestOutstandingPriorityLevel(root, renderExpirationTime); var earliestExpirationTimeMs = expirationTimeToMs(earliestExpirationTime); startTimeMs = earliestExpirationTimeMs - LOW_PRIORITY_EXPIRATION; } absoluteTimeoutMs = startTimeMs + earliestTimeoutMs; } // Mark the earliest timeout in the suspended fiber's ancestor path. // After completing the root, we'll take the largest of all the // suspended fiber's timeouts and use it to compute a timeout for the // whole tree. renderDidSuspend(root, absoluteTimeoutMs, renderExpirationTime); _workInProgress.effectTag |= ShouldCapture; _workInProgress.expirationTime = renderExpirationTime; return; } else if (enableSuspenseServerRenderer && _workInProgress.tag === DehydratedSuspenseComponent) { attachPingListener(root, renderExpirationTime, thenable); // Since we already have a current fiber, we can eagerly add a retry listener. var retryCache = _workInProgress.memoizedState; if (retryCache === null) { retryCache = _workInProgress.memoizedState = new PossiblyWeakSet(); var _current = _workInProgress.alternate; !_current ? reactProdInvariant('319') : void 0; _current.memoizedState = retryCache; } // Memoize using the boundary fiber to prevent redundant listeners. if (!retryCache.has(thenable)) { retryCache.add(thenable); var retry = retryTimedOutBoundary.bind(null, _workInProgress, thenable); if (enableSchedulerTracing) { retry = unstable_wrap(retry); } thenable.then(retry, retry); } _workInProgress.effectTag |= ShouldCapture; _workInProgress.expirationTime = renderExpirationTime; return; } // This boundary already captured during this render. Continue to the next // boundary. _workInProgress = _workInProgress.return; } while (_workInProgress !== null); // No boundary was found. Fallthrough to error mode. // TODO: Use invariant so the message is stripped in prod? value = new Error((getComponentName(sourceFiber.type) || 'A React component') + ' suspended while rendering, but no fallback UI was specified.\n' + '\n' + 'Add a component higher in the tree to ' + 'provide a loading indicator or placeholder to display.' + getStackByFiberInDevAndProd(sourceFiber)); } // 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. renderDidError(); value = createCapturedValue(value, sourceFiber); var workInProgress = returnFiber; do { switch (workInProgress.tag) { case HostRoot: { var _errorInfo = value; workInProgress.effectTag |= ShouldCapture; workInProgress.expirationTime = renderExpirationTime; var _update = createRootErrorUpdate(workInProgress, _errorInfo, renderExpirationTime); enqueueCapturedUpdate(workInProgress, _update); return; } case ClassComponent: // Capture and retry var errorInfo = value; var ctor = workInProgress.type; var instance = workInProgress.stateNode; if ((workInProgress.effectTag & DidCapture) === NoEffect && (typeof ctor.getDerivedStateFromError === 'function' || instance !== null && typeof instance.componentDidCatch === 'function' && !isAlreadyFailedLegacyErrorBoundary(instance))) { workInProgress.effectTag |= ShouldCapture; workInProgress.expirationTime = renderExpirationTime; // Schedule the error boundary to re-render using updated state var _update2 = createClassErrorUpdate(workInProgress, errorInfo, renderExpirationTime); enqueueCapturedUpdate(workInProgress, _update2); return; } break; default: break; } workInProgress = workInProgress.return; } while (workInProgress !== null); } function unwindWork(workInProgress, renderExpirationTime) { switch (workInProgress.tag) { case ClassComponent: { var Component = workInProgress.type; if (isContextProvider(Component)) { popContext(workInProgress); } var effectTag = workInProgress.effectTag; if (effectTag & ShouldCapture) { workInProgress.effectTag = effectTag & ~ShouldCapture | DidCapture; return workInProgress; } return null; } case HostRoot: { popHostContainer(workInProgress); popTopLevelContextObject(workInProgress); var _effectTag = workInProgress.effectTag; !((_effectTag & DidCapture) === NoEffect) ? reactProdInvariant('285') : void 0; workInProgress.effectTag = _effectTag & ~ShouldCapture | DidCapture; return workInProgress; } case HostComponent: { // TODO: popHydrationState popHostContext(workInProgress); return null; } case SuspenseComponent: { var _effectTag2 = workInProgress.effectTag; if (_effectTag2 & ShouldCapture) { workInProgress.effectTag = _effectTag2 & ~ShouldCapture | DidCapture; // Captured a suspense effect. Re-render the boundary. return workInProgress; } return null; } case DehydratedSuspenseComponent: { if (enableSuspenseServerRenderer) { // TODO: popHydrationState var _effectTag3 = workInProgress.effectTag; if (_effectTag3 & ShouldCapture) { workInProgress.effectTag = _effectTag3 & ~ShouldCapture | DidCapture; // Captured a suspense effect. Re-render the boundary. return workInProgress; } } return null; } case HostPortal: popHostContainer(workInProgress); return null; case ContextProvider: popProvider(workInProgress); return null; default: return null; } } function unwindInterruptedWork(interruptedWork) { switch (interruptedWork.tag) { case ClassComponent: { var childContextTypes = interruptedWork.type.childContextTypes; if (childContextTypes !== null && childContextTypes !== undefined) { popContext(interruptedWork); } break; } case HostRoot: { popHostContainer(interruptedWork); popTopLevelContextObject(interruptedWork); break; } case HostComponent: { popHostContext(interruptedWork); break; } case HostPortal: popHostContainer(interruptedWork); break; case ContextProvider: popProvider(interruptedWork); break; default: break; } } var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher; var ReactCurrentOwner$1 = ReactSharedInternals.ReactCurrentOwner; if (enableSchedulerTracing) { // Provide explicit error message when production+profiling bundle of e.g. react-dom // is used with production (non-profiling) bundle of scheduler/tracing !(__interactionsRef != null && __interactionsRef.current != null) ? reactProdInvariant('302') : void 0; } var isWorking = false; // The next work in progress fiber that we're currently working on. var nextUnitOfWork = null; var nextRoot = null; // The time at which we're currently rendering work. var nextRenderExpirationTime = NoWork; var nextLatestAbsoluteTimeoutMs = -1; var nextRenderDidError = false; // The next fiber with an effect that we're currently committing. var nextEffect = null; var isCommitting$1 = false; var rootWithPendingPassiveEffects = null; var passiveEffectCallbackHandle = null; var passiveEffectCallback = null; var legacyErrorBoundariesThatAlreadyFailed = null; // Used for performance tracking. var interruptedBy = null; function resetStack() { if (nextUnitOfWork !== null) { var interruptedWork = nextUnitOfWork.return; while (interruptedWork !== null) { unwindInterruptedWork(interruptedWork); interruptedWork = interruptedWork.return; } } nextRoot = null; nextRenderExpirationTime = NoWork; nextLatestAbsoluteTimeoutMs = -1; nextRenderDidError = false; nextUnitOfWork = null; } function commitAllHostEffects() { while (nextEffect !== null) { recordEffect(); var effectTag = nextEffect.effectTag; if (effectTag & ContentReset) { commitResetTextContent(nextEffect); } if (effectTag & Ref) { var current$$1 = nextEffect.alternate; if (current$$1 !== null) { commitDetachRef(current$$1); } } // The following switch statement is only concerned about placement, // updates, and deletions. To avoid needing to add a case for every // possible bitmap value, we remove the secondary effects from the // effect tag and switch on that value. var primaryEffectTag = effectTag & (Placement | Update | Deletion); switch (primaryEffectTag) { case Placement: { commitPlacement(nextEffect); // 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. nextEffect.effectTag &= ~Placement; break; } case PlacementAndUpdate: { // Placement commitPlacement(nextEffect); // Clear the "placement" from effect tag so that we know that this is inserted, before // any life-cycles like componentDidMount gets called. nextEffect.effectTag &= ~Placement; // Update var _current = nextEffect.alternate; commitWork(_current, nextEffect); break; } case Update: { var _current2 = nextEffect.alternate; commitWork(_current2, nextEffect); break; } case Deletion: { commitDeletion(nextEffect); break; } } nextEffect = nextEffect.nextEffect; } } function commitBeforeMutationLifecycles() { while (nextEffect !== null) { var effectTag = nextEffect.effectTag; if (effectTag & Snapshot) { recordEffect(); var current$$1 = nextEffect.alternate; commitBeforeMutationLifeCycles(current$$1, nextEffect); } nextEffect = nextEffect.nextEffect; } } function commitAllLifeCycles(finishedRoot, committedExpirationTime) { while (nextEffect !== null) { var effectTag = nextEffect.effectTag; if (effectTag & (Update | Callback)) { recordEffect(); var current$$1 = nextEffect.alternate; commitLifeCycles(finishedRoot, current$$1, nextEffect, committedExpirationTime); } if (effectTag & Ref) { recordEffect(); commitAttachRef(nextEffect); } if (effectTag & Passive) { rootWithPendingPassiveEffects = finishedRoot; } nextEffect = nextEffect.nextEffect; } } function commitPassiveEffects(root, firstEffect) { rootWithPendingPassiveEffects = null; passiveEffectCallbackHandle = null; passiveEffectCallback = null; // Set this to true to prevent re-entrancy var previousIsRendering = isRendering; isRendering = true; var effect = firstEffect; do { if (effect.effectTag & Passive) { var didError = false; var error = void 0; { try { commitPassiveHookEffects(effect); } catch (e) { didError = true; error = e; } } if (didError) { captureCommitPhaseError(effect, error); } } effect = effect.nextEffect; } while (effect !== null); isRendering = previousIsRendering; // Check if work was scheduled by one of the effects var rootExpirationTime = root.expirationTime; if (rootExpirationTime !== NoWork) { requestWork(root, rootExpirationTime); } // Flush any sync work that was scheduled by effects if (!isBatchingUpdates && !isRendering) { performSyncWork(); } } function isAlreadyFailedLegacyErrorBoundary(instance) { return legacyErrorBoundariesThatAlreadyFailed !== null && legacyErrorBoundariesThatAlreadyFailed.has(instance); } function markLegacyErrorBoundaryAsFailed(instance) { if (legacyErrorBoundariesThatAlreadyFailed === null) { legacyErrorBoundariesThatAlreadyFailed = new Set([instance]); } else { legacyErrorBoundariesThatAlreadyFailed.add(instance); } } function flushPassiveEffects$1() { if (passiveEffectCallbackHandle !== null) { cancelPassiveEffects(passiveEffectCallbackHandle); } if (passiveEffectCallback !== null) { // We call the scheduled callback instead of commitPassiveEffects directly // to ensure tracing works correctly. passiveEffectCallback(); } } function commitRoot(root, finishedWork) { isWorking = true; isCommitting$1 = true; startCommitTimer(); !(root.current !== finishedWork) ? reactProdInvariant('177') : void 0; var committedExpirationTime = root.pendingCommitExpirationTime; !(committedExpirationTime !== NoWork) ? reactProdInvariant('261') : void 0; root.pendingCommitExpirationTime = NoWork; // Update the pending priority levels to account for the work that we are // about to commit. This needs to happen before calling the lifecycles, since // they may schedule additional updates. var updateExpirationTimeBeforeCommit = finishedWork.expirationTime; var childExpirationTimeBeforeCommit = finishedWork.childExpirationTime; var earliestRemainingTimeBeforeCommit = childExpirationTimeBeforeCommit > updateExpirationTimeBeforeCommit ? childExpirationTimeBeforeCommit : updateExpirationTimeBeforeCommit; markCommittedPriorityLevels(root, earliestRemainingTimeBeforeCommit); var prevInteractions = null; if (enableSchedulerTracing) { // Restore any pending interactions at this point, // So that cascading work triggered during the render phase will be accounted for. prevInteractions = __interactionsRef.current; __interactionsRef.current = root.memoizedInteractions; } // Reset this to null before calling lifecycles ReactCurrentOwner$1.current = null; var firstEffect = void 0; if (finishedWork.effectTag > PerformedWork) { // A fiber's effect list consists only of its children, not itself. So if // the root has an effect, we need to add it to the end of the list. The // resulting list is the set that would belong to the root's parent, if // it had one; that is, all the effects in the tree including the root. if (finishedWork.lastEffect !== null) { finishedWork.lastEffect.nextEffect = finishedWork; firstEffect = finishedWork.firstEffect; } else { firstEffect = finishedWork; } } else { // There is no effect on the root. firstEffect = finishedWork.firstEffect; } prepareForCommit(root.containerInfo); // Invoke instances of getSnapshotBeforeUpdate before mutation. nextEffect = firstEffect; startCommitSnapshotEffectsTimer(); while (nextEffect !== null) { var didError = false; var error = void 0; { try { commitBeforeMutationLifecycles(); } catch (e) { didError = true; error = e; } } if (didError) { !(nextEffect !== null) ? reactProdInvariant('178') : void 0; captureCommitPhaseError(nextEffect, error); // Clean-up if (nextEffect !== null) { nextEffect = nextEffect.nextEffect; } } } stopCommitSnapshotEffectsTimer(); if (enableProfilerTimer) { // Mark the current commit time to be shared by all Profilers in this batch. // This enables them to be grouped later. recordCommitTime(); } // Commit all the side-effects within a tree. We'll do this in two passes. // The first pass performs all the host insertions, updates, deletions and // ref unmounts. nextEffect = firstEffect; startCommitHostEffectsTimer(); while (nextEffect !== null) { var _didError = false; var _error = void 0; { try { commitAllHostEffects(); } catch (e) { _didError = true; _error = e; } } if (_didError) { !(nextEffect !== null) ? reactProdInvariant('178') : void 0; captureCommitPhaseError(nextEffect, _error); // Clean-up if (nextEffect !== null) { nextEffect = nextEffect.nextEffect; } } } stopCommitHostEffectsTimer(); resetAfterCommit(root.containerInfo); // The work-in-progress tree is now the current tree. This must come after // the first pass of the commit phase, so that the previous tree is still // current during componentWillUnmount, but before the second pass, so that // the finished work is current during componentDidMount/Update. root.current = finishedWork; // In the second pass we'll perform all life-cycles and ref callbacks. // Life-cycles happen as a separate pass so that all placements, updates, // and deletions in the entire tree have already been invoked. // This pass also triggers any renderer-specific initial effects. nextEffect = firstEffect; startCommitLifeCyclesTimer(); while (nextEffect !== null) { var _didError2 = false; var _error2 = void 0; { try { commitAllLifeCycles(root, committedExpirationTime); } catch (e) { _didError2 = true; _error2 = e; } } if (_didError2) { !(nextEffect !== null) ? reactProdInvariant('178') : void 0; captureCommitPhaseError(nextEffect, _error2); if (nextEffect !== null) { nextEffect = nextEffect.nextEffect; } } } if (firstEffect !== null && rootWithPendingPassiveEffects !== null) { // This commit included a passive effect. These do not need to fire until // after the next paint. Schedule an callback to fire them in an async // event. To ensure serial execution, the callback will be flushed early if // we enter rootWithPendingPassiveEffects commit phase before then. var callback = commitPassiveEffects.bind(null, root, firstEffect); if (enableSchedulerTracing) { // TODO: Avoid this extra callback by mutating the tracing ref directly, // like we do at the beginning of commitRoot. I've opted not to do that // here because that code is still in flux. callback = unstable_wrap(callback); } passiveEffectCallbackHandle = unstable_runWithPriority(unstable_NormalPriority, function () { return schedulePassiveEffects(callback); }); passiveEffectCallback = callback; } isCommitting$1 = false; isWorking = false; stopCommitLifeCyclesTimer(); stopCommitTimer(); onCommitRoot(finishedWork.stateNode); var updateExpirationTimeAfterCommit = finishedWork.expirationTime; var childExpirationTimeAfterCommit = finishedWork.childExpirationTime; var earliestRemainingTimeAfterCommit = childExpirationTimeAfterCommit > updateExpirationTimeAfterCommit ? childExpirationTimeAfterCommit : updateExpirationTimeAfterCommit; if (earliestRemainingTimeAfterCommit === NoWork) { // If there's no remaining work, we can clear the set of already failed // error boundaries. legacyErrorBoundariesThatAlreadyFailed = null; } onCommit(root, earliestRemainingTimeAfterCommit); if (enableSchedulerTracing) { __interactionsRef.current = prevInteractions; var subscriber = void 0; try { subscriber = __subscriberRef.current; if (subscriber !== null && root.memoizedInteractions.size > 0) { var threadID = computeThreadID(committedExpirationTime, root.interactionThreadID); subscriber.onWorkStopped(root.memoizedInteractions, threadID); } } catch (error) { // It's not safe for commitRoot() to throw. // Store the error for now and we'll re-throw in finishRendering(). if (!hasUnhandledError) { hasUnhandledError = true; unhandledError = error; } } finally { // Clear completed interactions from the pending Map. // Unless the render was suspended or cascading work was scheduled, // In which case– leave pending interactions until the subsequent render. var pendingInteractionMap = root.pendingInteractionMap; pendingInteractionMap.forEach(function (scheduledInteractions, scheduledExpirationTime) { // Only decrement the pending interaction count if we're done. // If there's still work at the current priority, // That indicates that we are waiting for suspense data. if (scheduledExpirationTime > earliestRemainingTimeAfterCommit) { pendingInteractionMap.delete(scheduledExpirationTime); scheduledInteractions.forEach(function (interaction) { interaction.__count--; if (subscriber !== null && interaction.__count === 0) { try { subscriber.onInteractionScheduledWorkCompleted(interaction); } catch (error) { // It's not safe for commitRoot() to throw. // Store the error for now and we'll re-throw in finishRendering(). if (!hasUnhandledError) { hasUnhandledError = true; unhandledError = error; } } } }); } }); } } } function resetChildExpirationTime(workInProgress, renderTime) { if (renderTime !== Never && workInProgress.childExpirationTime === Never) { // The children of this component are hidden. Don't bubble their // expiration times. return; } var newChildExpirationTime = NoWork; // Bubble up the earliest expiration time. if (enableProfilerTimer && workInProgress.mode & ProfileMode) { // We're in profiling mode. // Let's use this same traversal to update the render durations. var actualDuration = workInProgress.actualDuration; var treeBaseDuration = workInProgress.selfBaseDuration; // 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. var shouldBubbleActualDurations = workInProgress.alternate === null || workInProgress.child !== workInProgress.alternate.child; var child = workInProgress.child; while (child !== null) { var childUpdateExpirationTime = child.expirationTime; var childChildExpirationTime = child.childExpirationTime; if (childUpdateExpirationTime > newChildExpirationTime) { newChildExpirationTime = childUpdateExpirationTime; } if (childChildExpirationTime > newChildExpirationTime) { newChildExpirationTime = childChildExpirationTime; } if (shouldBubbleActualDurations) { actualDuration += child.actualDuration; } treeBaseDuration += child.treeBaseDuration; child = child.sibling; } workInProgress.actualDuration = actualDuration; workInProgress.treeBaseDuration = treeBaseDuration; } else { var _child = workInProgress.child; while (_child !== null) { var _childUpdateExpirationTime = _child.expirationTime; var _childChildExpirationTime = _child.childExpirationTime; if (_childUpdateExpirationTime > newChildExpirationTime) { newChildExpirationTime = _childUpdateExpirationTime; } if (_childChildExpirationTime > newChildExpirationTime) { newChildExpirationTime = _childChildExpirationTime; } _child = _child.sibling; } } workInProgress.childExpirationTime = newChildExpirationTime; } function completeUnitOfWork(workInProgress) { // 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. while (true) { // 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$$1 = workInProgress.alternate; var returnFiber = workInProgress.return; var siblingFiber = workInProgress.sibling; if ((workInProgress.effectTag & Incomplete) === NoEffect) { nextUnitOfWork = workInProgress; if (enableProfilerTimer) { if (workInProgress.mode & ProfileMode) { startProfilerTimer(workInProgress); } nextUnitOfWork = completeWork(current$$1, workInProgress, nextRenderExpirationTime); if (workInProgress.mode & ProfileMode) { // Update render duration assuming we didn't error. stopProfilerTimerIfRunningAndRecordDelta(workInProgress, false); } } else { nextUnitOfWork = completeWork(current$$1, workInProgress, nextRenderExpirationTime); } stopWorkTimer(workInProgress); resetChildExpirationTime(workInProgress, nextRenderExpirationTime); if (nextUnitOfWork !== null) { // Completing this fiber spawned new work. Work on that next. return nextUnitOfWork; } if (returnFiber !== null && // Do not append effects to parents if a sibling failed to complete (returnFiber.effectTag & Incomplete) === NoEffect) { // Append all the effects of the subtree and this fiber onto the effect // list of the parent. The completion order of the children affects the // side-effect order. if (returnFiber.firstEffect === null) { returnFiber.firstEffect = workInProgress.firstEffect; } if (workInProgress.lastEffect !== null) { if (returnFiber.lastEffect !== null) { returnFiber.lastEffect.nextEffect = workInProgress.firstEffect; } returnFiber.lastEffect = workInProgress.lastEffect; } // If this fiber had side-effects, we append it AFTER the children's // side-effects. We can perform certain side-effects earlier if // needed, by doing multiple passes over the effect list. We don't want // to schedule our own side-effect on our own list because if end up // reusing children we'll schedule this effect onto itself since we're // at the end. var effectTag = workInProgress.effectTag; // Skip both NoWork and PerformedWork tags when creating the effect list. // PerformedWork effect is read by React DevTools but shouldn't be committed. if (effectTag > PerformedWork) { if (returnFiber.lastEffect !== null) { returnFiber.lastEffect.nextEffect = workInProgress; } else { returnFiber.firstEffect = workInProgress; } returnFiber.lastEffect = workInProgress; } } if (siblingFiber !== null) { // If there is more work to do in this returnFiber, do that next. return siblingFiber; } else if (returnFiber !== null) { // If there's no more work in this returnFiber. Complete the returnFiber. workInProgress = returnFiber; continue; } else { // We've reached the root. return null; } } else { if (enableProfilerTimer && workInProgress.mode & ProfileMode) { // Record the render duration for the fiber that errored. stopProfilerTimerIfRunningAndRecordDelta(workInProgress, false); // Include the time spent working on failed children before continuing. var actualDuration = workInProgress.actualDuration; var child = workInProgress.child; while (child !== null) { actualDuration += child.actualDuration; child = child.sibling; } workInProgress.actualDuration = actualDuration; } // 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(workInProgress, nextRenderExpirationTime); // Because this fiber did not complete, don't reset its expiration time. if (workInProgress.effectTag & DidCapture) { // Restarting an error boundary stopFailedWorkTimer(workInProgress); } else { stopWorkTimer(workInProgress); } if (next !== null) { stopWorkTimer(workInProgress); next.effectTag &= HostEffectMask; return next; } if (returnFiber !== null) { // Mark the parent fiber as incomplete and clear its effect list. returnFiber.firstEffect = returnFiber.lastEffect = null; returnFiber.effectTag |= Incomplete; } if (siblingFiber !== null) { // If there is more work to do in this returnFiber, do that next. return siblingFiber; } else if (returnFiber !== null) { // If there's no more work in this returnFiber. Complete the returnFiber. workInProgress = returnFiber; continue; } else { return null; } } } // Without this explicit null return Flow complains of invalid return type // TODO Remove the above while(true) loop // eslint-disable-next-line no-unreachable return null; } function performUnitOfWork(workInProgress) { // 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$$1 = workInProgress.alternate; // See if beginning this work spawns more work. startWorkTimer(workInProgress); var next = void 0; if (enableProfilerTimer) { if (workInProgress.mode & ProfileMode) { startProfilerTimer(workInProgress); } next = beginWork(current$$1, workInProgress, nextRenderExpirationTime); workInProgress.memoizedProps = workInProgress.pendingProps; if (workInProgress.mode & ProfileMode) { // Record the render duration assuming we didn't bailout (or error). stopProfilerTimerIfRunningAndRecordDelta(workInProgress, true); } } else { next = beginWork(current$$1, workInProgress, nextRenderExpirationTime); workInProgress.memoizedProps = workInProgress.pendingProps; } if (next === null) { // If this doesn't spawn new work, complete the current work. next = completeUnitOfWork(workInProgress); } ReactCurrentOwner$1.current = null; return next; } function workLoop(isYieldy) { if (!isYieldy) { // Flush work without yielding while (nextUnitOfWork !== null) { nextUnitOfWork = performUnitOfWork(nextUnitOfWork); } } else { // Flush asynchronous work until there's a higher priority event while (nextUnitOfWork !== null && !shouldYieldToRenderer()) { nextUnitOfWork = performUnitOfWork(nextUnitOfWork); } } } function renderRoot(root, isYieldy) { !!isWorking ? reactProdInvariant('243') : void 0; flushPassiveEffects$1(); isWorking = true; var previousDispatcher = ReactCurrentDispatcher.current; ReactCurrentDispatcher.current = ContextOnlyDispatcher; var expirationTime = root.nextExpirationTimeToWorkOn; // Check if we're starting from a fresh stack, or if we're resuming from // previously yielded work. if (expirationTime !== nextRenderExpirationTime || root !== nextRoot || nextUnitOfWork === null) { // Reset the stack and start working from the root. resetStack(); nextRoot = root; nextRenderExpirationTime = expirationTime; nextUnitOfWork = createWorkInProgress(nextRoot.current, null, nextRenderExpirationTime); root.pendingCommitExpirationTime = NoWork; if (enableSchedulerTracing) { // Determine which interactions this batch of work currently includes, // So that we can accurately attribute time spent working on it, var interactions = new Set(); root.pendingInteractionMap.forEach(function (scheduledInteractions, scheduledExpirationTime) { if (scheduledExpirationTime >= expirationTime) { scheduledInteractions.forEach(function (interaction) { return interactions.add(interaction); }); } }); // Store the current set of interactions on the FiberRoot for a few reasons: // We can re-use it in hot functions like renderRoot() without having to recalculate it. // We will also use it in commitWork() to pass to any Profiler onRender() hooks. // This also provides DevTools with a way to access it when the onCommitRoot() hook is called. root.memoizedInteractions = interactions; if (interactions.size > 0) { var subscriber = __subscriberRef.current; if (subscriber !== null) { var threadID = computeThreadID(expirationTime, root.interactionThreadID); try { subscriber.onWorkStarted(interactions, threadID); } catch (error) { // Work thrown by an interaction tracing subscriber should be rethrown, // But only once it's safe (to avoid leaving the scheduler in an invalid state). // Store the error for now and we'll re-throw in finishRendering(). if (!hasUnhandledError) { hasUnhandledError = true; unhandledError = error; } } } } } } var prevInteractions = null; if (enableSchedulerTracing) { // We're about to start new traced work. // Restore pending interactions so cascading work triggered during the render phase will be accounted for. prevInteractions = __interactionsRef.current; __interactionsRef.current = root.memoizedInteractions; } var didFatal = false; startWorkLoopTimer(nextUnitOfWork); do { try { workLoop(isYieldy); } catch (thrownValue) { resetContextDependences(); resetHooks(); // Reset in case completion throws. // This is only used in DEV and when replaying is on. if (nextUnitOfWork === null) { // This is a fatal error. didFatal = true; onUncaughtError(thrownValue); } else { if (enableProfilerTimer && nextUnitOfWork.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(nextUnitOfWork, true); } !(nextUnitOfWork !== null) ? reactProdInvariant('271') : void 0; var sourceFiber = nextUnitOfWork; var returnFiber = sourceFiber.return; if (returnFiber === null) { // This is the root. The root could capture its own errors. However, // we don't know if it errors before or after we pushed the host // context. This information is needed to avoid a stack mismatch. // Because we're not sure, treat this as a fatal error. We could track // which phase it fails in, but doesn't seem worth it. At least // for now. didFatal = true; onUncaughtError(thrownValue); } else { throwException(root, returnFiber, sourceFiber, thrownValue, nextRenderExpirationTime); nextUnitOfWork = completeUnitOfWork(sourceFiber); continue; } } } break; } while (true); if (enableSchedulerTracing) { // Traced work is done for now; restore the previous interactions. __interactionsRef.current = prevInteractions; } // We're done performing work. Time to clean up. isWorking = false; ReactCurrentDispatcher.current = previousDispatcher; resetContextDependences(); resetHooks(); // Yield back to main thread. if (didFatal) { var _didCompleteRoot = false; stopWorkLoopTimer(interruptedBy, _didCompleteRoot); interruptedBy = null; // There was a fatal error. nextRoot = null; onFatal(root); return; } if (nextUnitOfWork !== null) { // There's still remaining async work in this tree, but we ran out of time // in the current frame. Yield back to the renderer. Unless we're // interrupted by a higher priority update, we'll continue later from where // we left off. var _didCompleteRoot2 = false; stopWorkLoopTimer(interruptedBy, _didCompleteRoot2); interruptedBy = null; onYield(root); return; } // We completed the whole tree. var didCompleteRoot = true; stopWorkLoopTimer(interruptedBy, didCompleteRoot); var rootWorkInProgress = root.current.alternate; !(rootWorkInProgress !== null) ? reactProdInvariant('281') : void 0; // `nextRoot` points to the in-progress root. A non-null value indicates // that we're in the middle of an async render. Set it to null to indicate // there's no more work to be done in the current batch. nextRoot = null; interruptedBy = null; if (nextRenderDidError) { // There was an error if (hasLowerPriorityWork(root, expirationTime)) { // There's lower priority work. If so, it may have the effect of fixing // the exception that was just thrown. Exit without committing. This is // similar to a suspend, but without a timeout because we're not waiting // for a promise to resolve. React will restart at the lower // priority level. markSuspendedPriorityLevel(root, expirationTime); var suspendedExpirationTime = expirationTime; var rootExpirationTime = root.expirationTime; onSuspend(root, rootWorkInProgress, suspendedExpirationTime, rootExpirationTime, -1 // Indicates no timeout ); return; } else if ( // There's no lower priority work, but we're rendering asynchronously. // Synchronously attempt to render the same level one more time. This is // similar to a suspend, but without a timeout because we're not waiting // for a promise to resolve. !root.didError && isYieldy) { root.didError = true; var _suspendedExpirationTime = root.nextExpirationTimeToWorkOn = expirationTime; var _rootExpirationTime = root.expirationTime = Sync; onSuspend(root, rootWorkInProgress, _suspendedExpirationTime, _rootExpirationTime, -1 // Indicates no timeout ); return; } } if (isYieldy && nextLatestAbsoluteTimeoutMs !== -1) { // The tree was suspended. var _suspendedExpirationTime2 = expirationTime; markSuspendedPriorityLevel(root, _suspendedExpirationTime2); // Find the earliest uncommitted expiration time in the tree, including // work that is suspended. The timeout threshold cannot be longer than // the overall expiration. var earliestExpirationTime = findEarliestOutstandingPriorityLevel(root, expirationTime); var earliestExpirationTimeMs = expirationTimeToMs(earliestExpirationTime); if (earliestExpirationTimeMs < nextLatestAbsoluteTimeoutMs) { nextLatestAbsoluteTimeoutMs = earliestExpirationTimeMs; } // Subtract the current time from the absolute timeout to get the number // of milliseconds until the timeout. In other words, convert an absolute // timestamp to a relative time. This is the value that is passed // to `setTimeout`. var currentTimeMs = expirationTimeToMs(requestCurrentTime()); var msUntilTimeout = nextLatestAbsoluteTimeoutMs - currentTimeMs; msUntilTimeout = msUntilTimeout < 0 ? 0 : msUntilTimeout; // TODO: Account for the Just Noticeable Difference var _rootExpirationTime2 = root.expirationTime; onSuspend(root, rootWorkInProgress, _suspendedExpirationTime2, _rootExpirationTime2, msUntilTimeout); return; } // Ready to commit. onComplete(root, rootWorkInProgress, expirationTime); } function captureCommitPhaseError(sourceFiber, value) { var expirationTime = Sync; var fiber = sourceFiber.return; while (fiber !== null) { switch (fiber.tag) { case ClassComponent: var ctor = fiber.type; var instance = fiber.stateNode; if (typeof ctor.getDerivedStateFromError === 'function' || typeof instance.componentDidCatch === 'function' && !isAlreadyFailedLegacyErrorBoundary(instance)) { var errorInfo = createCapturedValue(value, sourceFiber); var update = createClassErrorUpdate(fiber, errorInfo, expirationTime); enqueueUpdate(fiber, update); scheduleWork(fiber, expirationTime); return; } break; case HostRoot: { var _errorInfo = createCapturedValue(value, sourceFiber); var _update = createRootErrorUpdate(fiber, _errorInfo, expirationTime); enqueueUpdate(fiber, _update); scheduleWork(fiber, expirationTime); return; } } fiber = fiber.return; } if (sourceFiber.tag === HostRoot) { // Error was thrown at the root. There is no parent, so the root // itself should capture it. var rootFiber = sourceFiber; var _errorInfo2 = createCapturedValue(value, rootFiber); var _update2 = createRootErrorUpdate(rootFiber, _errorInfo2, expirationTime); enqueueUpdate(rootFiber, _update2); scheduleWork(rootFiber, expirationTime); } } function computeThreadID(expirationTime, interactionThreadID) { // Interaction threads are unique per root and expiration time. return expirationTime * 1000 + interactionThreadID; } function computeExpirationForFiber(currentTime, fiber) { var priorityLevel = unstable_getCurrentPriorityLevel(); var expirationTime = void 0; if ((fiber.mode & ConcurrentMode) === NoContext) { // Outside of concurrent mode, updates are always synchronous. expirationTime = Sync; } else if (isWorking && !isCommitting$1) { // During render phase, updates expire during as the current render. expirationTime = nextRenderExpirationTime; } else { switch (priorityLevel) { case unstable_ImmediatePriority: expirationTime = Sync; break; case unstable_UserBlockingPriority: expirationTime = computeInteractiveExpiration(currentTime); break; case unstable_NormalPriority: // This is a normal, concurrent update expirationTime = computeAsyncExpiration(currentTime); break; case unstable_LowPriority: case unstable_IdlePriority: expirationTime = Never; break; default: reactProdInvariant('313'); } // If we're in the middle of rendering a tree, do not update at the same // expiration time that is already rendering. if (nextRoot !== null && expirationTime === nextRenderExpirationTime) { expirationTime -= 1; } } // Keep track of the lowest pending interactive expiration time. This // allows us to synchronously flush all interactive updates // when needed. // TODO: Move this to renderer? return expirationTime; } function renderDidSuspend(root, absoluteTimeoutMs, suspendedTime) { // Schedule the timeout. if (absoluteTimeoutMs >= 0 && nextLatestAbsoluteTimeoutMs < absoluteTimeoutMs) { nextLatestAbsoluteTimeoutMs = absoluteTimeoutMs; } } function renderDidError() { nextRenderDidError = true; } function pingSuspendedRoot(root, thenable, pingTime) { // A promise that previously suspended React from committing has resolved. // If React is still suspended, try again at the previous level (pingTime). var pingCache = root.pingCache; if (pingCache !== null) { // The thenable resolved, so we no longer need to memoize, because it will // never be thrown again. pingCache.delete(thenable); } if (nextRoot !== null && nextRenderExpirationTime === pingTime) { // Received a ping at the same priority level at which we're currently // rendering. Restart from the root. nextRoot = null; } else { // Confirm that the root is still suspended at this level. Otherwise exit. if (isPriorityLevelSuspended(root, pingTime)) { // Ping at the original level markPingedPriorityLevel(root, pingTime); var rootExpirationTime = root.expirationTime; if (rootExpirationTime !== NoWork) { requestWork(root, rootExpirationTime); } } } } function retryTimedOutBoundary(boundaryFiber, thenable) { // The boundary fiber (a Suspense component) previously timed out and 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 var retryCache = void 0; if (enableSuspenseServerRenderer) { switch (boundaryFiber.tag) { case SuspenseComponent: retryCache = boundaryFiber.stateNode; break; case DehydratedSuspenseComponent: retryCache = boundaryFiber.memoizedState; break; default: reactProdInvariant('314'); } } else { retryCache = boundaryFiber.stateNode; } if (retryCache !== null) { // The thenable resolved, so we no longer need to memoize, because it will // never be thrown again. retryCache.delete(thenable); } var currentTime = requestCurrentTime(); var retryTime = computeExpirationForFiber(currentTime, boundaryFiber); var root = scheduleWorkToRoot(boundaryFiber, retryTime); if (root !== null) { markPendingPriorityLevel(root, retryTime); var rootExpirationTime = root.expirationTime; if (rootExpirationTime !== NoWork) { requestWork(root, rootExpirationTime); } } } function scheduleWorkToRoot(fiber, expirationTime) { recordScheduleUpdate(); if (fiber.expirationTime < expirationTime) { fiber.expirationTime = expirationTime; } var alternate = fiber.alternate; if (alternate !== null && alternate.expirationTime < expirationTime) { alternate.expirationTime = expirationTime; } // Walk the parent path to the root and update the child expiration time. var node = fiber.return; var root = null; if (node === null && fiber.tag === HostRoot) { root = fiber.stateNode; } else { while (node !== null) { alternate = node.alternate; if (node.childExpirationTime < expirationTime) { node.childExpirationTime = expirationTime; if (alternate !== null && alternate.childExpirationTime < expirationTime) { alternate.childExpirationTime = expirationTime; } } else if (alternate !== null && alternate.childExpirationTime < expirationTime) { alternate.childExpirationTime = expirationTime; } if (node.return === null && node.tag === HostRoot) { root = node.stateNode; break; } node = node.return; } } if (enableSchedulerTracing) { if (root !== null) { var interactions = __interactionsRef.current; if (interactions.size > 0) { var pendingInteractionMap = root.pendingInteractionMap; var pendingInteractions = pendingInteractionMap.get(expirationTime); if (pendingInteractions != null) { interactions.forEach(function (interaction) { if (!pendingInteractions.has(interaction)) { // Update the pending async work count for previously unscheduled interaction. interaction.__count++; } pendingInteractions.add(interaction); }); } else { pendingInteractionMap.set(expirationTime, new Set(interactions)); // Update the pending async work count for the current interactions. interactions.forEach(function (interaction) { interaction.__count++; }); } var subscriber = __subscriberRef.current; if (subscriber !== null) { var threadID = computeThreadID(expirationTime, root.interactionThreadID); subscriber.onWorkScheduled(interactions, threadID); } } } } return root; } function scheduleWork(fiber, expirationTime) { var root = scheduleWorkToRoot(fiber, expirationTime); if (root === null) { return; } if (!isWorking && nextRenderExpirationTime !== NoWork && expirationTime > nextRenderExpirationTime) { // This is an interruption. (Used for performance tracking.) interruptedBy = fiber; resetStack(); } markPendingPriorityLevel(root, expirationTime); if ( // If we're in the render phase, we don't need to schedule this root // for an update, because we'll do it before we exit... !isWorking || isCommitting$1 || // ...unless this is a different root than the one we're rendering. nextRoot !== root) { var rootExpirationTime = root.expirationTime; requestWork(root, rootExpirationTime); } if (nestedUpdateCount > NESTED_UPDATE_LIMIT) { // Reset this back to zero so subsequent updates don't throw. nestedUpdateCount = 0; reactProdInvariant('185'); } } function syncUpdates(fn, a, b, c, d) { return unstable_runWithPriority(unstable_ImmediatePriority, function () { return fn(a, b, c, d); }); } // TODO: Everything below this is written as if it has been lifted to the // renderers. I'll do this in a follow-up. // Linked-list of roots var firstScheduledRoot = null; var lastScheduledRoot = null; var callbackExpirationTime = NoWork; var callbackID = void 0; var isRendering = false; var nextFlushedRoot = null; var nextFlushedExpirationTime = NoWork; var hasUnhandledError = false; var unhandledError = null; var isBatchingUpdates = false; var isUnbatchingUpdates = false; var completedBatches = null; var originalStartTimeMs = now(); var currentRendererTime = msToExpirationTime(originalStartTimeMs); var currentSchedulerTime = currentRendererTime; // Use these to prevent an infinite loop of nested updates var NESTED_UPDATE_LIMIT = 50; var nestedUpdateCount = 0; var lastCommittedRootDuringThisBatch = null; function recomputeCurrentRendererTime() { var currentTimeMs = now() - originalStartTimeMs; currentRendererTime = msToExpirationTime(currentTimeMs); } function scheduleCallbackWithExpirationTime(root, expirationTime) { if (callbackExpirationTime !== NoWork) { // A callback is already scheduled. Check its expiration time (timeout). if (expirationTime < callbackExpirationTime) { // Existing callback has sufficient timeout. Exit. return; } else { if (callbackID !== null) { // Existing callback has insufficient timeout. Cancel and schedule a // new one. cancelDeferredCallback$$1(callbackID); } } // The request callback timer is already running. Don't start a new one. } else { startRequestCallbackTimer(); } callbackExpirationTime = expirationTime; var currentMs = now() - originalStartTimeMs; var expirationTimeMs = expirationTimeToMs(expirationTime); var timeout = expirationTimeMs - currentMs; callbackID = scheduleDeferredCallback$$1(performAsyncWork, { timeout: timeout }); } // For every call to renderRoot, one of onFatal, onComplete, onSuspend, and // onYield is called upon exiting. We use these in lieu of returning a tuple. // I've also chosen not to inline them into renderRoot because these will // eventually be lifted into the renderer. function onFatal(root) { root.finishedWork = null; } function onComplete(root, finishedWork, expirationTime) { root.pendingCommitExpirationTime = expirationTime; root.finishedWork = finishedWork; } function onSuspend(root, finishedWork, suspendedExpirationTime, rootExpirationTime, msUntilTimeout) { root.expirationTime = rootExpirationTime; if (msUntilTimeout === 0 && !shouldYieldToRenderer()) { // Don't wait an additional tick. Commit the tree immediately. root.pendingCommitExpirationTime = suspendedExpirationTime; root.finishedWork = finishedWork; } else if (msUntilTimeout > 0) { // Wait `msUntilTimeout` milliseconds before committing. root.timeoutHandle = scheduleTimeout(onTimeout.bind(null, root, finishedWork, suspendedExpirationTime), msUntilTimeout); } } function onYield(root) { root.finishedWork = null; } function onTimeout(root, finishedWork, suspendedExpirationTime) { // The root timed out. Commit it. root.pendingCommitExpirationTime = suspendedExpirationTime; root.finishedWork = finishedWork; // Read the current time before entering the commit phase. We can be // certain this won't cause tearing related to batching of event updates // because we're at the top of a timer event. recomputeCurrentRendererTime(); currentSchedulerTime = currentRendererTime; flushRoot(root, suspendedExpirationTime); } function onCommit(root, expirationTime) { root.expirationTime = expirationTime; root.finishedWork = null; } function requestCurrentTime() { // requestCurrentTime is called by the scheduler to compute an expiration // time. // // Expiration times are computed by adding to the current time (the start // time). However, if two updates are scheduled within the same event, we // should treat their start times as simultaneous, even if the actual clock // time has advanced between the first and second call. // In other words, because expiration times determine how updates are batched, // we want all updates of like priority that occur within the same event to // receive the same expiration time. Otherwise we get tearing. // // We keep track of two separate times: the current "renderer" time and the // current "scheduler" time. The renderer time can be updated whenever; it // only exists to minimize the calls performance.now. // // But the scheduler time can only be updated if there's no pending work, or // if we know for certain that we're not in the middle of an event. if (isRendering) { // We're already rendering. Return the most recently read time. return currentSchedulerTime; } // Check if there's pending work. findHighestPriorityRoot(); if (nextFlushedExpirationTime === NoWork || nextFlushedExpirationTime === Never) { // If there's no pending work, or if the pending work is offscreen, we can // read the current time without risk of tearing. recomputeCurrentRendererTime(); currentSchedulerTime = currentRendererTime; return currentSchedulerTime; } // There's already pending work. We might be in the middle of a browser // event. If we were to read the current time, it could cause multiple updates // within the same event to receive different expiration times, leading to // tearing. Return the last read time. During the next idle callback, the // time will be updated. return currentSchedulerTime; } // requestWork is called by the scheduler whenever a root receives an update. // It's up to the renderer to call renderRoot at some point in the future. function requestWork(root, expirationTime) { addRootToSchedule(root, expirationTime); if (isRendering) { // Prevent reentrancy. Remaining work will be scheduled at the end of // the currently rendering batch. return; } if (isBatchingUpdates) { // Flush work at the end of the batch. if (isUnbatchingUpdates) { // ...unless we're inside unbatchedUpdates, in which case we should // flush it now. nextFlushedRoot = root; nextFlushedExpirationTime = Sync; performWorkOnRoot(root, Sync, false); } return; } // TODO: Get rid of Sync and use current time? if (expirationTime === Sync) { performSyncWork(); } else { scheduleCallbackWithExpirationTime(root, expirationTime); } } function addRootToSchedule(root, expirationTime) { // Add the root to the schedule. // Check if this root is already part of the schedule. if (root.nextScheduledRoot === null) { // This root is not already scheduled. Add it. root.expirationTime = expirationTime; if (lastScheduledRoot === null) { firstScheduledRoot = lastScheduledRoot = root; root.nextScheduledRoot = root; } else { lastScheduledRoot.nextScheduledRoot = root; lastScheduledRoot = root; lastScheduledRoot.nextScheduledRoot = firstScheduledRoot; } } else { // This root is already scheduled, but its priority may have increased. var remainingExpirationTime = root.expirationTime; if (expirationTime > remainingExpirationTime) { // Update the priority. root.expirationTime = expirationTime; } } } function findHighestPriorityRoot() { var highestPriorityWork = NoWork; var highestPriorityRoot = null; if (lastScheduledRoot !== null) { var previousScheduledRoot = lastScheduledRoot; var root = firstScheduledRoot; while (root !== null) { var remainingExpirationTime = root.expirationTime; if (remainingExpirationTime === NoWork) { // This root no longer has work. Remove it from the scheduler. // TODO: This check is redudant, but Flow is confused by the branch // below where we set lastScheduledRoot to null, even though we break // from the loop right after. !(previousScheduledRoot !== null && lastScheduledRoot !== null) ? reactProdInvariant('244') : void 0; if (root === root.nextScheduledRoot) { // This is the only root in the list. root.nextScheduledRoot = null; firstScheduledRoot = lastScheduledRoot = null; break; } else if (root === firstScheduledRoot) { // This is the first root in the list. var next = root.nextScheduledRoot; firstScheduledRoot = next; lastScheduledRoot.nextScheduledRoot = next; root.nextScheduledRoot = null; } else if (root === lastScheduledRoot) { // This is the last root in the list. lastScheduledRoot = previousScheduledRoot; lastScheduledRoot.nextScheduledRoot = firstScheduledRoot; root.nextScheduledRoot = null; break; } else { previousScheduledRoot.nextScheduledRoot = root.nextScheduledRoot; root.nextScheduledRoot = null; } root = previousScheduledRoot.nextScheduledRoot; } else { if (remainingExpirationTime > highestPriorityWork) { // Update the priority, if it's higher highestPriorityWork = remainingExpirationTime; highestPriorityRoot = root; } if (root === lastScheduledRoot) { break; } if (highestPriorityWork === Sync) { // Sync is highest priority by definition so // we can stop searching. break; } previousScheduledRoot = root; root = root.nextScheduledRoot; } } } nextFlushedRoot = highestPriorityRoot; nextFlushedExpirationTime = highestPriorityWork; } // TODO: This wrapper exists because many of the older tests (the ones that use // flushDeferredPri) rely on the number of times `shouldYield` is called. We // should get rid of it. var didYield = false; function shouldYieldToRenderer() { if (didYield) { return true; } if (shouldYield$$1()) { didYield = true; return true; } return false; } function performAsyncWork() { try { if (!shouldYieldToRenderer()) { // The callback timed out. That means at least one update has expired. // Iterate through the root schedule. If they contain expired work, set // the next render expiration time to the current time. This has the effect // of flushing all expired work in a single batch, instead of flushing each // level one at a time. if (firstScheduledRoot !== null) { recomputeCurrentRendererTime(); var root = firstScheduledRoot; do { didExpireAtExpirationTime(root, currentRendererTime); // The root schedule is circular, so this is never null. root = root.nextScheduledRoot; } while (root !== firstScheduledRoot); } } performWork(NoWork, true); } finally { didYield = false; } } function performSyncWork() { performWork(Sync, false); } function performWork(minExpirationTime, isYieldy) { // Keep working on roots until there's no more work, or until there's a higher // priority event. findHighestPriorityRoot(); if (isYieldy) { recomputeCurrentRendererTime(); currentSchedulerTime = currentRendererTime; if (enableUserTimingAPI) { var didExpire = nextFlushedExpirationTime > currentRendererTime; var timeout = expirationTimeToMs(nextFlushedExpirationTime); stopRequestCallbackTimer(didExpire, timeout); } while (nextFlushedRoot !== null && nextFlushedExpirationTime !== NoWork && minExpirationTime <= nextFlushedExpirationTime && !(didYield && currentRendererTime > nextFlushedExpirationTime)) { performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime, currentRendererTime > nextFlushedExpirationTime); findHighestPriorityRoot(); recomputeCurrentRendererTime(); currentSchedulerTime = currentRendererTime; } } else { while (nextFlushedRoot !== null && nextFlushedExpirationTime !== NoWork && minExpirationTime <= nextFlushedExpirationTime) { performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime, false); findHighestPriorityRoot(); } } // We're done flushing work. Either we ran out of time in this callback, // or there's no more work left with sufficient priority. // If we're inside a callback, set this to false since we just completed it. if (isYieldy) { callbackExpirationTime = NoWork; callbackID = null; } // If there's work left over, schedule a new callback. if (nextFlushedExpirationTime !== NoWork) { scheduleCallbackWithExpirationTime(nextFlushedRoot, nextFlushedExpirationTime); } // Clean-up. finishRendering(); } function flushRoot(root, expirationTime) { !!isRendering ? reactProdInvariant('253') : void 0; // Perform work on root as if the given expiration time is the current time. // This has the effect of synchronously flushing all work up to and // including the given time. nextFlushedRoot = root; nextFlushedExpirationTime = expirationTime; performWorkOnRoot(root, expirationTime, false); // Flush any sync work that was scheduled by lifecycles performSyncWork(); } function finishRendering() { nestedUpdateCount = 0; lastCommittedRootDuringThisBatch = null; if (completedBatches !== null) { var batches = completedBatches; completedBatches = null; for (var i = 0; i < batches.length; i++) { var batch = batches[i]; try { batch._onComplete(); } catch (error) { if (!hasUnhandledError) { hasUnhandledError = true; unhandledError = error; } } } } if (hasUnhandledError) { var error = unhandledError; unhandledError = null; hasUnhandledError = false; throw error; } } function performWorkOnRoot(root, expirationTime, isYieldy) { !!isRendering ? reactProdInvariant('245') : void 0; isRendering = true; // Check if this is async work or sync/expired work. if (!isYieldy) { // Flush work without yielding. // TODO: Non-yieldy work does not necessarily imply expired work. A renderer // may want to perform some work without yielding, but also without // requiring the root to complete (by triggering placeholders). var finishedWork = root.finishedWork; if (finishedWork !== null) { // This root is already complete. We can commit it. completeRoot(root, finishedWork, expirationTime); } else { root.finishedWork = null; // If this root previously suspended, clear its existing timeout, since // we're about to try rendering again. var timeoutHandle = root.timeoutHandle; if (timeoutHandle !== noTimeout) { root.timeoutHandle = noTimeout; // $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above cancelTimeout(timeoutHandle); } renderRoot(root, isYieldy); finishedWork = root.finishedWork; if (finishedWork !== null) { // We've completed the root. Commit it. completeRoot(root, finishedWork, expirationTime); } } } else { // Flush async work. var _finishedWork = root.finishedWork; if (_finishedWork !== null) { // This root is already complete. We can commit it. completeRoot(root, _finishedWork, expirationTime); } else { root.finishedWork = null; // If this root previously suspended, clear its existing timeout, since // we're about to try rendering again. var _timeoutHandle = root.timeoutHandle; if (_timeoutHandle !== noTimeout) { root.timeoutHandle = noTimeout; // $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above cancelTimeout(_timeoutHandle); } renderRoot(root, isYieldy); _finishedWork = root.finishedWork; if (_finishedWork !== null) { // We've completed the root. Check the if we should yield one more time // before committing. if (!shouldYieldToRenderer()) { // Still time left. Commit the root. completeRoot(root, _finishedWork, expirationTime); } else { // There's no time left. Mark this root as complete. We'll come // back and commit it later. root.finishedWork = _finishedWork; } } } } isRendering = false; } function completeRoot(root, finishedWork, expirationTime) { // Check if there's a batch that matches this expiration time. var firstBatch = root.firstBatch; if (firstBatch !== null && firstBatch._expirationTime >= expirationTime) { if (completedBatches === null) { completedBatches = [firstBatch]; } else { completedBatches.push(firstBatch); } if (firstBatch._defer) { // This root is blocked from committing by a batch. Unschedule it until // we receive another update. root.finishedWork = finishedWork; root.expirationTime = NoWork; return; } } // Commit the root. root.finishedWork = null; // Check if this is a nested update (a sync update scheduled during the // commit phase). if (root === lastCommittedRootDuringThisBatch) { // If the next root is the same as the previous root, this is a nested // update. To prevent an infinite loop, increment the nested update count. nestedUpdateCount++; } else { // Reset whenever we switch roots. lastCommittedRootDuringThisBatch = root; nestedUpdateCount = 0; } unstable_runWithPriority(unstable_ImmediatePriority, function () { commitRoot(root, finishedWork); }); } function onUncaughtError(error) { !(nextFlushedRoot !== null) ? reactProdInvariant('246') : void 0; // Unschedule this root so we don't work on it again until there's // another update. nextFlushedRoot.expirationTime = NoWork; if (!hasUnhandledError) { hasUnhandledError = true; unhandledError = error; } } // TODO: Batching should be implemented at the renderer level, not inside // the reconciler. function batchedUpdates(fn, a) { var previousIsBatchingUpdates = isBatchingUpdates; isBatchingUpdates = true; try { return fn(a); } finally { isBatchingUpdates = previousIsBatchingUpdates; if (!isBatchingUpdates && !isRendering) { performSyncWork(); } } } // TODO: Batching should be implemented at the renderer level, not within // the reconciler. function flushSync(fn, a) { !!isRendering ? reactProdInvariant('187') : void 0; var previousIsBatchingUpdates = isBatchingUpdates; isBatchingUpdates = true; try { return syncUpdates(fn, a); } finally { isBatchingUpdates = previousIsBatchingUpdates; performSyncWork(); } } function getContextForSubtree(parentComponent) { if (!parentComponent) { return emptyContextObject; } var fiber = get(parentComponent); var parentContext = findCurrentUnmaskedContext(fiber); if (fiber.tag === ClassComponent) { var Component = fiber.type; if (isContextProvider(Component)) { return processChildContext(fiber, Component, parentContext); } } return parentContext; } function scheduleRootUpdate(current$$1, element, expirationTime, callback) { var update = createUpdate(expirationTime); // Caution: React DevTools currently depends on this property // being called "element". update.payload = { element: element }; callback = callback === undefined ? null : callback; if (callback !== null) { update.callback = callback; } flushPassiveEffects$1(); enqueueUpdate(current$$1, update); scheduleWork(current$$1, expirationTime); return expirationTime; } function updateContainerAtExpirationTime(element, container, parentComponent, expirationTime, callback) { // TODO: If this is a nested container, this won't be the root. var current$$1 = container.current; var context = getContextForSubtree(parentComponent); if (container.context === null) { container.context = context; } else { container.pendingContext = context; } return scheduleRootUpdate(current$$1, element, expirationTime, callback); } function createContainer(containerInfo, isConcurrent, hydrate) { return createFiberRoot(containerInfo, isConcurrent, hydrate); } function updateContainer(element, container, parentComponent, callback) { var current$$1 = container.current; var currentTime = requestCurrentTime(); var expirationTime = computeExpirationForFiber(currentTime, current$$1); return updateContainerAtExpirationTime(element, container, parentComponent, expirationTime, callback); } function getPublicRootInstance(container) { var containerFiber = container.current; if (!containerFiber.child) { return null; } switch (containerFiber.child.tag) { case HostComponent: return getPublicInstance(containerFiber.child.stateNode); default: return containerFiber.child.stateNode; } } var overrideProps = null; function injectIntoDevTools(devToolsConfig) { var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher; return injectInternals(_assign({}, devToolsConfig, { overrideProps: overrideProps, currentDispatcherRef: ReactCurrentDispatcher, findHostInstanceByFiber: function (fiber) { var hostFiber = findCurrentHostFiber(fiber); if (hostFiber === null) { return null; } return hostFiber.stateNode; }, findFiberByHostInstance: function (instance) { if (!findFiberByHostInstance) { // Might not be implemented by the renderer. return null; } return findFiberByHostInstance(instance); } })); } // This file intentionally does *not* have the Flow annotation. // Don't add it. See `./inline-typed.js` for an explanation. // TODO: this is special because it gets imported during build. var ReactVersion = '16.8.6'; var _createClass = function () { 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); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } // for .act's return value 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; } 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, _children = _inst$props.children, _props = _objectWithoutProperties(_inst$props, ['children']); /* 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]); 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); } } function childrenToTree(node) { if (!node) { return null; } var children = nodeAndSiblingsArray(node); if (children.length === 0) { return null; } else if (children.length === 1) { return toTree(children[0]); } return flatten(children.map(toTree)); } function nodeAndSiblingsArray(nodeWithSibling) { var array = []; var node = nodeWithSibling; while (node != null) { array.push(node); node = node.sibling; } return array; } function flatten(arr) { var result = []; var stack = [{ i: 0, array: arr }]; while (stack.length) { var n = stack.pop(); while (n.i < n.array.length) { var el = n.array[n.i]; n.i += 1; if (Array.isArray(el)) { stack.push(n); stack.push({ i: 0, array: el }); break; } result.push(el); } } return result; } function toTree(node) { if (node == null) { return null; } switch (node.tag) { case HostRoot: return childrenToTree(node.child); case HostPortal: return childrenToTree(node.child); case ClassComponent: return { nodeType: 'component', type: node.type, props: _assign({}, node.memoizedProps), instance: node.stateNode, rendered: childrenToTree(node.child) }; case FunctionComponent: case SimpleMemoComponent: return { nodeType: 'component', type: node.type, props: _assign({}, node.memoizedProps), instance: null, rendered: childrenToTree(node.child) }; 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 HostText: return node.stateNode.text; case Fragment: case ContextProvider: case ContextConsumer: case Mode: case Profiler: case ForwardRef: case MemoComponent: case IncompleteClassComponent: return childrenToTree(node.child); default: reactProdInvariant('214', node.tag); } } var validWrapperTypes = new Set([FunctionComponent, ClassComponent, HostComponent, ForwardRef, MemoComponent, SimpleMemoComponent, // Normally skipped, but used when there's more than one root child. HostRoot]); function getChildren(parent) { var children = []; var startingNode = parent; var node = startingNode; if (node.child === null) { return children; } node.child.return = node; node = node.child; outer: while (true) { var descend = false; if (validWrapperTypes.has(node.tag)) { children.push(wrapFiber(node)); } else if (node.tag === HostText) { children.push('' + node.memoizedProps); } else { descend = true; } if (descend && node.child !== null) { node.child.return = node; node = node.child; continue; } while (node.sibling === null) { if (node.return === startingNode) { break outer; } node = node.return; } node.sibling.return = node.return; node = node.sibling; } return children; } var ReactTestInstance = function () { ReactTestInstance.prototype._currentFiber = function _currentFiber() { // Throws if this component has been unmounted. var fiber = findCurrentFiberUsingSlowPath(this._fiber); !(fiber !== null) ? reactProdInvariant('224') : void 0; return fiber; }; function ReactTestInstance(fiber) { _classCallCheck(this, ReactTestInstance); !validWrapperTypes.has(fiber.tag) ? reactProdInvariant('225', fiber.tag) : void 0; this._fiber = fiber; } // Custom search functions ReactTestInstance.prototype.find = function find(predicate) { return expectOne(this.findAll(predicate, { deep: false }), 'matching custom predicate: ' + predicate.toString()); }; ReactTestInstance.prototype.findByType = function findByType(type) { return expectOne(this.findAllByType(type, { deep: false }), 'with node type: "' + (type.displayName || type.name) + '"'); }; ReactTestInstance.prototype.findByProps = function findByProps(props) { return expectOne(this.findAllByProps(props, { deep: false }), 'with props: ' + JSON.stringify(props)); }; ReactTestInstance.prototype.findAll = function findAll(predicate) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; return _findAll(this, predicate, options); }; ReactTestInstance.prototype.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); }; ReactTestInstance.prototype.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); }; _createClass(ReactTestInstance, [{ key: 'instance', get: function () { if (this._fiber.tag === HostComponent) { 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); } parent = parent.return; } return null; } }, { key: 'children', get: function () { return getChildren(this._currentFiber()); } }]); return ReactTestInstance; }(); function _findAll(root, predicate, options) { var deep = options ? options.deep : true; var results = []; if (predicate(root)) { results.push(root); if (!deep) { return results; } } root.children.forEach(function (child) { if (typeof child === 'string') { return; } results.push.apply(results, _findAll(child, predicate, options)); }); 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); } function propsMatch(props, filter) { for (var key in filter) { if (props[key] !== filter[key]) { return false; } } return true; } var ReactTestRendererFiber = { create: function (element, options) { var createNodeMock = defaultTestOptions.createNodeMock; var isConcurrent = false; if (typeof options === 'object' && options !== null) { if (typeof options.createNodeMock === 'function') { createNodeMock = options.createNodeMock; } if (options.unstable_isConcurrent === true) { isConcurrent = true; } } var container = { children: [], createNodeMock: createNodeMock, tag: 'CONTAINER' }; var root = createContainer(container, isConcurrent, false); !(root != null) ? reactProdInvariant('215') : void 0; updateContainer(element, root, null, null); var entry = { 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 === 0) { return null; } if (container.children.length === 1) { return toJSON(container.children[0]); } 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]); } var renderedChildren = null; 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 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(null, root, null, null); container = null; root = null; }, getInstance: function () { if (root == null || root.current == null) { return null; } return getPublicRootInstance(root); }, unstable_flushAll: flushAll, unstable_flushSync: function (fn) { clearYields(); return flushSync(fn); }, unstable_flushNumberOfYields: flushNumberOfYields, unstable_clearYields: clearYields }; 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); 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. return wrapFiber(root.current); } } }); return entry; }, unstable_yield: yieldValue, unstable_clearYields: clearYields, /* eslint-disable camelcase */ unstable_batchedUpdates: batchedUpdates, /* eslint-enable camelcase */ unstable_setNowImplementation: setNowImplementation, act: function (callback) { // note: keep these warning messages in sync with // createNoop.js and ReactTestUtils.js var result = batchedUpdates(callback); flushPassiveEffects(); // we want the user to not expect a return, // but we want to warn if they use it like they can await on it. return { then: function () { } }; } }; // root used to flush effects during .act() calls var actRoot = createContainer({ children: [], createNodeMock: defaultTestOptions.createNodeMock, tag: 'CONTAINER' }, true, false); function flushPassiveEffects() { // Trick to flush passive effects without exposing an internal API: // Create a throwaway root and schedule a dummy update on it. updateContainer(null, actRoot, null, null); } var fiberToWrapper = new WeakMap(); function wrapFiber(fiber) { var wrapper = fiberToWrapper.get(fiber); if (wrapper === undefined && fiber.alternate !== null) { wrapper = fiberToWrapper.get(fiber.alternate); } if (wrapper === undefined) { wrapper = new ReactTestInstance(fiber); fiberToWrapper.set(fiber, wrapper); } return wrapper; } // Enable ReactTestRenderer to be used to test DevTools integration. injectIntoDevTools({ findFiberByHostInstance: function () { throw new Error('TestRenderer does not support findFiberByHostInstance()'); }, bundleType: 0, version: ReactVersion, rendererPackageName: 'react-test-renderer' }); var ReactTestRenderer = ({ default: ReactTestRendererFiber }); var ReactTestRenderer$1 = ( ReactTestRenderer && ReactTestRendererFiber ) || ReactTestRenderer; // TODO: decide on the top-level export form. // This is hacky but makes it work with both Rollup and Jest. var reactTestRenderer = ReactTestRenderer$1.default || ReactTestRenderer$1; return reactTestRenderer; })));