diff --git a/packages/react-native/Libraries/Renderer/implementations/ReactFabric-dev.js b/packages/react-native/Libraries/Renderer/implementations/ReactFabric-dev.js index 8b33632a90ce3f..2d08a1c3820f19 100644 --- a/packages/react-native/Libraries/Renderer/implementations/ReactFabric-dev.js +++ b/packages/react-native/Libraries/Renderer/implementations/ReactFabric-dev.js @@ -8,7 +8,7 @@ * @nolint * @providesModule ReactFabric-dev * @preventMunge - * @generated SignedSource<> + * @generated SignedSource<> */ "use strict"; @@ -3229,18 +3229,15 @@ to return true:wantsResponderID| | // where it would do it. } - var debugRenderPhaseSideEffectsForStrictMode = false; var enableSchedulingProfiler = false; var enableProfilerTimer = true; var enableProfilerCommitHooks = true; var enableProfilerNestedUpdatePhase = true; var syncLaneExpirationMs = 250; var transitionLaneExpirationMs = 5000; - var createRootStrictEffectsByDefault = false; var enableLazyContextPropagation = false; var enableLegacyHidden = false; var enableAsyncActions = false; - var alwaysThrottleRetries = true; var passChildrenWhenCloningPersistedNodes = false; var NoFlags$1 = @@ -3380,6 +3377,103 @@ to return true:wantsResponderID| | var NormalPriority = Scheduler.unstable_NormalPriority; var IdlePriority = Scheduler.unstable_IdlePriority; // this doesn't actually exist on the scheduler, but it *does* + // Helpers to patch console.logs to avoid logging during side-effect free + // replaying on render function. This currently only patches the object + // lazily which won't cover if the log function was extracted eagerly. + // We could also eagerly patch the method. + var disabledDepth = 0; + var prevLog; + var prevInfo; + var prevWarn; + var prevError; + var prevGroup; + var prevGroupCollapsed; + var prevGroupEnd; + + function disabledLog() {} + + disabledLog.__reactDisabledLog = true; + function disableLogs() { + { + if (disabledDepth === 0) { + /* eslint-disable react-internal/no-production-logging */ + prevLog = console.log; + prevInfo = console.info; + prevWarn = console.warn; + prevError = console.error; + prevGroup = console.group; + prevGroupCollapsed = console.groupCollapsed; + prevGroupEnd = console.groupEnd; // https://github.com/facebook/react/issues/19099 + + var props = { + configurable: true, + enumerable: true, + value: disabledLog, + writable: true + }; // $FlowFixMe[cannot-write] Flow thinks console is immutable. + + Object.defineProperties(console, { + info: props, + log: props, + warn: props, + error: props, + group: props, + groupCollapsed: props, + groupEnd: props + }); + /* eslint-enable react-internal/no-production-logging */ + } + + disabledDepth++; + } + } + function reenableLogs() { + { + disabledDepth--; + + if (disabledDepth === 0) { + /* eslint-disable react-internal/no-production-logging */ + var props = { + configurable: true, + enumerable: true, + writable: true + }; // $FlowFixMe[cannot-write] Flow thinks console is immutable. + + Object.defineProperties(console, { + log: assign({}, props, { + value: prevLog + }), + info: assign({}, props, { + value: prevInfo + }), + warn: assign({}, props, { + value: prevWarn + }), + error: assign({}, props, { + value: prevError + }), + group: assign({}, props, { + value: prevGroup + }), + groupCollapsed: assign({}, props, { + value: prevGroupCollapsed + }), + groupEnd: assign({}, props, { + value: prevGroupEnd + }) + }); + /* eslint-enable react-internal/no-production-logging */ + } + + if (disabledDepth < 0) { + error( + "disabledDepth fell below zero. " + + "This is a bug in React. Please file an issue." + ); + } + } + } + var rendererID = null; var injectedHook = null; var hasLoggedError = false; @@ -3538,6 +3632,15 @@ to return true:wantsResponderID| | } } } + function setIsStrictModeForDevtools(newIsStrictMode) { + { + if (newIsStrictMode) { + disableLogs(); + } else { + reenableLogs(); + } + } + } // Profiler API hooks function injectProfilingHooks(profilingHooks) {} @@ -4881,7 +4984,6 @@ to return true:wantsResponderID| | var REACT_PROFILER_TYPE = Symbol.for("react.profiler"); var REACT_PROVIDER_TYPE = Symbol.for("react.provider"); var REACT_CONTEXT_TYPE = Symbol.for("react.context"); - var REACT_SERVER_CONTEXT_TYPE = Symbol.for("react.server_context"); var REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"); var REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"); var REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"); @@ -5407,7 +5509,7 @@ to return true:wantsResponderID| | return false; } - function describeBuiltInComponentFrame(name, source, ownerFn) { + function describeBuiltInComponentFrame(name, ownerFn) { { var ownerName = null; @@ -5415,7 +5517,7 @@ to return true:wantsResponderID| | ownerName = ownerFn.displayName || ownerFn.name || null; } - return describeComponentFrame(name, source, ownerName); + return describeComponentFrame(name, ownerName); } } @@ -5423,43 +5525,23 @@ to return true:wantsResponderID| | var PossiblyWeakMap$1 = typeof WeakMap === "function" ? WeakMap : Map; new PossiblyWeakMap$1(); } - var BEFORE_SLASH_RE = /^(.*)[\\\/]/; - function describeComponentFrame(name, source, ownerName) { + function describeComponentFrame(name, ownerName) { var sourceInfo = ""; - if (source) { - var path = source.fileName; - var fileName = path.replace(BEFORE_SLASH_RE, ""); // In DEV, include code for a common special case: - // prefer "folder/index.js" instead of just "index.js". - - if (/^index\./.test(fileName)) { - var match = path.match(BEFORE_SLASH_RE); - - if (match) { - var pathBeforeSlash = match[1]; - - if (pathBeforeSlash) { - var folderName = pathBeforeSlash.replace(BEFORE_SLASH_RE, ""); - fileName = folderName + "/" + fileName; - } - } - } - - sourceInfo = " (at " + fileName + ":" + source.lineNumber + ")"; - } else if (ownerName) { + if (ownerName) { sourceInfo = " (created by " + ownerName + ")"; } return "\n in " + (name || "Unknown") + sourceInfo; } - function describeClassComponentFrame(ctor, source, ownerFn) { + function describeClassComponentFrame(ctor, ownerFn) { { - return describeFunctionComponentFrame(ctor, source, ownerFn); + return describeFunctionComponentFrame(ctor, ownerFn); } } - function describeFunctionComponentFrame(fn, source, ownerFn) { + function describeFunctionComponentFrame(fn, ownerFn) { { if (!fn) { return ""; @@ -5472,45 +5554,41 @@ to return true:wantsResponderID| | ownerName = ownerFn.displayName || ownerFn.name || null; } - return describeComponentFrame(name, source, ownerName); + return describeComponentFrame(name, ownerName); } } - function describeUnknownElementTypeFrameInDEV(type, source, ownerFn) { + function describeUnknownElementTypeFrameInDEV(type, ownerFn) { if (type == null) { return ""; } if (typeof type === "function") { { - return describeFunctionComponentFrame(type, source, ownerFn); + return describeFunctionComponentFrame(type, ownerFn); } } if (typeof type === "string") { - return describeBuiltInComponentFrame(type, source, ownerFn); + return describeBuiltInComponentFrame(type, ownerFn); } switch (type) { case REACT_SUSPENSE_TYPE: - return describeBuiltInComponentFrame("Suspense", source, ownerFn); + return describeBuiltInComponentFrame("Suspense", ownerFn); case REACT_SUSPENSE_LIST_TYPE: - return describeBuiltInComponentFrame("SuspenseList", source, ownerFn); + return describeBuiltInComponentFrame("SuspenseList", ownerFn); } if (typeof type === "object") { switch (type.$$typeof) { case REACT_FORWARD_REF_TYPE: - return describeFunctionComponentFrame(type.render, source, ownerFn); + return describeFunctionComponentFrame(type.render, ownerFn); case REACT_MEMO_TYPE: // Memo may contain any component type so we recursively resolve it. - return describeUnknownElementTypeFrameInDEV( - type.type, - source, - ownerFn - ); + return describeUnknownElementTypeFrameInDEV(type.type, ownerFn); case REACT_LAZY_TYPE: { var lazyComponent = type; @@ -5521,7 +5599,6 @@ to return true:wantsResponderID| | // Lazy may contain any component type so we recursively resolve it. return describeUnknownElementTypeFrameInDEV( init(payload), - source, ownerFn ); } catch (x) {} @@ -5544,7 +5621,6 @@ to return true:wantsResponderID| | var owner = element._owner; var stack = describeUnknownElementTypeFrameInDEV( element.type, - element._source, owner ? owner.type : null ); ReactDebugCurrentFrame$1.setExtraStackFrame(stack); @@ -6368,3686 +6444,3665 @@ to return true:wantsResponderID| | } } - var UpdateState = 0; - var ReplaceState = 1; - var ForceUpdate = 2; - var CaptureUpdate = 3; // Global state that is reset at the beginning of calling `processUpdateQueue`. - // It should only be read right after calling `processUpdateQueue`, via - // `checkHasForceUpdateAfterProcessing`. - - var hasForceUpdate = false; - var didWarnUpdateInsideUpdate; - var currentlyProcessingQueue; - - { - didWarnUpdateInsideUpdate = false; - currentlyProcessingQueue = null; - } - - function initializeUpdateQueue(fiber) { - var queue = { - baseState: fiber.memoizedState, - firstBaseUpdate: null, - lastBaseUpdate: null, - shared: { - pending: null, - lanes: NoLanes, - hiddenCallbacks: null - }, - callbacks: null - }; - fiber.updateQueue = queue; - } - function cloneUpdateQueue(current, workInProgress) { - // Clone the update queue from current. Unless it's already a clone. - var queue = workInProgress.updateQueue; - var currentQueue = current.updateQueue; - - if (queue === currentQueue) { - var clone = { - baseState: currentQueue.baseState, - firstBaseUpdate: currentQueue.firstBaseUpdate, - lastBaseUpdate: currentQueue.lastBaseUpdate, - shared: currentQueue.shared, - callbacks: null - }; - workInProgress.updateQueue = clone; - } - } - function createUpdate(lane) { - var update = { - lane: lane, - tag: UpdateState, - payload: null, - callback: null, - next: null - }; - return update; - } - function enqueueUpdate(fiber, update, lane) { - var updateQueue = fiber.updateQueue; - - if (updateQueue === null) { - // Only occurs if the fiber has been unmounted. - return null; - } + var ReactCurrentActQueue$3 = ReactSharedInternals.ReactCurrentActQueue; // A linked list of all the roots with pending work. In an idiomatic app, + // there's only a single root, but we do support multi root apps, hence this + // extra complexity. But this module is optimized for the single root case. - var sharedQueue = updateQueue.shared; + var firstScheduledRoot = null; + var lastScheduledRoot = null; // Used to prevent redundant mircotasks from being scheduled. - { - if ( - currentlyProcessingQueue === sharedQueue && - !didWarnUpdateInsideUpdate - ) { - var componentName = getComponentNameFromFiber(fiber); + var didScheduleMicrotask = false; // `act` "microtasks" are scheduled on the `act` queue instead of an actual + // microtask, so we have to dedupe those separately. This wouldn't be an issue + // if we required all `act` calls to be awaited, which we might in the future. - error( - "An update (setState, replaceState, or forceUpdate) was scheduled " + - "from inside an update function. Update functions should be pure, " + - "with zero side-effects. Consider using componentDidUpdate or a " + - "callback.\n\nPlease update the following component: %s", - componentName - ); + var didScheduleMicrotask_act = false; // Used to quickly bail out of flushSync if there's no sync work to do. - didWarnUpdateInsideUpdate = true; + var mightHavePendingSyncWork = false; + var isFlushingWork = false; + var currentEventTransitionLane = NoLane; + function ensureRootIsScheduled(root) { + // This function is called whenever a root receives an update. It does two + // things 1) it ensures the root is in the root schedule, and 2) it ensures + // there's a pending microtask to process the root schedule. + // + // Most of the actual scheduling logic does not happen until + // `scheduleTaskForRootDuringMicrotask` runs. + // Add the root to the schedule + if (root === lastScheduledRoot || root.next !== null); + else { + if (lastScheduledRoot === null) { + firstScheduledRoot = lastScheduledRoot = root; + } else { + lastScheduledRoot.next = root; + lastScheduledRoot = root; } - } + } // Any time a root received an update, we set this to true until the next time + // we process the schedule. If it's false, then we can quickly exit flushSync + // without consulting the schedule. - if (isUnsafeClassRenderPhaseUpdate()) { - // This is an unsafe render phase update. Add directly to the update - // queue so we can process it immediately during the current render. - var pending = sharedQueue.pending; + mightHavePendingSyncWork = true; // At the end of the current event, go through each of the roots and ensure + // there's a task scheduled for each one at the correct priority. - if (pending === null) { - // This is the first update. Create a circular list. - update.next = update; - } else { - update.next = pending.next; - pending.next = update; + if (ReactCurrentActQueue$3.current !== null) { + // We're inside an `act` scope. + if (!didScheduleMicrotask_act) { + didScheduleMicrotask_act = true; + scheduleImmediateTask(processRootScheduleInMicrotask); + } + } else { + if (!didScheduleMicrotask) { + didScheduleMicrotask = true; + scheduleImmediateTask(processRootScheduleInMicrotask); } + } - sharedQueue.pending = update; // Update the childLanes even though we're most likely already rendering - // this fiber. This is for backwards compatibility in the case where you - // update a different component during render phase than the one that is - // currently renderings (a pattern that is accompanied by a warning). + { + // While this flag is disabled, we schedule the render task immediately + // instead of waiting a microtask. + // TODO: We need to land enableDeferRootSchedulingToMicrotask ASAP to + // unblock additional features we have planned. + scheduleTaskForRootDuringMicrotask(root, now$1()); + } - return unsafe_markUpdateLaneFromFiberToRoot(fiber, lane); - } else { - return enqueueConcurrentClassUpdate(fiber, sharedQueue, update, lane); + if (ReactCurrentActQueue$3.isBatchingLegacy && root.tag === LegacyRoot) { + // Special `act` case: Record whenever a legacy update is scheduled. + ReactCurrentActQueue$3.didScheduleLegacyUpdate = true; } } - function entangleTransitions(root, fiber, lane) { - var updateQueue = fiber.updateQueue; + function flushSyncWorkOnAllRoots() { + // This is allowed to be called synchronously, but the caller should check + // the execution context first. + flushSyncWorkAcrossRoots_impl(false); + } + function flushSyncWorkOnLegacyRootsOnly() { + // This is allowed to be called synchronously, but the caller should check + // the execution context first. + flushSyncWorkAcrossRoots_impl(true); + } - if (updateQueue === null) { - // Only occurs if the fiber has been unmounted. + function flushSyncWorkAcrossRoots_impl(onlyLegacy) { + if (isFlushingWork) { + // Prevent reentrancy. + // TODO: Is this overly defensive? The callers must check the execution + // context first regardless. return; } - var sharedQueue = updateQueue.shared; + if (!mightHavePendingSyncWork) { + // Fast path. There's no sync work to do. + return; + } // There may or may not be synchronous work scheduled. Let's check. - if (isTransitionLane(lane)) { - var queueLanes = sharedQueue.lanes; // If any entangled lanes are no longer pending on the root, then they must - // have finished. We can remove them from the shared queue, which represents - // a superset of the actually pending lanes. In some cases we may entangle - // more than we need to, but that's OK. In fact it's worse if we *don't* - // entangle when we should. + var didPerformSomeWork; + var errors = null; + isFlushingWork = true; - queueLanes = intersectLanes(queueLanes, root.pendingLanes); // Entangle the new transition lane with the other transition lanes. + do { + didPerformSomeWork = false; + var root = firstScheduledRoot; - var newQueueLanes = mergeLanes(queueLanes, lane); - sharedQueue.lanes = newQueueLanes; // Even if queue.lanes already include lane, we don't know for certain if - // the lane finished since the last time we entangled it. So we need to - // entangle it again, just to be sure. + while (root !== null) { + if (onlyLegacy && root.tag !== LegacyRoot); + else { + var workInProgressRoot = getWorkInProgressRoot(); + var workInProgressRootRenderLanes = + getWorkInProgressRootRenderLanes(); + var nextLanes = getNextLanes( + root, + root === workInProgressRoot + ? workInProgressRootRenderLanes + : NoLanes + ); - markRootEntangled(root, newQueueLanes); - } - } - function enqueueCapturedUpdate(workInProgress, capturedUpdate) { - // Captured updates are updates that are thrown by a child during the render - // phase. They should be discarded if the render is aborted. Therefore, - // we should only put them on the work-in-progress queue, not the current one. - var queue = workInProgress.updateQueue; // Check if the work-in-progress queue is a clone. + if (includesSyncLane(nextLanes)) { + // This root has pending sync work. Flush it now. + try { + didPerformSomeWork = true; + performSyncWorkOnRoot(root, nextLanes); + } catch (error) { + // Collect errors so we can rethrow them at the end + if (errors === null) { + errors = [error]; + } else { + errors.push(error); + } + } + } + } - var current = workInProgress.alternate; + root = root.next; + } + } while (didPerformSomeWork); - if (current !== null) { - var currentQueue = current.updateQueue; + isFlushingWork = false; // If any errors were thrown, rethrow them right before exiting. + // TODO: Consider returning these to the caller, to allow them to decide + // how/when to rethrow. - if (queue === currentQueue) { - // The work-in-progress queue is the same as current. This happens when - // we bail out on a parent fiber that then captures an error thrown by - // a child. Since we want to append the update only to the work-in - // -progress queue, we need to clone the updates. We usually clone during - // processUpdateQueue, but that didn't happen in this case because we - // skipped over the parent when we bailed out. - var newFirst = null; - var newLast = null; - var firstBaseUpdate = queue.firstBaseUpdate; - - if (firstBaseUpdate !== null) { - // Loop through the updates and clone them. - var update = firstBaseUpdate; - - do { - var clone = { - lane: update.lane, - tag: update.tag, - payload: update.payload, - // When this update is rebased, we should not fire its - // callback again. - callback: null, - next: null - }; - - if (newLast === null) { - newFirst = newLast = clone; - } else { - newLast.next = clone; - newLast = clone; - } // $FlowFixMe[incompatible-type] we bail out when we get a null - - update = update.next; - } while (update !== null); // Append the captured update the end of the cloned list. - - if (newLast === null) { - newFirst = newLast = capturedUpdate; - } else { - newLast.next = capturedUpdate; - newLast = capturedUpdate; - } + if (errors !== null) { + if (errors.length > 1) { + if (typeof AggregateError === "function") { + // eslint-disable-next-line no-undef + throw new AggregateError(errors); } else { - // There are no base updates. - newFirst = newLast = capturedUpdate; - } + for (var i = 1; i < errors.length; i++) { + scheduleImmediateTask(throwError.bind(null, errors[i])); + } - queue = { - baseState: currentQueue.baseState, - firstBaseUpdate: newFirst, - lastBaseUpdate: newLast, - shared: currentQueue.shared, - callbacks: currentQueue.callbacks - }; - workInProgress.updateQueue = queue; - return; + var firstError = errors[0]; + throw firstError; + } + } else { + var error = errors[0]; + throw error; } - } // Append the update to the end of the list. - - var lastBaseUpdate = queue.lastBaseUpdate; - - if (lastBaseUpdate === null) { - queue.firstBaseUpdate = capturedUpdate; - } else { - lastBaseUpdate.next = capturedUpdate; } - - queue.lastBaseUpdate = capturedUpdate; } - function getStateFromUpdate( - workInProgress, - queue, - update, - prevState, - nextProps, - instance - ) { - switch (update.tag) { - case ReplaceState: { - var payload = update.payload; - - if (typeof payload === "function") { - // Updater function - { - enterDisallowedContextReadInDEV(); - } + function throwError(error) { + throw error; + } - var nextState = payload.call(instance, prevState, nextProps); + function processRootScheduleInMicrotask() { + // This function is always called inside a microtask. It should never be + // called synchronously. + didScheduleMicrotask = false; - { - exitDisallowedContextReadInDEV(); - } + { + didScheduleMicrotask_act = false; + } // We'll recompute this as we iterate through all the roots and schedule them. - return nextState; - } // State object + mightHavePendingSyncWork = false; + var currentTime = now$1(); + var prev = null; + var root = firstScheduledRoot; - return payload; - } + while (root !== null) { + var next = root.next; - case CaptureUpdate: { - workInProgress.flags = - (workInProgress.flags & ~ShouldCapture) | DidCapture; + if ( + currentEventTransitionLane !== NoLane && + shouldAttemptEagerTransition() + ) { + // A transition was scheduled during an event, but we're going to try to + // render it synchronously anyway. We do this during a popstate event to + // preserve the scroll position of the previous page. + upgradePendingLaneToSync(root, currentEventTransitionLane); } - // Intentional fallthrough - - case UpdateState: { - var _payload = update.payload; - var partialState; - if (typeof _payload === "function") { - // Updater function - { - enterDisallowedContextReadInDEV(); - } + var nextLanes = scheduleTaskForRootDuringMicrotask(root, currentTime); - partialState = _payload.call(instance, prevState, nextProps); + if (nextLanes === NoLane) { + // This root has no more pending work. Remove it from the schedule. To + // guard against subtle reentrancy bugs, this microtask is the only place + // we do this — you can add roots to the schedule whenever, but you can + // only remove them here. + // Null this out so we know it's been removed from the schedule. + root.next = null; - { - exitDisallowedContextReadInDEV(); - } + if (prev === null) { + // This is the new head of the list + firstScheduledRoot = next; } else { - // Partial state object - partialState = _payload; + prev.next = next; } - 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); - } + if (next === null) { + // This is the new tail of the list + lastScheduledRoot = prev; + } + } else { + // This root still has work. Keep it in the list. + prev = root; - case ForceUpdate: { - hasForceUpdate = true; - return prevState; + if (includesSyncLane(nextLanes)) { + mightHavePendingSyncWork = true; + } } - } - - return prevState; - } - - function processUpdateQueue(workInProgress, props, instance, renderLanes) { - // This is always non-null on a ClassComponent or HostRoot - var queue = workInProgress.updateQueue; - hasForceUpdate = false; - { - currentlyProcessingQueue = queue.shared; + root = next; } - var firstBaseUpdate = queue.firstBaseUpdate; - var lastBaseUpdate = queue.lastBaseUpdate; // Check if there are pending updates. If so, transfer them to the base queue. + currentEventTransitionLane = NoLane; // At the end of the microtask, flush any pending synchronous work. This has + // to come at the end, because it does actual rendering work that might throw. - var pendingQueue = queue.shared.pending; + flushSyncWorkOnAllRoots(); + } - if (pendingQueue !== null) { - queue.shared.pending = null; // The pending queue is circular. Disconnect the pointer between first - // and last so that it's non-circular. + function scheduleTaskForRootDuringMicrotask(root, currentTime) { + // This function is always called inside a microtask, or at the very end of a + // rendering task right before we yield to the main thread. It should never be + // called synchronously. + // + // TODO: Unless enableDeferRootSchedulingToMicrotask is off. We need to land + // that ASAP to unblock additional features we have planned. + // + // This function also never performs React work synchronously; it should + // only schedule work to be performed later, in a separate task or microtask. + // Check if any lanes are being starved by other work. If so, mark them as + // expired so we know to work on those next. + markStarvedLanesAsExpired(root, currentTime); // Determine the next lanes to work on, and their priority. - var lastPendingUpdate = pendingQueue; - var firstPendingUpdate = lastPendingUpdate.next; - lastPendingUpdate.next = null; // Append pending updates to base queue + var workInProgressRoot = getWorkInProgressRoot(); + var workInProgressRootRenderLanes = getWorkInProgressRootRenderLanes(); + var nextLanes = getNextLanes( + root, + root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes + ); + var existingCallbackNode = root.callbackNode; - if (lastBaseUpdate === null) { - firstBaseUpdate = firstPendingUpdate; - } else { - lastBaseUpdate.next = firstPendingUpdate; + if ( + // Check if there's nothing to work on + nextLanes === NoLanes || // If this root is currently suspended and waiting for data to resolve, don't + // schedule a task to render it. We'll either wait for a ping, or wait to + // receive an update. + // + // Suspended render phase + (root === workInProgressRoot && isWorkLoopSuspendedOnData()) || // Suspended commit phase + root.cancelPendingCommit !== null + ) { + // Fast path: There's nothing to work on. + if (existingCallbackNode !== null) { + cancelCallback(existingCallbackNode); } - lastBaseUpdate = lastPendingUpdate; // If there's a current queue, and it's different from the base queue, then - // we need to transfer the updates to that queue, too. Because the base - // queue is a singly-linked list with no cycles, we can append to both - // lists and take advantage of structural sharing. - // TODO: Pass `current` as argument + root.callbackNode = null; + root.callbackPriority = NoLane; + return NoLane; + } // Schedule a new callback in the host environment. - var current = workInProgress.alternate; + if (includesSyncLane(nextLanes)) { + // Synchronous work is always flushed at the end of the microtask, so we + // don't need to schedule an additional task. + if (existingCallbackNode !== null) { + cancelCallback(existingCallbackNode); + } - if (current !== null) { - // This is always non-null on a ClassComponent or HostRoot - var currentQueue = current.updateQueue; - var currentLastBaseUpdate = currentQueue.lastBaseUpdate; - - if (currentLastBaseUpdate !== lastBaseUpdate) { - if (currentLastBaseUpdate === null) { - currentQueue.firstBaseUpdate = firstPendingUpdate; - } else { - currentLastBaseUpdate.next = firstPendingUpdate; - } + root.callbackPriority = SyncLane; + root.callbackNode = null; + return SyncLane; + } else { + // We use the highest priority lane to represent the priority of the callback. + var existingCallbackPriority = root.callbackPriority; + var newCallbackPriority = getHighestPriorityLane(nextLanes); - currentQueue.lastBaseUpdate = lastPendingUpdate; - } + if ( + newCallbackPriority === existingCallbackPriority && // Special case related to `act`. If the currently scheduled task is a + // Scheduler task, rather than an `act` task, cancel it and re-schedule + // on the `act` queue. + !( + ReactCurrentActQueue$3.current !== null && + existingCallbackNode !== fakeActCallbackNode$1 + ) + ) { + // The priority hasn't changed. We can reuse the existing task. + return newCallbackPriority; + } else { + // Cancel the existing callback. We'll schedule a new one below. + cancelCallback(existingCallbackNode); } - } // These values may change as we process the queue. - - if (firstBaseUpdate !== null) { - // Iterate through the list of updates to compute the result. - var newState = queue.baseState; // TODO: Don't need to accumulate this. Instead, we can remove renderLanes - // from the original lanes. - - var newLanes = NoLanes; - var newBaseState = null; - var newFirstBaseUpdate = null; - var newLastBaseUpdate = null; - var update = firstBaseUpdate; - - do { - // An extra OffscreenLane bit is added to updates that were made to - // a hidden tree, so that we can distinguish them from updates that were - // already there when the tree was hidden. - var updateLane = removeLanes(update.lane, OffscreenLane); - var isHiddenUpdate = updateLane !== update.lane; // Check if this update was made while the tree was hidden. If so, then - // it's not a "base" update and we should disregard the extra base lanes - // that were added to renderLanes when we entered the Offscreen tree. - - var shouldSkipUpdate = isHiddenUpdate - ? !isSubsetOfLanes(getWorkInProgressRootRenderLanes(), updateLane) - : !isSubsetOfLanes(renderLanes, updateLane); - - if (shouldSkipUpdate) { - // Priority is insufficient. Skip this update. If this is the first - // skipped update, the previous update/state is the new base - // update/state. - var clone = { - lane: updateLane, - tag: update.tag, - payload: update.payload, - callback: update.callback, - next: null - }; - - if (newLastBaseUpdate === null) { - newFirstBaseUpdate = newLastBaseUpdate = clone; - newBaseState = newState; - } else { - newLastBaseUpdate = newLastBaseUpdate.next = clone; - } // Update the remaining priority in the queue. - - newLanes = mergeLanes(newLanes, updateLane); - } else { - // This update does have sufficient priority. - if (newLastBaseUpdate !== null) { - var _clone = { - // This update is going to be committed so we never want uncommit - // it. Using NoLane works because 0 is a subset of all bitmasks, so - // this will never be skipped by the check above. - lane: NoLane, - tag: update.tag, - payload: update.payload, - // When this update is rebased, we should not fire its - // callback again. - callback: null, - next: null - }; - newLastBaseUpdate = newLastBaseUpdate.next = _clone; - } // Process this update. - - newState = getStateFromUpdate( - workInProgress, - queue, - update, - newState, - props, - instance - ); - var callback = update.callback; - - if (callback !== null) { - workInProgress.flags |= Callback; - - if (isHiddenUpdate) { - workInProgress.flags |= Visibility; - } - - var callbacks = queue.callbacks; - if (callbacks === null) { - queue.callbacks = [callback]; - } else { - callbacks.push(callback); - } - } - } // $FlowFixMe[incompatible-type] we bail out when we get a null + var schedulerPriorityLevel; - update = update.next; + switch (lanesToEventPriority(nextLanes)) { + case DiscreteEventPriority: + schedulerPriorityLevel = ImmediatePriority; + break; - if (update === null) { - pendingQueue = queue.shared.pending; + case ContinuousEventPriority: + schedulerPriorityLevel = UserBlockingPriority; + break; - if (pendingQueue === null) { - break; - } else { - // An update was scheduled from inside a reducer. Add the new - // pending updates to the end of the list and keep processing. - var _lastPendingUpdate = pendingQueue; // Intentionally unsound. Pending updates form a circular list, but we - // unravel them when transferring them to the base queue. + case DefaultEventPriority: + schedulerPriorityLevel = NormalPriority; + break; - var _firstPendingUpdate = _lastPendingUpdate.next; - _lastPendingUpdate.next = null; - update = _firstPendingUpdate; - queue.lastBaseUpdate = _lastPendingUpdate; - queue.shared.pending = null; - } - } - } while (true); + case IdleEventPriority: + schedulerPriorityLevel = IdlePriority; + break; - if (newLastBaseUpdate === null) { - newBaseState = newState; + default: + schedulerPriorityLevel = NormalPriority; + break; } - queue.baseState = newBaseState; - queue.firstBaseUpdate = newFirstBaseUpdate; - queue.lastBaseUpdate = newLastBaseUpdate; + var newCallbackNode = scheduleCallback$1( + schedulerPriorityLevel, + performConcurrentWorkOnRoot.bind(null, root) + ); + root.callbackPriority = newCallbackPriority; + root.callbackNode = newCallbackNode; + return newCallbackPriority; + } + } - if (firstBaseUpdate === null) { - // `queue.lanes` is used for entangling transitions. We can set it back to - // zero once the queue is empty. - queue.shared.lanes = NoLanes; - } // Set the remaining expiration time to be whatever is remaining in the queue. - // This should be fine because the only two other things that contribute to - // expiration time are props and context. We're already in the middle of the - // begin phase by the time we start processing the queue, so we've already - // dealt with the props. Context in components that specify - // shouldComponentUpdate is tricky; but we'll have to account for - // that regardless. + function getContinuationForRoot(root, originalCallbackNode) { + // This is called at the end of `performConcurrentWorkOnRoot` to determine + // if we need to schedule a continuation task. + // + // Usually `scheduleTaskForRootDuringMicrotask` only runs inside a microtask; + // however, since most of the logic for determining if we need a continuation + // versus a new task is the same, we cheat a bit and call it here. This is + // only safe to do because we know we're at the end of the browser task. + // So although it's not an actual microtask, it might as well be. + scheduleTaskForRootDuringMicrotask(root, now$1()); - markSkippedUpdateLanes(newLanes); - workInProgress.lanes = newLanes; - workInProgress.memoizedState = newState; + if (root.callbackNode === originalCallbackNode) { + // The task node scheduled for this root is the same one that's + // currently executed. Need to return a continuation. + return performConcurrentWorkOnRoot.bind(null, root); } - { - currentlyProcessingQueue = null; - } + return null; } + var fakeActCallbackNode$1 = {}; - function callCallback(callback, context) { - if (typeof callback !== "function") { - throw new Error( - "Invalid argument passed as callback. Expected a function. Instead " + - ("received: " + callback) - ); + function scheduleCallback$1(priorityLevel, callback) { + if (ReactCurrentActQueue$3.current !== null) { + // Special case: We're inside an `act` scope (a testing utility). + // Instead of scheduling work in the host environment, add it to a + // fake internal queue that's managed by the `act` implementation. + ReactCurrentActQueue$3.current.push(callback); + return fakeActCallbackNode$1; + } else { + return scheduleCallback$2(priorityLevel, callback); } - - callback.call(context); } - function resetHasForceUpdateBeforeProcessing() { - hasForceUpdate = false; - } - function checkHasForceUpdateAfterProcessing() { - return hasForceUpdate; + function cancelCallback(callbackNode) { + if (callbackNode === fakeActCallbackNode$1); + else if (callbackNode !== null) { + cancelCallback$1(callbackNode); + } } - function deferHiddenCallbacks(updateQueue) { - // When an update finishes on a hidden component, its callback should not - // be fired until/unless the component is made visible again. Stash the - // callback on the shared queue object so it can be fired later. - var newHiddenCallbacks = updateQueue.callbacks; - if (newHiddenCallbacks !== null) { - var existingHiddenCallbacks = updateQueue.shared.hiddenCallbacks; + function scheduleImmediateTask(cb) { + if (ReactCurrentActQueue$3.current !== null) { + // Special case: Inside an `act` scope, we push microtasks to the fake `act` + // callback queue. This is because we currently support calling `act` + // without awaiting the result. The plan is to deprecate that, and require + // that you always await the result so that the microtasks have a chance to + // run. But it hasn't happened yet. + ReactCurrentActQueue$3.current.push(function () { + cb(); + return null; + }); + } // TODO: Can we land supportsMicrotasks? Which environments don't support it? + // Alternatively, can we move this check to the host config? - if (existingHiddenCallbacks === null) { - updateQueue.shared.hiddenCallbacks = newHiddenCallbacks; - } else { - updateQueue.shared.hiddenCallbacks = - existingHiddenCallbacks.concat(newHiddenCallbacks); - } + { + // If microtasks are not supported, use Scheduler. + scheduleCallback$2(ImmediatePriority, cb); } } - function commitHiddenCallbacks(updateQueue, context) { - // This component is switching from hidden -> visible. Commit any callbacks - // that were previously deferred. - var hiddenCallbacks = updateQueue.shared.hiddenCallbacks; - - if (hiddenCallbacks !== null) { - updateQueue.shared.hiddenCallbacks = null; - for (var i = 0; i < hiddenCallbacks.length; i++) { - var callback = hiddenCallbacks[i]; - callCallback(callback, context); - } + function requestTransitionLane( // This argument isn't used, it's only here to encourage the caller to + // check that it's inside a transition before calling this function. + // TODO: Make this non-nullable. Requires a tweak to useOptimistic. + transition + ) { + // The algorithm for assigning an update to a lane should be stable for all + // updates at the same priority within the same event. To do this, the + // inputs to the algorithm must be the same. + // + // The trick we use is to cache the first of each of these inputs within an + // event. Then reset the cached values once we can be sure the event is + // over. Our heuristic for that is whenever we enter a concurrent work loop. + if (currentEventTransitionLane === NoLane) { + // All transitions within the same event are assigned the same lane. + currentEventTransitionLane = claimNextTransitionLane(); } - } - function commitCallbacks(updateQueue, context) { - var callbacks = updateQueue.callbacks; - if (callbacks !== null) { - updateQueue.callbacks = null; - - for (var i = 0; i < callbacks.length; i++) { - var callback = callbacks[i]; - callCallback(callback, context); - } - } + return currentEventTransitionLane; } - /** - * 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 (objectIs(objA, objB)) { - return true; - } + var currentEntangledLane = NoLane; // A thenable that resolves when the entangled scope completes. It does not + // resolve to a particular value because it's only used for suspending the UI + // until the async action scope has completed. - if ( - typeof objA !== "object" || - objA === null || - typeof objB !== "object" || - objB === null - ) { - return false; - } + var currentEntangledActionThenable = null; - var keysA = Object.keys(objA); - var keysB = Object.keys(objB); + function chainThenableValue(thenable, result) { + // Equivalent to: Promise.resolve(thenable).then(() => result), except we can + // cheat a bit since we know that that this thenable is only ever consumed + // by React. + // + // We don't technically require promise support on the client yet, hence this + // extra code. + var listeners = []; + var thenableWithOverride = { + status: "pending", + value: null, + reason: null, + then: function (resolve) { + listeners.push(resolve); + } + }; + thenable.then( + function (value) { + var fulfilledThenable = thenableWithOverride; + fulfilledThenable.status = "fulfilled"; + fulfilledThenable.value = result; - if (keysA.length !== keysB.length) { - return false; - } // Test for A's keys different from B. + for (var i = 0; i < listeners.length; i++) { + var listener = listeners[i]; + listener(result); + } + }, + function (error) { + var rejectedThenable = thenableWithOverride; + rejectedThenable.status = "rejected"; + rejectedThenable.reason = error; - for (var i = 0; i < keysA.length; i++) { - var currentKey = keysA[i]; + for (var i = 0; i < listeners.length; i++) { + var listener = listeners[i]; // This is a perf hack where we call the `onFulfill` ping function + // instead of `onReject`, because we know that React is the only + // consumer of these promises, and it passes the same listener to both. + // We also know that it will read the error directly off the + // `.reason` field. - if ( - !hasOwnProperty.call(objB, currentKey) || // $FlowFixMe[incompatible-use] lost refinement of `objB` - !objectIs(objA[currentKey], objB[currentKey]) - ) { - return false; + listener(undefined); + } } - } - - return true; + ); + return thenableWithOverride; + } + function peekEntangledActionLane() { + return currentEntangledLane; + } + function peekEntangledActionThenable() { + return currentEntangledActionThenable; } - function describeFiber(fiber) { - var owner = fiber._debugOwner ? fiber._debugOwner.type : null; - var source = fiber._debugSource; + 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`. - switch (fiber.tag) { - case HostHoistable: - case HostSingleton: - case HostComponent: - return describeBuiltInComponentFrame(fiber.type, source, owner); + var hasForceUpdate = false; + var didWarnUpdateInsideUpdate; + var currentlyProcessingQueue; - case LazyComponent: - return describeBuiltInComponentFrame("Lazy", source, owner); + { + didWarnUpdateInsideUpdate = false; + currentlyProcessingQueue = null; + } - case SuspenseComponent: - return describeBuiltInComponentFrame("Suspense", source, owner); + function initializeUpdateQueue(fiber) { + var queue = { + baseState: fiber.memoizedState, + firstBaseUpdate: null, + lastBaseUpdate: null, + shared: { + pending: null, + lanes: NoLanes, + hiddenCallbacks: null + }, + callbacks: null + }; + fiber.updateQueue = queue; + } + function cloneUpdateQueue(current, workInProgress) { + // Clone the update queue from current. Unless it's already a clone. + var queue = workInProgress.updateQueue; + var currentQueue = current.updateQueue; - case SuspenseListComponent: - return describeBuiltInComponentFrame("SuspenseList", source, owner); + if (queue === currentQueue) { + var clone = { + baseState: currentQueue.baseState, + firstBaseUpdate: currentQueue.firstBaseUpdate, + lastBaseUpdate: currentQueue.lastBaseUpdate, + shared: currentQueue.shared, + callbacks: null + }; + workInProgress.updateQueue = clone; + } + } + function createUpdate(lane) { + var update = { + lane: lane, + tag: UpdateState, + payload: null, + callback: null, + next: null + }; + return update; + } + function enqueueUpdate(fiber, update, lane) { + var updateQueue = fiber.updateQueue; - case FunctionComponent: - case IndeterminateComponent: - case SimpleMemoComponent: - return describeFunctionComponentFrame(fiber.type, source, owner); + if (updateQueue === null) { + // Only occurs if the fiber has been unmounted. + return null; + } - case ForwardRef: - return describeFunctionComponentFrame( - fiber.type.render, - source, - owner - ); + var sharedQueue = updateQueue.shared; - case ClassComponent: - return describeClassComponentFrame(fiber.type, source, owner); + { + if ( + currentlyProcessingQueue === sharedQueue && + !didWarnUpdateInsideUpdate + ) { + var componentName = getComponentNameFromFiber(fiber); - default: - return ""; + error( + "An update (setState, replaceState, or forceUpdate) was scheduled " + + "from inside an update function. Update functions should be pure, " + + "with zero side-effects. Consider using componentDidUpdate or a " + + "callback.\n\nPlease update the following component: %s", + componentName + ); + + didWarnUpdateInsideUpdate = true; + } } - } - function getStackByFiberInDevAndProd(workInProgress) { - try { - var info = ""; - var node = workInProgress; + if (isUnsafeClassRenderPhaseUpdate()) { + // This is an unsafe render phase update. Add directly to the update + // queue so we can process it immediately during the current render. + var pending = sharedQueue.pending; - do { - info += describeFiber(node); // $FlowFixMe[incompatible-type] we bail out when we get a null + if (pending === null) { + // This is the first update. Create a circular list. + update.next = update; + } else { + update.next = pending.next; + pending.next = update; + } - node = node.return; - } while (node); + sharedQueue.pending = update; // Update the childLanes even though we're most likely already rendering + // this fiber. This is for backwards compatibility in the case where you + // update a different component during render phase than the one that is + // currently renderings (a pattern that is accompanied by a warning). - return info; - } catch (x) { - return "\nError generating stack: " + x.message + "\n" + x.stack; + return unsafe_markUpdateLaneFromFiberToRoot(fiber, lane); + } else { + return enqueueConcurrentClassUpdate(fiber, sharedQueue, update, lane); } } + function entangleTransitions(root, fiber, lane) { + var updateQueue = fiber.updateQueue; - var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; - var current = null; - var isRendering = false; - function getCurrentFiberOwnerNameInDevOrNull() { - { - if (current === null) { - return null; - } + if (updateQueue === null) { + // Only occurs if the fiber has been unmounted. + return; + } - var owner = current._debugOwner; + var sharedQueue = updateQueue.shared; - if (owner !== null && typeof owner !== "undefined") { - return getComponentNameFromFiber(owner); - } - } + if (isTransitionLane(lane)) { + var queueLanes = sharedQueue.lanes; // If any entangled lanes are no longer pending on the root, then they must + // have finished. We can remove them from the shared queue, which represents + // a superset of the actually pending lanes. In some cases we may entangle + // more than we need to, but that's OK. In fact it's worse if we *don't* + // entangle when we should. - return null; - } + queueLanes = intersectLanes(queueLanes, root.pendingLanes); // Entangle the new transition lane with the other transition lanes. - function getCurrentFiberStackInDev() { - { - if (current === null) { - return ""; - } // Safe because if current fiber exists, we are reconciling, - // and it is guaranteed to be the work-in-progress version. + var newQueueLanes = mergeLanes(queueLanes, lane); + sharedQueue.lanes = newQueueLanes; // Even if queue.lanes already include lane, we don't know for certain if + // the lane finished since the last time we entangled it. So we need to + // entangle it again, just to be sure. - return getStackByFiberInDevAndProd(current); + markRootEntangled(root, newQueueLanes); } } + function enqueueCapturedUpdate(workInProgress, capturedUpdate) { + // Captured updates are updates that are thrown by a child during the render + // phase. They should be discarded if the render is aborted. Therefore, + // we should only put them on the work-in-progress queue, not the current one. + var queue = workInProgress.updateQueue; // Check if the work-in-progress queue is a clone. - function resetCurrentFiber() { - { - ReactDebugCurrentFrame.getCurrentStack = null; - current = null; - isRendering = false; - } - } - function setCurrentFiber(fiber) { - { - ReactDebugCurrentFrame.getCurrentStack = - fiber === null ? null : getCurrentFiberStackInDev; - current = fiber; - isRendering = false; - } - } - function getCurrentFiber() { - { - return current; - } - } - function setIsRendering(rendering) { - { - isRendering = rendering; - } - } + var current = workInProgress.alternate; - var ReactStrictModeWarnings = { - recordUnsafeLifecycleWarnings: function (fiber, instance) {}, - flushPendingUnsafeLifecycleWarnings: function () {}, - recordLegacyContextWarning: function (fiber, instance) {}, - flushLegacyContextWarning: function () {}, - discardPendingWarnings: function () {} - }; + if (current !== null) { + var currentQueue = current.updateQueue; - { - var findStrictRoot = function (fiber) { - var maybeStrictRoot = null; - var node = fiber; + if (queue === currentQueue) { + // The work-in-progress queue is the same as current. This happens when + // we bail out on a parent fiber that then captures an error thrown by + // a child. Since we want to append the update only to the work-in + // -progress queue, we need to clone the updates. We usually clone during + // processUpdateQueue, but that didn't happen in this case because we + // skipped over the parent when we bailed out. + var newFirst = null; + var newLast = null; + var firstBaseUpdate = queue.firstBaseUpdate; - while (node !== null) { - if (node.mode & StrictLegacyMode) { - maybeStrictRoot = node; + if (firstBaseUpdate !== null) { + // Loop through the updates and clone them. + var update = firstBaseUpdate; + + do { + var clone = { + lane: update.lane, + tag: update.tag, + payload: update.payload, + // When this update is rebased, we should not fire its + // callback again. + callback: null, + next: null + }; + + if (newLast === null) { + newFirst = newLast = clone; + } else { + newLast.next = clone; + newLast = clone; + } // $FlowFixMe[incompatible-type] we bail out when we get a null + + update = update.next; + } while (update !== null); // Append the captured update the end of the cloned list. + + if (newLast === null) { + newFirst = newLast = capturedUpdate; + } else { + newLast.next = capturedUpdate; + newLast = capturedUpdate; + } + } else { + // There are no base updates. + newFirst = newLast = capturedUpdate; } - node = node.return; + queue = { + baseState: currentQueue.baseState, + firstBaseUpdate: newFirst, + lastBaseUpdate: newLast, + shared: currentQueue.shared, + callbacks: currentQueue.callbacks + }; + workInProgress.updateQueue = queue; + return; } + } // Append the update to the end of the list. - return maybeStrictRoot; - }; + var lastBaseUpdate = queue.lastBaseUpdate; - var setToSortedString = function (set) { - var array = []; - set.forEach(function (value) { - array.push(value); - }); - return array.sort().join(", "); - }; + if (lastBaseUpdate === null) { + queue.firstBaseUpdate = capturedUpdate; + } else { + lastBaseUpdate.next = capturedUpdate; + } - var pendingComponentWillMountWarnings = []; - var pendingUNSAFE_ComponentWillMountWarnings = []; - var pendingComponentWillReceivePropsWarnings = []; - var pendingUNSAFE_ComponentWillReceivePropsWarnings = []; - var pendingComponentWillUpdateWarnings = []; - var pendingUNSAFE_ComponentWillUpdateWarnings = []; // Tracks components we have already warned about. + queue.lastBaseUpdate = capturedUpdate; + } - var didWarnAboutUnsafeLifecycles = new Set(); + function getStateFromUpdate( + workInProgress, + queue, + update, + prevState, + nextProps, + instance + ) { + switch (update.tag) { + case ReplaceState: { + var payload = update.payload; - ReactStrictModeWarnings.recordUnsafeLifecycleWarnings = function ( - fiber, - instance - ) { - // Dedupe strategy: Warn once per component. - if (didWarnAboutUnsafeLifecycles.has(fiber.type)) { - return; - } + if (typeof payload === "function") { + // Updater function + { + enterDisallowedContextReadInDEV(); + } - if ( - typeof instance.componentWillMount === "function" && // Don't warn about react-lifecycles-compat polyfilled components. - instance.componentWillMount.__suppressDeprecationWarning !== true - ) { - pendingComponentWillMountWarnings.push(fiber); - } + var nextState = payload.call(instance, prevState, nextProps); - if ( - fiber.mode & StrictLegacyMode && - typeof instance.UNSAFE_componentWillMount === "function" - ) { - pendingUNSAFE_ComponentWillMountWarnings.push(fiber); - } + { + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); - if ( - typeof instance.componentWillReceiveProps === "function" && - instance.componentWillReceiveProps.__suppressDeprecationWarning !== - true - ) { - pendingComponentWillReceivePropsWarnings.push(fiber); - } + try { + payload.call(instance, prevState, nextProps); + } finally { + setIsStrictModeForDevtools(false); + } + } - if ( - fiber.mode & StrictLegacyMode && - typeof instance.UNSAFE_componentWillReceiveProps === "function" - ) { - pendingUNSAFE_ComponentWillReceivePropsWarnings.push(fiber); - } + exitDisallowedContextReadInDEV(); + } - if ( - typeof instance.componentWillUpdate === "function" && - instance.componentWillUpdate.__suppressDeprecationWarning !== true - ) { - pendingComponentWillUpdateWarnings.push(fiber); + return nextState; + } // State object + + return payload; } - if ( - fiber.mode & StrictLegacyMode && - typeof instance.UNSAFE_componentWillUpdate === "function" - ) { - pendingUNSAFE_ComponentWillUpdateWarnings.push(fiber); + case CaptureUpdate: { + workInProgress.flags = + (workInProgress.flags & ~ShouldCapture) | DidCapture; } - }; + // Intentional fallthrough - ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = - function () { - // We do an initial pass to gather component names - var componentWillMountUniqueNames = new Set(); + case UpdateState: { + var _payload = update.payload; + var partialState; - if (pendingComponentWillMountWarnings.length > 0) { - pendingComponentWillMountWarnings.forEach(function (fiber) { - componentWillMountUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingComponentWillMountWarnings = []; - } + if (typeof _payload === "function") { + // Updater function + { + enterDisallowedContextReadInDEV(); + } - var UNSAFE_componentWillMountUniqueNames = new Set(); + partialState = _payload.call(instance, prevState, nextProps); - if (pendingUNSAFE_ComponentWillMountWarnings.length > 0) { - pendingUNSAFE_ComponentWillMountWarnings.forEach(function (fiber) { - UNSAFE_componentWillMountUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingUNSAFE_ComponentWillMountWarnings = []; - } + { + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); - var componentWillReceivePropsUniqueNames = new Set(); + try { + _payload.call(instance, prevState, nextProps); + } finally { + setIsStrictModeForDevtools(false); + } + } - if (pendingComponentWillReceivePropsWarnings.length > 0) { - pendingComponentWillReceivePropsWarnings.forEach(function (fiber) { - componentWillReceivePropsUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingComponentWillReceivePropsWarnings = []; + exitDisallowedContextReadInDEV(); + } + } else { + // Partial state object + partialState = _payload; } - var UNSAFE_componentWillReceivePropsUniqueNames = new Set(); + if (partialState === null || partialState === undefined) { + // Null and undefined are treated as no-ops. + return prevState; + } // Merge the partial state and the previous state. - if (pendingUNSAFE_ComponentWillReceivePropsWarnings.length > 0) { - pendingUNSAFE_ComponentWillReceivePropsWarnings.forEach( - function (fiber) { - UNSAFE_componentWillReceivePropsUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - } - ); - pendingUNSAFE_ComponentWillReceivePropsWarnings = []; - } + return assign({}, prevState, partialState); + } - var componentWillUpdateUniqueNames = new Set(); + case ForceUpdate: { + hasForceUpdate = true; + return prevState; + } + } - if (pendingComponentWillUpdateWarnings.length > 0) { - pendingComponentWillUpdateWarnings.forEach(function (fiber) { - componentWillUpdateUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingComponentWillUpdateWarnings = []; - } + return prevState; + } - var UNSAFE_componentWillUpdateUniqueNames = new Set(); + var didReadFromEntangledAsyncAction = false; // Each call to processUpdateQueue should be accompanied by a call to this. It's + // only in a separate function because in updateHostRoot, it must happen after + // all the context stacks have been pushed to, to prevent a stack mismatch. A + // bit unfortunate. - if (pendingUNSAFE_ComponentWillUpdateWarnings.length > 0) { - pendingUNSAFE_ComponentWillUpdateWarnings.forEach(function (fiber) { - UNSAFE_componentWillUpdateUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingUNSAFE_ComponentWillUpdateWarnings = []; - } // Finally, we flush all the warnings - // UNSAFE_ ones before the deprecated ones, since they'll be 'louder' + function suspendIfUpdateReadFromEntangledAsyncAction() { + // Check if this update is part of a pending async action. If so, we'll + // need to suspend until the action has finished, so that it's batched + // together with future updates in the same action. + // TODO: Once we support hooks inside useMemo (or an equivalent + // memoization boundary like Forget), hoist this logic so that it only + // suspends if the memo boundary produces a new value. + if (didReadFromEntangledAsyncAction) { + var entangledActionThenable = peekEntangledActionThenable(); - if (UNSAFE_componentWillMountUniqueNames.size > 0) { - var sortedNames = setToSortedString( - UNSAFE_componentWillMountUniqueNames - ); + if (entangledActionThenable !== null) { + // TODO: Instead of the throwing the thenable directly, throw a + // special object like `use` does so we can detect if it's captured + // by userspace. + throw entangledActionThenable; + } + } + } + function processUpdateQueue(workInProgress, props, instance, renderLanes) { + didReadFromEntangledAsyncAction = false; // This is always non-null on a ClassComponent or HostRoot - error( - "Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code. " + - "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + - "* Move code with side effects to componentDidMount, and set initial state in the constructor.\n" + - "\nPlease update the following components: %s", - sortedNames - ); - } + var queue = workInProgress.updateQueue; + hasForceUpdate = false; - if (UNSAFE_componentWillReceivePropsUniqueNames.size > 0) { - var _sortedNames = setToSortedString( - UNSAFE_componentWillReceivePropsUniqueNames - ); + { + currentlyProcessingQueue = queue.shared; + } - error( - "Using UNSAFE_componentWillReceiveProps in strict mode is not recommended " + - "and may indicate bugs in your code. " + - "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + - "* Move data fetching code or side effects to componentDidUpdate.\n" + - "* If you're updating state whenever props change, " + - "refactor your code to use memoization techniques or move it to " + - "static getDerivedStateFromProps. Learn more at: https://reactjs.org/link/derived-state\n" + - "\nPlease update the following components: %s", - _sortedNames - ); - } + var firstBaseUpdate = queue.firstBaseUpdate; + var lastBaseUpdate = queue.lastBaseUpdate; // Check if there are pending updates. If so, transfer them to the base queue. - if (UNSAFE_componentWillUpdateUniqueNames.size > 0) { - var _sortedNames2 = setToSortedString( - UNSAFE_componentWillUpdateUniqueNames - ); + var pendingQueue = queue.shared.pending; - error( - "Using UNSAFE_componentWillUpdate in strict mode is not recommended " + - "and may indicate bugs in your code. " + - "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + - "* Move data fetching code or side effects to componentDidUpdate.\n" + - "\nPlease update the following components: %s", - _sortedNames2 - ); - } + if (pendingQueue !== null) { + queue.shared.pending = null; // The pending queue is circular. Disconnect the pointer between first + // and last so that it's non-circular. - if (componentWillMountUniqueNames.size > 0) { - var _sortedNames3 = setToSortedString( - componentWillMountUniqueNames - ); + var lastPendingUpdate = pendingQueue; + var firstPendingUpdate = lastPendingUpdate.next; + lastPendingUpdate.next = null; // Append pending updates to base queue - warn( - "componentWillMount has been renamed, and is not recommended for use. " + - "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + - "* Move code with side effects to componentDidMount, and set initial state in the constructor.\n" + - "* Rename componentWillMount to UNSAFE_componentWillMount to suppress " + - "this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. " + - "To rename all deprecated lifecycles to their new names, you can run " + - "`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n" + - "\nPlease update the following components: %s", - _sortedNames3 - ); - } + if (lastBaseUpdate === null) { + firstBaseUpdate = firstPendingUpdate; + } else { + lastBaseUpdate.next = firstPendingUpdate; + } - if (componentWillReceivePropsUniqueNames.size > 0) { - var _sortedNames4 = setToSortedString( - componentWillReceivePropsUniqueNames - ); + lastBaseUpdate = lastPendingUpdate; // If there's a current queue, and it's different from the base queue, then + // we need to transfer the updates to that queue, too. Because the base + // queue is a singly-linked list with no cycles, we can append to both + // lists and take advantage of structural sharing. + // TODO: Pass `current` as argument - warn( - "componentWillReceiveProps has been renamed, and is not recommended for use. " + - "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + - "* Move data fetching code or side effects to componentDidUpdate.\n" + - "* If you're updating state whenever props change, refactor your " + - "code to use memoization techniques or move it to " + - "static getDerivedStateFromProps. Learn more at: https://reactjs.org/link/derived-state\n" + - "* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress " + - "this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. " + - "To rename all deprecated lifecycles to their new names, you can run " + - "`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n" + - "\nPlease update the following components: %s", - _sortedNames4 - ); - } + var current = workInProgress.alternate; - if (componentWillUpdateUniqueNames.size > 0) { - var _sortedNames5 = setToSortedString( - componentWillUpdateUniqueNames - ); + if (current !== null) { + // This is always non-null on a ClassComponent or HostRoot + var currentQueue = current.updateQueue; + var currentLastBaseUpdate = currentQueue.lastBaseUpdate; - warn( - "componentWillUpdate has been renamed, and is not recommended for use. " + - "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + - "* Move data fetching code or side effects to componentDidUpdate.\n" + - "* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress " + - "this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. " + - "To rename all deprecated lifecycles to their new names, you can run " + - "`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n" + - "\nPlease update the following components: %s", - _sortedNames5 - ); + if (currentLastBaseUpdate !== lastBaseUpdate) { + if (currentLastBaseUpdate === null) { + currentQueue.firstBaseUpdate = firstPendingUpdate; + } else { + currentLastBaseUpdate.next = firstPendingUpdate; + } + + currentQueue.lastBaseUpdate = lastPendingUpdate; } - }; + } + } // These values may change as we process the queue. - var pendingLegacyContextWarning = new Map(); // Tracks components we have already warned about. + if (firstBaseUpdate !== null) { + // Iterate through the list of updates to compute the result. + var newState = queue.baseState; // TODO: Don't need to accumulate this. Instead, we can remove renderLanes + // from the original lanes. - var didWarnAboutLegacyContext = new Set(); + var newLanes = NoLanes; + var newBaseState = null; + var newFirstBaseUpdate = null; + var newLastBaseUpdate = null; + var update = firstBaseUpdate; - ReactStrictModeWarnings.recordLegacyContextWarning = function ( - fiber, - instance - ) { - var strictRoot = findStrictRoot(fiber); + do { + // An extra OffscreenLane bit is added to updates that were made to + // a hidden tree, so that we can distinguish them from updates that were + // already there when the tree was hidden. + var updateLane = removeLanes(update.lane, OffscreenLane); + var isHiddenUpdate = updateLane !== update.lane; // Check if this update was made while the tree was hidden. If so, then + // it's not a "base" update and we should disregard the extra base lanes + // that were added to renderLanes when we entered the Offscreen tree. - if (strictRoot === null) { - error( - "Expected to find a StrictMode component in a strict mode tree. " + - "This error is likely caused by a bug in React. Please file an issue." - ); + var shouldSkipUpdate = isHiddenUpdate + ? !isSubsetOfLanes(getWorkInProgressRootRenderLanes(), updateLane) + : !isSubsetOfLanes(renderLanes, updateLane); - return; - } // Dedup strategy: Warn once per component. + if (shouldSkipUpdate) { + // Priority is insufficient. Skip this update. If this is the first + // skipped update, the previous update/state is the new base + // update/state. + var clone = { + lane: updateLane, + tag: update.tag, + payload: update.payload, + callback: update.callback, + next: null + }; - if (didWarnAboutLegacyContext.has(fiber.type)) { - return; - } + if (newLastBaseUpdate === null) { + newFirstBaseUpdate = newLastBaseUpdate = clone; + newBaseState = newState; + } else { + newLastBaseUpdate = newLastBaseUpdate.next = clone; + } // Update the remaining priority in the queue. - var warningsForRoot = pendingLegacyContextWarning.get(strictRoot); + newLanes = mergeLanes(newLanes, updateLane); + } else { + // This update does have sufficient priority. + // Check if this update is part of a pending async action. If so, + // we'll need to suspend until the action has finished, so that it's + // batched together with future updates in the same action. + if ( + updateLane !== NoLane && + updateLane === peekEntangledActionLane() + ) { + didReadFromEntangledAsyncAction = true; + } - if ( - fiber.type.contextTypes != null || - fiber.type.childContextTypes != null || - (instance !== null && typeof instance.getChildContext === "function") - ) { - if (warningsForRoot === undefined) { - warningsForRoot = []; - pendingLegacyContextWarning.set(strictRoot, warningsForRoot); - } + if (newLastBaseUpdate !== null) { + var _clone = { + // This update is going to be committed so we never want uncommit + // it. Using NoLane works because 0 is a subset of all bitmasks, so + // this will never be skipped by the check above. + lane: NoLane, + tag: update.tag, + payload: update.payload, + // When this update is rebased, we should not fire its + // callback again. + callback: null, + next: null + }; + newLastBaseUpdate = newLastBaseUpdate.next = _clone; + } // Process this update. - warningsForRoot.push(fiber); - } - }; + newState = getStateFromUpdate( + workInProgress, + queue, + update, + newState, + props, + instance + ); + var callback = update.callback; - ReactStrictModeWarnings.flushLegacyContextWarning = function () { - pendingLegacyContextWarning.forEach(function (fiberArray, strictRoot) { - if (fiberArray.length === 0) { - return; - } + if (callback !== null) { + workInProgress.flags |= Callback; - var firstFiber = fiberArray[0]; - var uniqueNames = new Set(); - fiberArray.forEach(function (fiber) { - uniqueNames.add(getComponentNameFromFiber(fiber) || "Component"); - didWarnAboutLegacyContext.add(fiber.type); - }); - var sortedNames = setToSortedString(uniqueNames); + if (isHiddenUpdate) { + workInProgress.flags |= Visibility; + } - try { - setCurrentFiber(firstFiber); + var callbacks = queue.callbacks; - error( - "Legacy context API has been detected within a strict-mode tree." + - "\n\nThe old API will be supported in all 16.x releases, but applications " + - "using it should migrate to the new version." + - "\n\nPlease update the following components: %s" + - "\n\nLearn more about this warning here: https://reactjs.org/link/legacy-context", - sortedNames - ); - } finally { - resetCurrentFiber(); + if (callbacks === null) { + queue.callbacks = [callback]; + } else { + callbacks.push(callback); + } + } + } // $FlowFixMe[incompatible-type] we bail out when we get a null + + update = update.next; + + if (update === null) { + pendingQueue = queue.shared.pending; + + if (pendingQueue === null) { + break; + } else { + // An update was scheduled from inside a reducer. Add the new + // pending updates to the end of the list and keep processing. + var _lastPendingUpdate = pendingQueue; // Intentionally unsound. Pending updates form a circular list, but we + // unravel them when transferring them to the base queue. + + var _firstPendingUpdate = _lastPendingUpdate.next; + _lastPendingUpdate.next = null; + update = _firstPendingUpdate; + queue.lastBaseUpdate = _lastPendingUpdate; + queue.shared.pending = null; + } } - }); - }; + } while (true); - ReactStrictModeWarnings.discardPendingWarnings = function () { - pendingComponentWillMountWarnings = []; - pendingUNSAFE_ComponentWillMountWarnings = []; - pendingComponentWillReceivePropsWarnings = []; - pendingUNSAFE_ComponentWillReceivePropsWarnings = []; - pendingComponentWillUpdateWarnings = []; - pendingUNSAFE_ComponentWillUpdateWarnings = []; - pendingLegacyContextWarning = new Map(); - }; - } + if (newLastBaseUpdate === null) { + newBaseState = newState; + } - /* - * The `'' + value` pattern (used in perf-sensitive code) throws for Symbol - * and Temporal.* types. See https://github.com/facebook/react/pull/22064. - * - * The functions in this module will throw an easier-to-understand, - * easier-to-debug exception with a clear errors message message explaining the - * problem. (Instead of a confusing exception thrown inside the implementation - * of the `value` object). - */ - // $FlowFixMe[incompatible-return] only called in DEV, so void return is not possible. - function typeName(value) { - { - // toStringTag is needed for namespaced types like Temporal.Instant - var hasToStringTag = typeof Symbol === "function" && Symbol.toStringTag; - var type = - (hasToStringTag && value[Symbol.toStringTag]) || - value.constructor.name || - "Object"; // $FlowFixMe[incompatible-return] + queue.baseState = newBaseState; + queue.firstBaseUpdate = newFirstBaseUpdate; + queue.lastBaseUpdate = newLastBaseUpdate; - return type; + if (firstBaseUpdate === null) { + // `queue.lanes` is used for entangling transitions. We can set it back to + // zero once the queue is empty. + queue.shared.lanes = NoLanes; + } // Set the remaining expiration time to be whatever is remaining in the queue. + // This should be fine because the only two other things that contribute to + // expiration time are props and context. We're already in the middle of the + // begin phase by the time we start processing the queue, so we've already + // dealt with the props. Context in components that specify + // shouldComponentUpdate is tricky; but we'll have to account for + // that regardless. + + markSkippedUpdateLanes(newLanes); + workInProgress.lanes = newLanes; + workInProgress.memoizedState = newState; } - } // $FlowFixMe[incompatible-return] only called in DEV, so void return is not possible. - function willCoercionThrow(value) { { - try { - testStringCoercion(value); - return false; - } catch (e) { - return true; - } + currentlyProcessingQueue = null; } } - function testStringCoercion(value) { - // If you ended up here by following an exception call stack, here's what's - // happened: you supplied an object or symbol value to React (as a prop, key, - // DOM attribute, CSS property, string ref, etc.) and when React tried to - // coerce it to a string using `'' + value`, an exception was thrown. - // - // The most common types that will cause this exception are `Symbol` instances - // and Temporal objects like `Temporal.Instant`. But any object that has a - // `valueOf` or `[Symbol.toPrimitive]` method that throws will also cause this - // exception. (Library authors do this to prevent users from using built-in - // numeric operators like `+` or comparison operators like `>=` because custom - // methods are needed to perform accurate arithmetic or comparison.) - // - // To fix the problem, coerce this object or symbol value to a string before - // passing it to React. The most reliable way is usually `String(value)`. - // - // To find which value is throwing, check the browser or debugger console. - // Before this exception was thrown, there should be `console.error` output - // that shows the type (Symbol, Temporal.PlainDate, etc.) that caused the - // problem and how that type was used: key, atrribute, input value prop, etc. - // In most cases, this console output also shows the component and its - // ancestor components where the exception happened. - // - // eslint-disable-next-line react-internal/safe-string-coercion - return "" + value; + function callCallback(callback, context) { + if (typeof callback !== "function") { + throw new Error( + "Invalid argument passed as callback. Expected a function. Instead " + + ("received: " + callback) + ); + } + + callback.call(context); } - function checkKeyStringCoercion(value) { - { - if (willCoercionThrow(value)) { - error( - "The provided key is an unsupported type %s." + - " This value must be coerced to a string before using it here.", - typeName(value) - ); - return testStringCoercion(value); // throw (to help callers find troubleshooting comments) - } - } + function resetHasForceUpdateBeforeProcessing() { + hasForceUpdate = false; } - function checkPropStringCoercion(value, propName) { - { - if (willCoercionThrow(value)) { - error( - "The provided `%s` prop is an unsupported type %s." + - " This value must be coerced to a string before using it here.", - propName, - typeName(value) - ); + function checkHasForceUpdateAfterProcessing() { + return hasForceUpdate; + } + function deferHiddenCallbacks(updateQueue) { + // When an update finishes on a hidden component, its callback should not + // be fired until/unless the component is made visible again. Stash the + // callback on the shared queue object so it can be fired later. + var newHiddenCallbacks = updateQueue.callbacks; - return testStringCoercion(value); // throw (to help callers find troubleshooting comments) + if (newHiddenCallbacks !== null) { + var existingHiddenCallbacks = updateQueue.shared.hiddenCallbacks; + + if (existingHiddenCallbacks === null) { + updateQueue.shared.hiddenCallbacks = newHiddenCallbacks; + } else { + updateQueue.shared.hiddenCallbacks = + existingHiddenCallbacks.concat(newHiddenCallbacks); } } } + function commitHiddenCallbacks(updateQueue, context) { + // This component is switching from hidden -> visible. Commit any callbacks + // that were previously deferred. + var hiddenCallbacks = updateQueue.shared.hiddenCallbacks; - var ReactCurrentActQueue$3 = ReactSharedInternals.ReactCurrentActQueue; // An error that is thrown (e.g. by `use`) to trigger Suspense. If we - // detect this is caught by userspace, we'll log a warning in development. - - var SuspenseException = new Error( - "Suspense Exception: This is not a real error! It's an implementation " + - "detail of `use` to interrupt the current render. You must either " + - "rethrow it immediately, or move the `use` call outside of the " + - "`try/catch` block. Capturing without rethrowing will lead to " + - "unexpected behavior.\n\n" + - "To handle async errors, wrap your component in an error boundary, or " + - "call the promise's `.catch` method and pass the result to `use`" - ); - var SuspenseyCommitException = new Error( - "Suspense Exception: This is not a real error, and should not leak into " + - "userspace. If you're seeing this, it's likely a bug in React." - ); // This is a noop thenable that we use to trigger a fallback in throwException. - // TODO: It would be better to refactor throwException into multiple functions - // so we can trigger a fallback directly without having to check the type. But - // for now this will do. + if (hiddenCallbacks !== null) { + updateQueue.shared.hiddenCallbacks = null; - var noopSuspenseyCommitThenable = { - then: function () { - { - error( - "Internal React error: A listener was unexpectedly attached to a " + - '"noop" thenable. This is a bug in React. Please file an issue.' - ); + for (var i = 0; i < hiddenCallbacks.length; i++) { + var callback = hiddenCallbacks[i]; + callCallback(callback, context); } } - }; - function createThenableState() { - // The ThenableState is created the first time a component suspends. If it - // suspends again, we'll reuse the same state. - return []; - } - function isThenableResolved(thenable) { - var status = thenable.status; - return status === "fulfilled" || status === "rejected"; } + function commitCallbacks(updateQueue, context) { + var callbacks = updateQueue.callbacks; - function noop() {} + if (callbacks !== null) { + updateQueue.callbacks = null; - function trackUsedThenable(thenableState, thenable, index) { - if (ReactCurrentActQueue$3.current !== null) { - ReactCurrentActQueue$3.didUsePromise = true; + for (var i = 0; i < callbacks.length; i++) { + var callback = callbacks[i]; + callCallback(callback, context); + } } + } - var previous = thenableState[index]; - - if (previous === undefined) { - thenableState.push(thenable); - } else { - if (previous !== thenable) { - // Reuse the previous thenable, and drop the new one. We can assume - // they represent the same value, because components are idempotent. - // Avoid an unhandled rejection errors for the Promises that we'll - // intentionally ignore. - thenable.then(noop, noop); - thenable = previous; - } - } // We use an expando to track the status and result of a thenable so that we - // can synchronously unwrap the value. Think of this as an extension of the - // Promise API, or a custom interface that is a superset of Thenable. - // - // If the thenable doesn't have a status, set it to "pending" and attach - // a listener that will update its status and result when it resolves. + /** + * 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. + */ - switch (thenable.status) { - case "fulfilled": { - var fulfilledValue = thenable.value; - return fulfilledValue; - } + function shallowEqual(objA, objB) { + if (objectIs(objA, objB)) { + return true; + } - case "rejected": { - var rejectedError = thenable.reason; - checkIfUseWrappedInAsyncCatch(rejectedError); - throw rejectedError; + 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++) { + var currentKey = keysA[i]; + + if ( + !hasOwnProperty.call(objB, currentKey) || // $FlowFixMe[incompatible-use] lost refinement of `objB` + !objectIs(objA[currentKey], objB[currentKey]) + ) { + return false; } + } - default: { - if (typeof thenable.status === "string") { - // Only instrument the thenable if the status if not defined. If - // it's defined, but an unknown value, assume it's been instrumented by - // some custom userspace implementation. We treat it as "pending". - // Attach a dummy listener, to ensure that any lazy initialization can - // happen. Flight lazily parses JSON when the value is actually awaited. - thenable.then(noop, noop); - } else { - // This is an uncached thenable that we haven't seen before. - // Detect infinite ping loops caused by uncached promises. - var root = getWorkInProgressRoot(); + return true; + } - if (root !== null && root.shellSuspendCounter > 100) { - // This root has suspended repeatedly in the shell without making any - // progress (i.e. committing something). This is highly suggestive of - // an infinite ping loop, often caused by an accidental Async Client - // Component. - // - // During a transition, we can suspend the work loop until the promise - // to resolve, but this is a sync render, so that's not an option. We - // also can't show a fallback, because none was provided. So our last - // resort is to throw an error. - // - // TODO: Remove this error in a future release. Other ways of handling - // this case include forcing a concurrent render, or putting the whole - // root into offscreen mode. - throw new Error( - "async/await is not yet supported in Client Components, only " + - "Server Components. This error is often caused by accidentally " + - "adding `'use client'` to a module that was originally written " + - "for the server." - ); - } + function describeFiber(fiber) { + var owner = fiber._debugOwner ? fiber._debugOwner.type : null; - var pendingThenable = thenable; - pendingThenable.status = "pending"; - pendingThenable.then( - function (fulfilledValue) { - if (thenable.status === "pending") { - var fulfilledThenable = thenable; - fulfilledThenable.status = "fulfilled"; - fulfilledThenable.value = fulfilledValue; - } - }, - function (error) { - if (thenable.status === "pending") { - var rejectedThenable = thenable; - rejectedThenable.status = "rejected"; - rejectedThenable.reason = error; - } - } - ); // Check one more time in case the thenable resolved synchronously. + switch (fiber.tag) { + case HostHoistable: + case HostSingleton: + case HostComponent: + return describeBuiltInComponentFrame(fiber.type, owner); - switch (thenable.status) { - case "fulfilled": { - var fulfilledThenable = thenable; - return fulfilledThenable.value; - } + case LazyComponent: + return describeBuiltInComponentFrame("Lazy", owner); - case "rejected": { - var rejectedThenable = thenable; - var _rejectedError = rejectedThenable.reason; - checkIfUseWrappedInAsyncCatch(_rejectedError); - throw _rejectedError; - } - } - } // Suspend. - // - // Throwing here is an implementation detail that allows us to unwind the - // call stack. But we shouldn't allow it to leak into userspace. Throw an - // opaque placeholder value instead of the actual thenable. If it doesn't - // get captured by the work loop, log a warning, because that means - // something in userspace must have caught it. + case SuspenseComponent: + return describeBuiltInComponentFrame("Suspense", owner); - suspendedThenable = thenable; + case SuspenseListComponent: + return describeBuiltInComponentFrame("SuspenseList", owner); - { - needsToResetSuspendedThenableDEV = true; - } + case FunctionComponent: + case IndeterminateComponent: + case SimpleMemoComponent: + return describeFunctionComponentFrame(fiber.type, owner); - throw SuspenseException; - } + case ForwardRef: + return describeFunctionComponentFrame(fiber.type.render, owner); + + case ClassComponent: + return describeClassComponentFrame(fiber.type, owner); + + default: + return ""; } } - // passed to the rest of the Suspense implementation — which, for historical - // reasons, expects to receive a thenable. - var suspendedThenable = null; - var needsToResetSuspendedThenableDEV = false; - function getSuspendedThenable() { - // This is called right after `use` suspends by throwing an exception. `use` - // throws an opaque value instead of the thenable itself so that it can't be - // caught in userspace. Then the work loop accesses the actual thenable using - // this function. - if (suspendedThenable === null) { - throw new Error( - "Expected a suspended thenable. This is a bug in React. Please file " + - "an issue." - ); - } + function getStackByFiberInDevAndProd(workInProgress) { + try { + var info = ""; + var node = workInProgress; - var thenable = suspendedThenable; - suspendedThenable = null; + do { + info += describeFiber(node); // $FlowFixMe[incompatible-type] we bail out when we get a null + + node = node.return; + } while (node); + + return info; + } catch (x) { + return "\nError generating stack: " + x.message + "\n" + x.stack; + } + } + var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; + var current = null; + var isRendering = false; + function getCurrentFiberOwnerNameInDevOrNull() { { - needsToResetSuspendedThenableDEV = false; + if (current === null) { + return null; + } + + var owner = current._debugOwner; + + if (owner !== null && typeof owner !== "undefined") { + return getComponentNameFromFiber(owner); + } } - return thenable; + return null; } - function checkIfUseWrappedInTryCatch() { + + function getCurrentFiberStackInDev() { { - // This was set right before SuspenseException was thrown, and it should - // have been cleared when the exception was handled. If it wasn't, - // it must have been caught by userspace. - if (needsToResetSuspendedThenableDEV) { - needsToResetSuspendedThenableDEV = false; - return true; - } + if (current === null) { + return ""; + } // Safe because if current fiber exists, we are reconciling, + // and it is guaranteed to be the work-in-progress version. + + return getStackByFiberInDevAndProd(current); } + } - return false; + function resetCurrentFiber() { + { + ReactDebugCurrentFrame.getCurrentStack = null; + current = null; + isRendering = false; + } } - function checkIfUseWrappedInAsyncCatch(rejectedReason) { - // This check runs in prod, too, because it prevents a more confusing - // downstream error, where SuspenseException is caught by a promise and - // thrown asynchronously. - // TODO: Another way to prevent SuspenseException from leaking into an async - // execution context is to check the dispatcher every time `use` is called, - // or some equivalent. That might be preferable for other reasons, too, since - // it matches how we prevent similar mistakes for other hooks. - if (rejectedReason === SuspenseException) { - throw new Error( - "Hooks are not supported inside an async component. This " + - "error is often caused by accidentally adding `'use client'` " + - "to a module that was originally written for the server." - ); + function setCurrentFiber(fiber) { + { + ReactDebugCurrentFrame.getCurrentStack = + fiber === null ? null : getCurrentFiberStackInDev; + current = fiber; + isRendering = false; + } + } + function getCurrentFiber() { + { + return current; + } + } + function setIsRendering(rendering) { + { + isRendering = rendering; } } - var thenableState$1 = null; - var thenableIndexCounter$1 = 0; - var didWarnAboutMaps; - var didWarnAboutGenerators; - var didWarnAboutStringRefs; - var ownerHasKeyUseWarning; - var ownerHasFunctionTypeWarning; - - var warnForMissingKey = function (child, returnFiber) {}; + var ReactStrictModeWarnings = { + recordUnsafeLifecycleWarnings: function (fiber, instance) {}, + flushPendingUnsafeLifecycleWarnings: function () {}, + recordLegacyContextWarning: function (fiber, instance) {}, + flushLegacyContextWarning: function () {}, + discardPendingWarnings: function () {} + }; { - didWarnAboutMaps = false; - didWarnAboutGenerators = false; - didWarnAboutStringRefs = {}; - /** - * Warn if there's no key explicitly set on dynamic arrays of children or - * object keys are not valid. This allows us to keep track of children between - * updates. - */ + var findStrictRoot = function (fiber) { + var maybeStrictRoot = null; + var node = fiber; - ownerHasKeyUseWarning = {}; - ownerHasFunctionTypeWarning = {}; + while (node !== null) { + if (node.mode & StrictLegacyMode) { + maybeStrictRoot = node; + } - warnForMissingKey = function (child, returnFiber) { - if (child === null || typeof child !== "object") { - return; + node = node.return; } - if (!child._store || child._store.validated || child.key != null) { - return; - } + return maybeStrictRoot; + }; - if (typeof child._store !== "object") { - throw new Error( - "React Component in warnForMissingKey should have a _store. " + - "This error is likely caused by a bug in React. Please file an issue." - ); - } // $FlowFixMe[cannot-write] unable to narrow type from mixed to writable object + var setToSortedString = function (set) { + var array = []; + set.forEach(function (value) { + array.push(value); + }); + return array.sort().join(", "); + }; - child._store.validated = true; - var componentName = - getComponentNameFromFiber(returnFiber) || "Component"; + var pendingComponentWillMountWarnings = []; + var pendingUNSAFE_ComponentWillMountWarnings = []; + var pendingComponentWillReceivePropsWarnings = []; + var pendingUNSAFE_ComponentWillReceivePropsWarnings = []; + var pendingComponentWillUpdateWarnings = []; + var pendingUNSAFE_ComponentWillUpdateWarnings = []; // Tracks components we have already warned about. - if (ownerHasKeyUseWarning[componentName]) { + var didWarnAboutUnsafeLifecycles = new Set(); + + ReactStrictModeWarnings.recordUnsafeLifecycleWarnings = function ( + fiber, + instance + ) { + // Dedupe strategy: Warn once per component. + if (didWarnAboutUnsafeLifecycles.has(fiber.type)) { return; } - ownerHasKeyUseWarning[componentName] = true; - - error( - "Each child in a list should have a unique " + - '"key" prop. See https://reactjs.org/link/warning-keys for ' + - "more information." - ); - }; - } + if ( + typeof instance.componentWillMount === "function" && // Don't warn about react-lifecycles-compat polyfilled components. + instance.componentWillMount.__suppressDeprecationWarning !== true + ) { + pendingComponentWillMountWarnings.push(fiber); + } - function isReactClass(type) { - return type.prototype && type.prototype.isReactComponent; - } + if ( + fiber.mode & StrictLegacyMode && + typeof instance.UNSAFE_componentWillMount === "function" + ) { + pendingUNSAFE_ComponentWillMountWarnings.push(fiber); + } - function unwrapThenable(thenable) { - var index = thenableIndexCounter$1; - thenableIndexCounter$1 += 1; + if ( + typeof instance.componentWillReceiveProps === "function" && + instance.componentWillReceiveProps.__suppressDeprecationWarning !== + true + ) { + pendingComponentWillReceivePropsWarnings.push(fiber); + } - if (thenableState$1 === null) { - thenableState$1 = createThenableState(); - } + if ( + fiber.mode & StrictLegacyMode && + typeof instance.UNSAFE_componentWillReceiveProps === "function" + ) { + pendingUNSAFE_ComponentWillReceivePropsWarnings.push(fiber); + } - return trackUsedThenable(thenableState$1, thenable, index); - } + if ( + typeof instance.componentWillUpdate === "function" && + instance.componentWillUpdate.__suppressDeprecationWarning !== true + ) { + pendingComponentWillUpdateWarnings.push(fiber); + } - function coerceRef(returnFiber, current, element) { - var mixedRef = element.ref; + if ( + fiber.mode & StrictLegacyMode && + typeof instance.UNSAFE_componentWillUpdate === "function" + ) { + pendingUNSAFE_ComponentWillUpdateWarnings.push(fiber); + } + }; - if ( - mixedRef !== null && - typeof mixedRef !== "function" && - typeof mixedRef !== "object" - ) { - { - if ( - // We warn in ReactElement.js if owner and self are equal for string refs - // because these cannot be automatically converted to an arrow function - // using a codemod. Therefore, we don't have to warn about string refs again. - !( - element._owner && - element._self && - element._owner.stateNode !== element._self - ) && // Will already throw with "Function components cannot have string refs" - !(element._owner && element._owner.tag !== ClassComponent) && // Will already warn with "Function components cannot be given refs" - !( - typeof element.type === "function" && !isReactClass(element.type) - ) && // Will already throw with "Element ref was specified as a string (someStringRef) but no owner was set" - element._owner - ) { - var componentName = - getComponentNameFromFiber(returnFiber) || "Component"; + ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = + function () { + // We do an initial pass to gather component names + var componentWillMountUniqueNames = new Set(); - if (!didWarnAboutStringRefs[componentName]) { - error( - 'Component "%s" contains the string ref "%s". Support for string refs ' + - "will be removed in a future major release. We recommend using " + - "useRef() or createRef() instead. " + - "Learn more about using refs safely here: " + - "https://reactjs.org/link/strict-mode-string-ref", - componentName, - mixedRef + if (pendingComponentWillMountWarnings.length > 0) { + pendingComponentWillMountWarnings.forEach(function (fiber) { + componentWillMountUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" ); - - didWarnAboutStringRefs[componentName] = true; - } + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingComponentWillMountWarnings = []; } - } - - if (element._owner) { - var owner = element._owner; - var inst; - if (owner) { - var ownerFiber = owner; + var UNSAFE_componentWillMountUniqueNames = new Set(); - if (ownerFiber.tag !== ClassComponent) { - throw new Error( - "Function components cannot have string refs. " + - "We recommend using useRef() instead. " + - "Learn more about using refs safely here: " + - "https://reactjs.org/link/strict-mode-string-ref" + if (pendingUNSAFE_ComponentWillMountWarnings.length > 0) { + pendingUNSAFE_ComponentWillMountWarnings.forEach(function (fiber) { + UNSAFE_componentWillMountUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" ); - } - - inst = ownerFiber.stateNode; + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingUNSAFE_ComponentWillMountWarnings = []; } - if (!inst) { - throw new Error( - "Missing owner for string ref " + - mixedRef + - ". This error is likely caused by a " + - "bug in React. Please file an issue." - ); - } // Assigning this to a const so Flow knows it won't change in the closure - - var resolvedInst = inst; + var componentWillReceivePropsUniqueNames = new Set(); - { - checkPropStringCoercion(mixedRef, "ref"); + if (pendingComponentWillReceivePropsWarnings.length > 0) { + pendingComponentWillReceivePropsWarnings.forEach(function (fiber) { + componentWillReceivePropsUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingComponentWillReceivePropsWarnings = []; } - var stringRef = "" + mixedRef; // Check if previous string ref matches new string ref + var UNSAFE_componentWillReceivePropsUniqueNames = new Set(); - if ( - current !== null && - current.ref !== null && - typeof current.ref === "function" && - current.ref._stringRef === stringRef - ) { - return current.ref; + if (pendingUNSAFE_ComponentWillReceivePropsWarnings.length > 0) { + pendingUNSAFE_ComponentWillReceivePropsWarnings.forEach( + function (fiber) { + UNSAFE_componentWillReceivePropsUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + } + ); + pendingUNSAFE_ComponentWillReceivePropsWarnings = []; } - var ref = function (value) { - var refs = resolvedInst.refs; + var componentWillUpdateUniqueNames = new Set(); - if (value === null) { - delete refs[stringRef]; - } else { - refs[stringRef] = value; - } - }; + if (pendingComponentWillUpdateWarnings.length > 0) { + pendingComponentWillUpdateWarnings.forEach(function (fiber) { + componentWillUpdateUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingComponentWillUpdateWarnings = []; + } - ref._stringRef = stringRef; - return ref; - } else { - if (typeof mixedRef !== "string") { - throw new Error( - "Expected ref to be a function, a string, an object returned by React.createRef(), or null." + var UNSAFE_componentWillUpdateUniqueNames = new Set(); + + if (pendingUNSAFE_ComponentWillUpdateWarnings.length > 0) { + pendingUNSAFE_ComponentWillUpdateWarnings.forEach(function (fiber) { + UNSAFE_componentWillUpdateUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingUNSAFE_ComponentWillUpdateWarnings = []; + } // Finally, we flush all the warnings + // UNSAFE_ ones before the deprecated ones, since they'll be 'louder' + + if (UNSAFE_componentWillMountUniqueNames.size > 0) { + var sortedNames = setToSortedString( + UNSAFE_componentWillMountUniqueNames + ); + + error( + "Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code. " + + "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + + "* Move code with side effects to componentDidMount, and set initial state in the constructor.\n" + + "\nPlease update the following components: %s", + sortedNames ); } - if (!element._owner) { - throw new Error( - "Element ref was specified as a string (" + - mixedRef + - ") but no owner was set. This could happen for one of" + - " the following reasons:\n" + - "1. You may be adding a ref to a function component\n" + - "2. You may be adding a ref to a component that was not created inside a component's render method\n" + - "3. You have multiple copies of React loaded\n" + - "See https://reactjs.org/link/refs-must-have-owner for more information." + if (UNSAFE_componentWillReceivePropsUniqueNames.size > 0) { + var _sortedNames = setToSortedString( + UNSAFE_componentWillReceivePropsUniqueNames + ); + + error( + "Using UNSAFE_componentWillReceiveProps in strict mode is not recommended " + + "and may indicate bugs in your code. " + + "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + + "* Move data fetching code or side effects to componentDidUpdate.\n" + + "* If you're updating state whenever props change, " + + "refactor your code to use memoization techniques or move it to " + + "static getDerivedStateFromProps. Learn more at: https://reactjs.org/link/derived-state\n" + + "\nPlease update the following components: %s", + _sortedNames ); } - } - } - return mixedRef; - } + if (UNSAFE_componentWillUpdateUniqueNames.size > 0) { + var _sortedNames2 = setToSortedString( + UNSAFE_componentWillUpdateUniqueNames + ); - function throwOnInvalidObjectType(returnFiber, newChild) { - // $FlowFixMe[method-unbinding] - var childString = Object.prototype.toString.call(newChild); - throw new Error( - "Objects are not valid as a React child (found: " + - (childString === "[object Object]" - ? "object with keys {" + Object.keys(newChild).join(", ") + "}" - : childString) + - "). " + - "If you meant to render a collection of children, use an array " + - "instead." - ); - } + error( + "Using UNSAFE_componentWillUpdate in strict mode is not recommended " + + "and may indicate bugs in your code. " + + "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + + "* Move data fetching code or side effects to componentDidUpdate.\n" + + "\nPlease update the following components: %s", + _sortedNames2 + ); + } - function warnOnFunctionType(returnFiber) { - { - var componentName = - getComponentNameFromFiber(returnFiber) || "Component"; + if (componentWillMountUniqueNames.size > 0) { + var _sortedNames3 = setToSortedString( + componentWillMountUniqueNames + ); - if (ownerHasFunctionTypeWarning[componentName]) { - return; - } + warn( + "componentWillMount has been renamed, and is not recommended for use. " + + "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + + "* Move code with side effects to componentDidMount, and set initial state in the constructor.\n" + + "* Rename componentWillMount to UNSAFE_componentWillMount to suppress " + + "this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. " + + "To rename all deprecated lifecycles to their new names, you can run " + + "`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n" + + "\nPlease update the following components: %s", + _sortedNames3 + ); + } - ownerHasFunctionTypeWarning[componentName] = true; + if (componentWillReceivePropsUniqueNames.size > 0) { + var _sortedNames4 = setToSortedString( + componentWillReceivePropsUniqueNames + ); - error( - "Functions are not valid as a React child. This may happen if " + - "you return a Component instead of from render. " + - "Or maybe you meant to call this function rather than return it." - ); - } - } + warn( + "componentWillReceiveProps has been renamed, and is not recommended for use. " + + "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + + "* Move data fetching code or side effects to componentDidUpdate.\n" + + "* If you're updating state whenever props change, refactor your " + + "code to use memoization techniques or move it to " + + "static getDerivedStateFromProps. Learn more at: https://reactjs.org/link/derived-state\n" + + "* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress " + + "this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. " + + "To rename all deprecated lifecycles to their new names, you can run " + + "`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n" + + "\nPlease update the following components: %s", + _sortedNames4 + ); + } - function resolveLazy(lazyType) { - var payload = lazyType._payload; - var init = lazyType._init; - return init(payload); - } // This wrapper function exists because I expect to clone the code in each path - // to be able to optimize each path individually by branching early. This needs - // a compiler or we can do it manually. Helpers that don't need this branching - // live outside of this function. + if (componentWillUpdateUniqueNames.size > 0) { + var _sortedNames5 = setToSortedString( + componentWillUpdateUniqueNames + ); - function createChildReconciler(shouldTrackSideEffects) { - function deleteChild(returnFiber, childToDelete) { - if (!shouldTrackSideEffects) { - // Noop. - return; - } + warn( + "componentWillUpdate has been renamed, and is not recommended for use. " + + "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + + "* Move data fetching code or side effects to componentDidUpdate.\n" + + "* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress " + + "this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. " + + "To rename all deprecated lifecycles to their new names, you can run " + + "`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n" + + "\nPlease update the following components: %s", + _sortedNames5 + ); + } + }; - var deletions = returnFiber.deletions; + var pendingLegacyContextWarning = new Map(); // Tracks components we have already warned about. - if (deletions === null) { - returnFiber.deletions = [childToDelete]; - returnFiber.flags |= ChildDeletion; - } else { - deletions.push(childToDelete); - } - } + var didWarnAboutLegacyContext = new Set(); - 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. + ReactStrictModeWarnings.recordLegacyContextWarning = function ( + fiber, + instance + ) { + var strictRoot = findStrictRoot(fiber); - var childToDelete = currentFirstChild; + if (strictRoot === null) { + error( + "Expected to find a StrictMode component in a strict mode tree. " + + "This error is likely caused by a bug in React. Please file an issue." + ); - while (childToDelete !== null) { - deleteChild(returnFiber, childToDelete); - childToDelete = childToDelete.sibling; - } + return; + } // Dedup strategy: Warn once per component. - return null; - } + if (didWarnAboutLegacyContext.has(fiber.type)) { + return; + } - function mapRemainingChildren(returnFiber, currentFirstChild) { - // Add the remaining children to a temporary map so that we can find them by - // keys quickly. Implicit (null) keys get added to this set with their index - // instead. - var existingChildren = new Map(); - var existingChild = currentFirstChild; + var warningsForRoot = pendingLegacyContextWarning.get(strictRoot); - while (existingChild !== null) { - if (existingChild.key !== null) { - existingChildren.set(existingChild.key, existingChild); - } else { - existingChildren.set(existingChild.index, existingChild); + if ( + fiber.type.contextTypes != null || + fiber.type.childContextTypes != null || + (instance !== null && typeof instance.getChildContext === "function") + ) { + if (warningsForRoot === undefined) { + warningsForRoot = []; + pendingLegacyContextWarning.set(strictRoot, warningsForRoot); } - existingChild = existingChild.sibling; + warningsForRoot.push(fiber); } + }; - return existingChildren; - } + ReactStrictModeWarnings.flushLegacyContextWarning = function () { + pendingLegacyContextWarning.forEach(function (fiberArray, strictRoot) { + if (fiberArray.length === 0) { + return; + } - function useFiber(fiber, pendingProps) { - // We currently set sibling to null and index to 0 here because it is easy - // to forget to do before returning it. E.g. for the single child case. - var clone = createWorkInProgress(fiber, pendingProps); - clone.index = 0; - clone.sibling = null; - return clone; - } + var firstFiber = fiberArray[0]; + var uniqueNames = new Set(); + fiberArray.forEach(function (fiber) { + uniqueNames.add(getComponentNameFromFiber(fiber) || "Component"); + didWarnAboutLegacyContext.add(fiber.type); + }); + var sortedNames = setToSortedString(uniqueNames); - function placeChild(newFiber, lastPlacedIndex, newIndex) { - newFiber.index = newIndex; + try { + setCurrentFiber(firstFiber); - if (!shouldTrackSideEffects) { - // During hydration, the useId algorithm needs to know which fibers are - // part of a list of children (arrays, iterators). - newFiber.flags |= Forked; - return lastPlacedIndex; - } + error( + "Legacy context API has been detected within a strict-mode tree." + + "\n\nThe old API will be supported in all 16.x releases, but applications " + + "using it should migrate to the new version." + + "\n\nPlease update the following components: %s" + + "\n\nLearn more about this warning here: https://reactjs.org/link/legacy-context", + sortedNames + ); + } finally { + resetCurrentFiber(); + } + }); + }; - var current = newFiber.alternate; + ReactStrictModeWarnings.discardPendingWarnings = function () { + pendingComponentWillMountWarnings = []; + pendingUNSAFE_ComponentWillMountWarnings = []; + pendingComponentWillReceivePropsWarnings = []; + pendingUNSAFE_ComponentWillReceivePropsWarnings = []; + pendingComponentWillUpdateWarnings = []; + pendingUNSAFE_ComponentWillUpdateWarnings = []; + pendingLegacyContextWarning = new Map(); + }; + } - if (current !== null) { - var oldIndex = current.index; + /* + * The `'' + value` pattern (used in perf-sensitive code) throws for Symbol + * and Temporal.* types. See https://github.com/facebook/react/pull/22064. + * + * The functions in this module will throw an easier-to-understand, + * easier-to-debug exception with a clear errors message message explaining the + * problem. (Instead of a confusing exception thrown inside the implementation + * of the `value` object). + */ + // $FlowFixMe[incompatible-return] only called in DEV, so void return is not possible. + function typeName(value) { + { + // toStringTag is needed for namespaced types like Temporal.Instant + var hasToStringTag = typeof Symbol === "function" && Symbol.toStringTag; + var type = + (hasToStringTag && value[Symbol.toStringTag]) || + value.constructor.name || + "Object"; // $FlowFixMe[incompatible-return] - if (oldIndex < lastPlacedIndex) { - // This is a move. - newFiber.flags |= Placement | PlacementDEV; - return lastPlacedIndex; - } else { - // This item can stay in place. - return oldIndex; - } - } else { - // This is an insertion. - newFiber.flags |= Placement | PlacementDEV; - return lastPlacedIndex; + return type; + } + } // $FlowFixMe[incompatible-return] only called in DEV, so void return is not possible. + + function willCoercionThrow(value) { + { + try { + testStringCoercion(value); + return false; + } catch (e) { + return true; } } + } - function placeSingleChild(newFiber) { - // This is simpler for the single child case. We only need to do a - // placement for inserting new children. - if (shouldTrackSideEffects && newFiber.alternate === null) { - newFiber.flags |= Placement | PlacementDEV; + function testStringCoercion(value) { + // If you ended up here by following an exception call stack, here's what's + // happened: you supplied an object or symbol value to React (as a prop, key, + // DOM attribute, CSS property, string ref, etc.) and when React tried to + // coerce it to a string using `'' + value`, an exception was thrown. + // + // The most common types that will cause this exception are `Symbol` instances + // and Temporal objects like `Temporal.Instant`. But any object that has a + // `valueOf` or `[Symbol.toPrimitive]` method that throws will also cause this + // exception. (Library authors do this to prevent users from using built-in + // numeric operators like `+` or comparison operators like `>=` because custom + // methods are needed to perform accurate arithmetic or comparison.) + // + // To fix the problem, coerce this object or symbol value to a string before + // passing it to React. The most reliable way is usually `String(value)`. + // + // To find which value is throwing, check the browser or debugger console. + // Before this exception was thrown, there should be `console.error` output + // that shows the type (Symbol, Temporal.PlainDate, etc.) that caused the + // problem and how that type was used: key, atrribute, input value prop, etc. + // In most cases, this console output also shows the component and its + // ancestor components where the exception happened. + // + // eslint-disable-next-line react-internal/safe-string-coercion + return "" + value; + } + function checkKeyStringCoercion(value) { + { + if (willCoercionThrow(value)) { + error( + "The provided key is an unsupported type %s." + + " This value must be coerced to a string before using it here.", + typeName(value) + ); + + return testStringCoercion(value); // throw (to help callers find troubleshooting comments) } + } + } + function checkPropStringCoercion(value, propName) { + { + if (willCoercionThrow(value)) { + error( + "The provided `%s` prop is an unsupported type %s." + + " This value must be coerced to a string before using it here.", + propName, + typeName(value) + ); - return newFiber; + return testStringCoercion(value); // throw (to help callers find troubleshooting comments) + } } + } - function updateTextNode(returnFiber, current, textContent, lanes) { - if (current === null || current.tag !== HostText) { - // Insert - var created = createFiberFromText( - textContent, - returnFiber.mode, - lanes + var ReactCurrentActQueue$2 = ReactSharedInternals.ReactCurrentActQueue; + + function getThenablesFromState(state) { + { + var devState = state; + return devState.thenables; + } + } // An error that is thrown (e.g. by `use`) to trigger Suspense. If we + // detect this is caught by userspace, we'll log a warning in development. + + var SuspenseException = new Error( + "Suspense Exception: This is not a real error! It's an implementation " + + "detail of `use` to interrupt the current render. You must either " + + "rethrow it immediately, or move the `use` call outside of the " + + "`try/catch` block. Capturing without rethrowing will lead to " + + "unexpected behavior.\n\n" + + "To handle async errors, wrap your component in an error boundary, or " + + "call the promise's `.catch` method and pass the result to `use`" + ); + var SuspenseyCommitException = new Error( + "Suspense Exception: This is not a real error, and should not leak into " + + "userspace. If you're seeing this, it's likely a bug in React." + ); // This is a noop thenable that we use to trigger a fallback in throwException. + // TODO: It would be better to refactor throwException into multiple functions + // so we can trigger a fallback directly without having to check the type. But + // for now this will do. + + var noopSuspenseyCommitThenable = { + then: function () { + { + error( + "Internal React error: A listener was unexpectedly attached to a " + + '"noop" thenable. This is a bug in React. Please file an issue.' ); - created.return = returnFiber; - return created; - } else { - // Update - var existing = useFiber(current, textContent); - existing.return = returnFiber; - return existing; } } + }; + function createThenableState() { + // The ThenableState is created the first time a component suspends. If it + // suspends again, we'll reuse the same state. + { + return { + didWarnAboutUncachedPromise: false, + thenables: [] + }; + } + } + function isThenableResolved(thenable) { + var status = thenable.status; + return status === "fulfilled" || status === "rejected"; + } - function updateElement(returnFiber, current, element, lanes) { - var elementType = element.type; + function noop() {} - if (elementType === REACT_FRAGMENT_TYPE) { - return updateFragment( - returnFiber, - current, - element.props.children, - lanes, - element.key - ); + function trackUsedThenable(thenableState, thenable, index) { + if (ReactCurrentActQueue$2.current !== null) { + ReactCurrentActQueue$2.didUsePromise = true; + } + + var trackedThenables = getThenablesFromState(thenableState); + var previous = trackedThenables[index]; + + if (previous === undefined) { + trackedThenables.push(thenable); + } else { + if (previous !== thenable) { + // Reuse the previous thenable, and drop the new one. We can assume + // they represent the same value, because components are idempotent. + { + var thenableStateDev = thenableState; + + if (!thenableStateDev.didWarnAboutUncachedPromise) { + // We should only warn the first time an uncached thenable is + // discovered per component, because if there are multiple, the + // subsequent ones are likely derived from the first. + // + // We track this on the thenableState instead of deduping using the + // component name like we usually do, because in the case of a + // promise-as-React-node, the owner component is likely different from + // the parent that's currently being reconciled. We'd have to track + // the owner using state, which we're trying to move away from. Though + // since this is dev-only, maybe that'd be OK. + // + // However, another benefit of doing it this way is we might + // eventually have a thenableState per memo/Forget boundary instead + // of per component, so this would allow us to have more + // granular warnings. + thenableStateDev.didWarnAboutUncachedPromise = true; // TODO: This warning should link to a corresponding docs page. + + error( + "A component was suspended by an uncached promise. Creating " + + "promises inside a Client Component or hook is not yet " + + "supported, except via a Suspense-compatible library or framework." + ); + } + } // Avoid an unhandled rejection errors for the Promises that we'll + // intentionally ignore. + + thenable.then(noop, noop); + thenable = previous; } + } // We use an expando to track the status and result of a thenable so that we + // can synchronously unwrap the value. Think of this as an extension of the + // Promise API, or a custom interface that is a superset of Thenable. + // + // If the thenable doesn't have a status, set it to "pending" and attach + // a listener that will update its status and result when it resolves. - if (current !== null) { - if ( - current.elementType === elementType || // Keep this check inline so it only runs on the false path: - isCompatibleFamilyForHotReloading(current, element) || // Lazy types should reconcile their resolved type. - // We need to do this after the Hot Reloading check above, - // because hot reloading has different semantics than prod because - // it doesn't resuspend. So we can't let the call below suspend. - (typeof elementType === "object" && - elementType !== null && - elementType.$$typeof === REACT_LAZY_TYPE && - resolveLazy(elementType) === current.type) - ) { - // Move based on index - var existing = useFiber(current, element.props); - existing.ref = coerceRef(returnFiber, current, element); - existing.return = returnFiber; + switch (thenable.status) { + case "fulfilled": { + var fulfilledValue = thenable.value; + return fulfilledValue; + } - { - existing._debugSource = element._source; - existing._debugOwner = element._owner; + case "rejected": { + var rejectedError = thenable.reason; + checkIfUseWrappedInAsyncCatch(rejectedError); + throw rejectedError; + } + + default: { + if (typeof thenable.status === "string") { + // Only instrument the thenable if the status if not defined. If + // it's defined, but an unknown value, assume it's been instrumented by + // some custom userspace implementation. We treat it as "pending". + // Attach a dummy listener, to ensure that any lazy initialization can + // happen. Flight lazily parses JSON when the value is actually awaited. + thenable.then(noop, noop); + } else { + // This is an uncached thenable that we haven't seen before. + // Detect infinite ping loops caused by uncached promises. + var root = getWorkInProgressRoot(); + + if (root !== null && root.shellSuspendCounter > 100) { + // This root has suspended repeatedly in the shell without making any + // progress (i.e. committing something). This is highly suggestive of + // an infinite ping loop, often caused by an accidental Async Client + // Component. + // + // During a transition, we can suspend the work loop until the promise + // to resolve, but this is a sync render, so that's not an option. We + // also can't show a fallback, because none was provided. So our last + // resort is to throw an error. + // + // TODO: Remove this error in a future release. Other ways of handling + // this case include forcing a concurrent render, or putting the whole + // root into offscreen mode. + throw new Error( + "async/await is not yet supported in Client Components, only " + + "Server Components. This error is often caused by accidentally " + + "adding `'use client'` to a module that was originally written " + + "for the server." + ); } - return existing; - } - } // Insert + var pendingThenable = thenable; + pendingThenable.status = "pending"; + pendingThenable.then( + function (fulfilledValue) { + if (thenable.status === "pending") { + var fulfilledThenable = thenable; + fulfilledThenable.status = "fulfilled"; + fulfilledThenable.value = fulfilledValue; + } + }, + function (error) { + if (thenable.status === "pending") { + var rejectedThenable = thenable; + rejectedThenable.status = "rejected"; + rejectedThenable.reason = error; + } + } + ); // Check one more time in case the thenable resolved synchronously. + + switch (thenable.status) { + case "fulfilled": { + var fulfilledThenable = thenable; + return fulfilledThenable.value; + } + + case "rejected": { + var rejectedThenable = thenable; + var _rejectedError = rejectedThenable.reason; + checkIfUseWrappedInAsyncCatch(_rejectedError); + throw _rejectedError; + } + } + } // Suspend. + // + // Throwing here is an implementation detail that allows us to unwind the + // call stack. But we shouldn't allow it to leak into userspace. Throw an + // opaque placeholder value instead of the actual thenable. If it doesn't + // get captured by the work loop, log a warning, because that means + // something in userspace must have caught it. + + suspendedThenable = thenable; - var created = createFiberFromElement(element, returnFiber.mode, lanes); - created.ref = coerceRef(returnFiber, current, element); - created.return = returnFiber; - return created; - } + { + needsToResetSuspendedThenableDEV = true; + } - function updatePortal(returnFiber, current, portal, lanes) { - if ( - current === null || - current.tag !== HostPortal || - current.stateNode.containerInfo !== portal.containerInfo || - current.stateNode.implementation !== portal.implementation - ) { - // Insert - var created = createFiberFromPortal(portal, returnFiber.mode, lanes); - created.return = returnFiber; - return created; - } else { - // Update - var existing = useFiber(current, portal.children || []); - existing.return = returnFiber; - return existing; + throw SuspenseException; } } + } + // passed to the rest of the Suspense implementation — which, for historical + // reasons, expects to receive a thenable. - function updateFragment(returnFiber, current, fragment, lanes, key) { - if (current === null || current.tag !== Fragment) { - // Insert - var created = createFiberFromFragment( - fragment, - returnFiber.mode, - lanes, - key - ); - created.return = returnFiber; - return created; - } else { - // Update - var existing = useFiber(current, fragment); - existing.return = returnFiber; - return existing; - } + var suspendedThenable = null; + var needsToResetSuspendedThenableDEV = false; + function getSuspendedThenable() { + // This is called right after `use` suspends by throwing an exception. `use` + // throws an opaque value instead of the thenable itself so that it can't be + // caught in userspace. Then the work loop accesses the actual thenable using + // this function. + if (suspendedThenable === null) { + throw new Error( + "Expected a suspended thenable. This is a bug in React. Please file " + + "an issue." + ); } - function createChild(returnFiber, newChild, lanes) { - if ( - (typeof newChild === "string" && newChild !== "") || - typeof newChild === "number" - ) { - // Text nodes don't have keys. If the previous node is implicitly keyed - // we can continue to replace it without aborting even if it is not a text - // node. - var created = createFiberFromText( - "" + newChild, - returnFiber.mode, - lanes - ); - created.return = returnFiber; - return created; - } - - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: { - var _created = createFiberFromElement( - newChild, - returnFiber.mode, - lanes - ); - - _created.ref = coerceRef(returnFiber, null, newChild); - _created.return = returnFiber; - return _created; - } + var thenable = suspendedThenable; + suspendedThenable = null; - case REACT_PORTAL_TYPE: { - var _created2 = createFiberFromPortal( - newChild, - returnFiber.mode, - lanes - ); + { + needsToResetSuspendedThenableDEV = false; + } - _created2.return = returnFiber; - return _created2; - } + return thenable; + } + function checkIfUseWrappedInTryCatch() { + { + // This was set right before SuspenseException was thrown, and it should + // have been cleared when the exception was handled. If it wasn't, + // it must have been caught by userspace. + if (needsToResetSuspendedThenableDEV) { + needsToResetSuspendedThenableDEV = false; + return true; + } + } - case REACT_LAZY_TYPE: { - var payload = newChild._payload; - var init = newChild._init; - return createChild(returnFiber, init(payload), lanes); - } - } + return false; + } + function checkIfUseWrappedInAsyncCatch(rejectedReason) { + // This check runs in prod, too, because it prevents a more confusing + // downstream error, where SuspenseException is caught by a promise and + // thrown asynchronously. + // TODO: Another way to prevent SuspenseException from leaking into an async + // execution context is to check the dispatcher every time `use` is called, + // or some equivalent. That might be preferable for other reasons, too, since + // it matches how we prevent similar mistakes for other hooks. + if (rejectedReason === SuspenseException) { + throw new Error( + "Hooks are not supported inside an async component. This " + + "error is often caused by accidentally adding `'use client'` " + + "to a module that was originally written for the server." + ); + } + } - if (isArray(newChild) || getIteratorFn(newChild)) { - var _created3 = createFiberFromFragment( - newChild, - returnFiber.mode, - lanes, - null - ); + var thenableState$1 = null; + var thenableIndexCounter$1 = 0; + var didWarnAboutMaps; + var didWarnAboutGenerators; + var didWarnAboutStringRefs; + var ownerHasKeyUseWarning; + var ownerHasFunctionTypeWarning; - _created3.return = returnFiber; - return _created3; - } // Usable node types - // - // Unwrap the inner value and recursively call this function again. + var warnForMissingKey = function (child, returnFiber) {}; - if (typeof newChild.then === "function") { - var thenable = newChild; - return createChild(returnFiber, unwrapThenable(thenable), lanes); - } + { + didWarnAboutMaps = false; + didWarnAboutGenerators = false; + didWarnAboutStringRefs = {}; + /** + * Warn if there's no key explicitly set on dynamic arrays of children or + * object keys are not valid. This allows us to keep track of children between + * updates. + */ - if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) { - var context = newChild; - return createChild( - returnFiber, - readContextDuringReconcilation(returnFiber, context, lanes), - lanes - ); - } + ownerHasKeyUseWarning = {}; + ownerHasFunctionTypeWarning = {}; - throwOnInvalidObjectType(returnFiber, newChild); + warnForMissingKey = function (child, returnFiber) { + if (child === null || typeof child !== "object") { + return; } - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber); - } + if (!child._store || child._store.validated || child.key != null) { + return; } - return null; - } - - function updateSlot(returnFiber, oldFiber, newChild, lanes) { - // Update the fiber if the keys match, otherwise return null. - var key = oldFiber !== null ? oldFiber.key : null; + if (typeof child._store !== "object") { + throw new Error( + "React Component in warnForMissingKey should have a _store. " + + "This error is likely caused by a bug in React. Please file an issue." + ); + } // $FlowFixMe[cannot-write] unable to narrow type from mixed to writable object - if ( - (typeof newChild === "string" && newChild !== "") || - typeof newChild === "number" - ) { - // Text nodes don't have keys. If the previous node is implicitly keyed - // we can continue to replace it without aborting even if it is not a text - // node. - if (key !== null) { - return null; - } + child._store.validated = true; + var componentName = + getComponentNameFromFiber(returnFiber) || "Component"; - return updateTextNode(returnFiber, oldFiber, "" + newChild, lanes); + if (ownerHasKeyUseWarning[componentName]) { + return; } - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: { - if (newChild.key === key) { - return updateElement(returnFiber, oldFiber, newChild, lanes); - } else { - return null; - } - } + ownerHasKeyUseWarning[componentName] = true; - case REACT_PORTAL_TYPE: { - if (newChild.key === key) { - return updatePortal(returnFiber, oldFiber, newChild, lanes); - } else { - return null; - } - } + error( + "Each child in a list should have a unique " + + '"key" prop. See https://reactjs.org/link/warning-keys for ' + + "more information." + ); + }; + } - case REACT_LAZY_TYPE: { - var payload = newChild._payload; - var init = newChild._init; - return updateSlot(returnFiber, oldFiber, init(payload), lanes); - } - } + function isReactClass(type) { + return type.prototype && type.prototype.isReactComponent; + } + + function unwrapThenable(thenable) { + var index = thenableIndexCounter$1; + thenableIndexCounter$1 += 1; - if (isArray(newChild) || getIteratorFn(newChild)) { - if (key !== null) { - return null; - } + if (thenableState$1 === null) { + thenableState$1 = createThenableState(); + } - return updateFragment(returnFiber, oldFiber, newChild, lanes, null); - } // Usable node types - // - // Unwrap the inner value and recursively call this function again. + return trackUsedThenable(thenableState$1, thenable, index); + } - if (typeof newChild.then === "function") { - var thenable = newChild; - return updateSlot( - returnFiber, - oldFiber, - unwrapThenable(thenable), - lanes - ); - } + function coerceRef(returnFiber, current, element) { + var mixedRef = element.ref; + if ( + mixedRef !== null && + typeof mixedRef !== "function" && + typeof mixedRef !== "object" + ) { + { if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE + // Will already throw with "Function components cannot have string refs" + !(element._owner && element._owner.tag !== ClassComponent) && // Will already warn with "Function components cannot be given refs" + !( + typeof element.type === "function" && !isReactClass(element.type) + ) && // Will already throw with "Element ref was specified as a string (someStringRef) but no owner was set" + element._owner ) { - var context = newChild; - return updateSlot( - returnFiber, - oldFiber, - readContextDuringReconcilation(returnFiber, context, lanes), - lanes - ); - } + var componentName = + getComponentNameFromFiber(returnFiber) || "Component"; - throwOnInvalidObjectType(returnFiber, newChild); - } + if (!didWarnAboutStringRefs[componentName]) { + error( + 'Component "%s" contains the string ref "%s". Support for string refs ' + + "will be removed in a future major release. We recommend using " + + "useRef() or createRef() instead. " + + "Learn more about using refs safely here: " + + "https://reactjs.org/link/strict-mode-string-ref", + componentName, + mixedRef + ); - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber); + didWarnAboutStringRefs[componentName] = true; + } } } - return null; - } - - function updateFromMap( - existingChildren, - returnFiber, - newIdx, - newChild, - lanes - ) { - if ( - (typeof newChild === "string" && newChild !== "") || - typeof newChild === "number" - ) { - // Text nodes don't have keys, so we neither have to check the old nor - // new node for the key. If both are text nodes, they match. - var matchedFiber = existingChildren.get(newIdx) || null; - return updateTextNode( - returnFiber, - matchedFiber, - "" + newChild, - lanes - ); - } - - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: { - var _matchedFiber = - existingChildren.get( - newChild.key === null ? newIdx : newChild.key - ) || null; - - return updateElement(returnFiber, _matchedFiber, newChild, lanes); - } + if (element._owner) { + var owner = element._owner; + var inst; - case REACT_PORTAL_TYPE: { - var _matchedFiber2 = - existingChildren.get( - newChild.key === null ? newIdx : newChild.key - ) || null; + if (owner) { + var ownerFiber = owner; - return updatePortal(returnFiber, _matchedFiber2, newChild, lanes); + if (ownerFiber.tag !== ClassComponent) { + throw new Error( + "Function components cannot have string refs. " + + "We recommend using useRef() instead. " + + "Learn more about using refs safely here: " + + "https://reactjs.org/link/strict-mode-string-ref" + ); } - case REACT_LAZY_TYPE: - var payload = newChild._payload; - var init = newChild._init; - return updateFromMap( - existingChildren, - returnFiber, - newIdx, - init(payload), - lanes - ); + inst = ownerFiber.stateNode; } - if (isArray(newChild) || getIteratorFn(newChild)) { - var _matchedFiber3 = existingChildren.get(newIdx) || null; - - return updateFragment( - returnFiber, - _matchedFiber3, - newChild, - lanes, - null + if (!inst) { + throw new Error( + "Missing owner for string ref " + + mixedRef + + ". This error is likely caused by a " + + "bug in React. Please file an issue." ); - } // Usable node types - // - // Unwrap the inner value and recursively call this function again. + } // Assigning this to a const so Flow knows it won't change in the closure - if (typeof newChild.then === "function") { - var thenable = newChild; - return updateFromMap( - existingChildren, - returnFiber, - newIdx, - unwrapThenable(thenable), - lanes - ); + var resolvedInst = inst; + + { + checkPropStringCoercion(mixedRef, "ref"); } + var stringRef = "" + mixedRef; // Check if previous string ref matches new string ref + if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE + current !== null && + current.ref !== null && + typeof current.ref === "function" && + current.ref._stringRef === stringRef ) { - var context = newChild; - return updateFromMap( - existingChildren, - returnFiber, - newIdx, - readContextDuringReconcilation(returnFiber, context, lanes), - lanes - ); + return current.ref; } - throwOnInvalidObjectType(returnFiber, newChild); - } - - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber); - } - } + var ref = function (value) { + var refs = resolvedInst.refs; - return null; - } - /** - * Warns if there is a duplicate or missing key - */ + if (value === null) { + delete refs[stringRef]; + } else { + refs[stringRef] = value; + } + }; - function warnOnInvalidKey(child, knownKeys, returnFiber) { - { - if (typeof child !== "object" || child === null) { - return knownKeys; + ref._stringRef = stringRef; + return ref; + } else { + if (typeof mixedRef !== "string") { + throw new Error( + "Expected ref to be a function, a string, an object returned by React.createRef(), or null." + ); } - switch (child.$$typeof) { - case REACT_ELEMENT_TYPE: - case REACT_PORTAL_TYPE: - warnForMissingKey(child, returnFiber); - var key = child.key; - - if (typeof key !== "string") { - break; - } - - if (knownKeys === null) { - knownKeys = new Set(); - knownKeys.add(key); - break; - } + if (!element._owner) { + throw new Error( + "Element ref was specified as a string (" + + mixedRef + + ") but no owner was set. This could happen for one of" + + " the following reasons:\n" + + "1. You may be adding a ref to a function component\n" + + "2. You may be adding a ref to a component that was not created inside a component's render method\n" + + "3. You have multiple copies of React loaded\n" + + "See https://reactjs.org/link/refs-must-have-owner for more information." + ); + } + } + } - if (!knownKeys.has(key)) { - knownKeys.add(key); - break; - } + return mixedRef; + } - error( - "Encountered two children with the same key, `%s`. " + - "Keys should be unique so that components maintain their identity " + - "across updates. Non-unique keys may cause children to be " + - "duplicated and/or omitted — the behavior is unsupported and " + - "could change in a future version.", - key - ); + function throwOnInvalidObjectType(returnFiber, newChild) { + // $FlowFixMe[method-unbinding] + var childString = Object.prototype.toString.call(newChild); + throw new Error( + "Objects are not valid as a React child (found: " + + (childString === "[object Object]" + ? "object with keys {" + Object.keys(newChild).join(", ") + "}" + : childString) + + "). " + + "If you meant to render a collection of children, use an array " + + "instead." + ); + } - break; + function warnOnFunctionType(returnFiber) { + { + var componentName = + getComponentNameFromFiber(returnFiber) || "Component"; - case REACT_LAZY_TYPE: - var payload = child._payload; - var init = child._init; - warnOnInvalidKey(init(payload), knownKeys, returnFiber); - break; - } + if (ownerHasFunctionTypeWarning[componentName]) { + return; } - return knownKeys; + ownerHasFunctionTypeWarning[componentName] = true; + + error( + "Functions are not valid as a React child. This may happen if " + + "you return a Component instead of from render. " + + "Or maybe you meant to call this function rather than return it." + ); } + } - function reconcileChildrenArray( - returnFiber, - currentFirstChild, - newChildren, - lanes - ) { - // This algorithm can't optimize by searching from both ends since we - // don't have backpointers on fibers. I'm trying to see how far we can get - // with that model. If it ends up not being worth the tradeoffs, we can - // add it later. - // Even with a two ended optimization, we'd want to optimize for the case - // where there are few changes and brute force the comparison instead of - // going for the Map. It'd like to explore hitting that path first in - // forward-only mode and only go for the Map once we notice that we need - // lots of look ahead. This doesn't handle reversal as well as two ended - // search but that's unusual. Besides, for the two ended optimization to - // work on Iterables, we'd need to copy the whole set. - // In this first iteration, we'll just live with hitting the bad case - // (adding everything to a Map) in for every insert/move. - // If you change this code, also update reconcileChildrenIterator() which - // uses the same algorithm. - { - // First, validate keys. - var knownKeys = null; + function resolveLazy(lazyType) { + var payload = lazyType._payload; + var init = lazyType._init; + return init(payload); + } // This wrapper function exists because I expect to clone the code in each path + // to be able to optimize each path individually by branching early. This needs + // a compiler or we can do it manually. Helpers that don't need this branching + // live outside of this function. - for (var i = 0; i < newChildren.length; i++) { - var child = newChildren[i]; - knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber); - } + function createChildReconciler(shouldTrackSideEffects) { + function deleteChild(returnFiber, childToDelete) { + if (!shouldTrackSideEffects) { + // Noop. + return; } - var resultingFirstChild = null; - var previousNewFiber = null; - var oldFiber = currentFirstChild; - var lastPlacedIndex = 0; - var newIdx = 0; - var nextOldFiber = null; + var deletions = returnFiber.deletions; - for (; oldFiber !== null && newIdx < newChildren.length; newIdx++) { - if (oldFiber.index > newIdx) { - nextOldFiber = oldFiber; - oldFiber = null; - } else { - nextOldFiber = oldFiber.sibling; - } + if (deletions === null) { + returnFiber.deletions = [childToDelete]; + returnFiber.flags |= ChildDeletion; + } else { + deletions.push(childToDelete); + } + } - var newFiber = updateSlot( - returnFiber, - oldFiber, - newChildren[newIdx], - lanes - ); + function deleteRemainingChildren(returnFiber, currentFirstChild) { + if (!shouldTrackSideEffects) { + // Noop. + return null; + } // TODO: For the shouldClone case, this could be micro-optimized a bit by + // assuming that after the first child we've already added everything. - if (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; - } + var childToDelete = currentFirstChild; - break; - } + while (childToDelete !== null) { + deleteChild(returnFiber, childToDelete); + childToDelete = childToDelete.sibling; + } - if (shouldTrackSideEffects) { - if (oldFiber && newFiber.alternate === null) { - // We matched the slot, but we didn't reuse the existing fiber, so we - // need to delete the existing child. - deleteChild(returnFiber, oldFiber); - } - } + return null; + } - lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); + function mapRemainingChildren(returnFiber, currentFirstChild) { + // Add the remaining children to a temporary map so that we can find them by + // keys quickly. Implicit (null) keys get added to this set with their index + // instead. + var existingChildren = new Map(); + var existingChild = currentFirstChild; - if (previousNewFiber === null) { - // TODO: Move out of the loop. This only happens for the first run. - resultingFirstChild = newFiber; + while (existingChild !== null) { + if (existingChild.key !== null) { + existingChildren.set(existingChild.key, existingChild); } 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; + existingChildren.set(existingChild.index, existingChild); } - previousNewFiber = newFiber; - oldFiber = nextOldFiber; + existingChild = existingChild.sibling; } - if (newIdx === newChildren.length) { - // We've reached the end of the new children. We can delete the rest. - deleteRemainingChildren(returnFiber, oldFiber); + return existingChildren; + } - return resultingFirstChild; - } + function useFiber(fiber, pendingProps) { + // We currently set sibling to null and index to 0 here because it is easy + // to forget to do before returning it. E.g. for the single child case. + var clone = createWorkInProgress(fiber, pendingProps); + clone.index = 0; + clone.sibling = null; + return clone; + } - if (oldFiber === null) { - // If we don't have any more existing children we can choose a fast path - // since the rest will all be insertions. - for (; newIdx < newChildren.length; newIdx++) { - var _newFiber = createChild( - returnFiber, - newChildren[newIdx], - lanes - ); + function placeChild(newFiber, lastPlacedIndex, newIndex) { + newFiber.index = newIndex; - if (_newFiber === null) { - continue; - } + if (!shouldTrackSideEffects) { + // During hydration, the useId algorithm needs to know which fibers are + // part of a list of children (arrays, iterators). + newFiber.flags |= Forked; + return lastPlacedIndex; + } - lastPlacedIndex = placeChild(_newFiber, lastPlacedIndex, newIdx); + var current = newFiber.alternate; - if (previousNewFiber === null) { - // TODO: Move out of the loop. This only happens for the first run. - resultingFirstChild = _newFiber; - } else { - previousNewFiber.sibling = _newFiber; - } + if (current !== null) { + var oldIndex = current.index; - previousNewFiber = _newFiber; + if (oldIndex < lastPlacedIndex) { + // This is a move. + newFiber.flags |= Placement | PlacementDEV; + return lastPlacedIndex; + } else { + // This item can stay in place. + return oldIndex; } + } else { + // This is an insertion. + newFiber.flags |= Placement | PlacementDEV; + return lastPlacedIndex; + } + } - return resultingFirstChild; - } // Add all children to a key map for quick lookups. + function placeSingleChild(newFiber) { + // This is simpler for the single child case. We only need to do a + // placement for inserting new children. + if (shouldTrackSideEffects && newFiber.alternate === null) { + newFiber.flags |= Placement | PlacementDEV; + } - var existingChildren = mapRemainingChildren(returnFiber, oldFiber); // Keep scanning and use the map to restore deleted items as moves. + return newFiber; + } - for (; newIdx < newChildren.length; newIdx++) { - var _newFiber2 = updateFromMap( - existingChildren, - returnFiber, - newIdx, - newChildren[newIdx], + function updateTextNode(returnFiber, current, textContent, lanes) { + if (current === null || current.tag !== HostText) { + // Insert + var created = createFiberFromText( + textContent, + returnFiber.mode, lanes ); + created.return = returnFiber; + return created; + } else { + // Update + var existing = useFiber(current, textContent); + existing.return = returnFiber; + return existing; + } + } - if (_newFiber2 !== null) { - if (shouldTrackSideEffects) { - if (_newFiber2.alternate !== null) { - // The new fiber is a work in progress, but if there exists a - // current, that means that we reused the fiber. We need to delete - // it from the child list so that we don't add it to the deletion - // list. - existingChildren.delete( - _newFiber2.key === null ? newIdx : _newFiber2.key - ); - } - } + function updateElement(returnFiber, current, element, lanes) { + var elementType = element.type; + + if (elementType === REACT_FRAGMENT_TYPE) { + return updateFragment( + returnFiber, + current, + element.props.children, + lanes, + element.key + ); + } - lastPlacedIndex = placeChild(_newFiber2, lastPlacedIndex, newIdx); + if (current !== null) { + if ( + current.elementType === elementType || // Keep this check inline so it only runs on the false path: + isCompatibleFamilyForHotReloading(current, element) || // Lazy types should reconcile their resolved type. + // We need to do this after the Hot Reloading check above, + // because hot reloading has different semantics than prod because + // it doesn't resuspend. So we can't let the call below suspend. + (typeof elementType === "object" && + elementType !== null && + elementType.$$typeof === REACT_LAZY_TYPE && + resolveLazy(elementType) === current.type) + ) { + // Move based on index + var existing = useFiber(current, element.props); + existing.ref = coerceRef(returnFiber, current, element); + existing.return = returnFiber; - if (previousNewFiber === null) { - resultingFirstChild = _newFiber2; - } else { - previousNewFiber.sibling = _newFiber2; + { + existing._debugOwner = element._owner; } - previousNewFiber = _newFiber2; + return existing; } - } + } // Insert - if (shouldTrackSideEffects) { - // Any existing children that weren't consumed above were deleted. We need - // to add them to the deletion list. - existingChildren.forEach(function (child) { - return deleteChild(returnFiber, child); - }); - } + var created = createFiberFromElement(element, returnFiber.mode, lanes); + created.ref = coerceRef(returnFiber, current, element); + created.return = returnFiber; + return created; + } - return resultingFirstChild; + function updatePortal(returnFiber, current, portal, lanes) { + if ( + current === null || + current.tag !== HostPortal || + current.stateNode.containerInfo !== portal.containerInfo || + current.stateNode.implementation !== portal.implementation + ) { + // Insert + var created = createFiberFromPortal(portal, returnFiber.mode, lanes); + created.return = returnFiber; + return created; + } else { + // Update + var existing = useFiber(current, portal.children || []); + existing.return = returnFiber; + return existing; + } } - function reconcileChildrenIterator( - returnFiber, - currentFirstChild, - newChildrenIterable, - lanes - ) { - // This is the same implementation as reconcileChildrenArray(), - // but using the iterator instead. - var iteratorFn = getIteratorFn(newChildrenIterable); + function updateFragment(returnFiber, current, fragment, lanes, key) { + if (current === null || current.tag !== Fragment) { + // Insert + var created = createFiberFromFragment( + fragment, + returnFiber.mode, + lanes, + key + ); + created.return = returnFiber; + return created; + } else { + // Update + var existing = useFiber(current, fragment); + existing.return = returnFiber; + return existing; + } + } - if (typeof iteratorFn !== "function") { - throw new Error( - "An object is not an iterable. This error is likely caused by a bug in " + - "React. Please file an issue." + function createChild(returnFiber, newChild, lanes) { + if ( + (typeof newChild === "string" && newChild !== "") || + typeof newChild === "number" + ) { + // Text nodes don't have keys. If the previous node is implicitly keyed + // we can continue to replace it without aborting even if it is not a text + // node. + var created = createFiberFromText( + "" + newChild, + returnFiber.mode, + lanes ); + created.return = returnFiber; + return created; } - { - // We don't support rendering Generators because it's a mutation. - // See https://github.com/facebook/react/issues/12995 - if ( - typeof Symbol === "function" && // $FlowFixMe[prop-missing] Flow doesn't know about toStringTag - newChildrenIterable[Symbol.toStringTag] === "Generator" - ) { - if (!didWarnAboutGenerators) { - error( - "Using Generators as children is unsupported and will likely yield " + - "unexpected results because enumerating a generator mutates it. " + - "You may convert it to an array with `Array.from()` or the " + - "`[...spread]` operator before rendering. Keep in mind " + - "you might need to polyfill these features for older browsers." + if (typeof newChild === "object" && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: { + var _created = createFiberFromElement( + newChild, + returnFiber.mode, + lanes ); - } - - didWarnAboutGenerators = true; - } // Warn about using Maps as children - if (newChildrenIterable.entries === iteratorFn) { - if (!didWarnAboutMaps) { - error( - "Using Maps as children is not supported. " + - "Use an array of keyed ReactElements instead." - ); + _created.ref = coerceRef(returnFiber, null, newChild); + _created.return = returnFiber; + return _created; } - didWarnAboutMaps = true; - } // First, validate keys. - // We'll get a different iterator later for the main pass. - - var _newChildren = iteratorFn.call(newChildrenIterable); - - if (_newChildren) { - var knownKeys = null; + case REACT_PORTAL_TYPE: { + var _created2 = createFiberFromPortal( + newChild, + returnFiber.mode, + lanes + ); - var _step = _newChildren.next(); + _created2.return = returnFiber; + return _created2; + } - for (; !_step.done; _step = _newChildren.next()) { - var child = _step.value; - knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber); + case REACT_LAZY_TYPE: { + var payload = newChild._payload; + var init = newChild._init; + return createChild(returnFiber, init(payload), lanes); } } - } - var newChildren = iteratorFn.call(newChildrenIterable); - - if (newChildren == null) { - throw new Error("An iterable object provided no iterator."); - } + if (isArray(newChild) || getIteratorFn(newChild)) { + var _created3 = createFiberFromFragment( + newChild, + returnFiber.mode, + lanes, + null + ); - var resultingFirstChild = null; - var previousNewFiber = null; - var oldFiber = currentFirstChild; - var lastPlacedIndex = 0; - var newIdx = 0; - var nextOldFiber = null; - var step = newChildren.next(); + _created3.return = returnFiber; + return _created3; + } // Usable node types + // + // Unwrap the inner value and recursively call this function again. - for ( - ; - oldFiber !== null && !step.done; - newIdx++, step = newChildren.next() - ) { - if (oldFiber.index > newIdx) { - nextOldFiber = oldFiber; - oldFiber = null; - } else { - nextOldFiber = oldFiber.sibling; + if (typeof newChild.then === "function") { + var thenable = newChild; + return createChild(returnFiber, unwrapThenable(thenable), lanes); } - var newFiber = updateSlot(returnFiber, oldFiber, step.value, lanes); + if (newChild.$$typeof === REACT_CONTEXT_TYPE) { + var context = newChild; + return createChild( + returnFiber, + readContextDuringReconcilation(returnFiber, context, lanes), + lanes + ); + } - 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; - } + throwOnInvalidObjectType(returnFiber, newChild); + } - break; + { + if (typeof newChild === "function") { + warnOnFunctionType(returnFiber); } + } - if (shouldTrackSideEffects) { - if (oldFiber && newFiber.alternate === null) { - // We matched the slot, but we didn't reuse the existing fiber, so we - // need to delete the existing child. - deleteChild(returnFiber, oldFiber); - } - } + return null; + } - lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); + function updateSlot(returnFiber, oldFiber, newChild, lanes) { + // Update the fiber if the keys match, otherwise return null. + var key = oldFiber !== null ? oldFiber.key : null; - if (previousNewFiber === null) { - // TODO: Move out of the loop. This only happens for the first run. - resultingFirstChild = newFiber; - } else { - // TODO: Defer siblings if we're not at the right index for this slot. - // I.e. if we had null values before, then we want to defer this - // for each null value. However, we also don't want to call updateSlot - // with the previous one. - previousNewFiber.sibling = newFiber; + if ( + (typeof newChild === "string" && newChild !== "") || + typeof newChild === "number" + ) { + // Text nodes don't have keys. If the previous node is implicitly keyed + // we can continue to replace it without aborting even if it is not a text + // node. + if (key !== null) { + return null; } - previousNewFiber = newFiber; - oldFiber = nextOldFiber; + return updateTextNode(returnFiber, oldFiber, "" + newChild, lanes); } - if (step.done) { - // We've reached the end of the new children. We can delete the rest. - deleteRemainingChildren(returnFiber, oldFiber); + if (typeof newChild === "object" && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: { + if (newChild.key === key) { + return updateElement(returnFiber, oldFiber, newChild, lanes); + } else { + return null; + } + } - return resultingFirstChild; - } + case REACT_PORTAL_TYPE: { + if (newChild.key === key) { + return updatePortal(returnFiber, oldFiber, newChild, lanes); + } else { + return null; + } + } - if (oldFiber === null) { - // If we don't have any more existing children we can choose a fast path - // since the rest will all be insertions. - for (; !step.done; newIdx++, step = newChildren.next()) { - var _newFiber3 = createChild(returnFiber, step.value, lanes); + case REACT_LAZY_TYPE: { + var payload = newChild._payload; + var init = newChild._init; + return updateSlot(returnFiber, oldFiber, init(payload), lanes); + } + } - if (_newFiber3 === null) { - continue; + if (isArray(newChild) || getIteratorFn(newChild)) { + if (key !== null) { + return null; } - lastPlacedIndex = placeChild(_newFiber3, lastPlacedIndex, newIdx); + return updateFragment(returnFiber, oldFiber, newChild, lanes, null); + } // Usable node types + // + // Unwrap the inner value and recursively call this function again. - if (previousNewFiber === null) { - // TODO: Move out of the loop. This only happens for the first run. - resultingFirstChild = _newFiber3; - } else { - previousNewFiber.sibling = _newFiber3; - } + if (typeof newChild.then === "function") { + var thenable = newChild; + return updateSlot( + returnFiber, + oldFiber, + unwrapThenable(thenable), + lanes + ); + } - previousNewFiber = _newFiber3; + if (newChild.$$typeof === REACT_CONTEXT_TYPE) { + var context = newChild; + return updateSlot( + returnFiber, + oldFiber, + readContextDuringReconcilation(returnFiber, context, lanes), + lanes + ); } - return resultingFirstChild; - } // Add all children to a key map for quick lookups. + throwOnInvalidObjectType(returnFiber, newChild); + } - var existingChildren = mapRemainingChildren(returnFiber, oldFiber); // Keep scanning and use the map to restore deleted items as moves. + { + if (typeof newChild === "function") { + warnOnFunctionType(returnFiber); + } + } - for (; !step.done; newIdx++, step = newChildren.next()) { - var _newFiber4 = updateFromMap( - existingChildren, + return null; + } + + function updateFromMap( + existingChildren, + returnFiber, + newIdx, + newChild, + lanes + ) { + if ( + (typeof newChild === "string" && newChild !== "") || + typeof newChild === "number" + ) { + // Text nodes don't have keys, so we neither have to check the old nor + // new node for the key. If both are text nodes, they match. + var matchedFiber = existingChildren.get(newIdx) || null; + return updateTextNode( returnFiber, - newIdx, - step.value, + matchedFiber, + "" + newChild, lanes ); + } - if (_newFiber4 !== null) { - if (shouldTrackSideEffects) { - if (_newFiber4.alternate !== null) { - // The new fiber is a work in progress, but if there exists a - // current, that means that we reused the fiber. We need to delete - // it from the child list so that we don't add it to the deletion - // list. - existingChildren.delete( - _newFiber4.key === null ? newIdx : _newFiber4.key - ); - } + if (typeof newChild === "object" && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: { + var _matchedFiber = + existingChildren.get( + newChild.key === null ? newIdx : newChild.key + ) || null; + + return updateElement(returnFiber, _matchedFiber, newChild, lanes); } - lastPlacedIndex = placeChild(_newFiber4, lastPlacedIndex, newIdx); + case REACT_PORTAL_TYPE: { + var _matchedFiber2 = + existingChildren.get( + newChild.key === null ? newIdx : newChild.key + ) || null; - if (previousNewFiber === null) { - resultingFirstChild = _newFiber4; - } else { - previousNewFiber.sibling = _newFiber4; + return updatePortal(returnFiber, _matchedFiber2, newChild, lanes); } - previousNewFiber = _newFiber4; + case REACT_LAZY_TYPE: + var payload = newChild._payload; + var init = newChild._init; + return updateFromMap( + existingChildren, + returnFiber, + newIdx, + init(payload), + lanes + ); } - } - - 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, - lanes - ) { - // There's no need to check for keys on text nodes since we don't have a - // way to define them. - if (currentFirstChild !== null && currentFirstChild.tag === HostText) { - // We already have an existing node so let's just update it and delete - // the rest. - deleteRemainingChildren(returnFiber, currentFirstChild.sibling); - var existing = useFiber(currentFirstChild, textContent); - existing.return = returnFiber; - return existing; - } // The existing first child is not a text node so we need to create one - // and delete the existing ones. - deleteRemainingChildren(returnFiber, currentFirstChild); - var created = createFiberFromText(textContent, returnFiber.mode, lanes); - created.return = returnFiber; - return created; - } + if (isArray(newChild) || getIteratorFn(newChild)) { + var _matchedFiber3 = existingChildren.get(newIdx) || null; - function reconcileSingleElement( - returnFiber, - currentFirstChild, - element, - lanes - ) { - var key = element.key; - var child = currentFirstChild; + return updateFragment( + returnFiber, + _matchedFiber3, + newChild, + lanes, + null + ); + } // Usable node types + // + // Unwrap the inner value and recursively call this function again. - while (child !== null) { - // TODO: If key === null and child.key === null, then this only applies to - // the first item in the list. - if (child.key === key) { - var elementType = element.type; + if (typeof newChild.then === "function") { + var thenable = newChild; + return updateFromMap( + existingChildren, + returnFiber, + newIdx, + unwrapThenable(thenable), + lanes + ); + } - if (elementType === REACT_FRAGMENT_TYPE) { - if (child.tag === Fragment) { - deleteRemainingChildren(returnFiber, child.sibling); - var existing = useFiber(child, element.props.children); - existing.return = returnFiber; + if (newChild.$$typeof === REACT_CONTEXT_TYPE) { + var context = newChild; + return updateFromMap( + existingChildren, + returnFiber, + newIdx, + readContextDuringReconcilation(returnFiber, context, lanes), + lanes + ); + } - { - existing._debugSource = element._source; - existing._debugOwner = element._owner; - } + throwOnInvalidObjectType(returnFiber, newChild); + } - return existing; - } - } else { - if ( - child.elementType === elementType || // Keep this check inline so it only runs on the false path: - isCompatibleFamilyForHotReloading(child, element) || // Lazy types should reconcile their resolved type. - // We need to do this after the Hot Reloading check above, - // because hot reloading has different semantics than prod because - // it doesn't resuspend. So we can't let the call below suspend. - (typeof elementType === "object" && - elementType !== null && - elementType.$$typeof === REACT_LAZY_TYPE && - resolveLazy(elementType) === child.type) - ) { - deleteRemainingChildren(returnFiber, child.sibling); + { + if (typeof newChild === "function") { + warnOnFunctionType(returnFiber); + } + } - var _existing = useFiber(child, element.props); + return null; + } + /** + * Warns if there is a duplicate or missing key + */ - _existing.ref = coerceRef(returnFiber, child, element); - _existing.return = returnFiber; + function warnOnInvalidKey(child, knownKeys, returnFiber) { + { + if (typeof child !== "object" || child === null) { + return knownKeys; + } - { - _existing._debugSource = element._source; - _existing._debugOwner = element._owner; - } + switch (child.$$typeof) { + case REACT_ELEMENT_TYPE: + case REACT_PORTAL_TYPE: + warnForMissingKey(child, returnFiber); + var key = child.key; - return _existing; + if (typeof key !== "string") { + break; } - } // Didn't match. - - deleteRemainingChildren(returnFiber, child); - break; - } else { - deleteChild(returnFiber, child); - } - child = child.sibling; - } + if (knownKeys === null) { + knownKeys = new Set(); + knownKeys.add(key); + break; + } - if (element.type === REACT_FRAGMENT_TYPE) { - var created = createFiberFromFragment( - element.props.children, - returnFiber.mode, - lanes, - element.key - ); - created.return = returnFiber; - return created; - } else { - var _created4 = createFiberFromElement( - element, - returnFiber.mode, - lanes - ); + if (!knownKeys.has(key)) { + knownKeys.add(key); + break; + } - _created4.ref = coerceRef(returnFiber, currentFirstChild, element); - _created4.return = returnFiber; - return _created4; - } - } + error( + "Encountered two children with the same key, `%s`. " + + "Keys should be unique so that components maintain their identity " + + "across updates. Non-unique keys may cause children to be " + + "duplicated and/or omitted — the behavior is unsupported and " + + "could change in a future version.", + key + ); - function reconcileSinglePortal( - returnFiber, - currentFirstChild, - portal, - lanes - ) { - var key = portal.key; - var child = currentFirstChild; + break; - while (child !== null) { - // TODO: If key === null and child.key === null, then this only applies to - // the first item in the list. - if (child.key === key) { - if ( - child.tag === HostPortal && - child.stateNode.containerInfo === portal.containerInfo && - child.stateNode.implementation === portal.implementation - ) { - deleteRemainingChildren(returnFiber, child.sibling); - var existing = useFiber(child, portal.children || []); - existing.return = returnFiber; - return existing; - } else { - deleteRemainingChildren(returnFiber, child); + case REACT_LAZY_TYPE: + var payload = child._payload; + var init = child._init; + warnOnInvalidKey(init(payload), knownKeys, returnFiber); break; - } - } else { - deleteChild(returnFiber, child); } - - child = child.sibling; } - var created = createFiberFromPortal(portal, returnFiber.mode, lanes); - created.return = returnFiber; - return created; - } // This API will tag the children with the side-effect of the reconciliation - // itself. They will be added to the side-effect list as we pass through the - // children and the parent. + return knownKeys; + } - function reconcileChildFibersImpl( + function reconcileChildrenArray( returnFiber, currentFirstChild, - newChild, + newChildren, lanes ) { - // This function is not recursive. - // If the top level item is an array, we treat it as a set of children, - // not as a fragment. Nested arrays on the other hand will be treated as - // fragment nodes. Recursion happens at the normal flow. - // Handle top level unkeyed fragments as if they were arrays. - // This leads to an ambiguity between <>{[...]} and <>.... - // We treat the ambiguous cases above the same. - // TODO: Let's use recursion like we do for Usable nodes? - var isUnkeyedTopLevelFragment = - typeof newChild === "object" && - newChild !== null && - newChild.type === REACT_FRAGMENT_TYPE && - newChild.key === null; + // This algorithm can't optimize by searching from both ends since we + // don't have backpointers on fibers. I'm trying to see how far we can get + // with that model. If it ends up not being worth the tradeoffs, we can + // add it later. + // Even with a two ended optimization, we'd want to optimize for the case + // where there are few changes and brute force the comparison instead of + // going for the Map. It'd like to explore hitting that path first in + // forward-only mode and only go for the Map once we notice that we need + // lots of look ahead. This doesn't handle reversal as well as two ended + // search but that's unusual. Besides, for the two ended optimization to + // work on Iterables, we'd need to copy the whole set. + // In this first iteration, we'll just live with hitting the bad case + // (adding everything to a Map) in for every insert/move. + // If you change this code, also update reconcileChildrenIterator() which + // uses the same algorithm. + { + // First, validate keys. + var knownKeys = null; - if (isUnkeyedTopLevelFragment) { - newChild = newChild.props.children; - } // Handle object types + for (var i = 0; i < newChildren.length; i++) { + var child = newChildren[i]; + knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber); + } + } - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: - return placeSingleChild( - reconcileSingleElement( - returnFiber, - currentFirstChild, - newChild, - lanes - ) - ); + var resultingFirstChild = null; + var previousNewFiber = null; + var oldFiber = currentFirstChild; + var lastPlacedIndex = 0; + var newIdx = 0; + var nextOldFiber = null; - case REACT_PORTAL_TYPE: - return placeSingleChild( - reconcileSinglePortal( - returnFiber, - currentFirstChild, - newChild, - lanes - ) - ); + for (; oldFiber !== null && newIdx < newChildren.length; newIdx++) { + if (oldFiber.index > newIdx) { + nextOldFiber = oldFiber; + oldFiber = null; + } else { + nextOldFiber = oldFiber.sibling; + } - case REACT_LAZY_TYPE: - var payload = newChild._payload; - var init = newChild._init; // TODO: This function is supposed to be non-recursive. + var newFiber = updateSlot( + returnFiber, + oldFiber, + newChildren[newIdx], + lanes + ); - return reconcileChildFibers( - returnFiber, - currentFirstChild, - init(payload), - lanes - ); - } + if (newFiber === null) { + // TODO: This breaks on empty slots like null children. That's + // unfortunate because it triggers the slow path all the time. We need + // a better way to communicate whether this was a miss or null, + // boolean, undefined, etc. + if (oldFiber === null) { + oldFiber = nextOldFiber; + } - if (isArray(newChild)) { - return reconcileChildrenArray( - returnFiber, - currentFirstChild, - newChild, - lanes - ); + break; } - if (getIteratorFn(newChild)) { - return reconcileChildrenIterator( - returnFiber, - currentFirstChild, - newChild, - lanes - ); - } // Usables are a valid React node type. When React encounters a Usable in - // a child position, it unwraps it using the same algorithm as `use`. For - // example, for promises, React will throw an exception to unwind the - // stack, then replay the component once the promise resolves. - // - // A difference from `use` is that React will keep unwrapping the value - // until it reaches a non-Usable type. - // - // e.g. Usable>> should resolve to T - // - // The structure is a bit unfortunate. Ideally, we shouldn't need to - // replay the entire begin phase of the parent fiber in order to reconcile - // the children again. This would require a somewhat significant refactor, - // because reconcilation happens deep within the begin phase, and - // depending on the type of work, not always at the end. We should - // consider as an future improvement. - - if (typeof newChild.then === "function") { - var thenable = newChild; - return reconcileChildFibersImpl( - returnFiber, - currentFirstChild, - unwrapThenable(thenable), - lanes - ); + if (shouldTrackSideEffects) { + if (oldFiber && newFiber.alternate === null) { + // We matched the slot, but we didn't reuse the existing fiber, so we + // need to delete the existing child. + deleteChild(returnFiber, oldFiber); + } } - if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) { - var context = newChild; - return reconcileChildFibersImpl( - returnFiber, - currentFirstChild, - readContextDuringReconcilation(returnFiber, context, lanes), - lanes - ); + 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; } - throwOnInvalidObjectType(returnFiber, newChild); + previousNewFiber = newFiber; + oldFiber = nextOldFiber; } - if ( - (typeof newChild === "string" && newChild !== "") || - typeof newChild === "number" - ) { - return placeSingleChild( - reconcileSingleTextNode( - returnFiber, - currentFirstChild, - "" + newChild, - lanes - ) - ); - } + if (newIdx === newChildren.length) { + // We've reached the end of the new children. We can delete the rest. + deleteRemainingChildren(returnFiber, oldFiber); - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber); - } - } // Remaining cases are all treated as empty. + return resultingFirstChild; + } - return deleteRemainingChildren(returnFiber, currentFirstChild); - } + if (oldFiber === null) { + // If we don't have any more existing children we can choose a fast path + // since the rest will all be insertions. + for (; newIdx < newChildren.length; newIdx++) { + var _newFiber = createChild( + returnFiber, + newChildren[newIdx], + lanes + ); - function reconcileChildFibers( - returnFiber, - currentFirstChild, - newChild, - lanes - ) { - // This indirection only exists so we can reset `thenableState` at the end. - // It should get inlined by Closure. - thenableIndexCounter$1 = 0; - var firstChildFiber = reconcileChildFibersImpl( - returnFiber, - currentFirstChild, - newChild, - lanes - ); - thenableState$1 = null; // Don't bother to reset `thenableIndexCounter` to 0 because it always gets - // set at the beginning. + if (_newFiber === null) { + continue; + } - return firstChildFiber; - } + lastPlacedIndex = placeChild(_newFiber, lastPlacedIndex, newIdx); - return reconcileChildFibers; - } + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = _newFiber; + } else { + previousNewFiber.sibling = _newFiber; + } - var reconcileChildFibers = createChildReconciler(true); - var mountChildFibers = createChildReconciler(false); - function resetChildReconcilerOnUnwind() { - // On unwind, clear any pending thenables that were used. - thenableState$1 = null; - thenableIndexCounter$1 = 0; - } - function cloneChildFibers(current, workInProgress) { - if (current !== null && workInProgress.child !== current.child) { - throw new Error("Resuming work not yet implemented."); - } + previousNewFiber = _newFiber; + } - if (workInProgress.child === null) { - return; - } + return resultingFirstChild; + } // Add all children to a key map for quick lookups. - var currentChild = workInProgress.child; - var newChild = createWorkInProgress( - currentChild, - currentChild.pendingProps - ); - workInProgress.child = newChild; - newChild.return = workInProgress; + var existingChildren = mapRemainingChildren(returnFiber, oldFiber); // Keep scanning and use the map to restore deleted items as moves. - while (currentChild.sibling !== null) { - currentChild = currentChild.sibling; - newChild = newChild.sibling = createWorkInProgress( - currentChild, - currentChild.pendingProps - ); - newChild.return = workInProgress; - } + for (; newIdx < newChildren.length; newIdx++) { + var _newFiber2 = updateFromMap( + existingChildren, + returnFiber, + newIdx, + newChildren[newIdx], + lanes + ); - newChild.sibling = null; - } // Reset a workInProgress child set to prepare it for a second pass. + if (_newFiber2 !== null) { + if (shouldTrackSideEffects) { + if (_newFiber2.alternate !== null) { + // The new fiber is a work in progress, but if there exists a + // current, that means that we reused the fiber. We need to delete + // it from the child list so that we don't add it to the deletion + // list. + existingChildren.delete( + _newFiber2.key === null ? newIdx : _newFiber2.key + ); + } + } - function resetChildFibers(workInProgress, lanes) { - var child = workInProgress.child; + lastPlacedIndex = placeChild(_newFiber2, lastPlacedIndex, newIdx); - while (child !== null) { - resetWorkInProgress(child, lanes); - child = child.sibling; - } - } + if (previousNewFiber === null) { + resultingFirstChild = _newFiber2; + } else { + previousNewFiber.sibling = _newFiber2; + } - // TODO: This isn't being used yet, but it's intended to replace the - // InvisibleParentContext that is currently managed by SuspenseContext. + previousNewFiber = _newFiber2; + } + } - var currentTreeHiddenStackCursor = createCursor(null); - var prevEntangledRenderLanesCursor = createCursor(NoLanes); - function pushHiddenContext(fiber, context) { - var prevEntangledRenderLanes = getEntangledRenderLanes(); - push(prevEntangledRenderLanesCursor, prevEntangledRenderLanes, fiber); - push(currentTreeHiddenStackCursor, context, fiber); // When rendering a subtree that's currently hidden, we must include all - // lanes that would have rendered if the hidden subtree hadn't been deferred. - // That is, in order to reveal content from hidden -> visible, we must commit - // all the updates that we skipped when we originally hid the tree. + 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); + }); + } - setEntangledRenderLanes( - mergeLanes(prevEntangledRenderLanes, context.baseLanes) - ); - } - function reuseHiddenContextOnStack(fiber) { - // This subtree is not currently hidden, so we don't need to add any lanes - // to the render lanes. But we still need to push something to avoid a - // context mismatch. Reuse the existing context on the stack. - push(prevEntangledRenderLanesCursor, getEntangledRenderLanes(), fiber); - push( - currentTreeHiddenStackCursor, - currentTreeHiddenStackCursor.current, - fiber - ); - } - function popHiddenContext(fiber) { - // Restore the previous render lanes from the stack - setEntangledRenderLanes(prevEntangledRenderLanesCursor.current); - pop(currentTreeHiddenStackCursor, fiber); - pop(prevEntangledRenderLanesCursor, fiber); - } - function isCurrentTreeHidden() { - return currentTreeHiddenStackCursor.current !== null; - } + return resultingFirstChild; + } - // suspends, i.e. it's the nearest `catch` block on the stack. + function reconcileChildrenIterator( + returnFiber, + currentFirstChild, + newChildrenIterable, + lanes + ) { + // This is the same implementation as reconcileChildrenArray(), + // but using the iterator instead. + var iteratorFn = getIteratorFn(newChildrenIterable); - var suspenseHandlerStackCursor = createCursor(null); // Represents the outermost boundary that is not visible in the current tree. - // Everything above this is the "shell". When this is null, it means we're - // rendering in the shell of the app. If it's non-null, it means we're rendering - // deeper than the shell, inside a new tree that wasn't already visible. - // - // The main way we use this concept is to determine whether showing a fallback - // would result in a desirable or undesirable loading state. Activing a fallback - // in the shell is considered an undersirable loading state, because it would - // mean hiding visible (albeit stale) content in the current tree — we prefer to - // show the stale content, rather than switch to a fallback. But showing a - // fallback in a new tree is fine, because there's no stale content to - // prefer instead. + if (typeof iteratorFn !== "function") { + throw new Error( + "An object is not an iterable. This error is likely caused by a bug in " + + "React. Please file an issue." + ); + } - var shellBoundary = null; - function getShellBoundary() { - return shellBoundary; - } - function pushPrimaryTreeSuspenseHandler(handler) { - // TODO: Pass as argument - var current = handler.alternate; - // propagated a single level. For example, when ForceSuspenseFallback is set, - // it should only force the nearest Suspense boundary into fallback mode. + { + // We don't support rendering Generators because it's a mutation. + // See https://github.com/facebook/react/issues/12995 + if ( + typeof Symbol === "function" && // $FlowFixMe[prop-missing] Flow doesn't know about toStringTag + newChildrenIterable[Symbol.toStringTag] === "Generator" + ) { + if (!didWarnAboutGenerators) { + error( + "Using Generators as children is unsupported and will likely yield " + + "unexpected results because enumerating a generator mutates it. " + + "You may convert it to an array with `Array.from()` or the " + + "`[...spread]` operator before rendering. Keep in mind " + + "you might need to polyfill these features for older browsers." + ); + } - pushSuspenseListContext( - handler, - setDefaultShallowSuspenseListContext(suspenseStackCursor.current) - ); // Experimental feature: Some Suspense boundaries are marked as having an - // to push a nested Suspense handler, because it will get replaced by the - // outer fallback, anyway. Consider this as a future optimization. + didWarnAboutGenerators = true; + } // Warn about using Maps as children - push(suspenseHandlerStackCursor, handler, handler); + if (newChildrenIterable.entries === iteratorFn) { + if (!didWarnAboutMaps) { + error( + "Using Maps as children is not supported. " + + "Use an array of keyed ReactElements instead." + ); + } - if (shellBoundary === null) { - if (current === null || isCurrentTreeHidden()) { - // This boundary is not visible in the current UI. - shellBoundary = handler; - } else { - var prevState = current.memoizedState; + didWarnAboutMaps = true; + } // First, validate keys. + // We'll get a different iterator later for the main pass. - if (prevState !== null) { - // This boundary is showing a fallback in the current UI. - shellBoundary = handler; - } - } - } - } - function pushFallbackTreeSuspenseHandler(fiber) { - // We're about to render the fallback. If something in the fallback suspends, - // it's akin to throwing inside of a `catch` block. This boundary should not - // capture. Reuse the existing handler on the stack. - reuseSuspenseHandlerOnStack(fiber); - } - function pushOffscreenSuspenseHandler(fiber) { - if (fiber.tag === OffscreenComponent) { - // A SuspenseList context is only pushed here to avoid a push/pop mismatch. - // Reuse the current value on the stack. - // TODO: We can avoid needing to push here by by forking popSuspenseHandler - // into separate functions for Suspense and Offscreen. - pushSuspenseListContext(fiber, suspenseStackCursor.current); - push(suspenseHandlerStackCursor, fiber, fiber); + var _newChildren = iteratorFn.call(newChildrenIterable); - if (shellBoundary !== null); - else { - var current = fiber.alternate; + if (_newChildren) { + var knownKeys = null; - if (current !== null) { - var prevState = current.memoizedState; + var _step = _newChildren.next(); - if (prevState !== null) { - // This is the first boundary in the stack that's already showing - // a fallback. So everything outside is considered the shell. - shellBoundary = fiber; + for (; !_step.done; _step = _newChildren.next()) { + var child = _step.value; + knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber); } } } - } else { - // This is a LegacyHidden component. - reuseSuspenseHandlerOnStack(fiber); - } - } - function reuseSuspenseHandlerOnStack(fiber) { - pushSuspenseListContext(fiber, suspenseStackCursor.current); - push(suspenseHandlerStackCursor, getSuspenseHandler(), fiber); - } - function getSuspenseHandler() { - return suspenseHandlerStackCursor.current; - } - function popSuspenseHandler(fiber) { - pop(suspenseHandlerStackCursor, fiber); - if (shellBoundary === fiber) { - // Popping back into the shell. - shellBoundary = null; - } - - popSuspenseListContext(fiber); - } // SuspenseList context - // TODO: Move to a separate module? We may change the SuspenseList - // implementation to hide/show in the commit phase, anyway. + var newChildren = iteratorFn.call(newChildrenIterable); - var DefaultSuspenseContext = 0; - var SubtreeSuspenseContextMask = 1; // ForceSuspenseFallback can be used by SuspenseList to force newly added - // items into their fallback state during one of the render passes. + if (newChildren == null) { + throw new Error("An iterable object provided no iterator."); + } - var ForceSuspenseFallback = 2; - var suspenseStackCursor = createCursor(DefaultSuspenseContext); - function hasSuspenseListContext(parentContext, flag) { - return (parentContext & flag) !== 0; - } - function setDefaultShallowSuspenseListContext(parentContext) { - return parentContext & SubtreeSuspenseContextMask; - } - function setShallowSuspenseListContext(parentContext, shallowContext) { - return (parentContext & SubtreeSuspenseContextMask) | shallowContext; - } - function pushSuspenseListContext(fiber, newContext) { - push(suspenseStackCursor, newContext, fiber); - } - function popSuspenseListContext(fiber) { - pop(suspenseStackCursor, fiber); - } + var resultingFirstChild = null; + var previousNewFiber = null; + var oldFiber = currentFirstChild; + var lastPlacedIndex = 0; + var newIdx = 0; + var nextOldFiber = null; + var step = newChildren.next(); - // A non-null SuspenseState means that it is blocked for one reason or another. - // - A non-null dehydrated field means it's blocked pending hydration. - // - A non-null dehydrated field can use isSuspenseInstancePending or - // isSuspenseInstanceFallback to query the reason for being dehydrated. - // - A null dehydrated field means it's blocked by something suspending and - // we're currently showing a fallback instead. + for ( + ; + oldFiber !== null && !step.done; + newIdx++, step = newChildren.next() + ) { + if (oldFiber.index > newIdx) { + nextOldFiber = oldFiber; + oldFiber = null; + } else { + nextOldFiber = oldFiber.sibling; + } - function findFirstSuspended(row) { - var node = row; + var newFiber = updateSlot(returnFiber, oldFiber, step.value, lanes); - while (node !== null) { - if (node.tag === SuspenseComponent) { - var state = node.memoizedState; + if (newFiber === null) { + // TODO: This breaks on empty slots like null children. That's + // unfortunate because it triggers the slow path all the time. We need + // a better way to communicate whether this was a miss or null, + // boolean, undefined, etc. + if (oldFiber === null) { + oldFiber = nextOldFiber; + } - if (state !== null) { - var dehydrated = state.dehydrated; + break; + } - if ( - dehydrated === null || - isSuspenseInstancePending() || - isSuspenseInstanceFallback() - ) { - return node; + 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); } } - } else if ( - node.tag === SuspenseListComponent && // revealOrder undefined can't be trusted because it don't - // keep track of whether it suspended or not. - node.memoizedProps.revealOrder !== undefined - ) { - var didSuspend = (node.flags & DidCapture) !== NoFlags$1; - if (didSuspend) { - return node; + 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; } - } else if (node.child !== null) { - node.child.return = node; - node = node.child; - continue; - } - if (node === row) { - return null; + previousNewFiber = newFiber; + oldFiber = nextOldFiber; } - while (node.sibling === null) { - if (node.return === null || node.return === row) { - return null; - } + if (step.done) { + // We've reached the end of the new children. We can delete the rest. + deleteRemainingChildren(returnFiber, oldFiber); - node = node.return; + return resultingFirstChild; } - node.sibling.return = node.return; - node = node.sibling; - } + if (oldFiber === null) { + // If we don't have any more existing children we can choose a fast path + // since the rest will all be insertions. + for (; !step.done; newIdx++, step = newChildren.next()) { + var _newFiber3 = createChild(returnFiber, step.value, lanes); - return null; - } + if (_newFiber3 === null) { + continue; + } - var NoFlags = - /* */ - 0; // Represents whether effect should fire. + lastPlacedIndex = placeChild(_newFiber3, lastPlacedIndex, newIdx); - var HasEffect = - /* */ - 1; // Represents the phase in which the effect (not the clean-up) fires. + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = _newFiber3; + } else { + previousNewFiber.sibling = _newFiber3; + } - var Insertion = - /* */ - 2; - var Layout = - /* */ - 4; - var Passive = - /* */ - 8; + previousNewFiber = _newFiber3; + } - var ReactCurrentActQueue$2 = ReactSharedInternals.ReactCurrentActQueue; // A linked list of all the roots with pending work. In an idiomatic app, - // there's only a single root, but we do support multi root apps, hence this - // extra complexity. But this module is optimized for the single root case. + return resultingFirstChild; + } // Add all children to a key map for quick lookups. - var firstScheduledRoot = null; - var lastScheduledRoot = null; // Used to prevent redundant mircotasks from being scheduled. + var existingChildren = mapRemainingChildren(returnFiber, oldFiber); // Keep scanning and use the map to restore deleted items as moves. - var didScheduleMicrotask = false; // `act` "microtasks" are scheduled on the `act` queue instead of an actual - // microtask, so we have to dedupe those separately. This wouldn't be an issue - // if we required all `act` calls to be awaited, which we might in the future. + for (; !step.done; newIdx++, step = newChildren.next()) { + var _newFiber4 = updateFromMap( + existingChildren, + returnFiber, + newIdx, + step.value, + lanes + ); - var didScheduleMicrotask_act = false; // Used to quickly bail out of flushSync if there's no sync work to do. + 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 + ); + } + } - var mightHavePendingSyncWork = false; - var isFlushingWork = false; - var currentEventTransitionLane = NoLane; - function ensureRootIsScheduled(root) { - // This function is called whenever a root receives an update. It does two - // things 1) it ensures the root is in the root schedule, and 2) it ensures - // there's a pending microtask to process the root schedule. - // - // Most of the actual scheduling logic does not happen until - // `scheduleTaskForRootDuringMicrotask` runs. - // Add the root to the schedule - if (root === lastScheduledRoot || root.next !== null); - else { - if (lastScheduledRoot === null) { - firstScheduledRoot = lastScheduledRoot = root; - } else { - lastScheduledRoot.next = root; - lastScheduledRoot = root; - } - } // Any time a root received an update, we set this to true until the next time - // we process the schedule. If it's false, then we can quickly exit flushSync - // without consulting the schedule. + lastPlacedIndex = placeChild(_newFiber4, lastPlacedIndex, newIdx); - mightHavePendingSyncWork = true; // At the end of the current event, go through each of the roots and ensure - // there's a task scheduled for each one at the correct priority. + if (previousNewFiber === null) { + resultingFirstChild = _newFiber4; + } else { + previousNewFiber.sibling = _newFiber4; + } - if (ReactCurrentActQueue$2.current !== null) { - // We're inside an `act` scope. - if (!didScheduleMicrotask_act) { - didScheduleMicrotask_act = true; - scheduleImmediateTask(processRootScheduleInMicrotask); + previousNewFiber = _newFiber4; + } } - } else { - if (!didScheduleMicrotask) { - didScheduleMicrotask = true; - scheduleImmediateTask(processRootScheduleInMicrotask); + + if (shouldTrackSideEffects) { + // Any existing children that weren't consumed above were deleted. We need + // to add them to the deletion list. + existingChildren.forEach(function (child) { + return deleteChild(returnFiber, child); + }); } - } - if (ReactCurrentActQueue$2.isBatchingLegacy && root.tag === LegacyRoot) { - // Special `act` case: Record whenever a legacy update is scheduled. - ReactCurrentActQueue$2.didScheduleLegacyUpdate = true; + return resultingFirstChild; } - } - function flushSyncWorkOnAllRoots() { - // This is allowed to be called synchronously, but the caller should check - // the execution context first. - flushSyncWorkAcrossRoots_impl(false); - } - function flushSyncWorkOnLegacyRootsOnly() { - // This is allowed to be called synchronously, but the caller should check - // the execution context first. - flushSyncWorkAcrossRoots_impl(true); - } - function flushSyncWorkAcrossRoots_impl(onlyLegacy) { - if (isFlushingWork) { - // Prevent reentrancy. - // TODO: Is this overly defensive? The callers must check the execution - // context first regardless. - return; + function reconcileSingleTextNode( + returnFiber, + currentFirstChild, + textContent, + lanes + ) { + // There's no need to check for keys on text nodes since we don't have a + // way to define them. + if (currentFirstChild !== null && currentFirstChild.tag === HostText) { + // We already have an existing node so let's just update it and delete + // the rest. + deleteRemainingChildren(returnFiber, currentFirstChild.sibling); + var existing = useFiber(currentFirstChild, textContent); + existing.return = returnFiber; + return existing; + } // The existing first child is not a text node so we need to create one + // and delete the existing ones. + + deleteRemainingChildren(returnFiber, currentFirstChild); + var created = createFiberFromText(textContent, returnFiber.mode, lanes); + created.return = returnFiber; + return created; } - if (!mightHavePendingSyncWork) { - // Fast path. There's no sync work to do. - return; - } // There may or may not be synchronous work scheduled. Let's check. + function reconcileSingleElement( + returnFiber, + currentFirstChild, + element, + lanes + ) { + var key = element.key; + var child = currentFirstChild; - var didPerformSomeWork; - var errors = null; - isFlushingWork = true; + while (child !== null) { + // TODO: If key === null and child.key === null, then this only applies to + // the first item in the list. + if (child.key === key) { + var elementType = element.type; - do { - didPerformSomeWork = false; - var root = firstScheduledRoot; + if (elementType === REACT_FRAGMENT_TYPE) { + if (child.tag === Fragment) { + deleteRemainingChildren(returnFiber, child.sibling); + var existing = useFiber(child, element.props.children); + existing.return = returnFiber; - while (root !== null) { - if (onlyLegacy && root.tag !== LegacyRoot); - else { - var workInProgressRoot = getWorkInProgressRoot(); - var workInProgressRootRenderLanes = - getWorkInProgressRootRenderLanes(); - var nextLanes = getNextLanes( - root, - root === workInProgressRoot - ? workInProgressRootRenderLanes - : NoLanes - ); + { + existing._debugOwner = element._owner; + } - if (includesSyncLane(nextLanes)) { - // This root has pending sync work. Flush it now. - try { - didPerformSomeWork = true; - performSyncWorkOnRoot(root, nextLanes); - } catch (error) { - // Collect errors so we can rethrow them at the end - if (errors === null) { - errors = [error]; - } else { - errors.push(error); + return existing; + } + } else { + if ( + child.elementType === elementType || // Keep this check inline so it only runs on the false path: + isCompatibleFamilyForHotReloading(child, element) || // Lazy types should reconcile their resolved type. + // We need to do this after the Hot Reloading check above, + // because hot reloading has different semantics than prod because + // it doesn't resuspend. So we can't let the call below suspend. + (typeof elementType === "object" && + elementType !== null && + elementType.$$typeof === REACT_LAZY_TYPE && + resolveLazy(elementType) === child.type) + ) { + deleteRemainingChildren(returnFiber, child.sibling); + + var _existing = useFiber(child, element.props); + + _existing.ref = coerceRef(returnFiber, child, element); + _existing.return = returnFiber; + + { + _existing._debugOwner = element._owner; } + + return _existing; } - } + } // Didn't match. + + deleteRemainingChildren(returnFiber, child); + break; + } else { + deleteChild(returnFiber, child); } - root = root.next; + child = child.sibling; } - } while (didPerformSomeWork); - isFlushingWork = false; // If any errors were thrown, rethrow them right before exiting. - // TODO: Consider returning these to the caller, to allow them to decide - // how/when to rethrow. + if (element.type === REACT_FRAGMENT_TYPE) { + var created = createFiberFromFragment( + element.props.children, + returnFiber.mode, + lanes, + element.key + ); + created.return = returnFiber; + return created; + } else { + var _created4 = createFiberFromElement( + element, + returnFiber.mode, + lanes + ); - if (errors !== null) { - if (errors.length > 1) { - if (typeof AggregateError === "function") { - // eslint-disable-next-line no-undef - throw new AggregateError(errors); - } else { - for (var i = 1; i < errors.length; i++) { - scheduleImmediateTask(throwError.bind(null, errors[i])); - } + _created4.ref = coerceRef(returnFiber, currentFirstChild, element); + _created4.return = returnFiber; + return _created4; + } + } - var firstError = errors[0]; - throw firstError; + function reconcileSinglePortal( + returnFiber, + currentFirstChild, + portal, + lanes + ) { + var key = portal.key; + var child = currentFirstChild; + + while (child !== null) { + // TODO: If key === null and child.key === null, then this only applies to + // the first item in the list. + if (child.key === key) { + if ( + child.tag === HostPortal && + child.stateNode.containerInfo === portal.containerInfo && + child.stateNode.implementation === portal.implementation + ) { + deleteRemainingChildren(returnFiber, child.sibling); + var existing = useFiber(child, portal.children || []); + existing.return = returnFiber; + return existing; + } else { + deleteRemainingChildren(returnFiber, child); + break; + } + } else { + deleteChild(returnFiber, child); } - } else { - var error = errors[0]; - throw error; - } - } - } - - function throwError(error) { - throw error; - } - function processRootScheduleInMicrotask() { - // This function is always called inside a microtask. It should never be - // called synchronously. - didScheduleMicrotask = false; + child = child.sibling; + } - { - didScheduleMicrotask_act = false; - } // We'll recompute this as we iterate through all the roots and schedule them. + var created = createFiberFromPortal(portal, returnFiber.mode, lanes); + created.return = returnFiber; + return created; + } // This API will tag the children with the side-effect of the reconciliation + // itself. They will be added to the side-effect list as we pass through the + // children and the parent. - mightHavePendingSyncWork = false; - var currentTime = now$1(); - var prev = null; - var root = firstScheduledRoot; + function reconcileChildFibersImpl( + returnFiber, + currentFirstChild, + newChild, + lanes + ) { + // This function is not recursive. + // If the top level item is an array, we treat it as a set of children, + // not as a fragment. Nested arrays on the other hand will be treated as + // fragment nodes. Recursion happens at the normal flow. + // Handle top level unkeyed fragments as if they were arrays. + // This leads to an ambiguity between <>{[...]} and <>.... + // We treat the ambiguous cases above the same. + // TODO: Let's use recursion like we do for Usable nodes? + var isUnkeyedTopLevelFragment = + typeof newChild === "object" && + newChild !== null && + newChild.type === REACT_FRAGMENT_TYPE && + newChild.key === null; - while (root !== null) { - var next = root.next; + if (isUnkeyedTopLevelFragment) { + newChild = newChild.props.children; + } // Handle object types - if ( - currentEventTransitionLane !== NoLane && - shouldAttemptEagerTransition() - ) { - // A transition was scheduled during an event, but we're going to try to - // render it synchronously anyway. We do this during a popstate event to - // preserve the scroll position of the previous page. - upgradePendingLaneToSync(root, currentEventTransitionLane); - } + if (typeof newChild === "object" && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return placeSingleChild( + reconcileSingleElement( + returnFiber, + currentFirstChild, + newChild, + lanes + ) + ); - var nextLanes = scheduleTaskForRootDuringMicrotask(root, currentTime); + case REACT_PORTAL_TYPE: + return placeSingleChild( + reconcileSinglePortal( + returnFiber, + currentFirstChild, + newChild, + lanes + ) + ); - if (nextLanes === NoLane) { - // This root has no more pending work. Remove it from the schedule. To - // guard against subtle reentrancy bugs, this microtask is the only place - // we do this — you can add roots to the schedule whenever, but you can - // only remove them here. - // Null this out so we know it's been removed from the schedule. - root.next = null; + case REACT_LAZY_TYPE: + var payload = newChild._payload; + var init = newChild._init; // TODO: This function is supposed to be non-recursive. - if (prev === null) { - // This is the new head of the list - firstScheduledRoot = next; - } else { - prev.next = next; + return reconcileChildFibers( + returnFiber, + currentFirstChild, + init(payload), + lanes + ); } - if (next === null) { - // This is the new tail of the list - lastScheduledRoot = prev; + if (isArray(newChild)) { + return reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChild, + lanes + ); } - } else { - // This root still has work. Keep it in the list. - prev = root; - if (includesSyncLane(nextLanes)) { - mightHavePendingSyncWork = true; + if (getIteratorFn(newChild)) { + return reconcileChildrenIterator( + returnFiber, + currentFirstChild, + newChild, + lanes + ); + } // Usables are a valid React node type. When React encounters a Usable in + // a child position, it unwraps it using the same algorithm as `use`. For + // example, for promises, React will throw an exception to unwind the + // stack, then replay the component once the promise resolves. + // + // A difference from `use` is that React will keep unwrapping the value + // until it reaches a non-Usable type. + // + // e.g. Usable>> should resolve to T + // + // The structure is a bit unfortunate. Ideally, we shouldn't need to + // replay the entire begin phase of the parent fiber in order to reconcile + // the children again. This would require a somewhat significant refactor, + // because reconcilation happens deep within the begin phase, and + // depending on the type of work, not always at the end. We should + // consider as an future improvement. + + if (typeof newChild.then === "function") { + var thenable = newChild; + return reconcileChildFibersImpl( + returnFiber, + currentFirstChild, + unwrapThenable(thenable), + lanes + ); } - } - root = next; - } + if (newChild.$$typeof === REACT_CONTEXT_TYPE) { + var context = newChild; + return reconcileChildFibersImpl( + returnFiber, + currentFirstChild, + readContextDuringReconcilation(returnFiber, context, lanes), + lanes + ); + } - currentEventTransitionLane = NoLane; // At the end of the microtask, flush any pending synchronous work. This has - // to come at the end, because it does actual rendering work that might throw. + throwOnInvalidObjectType(returnFiber, newChild); + } - flushSyncWorkOnAllRoots(); - } + if ( + (typeof newChild === "string" && newChild !== "") || + typeof newChild === "number" + ) { + return placeSingleChild( + reconcileSingleTextNode( + returnFiber, + currentFirstChild, + "" + newChild, + lanes + ) + ); + } - function scheduleTaskForRootDuringMicrotask(root, currentTime) { - // This function is always called inside a microtask, or at the very end of a - // rendering task right before we yield to the main thread. It should never be - // called synchronously. - // - // TODO: Unless enableDeferRootSchedulingToMicrotask is off. We need to land - // that ASAP to unblock additional features we have planned. - // - // This function also never performs React work synchronously; it should - // only schedule work to be performed later, in a separate task or microtask. - // Check if any lanes are being starved by other work. If so, mark them as - // expired so we know to work on those next. - markStarvedLanesAsExpired(root, currentTime); // Determine the next lanes to work on, and their priority. + { + if (typeof newChild === "function") { + warnOnFunctionType(returnFiber); + } + } // Remaining cases are all treated as empty. - var workInProgressRoot = getWorkInProgressRoot(); - var workInProgressRootRenderLanes = getWorkInProgressRootRenderLanes(); - var nextLanes = getNextLanes( - root, - root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes - ); - var existingCallbackNode = root.callbackNode; + return deleteRemainingChildren(returnFiber, currentFirstChild); + } - if ( - // Check if there's nothing to work on - nextLanes === NoLanes || // If this root is currently suspended and waiting for data to resolve, don't - // schedule a task to render it. We'll either wait for a ping, or wait to - // receive an update. - // - // Suspended render phase - (root === workInProgressRoot && isWorkLoopSuspendedOnData()) || // Suspended commit phase - root.cancelPendingCommit !== null + function reconcileChildFibers( + returnFiber, + currentFirstChild, + newChild, + lanes ) { - // Fast path: There's nothing to work on. - if (existingCallbackNode !== null) { - cancelCallback(existingCallbackNode); - } - - root.callbackNode = null; - root.callbackPriority = NoLane; - return NoLane; - } // Schedule a new callback in the host environment. - - if (includesSyncLane(nextLanes)) { - // Synchronous work is always flushed at the end of the microtask, so we - // don't need to schedule an additional task. - if (existingCallbackNode !== null) { - cancelCallback(existingCallbackNode); - } + // This indirection only exists so we can reset `thenableState` at the end. + // It should get inlined by Closure. + thenableIndexCounter$1 = 0; + var firstChildFiber = reconcileChildFibersImpl( + returnFiber, + currentFirstChild, + newChild, + lanes + ); + thenableState$1 = null; // Don't bother to reset `thenableIndexCounter` to 0 because it always gets + // set at the beginning. - root.callbackPriority = SyncLane; - root.callbackNode = null; - return SyncLane; - } else { - // We use the highest priority lane to represent the priority of the callback. - var existingCallbackPriority = root.callbackPriority; - var newCallbackPriority = getHighestPriorityLane(nextLanes); + return firstChildFiber; + } - if ( - newCallbackPriority === existingCallbackPriority && // Special case related to `act`. If the currently scheduled task is a - // Scheduler task, rather than an `act` task, cancel it and re-schedule - // on the `act` queue. - !( - ReactCurrentActQueue$2.current !== null && - existingCallbackNode !== fakeActCallbackNode$1 - ) - ) { - // The priority hasn't changed. We can reuse the existing task. - return newCallbackPriority; - } else { - // Cancel the existing callback. We'll schedule a new one below. - cancelCallback(existingCallbackNode); - } + return reconcileChildFibers; + } - var schedulerPriorityLevel; + var reconcileChildFibers = createChildReconciler(true); + var mountChildFibers = createChildReconciler(false); + function resetChildReconcilerOnUnwind() { + // On unwind, clear any pending thenables that were used. + thenableState$1 = null; + thenableIndexCounter$1 = 0; + } + function cloneChildFibers(current, workInProgress) { + if (current !== null && workInProgress.child !== current.child) { + throw new Error("Resuming work not yet implemented."); + } - switch (lanesToEventPriority(nextLanes)) { - case DiscreteEventPriority: - schedulerPriorityLevel = ImmediatePriority; - break; + if (workInProgress.child === null) { + return; + } - case ContinuousEventPriority: - schedulerPriorityLevel = UserBlockingPriority; - break; + var currentChild = workInProgress.child; + var newChild = createWorkInProgress( + currentChild, + currentChild.pendingProps + ); + workInProgress.child = newChild; + newChild.return = workInProgress; - case DefaultEventPriority: - schedulerPriorityLevel = NormalPriority; - break; + while (currentChild.sibling !== null) { + currentChild = currentChild.sibling; + newChild = newChild.sibling = createWorkInProgress( + currentChild, + currentChild.pendingProps + ); + newChild.return = workInProgress; + } - case IdleEventPriority: - schedulerPriorityLevel = IdlePriority; - break; + newChild.sibling = null; + } // Reset a workInProgress child set to prepare it for a second pass. - default: - schedulerPriorityLevel = NormalPriority; - break; - } + function resetChildFibers(workInProgress, lanes) { + var child = workInProgress.child; - var newCallbackNode = scheduleCallback$1( - schedulerPriorityLevel, - performConcurrentWorkOnRoot.bind(null, root) - ); - root.callbackPriority = newCallbackPriority; - root.callbackNode = newCallbackNode; - return newCallbackPriority; + while (child !== null) { + resetWorkInProgress(child, lanes); + child = child.sibling; } } - function getContinuationForRoot(root, originalCallbackNode) { - // This is called at the end of `performConcurrentWorkOnRoot` to determine - // if we need to schedule a continuation task. - // - // Usually `scheduleTaskForRootDuringMicrotask` only runs inside a microtask; - // however, since most of the logic for determining if we need a continuation - // versus a new task is the same, we cheat a bit and call it here. This is - // only safe to do because we know we're at the end of the browser task. - // So although it's not an actual microtask, it might as well be. - scheduleTaskForRootDuringMicrotask(root, now$1()); + // TODO: This isn't being used yet, but it's intended to replace the + // InvisibleParentContext that is currently managed by SuspenseContext. - if (root.callbackNode === originalCallbackNode) { - // The task node scheduled for this root is the same one that's - // currently executed. Need to return a continuation. - return performConcurrentWorkOnRoot.bind(null, root); - } + var currentTreeHiddenStackCursor = createCursor(null); + var prevEntangledRenderLanesCursor = createCursor(NoLanes); + function pushHiddenContext(fiber, context) { + var prevEntangledRenderLanes = getEntangledRenderLanes(); + push(prevEntangledRenderLanesCursor, prevEntangledRenderLanes, fiber); + push(currentTreeHiddenStackCursor, context, fiber); // When rendering a subtree that's currently hidden, we must include all + // lanes that would have rendered if the hidden subtree hadn't been deferred. + // That is, in order to reveal content from hidden -> visible, we must commit + // all the updates that we skipped when we originally hid the tree. - return null; + setEntangledRenderLanes( + mergeLanes(prevEntangledRenderLanes, context.baseLanes) + ); + } + function reuseHiddenContextOnStack(fiber) { + // This subtree is not currently hidden, so we don't need to add any lanes + // to the render lanes. But we still need to push something to avoid a + // context mismatch. Reuse the existing context on the stack. + push(prevEntangledRenderLanesCursor, getEntangledRenderLanes(), fiber); + push( + currentTreeHiddenStackCursor, + currentTreeHiddenStackCursor.current, + fiber + ); + } + function popHiddenContext(fiber) { + // Restore the previous render lanes from the stack + setEntangledRenderLanes(prevEntangledRenderLanesCursor.current); + pop(currentTreeHiddenStackCursor, fiber); + pop(prevEntangledRenderLanesCursor, fiber); + } + function isCurrentTreeHidden() { + return currentTreeHiddenStackCursor.current !== null; } - var fakeActCallbackNode$1 = {}; - function scheduleCallback$1(priorityLevel, callback) { - if (ReactCurrentActQueue$2.current !== null) { - // Special case: We're inside an `act` scope (a testing utility). - // Instead of scheduling work in the host environment, add it to a - // fake internal queue that's managed by the `act` implementation. - ReactCurrentActQueue$2.current.push(callback); - return fakeActCallbackNode$1; - } else { - return scheduleCallback$2(priorityLevel, callback); - } + // suspends, i.e. it's the nearest `catch` block on the stack. + + var suspenseHandlerStackCursor = createCursor(null); // Represents the outermost boundary that is not visible in the current tree. + // Everything above this is the "shell". When this is null, it means we're + // rendering in the shell of the app. If it's non-null, it means we're rendering + // deeper than the shell, inside a new tree that wasn't already visible. + // + // The main way we use this concept is to determine whether showing a fallback + // would result in a desirable or undesirable loading state. Activing a fallback + // in the shell is considered an undersirable loading state, because it would + // mean hiding visible (albeit stale) content in the current tree — we prefer to + // show the stale content, rather than switch to a fallback. But showing a + // fallback in a new tree is fine, because there's no stale content to + // prefer instead. + + var shellBoundary = null; + function getShellBoundary() { + return shellBoundary; } + function pushPrimaryTreeSuspenseHandler(handler) { + // TODO: Pass as argument + var current = handler.alternate; + // propagated a single level. For example, when ForceSuspenseFallback is set, + // it should only force the nearest Suspense boundary into fallback mode. - function cancelCallback(callbackNode) { - if (callbackNode === fakeActCallbackNode$1); - else if (callbackNode !== null) { - cancelCallback$1(callbackNode); + pushSuspenseListContext( + handler, + setDefaultShallowSuspenseListContext(suspenseStackCursor.current) + ); // Experimental feature: Some Suspense boundaries are marked as having an + // to push a nested Suspense handler, because it will get replaced by the + // outer fallback, anyway. Consider this as a future optimization. + + push(suspenseHandlerStackCursor, handler, handler); + + if (shellBoundary === null) { + if (current === null || isCurrentTreeHidden()) { + // This boundary is not visible in the current UI. + shellBoundary = handler; + } else { + var prevState = current.memoizedState; + + if (prevState !== null) { + // This boundary is showing a fallback in the current UI. + shellBoundary = handler; + } + } } } + function pushFallbackTreeSuspenseHandler(fiber) { + // We're about to render the fallback. If something in the fallback suspends, + // it's akin to throwing inside of a `catch` block. This boundary should not + // capture. Reuse the existing handler on the stack. + reuseSuspenseHandlerOnStack(fiber); + } + function pushOffscreenSuspenseHandler(fiber) { + if (fiber.tag === OffscreenComponent) { + // A SuspenseList context is only pushed here to avoid a push/pop mismatch. + // Reuse the current value on the stack. + // TODO: We can avoid needing to push here by by forking popSuspenseHandler + // into separate functions for Suspense and Offscreen. + pushSuspenseListContext(fiber, suspenseStackCursor.current); + push(suspenseHandlerStackCursor, fiber, fiber); - function scheduleImmediateTask(cb) { - if (ReactCurrentActQueue$2.current !== null) { - // Special case: Inside an `act` scope, we push microtasks to the fake `act` - // callback queue. This is because we currently support calling `act` - // without awaiting the result. The plan is to deprecate that, and require - // that you always await the result so that the microtasks have a chance to - // run. But it hasn't happened yet. - ReactCurrentActQueue$2.current.push(function () { - cb(); - return null; - }); - } // TODO: Can we land supportsMicrotasks? Which environments don't support it? - // Alternatively, can we move this check to the host config? + if (shellBoundary !== null); + else { + var current = fiber.alternate; - { - // If microtasks are not supported, use Scheduler. - scheduleCallback$2(ImmediatePriority, cb); + if (current !== null) { + var prevState = current.memoizedState; + + if (prevState !== null) { + // This is the first boundary in the stack that's already showing + // a fallback. So everything outside is considered the shell. + shellBoundary = fiber; + } + } + } + } else { + // This is a LegacyHidden component. + reuseSuspenseHandlerOnStack(fiber); } } + function reuseSuspenseHandlerOnStack(fiber) { + pushSuspenseListContext(fiber, suspenseStackCursor.current); + push(suspenseHandlerStackCursor, getSuspenseHandler(), fiber); + } + function getSuspenseHandler() { + return suspenseHandlerStackCursor.current; + } + function popSuspenseHandler(fiber) { + pop(suspenseHandlerStackCursor, fiber); - function requestTransitionLane() { - // The algorithm for assigning an update to a lane should be stable for all - // updates at the same priority within the same event. To do this, the - // inputs to the algorithm must be the same. - // - // The trick we use is to cache the first of each of these inputs within an - // event. Then reset the cached values once we can be sure the event is - // over. Our heuristic for that is whenever we enter a concurrent work loop. - if (currentEventTransitionLane === NoLane) { - // All transitions within the same event are assigned the same lane. - currentEventTransitionLane = claimNextTransitionLane(); + if (shellBoundary === fiber) { + // Popping back into the shell. + shellBoundary = null; } - return currentEventTransitionLane; - } + popSuspenseListContext(fiber); + } // SuspenseList context + // TODO: Move to a separate module? We may change the SuspenseList + // implementation to hide/show in the commit phase, anyway. + + var DefaultSuspenseContext = 0; + var SubtreeSuspenseContextMask = 1; // ForceSuspenseFallback can be used by SuspenseList to force newly added + // items into their fallback state during one of the render passes. - // transition updates that occur while the async action is still in progress - // are treated as part of the action. - // - // The ideal behavior would be to treat each async function as an independent - // action. However, without a mechanism like AsyncContext, we can't tell which - // action an update corresponds to. So instead, we entangle them all into one. - // The listeners to notify once the entangled scope completes. + var ForceSuspenseFallback = 2; + var suspenseStackCursor = createCursor(DefaultSuspenseContext); + function hasSuspenseListContext(parentContext, flag) { + return (parentContext & flag) !== 0; + } + function setDefaultShallowSuspenseListContext(parentContext) { + return parentContext & SubtreeSuspenseContextMask; + } + function setShallowSuspenseListContext(parentContext, shallowContext) { + return (parentContext & SubtreeSuspenseContextMask) | shallowContext; + } + function pushSuspenseListContext(fiber, newContext) { + push(suspenseStackCursor, newContext, fiber); + } + function popSuspenseListContext(fiber) { + pop(suspenseStackCursor, fiber); + } - var currentEntangledListeners = null; // The number of pending async actions in the entangled scope. + // A non-null SuspenseState means that it is blocked for one reason or another. + // - A non-null dehydrated field means it's blocked pending hydration. + // - A non-null dehydrated field can use isSuspenseInstancePending or + // isSuspenseInstanceFallback to query the reason for being dehydrated. + // - A null dehydrated field means it's blocked by something suspending and + // we're currently showing a fallback instead. - var currentEntangledPendingCount = 0; // The transition lane shared by all updates in the entangled scope. + function findFirstSuspended(row) { + var node = row; - var currentEntangledLane = NoLane; - function requestAsyncActionContext( - actionReturnValue, // If this is provided, this resulting thenable resolves to this value instead - // of the return value of the action. This is a perf trick to avoid composing - // an extra async function. - overrideReturnValue - ) { - // This is an async action. - // - // Return a thenable that resolves once the action scope (i.e. the async - // function passed to startTransition) has finished running. - var thenable = actionReturnValue; - var entangledListeners; - - if (currentEntangledListeners === null) { - // There's no outer async action scope. Create a new one. - entangledListeners = currentEntangledListeners = []; - currentEntangledPendingCount = 0; - currentEntangledLane = requestTransitionLane(); - } else { - entangledListeners = currentEntangledListeners; - } + while (node !== null) { + if (node.tag === SuspenseComponent) { + var state = node.memoizedState; - currentEntangledPendingCount++; // Create a thenable that represents the result of this action, but doesn't - // resolve until the entire entangled scope has finished. - // - // Expressed using promises: - // const [thisResult] = await Promise.all([thisAction, entangledAction]); - // return thisResult; - - var resultThenable = createResultThenable(entangledListeners); - var resultStatus = "pending"; - var resultValue; - var rejectedReason; - thenable.then( - function (value) { - resultStatus = "fulfilled"; - resultValue = - overrideReturnValue !== null ? overrideReturnValue : value; - pingEngtangledActionScope(); - }, - function (error) { - resultStatus = "rejected"; - rejectedReason = error; - pingEngtangledActionScope(); - } - ); // Attach a listener to fill in the result. - - entangledListeners.push(function () { - switch (resultStatus) { - case "fulfilled": { - var fulfilledThenable = resultThenable; - fulfilledThenable.status = "fulfilled"; - fulfilledThenable.value = resultValue; - break; - } + if (state !== null) { + var dehydrated = state.dehydrated; - case "rejected": { - var rejectedThenable = resultThenable; - rejectedThenable.status = "rejected"; - rejectedThenable.reason = rejectedReason; - break; + if ( + dehydrated === null || + isSuspenseInstancePending() || + isSuspenseInstanceFallback() + ) { + return node; + } } + } else if ( + node.tag === SuspenseListComponent && // revealOrder undefined can't be trusted because it don't + // keep track of whether it suspended or not. + node.memoizedProps.revealOrder !== undefined + ) { + var didSuspend = (node.flags & DidCapture) !== NoFlags$1; - case "pending": - default: { - // The listener above should have been called first, so `resultStatus` - // should already be set to the correct value. - throw new Error( - "Thenable should have already resolved. This " + - "is a bug in React." - ); + if (didSuspend) { + return node; } + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; } - }); - return resultThenable; - } - function requestSyncActionContext( - actionReturnValue, // If this is provided, this resulting thenable resolves to this value instead - // of the return value of the action. This is a perf trick to avoid composing - // an extra async function. - overrideReturnValue - ) { - var resultValue = - overrideReturnValue !== null ? overrideReturnValue : actionReturnValue; // This is not an async action, but it may be part of an outer async action. - if (currentEntangledListeners === null) { - return resultValue; - } else { - // Return a thenable that does not resolve until the entangled actions - // have finished. - var entangledListeners = currentEntangledListeners; - var resultThenable = createResultThenable(entangledListeners); - entangledListeners.push(function () { - var fulfilledThenable = resultThenable; - fulfilledThenable.status = "fulfilled"; - fulfilledThenable.value = resultValue; - }); - return resultThenable; - } - } + if (node === row) { + return null; + } - function pingEngtangledActionScope() { - if ( - currentEntangledListeners !== null && - --currentEntangledPendingCount === 0 - ) { - // All the actions have finished. Close the entangled async action scope - // and notify all the listeners. - var listeners = currentEntangledListeners; - currentEntangledListeners = null; - currentEntangledLane = NoLane; + while (node.sibling === null) { + if (node.return === null || node.return === row) { + return null; + } - for (var i = 0; i < listeners.length; i++) { - var listener = listeners[i]; - listener(); + node = node.return; } + + node.sibling.return = node.return; + node = node.sibling; } - } - function createResultThenable(entangledListeners) { - // Waits for the entangled async action to complete, then resolves to the - // result of an individual action. - var resultThenable = { - status: "pending", - value: null, - reason: null, - then: function (resolve) { - // This is a bit of a cheat. `resolve` expects a value of type `S` to be - // passed, but because we're instrumenting the `status` field ourselves, - // and we know this thenable will only be used by React, we also know - // the value isn't actually needed. So we add the resolve function - // directly to the entangled listeners. - // - // This is also why we don't need to check if the thenable is still - // pending; the Suspense implementation already performs that check. - var ping = resolve; - entangledListeners.push(ping); - } - }; - return resultThenable; + return null; } - function peekEntangledActionLane() { - return currentEntangledLane; - } + var NoFlags = + /* */ + 0; // Represents whether effect should fire. + + var HasEffect = + /* */ + 1; // Represents the phase in which the effect (not the clean-up) fires. + + var Insertion = + /* */ + 2; + var Layout = + /* */ + 4; + var Passive = + /* */ + 8; var ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher, ReactCurrentBatchConfig$2 = ReactSharedInternals.ReactCurrentBatchConfig; @@ -10202,7 +10257,7 @@ to return true:wantsResponderID| | } } - function warnIfAsyncClientComponent(Component, componentDoesIncludeHooks) { + function warnIfAsyncClientComponent(Component) { { // This dev-only check only works for detecting native async functions, // not transpiled ones. There's also a prod check that we use to prevent @@ -10214,43 +10269,20 @@ to return true:wantsResponderID| | "[object AsyncFunction]"; if (isAsyncFunction) { - // Encountered an async Client Component. This is not yet supported, - // except in certain constrained cases, like during a route navigation. + // Encountered an async Client Component. This is not yet supported. var componentName = getComponentNameFromFiber( currentlyRenderingFiber$1 ); if (!didWarnAboutAsyncClientComponent.has(componentName)) { - didWarnAboutAsyncClientComponent.add(componentName); // Check if this is a sync update. We use the "root" render lanes here - // because the "subtree" render lanes may include additional entangled - // lanes related to revealing previously hidden content. + didWarnAboutAsyncClientComponent.add(componentName); - var root = getWorkInProgressRoot(); - var rootRenderLanes = getWorkInProgressRootRenderLanes(); - - if (root !== null && includesBlockingLane(root, rootRenderLanes)) { - error( - "async/await is not yet supported in Client Components, only " + - "Server Components. This error is often caused by accidentally " + - "adding `'use client'` to a module that was originally written " + - "for the server." - ); - } else { - // This is a concurrent (Transition, Retry, etc) render. We don't - // warn in these cases. - // - // However, Async Components are forbidden to include hooks, even - // during a transition, so let's check for that here. - // - // TODO: Add a corresponding warning to Server Components runtime. - if (componentDoesIncludeHooks) { - error( - "Hooks are not supported inside an async component. This " + - "error is often caused by accidentally adding `'use client'` " + - "to a module that was originally written for the server." - ); - } - } + error( + "async/await is not yet supported in Client Components, only " + + "Server Components. This error is often caused by accidentally " + + "adding `'use client'` to a module that was originally written " + + "for the server." + ); } } } @@ -10333,6 +10365,7 @@ to return true:wantsResponderID| | ignorePreviousDependencies = current !== null && current.type !== workInProgress.type; + warnIfAsyncClientComponent(Component); } workInProgress.memoizedState = null; @@ -10392,7 +10425,8 @@ to return true:wantsResponderID| | // // There are plenty of tests to ensure this behavior is correct. - var shouldDoubleRenderDEV = debugRenderPhaseSideEffectsForStrictMode; + var shouldDoubleRenderDEV = + (workInProgress.mode & StrictLegacyMode) !== NoMode; shouldDoubleInvokeUserFnsInHooksDEV = shouldDoubleRenderDEV; var children = Component(props, secondArg); shouldDoubleInvokeUserFnsInHooksDEV = false; // Check if there was a render phase update @@ -10408,16 +10442,29 @@ to return true:wantsResponderID| | ); } - finishRenderingHooks(current, workInProgress, Component); + if (shouldDoubleRenderDEV) { + // In development, components are invoked twice to help detect side effects. + setIsStrictModeForDevtools(true); + + try { + children = renderWithHooksAgain( + workInProgress, + Component, + props, + secondArg + ); + } finally { + setIsStrictModeForDevtools(false); + } + } + + finishRenderingHooks(current, workInProgress); return children; } function finishRenderingHooks(current, workInProgress, Component) { { workInProgress._debugHookTypes = hookTypesDev; - var componentDoesIncludeHooks = - workInProgressHook !== null || thenableIndexCounter !== 0; - warnIfAsyncClientComponent(Component, componentDoesIncludeHooks); } // We can assume the previous dispatcher is always this one, since we set it // at the beginning of the render phase and there's no re-entrance. @@ -10519,7 +10566,7 @@ to return true:wantsResponderID| | props, secondArg ); - finishRenderingHooks(current, workInProgress, Component); + finishRenderingHooks(current, workInProgress); return children; } @@ -10791,10 +10838,7 @@ to return true:wantsResponderID| | // This is a thenable. var thenable = usable; return useThenable(thenable); - } else if ( - usable.$$typeof === REACT_CONTEXT_TYPE || - usable.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) { + } else if (usable.$$typeof === REACT_CONTEXT_TYPE) { var context = usable; return readContext(context); } @@ -10816,6 +10860,12 @@ to return true:wantsResponderID| | if (init !== undefined) { initialState = init(initialArg); + + if (shouldDoubleInvokeUserFnsInHooksDEV) { + setIsStrictModeForDevtools(true); + init(initialArg); + setIsStrictModeForDevtools(false); + } } else { initialState = initialArg; } @@ -10900,6 +10950,7 @@ to return true:wantsResponderID| | var newBaseQueueFirst = null; var newBaseQueueLast = null; var update = first; + var didReadFromEntangledAsyncAction = false; do { // An extra OffscreenLane bit is added to updates that were made to @@ -10959,6 +11010,12 @@ to return true:wantsResponderID| | next: null }; newBaseQueueLast = newBaseQueueLast.next = _clone; + } // Check if this update is part of a pending async action. If so, + // we'll need to suspend until the action has finished, so that it's + // batched together with future updates in the same action. + + if (updateLane === peekEntangledActionLane()) { + didReadFromEntangledAsyncAction = true; } } // Process this update. @@ -10988,7 +11045,23 @@ to return true:wantsResponderID| | // different from the current state. if (!objectIs(newState, hook.memoizedState)) { - markWorkInProgressReceivedUpdate(); + markWorkInProgressReceivedUpdate(); // Check if this update is part of a pending async action. If so, we'll + // need to suspend until the action has finished, so that it's batched + // together with future updates in the same action. + // TODO: Once we support hooks inside useMemo (or an equivalent + // memoization boundary like Forget), hoist this logic so that it only + // suspends if the memo boundary produces a new value. + + if (didReadFromEntangledAsyncAction) { + var entangledActionThenable = peekEntangledActionThenable(); + + if (entangledActionThenable !== null) { + // TODO: Instead of the throwing the thenable directly, throw a + // special object like `use` does so we can detect if it's captured + // by userspace. + throw entangledActionThenable; + } + } } hook.memoizedState = newState; @@ -11288,8 +11361,16 @@ to return true:wantsResponderID| | var hook = mountWorkInProgressHook(); if (typeof initialState === "function") { - // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types - initialState = initialState(); + var initialStateInitializer = initialState; // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types + + initialState = initialStateInitializer(); + + if (shouldDoubleInvokeUserFnsInHooksDEV) { + setIsStrictModeForDevtools(true); // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types + + initialStateInitializer(); + setIsStrictModeForDevtools(false); + } } hook.memoizedState = hook.baseState = initialState; @@ -11573,12 +11654,14 @@ to return true:wantsResponderID| | function mountMemo(nextCreate, deps) { var hook = mountWorkInProgressHook(); var nextDeps = deps === undefined ? null : deps; + var nextValue = nextCreate(); if (shouldDoubleInvokeUserFnsInHooksDEV) { + setIsStrictModeForDevtools(true); nextCreate(); + setIsStrictModeForDevtools(false); } - var nextValue = nextCreate(); hook.memoizedState = [nextValue, nextDeps]; return nextValue; } @@ -11596,11 +11679,14 @@ to return true:wantsResponderID| | } } + var nextValue = nextCreate(); + if (shouldDoubleInvokeUserFnsInHooksDEV) { + setIsStrictModeForDevtools(true); nextCreate(); + setIsStrictModeForDevtools(false); } - var nextValue = nextCreate(); hook.memoizedState = [nextValue, nextDeps]; return nextValue; } @@ -11715,7 +11801,9 @@ to return true:wantsResponderID| | higherEventPriority(previousPriority, ContinuousEventPriority) ); var prevTransition = ReactCurrentBatchConfig$2.transition; - var currentTransition = {}; + var currentTransition = { + _callbacks: new Set() + }; { ReactCurrentBatchConfig$2.transition = null; @@ -11728,7 +11816,7 @@ to return true:wantsResponderID| | } try { - var returnValue, thenable, entangledResult, _entangledResult2; + var returnValue, thenable, thenableForFinishedState; if (enableAsyncActions); else { // Async actions are not enabled. @@ -13152,6 +13240,17 @@ to return true:wantsResponderID| | var partialState = getDerivedStateFromProps(nextProps, prevState); { + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); + + try { + // Invoke the function an extra time to help detect side-effects. + partialState = getDerivedStateFromProps(nextProps, prevState); + } finally { + setIsStrictModeForDevtools(false); + } + } + warnOnUndefinedDerivedState(ctor, partialState); } // Merge the partial state and the previous state. @@ -13258,6 +13357,21 @@ to return true:wantsResponderID| | ); { + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); + + try { + // Invoke the function an extra time to help detect side-effects. + shouldUpdate = instance.shouldComponentUpdate( + newProps, + newState, + nextContext + ); + } finally { + setIsStrictModeForDevtools(false); + } + } + if (shouldUpdate === undefined) { error( "%s.shouldComponentUpdate(): Returned undefined instead of a " + @@ -13578,6 +13692,18 @@ to return true:wantsResponderID| | var instance = new ctor(props, context); // Instantiate twice to help detect side-effects. + { + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); + + try { + instance = new ctor(props, context); // eslint-disable-line no-new + } finally { + setIsStrictModeForDevtools(false); + } + } + } + var state = (workInProgress.memoizedState = instance.state !== null && instance.state !== undefined ? instance.state @@ -13833,6 +13959,7 @@ to return true:wantsResponderID| | // process them now. processUpdateQueue(workInProgress, newProps, instance, renderLanes); + suspendIfUpdateReadFromEntangledAsyncAction(); instance.state = workInProgress.memoizedState; } @@ -13900,6 +14027,7 @@ to return true:wantsResponderID| | var oldState = workInProgress.memoizedState; var newState = (instance.state = oldState); processUpdateQueue(workInProgress, newProps, instance, renderLanes); + suspendIfUpdateReadFromEntangledAsyncAction(); newState = workInProgress.memoizedState; if ( @@ -14052,6 +14180,7 @@ to return true:wantsResponderID| | var oldState = workInProgress.memoizedState; var newState = (instance.state = oldState); processUpdateQueue(workInProgress, newProps, instance, renderLanes); + suspendIfUpdateReadFromEntangledAsyncAction(); newState = workInProgress.memoizedState; if ( @@ -14625,7 +14754,7 @@ to return true:wantsResponderID| | } } - return; + return false; } case OffscreenComponent: { @@ -14660,7 +14789,7 @@ to return true:wantsResponderID| | attachPingListener(root, wakeable, rootRenderLanes); } - return; + return false; } } } @@ -14683,7 +14812,7 @@ to return true:wantsResponderID| | // and potentially log a warning. Revisit this for a future release. attachPingListener(root, wakeable, rootRenderLanes); renderDidSuspendDelayIfPossible(); - return; + return false; } else { // In a legacy root, suspending without a boundary is always an error. var uncaughtSuspenseError = new Error( @@ -14703,6 +14832,12 @@ to return true:wantsResponderID| | // over and traverse parent path again, this time treating the exception // as an error. + if (returnFiber === null) { + // There's no return fiber, which means the root errored. This should never + // happen. Return `true` to trigger a fatal error (panic). + return true; + } + var workInProgress = returnFiber; do { @@ -14718,7 +14853,7 @@ to return true:wantsResponderID| | lane ); enqueueCapturedUpdate(workInProgress, update); - return; + return false; } case ClassComponent: @@ -14747,7 +14882,7 @@ to return true:wantsResponderID| | ); enqueueCapturedUpdate(workInProgress, _update); - return; + return false; } break; @@ -14755,6 +14890,8 @@ to return true:wantsResponderID| | workInProgress = workInProgress.return; } while (workInProgress !== null); + + return false; } var ReactCurrentOwner$2 = ReactSharedInternals.ReactCurrentOwner; // A special exception that's used to unwind the stack when an update flows @@ -14985,7 +15122,6 @@ to return true:wantsResponderID| | Component.type, null, nextProps, - null, workInProgress, workInProgress.mode, renderLanes @@ -15618,6 +15754,16 @@ to return true:wantsResponderID| | setIsRendering(true); nextChildren = instance.render(); + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); + + try { + instance.render(); + } finally { + setIsStrictModeForDevtools(false); + } + } + setIsRendering(false); } } // React DevTools reads this flag. @@ -15679,6 +15825,10 @@ to return true:wantsResponderID| | cloneUpdateQueue(current, workInProgress); processUpdateQueue(workInProgress, nextProps, null, renderLanes); var nextState = workInProgress.memoizedState; + // it needs to happen after the `pushCacheProvider` call above to avoid a + // context stack mismatch. A bit unfortunate. + + suspendIfUpdateReadFromEntangledAsyncAction(); // Caution: React DevTools currently depends on this property // being called "element". var nextChildren = nextState.element; @@ -16052,18 +16202,14 @@ to return true:wantsResponderID| | if (workInProgress.ref !== null) { var info = ""; + var componentName = getComponentNameFromType(Component) || "Unknown"; var ownerName = getCurrentFiberOwnerNameInDevOrNull(); if (ownerName) { info += "\n\nCheck the render method of `" + ownerName + "`."; } - var warningKey = ownerName || ""; - var debugSource = workInProgress._debugSource; - - if (debugSource) { - warningKey = debugSource.fileName + ":" + debugSource.lineNumber; - } + var warningKey = componentName + "|" + (ownerName || ""); if (!didWarnAboutFunctionRefs[warningKey]) { didWarnAboutFunctionRefs[warningKey] = true; @@ -16078,32 +16224,33 @@ to return true:wantsResponderID| | } if (Component.defaultProps !== undefined) { - var componentName = getComponentNameFromType(Component) || "Unknown"; + var _componentName3 = + getComponentNameFromType(Component) || "Unknown"; - if (!didWarnAboutDefaultPropsOnFunctionComponent[componentName]) { + if (!didWarnAboutDefaultPropsOnFunctionComponent[_componentName3]) { error( "%s: Support for defaultProps will be removed from function components " + "in a future major release. Use JavaScript default parameters instead.", - componentName + _componentName3 ); - didWarnAboutDefaultPropsOnFunctionComponent[componentName] = true; + didWarnAboutDefaultPropsOnFunctionComponent[_componentName3] = true; } } if (typeof Component.getDerivedStateFromProps === "function") { - var _componentName3 = + var _componentName4 = getComponentNameFromType(Component) || "Unknown"; if ( - !didWarnAboutGetDerivedStateOnFunctionComponent[_componentName3] + !didWarnAboutGetDerivedStateOnFunctionComponent[_componentName4] ) { error( "%s: Function components do not support getDerivedStateFromProps.", - _componentName3 + _componentName4 ); - didWarnAboutGetDerivedStateOnFunctionComponent[_componentName3] = + didWarnAboutGetDerivedStateOnFunctionComponent[_componentName4] = true; } } @@ -16112,16 +16259,16 @@ to return true:wantsResponderID| | typeof Component.contextType === "object" && Component.contextType !== null ) { - var _componentName4 = + var _componentName5 = getComponentNameFromType(Component) || "Unknown"; - if (!didWarnAboutContextTypeOnFunctionComponent[_componentName4]) { + if (!didWarnAboutContextTypeOnFunctionComponent[_componentName5]) { error( "%s: Function components do not support contextType.", - _componentName4 + _componentName5 ); - didWarnAboutContextTypeOnFunctionComponent[_componentName4] = true; + didWarnAboutContextTypeOnFunctionComponent[_componentName5] = true; } } } @@ -17727,7 +17874,6 @@ to return true:wantsResponderID| | workInProgress.type, workInProgress.key, workInProgress.pendingProps, - workInProgress._debugSource || null, workInProgress._debugOwner || null, workInProgress.mode, workInProgress.lanes @@ -18053,9 +18199,7 @@ to return true:wantsResponderID| | var currentValue = valueCursor.current; { - { - context._currentValue2 = currentValue; - } + context._currentValue2 = currentValue; { var currentRenderer2 = renderer2CursorDEV.current; @@ -18338,9 +18482,25 @@ to return true:wantsResponderID| | var ReactCurrentBatchConfig$1 = ReactSharedInternals.ReactCurrentBatchConfig; - var NoTransition = null; function requestCurrentTransition() { - return ReactCurrentBatchConfig$1.transition; + var transition = ReactCurrentBatchConfig$1.transition; + + if (transition !== null) { + // Whenever a transition update is scheduled, register a callback on the + // transition object so we can get the return value of the scope function. + transition._callbacks.add(handleAsyncAction); + } + + return transition; + } + + function handleAsyncAction(transition, thenable) {} + + function notifyTransitionCallbacks(transition, returnValue) { + var callbacks = transition._callbacks; + callbacks.forEach(function (callback) { + return callback(transition, returnValue); + }); } // When retrying a Suspense/Offscreen boundary, we restore the cache that was function getSuspendedCache() { { @@ -20766,7 +20926,6 @@ to return true:wantsResponderID| | fiber.stateNode = null; { - fiber._debugSource = null; fiber._debugOwner = null; } // Theoretically, nothing in here should be necessary, because we already // disconnected the fiber from the tree. So even if something leaks this @@ -21351,8 +21510,9 @@ to return true:wantsResponderID| | current !== null && current.memoizedState !== null; { - if (isShowingFallback !== wasShowingFallback) { - // A fallback is either appearing or disappearing. + if (isShowingFallback && !wasShowingFallback) { + // Old behavior. Only mark when a fallback appears, not when + // it disappears. markCommitTimeOfFallback(); } } @@ -22716,17 +22876,17 @@ to return true:wantsResponderID| | return pickArbitraryLane(workInProgressRootRenderLanes); } - var isTransition = requestCurrentTransition() !== NoTransition; + var transition = requestCurrentTransition(); - if (isTransition) { - if (ReactCurrentBatchConfig.transition !== null) { - var transition = ReactCurrentBatchConfig.transition; + if (transition !== null) { + { + var batchConfigTransition = ReactCurrentBatchConfig.transition; - if (!transition._updatedFibers) { - transition._updatedFibers = new Set(); + if (!batchConfigTransition._updatedFibers) { + batchConfigTransition._updatedFibers = new Set(); } - transition._updatedFibers.add(fiber); + batchConfigTransition._updatedFibers.add(fiber); } var actionScopeLane = peekEntangledActionLane(); @@ -22793,7 +22953,7 @@ to return true:wantsResponderID| | workInProgressDeferredLane = OffscreenLane; } else { // Everything else is spawned as a transition. - workInProgressDeferredLane = requestTransitionLane(); + workInProgressDeferredLane = claimNextTransitionLane(); } } // Mark the parent Suspense boundary so it knows to spawn the deferred lane. @@ -23165,7 +23325,7 @@ to return true:wantsResponderID| | workInProgressDeferredLane ); } else { - if (includesOnlyRetries(lanes) && alwaysThrottleRetries) { + if (includesOnlyRetries(lanes) && exitStatus === RootSuspended) { // This render only included retries, no updates. Throttle committing // retries so that we don't show too many loading states too quickly. var msUntilTimeout = @@ -23854,7 +24014,7 @@ to return true:wantsResponderID| | // Unwind then continue with the normal work loop. workInProgressSuspendedReason = NotSuspended; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(unitOfWork, thrownValue); + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); break; } } @@ -23951,7 +24111,7 @@ to return true:wantsResponderID| | // Unwind then continue with the normal work loop. workInProgressSuspendedReason = NotSuspended; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(unitOfWork, thrownValue); + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); break; } @@ -24016,7 +24176,7 @@ to return true:wantsResponderID| | // Otherwise, unwind then continue with the normal work loop. workInProgressSuspendedReason = NotSuspended; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(unitOfWork, thrownValue); + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); } break; @@ -24081,7 +24241,7 @@ to return true:wantsResponderID| | workInProgressSuspendedReason = NotSuspended; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(unitOfWork, thrownValue); + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); break; } @@ -24092,7 +24252,7 @@ to return true:wantsResponderID| | // always unwind. workInProgressSuspendedReason = NotSuspended; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(unitOfWork, thrownValue); + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); break; } @@ -24310,7 +24470,7 @@ to return true:wantsResponderID| | ReactCurrentOwner$1.current = null; } - function throwAndUnwindWorkLoop(unitOfWork, thrownValue) { + function throwAndUnwindWorkLoop(root, unitOfWork, thrownValue) { // This is a fork of performUnitOfWork specifcally for unwinding a fiber // that threw an exception. // @@ -24319,40 +24479,33 @@ to return true:wantsResponderID| | resetSuspendedWorkLoopOnUnwind(unitOfWork); var returnFiber = unitOfWork.return; - if (returnFiber === null || workInProgressRoot === null) { - // Expected to be working on a non-root fiber. This is a fatal error - // because there's no ancestor that can handle it; the root is - // supposed to capture all errors that weren't caught by an error - // boundary. - workInProgressRootExitStatus = RootFatalErrored; - workInProgressRootFatalError = thrownValue; // Set `workInProgress` to null. This represents advancing to the next - // sibling, or the parent if there are no siblings. But since the root - // has no siblings nor a parent, we set it to null. Usually this is - // handled by `completeUnitOfWork` or `unwindWork`, but since we're - // intentionally not calling those, we need set it here. - // TODO: Consider calling `unwindWork` to pop the contexts. - - workInProgress = null; - return; - } - try { // Find and mark the nearest Suspense or error boundary that can handle // this "exception". - throwException( - workInProgressRoot, + var didFatal = throwException( + root, returnFiber, unitOfWork, thrownValue, workInProgressRootRenderLanes ); + + if (didFatal) { + panicOnRootError(thrownValue); + return; + } } catch (error) { // We had trouble processing the error. An example of this happening is // when accessing the `componentDidCatch` property of an error boundary // throws an error. A weird edge case. There's a regression test for this. // To prevent an infinite loop, bubble the error up to the next parent. - workInProgress = returnFiber; - throw error; + if (returnFiber !== null) { + workInProgress = returnFiber; + throw error; + } else { + panicOnRootError(thrownValue); + return; + } } if (unitOfWork.flags & Incomplete) { @@ -24372,6 +24525,22 @@ to return true:wantsResponderID| | } } + function panicOnRootError(error) { + // There's no ancestor that can handle this exception. This should never + // happen because the root is supposed to capture all errors that weren't + // caught by an error boundary. This is a fatal error, or panic condition, + // because we've run out of ways to recover. + workInProgressRootExitStatus = RootFatalErrored; + workInProgressRootFatalError = error; // Set `workInProgress` to null. This represents advancing to the next + // sibling, or the parent if there are no siblings. But since the root + // has no siblings nor a parent, we set it to null. Usually this is + // handled by `completeUnitOfWork` or `unwindWork`, but since we're + // intentionally not calling those, we need set it here. + // TODO: Consider calling `unwindWork` to pop the contexts. + + workInProgress = null; + } + function completeUnitOfWork(unitOfWork) { // Attempt to complete the current unit of work, then move to the next // sibling. If there are no more siblings, return to the parent fiber. @@ -26128,7 +26297,6 @@ to return true:wantsResponderID| | { // This isn't directly used but is handy for debugging internals: - this._debugSource = null; this._debugOwner = null; this._debugNeedsRemount = false; this._debugHookTypes = null; @@ -26210,7 +26378,6 @@ to return true:wantsResponderID| | { // DEV-only fields - workInProgress._debugSource = current._debugSource; workInProgress._debugOwner = current._debugOwner; workInProgress._debugHookTypes = current._debugHookTypes; } @@ -26366,7 +26533,7 @@ to return true:wantsResponderID| | if (tag === ConcurrentRoot) { mode = ConcurrentMode; - if (isStrictMode === true || createRootStrictEffectsByDefault) { + if (isStrictMode === true) { mode |= StrictLegacyMode | StrictEffectsMode; } } else { @@ -26386,7 +26553,6 @@ to return true:wantsResponderID| | type, // React$ElementType key, pendingProps, - source, owner, mode, lanes @@ -26534,18 +26700,15 @@ to return true:wantsResponderID| | fiber.lanes = lanes; { - fiber._debugSource = source; fiber._debugOwner = owner; } return fiber; } function createFiberFromElement(element, mode, lanes) { - var source = null; var owner = null; { - source = element._source; owner = element._owner; } @@ -26556,14 +26719,12 @@ to return true:wantsResponderID| | type, key, pendingProps, - source, owner, mode, lanes ); { - fiber._debugSource = element._source; fiber._debugOwner = element._owner; } @@ -26692,7 +26853,6 @@ to return true:wantsResponderID| | target.treeBaseDuration = source.treeBaseDuration; } - target._debugSource = source._debugSource; target._debugOwner = source._debugOwner; target._debugNeedsRemount = source._debugNeedsRemount; target._debugHookTypes = source._debugHookTypes; @@ -26808,7 +26968,7 @@ to return true:wantsResponderID| | return root; } - var ReactVersion = "18.3.0-canary-b2d637128-20240123"; + var ReactVersion = "18.3.0-canary-03d6f7cf0-20240209"; function createPortal$1( children, @@ -27591,7 +27751,6 @@ to return true:wantsResponderID| | getInspectorData: function (findNodeHandle) { return { props: getHostProps(fiber), - source: fiber._debugSource, measure: function (callback) { // If this is Fabric, we'll find a shadow node and use that to measure. var hostFiber = findCurrentHostFiber(fiber); @@ -27654,7 +27813,7 @@ to return true:wantsResponderID| | hierarchy: [], props: emptyObject, selectedIndex: null, - source: null + componentStack: "" }; } @@ -27663,14 +27822,15 @@ to return true:wantsResponderID| | var instance = lastNonHostInstance(fiberHierarchy); var hierarchy = createHierarchy(fiberHierarchy); var props = getHostProps(instance); - var source = instance._debugSource; var selectedIndex = fiberHierarchy.indexOf(instance); + var componentStack = + fiber !== null ? getStackByFiberInDevAndProd(fiber) : ""; return { closestInstance: instance, hierarchy: hierarchy, props: props, selectedIndex: selectedIndex, - source: source + componentStack: componentStack }; } } diff --git a/packages/react-native/Libraries/Renderer/implementations/ReactFabric-prod.js b/packages/react-native/Libraries/Renderer/implementations/ReactFabric-prod.js index b62db05085d885..6753ca0e3d8f0f 100644 --- a/packages/react-native/Libraries/Renderer/implementations/ReactFabric-prod.js +++ b/packages/react-native/Libraries/Renderer/implementations/ReactFabric-prod.js @@ -8,7 +8,7 @@ * @nolint * @providesModule ReactFabric-prod * @preventMunge - * @generated SignedSource<> + * @generated SignedSource<> */ "use strict"; @@ -940,7 +940,7 @@ eventPluginOrder = Array.prototype.slice.call([ "ReactNativeBridgeEventPlugin" ]); recomputePluginOrdering(); -var injectedNamesToPlugins$jscomp$inline_230 = { +var injectedNamesToPlugins$jscomp$inline_232 = { ResponderEventPlugin: ResponderEventPlugin, ReactNativeBridgeEventPlugin: { eventTypes: {}, @@ -986,32 +986,32 @@ var injectedNamesToPlugins$jscomp$inline_230 = { } } }, - isOrderingDirty$jscomp$inline_231 = !1, - pluginName$jscomp$inline_232; -for (pluginName$jscomp$inline_232 in injectedNamesToPlugins$jscomp$inline_230) + isOrderingDirty$jscomp$inline_233 = !1, + pluginName$jscomp$inline_234; +for (pluginName$jscomp$inline_234 in injectedNamesToPlugins$jscomp$inline_232) if ( - injectedNamesToPlugins$jscomp$inline_230.hasOwnProperty( - pluginName$jscomp$inline_232 + injectedNamesToPlugins$jscomp$inline_232.hasOwnProperty( + pluginName$jscomp$inline_234 ) ) { - var pluginModule$jscomp$inline_233 = - injectedNamesToPlugins$jscomp$inline_230[pluginName$jscomp$inline_232]; + var pluginModule$jscomp$inline_235 = + injectedNamesToPlugins$jscomp$inline_232[pluginName$jscomp$inline_234]; if ( - !namesToPlugins.hasOwnProperty(pluginName$jscomp$inline_232) || - namesToPlugins[pluginName$jscomp$inline_232] !== - pluginModule$jscomp$inline_233 + !namesToPlugins.hasOwnProperty(pluginName$jscomp$inline_234) || + namesToPlugins[pluginName$jscomp$inline_234] !== + pluginModule$jscomp$inline_235 ) { - if (namesToPlugins[pluginName$jscomp$inline_232]) + if (namesToPlugins[pluginName$jscomp$inline_234]) throw Error( "EventPluginRegistry: Cannot inject two different event plugins using the same name, `" + - (pluginName$jscomp$inline_232 + "`.") + (pluginName$jscomp$inline_234 + "`.") ); - namesToPlugins[pluginName$jscomp$inline_232] = - pluginModule$jscomp$inline_233; - isOrderingDirty$jscomp$inline_231 = !0; + namesToPlugins[pluginName$jscomp$inline_234] = + pluginModule$jscomp$inline_235; + isOrderingDirty$jscomp$inline_233 = !0; } } -isOrderingDirty$jscomp$inline_231 && recomputePluginOrdering(); +isOrderingDirty$jscomp$inline_233 && recomputePluginOrdering(); var emptyObject = {}, removedKeys = null, removedKeyCount = 0, @@ -1475,6 +1475,12 @@ function getLanesToRetrySynchronouslyOnError(root, originallyAttemptedLanes) { root = root.pendingLanes & -536870913; return 0 !== root ? root : root & 536870912 ? 536870912 : 0; } +function claimNextTransitionLane() { + var lane = nextTransitionLane; + nextTransitionLane <<= 1; + 0 === (nextTransitionLane & 4194176) && (nextTransitionLane = 128); + return lane; +} function claimNextRetryLane() { var lane = nextRetryLane; nextRetryLane <<= 1; @@ -1657,7 +1663,6 @@ var REACT_ELEMENT_TYPE = Symbol.for("react.element"), REACT_PROFILER_TYPE = Symbol.for("react.profiler"), REACT_PROVIDER_TYPE = Symbol.for("react.provider"), REACT_CONTEXT_TYPE = Symbol.for("react.context"), - REACT_SERVER_CONTEXT_TYPE = Symbol.for("react.server_context"), REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"), REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"), REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"), @@ -1894,14 +1899,14 @@ function findCurrentHostFiberImpl(node) { } return null; } -function describeComponentFrame(name, source, ownerName) { - source = ""; - ownerName && (source = " (created by " + ownerName + ")"); - return "\n in " + (name || "Unknown") + source; +function describeComponentFrame(name, ownerName) { + var sourceInfo = ""; + ownerName && (sourceInfo = " (created by " + ownerName + ")"); + return "\n in " + (name || "Unknown") + sourceInfo; } -function describeFunctionComponentFrame(fn, source) { +function describeFunctionComponentFrame(fn) { return fn - ? describeComponentFrame(fn.displayName || fn.name || null, source, null) + ? describeComponentFrame(fn.displayName || fn.name || null, null) : ""; } var hasOwnProperty = Object.prototype.hasOwnProperty, @@ -2123,6 +2128,208 @@ function getRootForUpdatedFiber(sourceFiber) { (sourceFiber = parent), (parent = sourceFiber.return); return 3 === sourceFiber.tag ? sourceFiber.stateNode : null; } +var firstScheduledRoot = null, + lastScheduledRoot = null, + didScheduleMicrotask = !1, + mightHavePendingSyncWork = !1, + isFlushingWork = !1, + currentEventTransitionLane = 0; +function ensureRootIsScheduled(root) { + root !== lastScheduledRoot && + null === root.next && + (null === lastScheduledRoot + ? (firstScheduledRoot = lastScheduledRoot = root) + : (lastScheduledRoot = lastScheduledRoot.next = root)); + mightHavePendingSyncWork = !0; + didScheduleMicrotask || + ((didScheduleMicrotask = !0), + scheduleCallback$2(ImmediatePriority, processRootScheduleInMicrotask)); + scheduleTaskForRootDuringMicrotask(root, now()); +} +function flushSyncWorkAcrossRoots_impl(onlyLegacy) { + if (!isFlushingWork && mightHavePendingSyncWork) { + var errors = null; + isFlushingWork = !0; + do { + var didPerformSomeWork = !1; + for (var root = firstScheduledRoot; null !== root; ) { + if (!onlyLegacy || 0 === root.tag) { + var workInProgressRootRenderLanes$9 = workInProgressRootRenderLanes, + nextLanes = getNextLanes( + root, + root === workInProgressRoot ? workInProgressRootRenderLanes$9 : 0 + ); + if (0 !== (nextLanes & 3)) + try { + didPerformSomeWork = !0; + workInProgressRootRenderLanes$9 = root; + if (0 !== (executionContext & 6)) + throw Error("Should not already be working."); + if (!flushPassiveEffects()) { + var exitStatus = renderRootSync( + workInProgressRootRenderLanes$9, + nextLanes + ); + if ( + 0 !== workInProgressRootRenderLanes$9.tag && + 2 === exitStatus + ) { + var originallyAttemptedLanes = nextLanes, + errorRetryLanes = getLanesToRetrySynchronouslyOnError( + workInProgressRootRenderLanes$9, + originallyAttemptedLanes + ); + 0 !== errorRetryLanes && + ((nextLanes = errorRetryLanes), + (exitStatus = recoverFromConcurrentError( + workInProgressRootRenderLanes$9, + originallyAttemptedLanes, + errorRetryLanes + ))); + } + if (1 === exitStatus) + throw ( + ((originallyAttemptedLanes = workInProgressRootFatalError), + prepareFreshStack(workInProgressRootRenderLanes$9, 0), + markRootSuspended( + workInProgressRootRenderLanes$9, + nextLanes, + 0 + ), + ensureRootIsScheduled(workInProgressRootRenderLanes$9), + originallyAttemptedLanes) + ); + 6 === exitStatus + ? markRootSuspended( + workInProgressRootRenderLanes$9, + nextLanes, + workInProgressDeferredLane + ) + : ((workInProgressRootRenderLanes$9.finishedWork = + workInProgressRootRenderLanes$9.current.alternate), + (workInProgressRootRenderLanes$9.finishedLanes = nextLanes), + commitRoot( + workInProgressRootRenderLanes$9, + workInProgressRootRecoverableErrors, + workInProgressTransitions, + workInProgressDeferredLane + )); + } + ensureRootIsScheduled(workInProgressRootRenderLanes$9); + } catch (error) { + null === errors ? (errors = [error]) : errors.push(error); + } + } + root = root.next; + } + } while (didPerformSomeWork); + isFlushingWork = !1; + if (null !== errors) { + if (1 < errors.length) { + if ("function" === typeof AggregateError) + throw new AggregateError(errors); + for (onlyLegacy = 1; onlyLegacy < errors.length; onlyLegacy++) + (didPerformSomeWork = throwError.bind(null, errors[onlyLegacy])), + scheduleCallback$2(ImmediatePriority, didPerformSomeWork); + } + throw errors[0]; + } + } +} +function throwError(error) { + throw error; +} +function processRootScheduleInMicrotask() { + mightHavePendingSyncWork = didScheduleMicrotask = !1; + for ( + var currentTime = now(), prev = null, root = firstScheduledRoot; + null !== root; + + ) { + var next = root.next, + nextLanes = scheduleTaskForRootDuringMicrotask(root, currentTime); + 0 === nextLanes + ? ((root.next = null), + null === prev ? (firstScheduledRoot = next) : (prev.next = next), + null === next && (lastScheduledRoot = prev)) + : ((prev = root), + 0 !== (nextLanes & 3) && (mightHavePendingSyncWork = !0)); + root = next; + } + currentEventTransitionLane = 0; + flushSyncWorkAcrossRoots_impl(!1); +} +function scheduleTaskForRootDuringMicrotask(root, currentTime) { + for ( + var suspendedLanes = root.suspendedLanes, + pingedLanes = root.pingedLanes, + expirationTimes = root.expirationTimes, + lanes = root.pendingLanes & -62914561; + 0 < lanes; + + ) { + var index$3 = 31 - clz32(lanes), + lane = 1 << index$3, + expirationTime = expirationTimes[index$3]; + if (-1 === expirationTime) { + if (0 === (lane & suspendedLanes) || 0 !== (lane & pingedLanes)) + expirationTimes[index$3] = computeExpirationTime(lane, currentTime); + } else expirationTime <= currentTime && (root.expiredLanes |= lane); + lanes &= ~lane; + } + currentTime = workInProgressRoot; + suspendedLanes = workInProgressRootRenderLanes; + suspendedLanes = getNextLanes( + root, + root === currentTime ? suspendedLanes : 0 + ); + pingedLanes = root.callbackNode; + if ( + 0 === suspendedLanes || + (root === currentTime && 2 === workInProgressSuspendedReason) || + null !== root.cancelPendingCommit + ) + return ( + null !== pingedLanes && + null !== pingedLanes && + cancelCallback$1(pingedLanes), + (root.callbackNode = null), + (root.callbackPriority = 0) + ); + if (0 !== (suspendedLanes & 3)) + return ( + null !== pingedLanes && + null !== pingedLanes && + cancelCallback$1(pingedLanes), + (root.callbackPriority = 2), + (root.callbackNode = null), + 2 + ); + currentTime = suspendedLanes & -suspendedLanes; + if (currentTime === root.callbackPriority) return currentTime; + null !== pingedLanes && cancelCallback$1(pingedLanes); + switch (lanesToEventPriority(suspendedLanes)) { + case 2: + suspendedLanes = ImmediatePriority; + break; + case 8: + suspendedLanes = UserBlockingPriority; + break; + case 32: + suspendedLanes = NormalPriority; + break; + case 268435456: + suspendedLanes = IdlePriority; + break; + default: + suspendedLanes = NormalPriority; + } + pingedLanes = performConcurrentWorkOnRoot.bind(null, root); + suspendedLanes = scheduleCallback$2(suspendedLanes, pingedLanes); + root.callbackPriority = currentTime; + root.callbackNode = suspendedLanes; + return currentTime; +} var hasForceUpdate = !1; function initializeUpdateQueue(fiber) { fiber.updateQueue = { @@ -2386,21 +2593,21 @@ function describeFiber(fiber) { case 26: case 27: case 5: - return describeComponentFrame(fiber.type, null, null); + return describeComponentFrame(fiber.type, null); case 16: - return describeComponentFrame("Lazy", null, null); + return describeComponentFrame("Lazy", null); case 13: - return describeComponentFrame("Suspense", null, null); + return describeComponentFrame("Suspense", null); case 19: - return describeComponentFrame("SuspenseList", null, null); + return describeComponentFrame("SuspenseList", null); case 0: case 2: case 15: - return describeFunctionComponentFrame(fiber.type, null); + return describeFunctionComponentFrame(fiber.type); case 11: - return describeFunctionComponentFrame(fiber.type.render, null); + return describeFunctionComponentFrame(fiber.type.render); case 1: - return (fiber = describeFunctionComponentFrame(fiber.type, null)), fiber; + return (fiber = describeFunctionComponentFrame(fiber.type)), fiber; default: return ""; } @@ -2652,7 +2859,6 @@ function createChildReconciler(shouldTrackSideEffects) { element.key, element.props, null, - null, returnFiber.mode, lanes ); @@ -2715,7 +2921,6 @@ function createChildReconciler(shouldTrackSideEffects) { newChild.key, newChild.props, null, - null, returnFiber.mode, lanes )), @@ -2750,10 +2955,7 @@ function createChildReconciler(shouldTrackSideEffects) { ); if ("function" === typeof newChild.then) return createChild(returnFiber, unwrapThenable(newChild), lanes); - if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) + if (newChild.$$typeof === REACT_CONTEXT_TYPE) return createChild( returnFiber, readContextDuringReconcilation(returnFiber, newChild, lanes), @@ -2799,10 +3001,7 @@ function createChildReconciler(shouldTrackSideEffects) { unwrapThenable(newChild), lanes ); - if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) + if (newChild.$$typeof === REACT_CONTEXT_TYPE) return updateSlot( returnFiber, oldFiber, @@ -2869,10 +3068,7 @@ function createChildReconciler(shouldTrackSideEffects) { unwrapThenable(newChild), lanes ); - if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) + if (newChild.$$typeof === REACT_CONTEXT_TYPE) return updateFromMap( existingChildren, returnFiber, @@ -3121,7 +3317,6 @@ function createChildReconciler(shouldTrackSideEffects) { newChild.key, newChild.props, null, - null, returnFiber.mode, lanes )), @@ -3204,10 +3399,7 @@ function createChildReconciler(shouldTrackSideEffects) { unwrapThenable(newChild), lanes ); - if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) + if (newChild.$$typeof === REACT_CONTEXT_TYPE) return reconcileChildFibersImpl( returnFiber, currentFirstChild, @@ -3330,217 +3522,6 @@ function findFirstSuspended(row) { } return null; } -var firstScheduledRoot = null, - lastScheduledRoot = null, - didScheduleMicrotask = !1, - mightHavePendingSyncWork = !1, - isFlushingWork = !1, - currentEventTransitionLane = 0; -function ensureRootIsScheduled(root) { - root !== lastScheduledRoot && - null === root.next && - (null === lastScheduledRoot - ? (firstScheduledRoot = lastScheduledRoot = root) - : (lastScheduledRoot = lastScheduledRoot.next = root)); - mightHavePendingSyncWork = !0; - didScheduleMicrotask || - ((didScheduleMicrotask = !0), - scheduleCallback$2(ImmediatePriority, processRootScheduleInMicrotask)); -} -function flushSyncWorkAcrossRoots_impl(onlyLegacy) { - if (!isFlushingWork && mightHavePendingSyncWork) { - var errors = null; - isFlushingWork = !0; - do { - var didPerformSomeWork = !1; - for (var root = firstScheduledRoot; null !== root; ) { - if (!onlyLegacy || 0 === root.tag) { - var workInProgressRootRenderLanes$26 = workInProgressRootRenderLanes, - nextLanes = getNextLanes( - root, - root === workInProgressRoot ? workInProgressRootRenderLanes$26 : 0 - ); - if (0 !== (nextLanes & 3)) - try { - didPerformSomeWork = !0; - workInProgressRootRenderLanes$26 = root; - if (0 !== (executionContext & 6)) - throw Error("Should not already be working."); - if (!flushPassiveEffects()) { - var exitStatus = renderRootSync( - workInProgressRootRenderLanes$26, - nextLanes - ); - if ( - 0 !== workInProgressRootRenderLanes$26.tag && - 2 === exitStatus - ) { - var originallyAttemptedLanes = nextLanes, - errorRetryLanes = getLanesToRetrySynchronouslyOnError( - workInProgressRootRenderLanes$26, - originallyAttemptedLanes - ); - 0 !== errorRetryLanes && - ((nextLanes = errorRetryLanes), - (exitStatus = recoverFromConcurrentError( - workInProgressRootRenderLanes$26, - originallyAttemptedLanes, - errorRetryLanes - ))); - } - if (1 === exitStatus) - throw ( - ((originallyAttemptedLanes = workInProgressRootFatalError), - prepareFreshStack(workInProgressRootRenderLanes$26, 0), - markRootSuspended( - workInProgressRootRenderLanes$26, - nextLanes, - 0 - ), - ensureRootIsScheduled(workInProgressRootRenderLanes$26), - originallyAttemptedLanes) - ); - 6 === exitStatus - ? markRootSuspended( - workInProgressRootRenderLanes$26, - nextLanes, - workInProgressDeferredLane - ) - : ((workInProgressRootRenderLanes$26.finishedWork = - workInProgressRootRenderLanes$26.current.alternate), - (workInProgressRootRenderLanes$26.finishedLanes = - nextLanes), - commitRoot( - workInProgressRootRenderLanes$26, - workInProgressRootRecoverableErrors, - workInProgressTransitions, - workInProgressDeferredLane - )); - } - ensureRootIsScheduled(workInProgressRootRenderLanes$26); - } catch (error) { - null === errors ? (errors = [error]) : errors.push(error); - } - } - root = root.next; - } - } while (didPerformSomeWork); - isFlushingWork = !1; - if (null !== errors) { - if (1 < errors.length) { - if ("function" === typeof AggregateError) - throw new AggregateError(errors); - for (onlyLegacy = 1; onlyLegacy < errors.length; onlyLegacy++) - (didPerformSomeWork = throwError.bind(null, errors[onlyLegacy])), - scheduleCallback$2(ImmediatePriority, didPerformSomeWork); - } - throw errors[0]; - } - } -} -function throwError(error) { - throw error; -} -function processRootScheduleInMicrotask() { - mightHavePendingSyncWork = didScheduleMicrotask = !1; - for ( - var currentTime = now(), prev = null, root = firstScheduledRoot; - null !== root; - - ) { - var next = root.next, - nextLanes = scheduleTaskForRootDuringMicrotask(root, currentTime); - 0 === nextLanes - ? ((root.next = null), - null === prev ? (firstScheduledRoot = next) : (prev.next = next), - null === next && (lastScheduledRoot = prev)) - : ((prev = root), - 0 !== (nextLanes & 3) && (mightHavePendingSyncWork = !0)); - root = next; - } - currentEventTransitionLane = 0; - flushSyncWorkAcrossRoots_impl(!1); -} -function scheduleTaskForRootDuringMicrotask(root, currentTime) { - for ( - var suspendedLanes = root.suspendedLanes, - pingedLanes = root.pingedLanes, - expirationTimes = root.expirationTimes, - lanes = root.pendingLanes & -62914561; - 0 < lanes; - - ) { - var index$3 = 31 - clz32(lanes), - lane = 1 << index$3, - expirationTime = expirationTimes[index$3]; - if (-1 === expirationTime) { - if (0 === (lane & suspendedLanes) || 0 !== (lane & pingedLanes)) - expirationTimes[index$3] = computeExpirationTime(lane, currentTime); - } else expirationTime <= currentTime && (root.expiredLanes |= lane); - lanes &= ~lane; - } - currentTime = workInProgressRoot; - suspendedLanes = workInProgressRootRenderLanes; - suspendedLanes = getNextLanes( - root, - root === currentTime ? suspendedLanes : 0 - ); - pingedLanes = root.callbackNode; - if ( - 0 === suspendedLanes || - (root === currentTime && 2 === workInProgressSuspendedReason) || - null !== root.cancelPendingCommit - ) - return ( - null !== pingedLanes && - null !== pingedLanes && - cancelCallback$1(pingedLanes), - (root.callbackNode = null), - (root.callbackPriority = 0) - ); - if (0 !== (suspendedLanes & 3)) - return ( - null !== pingedLanes && - null !== pingedLanes && - cancelCallback$1(pingedLanes), - (root.callbackPriority = 2), - (root.callbackNode = null), - 2 - ); - currentTime = suspendedLanes & -suspendedLanes; - if (currentTime === root.callbackPriority) return currentTime; - null !== pingedLanes && cancelCallback$1(pingedLanes); - switch (lanesToEventPriority(suspendedLanes)) { - case 2: - suspendedLanes = ImmediatePriority; - break; - case 8: - suspendedLanes = UserBlockingPriority; - break; - case 32: - suspendedLanes = NormalPriority; - break; - case 268435456: - suspendedLanes = IdlePriority; - break; - default: - suspendedLanes = NormalPriority; - } - pingedLanes = performConcurrentWorkOnRoot.bind(null, root); - suspendedLanes = scheduleCallback$2(suspendedLanes, pingedLanes); - root.callbackPriority = currentTime; - root.callbackNode = suspendedLanes; - return currentTime; -} -function requestTransitionLane() { - if (0 === currentEventTransitionLane) { - var lane = nextTransitionLane; - nextTransitionLane <<= 1; - 0 === (nextTransitionLane & 4194176) && (nextTransitionLane = 128); - currentEventTransitionLane = lane; - } - return currentEventTransitionLane; -} var ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher, ReactCurrentBatchConfig$2 = ReactSharedInternals.ReactCurrentBatchConfig, renderLanes = 0, @@ -3718,11 +3699,7 @@ function useThenable(thenable) { function use(usable) { if (null !== usable && "object" === typeof usable) { if ("function" === typeof usable.then) return useThenable(usable); - if ( - usable.$$typeof === REACT_CONTEXT_TYPE || - usable.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) - return readContext(usable); + if (usable.$$typeof === REACT_CONTEXT_TYPE) return readContext(usable); } throw Error("An unsupported type was passed to use(): " + String(usable)); } @@ -3906,7 +3883,11 @@ function forceStoreRerender(fiber) { } function mountStateImpl(initialState) { var hook = mountWorkInProgressHook(); - "function" === typeof initialState && (initialState = initialState()); + if ("function" === typeof initialState) { + var initialStateInitializer = initialState; + initialState = initialStateInitializer(); + shouldDoubleInvokeUserFnsInHooksDEV && initialStateInitializer(); + } hook.memoizedState = hook.baseState = initialState; hook.queue = { pending: null, @@ -4007,10 +3988,10 @@ function updateMemo(nextCreate, deps) { var prevState = hook.memoizedState; if (null !== deps && areHookInputsEqual(deps, prevState[1])) return prevState[0]; + prevState = nextCreate(); shouldDoubleInvokeUserFnsInHooksDEV && nextCreate(); - nextCreate = nextCreate(); - hook.memoizedState = [nextCreate, deps]; - return nextCreate; + hook.memoizedState = [prevState, deps]; + return prevState; } function mountDeferredValueImpl(hook, value, initialValue) { return void 0 !== initialValue && 0 === (renderLanes & 1073741824) @@ -4040,10 +4021,11 @@ function startTransition(fiber, queue, pendingState, finishedState, callback) { var previousPriority = currentUpdatePriority; currentUpdatePriority = 0 !== previousPriority && 8 > previousPriority ? previousPriority : 8; - var prevTransition = ReactCurrentBatchConfig$2.transition; + var prevTransition = ReactCurrentBatchConfig$2.transition, + currentTransition = { _callbacks: new Set() }; ReactCurrentBatchConfig$2.transition = null; dispatchSetState(fiber, queue, pendingState); - ReactCurrentBatchConfig$2.transition = {}; + ReactCurrentBatchConfig$2.transition = currentTransition; try { dispatchSetState(fiber, queue, finishedState), callback(); } catch (error) { @@ -4186,21 +4168,24 @@ var ContextOnlyDispatcher = { useMemo: function (nextCreate, deps) { var hook = mountWorkInProgressHook(); deps = void 0 === deps ? null : deps; + var nextValue = nextCreate(); shouldDoubleInvokeUserFnsInHooksDEV && nextCreate(); - nextCreate = nextCreate(); - hook.memoizedState = [nextCreate, deps]; - return nextCreate; + hook.memoizedState = [nextValue, deps]; + return nextValue; }, useReducer: function (reducer, initialArg, init) { var hook = mountWorkInProgressHook(); - initialArg = void 0 !== init ? init(initialArg) : initialArg; - hook.memoizedState = hook.baseState = initialArg; + if (void 0 !== init) { + var initialState = init(initialArg); + shouldDoubleInvokeUserFnsInHooksDEV && init(initialArg); + } else initialState = initialArg; + hook.memoizedState = hook.baseState = initialState; reducer = { pending: null, lanes: 0, dispatch: null, lastRenderedReducer: reducer, - lastRenderedState: initialArg + lastRenderedState: initialState }; hook.queue = reducer; reducer = reducer.dispatch = dispatchReducerAction.bind( @@ -4594,6 +4579,153 @@ function createClassErrorUpdate(fiber, errorInfo, lane) { }); return lane; } +function throwException( + root, + returnFiber, + sourceFiber, + value, + rootRenderLanes +) { + sourceFiber.flags |= 32768; + if ( + null !== value && + "object" === typeof value && + "function" === typeof value.then + ) { + var tag = sourceFiber.tag; + 0 !== (sourceFiber.mode & 1) || + (0 !== tag && 11 !== tag && 15 !== tag) || + ((tag = sourceFiber.alternate) + ? ((sourceFiber.updateQueue = tag.updateQueue), + (sourceFiber.memoizedState = tag.memoizedState), + (sourceFiber.lanes = tag.lanes)) + : ((sourceFiber.updateQueue = null), + (sourceFiber.memoizedState = null))); + tag = suspenseHandlerStackCursor.current; + if (null !== tag) { + switch (tag.tag) { + case 13: + return ( + sourceFiber.mode & 1 && + (null === shellBoundary + ? renderDidSuspendDelayIfPossible() + : null === tag.alternate && + 0 === workInProgressRootExitStatus && + (workInProgressRootExitStatus = 3)), + (tag.flags &= -257), + 0 === (tag.mode & 1) + ? tag === returnFiber + ? (tag.flags |= 65536) + : ((tag.flags |= 128), + (sourceFiber.flags |= 131072), + (sourceFiber.flags &= -52805), + 1 === sourceFiber.tag && + (null === sourceFiber.alternate + ? (sourceFiber.tag = 17) + : ((returnFiber = createUpdate(2)), + (returnFiber.tag = 2), + enqueueUpdate(sourceFiber, returnFiber, 2))), + (sourceFiber.lanes |= 2)) + : ((tag.flags |= 65536), (tag.lanes = rootRenderLanes)), + value === noopSuspenseyCommitThenable + ? (tag.flags |= 16384) + : ((returnFiber = tag.updateQueue), + null === returnFiber + ? (tag.updateQueue = new Set([value])) + : returnFiber.add(value), + tag.mode & 1 && + attachPingListener(root, value, rootRenderLanes)), + !1 + ); + case 22: + if (tag.mode & 1) + return ( + (tag.flags |= 65536), + value === noopSuspenseyCommitThenable + ? (tag.flags |= 16384) + : ((returnFiber = tag.updateQueue), + null === returnFiber + ? ((returnFiber = { + transitions: null, + markerInstances: null, + retryQueue: new Set([value]) + }), + (tag.updateQueue = returnFiber)) + : ((sourceFiber = returnFiber.retryQueue), + null === sourceFiber + ? (returnFiber.retryQueue = new Set([value])) + : sourceFiber.add(value)), + attachPingListener(root, value, rootRenderLanes)), + !1 + ); + } + throw Error( + "Unexpected Suspense handler tag (" + + tag.tag + + "). This is a bug in React." + ); + } + if (1 === root.tag) + return ( + attachPingListener(root, value, rootRenderLanes), + renderDidSuspendDelayIfPossible(), + !1 + ); + value = Error( + "A component suspended while responding to synchronous input. This will cause the UI to be replaced with a loading indicator. To fix, updates that suspend should be wrapped with startTransition." + ); + } + root = value = createCapturedValueAtFiber(value, sourceFiber); + 4 !== workInProgressRootExitStatus && (workInProgressRootExitStatus = 2); + null === workInProgressRootConcurrentErrors + ? (workInProgressRootConcurrentErrors = [root]) + : workInProgressRootConcurrentErrors.push(root); + if (null === returnFiber) return !0; + root = returnFiber; + do { + switch (root.tag) { + case 3: + return ( + (root.flags |= 65536), + (rootRenderLanes &= -rootRenderLanes), + (root.lanes |= rootRenderLanes), + (rootRenderLanes = createRootErrorUpdate( + root, + value, + rootRenderLanes + )), + enqueueCapturedUpdate(root, rootRenderLanes), + !1 + ); + case 1: + if ( + ((returnFiber = value), + (sourceFiber = root.type), + (tag = root.stateNode), + 0 === (root.flags & 128) && + ("function" === typeof sourceFiber.getDerivedStateFromError || + (null !== tag && + "function" === typeof tag.componentDidCatch && + (null === legacyErrorBoundariesThatAlreadyFailed || + !legacyErrorBoundariesThatAlreadyFailed.has(tag))))) + ) + return ( + (root.flags |= 65536), + (rootRenderLanes &= -rootRenderLanes), + (root.lanes |= rootRenderLanes), + (rootRenderLanes = createClassErrorUpdate( + root, + returnFiber, + rootRenderLanes + )), + enqueueCapturedUpdate(root, rootRenderLanes), + !1 + ); + } + root = root.return; + } while (null !== root); + return !1; +} var ReactCurrentOwner$1 = ReactSharedInternals.ReactCurrentOwner, SelectiveHydrationException = Error( "This is not a real error. It's an implementation detail of React's selective hydration feature. If this leaks into userspace, it's a bug in React. Please file an issue." @@ -4668,7 +4800,6 @@ function updateMemoComponent( Component.type, null, nextProps, - null, workInProgress, workInProgress.mode, renderLanes @@ -5724,6 +5855,7 @@ function readContextForConsumer(consumer, context) { return value; } var ReactCurrentBatchConfig$1 = ReactSharedInternals.ReactCurrentBatchConfig; +function handleAsyncAction() {} function doesRequireClone(current, completedWork) { if (null !== current && current.child === completedWork.child) return !1; if (0 !== (completedWork.flags & 16)) return !0; @@ -6835,11 +6967,11 @@ function commitMutationEffectsOnFiber(finishedWork, root) { offscreenSubtreeIsHidden && ((finishedWork = finishedWork.updateQueue), null !== finishedWork && - ((current = finishedWork.callbacks), - null !== current && - ((flags = finishedWork.shared.hiddenCallbacks), + ((flags = finishedWork.callbacks), + null !== flags && + ((current = finishedWork.shared.hiddenCallbacks), (finishedWork.shared.hiddenCallbacks = - null === flags ? current : flags.concat(current))))); + null === current ? flags : current.concat(flags))))); break; case 26: case 27: @@ -6866,14 +6998,15 @@ function commitMutationEffectsOnFiber(finishedWork, root) { recursivelyTraverseMutationEffects(root, finishedWork); commitReconciliationEffects(finishedWork); finishedWork.child.flags & 8192 && - (null !== finishedWork.memoizedState) !== - (null !== current && null !== current.memoizedState) && - (globalMostRecentFallbackTime = now()); + ((current = null !== current && null !== current.memoizedState), + null === finishedWork.memoizedState || + current || + (globalMostRecentFallbackTime = now())); flags & 4 && - ((current = finishedWork.updateQueue), - null !== current && + ((flags = finishedWork.updateQueue), + null !== flags && ((finishedWork.updateQueue = null), - attachSuspenseRetryListeners(finishedWork, current))); + attachSuspenseRetryListeners(finishedWork, flags))); break; case 22: flags & 512 && @@ -6907,21 +7040,21 @@ function commitMutationEffectsOnFiber(finishedWork, root) { (0 !== (finishedWork.mode & 1) && recursivelyTraverseDisappearLayoutEffects(finishedWork)))); flags & 4 && - ((current = finishedWork.updateQueue), - null !== current && - ((flags = current.retryQueue), - null !== flags && - ((current.retryQueue = null), - attachSuspenseRetryListeners(finishedWork, flags)))); + ((flags = finishedWork.updateQueue), + null !== flags && + ((current = flags.retryQueue), + null !== current && + ((flags.retryQueue = null), + attachSuspenseRetryListeners(finishedWork, current)))); break; case 19: recursivelyTraverseMutationEffects(root, finishedWork); commitReconciliationEffects(finishedWork); flags & 4 && - ((current = finishedWork.updateQueue), - null !== current && + ((flags = finishedWork.updateQueue), + null !== flags && ((finishedWork.updateQueue = null), - attachSuspenseRetryListeners(finishedWork, current))); + attachSuspenseRetryListeners(finishedWork, flags))); break; case 21: break; @@ -7376,8 +7509,14 @@ function requestUpdateLane(fiber) { if (0 === (fiber.mode & 1)) return 2; if (0 !== (executionContext & 2) && 0 !== workInProgressRootRenderLanes) return workInProgressRootRenderLanes & -workInProgressRootRenderLanes; - if (null !== ReactCurrentBatchConfig$1.transition) - return requestTransitionLane(); + fiber = ReactCurrentBatchConfig$1.transition; + null !== fiber && fiber._callbacks.add(handleAsyncAction); + if (null !== fiber) + return ( + 0 === currentEventTransitionLane && + (currentEventTransitionLane = claimNextTransitionLane()), + currentEventTransitionLane + ); fiber = currentUpdatePriority; if (0 === fiber) a: { @@ -7399,7 +7538,7 @@ function requestDeferredLane() { (workInProgressDeferredLane = 0 !== (workInProgressRootRenderLanes & 536870912) ? 536870912 - : requestTransitionLane()); + : claimNextTransitionLane()); var suspenseHandler = suspenseHandlerStackCursor.current; null !== suspenseHandler && (suspenseHandler.flags |= 32); return workInProgressDeferredLane; @@ -7444,26 +7583,25 @@ function performConcurrentWorkOnRoot(root, didTimeout) { root === workInProgressRoot ? workInProgressRootRenderLanes : 0 ); if (0 === lanes) return null; - var shouldTimeSlice = - 0 === (lanes & 60) && 0 === (lanes & root.expiredLanes) && !didTimeout; - didTimeout = shouldTimeSlice + var exitStatus = (didTimeout = + 0 === (lanes & 60) && 0 === (lanes & root.expiredLanes) && !didTimeout) ? renderRootConcurrent(root, lanes) : renderRootSync(root, lanes); - if (0 !== didTimeout) { - var renderWasConcurrent = shouldTimeSlice; + if (0 !== exitStatus) { + var renderWasConcurrent = didTimeout; do { - if (6 === didTimeout) markRootSuspended(root, lanes, 0); + if (6 === exitStatus) markRootSuspended(root, lanes, 0); else { - shouldTimeSlice = root.current.alternate; + didTimeout = root.current.alternate; if ( renderWasConcurrent && - !isRenderConsistentWithExternalStores(shouldTimeSlice) + !isRenderConsistentWithExternalStores(didTimeout) ) { - didTimeout = renderRootSync(root, lanes); + exitStatus = renderRootSync(root, lanes); renderWasConcurrent = !1; continue; } - if (2 === didTimeout) { + if (2 === exitStatus) { renderWasConcurrent = lanes; var errorRetryLanes = getLanesToRetrySynchronouslyOnError( root, @@ -7471,13 +7609,13 @@ function performConcurrentWorkOnRoot(root, didTimeout) { ); 0 !== errorRetryLanes && ((lanes = errorRetryLanes), - (didTimeout = recoverFromConcurrentError( + (exitStatus = recoverFromConcurrentError( root, renderWasConcurrent, errorRetryLanes ))); } - if (1 === didTimeout) + if (1 === exitStatus) throw ( ((originalCallbackNode = workInProgressRootFatalError), prepareFreshStack(root, 0), @@ -7485,11 +7623,11 @@ function performConcurrentWorkOnRoot(root, didTimeout) { ensureRootIsScheduled(root), originalCallbackNode) ); - root.finishedWork = shouldTimeSlice; + root.finishedWork = didTimeout; root.finishedLanes = lanes; a: { renderWasConcurrent = root; - switch (didTimeout) { + switch (exitStatus) { case 0: case 1: throw Error("Root did not complete. This is a bug in React."); @@ -7512,8 +7650,9 @@ function performConcurrentWorkOnRoot(root, didTimeout) { } if ( (lanes & 62914560) === lanes && - ((didTimeout = globalMostRecentFallbackTime + 300 - now()), - 10 < didTimeout) + 3 === exitStatus && + ((exitStatus = globalMostRecentFallbackTime + 300 - now()), + 10 < exitStatus) ) { markRootSuspended( renderWasConcurrent, @@ -7525,19 +7664,19 @@ function performConcurrentWorkOnRoot(root, didTimeout) { commitRootWhenReady.bind( null, renderWasConcurrent, - shouldTimeSlice, + didTimeout, workInProgressRootRecoverableErrors, workInProgressTransitions, lanes, workInProgressDeferredLane ), - didTimeout + exitStatus ); break a; } commitRootWhenReady( renderWasConcurrent, - shouldTimeSlice, + didTimeout, workInProgressRootRecoverableErrors, workInProgressTransitions, lanes, @@ -7786,7 +7925,7 @@ function renderRootSync(root, lanes) { default: (workInProgressSuspendedReason = 0), (workInProgressThrownValue = null), - throwAndUnwindWorkLoop(unitOfWork, thrownValue); + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); } } workLoopSync(); @@ -7828,7 +7967,7 @@ function renderRootConcurrent(root, lanes) { case 1: workInProgressSuspendedReason = 0; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(lanes, thrownValue); + throwAndUnwindWorkLoop(root, lanes, thrownValue); break; case 2: if (isThenableResolved(thrownValue)) { @@ -7858,7 +7997,7 @@ function renderRootConcurrent(root, lanes) { replaySuspendedUnitOfWork(lanes)) : ((workInProgressSuspendedReason = 0), (workInProgressThrownValue = null), - throwAndUnwindWorkLoop(lanes, thrownValue)); + throwAndUnwindWorkLoop(root, lanes, thrownValue)); break; case 5: switch (workInProgress.tag) { @@ -7881,12 +8020,12 @@ function renderRootConcurrent(root, lanes) { } workInProgressSuspendedReason = 0; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(lanes, thrownValue); + throwAndUnwindWorkLoop(root, lanes, thrownValue); break; case 6: workInProgressSuspendedReason = 0; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(lanes, thrownValue); + throwAndUnwindWorkLoop(root, lanes, thrownValue); break; case 8: resetWorkInProgressStack(); @@ -7977,191 +8116,55 @@ function replaySuspendedUnitOfWork(unitOfWork) { : (workInProgress = current); ReactCurrentOwner.current = null; } -function throwAndUnwindWorkLoop(unitOfWork, thrownValue) { +function throwAndUnwindWorkLoop(root, unitOfWork, thrownValue) { resetContextDependencies(); resetHooksOnUnwind(unitOfWork); thenableState$1 = null; thenableIndexCounter$1 = 0; var returnFiber = unitOfWork.return; - if (null === returnFiber || null === workInProgressRoot) - (workInProgressRootExitStatus = 1), - (workInProgressRootFatalError = thrownValue), - (workInProgress = null); - else { - try { - a: { - var root = workInProgressRoot, - value = thrownValue; - thrownValue = workInProgressRootRenderLanes; - unitOfWork.flags |= 32768; - if ( - null !== value && - "object" === typeof value && - "function" === typeof value.then - ) { - var wakeable = value, - tag = unitOfWork.tag; - if ( - 0 === (unitOfWork.mode & 1) && - (0 === tag || 11 === tag || 15 === tag) - ) { - var currentSource = unitOfWork.alternate; - currentSource - ? ((unitOfWork.updateQueue = currentSource.updateQueue), - (unitOfWork.memoizedState = currentSource.memoizedState), - (unitOfWork.lanes = currentSource.lanes)) - : ((unitOfWork.updateQueue = null), - (unitOfWork.memoizedState = null)); - } - var suspenseBoundary = suspenseHandlerStackCursor.current; - if (null !== suspenseBoundary) { - switch (suspenseBoundary.tag) { - case 13: - unitOfWork.mode & 1 && - (null === shellBoundary - ? renderDidSuspendDelayIfPossible() - : null === suspenseBoundary.alternate && - 0 === workInProgressRootExitStatus && - (workInProgressRootExitStatus = 3)); - suspenseBoundary.flags &= -257; - if (0 === (suspenseBoundary.mode & 1)) - if (suspenseBoundary === returnFiber) - suspenseBoundary.flags |= 65536; - else { - suspenseBoundary.flags |= 128; - unitOfWork.flags |= 131072; - unitOfWork.flags &= -52805; - if (1 === unitOfWork.tag) - if (null === unitOfWork.alternate) unitOfWork.tag = 17; - else { - var update = createUpdate(2); - update.tag = 2; - enqueueUpdate(unitOfWork, update, 2); - } - unitOfWork.lanes |= 2; - } - else - (suspenseBoundary.flags |= 65536), - (suspenseBoundary.lanes = thrownValue); - if (wakeable === noopSuspenseyCommitThenable) - suspenseBoundary.flags |= 16384; - else { - var retryQueue = suspenseBoundary.updateQueue; - null === retryQueue - ? (suspenseBoundary.updateQueue = new Set([wakeable])) - : retryQueue.add(wakeable); - suspenseBoundary.mode & 1 && - attachPingListener(root, wakeable, thrownValue); - } - break a; - case 22: - if (suspenseBoundary.mode & 1) { - suspenseBoundary.flags |= 65536; - if (wakeable === noopSuspenseyCommitThenable) - suspenseBoundary.flags |= 16384; - else { - var offscreenQueue = suspenseBoundary.updateQueue; - if (null === offscreenQueue) { - var newOffscreenQueue = { - transitions: null, - markerInstances: null, - retryQueue: new Set([wakeable]) - }; - suspenseBoundary.updateQueue = newOffscreenQueue; - } else { - var retryQueue$31 = offscreenQueue.retryQueue; - null === retryQueue$31 - ? (offscreenQueue.retryQueue = new Set([wakeable])) - : retryQueue$31.add(wakeable); - } - attachPingListener(root, wakeable, thrownValue); - } - break a; - } - } - throw Error( - "Unexpected Suspense handler tag (" + - suspenseBoundary.tag + - "). This is a bug in React." - ); - } - if (1 === root.tag) { - attachPingListener(root, wakeable, thrownValue); - renderDidSuspendDelayIfPossible(); - break a; - } else - value = Error( - "A component suspended while responding to synchronous input. This will cause the UI to be replaced with a loading indicator. To fix, updates that suspend should be wrapped with startTransition." - ); - } - root = value = createCapturedValueAtFiber(value, unitOfWork); - 4 !== workInProgressRootExitStatus && - (workInProgressRootExitStatus = 2); - null === workInProgressRootConcurrentErrors - ? (workInProgressRootConcurrentErrors = [root]) - : workInProgressRootConcurrentErrors.push(root); - root = returnFiber; - do { - switch (root.tag) { - case 3: - var errorInfo = value; - root.flags |= 65536; - thrownValue &= -thrownValue; - root.lanes |= thrownValue; - var update$jscomp$0 = createRootErrorUpdate( - root, - errorInfo, - thrownValue - ); - enqueueCapturedUpdate(root, update$jscomp$0); - break a; - case 1: - tag = value; - var ctor = root.type, - instance = root.stateNode; - if ( - 0 === (root.flags & 128) && - ("function" === typeof ctor.getDerivedStateFromError || - (null !== instance && - "function" === typeof instance.componentDidCatch && - (null === legacyErrorBoundariesThatAlreadyFailed || - !legacyErrorBoundariesThatAlreadyFailed.has(instance)))) - ) { - root.flags |= 65536; - update$jscomp$0 = thrownValue & -thrownValue; - root.lanes |= update$jscomp$0; - errorInfo = createClassErrorUpdate(root, tag, update$jscomp$0); - enqueueCapturedUpdate(root, errorInfo); - break a; - } - } - root = root.return; - } while (null !== root); - } - } catch (error) { - throw ((workInProgress = returnFiber), error); + try { + if ( + throwException( + root, + returnFiber, + unitOfWork, + thrownValue, + workInProgressRootRenderLanes + ) + ) { + workInProgressRootExitStatus = 1; + workInProgressRootFatalError = thrownValue; + workInProgress = null; + return; } - if (unitOfWork.flags & 32768) - a: { - do { - returnFiber = unwindWork(unitOfWork.alternate, unitOfWork); - if (null !== returnFiber) { - returnFiber.flags &= 32767; - workInProgress = returnFiber; - break a; - } - unitOfWork = unitOfWork.return; - null !== unitOfWork && - ((unitOfWork.flags |= 32768), - (unitOfWork.subtreeFlags = 0), - (unitOfWork.deletions = null)); - workInProgress = unitOfWork; - } while (null !== unitOfWork); - workInProgressRootExitStatus = 6; - workInProgress = null; - } - else completeUnitOfWork(unitOfWork); + } catch (error) { + if (null !== returnFiber) throw ((workInProgress = returnFiber), error); + workInProgressRootExitStatus = 1; + workInProgressRootFatalError = thrownValue; + workInProgress = null; + return; } + if (unitOfWork.flags & 32768) + a: { + root = unitOfWork; + do { + unitOfWork = unwindWork(root.alternate, root); + if (null !== unitOfWork) { + unitOfWork.flags &= 32767; + workInProgress = unitOfWork; + break a; + } + root = root.return; + null !== root && + ((root.flags |= 32768), + (root.subtreeFlags = 0), + (root.deletions = null)); + workInProgress = root; + } while (null !== root); + workInProgressRootExitStatus = 6; + workInProgress = null; + } + else completeUnitOfWork(unitOfWork); } function completeUnitOfWork(unitOfWork) { var completedWork = unitOfWork; @@ -9009,21 +9012,20 @@ function createFiberFromTypeAndProps( type, key, pendingProps, - source, owner, mode, lanes ) { - owner = 2; - source = type; - if ("function" === typeof type) shouldConstruct(type) && (owner = 1); - else if ("string" === typeof type) owner = 5; + var fiberTag = 2; + owner = type; + if ("function" === typeof type) shouldConstruct(type) && (fiberTag = 1); + else if ("string" === typeof type) fiberTag = 5; else a: switch (type) { case REACT_FRAGMENT_TYPE: return createFiberFromFragment(pendingProps.children, mode, lanes, key); case REACT_STRICT_MODE_TYPE: - owner = 8; + fiberTag = 8; mode |= 8; 0 !== (mode & 1) && (mode |= 16); break; @@ -9054,20 +9056,20 @@ function createFiberFromTypeAndProps( if ("object" === typeof type && null !== type) switch (type.$$typeof) { case REACT_PROVIDER_TYPE: - owner = 10; + fiberTag = 10; break a; case REACT_CONTEXT_TYPE: - owner = 9; + fiberTag = 9; break a; case REACT_FORWARD_REF_TYPE: - owner = 11; + fiberTag = 11; break a; case REACT_MEMO_TYPE: - owner = 14; + fiberTag = 14; break a; case REACT_LAZY_TYPE: - owner = 16; - source = null; + fiberTag = 16; + owner = null; break a; } throw Error( @@ -9075,9 +9077,9 @@ function createFiberFromTypeAndProps( ((null == type ? type : typeof type) + ".") ); } - key = createFiber(owner, pendingProps, key, mode); + key = createFiber(fiberTag, pendingProps, key, mode); key.elementType = type; - key.type = source; + key.type = owner; key.lanes = lanes; return key; } @@ -9319,7 +9321,7 @@ var roots = new Map(), devToolsConfig$jscomp$inline_1055 = { findFiberByHostInstance: getInstanceFromNode, bundleType: 0, - version: "18.3.0-canary-b2d637128-20240123", + version: "18.3.0-canary-03d6f7cf0-20240209", rendererPackageName: "react-native-renderer", rendererConfig: { getInspectorDataForInstance: getInspectorDataForInstance, @@ -9335,7 +9337,7 @@ var roots = new Map(), }.bind(null, findNodeHandle) } }; -var internals$jscomp$inline_1297 = { +var internals$jscomp$inline_1280 = { bundleType: devToolsConfig$jscomp$inline_1055.bundleType, version: devToolsConfig$jscomp$inline_1055.version, rendererPackageName: devToolsConfig$jscomp$inline_1055.rendererPackageName, @@ -9362,19 +9364,19 @@ var internals$jscomp$inline_1297 = { scheduleRoot: null, setRefreshHandler: null, getCurrentFiber: null, - reconcilerVersion: "18.3.0-canary-b2d637128-20240123" + reconcilerVersion: "18.3.0-canary-03d6f7cf0-20240209" }; if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) { - var hook$jscomp$inline_1298 = __REACT_DEVTOOLS_GLOBAL_HOOK__; + var hook$jscomp$inline_1281 = __REACT_DEVTOOLS_GLOBAL_HOOK__; if ( - !hook$jscomp$inline_1298.isDisabled && - hook$jscomp$inline_1298.supportsFiber + !hook$jscomp$inline_1281.isDisabled && + hook$jscomp$inline_1281.supportsFiber ) try { - (rendererID = hook$jscomp$inline_1298.inject( - internals$jscomp$inline_1297 + (rendererID = hook$jscomp$inline_1281.inject( + internals$jscomp$inline_1280 )), - (injectedHook = hook$jscomp$inline_1298); + (injectedHook = hook$jscomp$inline_1281); } catch (err) {} } exports.createPortal = function (children, containerTag) { diff --git a/packages/react-native/Libraries/Renderer/implementations/ReactFabric-profiling.js b/packages/react-native/Libraries/Renderer/implementations/ReactFabric-profiling.js index b24f9c99f22669..25d43a4a918176 100644 --- a/packages/react-native/Libraries/Renderer/implementations/ReactFabric-profiling.js +++ b/packages/react-native/Libraries/Renderer/implementations/ReactFabric-profiling.js @@ -8,7 +8,7 @@ * @nolint * @providesModule ReactFabric-profiling * @preventMunge - * @generated SignedSource<> + * @generated SignedSource<<51d6b522792ab4b6c4d286b5e09bbfcd>> */ "use strict"; @@ -944,7 +944,7 @@ eventPluginOrder = Array.prototype.slice.call([ "ReactNativeBridgeEventPlugin" ]); recomputePluginOrdering(); -var injectedNamesToPlugins$jscomp$inline_245 = { +var injectedNamesToPlugins$jscomp$inline_251 = { ResponderEventPlugin: ResponderEventPlugin, ReactNativeBridgeEventPlugin: { eventTypes: {}, @@ -990,32 +990,32 @@ var injectedNamesToPlugins$jscomp$inline_245 = { } } }, - isOrderingDirty$jscomp$inline_246 = !1, - pluginName$jscomp$inline_247; -for (pluginName$jscomp$inline_247 in injectedNamesToPlugins$jscomp$inline_245) + isOrderingDirty$jscomp$inline_252 = !1, + pluginName$jscomp$inline_253; +for (pluginName$jscomp$inline_253 in injectedNamesToPlugins$jscomp$inline_251) if ( - injectedNamesToPlugins$jscomp$inline_245.hasOwnProperty( - pluginName$jscomp$inline_247 + injectedNamesToPlugins$jscomp$inline_251.hasOwnProperty( + pluginName$jscomp$inline_253 ) ) { - var pluginModule$jscomp$inline_248 = - injectedNamesToPlugins$jscomp$inline_245[pluginName$jscomp$inline_247]; + var pluginModule$jscomp$inline_254 = + injectedNamesToPlugins$jscomp$inline_251[pluginName$jscomp$inline_253]; if ( - !namesToPlugins.hasOwnProperty(pluginName$jscomp$inline_247) || - namesToPlugins[pluginName$jscomp$inline_247] !== - pluginModule$jscomp$inline_248 + !namesToPlugins.hasOwnProperty(pluginName$jscomp$inline_253) || + namesToPlugins[pluginName$jscomp$inline_253] !== + pluginModule$jscomp$inline_254 ) { - if (namesToPlugins[pluginName$jscomp$inline_247]) + if (namesToPlugins[pluginName$jscomp$inline_253]) throw Error( "EventPluginRegistry: Cannot inject two different event plugins using the same name, `" + - (pluginName$jscomp$inline_247 + "`.") + (pluginName$jscomp$inline_253 + "`.") ); - namesToPlugins[pluginName$jscomp$inline_247] = - pluginModule$jscomp$inline_248; - isOrderingDirty$jscomp$inline_246 = !0; + namesToPlugins[pluginName$jscomp$inline_253] = + pluginModule$jscomp$inline_254; + isOrderingDirty$jscomp$inline_252 = !0; } } -isOrderingDirty$jscomp$inline_246 && recomputePluginOrdering(); +isOrderingDirty$jscomp$inline_252 && recomputePluginOrdering(); var emptyObject = {}, removedKeys = null, removedKeyCount = 0, @@ -1497,6 +1497,12 @@ function getLanesToRetrySynchronouslyOnError(root, originallyAttemptedLanes) { root = root.pendingLanes & -536870913; return 0 !== root ? root : root & 536870912 ? 536870912 : 0; } +function claimNextTransitionLane() { + var lane = nextTransitionLane; + nextTransitionLane <<= 1; + 0 === (nextTransitionLane & 4194176) && (nextTransitionLane = 128); + return lane; +} function claimNextRetryLane() { var lane = nextRetryLane; nextRetryLane <<= 1; @@ -1709,7 +1715,6 @@ var REACT_ELEMENT_TYPE = Symbol.for("react.element"), REACT_PROFILER_TYPE = Symbol.for("react.profiler"), REACT_PROVIDER_TYPE = Symbol.for("react.provider"), REACT_CONTEXT_TYPE = Symbol.for("react.context"), - REACT_SERVER_CONTEXT_TYPE = Symbol.for("react.server_context"), REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"), REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"), REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"), @@ -1946,14 +1951,14 @@ function findCurrentHostFiberImpl(node) { } return null; } -function describeComponentFrame(name, source, ownerName) { - source = ""; - ownerName && (source = " (created by " + ownerName + ")"); - return "\n in " + (name || "Unknown") + source; +function describeComponentFrame(name, ownerName) { + var sourceInfo = ""; + ownerName && (sourceInfo = " (created by " + ownerName + ")"); + return "\n in " + (name || "Unknown") + sourceInfo; } -function describeFunctionComponentFrame(fn, source) { +function describeFunctionComponentFrame(fn) { return fn - ? describeComponentFrame(fn.displayName || fn.name || null, source, null) + ? describeComponentFrame(fn.displayName || fn.name || null, null) : ""; } var hasOwnProperty = Object.prototype.hasOwnProperty, @@ -2175,6 +2180,211 @@ function getRootForUpdatedFiber(sourceFiber) { (sourceFiber = parent), (parent = sourceFiber.return); return 3 === sourceFiber.tag ? sourceFiber.stateNode : null; } +var firstScheduledRoot = null, + lastScheduledRoot = null, + didScheduleMicrotask = !1, + mightHavePendingSyncWork = !1, + isFlushingWork = !1, + currentEventTransitionLane = 0; +function ensureRootIsScheduled(root) { + root !== lastScheduledRoot && + null === root.next && + (null === lastScheduledRoot + ? (firstScheduledRoot = lastScheduledRoot = root) + : (lastScheduledRoot = lastScheduledRoot.next = root)); + mightHavePendingSyncWork = !0; + didScheduleMicrotask || + ((didScheduleMicrotask = !0), + scheduleCallback$2(ImmediatePriority, processRootScheduleInMicrotask)); + scheduleTaskForRootDuringMicrotask(root, now$1()); +} +function flushSyncWorkAcrossRoots_impl(onlyLegacy) { + if (!isFlushingWork && mightHavePendingSyncWork) { + var errors = null; + isFlushingWork = !0; + do { + var didPerformSomeWork = !1; + for (var root = firstScheduledRoot; null !== root; ) { + if (!onlyLegacy || 0 === root.tag) { + var workInProgressRootRenderLanes$11 = workInProgressRootRenderLanes, + nextLanes = getNextLanes( + root, + root === workInProgressRoot ? workInProgressRootRenderLanes$11 : 0 + ); + if (0 !== (nextLanes & 3)) + try { + didPerformSomeWork = !0; + workInProgressRootRenderLanes$11 = root; + if (0 !== (executionContext & 6)) + throw Error("Should not already be working."); + if (!flushPassiveEffects()) { + currentUpdateIsNested = nestedUpdateScheduled; + nestedUpdateScheduled = !1; + var exitStatus = renderRootSync( + workInProgressRootRenderLanes$11, + nextLanes + ); + if ( + 0 !== workInProgressRootRenderLanes$11.tag && + 2 === exitStatus + ) { + var originallyAttemptedLanes = nextLanes, + errorRetryLanes = getLanesToRetrySynchronouslyOnError( + workInProgressRootRenderLanes$11, + originallyAttemptedLanes + ); + 0 !== errorRetryLanes && + ((nextLanes = errorRetryLanes), + (exitStatus = recoverFromConcurrentError( + workInProgressRootRenderLanes$11, + originallyAttemptedLanes, + errorRetryLanes + ))); + } + if (1 === exitStatus) + throw ( + ((originallyAttemptedLanes = workInProgressRootFatalError), + prepareFreshStack(workInProgressRootRenderLanes$11, 0), + markRootSuspended( + workInProgressRootRenderLanes$11, + nextLanes, + 0 + ), + ensureRootIsScheduled(workInProgressRootRenderLanes$11), + originallyAttemptedLanes) + ); + 6 === exitStatus + ? markRootSuspended( + workInProgressRootRenderLanes$11, + nextLanes, + workInProgressDeferredLane + ) + : ((workInProgressRootRenderLanes$11.finishedWork = + workInProgressRootRenderLanes$11.current.alternate), + (workInProgressRootRenderLanes$11.finishedLanes = + nextLanes), + commitRoot( + workInProgressRootRenderLanes$11, + workInProgressRootRecoverableErrors, + workInProgressTransitions, + workInProgressDeferredLane + )); + } + ensureRootIsScheduled(workInProgressRootRenderLanes$11); + } catch (error) { + null === errors ? (errors = [error]) : errors.push(error); + } + } + root = root.next; + } + } while (didPerformSomeWork); + isFlushingWork = !1; + if (null !== errors) { + if (1 < errors.length) { + if ("function" === typeof AggregateError) + throw new AggregateError(errors); + for (onlyLegacy = 1; onlyLegacy < errors.length; onlyLegacy++) + (didPerformSomeWork = throwError.bind(null, errors[onlyLegacy])), + scheduleCallback$2(ImmediatePriority, didPerformSomeWork); + } + throw errors[0]; + } + } +} +function throwError(error) { + throw error; +} +function processRootScheduleInMicrotask() { + mightHavePendingSyncWork = didScheduleMicrotask = !1; + for ( + var currentTime = now$1(), prev = null, root = firstScheduledRoot; + null !== root; + + ) { + var next = root.next, + nextLanes = scheduleTaskForRootDuringMicrotask(root, currentTime); + 0 === nextLanes + ? ((root.next = null), + null === prev ? (firstScheduledRoot = next) : (prev.next = next), + null === next && (lastScheduledRoot = prev)) + : ((prev = root), + 0 !== (nextLanes & 3) && (mightHavePendingSyncWork = !0)); + root = next; + } + currentEventTransitionLane = 0; + flushSyncWorkAcrossRoots_impl(!1); +} +function scheduleTaskForRootDuringMicrotask(root, currentTime) { + for ( + var suspendedLanes = root.suspendedLanes, + pingedLanes = root.pingedLanes, + expirationTimes = root.expirationTimes, + lanes = root.pendingLanes & -62914561; + 0 < lanes; + + ) { + var index$3 = 31 - clz32(lanes), + lane = 1 << index$3, + expirationTime = expirationTimes[index$3]; + if (-1 === expirationTime) { + if (0 === (lane & suspendedLanes) || 0 !== (lane & pingedLanes)) + expirationTimes[index$3] = computeExpirationTime(lane, currentTime); + } else expirationTime <= currentTime && (root.expiredLanes |= lane); + lanes &= ~lane; + } + currentTime = workInProgressRoot; + suspendedLanes = workInProgressRootRenderLanes; + suspendedLanes = getNextLanes( + root, + root === currentTime ? suspendedLanes : 0 + ); + pingedLanes = root.callbackNode; + if ( + 0 === suspendedLanes || + (root === currentTime && 2 === workInProgressSuspendedReason) || + null !== root.cancelPendingCommit + ) + return ( + null !== pingedLanes && + null !== pingedLanes && + cancelCallback$1(pingedLanes), + (root.callbackNode = null), + (root.callbackPriority = 0) + ); + if (0 !== (suspendedLanes & 3)) + return ( + null !== pingedLanes && + null !== pingedLanes && + cancelCallback$1(pingedLanes), + (root.callbackPriority = 2), + (root.callbackNode = null), + 2 + ); + currentTime = suspendedLanes & -suspendedLanes; + if (currentTime === root.callbackPriority) return currentTime; + null !== pingedLanes && cancelCallback$1(pingedLanes); + switch (lanesToEventPriority(suspendedLanes)) { + case 2: + suspendedLanes = ImmediatePriority; + break; + case 8: + suspendedLanes = UserBlockingPriority; + break; + case 32: + suspendedLanes = NormalPriority; + break; + case 268435456: + suspendedLanes = IdlePriority; + break; + default: + suspendedLanes = NormalPriority; + } + pingedLanes = performConcurrentWorkOnRoot.bind(null, root); + suspendedLanes = scheduleCallback$2(suspendedLanes, pingedLanes); + root.callbackPriority = currentTime; + root.callbackNode = suspendedLanes; + return currentTime; +} var hasForceUpdate = !1; function initializeUpdateQueue(fiber) { fiber.updateQueue = { @@ -2438,21 +2648,21 @@ function describeFiber(fiber) { case 26: case 27: case 5: - return describeComponentFrame(fiber.type, null, null); + return describeComponentFrame(fiber.type, null); case 16: - return describeComponentFrame("Lazy", null, null); + return describeComponentFrame("Lazy", null); case 13: - return describeComponentFrame("Suspense", null, null); + return describeComponentFrame("Suspense", null); case 19: - return describeComponentFrame("SuspenseList", null, null); + return describeComponentFrame("SuspenseList", null); case 0: case 2: case 15: - return describeFunctionComponentFrame(fiber.type, null); + return describeFunctionComponentFrame(fiber.type); case 11: - return describeFunctionComponentFrame(fiber.type.render, null); + return describeFunctionComponentFrame(fiber.type.render); case 1: - return (fiber = describeFunctionComponentFrame(fiber.type, null)), fiber; + return (fiber = describeFunctionComponentFrame(fiber.type)), fiber; default: return ""; } @@ -2704,7 +2914,6 @@ function createChildReconciler(shouldTrackSideEffects) { element.key, element.props, null, - null, returnFiber.mode, lanes ); @@ -2767,7 +2976,6 @@ function createChildReconciler(shouldTrackSideEffects) { newChild.key, newChild.props, null, - null, returnFiber.mode, lanes )), @@ -2802,10 +3010,7 @@ function createChildReconciler(shouldTrackSideEffects) { ); if ("function" === typeof newChild.then) return createChild(returnFiber, unwrapThenable(newChild), lanes); - if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) + if (newChild.$$typeof === REACT_CONTEXT_TYPE) return createChild( returnFiber, readContextDuringReconcilation(returnFiber, newChild, lanes), @@ -2851,10 +3056,7 @@ function createChildReconciler(shouldTrackSideEffects) { unwrapThenable(newChild), lanes ); - if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) + if (newChild.$$typeof === REACT_CONTEXT_TYPE) return updateSlot( returnFiber, oldFiber, @@ -2921,10 +3123,7 @@ function createChildReconciler(shouldTrackSideEffects) { unwrapThenable(newChild), lanes ); - if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) + if (newChild.$$typeof === REACT_CONTEXT_TYPE) return updateFromMap( existingChildren, returnFiber, @@ -3173,7 +3372,6 @@ function createChildReconciler(shouldTrackSideEffects) { newChild.key, newChild.props, null, - null, returnFiber.mode, lanes )), @@ -3256,10 +3454,7 @@ function createChildReconciler(shouldTrackSideEffects) { unwrapThenable(newChild), lanes ); - if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) + if (newChild.$$typeof === REACT_CONTEXT_TYPE) return reconcileChildFibersImpl( returnFiber, currentFirstChild, @@ -3287,313 +3482,100 @@ function createChildReconciler(shouldTrackSideEffects) { placeSingleChild(returnFiber)) : deleteRemainingChildren(returnFiber, currentFirstChild); } - function reconcileChildFibers( - returnFiber, - currentFirstChild, - newChild, - lanes - ) { - thenableIndexCounter$1 = 0; - returnFiber = reconcileChildFibersImpl( - returnFiber, - currentFirstChild, - newChild, - lanes - ); - thenableState$1 = null; - return returnFiber; - } - return reconcileChildFibers; -} -var reconcileChildFibers = createChildReconciler(!0), - mountChildFibers = createChildReconciler(!1), - currentTreeHiddenStackCursor = createCursor(null), - prevEntangledRenderLanesCursor = createCursor(0); -function pushHiddenContext(fiber, context) { - fiber = entangledRenderLanes; - push(prevEntangledRenderLanesCursor, fiber); - push(currentTreeHiddenStackCursor, context); - entangledRenderLanes = fiber | context.baseLanes; -} -function reuseHiddenContextOnStack() { - push(prevEntangledRenderLanesCursor, entangledRenderLanes); - push(currentTreeHiddenStackCursor, currentTreeHiddenStackCursor.current); -} -function popHiddenContext() { - entangledRenderLanes = prevEntangledRenderLanesCursor.current; - pop(currentTreeHiddenStackCursor); - pop(prevEntangledRenderLanesCursor); -} -var suspenseHandlerStackCursor = createCursor(null), - shellBoundary = null; -function pushPrimaryTreeSuspenseHandler(handler) { - var current = handler.alternate; - push(suspenseStackCursor, suspenseStackCursor.current & 1); - push(suspenseHandlerStackCursor, handler); - null === shellBoundary && - (null === current || null !== currentTreeHiddenStackCursor.current - ? (shellBoundary = handler) - : null !== current.memoizedState && (shellBoundary = handler)); -} -function pushOffscreenSuspenseHandler(fiber) { - if (22 === fiber.tag) { - if ( - (push(suspenseStackCursor, suspenseStackCursor.current), - push(suspenseHandlerStackCursor, fiber), - null === shellBoundary) - ) { - var current = fiber.alternate; - null !== current && - null !== current.memoizedState && - (shellBoundary = fiber); - } - } else reuseSuspenseHandlerOnStack(fiber); -} -function reuseSuspenseHandlerOnStack() { - push(suspenseStackCursor, suspenseStackCursor.current); - push(suspenseHandlerStackCursor, suspenseHandlerStackCursor.current); -} -function popSuspenseHandler(fiber) { - pop(suspenseHandlerStackCursor); - shellBoundary === fiber && (shellBoundary = null); - pop(suspenseStackCursor); -} -var suspenseStackCursor = createCursor(0); -function findFirstSuspended(row) { - for (var node = row; null !== node; ) { - if (13 === node.tag) { - var state = node.memoizedState; - if (null !== state && (null === state.dehydrated || shim$1() || shim$1())) - return node; - } else if (19 === node.tag && void 0 !== node.memoizedProps.revealOrder) { - if (0 !== (node.flags & 128)) return node; - } else if (null !== node.child) { - node.child.return = node; - node = node.child; - continue; - } - if (node === row) break; - for (; null === node.sibling; ) { - if (null === node.return || node.return === row) return null; - node = node.return; - } - node.sibling.return = node.return; - node = node.sibling; - } - return null; -} -var firstScheduledRoot = null, - lastScheduledRoot = null, - didScheduleMicrotask = !1, - mightHavePendingSyncWork = !1, - isFlushingWork = !1, - currentEventTransitionLane = 0; -function ensureRootIsScheduled(root) { - root !== lastScheduledRoot && - null === root.next && - (null === lastScheduledRoot - ? (firstScheduledRoot = lastScheduledRoot = root) - : (lastScheduledRoot = lastScheduledRoot.next = root)); - mightHavePendingSyncWork = !0; - didScheduleMicrotask || - ((didScheduleMicrotask = !0), - scheduleCallback$2(ImmediatePriority, processRootScheduleInMicrotask)); -} -function flushSyncWorkAcrossRoots_impl(onlyLegacy) { - if (!isFlushingWork && mightHavePendingSyncWork) { - var errors = null; - isFlushingWork = !0; - do { - var didPerformSomeWork = !1; - for (var root = firstScheduledRoot; null !== root; ) { - if (!onlyLegacy || 0 === root.tag) { - var workInProgressRootRenderLanes$28 = workInProgressRootRenderLanes, - nextLanes = getNextLanes( - root, - root === workInProgressRoot ? workInProgressRootRenderLanes$28 : 0 - ); - if (0 !== (nextLanes & 3)) - try { - didPerformSomeWork = !0; - workInProgressRootRenderLanes$28 = root; - if (0 !== (executionContext & 6)) - throw Error("Should not already be working."); - if (!flushPassiveEffects()) { - currentUpdateIsNested = nestedUpdateScheduled; - nestedUpdateScheduled = !1; - var exitStatus = renderRootSync( - workInProgressRootRenderLanes$28, - nextLanes - ); - if ( - 0 !== workInProgressRootRenderLanes$28.tag && - 2 === exitStatus - ) { - var originallyAttemptedLanes = nextLanes, - errorRetryLanes = getLanesToRetrySynchronouslyOnError( - workInProgressRootRenderLanes$28, - originallyAttemptedLanes - ); - 0 !== errorRetryLanes && - ((nextLanes = errorRetryLanes), - (exitStatus = recoverFromConcurrentError( - workInProgressRootRenderLanes$28, - originallyAttemptedLanes, - errorRetryLanes - ))); - } - if (1 === exitStatus) - throw ( - ((originallyAttemptedLanes = workInProgressRootFatalError), - prepareFreshStack(workInProgressRootRenderLanes$28, 0), - markRootSuspended( - workInProgressRootRenderLanes$28, - nextLanes, - 0 - ), - ensureRootIsScheduled(workInProgressRootRenderLanes$28), - originallyAttemptedLanes) - ); - 6 === exitStatus - ? markRootSuspended( - workInProgressRootRenderLanes$28, - nextLanes, - workInProgressDeferredLane - ) - : ((workInProgressRootRenderLanes$28.finishedWork = - workInProgressRootRenderLanes$28.current.alternate), - (workInProgressRootRenderLanes$28.finishedLanes = - nextLanes), - commitRoot( - workInProgressRootRenderLanes$28, - workInProgressRootRecoverableErrors, - workInProgressTransitions, - workInProgressDeferredLane - )); - } - ensureRootIsScheduled(workInProgressRootRenderLanes$28); - } catch (error) { - null === errors ? (errors = [error]) : errors.push(error); - } - } - root = root.next; - } - } while (didPerformSomeWork); - isFlushingWork = !1; - if (null !== errors) { - if (1 < errors.length) { - if ("function" === typeof AggregateError) - throw new AggregateError(errors); - for (onlyLegacy = 1; onlyLegacy < errors.length; onlyLegacy++) - (didPerformSomeWork = throwError.bind(null, errors[onlyLegacy])), - scheduleCallback$2(ImmediatePriority, didPerformSomeWork); - } - throw errors[0]; - } - } -} -function throwError(error) { - throw error; -} -function processRootScheduleInMicrotask() { - mightHavePendingSyncWork = didScheduleMicrotask = !1; - for ( - var currentTime = now$1(), prev = null, root = firstScheduledRoot; - null !== root; - - ) { - var next = root.next, - nextLanes = scheduleTaskForRootDuringMicrotask(root, currentTime); - 0 === nextLanes - ? ((root.next = null), - null === prev ? (firstScheduledRoot = next) : (prev.next = next), - null === next && (lastScheduledRoot = prev)) - : ((prev = root), - 0 !== (nextLanes & 3) && (mightHavePendingSyncWork = !0)); - root = next; - } - currentEventTransitionLane = 0; - flushSyncWorkAcrossRoots_impl(!1); -} -function scheduleTaskForRootDuringMicrotask(root, currentTime) { - for ( - var suspendedLanes = root.suspendedLanes, - pingedLanes = root.pingedLanes, - expirationTimes = root.expirationTimes, - lanes = root.pendingLanes & -62914561; - 0 < lanes; - - ) { - var index$3 = 31 - clz32(lanes), - lane = 1 << index$3, - expirationTime = expirationTimes[index$3]; - if (-1 === expirationTime) { - if (0 === (lane & suspendedLanes) || 0 !== (lane & pingedLanes)) - expirationTimes[index$3] = computeExpirationTime(lane, currentTime); - } else expirationTime <= currentTime && (root.expiredLanes |= lane); - lanes &= ~lane; - } - currentTime = workInProgressRoot; - suspendedLanes = workInProgressRootRenderLanes; - suspendedLanes = getNextLanes( - root, - root === currentTime ? suspendedLanes : 0 - ); - pingedLanes = root.callbackNode; - if ( - 0 === suspendedLanes || - (root === currentTime && 2 === workInProgressSuspendedReason) || - null !== root.cancelPendingCommit - ) - return ( - null !== pingedLanes && - null !== pingedLanes && - cancelCallback$1(pingedLanes), - (root.callbackNode = null), - (root.callbackPriority = 0) - ); - if (0 !== (suspendedLanes & 3)) - return ( - null !== pingedLanes && - null !== pingedLanes && - cancelCallback$1(pingedLanes), - (root.callbackPriority = 2), - (root.callbackNode = null), - 2 + function reconcileChildFibers( + returnFiber, + currentFirstChild, + newChild, + lanes + ) { + thenableIndexCounter$1 = 0; + returnFiber = reconcileChildFibersImpl( + returnFiber, + currentFirstChild, + newChild, + lanes ); - currentTime = suspendedLanes & -suspendedLanes; - if (currentTime === root.callbackPriority) return currentTime; - null !== pingedLanes && cancelCallback$1(pingedLanes); - switch (lanesToEventPriority(suspendedLanes)) { - case 2: - suspendedLanes = ImmediatePriority; - break; - case 8: - suspendedLanes = UserBlockingPriority; - break; - case 32: - suspendedLanes = NormalPriority; - break; - case 268435456: - suspendedLanes = IdlePriority; - break; - default: - suspendedLanes = NormalPriority; + thenableState$1 = null; + return returnFiber; } - pingedLanes = performConcurrentWorkOnRoot.bind(null, root); - suspendedLanes = scheduleCallback$2(suspendedLanes, pingedLanes); - root.callbackPriority = currentTime; - root.callbackNode = suspendedLanes; - return currentTime; + return reconcileChildFibers; +} +var reconcileChildFibers = createChildReconciler(!0), + mountChildFibers = createChildReconciler(!1), + currentTreeHiddenStackCursor = createCursor(null), + prevEntangledRenderLanesCursor = createCursor(0); +function pushHiddenContext(fiber, context) { + fiber = entangledRenderLanes; + push(prevEntangledRenderLanesCursor, fiber); + push(currentTreeHiddenStackCursor, context); + entangledRenderLanes = fiber | context.baseLanes; +} +function reuseHiddenContextOnStack() { + push(prevEntangledRenderLanesCursor, entangledRenderLanes); + push(currentTreeHiddenStackCursor, currentTreeHiddenStackCursor.current); +} +function popHiddenContext() { + entangledRenderLanes = prevEntangledRenderLanesCursor.current; + pop(currentTreeHiddenStackCursor); + pop(prevEntangledRenderLanesCursor); +} +var suspenseHandlerStackCursor = createCursor(null), + shellBoundary = null; +function pushPrimaryTreeSuspenseHandler(handler) { + var current = handler.alternate; + push(suspenseStackCursor, suspenseStackCursor.current & 1); + push(suspenseHandlerStackCursor, handler); + null === shellBoundary && + (null === current || null !== currentTreeHiddenStackCursor.current + ? (shellBoundary = handler) + : null !== current.memoizedState && (shellBoundary = handler)); +} +function pushOffscreenSuspenseHandler(fiber) { + if (22 === fiber.tag) { + if ( + (push(suspenseStackCursor, suspenseStackCursor.current), + push(suspenseHandlerStackCursor, fiber), + null === shellBoundary) + ) { + var current = fiber.alternate; + null !== current && + null !== current.memoizedState && + (shellBoundary = fiber); + } + } else reuseSuspenseHandlerOnStack(fiber); +} +function reuseSuspenseHandlerOnStack() { + push(suspenseStackCursor, suspenseStackCursor.current); + push(suspenseHandlerStackCursor, suspenseHandlerStackCursor.current); +} +function popSuspenseHandler(fiber) { + pop(suspenseHandlerStackCursor); + shellBoundary === fiber && (shellBoundary = null); + pop(suspenseStackCursor); } -function requestTransitionLane() { - if (0 === currentEventTransitionLane) { - var lane = nextTransitionLane; - nextTransitionLane <<= 1; - 0 === (nextTransitionLane & 4194176) && (nextTransitionLane = 128); - currentEventTransitionLane = lane; +var suspenseStackCursor = createCursor(0); +function findFirstSuspended(row) { + for (var node = row; null !== node; ) { + if (13 === node.tag) { + var state = node.memoizedState; + if (null !== state && (null === state.dehydrated || shim$1() || shim$1())) + return node; + } else if (19 === node.tag && void 0 !== node.memoizedProps.revealOrder) { + if (0 !== (node.flags & 128)) return node; + } else if (null !== node.child) { + node.child.return = node; + node = node.child; + continue; + } + if (node === row) break; + for (; null === node.sibling; ) { + if (null === node.return || node.return === row) return null; + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; } - return currentEventTransitionLane; + return null; } var ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher, ReactCurrentBatchConfig$2 = ReactSharedInternals.ReactCurrentBatchConfig, @@ -3772,11 +3754,7 @@ function useThenable(thenable) { function use(usable) { if (null !== usable && "object" === typeof usable) { if ("function" === typeof usable.then) return useThenable(usable); - if ( - usable.$$typeof === REACT_CONTEXT_TYPE || - usable.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) - return readContext(usable); + if (usable.$$typeof === REACT_CONTEXT_TYPE) return readContext(usable); } throw Error("An unsupported type was passed to use(): " + String(usable)); } @@ -3960,7 +3938,11 @@ function forceStoreRerender(fiber) { } function mountStateImpl(initialState) { var hook = mountWorkInProgressHook(); - "function" === typeof initialState && (initialState = initialState()); + if ("function" === typeof initialState) { + var initialStateInitializer = initialState; + initialState = initialStateInitializer(); + shouldDoubleInvokeUserFnsInHooksDEV && initialStateInitializer(); + } hook.memoizedState = hook.baseState = initialState; hook.queue = { pending: null, @@ -4061,31 +4043,29 @@ function updateMemo(nextCreate, deps) { var prevState = hook.memoizedState; if (null !== deps && areHookInputsEqual(deps, prevState[1])) return prevState[0]; + prevState = nextCreate(); shouldDoubleInvokeUserFnsInHooksDEV && nextCreate(); - nextCreate = nextCreate(); - hook.memoizedState = [nextCreate, deps]; - return nextCreate; -} -function mountDeferredValueImpl(hook, value, initialValue) { - return void 0 !== initialValue && 0 === (renderLanes & 1073741824) - ? ((hook.memoizedState = initialValue), - (hook = requestDeferredLane()), - (currentlyRenderingFiber$1.lanes |= hook), - (workInProgressRootSkippedLanes |= hook), - initialValue) - : (hook.memoizedState = value); -} -function updateDeferredValueImpl(hook, prevValue, value, initialValue) { + hook.memoizedState = [prevState, deps]; + return prevState; +} +function updateDeferredValueImpl(hook, prevValue, value) { if (objectIs(value, prevValue)) return value; if (null !== currentTreeHiddenStackCursor.current) return ( - (hook = mountDeferredValueImpl(hook, value, initialValue)), - objectIs(hook, prevValue) || (didReceiveUpdate = !0), - hook + (hook.memoizedState = value), + objectIs(value, prevValue) || (didReceiveUpdate = !0), + value ); if (0 === (renderLanes & 42)) return (didReceiveUpdate = !0), (hook.memoizedState = value); - hook = requestDeferredLane(); + 0 === workInProgressDeferredLane && + (workInProgressDeferredLane = + 0 !== (workInProgressRootRenderLanes & 536870912) + ? 536870912 + : claimNextTransitionLane()); + hook = suspenseHandlerStackCursor.current; + null !== hook && (hook.flags |= 32); + hook = workInProgressDeferredLane; currentlyRenderingFiber$1.lanes |= hook; workInProgressRootSkippedLanes |= hook; return prevValue; @@ -4094,10 +4074,11 @@ function startTransition(fiber, queue, pendingState, finishedState, callback) { var previousPriority = currentUpdatePriority; currentUpdatePriority = 0 !== previousPriority && 8 > previousPriority ? previousPriority : 8; - var prevTransition = ReactCurrentBatchConfig$2.transition; + var prevTransition = ReactCurrentBatchConfig$2.transition, + currentTransition = { _callbacks: new Set() }; ReactCurrentBatchConfig$2.transition = null; dispatchSetState(fiber, queue, pendingState); - ReactCurrentBatchConfig$2.transition = {}; + ReactCurrentBatchConfig$2.transition = currentTransition; try { dispatchSetState(fiber, queue, finishedState), callback(); } catch (error) { @@ -4240,21 +4221,24 @@ var ContextOnlyDispatcher = { useMemo: function (nextCreate, deps) { var hook = mountWorkInProgressHook(); deps = void 0 === deps ? null : deps; + var nextValue = nextCreate(); shouldDoubleInvokeUserFnsInHooksDEV && nextCreate(); - nextCreate = nextCreate(); - hook.memoizedState = [nextCreate, deps]; - return nextCreate; + hook.memoizedState = [nextValue, deps]; + return nextValue; }, useReducer: function (reducer, initialArg, init) { var hook = mountWorkInProgressHook(); - initialArg = void 0 !== init ? init(initialArg) : initialArg; - hook.memoizedState = hook.baseState = initialArg; + if (void 0 !== init) { + var initialState = init(initialArg); + shouldDoubleInvokeUserFnsInHooksDEV && init(initialArg); + } else initialState = initialArg; + hook.memoizedState = hook.baseState = initialState; reducer = { pending: null, lanes: 0, dispatch: null, lastRenderedReducer: reducer, - lastRenderedState: initialArg + lastRenderedState: initialState }; hook.queue = reducer; reducer = reducer.dispatch = dispatchReducerAction.bind( @@ -4281,9 +4265,9 @@ var ContextOnlyDispatcher = { return [initialState.memoizedState, dispatch]; }, useDebugValue: mountDebugValue, - useDeferredValue: function (value, initialValue) { - var hook = mountWorkInProgressHook(); - return mountDeferredValueImpl(hook, value, initialValue); + useDeferredValue: function (value) { + mountWorkInProgressHook().memoizedState = value; + return value; }, useTransition: function () { var stateHook = mountStateImpl(!1); @@ -4347,14 +4331,9 @@ var ContextOnlyDispatcher = { return updateReducer(basicStateReducer); }, useDebugValue: mountDebugValue, - useDeferredValue: function (value, initialValue) { + useDeferredValue: function (value) { var hook = updateWorkInProgressHook(); - return updateDeferredValueImpl( - hook, - currentHook.memoizedState, - value, - initialValue - ); + return updateDeferredValueImpl(hook, currentHook.memoizedState, value); }, useTransition: function () { var booleanOrThenable = updateReducer(basicStateReducer)[0], @@ -4385,16 +4364,11 @@ var ContextOnlyDispatcher = { return rerenderReducer(basicStateReducer); }, useDebugValue: mountDebugValue, - useDeferredValue: function (value, initialValue) { + useDeferredValue: function (value) { var hook = updateWorkInProgressHook(); return null === currentHook - ? mountDeferredValueImpl(hook, value, initialValue) - : updateDeferredValueImpl( - hook, - currentHook.memoizedState, - value, - initialValue - ); + ? ((hook.memoizedState = value), value) + : updateDeferredValueImpl(hook, currentHook.memoizedState, value); }, useTransition: function () { var booleanOrThenable = rerenderReducer(basicStateReducer)[0], @@ -4710,6 +4684,154 @@ function createClassErrorUpdate(fiber, errorInfo, lane) { }); return lane; } +function throwException( + root, + returnFiber, + sourceFiber, + value, + rootRenderLanes +) { + sourceFiber.flags |= 32768; + isDevToolsPresent && restorePendingUpdaters(root, rootRenderLanes); + if ( + null !== value && + "object" === typeof value && + "function" === typeof value.then + ) { + var tag = sourceFiber.tag; + 0 !== (sourceFiber.mode & 1) || + (0 !== tag && 11 !== tag && 15 !== tag) || + ((tag = sourceFiber.alternate) + ? ((sourceFiber.updateQueue = tag.updateQueue), + (sourceFiber.memoizedState = tag.memoizedState), + (sourceFiber.lanes = tag.lanes)) + : ((sourceFiber.updateQueue = null), + (sourceFiber.memoizedState = null))); + tag = suspenseHandlerStackCursor.current; + if (null !== tag) { + switch (tag.tag) { + case 13: + return ( + sourceFiber.mode & 1 && + (null === shellBoundary + ? renderDidSuspendDelayIfPossible() + : null === tag.alternate && + 0 === workInProgressRootExitStatus && + (workInProgressRootExitStatus = 3)), + (tag.flags &= -257), + 0 === (tag.mode & 1) + ? tag === returnFiber + ? (tag.flags |= 65536) + : ((tag.flags |= 128), + (sourceFiber.flags |= 131072), + (sourceFiber.flags &= -52805), + 1 === sourceFiber.tag && + (null === sourceFiber.alternate + ? (sourceFiber.tag = 17) + : ((returnFiber = createUpdate(2)), + (returnFiber.tag = 2), + enqueueUpdate(sourceFiber, returnFiber, 2))), + (sourceFiber.lanes |= 2)) + : ((tag.flags |= 65536), (tag.lanes = rootRenderLanes)), + value === noopSuspenseyCommitThenable + ? (tag.flags |= 16384) + : ((returnFiber = tag.updateQueue), + null === returnFiber + ? (tag.updateQueue = new Set([value])) + : returnFiber.add(value), + tag.mode & 1 && + attachPingListener(root, value, rootRenderLanes)), + !1 + ); + case 22: + if (tag.mode & 1) + return ( + (tag.flags |= 65536), + value === noopSuspenseyCommitThenable + ? (tag.flags |= 16384) + : ((returnFiber = tag.updateQueue), + null === returnFiber + ? ((returnFiber = { + transitions: null, + markerInstances: null, + retryQueue: new Set([value]) + }), + (tag.updateQueue = returnFiber)) + : ((sourceFiber = returnFiber.retryQueue), + null === sourceFiber + ? (returnFiber.retryQueue = new Set([value])) + : sourceFiber.add(value)), + attachPingListener(root, value, rootRenderLanes)), + !1 + ); + } + throw Error( + "Unexpected Suspense handler tag (" + + tag.tag + + "). This is a bug in React." + ); + } + if (1 === root.tag) + return ( + attachPingListener(root, value, rootRenderLanes), + renderDidSuspendDelayIfPossible(), + !1 + ); + value = Error( + "A component suspended while responding to synchronous input. This will cause the UI to be replaced with a loading indicator. To fix, updates that suspend should be wrapped with startTransition." + ); + } + root = value = createCapturedValueAtFiber(value, sourceFiber); + 4 !== workInProgressRootExitStatus && (workInProgressRootExitStatus = 2); + null === workInProgressRootConcurrentErrors + ? (workInProgressRootConcurrentErrors = [root]) + : workInProgressRootConcurrentErrors.push(root); + if (null === returnFiber) return !0; + root = returnFiber; + do { + switch (root.tag) { + case 3: + return ( + (root.flags |= 65536), + (rootRenderLanes &= -rootRenderLanes), + (root.lanes |= rootRenderLanes), + (rootRenderLanes = createRootErrorUpdate( + root, + value, + rootRenderLanes + )), + enqueueCapturedUpdate(root, rootRenderLanes), + !1 + ); + case 1: + if ( + ((returnFiber = value), + (sourceFiber = root.type), + (tag = root.stateNode), + 0 === (root.flags & 128) && + ("function" === typeof sourceFiber.getDerivedStateFromError || + (null !== tag && + "function" === typeof tag.componentDidCatch && + (null === legacyErrorBoundariesThatAlreadyFailed || + !legacyErrorBoundariesThatAlreadyFailed.has(tag))))) + ) + return ( + (root.flags |= 65536), + (rootRenderLanes &= -rootRenderLanes), + (root.lanes |= rootRenderLanes), + (rootRenderLanes = createClassErrorUpdate( + root, + returnFiber, + rootRenderLanes + )), + enqueueCapturedUpdate(root, rootRenderLanes), + !1 + ); + } + root = root.return; + } while (null !== root); + return !1; +} var ReactCurrentOwner$1 = ReactSharedInternals.ReactCurrentOwner, SelectiveHydrationException = Error( "This is not a real error. It's an implementation detail of React's selective hydration feature. If this leaks into userspace, it's a bug in React. Please file an issue." @@ -4784,7 +4906,6 @@ function updateMemoComponent( Component.type, null, nextProps, - null, workInProgress, workInProgress.mode, renderLanes @@ -4866,23 +4987,23 @@ function updateOffscreenComponent(current, workInProgress, renderLanes) { } if (0 === (workInProgress.mode & 1)) (workInProgress.memoizedState = { baseLanes: 0, cachePool: null }), - reuseHiddenContextOnStack(); - else { - if (0 === (renderLanes & 536870912)) - return ( - (workInProgress.lanes = workInProgress.childLanes = 536870912), - deferHiddenOffscreenComponent( - current, - workInProgress, - null !== prevState ? prevState.baseLanes | renderLanes : renderLanes - ) - ); - workInProgress.memoizedState = { baseLanes: 0, cachePool: null }; - null !== prevState - ? pushHiddenContext(workInProgress, prevState) - : reuseHiddenContextOnStack(); - } - pushOffscreenSuspenseHandler(workInProgress); + reuseHiddenContextOnStack(), + pushOffscreenSuspenseHandler(workInProgress); + else if (0 !== (renderLanes & 536870912)) + (workInProgress.memoizedState = { baseLanes: 0, cachePool: null }), + null !== prevState + ? pushHiddenContext(workInProgress, prevState) + : reuseHiddenContextOnStack(), + pushOffscreenSuspenseHandler(workInProgress); + else + return ( + (workInProgress.lanes = workInProgress.childLanes = 536870912), + deferHiddenOffscreenComponent( + current, + workInProgress, + null !== prevState ? prevState.baseLanes | renderLanes : renderLanes + ) + ); } else null !== prevState ? (pushHiddenContext(workInProgress, prevState), @@ -5864,6 +5985,7 @@ function readContextForConsumer(consumer, context) { return value; } var ReactCurrentBatchConfig$1 = ReactSharedInternals.ReactCurrentBatchConfig; +function handleAsyncAction() {} function doesRequireClone(current, completedWork) { if (null !== current && current.child === completedWork.child) return !1; if (0 !== (completedWork.flags & 16)) return !0; @@ -7191,11 +7313,11 @@ function commitMutationEffectsOnFiber(finishedWork, root) { offscreenSubtreeIsHidden && ((finishedWork = finishedWork.updateQueue), null !== finishedWork && - ((current = finishedWork.callbacks), - null !== current && - ((flags = finishedWork.shared.hiddenCallbacks), + ((flags = finishedWork.callbacks), + null !== flags && + ((current = finishedWork.shared.hiddenCallbacks), (finishedWork.shared.hiddenCallbacks = - null === flags ? current : flags.concat(current))))); + null === current ? flags : current.concat(flags))))); break; case 26: case 27: @@ -7222,14 +7344,15 @@ function commitMutationEffectsOnFiber(finishedWork, root) { recursivelyTraverseMutationEffects(root, finishedWork); commitReconciliationEffects(finishedWork); finishedWork.child.flags & 8192 && - (null !== finishedWork.memoizedState) !== - (null !== current && null !== current.memoizedState) && - (globalMostRecentFallbackTime = now$1()); + ((current = null !== current && null !== current.memoizedState), + null === finishedWork.memoizedState || + current || + (globalMostRecentFallbackTime = now$1())); flags & 4 && - ((current = finishedWork.updateQueue), - null !== current && + ((flags = finishedWork.updateQueue), + null !== flags && ((finishedWork.updateQueue = null), - attachSuspenseRetryListeners(finishedWork, current))); + attachSuspenseRetryListeners(finishedWork, flags))); break; case 22: flags & 512 && @@ -7263,21 +7386,21 @@ function commitMutationEffectsOnFiber(finishedWork, root) { (0 !== (finishedWork.mode & 1) && recursivelyTraverseDisappearLayoutEffects(finishedWork)))); flags & 4 && - ((current = finishedWork.updateQueue), - null !== current && - ((flags = current.retryQueue), - null !== flags && - ((current.retryQueue = null), - attachSuspenseRetryListeners(finishedWork, flags)))); + ((flags = finishedWork.updateQueue), + null !== flags && + ((current = flags.retryQueue), + null !== current && + ((flags.retryQueue = null), + attachSuspenseRetryListeners(finishedWork, current)))); break; case 19: recursivelyTraverseMutationEffects(root, finishedWork); commitReconciliationEffects(finishedWork); flags & 4 && - ((current = finishedWork.updateQueue), - null !== current && + ((flags = finishedWork.updateQueue), + null !== flags && ((finishedWork.updateQueue = null), - attachSuspenseRetryListeners(finishedWork, current))); + attachSuspenseRetryListeners(finishedWork, flags))); break; case 21: break; @@ -7774,8 +7897,14 @@ function requestUpdateLane(fiber) { if (0 === (fiber.mode & 1)) return 2; if (0 !== (executionContext & 2) && 0 !== workInProgressRootRenderLanes) return workInProgressRootRenderLanes & -workInProgressRootRenderLanes; - if (null !== ReactCurrentBatchConfig$1.transition) - return requestTransitionLane(); + fiber = ReactCurrentBatchConfig$1.transition; + null !== fiber && fiber._callbacks.add(handleAsyncAction); + if (null !== fiber) + return ( + 0 === currentEventTransitionLane && + (currentEventTransitionLane = claimNextTransitionLane()), + currentEventTransitionLane + ); fiber = currentUpdatePriority; if (0 === fiber) a: { @@ -7792,16 +7921,6 @@ function requestUpdateLane(fiber) { } return fiber; } -function requestDeferredLane() { - 0 === workInProgressDeferredLane && - (workInProgressDeferredLane = - 0 !== (workInProgressRootRenderLanes & 536870912) - ? 536870912 - : requestTransitionLane()); - var suspenseHandler = suspenseHandlerStackCursor.current; - null !== suspenseHandler && (suspenseHandler.flags |= 32); - return workInProgressDeferredLane; -} function scheduleUpdateOnFiber(root, fiber, lane) { if ( (root === workInProgressRoot && 2 === workInProgressSuspendedReason) || @@ -7844,26 +7963,25 @@ function performConcurrentWorkOnRoot(root, didTimeout) { root === workInProgressRoot ? workInProgressRootRenderLanes : 0 ); if (0 === lanes) return null; - var shouldTimeSlice = - 0 === (lanes & 60) && 0 === (lanes & root.expiredLanes) && !didTimeout; - didTimeout = shouldTimeSlice + var exitStatus = (didTimeout = + 0 === (lanes & 60) && 0 === (lanes & root.expiredLanes) && !didTimeout) ? renderRootConcurrent(root, lanes) : renderRootSync(root, lanes); - if (0 !== didTimeout) { - var renderWasConcurrent = shouldTimeSlice; + if (0 !== exitStatus) { + var renderWasConcurrent = didTimeout; do { - if (6 === didTimeout) markRootSuspended(root, lanes, 0); + if (6 === exitStatus) markRootSuspended(root, lanes, 0); else { - shouldTimeSlice = root.current.alternate; + didTimeout = root.current.alternate; if ( renderWasConcurrent && - !isRenderConsistentWithExternalStores(shouldTimeSlice) + !isRenderConsistentWithExternalStores(didTimeout) ) { - didTimeout = renderRootSync(root, lanes); + exitStatus = renderRootSync(root, lanes); renderWasConcurrent = !1; continue; } - if (2 === didTimeout) { + if (2 === exitStatus) { renderWasConcurrent = lanes; var errorRetryLanes = getLanesToRetrySynchronouslyOnError( root, @@ -7871,13 +7989,13 @@ function performConcurrentWorkOnRoot(root, didTimeout) { ); 0 !== errorRetryLanes && ((lanes = errorRetryLanes), - (didTimeout = recoverFromConcurrentError( + (exitStatus = recoverFromConcurrentError( root, renderWasConcurrent, errorRetryLanes ))); } - if (1 === didTimeout) + if (1 === exitStatus) throw ( ((originalCallbackNode = workInProgressRootFatalError), prepareFreshStack(root, 0), @@ -7885,11 +8003,11 @@ function performConcurrentWorkOnRoot(root, didTimeout) { ensureRootIsScheduled(root), originalCallbackNode) ); - root.finishedWork = shouldTimeSlice; + root.finishedWork = didTimeout; root.finishedLanes = lanes; a: { renderWasConcurrent = root; - switch (didTimeout) { + switch (exitStatus) { case 0: case 1: throw Error("Root did not complete. This is a bug in React."); @@ -7912,8 +8030,9 @@ function performConcurrentWorkOnRoot(root, didTimeout) { } if ( (lanes & 62914560) === lanes && - ((didTimeout = globalMostRecentFallbackTime + 300 - now$1()), - 10 < didTimeout) + 3 === exitStatus && + ((exitStatus = globalMostRecentFallbackTime + 300 - now$1()), + 10 < exitStatus) ) { markRootSuspended( renderWasConcurrent, @@ -7925,19 +8044,19 @@ function performConcurrentWorkOnRoot(root, didTimeout) { commitRootWhenReady.bind( null, renderWasConcurrent, - shouldTimeSlice, + didTimeout, workInProgressRootRecoverableErrors, workInProgressTransitions, lanes, workInProgressDeferredLane ), - didTimeout + exitStatus ); break a; } commitRootWhenReady( renderWasConcurrent, - shouldTimeSlice, + didTimeout, workInProgressRootRecoverableErrors, workInProgressTransitions, lanes, @@ -8197,7 +8316,7 @@ function renderRootSync(root, lanes) { default: (workInProgressSuspendedReason = 0), (workInProgressThrownValue = null), - throwAndUnwindWorkLoop(memoizedUpdaters, thrownValue); + throwAndUnwindWorkLoop(root, memoizedUpdaters, thrownValue); } } workLoopSync(); @@ -8249,7 +8368,7 @@ function renderRootConcurrent(root, lanes) { case 1: workInProgressSuspendedReason = 0; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(lanes, memoizedUpdaters); + throwAndUnwindWorkLoop(root, lanes, memoizedUpdaters); break; case 2: if (isThenableResolved(memoizedUpdaters)) { @@ -8279,7 +8398,7 @@ function renderRootConcurrent(root, lanes) { replaySuspendedUnitOfWork(lanes)) : ((workInProgressSuspendedReason = 0), (workInProgressThrownValue = null), - throwAndUnwindWorkLoop(lanes, memoizedUpdaters)); + throwAndUnwindWorkLoop(root, lanes, memoizedUpdaters)); break; case 5: switch (workInProgress.tag) { @@ -8302,12 +8421,12 @@ function renderRootConcurrent(root, lanes) { } workInProgressSuspendedReason = 0; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(lanes, memoizedUpdaters); + throwAndUnwindWorkLoop(root, lanes, memoizedUpdaters); break; case 6: workInProgressSuspendedReason = 0; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(lanes, memoizedUpdaters); + throwAndUnwindWorkLoop(root, lanes, memoizedUpdaters); break; case 8: resetWorkInProgressStack(); @@ -8407,200 +8526,63 @@ function replaySuspendedUnitOfWork(unitOfWork) { : (workInProgress = current); ReactCurrentOwner.current = null; } -function throwAndUnwindWorkLoop(unitOfWork, thrownValue) { +function throwAndUnwindWorkLoop(root, unitOfWork, thrownValue) { resetContextDependencies(); resetHooksOnUnwind(unitOfWork); thenableState$1 = null; thenableIndexCounter$1 = 0; var returnFiber = unitOfWork.return; - if (null === returnFiber || null === workInProgressRoot) - (workInProgressRootExitStatus = 1), - (workInProgressRootFatalError = thrownValue), - (workInProgress = null); - else { - try { - a: { - var root = workInProgressRoot, - value = thrownValue; - thrownValue = workInProgressRootRenderLanes; - unitOfWork.flags |= 32768; - isDevToolsPresent && restorePendingUpdaters(root, thrownValue); - if ( - null !== value && - "object" === typeof value && - "function" === typeof value.then - ) { - var wakeable = value, - tag = unitOfWork.tag; - if ( - 0 === (unitOfWork.mode & 1) && - (0 === tag || 11 === tag || 15 === tag) - ) { - var currentSource = unitOfWork.alternate; - currentSource - ? ((unitOfWork.updateQueue = currentSource.updateQueue), - (unitOfWork.memoizedState = currentSource.memoizedState), - (unitOfWork.lanes = currentSource.lanes)) - : ((unitOfWork.updateQueue = null), - (unitOfWork.memoizedState = null)); - } - var suspenseBoundary = suspenseHandlerStackCursor.current; - if (null !== suspenseBoundary) { - switch (suspenseBoundary.tag) { - case 13: - unitOfWork.mode & 1 && - (null === shellBoundary - ? renderDidSuspendDelayIfPossible() - : null === suspenseBoundary.alternate && - 0 === workInProgressRootExitStatus && - (workInProgressRootExitStatus = 3)); - suspenseBoundary.flags &= -257; - if (0 === (suspenseBoundary.mode & 1)) - if (suspenseBoundary === returnFiber) - suspenseBoundary.flags |= 65536; - else { - suspenseBoundary.flags |= 128; - unitOfWork.flags |= 131072; - unitOfWork.flags &= -52805; - if (1 === unitOfWork.tag) - if (null === unitOfWork.alternate) unitOfWork.tag = 17; - else { - var update = createUpdate(2); - update.tag = 2; - enqueueUpdate(unitOfWork, update, 2); - } - unitOfWork.lanes |= 2; - } - else - (suspenseBoundary.flags |= 65536), - (suspenseBoundary.lanes = thrownValue); - if (wakeable === noopSuspenseyCommitThenable) - suspenseBoundary.flags |= 16384; - else { - var retryQueue = suspenseBoundary.updateQueue; - null === retryQueue - ? (suspenseBoundary.updateQueue = new Set([wakeable])) - : retryQueue.add(wakeable); - suspenseBoundary.mode & 1 && - attachPingListener(root, wakeable, thrownValue); - } - break a; - case 22: - if (suspenseBoundary.mode & 1) { - suspenseBoundary.flags |= 65536; - if (wakeable === noopSuspenseyCommitThenable) - suspenseBoundary.flags |= 16384; - else { - var offscreenQueue = suspenseBoundary.updateQueue; - if (null === offscreenQueue) { - var newOffscreenQueue = { - transitions: null, - markerInstances: null, - retryQueue: new Set([wakeable]) - }; - suspenseBoundary.updateQueue = newOffscreenQueue; - } else { - var retryQueue$33 = offscreenQueue.retryQueue; - null === retryQueue$33 - ? (offscreenQueue.retryQueue = new Set([wakeable])) - : retryQueue$33.add(wakeable); - } - attachPingListener(root, wakeable, thrownValue); - } - break a; - } - } - throw Error( - "Unexpected Suspense handler tag (" + - suspenseBoundary.tag + - "). This is a bug in React." - ); - } - if (1 === root.tag) { - attachPingListener(root, wakeable, thrownValue); - renderDidSuspendDelayIfPossible(); - break a; - } else - value = Error( - "A component suspended while responding to synchronous input. This will cause the UI to be replaced with a loading indicator. To fix, updates that suspend should be wrapped with startTransition." - ); - } - root = value = createCapturedValueAtFiber(value, unitOfWork); - 4 !== workInProgressRootExitStatus && - (workInProgressRootExitStatus = 2); - null === workInProgressRootConcurrentErrors - ? (workInProgressRootConcurrentErrors = [root]) - : workInProgressRootConcurrentErrors.push(root); - root = returnFiber; - do { - switch (root.tag) { - case 3: - var errorInfo = value; - root.flags |= 65536; - thrownValue &= -thrownValue; - root.lanes |= thrownValue; - var update$jscomp$0 = createRootErrorUpdate( - root, - errorInfo, - thrownValue - ); - enqueueCapturedUpdate(root, update$jscomp$0); - break a; - case 1: - tag = value; - var ctor = root.type, - instance = root.stateNode; - if ( - 0 === (root.flags & 128) && - ("function" === typeof ctor.getDerivedStateFromError || - (null !== instance && - "function" === typeof instance.componentDidCatch && - (null === legacyErrorBoundariesThatAlreadyFailed || - !legacyErrorBoundariesThatAlreadyFailed.has(instance)))) - ) { - root.flags |= 65536; - update$jscomp$0 = thrownValue & -thrownValue; - root.lanes |= update$jscomp$0; - errorInfo = createClassErrorUpdate(root, tag, update$jscomp$0); - enqueueCapturedUpdate(root, errorInfo); - break a; - } - } - root = root.return; - } while (null !== root); - } - } catch (error) { - throw ((workInProgress = returnFiber), error); + try { + if ( + throwException( + root, + returnFiber, + unitOfWork, + thrownValue, + workInProgressRootRenderLanes + ) + ) { + workInProgressRootExitStatus = 1; + workInProgressRootFatalError = thrownValue; + workInProgress = null; + return; } - if (unitOfWork.flags & 32768) - a: { - do { - returnFiber = unwindWork(unitOfWork.alternate, unitOfWork); - if (null !== returnFiber) { - returnFiber.flags &= 32767; - workInProgress = returnFiber; - break a; - } - if (0 !== (unitOfWork.mode & 2)) { - stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, !1); - returnFiber = unitOfWork.actualDuration; - for (update$jscomp$0 = unitOfWork.child; null !== update$jscomp$0; ) - (returnFiber += update$jscomp$0.actualDuration), - (update$jscomp$0 = update$jscomp$0.sibling); - unitOfWork.actualDuration = returnFiber; - } - unitOfWork = unitOfWork.return; - null !== unitOfWork && - ((unitOfWork.flags |= 32768), - (unitOfWork.subtreeFlags = 0), - (unitOfWork.deletions = null)); - workInProgress = unitOfWork; - } while (null !== unitOfWork); - workInProgressRootExitStatus = 6; - workInProgress = null; - } - else completeUnitOfWork(unitOfWork); + } catch (error) { + if (null !== returnFiber) throw ((workInProgress = returnFiber), error); + workInProgressRootExitStatus = 1; + workInProgressRootFatalError = thrownValue; + workInProgress = null; + return; } + if (unitOfWork.flags & 32768) + a: { + root = unitOfWork; + do { + unitOfWork = unwindWork(root.alternate, root); + if (null !== unitOfWork) { + unitOfWork.flags &= 32767; + workInProgress = unitOfWork; + break a; + } + if (0 !== (root.mode & 2)) { + stopProfilerTimerIfRunningAndRecordDelta(root, !1); + unitOfWork = root.actualDuration; + for (thrownValue = root.child; null !== thrownValue; ) + (unitOfWork += thrownValue.actualDuration), + (thrownValue = thrownValue.sibling); + root.actualDuration = unitOfWork; + } + root = root.return; + null !== root && + ((root.flags |= 32768), + (root.subtreeFlags = 0), + (root.deletions = null)); + workInProgress = root; + } while (null !== root); + workInProgressRootExitStatus = 6; + workInProgress = null; + } + else completeUnitOfWork(unitOfWork); } function completeUnitOfWork(unitOfWork) { var completedWork = unitOfWork; @@ -9519,21 +9501,20 @@ function createFiberFromTypeAndProps( type, key, pendingProps, - source, owner, mode, lanes ) { - owner = 2; - source = type; - if ("function" === typeof type) shouldConstruct(type) && (owner = 1); - else if ("string" === typeof type) owner = 5; + var fiberTag = 2; + owner = type; + if ("function" === typeof type) shouldConstruct(type) && (fiberTag = 1); + else if ("string" === typeof type) fiberTag = 5; else a: switch (type) { case REACT_FRAGMENT_TYPE: return createFiberFromFragment(pendingProps.children, mode, lanes, key); case REACT_STRICT_MODE_TYPE: - owner = 8; + fiberTag = 8; mode |= 8; 0 !== (mode & 1) && (mode |= 16); break; @@ -9565,20 +9546,20 @@ function createFiberFromTypeAndProps( if ("object" === typeof type && null !== type) switch (type.$$typeof) { case REACT_PROVIDER_TYPE: - owner = 10; + fiberTag = 10; break a; case REACT_CONTEXT_TYPE: - owner = 9; + fiberTag = 9; break a; case REACT_FORWARD_REF_TYPE: - owner = 11; + fiberTag = 11; break a; case REACT_MEMO_TYPE: - owner = 14; + fiberTag = 14; break a; case REACT_LAZY_TYPE: - owner = 16; - source = null; + fiberTag = 16; + owner = null; break a; } throw Error( @@ -9586,9 +9567,9 @@ function createFiberFromTypeAndProps( ((null == type ? type : typeof type) + ".") ); } - key = createFiber(owner, pendingProps, key, mode); + key = createFiber(fiberTag, pendingProps, key, mode); key.elementType = type; - key.type = source; + key.type = owner; key.lanes = lanes; return key; } @@ -9831,10 +9812,10 @@ batchedUpdatesImpl = function (fn, a) { } }; var roots = new Map(), - devToolsConfig$jscomp$inline_1095 = { + devToolsConfig$jscomp$inline_1114 = { findFiberByHostInstance: getInstanceFromNode, bundleType: 0, - version: "18.3.0-canary-b2d637128-20240123", + version: "18.3.0-canary-c1b45781", rendererPackageName: "react-native-renderer", rendererConfig: { getInspectorDataForInstance: getInspectorDataForInstance, @@ -9851,10 +9832,10 @@ var roots = new Map(), } }; var internals$jscomp$inline_1333 = { - bundleType: devToolsConfig$jscomp$inline_1095.bundleType, - version: devToolsConfig$jscomp$inline_1095.version, - rendererPackageName: devToolsConfig$jscomp$inline_1095.rendererPackageName, - rendererConfig: devToolsConfig$jscomp$inline_1095.rendererConfig, + bundleType: devToolsConfig$jscomp$inline_1114.bundleType, + version: devToolsConfig$jscomp$inline_1114.version, + rendererPackageName: devToolsConfig$jscomp$inline_1114.rendererPackageName, + rendererConfig: devToolsConfig$jscomp$inline_1114.rendererConfig, overrideHookState: null, overrideHookStateDeletePath: null, overrideHookStateRenamePath: null, @@ -9870,14 +9851,14 @@ var internals$jscomp$inline_1333 = { return null === fiber ? null : fiber.stateNode; }, findFiberByHostInstance: - devToolsConfig$jscomp$inline_1095.findFiberByHostInstance || + devToolsConfig$jscomp$inline_1114.findFiberByHostInstance || emptyFindFiberByHostInstance, findHostInstancesForRefresh: null, scheduleRefresh: null, scheduleRoot: null, setRefreshHandler: null, getCurrentFiber: null, - reconcilerVersion: "18.3.0-canary-b2d637128-20240123" + reconcilerVersion: "18.3.0-canary-c1b45781" }; if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) { var hook$jscomp$inline_1334 = __REACT_DEVTOOLS_GLOBAL_HOOK__; diff --git a/packages/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js b/packages/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js index 8ccdb679c6e0a6..d993f420538989 100644 --- a/packages/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js +++ b/packages/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js @@ -8,7 +8,7 @@ * @nolint * @providesModule ReactNativeRenderer-dev * @preventMunge - * @generated SignedSource<> + * @generated SignedSource<<434937dbc3b1c3592d8ef8196d0c1a52>> */ "use strict"; @@ -2940,18 +2940,15 @@ to return true:wantsResponderID| | key._reactInternals = value; } - var debugRenderPhaseSideEffectsForStrictMode = false; var enableSchedulingProfiler = false; var enableProfilerTimer = true; var enableProfilerCommitHooks = true; var enableProfilerNestedUpdatePhase = true; var syncLaneExpirationMs = 250; var transitionLaneExpirationMs = 5000; - var createRootStrictEffectsByDefault = false; var enableLazyContextPropagation = false; var enableLegacyHidden = false; var enableAsyncActions = false; - var alwaysThrottleRetries = true; // ATTENTION // When adding new symbols to this file, @@ -2964,7 +2961,6 @@ to return true:wantsResponderID| | var REACT_PROFILER_TYPE = Symbol.for("react.profiler"); var REACT_PROVIDER_TYPE = Symbol.for("react.provider"); var REACT_CONTEXT_TYPE = Symbol.for("react.context"); - var REACT_SERVER_CONTEXT_TYPE = Symbol.for("react.server_context"); var REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"); var REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"); var REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"); @@ -4261,6 +4257,103 @@ to return true:wantsResponderID| | var NormalPriority = Scheduler.unstable_NormalPriority; var IdlePriority = Scheduler.unstable_IdlePriority; // this doesn't actually exist on the scheduler, but it *does* + // Helpers to patch console.logs to avoid logging during side-effect free + // replaying on render function. This currently only patches the object + // lazily which won't cover if the log function was extracted eagerly. + // We could also eagerly patch the method. + var disabledDepth = 0; + var prevLog; + var prevInfo; + var prevWarn; + var prevError; + var prevGroup; + var prevGroupCollapsed; + var prevGroupEnd; + + function disabledLog() {} + + disabledLog.__reactDisabledLog = true; + function disableLogs() { + { + if (disabledDepth === 0) { + /* eslint-disable react-internal/no-production-logging */ + prevLog = console.log; + prevInfo = console.info; + prevWarn = console.warn; + prevError = console.error; + prevGroup = console.group; + prevGroupCollapsed = console.groupCollapsed; + prevGroupEnd = console.groupEnd; // https://github.com/facebook/react/issues/19099 + + var props = { + configurable: true, + enumerable: true, + value: disabledLog, + writable: true + }; // $FlowFixMe[cannot-write] Flow thinks console is immutable. + + Object.defineProperties(console, { + info: props, + log: props, + warn: props, + error: props, + group: props, + groupCollapsed: props, + groupEnd: props + }); + /* eslint-enable react-internal/no-production-logging */ + } + + disabledDepth++; + } + } + function reenableLogs() { + { + disabledDepth--; + + if (disabledDepth === 0) { + /* eslint-disable react-internal/no-production-logging */ + var props = { + configurable: true, + enumerable: true, + writable: true + }; // $FlowFixMe[cannot-write] Flow thinks console is immutable. + + Object.defineProperties(console, { + log: assign({}, props, { + value: prevLog + }), + info: assign({}, props, { + value: prevInfo + }), + warn: assign({}, props, { + value: prevWarn + }), + error: assign({}, props, { + value: prevError + }), + group: assign({}, props, { + value: prevGroup + }), + groupCollapsed: assign({}, props, { + value: prevGroupCollapsed + }), + groupEnd: assign({}, props, { + value: prevGroupEnd + }) + }); + /* eslint-enable react-internal/no-production-logging */ + } + + if (disabledDepth < 0) { + error( + "disabledDepth fell below zero. " + + "This is a bug in React. Please file an issue." + ); + } + } + } + var rendererID = null; var injectedHook = null; var hasLoggedError = false; @@ -4419,6 +4512,15 @@ to return true:wantsResponderID| | } } } + function setIsStrictModeForDevtools(newIsStrictMode) { + { + if (newIsStrictMode) { + disableLogs(); + } else { + reenableLogs(); + } + } + } // Profiler API hooks function injectProfilingHooks(profilingHooks) {} @@ -5715,7 +5817,7 @@ to return true:wantsResponderID| | return null; } - function describeBuiltInComponentFrame(name, source, ownerFn) { + function describeBuiltInComponentFrame(name, ownerFn) { { var ownerName = null; @@ -5723,7 +5825,7 @@ to return true:wantsResponderID| | ownerName = ownerFn.displayName || ownerFn.name || null; } - return describeComponentFrame(name, source, ownerName); + return describeComponentFrame(name, ownerName); } } @@ -5731,43 +5833,23 @@ to return true:wantsResponderID| | var PossiblyWeakMap$1 = typeof WeakMap === "function" ? WeakMap : Map; new PossiblyWeakMap$1(); } - var BEFORE_SLASH_RE = /^(.*)[\\\/]/; - function describeComponentFrame(name, source, ownerName) { + function describeComponentFrame(name, ownerName) { var sourceInfo = ""; - if (source) { - var path = source.fileName; - var fileName = path.replace(BEFORE_SLASH_RE, ""); // In DEV, include code for a common special case: - // prefer "folder/index.js" instead of just "index.js". - - if (/^index\./.test(fileName)) { - var match = path.match(BEFORE_SLASH_RE); - - if (match) { - var pathBeforeSlash = match[1]; - - if (pathBeforeSlash) { - var folderName = pathBeforeSlash.replace(BEFORE_SLASH_RE, ""); - fileName = folderName + "/" + fileName; - } - } - } - - sourceInfo = " (at " + fileName + ":" + source.lineNumber + ")"; - } else if (ownerName) { + if (ownerName) { sourceInfo = " (created by " + ownerName + ")"; } return "\n in " + (name || "Unknown") + sourceInfo; } - function describeClassComponentFrame(ctor, source, ownerFn) { + function describeClassComponentFrame(ctor, ownerFn) { { - return describeFunctionComponentFrame(ctor, source, ownerFn); + return describeFunctionComponentFrame(ctor, ownerFn); } } - function describeFunctionComponentFrame(fn, source, ownerFn) { + function describeFunctionComponentFrame(fn, ownerFn) { { if (!fn) { return ""; @@ -5780,45 +5862,41 @@ to return true:wantsResponderID| | ownerName = ownerFn.displayName || ownerFn.name || null; } - return describeComponentFrame(name, source, ownerName); + return describeComponentFrame(name, ownerName); } } - function describeUnknownElementTypeFrameInDEV(type, source, ownerFn) { + function describeUnknownElementTypeFrameInDEV(type, ownerFn) { if (type == null) { return ""; } if (typeof type === "function") { { - return describeFunctionComponentFrame(type, source, ownerFn); + return describeFunctionComponentFrame(type, ownerFn); } } if (typeof type === "string") { - return describeBuiltInComponentFrame(type, source, ownerFn); + return describeBuiltInComponentFrame(type, ownerFn); } switch (type) { case REACT_SUSPENSE_TYPE: - return describeBuiltInComponentFrame("Suspense", source, ownerFn); + return describeBuiltInComponentFrame("Suspense", ownerFn); case REACT_SUSPENSE_LIST_TYPE: - return describeBuiltInComponentFrame("SuspenseList", source, ownerFn); + return describeBuiltInComponentFrame("SuspenseList", ownerFn); } if (typeof type === "object") { switch (type.$$typeof) { case REACT_FORWARD_REF_TYPE: - return describeFunctionComponentFrame(type.render, source, ownerFn); + return describeFunctionComponentFrame(type.render, ownerFn); case REACT_MEMO_TYPE: // Memo may contain any component type so we recursively resolve it. - return describeUnknownElementTypeFrameInDEV( - type.type, - source, - ownerFn - ); + return describeUnknownElementTypeFrameInDEV(type.type, ownerFn); case REACT_LAZY_TYPE: { var lazyComponent = type; @@ -5829,7 +5907,6 @@ to return true:wantsResponderID| | // Lazy may contain any component type so we recursively resolve it. return describeUnknownElementTypeFrameInDEV( init(payload), - source, ownerFn ); } catch (x) {} @@ -5852,7 +5929,6 @@ to return true:wantsResponderID| | var owner = element._owner; var stack = describeUnknownElementTypeFrameInDEV( element.type, - element._source, owner ? owner.type : null ); ReactDebugCurrentFrame$1.setExtraStackFrame(stack); @@ -6676,3686 +6752,3665 @@ to return true:wantsResponderID| | } } - var UpdateState = 0; - var ReplaceState = 1; - var ForceUpdate = 2; - var CaptureUpdate = 3; // Global state that is reset at the beginning of calling `processUpdateQueue`. - // It should only be read right after calling `processUpdateQueue`, via - // `checkHasForceUpdateAfterProcessing`. - - var hasForceUpdate = false; - var didWarnUpdateInsideUpdate; - var currentlyProcessingQueue; - - { - didWarnUpdateInsideUpdate = false; - currentlyProcessingQueue = null; - } - - function initializeUpdateQueue(fiber) { - var queue = { - baseState: fiber.memoizedState, - firstBaseUpdate: null, - lastBaseUpdate: null, - shared: { - pending: null, - lanes: NoLanes, - hiddenCallbacks: null - }, - callbacks: null - }; - fiber.updateQueue = queue; - } - function cloneUpdateQueue(current, workInProgress) { - // Clone the update queue from current. Unless it's already a clone. - var queue = workInProgress.updateQueue; - var currentQueue = current.updateQueue; - - if (queue === currentQueue) { - var clone = { - baseState: currentQueue.baseState, - firstBaseUpdate: currentQueue.firstBaseUpdate, - lastBaseUpdate: currentQueue.lastBaseUpdate, - shared: currentQueue.shared, - callbacks: null - }; - workInProgress.updateQueue = clone; - } - } - function createUpdate(lane) { - var update = { - lane: lane, - tag: UpdateState, - payload: null, - callback: null, - next: null - }; - return update; - } - function enqueueUpdate(fiber, update, lane) { - var updateQueue = fiber.updateQueue; - - if (updateQueue === null) { - // Only occurs if the fiber has been unmounted. - return null; - } + var ReactCurrentActQueue$3 = ReactSharedInternals.ReactCurrentActQueue; // A linked list of all the roots with pending work. In an idiomatic app, + // there's only a single root, but we do support multi root apps, hence this + // extra complexity. But this module is optimized for the single root case. - var sharedQueue = updateQueue.shared; + var firstScheduledRoot = null; + var lastScheduledRoot = null; // Used to prevent redundant mircotasks from being scheduled. - { - if ( - currentlyProcessingQueue === sharedQueue && - !didWarnUpdateInsideUpdate - ) { - var componentName = getComponentNameFromFiber(fiber); + var didScheduleMicrotask = false; // `act` "microtasks" are scheduled on the `act` queue instead of an actual + // microtask, so we have to dedupe those separately. This wouldn't be an issue + // if we required all `act` calls to be awaited, which we might in the future. - error( - "An update (setState, replaceState, or forceUpdate) was scheduled " + - "from inside an update function. Update functions should be pure, " + - "with zero side-effects. Consider using componentDidUpdate or a " + - "callback.\n\nPlease update the following component: %s", - componentName - ); + var didScheduleMicrotask_act = false; // Used to quickly bail out of flushSync if there's no sync work to do. - didWarnUpdateInsideUpdate = true; + var mightHavePendingSyncWork = false; + var isFlushingWork = false; + var currentEventTransitionLane = NoLane; + function ensureRootIsScheduled(root) { + // This function is called whenever a root receives an update. It does two + // things 1) it ensures the root is in the root schedule, and 2) it ensures + // there's a pending microtask to process the root schedule. + // + // Most of the actual scheduling logic does not happen until + // `scheduleTaskForRootDuringMicrotask` runs. + // Add the root to the schedule + if (root === lastScheduledRoot || root.next !== null); + else { + if (lastScheduledRoot === null) { + firstScheduledRoot = lastScheduledRoot = root; + } else { + lastScheduledRoot.next = root; + lastScheduledRoot = root; } - } + } // Any time a root received an update, we set this to true until the next time + // we process the schedule. If it's false, then we can quickly exit flushSync + // without consulting the schedule. - if (isUnsafeClassRenderPhaseUpdate()) { - // This is an unsafe render phase update. Add directly to the update - // queue so we can process it immediately during the current render. - var pending = sharedQueue.pending; + mightHavePendingSyncWork = true; // At the end of the current event, go through each of the roots and ensure + // there's a task scheduled for each one at the correct priority. - if (pending === null) { - // This is the first update. Create a circular list. - update.next = update; - } else { - update.next = pending.next; - pending.next = update; + if (ReactCurrentActQueue$3.current !== null) { + // We're inside an `act` scope. + if (!didScheduleMicrotask_act) { + didScheduleMicrotask_act = true; + scheduleImmediateTask(processRootScheduleInMicrotask); + } + } else { + if (!didScheduleMicrotask) { + didScheduleMicrotask = true; + scheduleImmediateTask(processRootScheduleInMicrotask); } + } - sharedQueue.pending = update; // Update the childLanes even though we're most likely already rendering - // this fiber. This is for backwards compatibility in the case where you - // update a different component during render phase than the one that is - // currently renderings (a pattern that is accompanied by a warning). + { + // While this flag is disabled, we schedule the render task immediately + // instead of waiting a microtask. + // TODO: We need to land enableDeferRootSchedulingToMicrotask ASAP to + // unblock additional features we have planned. + scheduleTaskForRootDuringMicrotask(root, now$1()); + } - return unsafe_markUpdateLaneFromFiberToRoot(fiber, lane); - } else { - return enqueueConcurrentClassUpdate(fiber, sharedQueue, update, lane); + if (ReactCurrentActQueue$3.isBatchingLegacy && root.tag === LegacyRoot) { + // Special `act` case: Record whenever a legacy update is scheduled. + ReactCurrentActQueue$3.didScheduleLegacyUpdate = true; } } - function entangleTransitions(root, fiber, lane) { - var updateQueue = fiber.updateQueue; + function flushSyncWorkOnAllRoots() { + // This is allowed to be called synchronously, but the caller should check + // the execution context first. + flushSyncWorkAcrossRoots_impl(false); + } + function flushSyncWorkOnLegacyRootsOnly() { + // This is allowed to be called synchronously, but the caller should check + // the execution context first. + flushSyncWorkAcrossRoots_impl(true); + } - if (updateQueue === null) { - // Only occurs if the fiber has been unmounted. + function flushSyncWorkAcrossRoots_impl(onlyLegacy) { + if (isFlushingWork) { + // Prevent reentrancy. + // TODO: Is this overly defensive? The callers must check the execution + // context first regardless. return; } - var sharedQueue = updateQueue.shared; + if (!mightHavePendingSyncWork) { + // Fast path. There's no sync work to do. + return; + } // There may or may not be synchronous work scheduled. Let's check. - if (isTransitionLane(lane)) { - var queueLanes = sharedQueue.lanes; // If any entangled lanes are no longer pending on the root, then they must - // have finished. We can remove them from the shared queue, which represents - // a superset of the actually pending lanes. In some cases we may entangle - // more than we need to, but that's OK. In fact it's worse if we *don't* - // entangle when we should. + var didPerformSomeWork; + var errors = null; + isFlushingWork = true; - queueLanes = intersectLanes(queueLanes, root.pendingLanes); // Entangle the new transition lane with the other transition lanes. + do { + didPerformSomeWork = false; + var root = firstScheduledRoot; - var newQueueLanes = mergeLanes(queueLanes, lane); - sharedQueue.lanes = newQueueLanes; // Even if queue.lanes already include lane, we don't know for certain if - // the lane finished since the last time we entangled it. So we need to - // entangle it again, just to be sure. + while (root !== null) { + if (onlyLegacy && root.tag !== LegacyRoot); + else { + var workInProgressRoot = getWorkInProgressRoot(); + var workInProgressRootRenderLanes = + getWorkInProgressRootRenderLanes(); + var nextLanes = getNextLanes( + root, + root === workInProgressRoot + ? workInProgressRootRenderLanes + : NoLanes + ); - markRootEntangled(root, newQueueLanes); - } - } - function enqueueCapturedUpdate(workInProgress, capturedUpdate) { - // Captured updates are updates that are thrown by a child during the render - // phase. They should be discarded if the render is aborted. Therefore, - // we should only put them on the work-in-progress queue, not the current one. - var queue = workInProgress.updateQueue; // Check if the work-in-progress queue is a clone. + if (includesSyncLane(nextLanes)) { + // This root has pending sync work. Flush it now. + try { + didPerformSomeWork = true; + performSyncWorkOnRoot(root, nextLanes); + } catch (error) { + // Collect errors so we can rethrow them at the end + if (errors === null) { + errors = [error]; + } else { + errors.push(error); + } + } + } + } - var current = workInProgress.alternate; + root = root.next; + } + } while (didPerformSomeWork); - if (current !== null) { - var currentQueue = current.updateQueue; + isFlushingWork = false; // If any errors were thrown, rethrow them right before exiting. + // TODO: Consider returning these to the caller, to allow them to decide + // how/when to rethrow. - if (queue === currentQueue) { - // The work-in-progress queue is the same as current. This happens when - // we bail out on a parent fiber that then captures an error thrown by - // a child. Since we want to append the update only to the work-in - // -progress queue, we need to clone the updates. We usually clone during - // processUpdateQueue, but that didn't happen in this case because we - // skipped over the parent when we bailed out. - var newFirst = null; - var newLast = null; - var firstBaseUpdate = queue.firstBaseUpdate; - - if (firstBaseUpdate !== null) { - // Loop through the updates and clone them. - var update = firstBaseUpdate; - - do { - var clone = { - lane: update.lane, - tag: update.tag, - payload: update.payload, - // When this update is rebased, we should not fire its - // callback again. - callback: null, - next: null - }; - - if (newLast === null) { - newFirst = newLast = clone; - } else { - newLast.next = clone; - newLast = clone; - } // $FlowFixMe[incompatible-type] we bail out when we get a null - - update = update.next; - } while (update !== null); // Append the captured update the end of the cloned list. - - if (newLast === null) { - newFirst = newLast = capturedUpdate; - } else { - newLast.next = capturedUpdate; - newLast = capturedUpdate; - } + if (errors !== null) { + if (errors.length > 1) { + if (typeof AggregateError === "function") { + // eslint-disable-next-line no-undef + throw new AggregateError(errors); } else { - // There are no base updates. - newFirst = newLast = capturedUpdate; - } + for (var i = 1; i < errors.length; i++) { + scheduleImmediateTask(throwError.bind(null, errors[i])); + } - queue = { - baseState: currentQueue.baseState, - firstBaseUpdate: newFirst, - lastBaseUpdate: newLast, - shared: currentQueue.shared, - callbacks: currentQueue.callbacks - }; - workInProgress.updateQueue = queue; - return; + var firstError = errors[0]; + throw firstError; + } + } else { + var error = errors[0]; + throw error; } - } // Append the update to the end of the list. - - var lastBaseUpdate = queue.lastBaseUpdate; - - if (lastBaseUpdate === null) { - queue.firstBaseUpdate = capturedUpdate; - } else { - lastBaseUpdate.next = capturedUpdate; } - - queue.lastBaseUpdate = capturedUpdate; } - function getStateFromUpdate( - workInProgress, - queue, - update, - prevState, - nextProps, - instance - ) { - switch (update.tag) { - case ReplaceState: { - var payload = update.payload; - - if (typeof payload === "function") { - // Updater function - { - enterDisallowedContextReadInDEV(); - } + function throwError(error) { + throw error; + } - var nextState = payload.call(instance, prevState, nextProps); + function processRootScheduleInMicrotask() { + // This function is always called inside a microtask. It should never be + // called synchronously. + didScheduleMicrotask = false; - { - exitDisallowedContextReadInDEV(); - } + { + didScheduleMicrotask_act = false; + } // We'll recompute this as we iterate through all the roots and schedule them. - return nextState; - } // State object + mightHavePendingSyncWork = false; + var currentTime = now$1(); + var prev = null; + var root = firstScheduledRoot; - return payload; - } + while (root !== null) { + var next = root.next; - case CaptureUpdate: { - workInProgress.flags = - (workInProgress.flags & ~ShouldCapture) | DidCapture; + if ( + currentEventTransitionLane !== NoLane && + shouldAttemptEagerTransition() + ) { + // A transition was scheduled during an event, but we're going to try to + // render it synchronously anyway. We do this during a popstate event to + // preserve the scroll position of the previous page. + upgradePendingLaneToSync(root, currentEventTransitionLane); } - // Intentional fallthrough - - case UpdateState: { - var _payload = update.payload; - var partialState; - if (typeof _payload === "function") { - // Updater function - { - enterDisallowedContextReadInDEV(); - } + var nextLanes = scheduleTaskForRootDuringMicrotask(root, currentTime); - partialState = _payload.call(instance, prevState, nextProps); + if (nextLanes === NoLane) { + // This root has no more pending work. Remove it from the schedule. To + // guard against subtle reentrancy bugs, this microtask is the only place + // we do this — you can add roots to the schedule whenever, but you can + // only remove them here. + // Null this out so we know it's been removed from the schedule. + root.next = null; - { - exitDisallowedContextReadInDEV(); - } + if (prev === null) { + // This is the new head of the list + firstScheduledRoot = next; } else { - // Partial state object - partialState = _payload; + prev.next = next; } - 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); - } + if (next === null) { + // This is the new tail of the list + lastScheduledRoot = prev; + } + } else { + // This root still has work. Keep it in the list. + prev = root; - case ForceUpdate: { - hasForceUpdate = true; - return prevState; + if (includesSyncLane(nextLanes)) { + mightHavePendingSyncWork = true; + } } - } - - return prevState; - } - - function processUpdateQueue(workInProgress, props, instance, renderLanes) { - // This is always non-null on a ClassComponent or HostRoot - var queue = workInProgress.updateQueue; - hasForceUpdate = false; - { - currentlyProcessingQueue = queue.shared; + root = next; } - var firstBaseUpdate = queue.firstBaseUpdate; - var lastBaseUpdate = queue.lastBaseUpdate; // Check if there are pending updates. If so, transfer them to the base queue. + currentEventTransitionLane = NoLane; // At the end of the microtask, flush any pending synchronous work. This has + // to come at the end, because it does actual rendering work that might throw. - var pendingQueue = queue.shared.pending; + flushSyncWorkOnAllRoots(); + } - if (pendingQueue !== null) { - queue.shared.pending = null; // The pending queue is circular. Disconnect the pointer between first - // and last so that it's non-circular. + function scheduleTaskForRootDuringMicrotask(root, currentTime) { + // This function is always called inside a microtask, or at the very end of a + // rendering task right before we yield to the main thread. It should never be + // called synchronously. + // + // TODO: Unless enableDeferRootSchedulingToMicrotask is off. We need to land + // that ASAP to unblock additional features we have planned. + // + // This function also never performs React work synchronously; it should + // only schedule work to be performed later, in a separate task or microtask. + // Check if any lanes are being starved by other work. If so, mark them as + // expired so we know to work on those next. + markStarvedLanesAsExpired(root, currentTime); // Determine the next lanes to work on, and their priority. - var lastPendingUpdate = pendingQueue; - var firstPendingUpdate = lastPendingUpdate.next; - lastPendingUpdate.next = null; // Append pending updates to base queue + var workInProgressRoot = getWorkInProgressRoot(); + var workInProgressRootRenderLanes = getWorkInProgressRootRenderLanes(); + var nextLanes = getNextLanes( + root, + root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes + ); + var existingCallbackNode = root.callbackNode; - if (lastBaseUpdate === null) { - firstBaseUpdate = firstPendingUpdate; - } else { - lastBaseUpdate.next = firstPendingUpdate; + if ( + // Check if there's nothing to work on + nextLanes === NoLanes || // If this root is currently suspended and waiting for data to resolve, don't + // schedule a task to render it. We'll either wait for a ping, or wait to + // receive an update. + // + // Suspended render phase + (root === workInProgressRoot && isWorkLoopSuspendedOnData()) || // Suspended commit phase + root.cancelPendingCommit !== null + ) { + // Fast path: There's nothing to work on. + if (existingCallbackNode !== null) { + cancelCallback(existingCallbackNode); } - lastBaseUpdate = lastPendingUpdate; // If there's a current queue, and it's different from the base queue, then - // we need to transfer the updates to that queue, too. Because the base - // queue is a singly-linked list with no cycles, we can append to both - // lists and take advantage of structural sharing. - // TODO: Pass `current` as argument + root.callbackNode = null; + root.callbackPriority = NoLane; + return NoLane; + } // Schedule a new callback in the host environment. - var current = workInProgress.alternate; + if (includesSyncLane(nextLanes)) { + // Synchronous work is always flushed at the end of the microtask, so we + // don't need to schedule an additional task. + if (existingCallbackNode !== null) { + cancelCallback(existingCallbackNode); + } - if (current !== null) { - // This is always non-null on a ClassComponent or HostRoot - var currentQueue = current.updateQueue; - var currentLastBaseUpdate = currentQueue.lastBaseUpdate; - - if (currentLastBaseUpdate !== lastBaseUpdate) { - if (currentLastBaseUpdate === null) { - currentQueue.firstBaseUpdate = firstPendingUpdate; - } else { - currentLastBaseUpdate.next = firstPendingUpdate; - } + root.callbackPriority = SyncLane; + root.callbackNode = null; + return SyncLane; + } else { + // We use the highest priority lane to represent the priority of the callback. + var existingCallbackPriority = root.callbackPriority; + var newCallbackPriority = getHighestPriorityLane(nextLanes); - currentQueue.lastBaseUpdate = lastPendingUpdate; - } + if ( + newCallbackPriority === existingCallbackPriority && // Special case related to `act`. If the currently scheduled task is a + // Scheduler task, rather than an `act` task, cancel it and re-schedule + // on the `act` queue. + !( + ReactCurrentActQueue$3.current !== null && + existingCallbackNode !== fakeActCallbackNode$1 + ) + ) { + // The priority hasn't changed. We can reuse the existing task. + return newCallbackPriority; + } else { + // Cancel the existing callback. We'll schedule a new one below. + cancelCallback(existingCallbackNode); } - } // These values may change as we process the queue. - - if (firstBaseUpdate !== null) { - // Iterate through the list of updates to compute the result. - var newState = queue.baseState; // TODO: Don't need to accumulate this. Instead, we can remove renderLanes - // from the original lanes. - - var newLanes = NoLanes; - var newBaseState = null; - var newFirstBaseUpdate = null; - var newLastBaseUpdate = null; - var update = firstBaseUpdate; - - do { - // An extra OffscreenLane bit is added to updates that were made to - // a hidden tree, so that we can distinguish them from updates that were - // already there when the tree was hidden. - var updateLane = removeLanes(update.lane, OffscreenLane); - var isHiddenUpdate = updateLane !== update.lane; // Check if this update was made while the tree was hidden. If so, then - // it's not a "base" update and we should disregard the extra base lanes - // that were added to renderLanes when we entered the Offscreen tree. - - var shouldSkipUpdate = isHiddenUpdate - ? !isSubsetOfLanes(getWorkInProgressRootRenderLanes(), updateLane) - : !isSubsetOfLanes(renderLanes, updateLane); - - if (shouldSkipUpdate) { - // Priority is insufficient. Skip this update. If this is the first - // skipped update, the previous update/state is the new base - // update/state. - var clone = { - lane: updateLane, - tag: update.tag, - payload: update.payload, - callback: update.callback, - next: null - }; - - if (newLastBaseUpdate === null) { - newFirstBaseUpdate = newLastBaseUpdate = clone; - newBaseState = newState; - } else { - newLastBaseUpdate = newLastBaseUpdate.next = clone; - } // Update the remaining priority in the queue. - - newLanes = mergeLanes(newLanes, updateLane); - } else { - // This update does have sufficient priority. - if (newLastBaseUpdate !== null) { - var _clone = { - // This update is going to be committed so we never want uncommit - // it. Using NoLane works because 0 is a subset of all bitmasks, so - // this will never be skipped by the check above. - lane: NoLane, - tag: update.tag, - payload: update.payload, - // When this update is rebased, we should not fire its - // callback again. - callback: null, - next: null - }; - newLastBaseUpdate = newLastBaseUpdate.next = _clone; - } // Process this update. - - newState = getStateFromUpdate( - workInProgress, - queue, - update, - newState, - props, - instance - ); - var callback = update.callback; - - if (callback !== null) { - workInProgress.flags |= Callback; - - if (isHiddenUpdate) { - workInProgress.flags |= Visibility; - } - - var callbacks = queue.callbacks; - if (callbacks === null) { - queue.callbacks = [callback]; - } else { - callbacks.push(callback); - } - } - } // $FlowFixMe[incompatible-type] we bail out when we get a null + var schedulerPriorityLevel; - update = update.next; + switch (lanesToEventPriority(nextLanes)) { + case DiscreteEventPriority: + schedulerPriorityLevel = ImmediatePriority; + break; - if (update === null) { - pendingQueue = queue.shared.pending; + case ContinuousEventPriority: + schedulerPriorityLevel = UserBlockingPriority; + break; - if (pendingQueue === null) { - break; - } else { - // An update was scheduled from inside a reducer. Add the new - // pending updates to the end of the list and keep processing. - var _lastPendingUpdate = pendingQueue; // Intentionally unsound. Pending updates form a circular list, but we - // unravel them when transferring them to the base queue. + case DefaultEventPriority: + schedulerPriorityLevel = NormalPriority; + break; - var _firstPendingUpdate = _lastPendingUpdate.next; - _lastPendingUpdate.next = null; - update = _firstPendingUpdate; - queue.lastBaseUpdate = _lastPendingUpdate; - queue.shared.pending = null; - } - } - } while (true); + case IdleEventPriority: + schedulerPriorityLevel = IdlePriority; + break; - if (newLastBaseUpdate === null) { - newBaseState = newState; + default: + schedulerPriorityLevel = NormalPriority; + break; } - queue.baseState = newBaseState; - queue.firstBaseUpdate = newFirstBaseUpdate; - queue.lastBaseUpdate = newLastBaseUpdate; + var newCallbackNode = scheduleCallback$1( + schedulerPriorityLevel, + performConcurrentWorkOnRoot.bind(null, root) + ); + root.callbackPriority = newCallbackPriority; + root.callbackNode = newCallbackNode; + return newCallbackPriority; + } + } - if (firstBaseUpdate === null) { - // `queue.lanes` is used for entangling transitions. We can set it back to - // zero once the queue is empty. - queue.shared.lanes = NoLanes; - } // Set the remaining expiration time to be whatever is remaining in the queue. - // This should be fine because the only two other things that contribute to - // expiration time are props and context. We're already in the middle of the - // begin phase by the time we start processing the queue, so we've already - // dealt with the props. Context in components that specify - // shouldComponentUpdate is tricky; but we'll have to account for - // that regardless. + function getContinuationForRoot(root, originalCallbackNode) { + // This is called at the end of `performConcurrentWorkOnRoot` to determine + // if we need to schedule a continuation task. + // + // Usually `scheduleTaskForRootDuringMicrotask` only runs inside a microtask; + // however, since most of the logic for determining if we need a continuation + // versus a new task is the same, we cheat a bit and call it here. This is + // only safe to do because we know we're at the end of the browser task. + // So although it's not an actual microtask, it might as well be. + scheduleTaskForRootDuringMicrotask(root, now$1()); - markSkippedUpdateLanes(newLanes); - workInProgress.lanes = newLanes; - workInProgress.memoizedState = newState; + if (root.callbackNode === originalCallbackNode) { + // The task node scheduled for this root is the same one that's + // currently executed. Need to return a continuation. + return performConcurrentWorkOnRoot.bind(null, root); } - { - currentlyProcessingQueue = null; - } + return null; } + var fakeActCallbackNode$1 = {}; - function callCallback(callback, context) { - if (typeof callback !== "function") { - throw new Error( - "Invalid argument passed as callback. Expected a function. Instead " + - ("received: " + callback) - ); + function scheduleCallback$1(priorityLevel, callback) { + if (ReactCurrentActQueue$3.current !== null) { + // Special case: We're inside an `act` scope (a testing utility). + // Instead of scheduling work in the host environment, add it to a + // fake internal queue that's managed by the `act` implementation. + ReactCurrentActQueue$3.current.push(callback); + return fakeActCallbackNode$1; + } else { + return scheduleCallback$2(priorityLevel, callback); } - - callback.call(context); } - function resetHasForceUpdateBeforeProcessing() { - hasForceUpdate = false; - } - function checkHasForceUpdateAfterProcessing() { - return hasForceUpdate; + function cancelCallback(callbackNode) { + if (callbackNode === fakeActCallbackNode$1); + else if (callbackNode !== null) { + cancelCallback$1(callbackNode); + } } - function deferHiddenCallbacks(updateQueue) { - // When an update finishes on a hidden component, its callback should not - // be fired until/unless the component is made visible again. Stash the - // callback on the shared queue object so it can be fired later. - var newHiddenCallbacks = updateQueue.callbacks; - if (newHiddenCallbacks !== null) { - var existingHiddenCallbacks = updateQueue.shared.hiddenCallbacks; + function scheduleImmediateTask(cb) { + if (ReactCurrentActQueue$3.current !== null) { + // Special case: Inside an `act` scope, we push microtasks to the fake `act` + // callback queue. This is because we currently support calling `act` + // without awaiting the result. The plan is to deprecate that, and require + // that you always await the result so that the microtasks have a chance to + // run. But it hasn't happened yet. + ReactCurrentActQueue$3.current.push(function () { + cb(); + return null; + }); + } // TODO: Can we land supportsMicrotasks? Which environments don't support it? + // Alternatively, can we move this check to the host config? - if (existingHiddenCallbacks === null) { - updateQueue.shared.hiddenCallbacks = newHiddenCallbacks; - } else { - updateQueue.shared.hiddenCallbacks = - existingHiddenCallbacks.concat(newHiddenCallbacks); - } + { + // If microtasks are not supported, use Scheduler. + scheduleCallback$2(ImmediatePriority, cb); } } - function commitHiddenCallbacks(updateQueue, context) { - // This component is switching from hidden -> visible. Commit any callbacks - // that were previously deferred. - var hiddenCallbacks = updateQueue.shared.hiddenCallbacks; - - if (hiddenCallbacks !== null) { - updateQueue.shared.hiddenCallbacks = null; - for (var i = 0; i < hiddenCallbacks.length; i++) { - var callback = hiddenCallbacks[i]; - callCallback(callback, context); - } + function requestTransitionLane( // This argument isn't used, it's only here to encourage the caller to + // check that it's inside a transition before calling this function. + // TODO: Make this non-nullable. Requires a tweak to useOptimistic. + transition + ) { + // The algorithm for assigning an update to a lane should be stable for all + // updates at the same priority within the same event. To do this, the + // inputs to the algorithm must be the same. + // + // The trick we use is to cache the first of each of these inputs within an + // event. Then reset the cached values once we can be sure the event is + // over. Our heuristic for that is whenever we enter a concurrent work loop. + if (currentEventTransitionLane === NoLane) { + // All transitions within the same event are assigned the same lane. + currentEventTransitionLane = claimNextTransitionLane(); } - } - function commitCallbacks(updateQueue, context) { - var callbacks = updateQueue.callbacks; - if (callbacks !== null) { - updateQueue.callbacks = null; - - for (var i = 0; i < callbacks.length; i++) { - var callback = callbacks[i]; - callCallback(callback, context); - } - } + return currentEventTransitionLane; } - /** - * 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 (objectIs(objA, objB)) { - return true; - } + var currentEntangledLane = NoLane; // A thenable that resolves when the entangled scope completes. It does not + // resolve to a particular value because it's only used for suspending the UI + // until the async action scope has completed. - if ( - typeof objA !== "object" || - objA === null || - typeof objB !== "object" || - objB === null - ) { - return false; - } + var currentEntangledActionThenable = null; - var keysA = Object.keys(objA); - var keysB = Object.keys(objB); + function chainThenableValue(thenable, result) { + // Equivalent to: Promise.resolve(thenable).then(() => result), except we can + // cheat a bit since we know that that this thenable is only ever consumed + // by React. + // + // We don't technically require promise support on the client yet, hence this + // extra code. + var listeners = []; + var thenableWithOverride = { + status: "pending", + value: null, + reason: null, + then: function (resolve) { + listeners.push(resolve); + } + }; + thenable.then( + function (value) { + var fulfilledThenable = thenableWithOverride; + fulfilledThenable.status = "fulfilled"; + fulfilledThenable.value = result; - if (keysA.length !== keysB.length) { - return false; - } // Test for A's keys different from B. + for (var i = 0; i < listeners.length; i++) { + var listener = listeners[i]; + listener(result); + } + }, + function (error) { + var rejectedThenable = thenableWithOverride; + rejectedThenable.status = "rejected"; + rejectedThenable.reason = error; - for (var i = 0; i < keysA.length; i++) { - var currentKey = keysA[i]; + for (var i = 0; i < listeners.length; i++) { + var listener = listeners[i]; // This is a perf hack where we call the `onFulfill` ping function + // instead of `onReject`, because we know that React is the only + // consumer of these promises, and it passes the same listener to both. + // We also know that it will read the error directly off the + // `.reason` field. - if ( - !hasOwnProperty.call(objB, currentKey) || // $FlowFixMe[incompatible-use] lost refinement of `objB` - !objectIs(objA[currentKey], objB[currentKey]) - ) { - return false; + listener(undefined); + } } - } - - return true; + ); + return thenableWithOverride; + } + function peekEntangledActionLane() { + return currentEntangledLane; + } + function peekEntangledActionThenable() { + return currentEntangledActionThenable; } - function describeFiber(fiber) { - var owner = fiber._debugOwner ? fiber._debugOwner.type : null; - var source = fiber._debugSource; + 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`. - switch (fiber.tag) { - case HostHoistable: - case HostSingleton: - case HostComponent: - return describeBuiltInComponentFrame(fiber.type, source, owner); + var hasForceUpdate = false; + var didWarnUpdateInsideUpdate; + var currentlyProcessingQueue; - case LazyComponent: - return describeBuiltInComponentFrame("Lazy", source, owner); + { + didWarnUpdateInsideUpdate = false; + currentlyProcessingQueue = null; + } - case SuspenseComponent: - return describeBuiltInComponentFrame("Suspense", source, owner); + function initializeUpdateQueue(fiber) { + var queue = { + baseState: fiber.memoizedState, + firstBaseUpdate: null, + lastBaseUpdate: null, + shared: { + pending: null, + lanes: NoLanes, + hiddenCallbacks: null + }, + callbacks: null + }; + fiber.updateQueue = queue; + } + function cloneUpdateQueue(current, workInProgress) { + // Clone the update queue from current. Unless it's already a clone. + var queue = workInProgress.updateQueue; + var currentQueue = current.updateQueue; - case SuspenseListComponent: - return describeBuiltInComponentFrame("SuspenseList", source, owner); + if (queue === currentQueue) { + var clone = { + baseState: currentQueue.baseState, + firstBaseUpdate: currentQueue.firstBaseUpdate, + lastBaseUpdate: currentQueue.lastBaseUpdate, + shared: currentQueue.shared, + callbacks: null + }; + workInProgress.updateQueue = clone; + } + } + function createUpdate(lane) { + var update = { + lane: lane, + tag: UpdateState, + payload: null, + callback: null, + next: null + }; + return update; + } + function enqueueUpdate(fiber, update, lane) { + var updateQueue = fiber.updateQueue; - case FunctionComponent: - case IndeterminateComponent: - case SimpleMemoComponent: - return describeFunctionComponentFrame(fiber.type, source, owner); + if (updateQueue === null) { + // Only occurs if the fiber has been unmounted. + return null; + } - case ForwardRef: - return describeFunctionComponentFrame( - fiber.type.render, - source, - owner - ); + var sharedQueue = updateQueue.shared; - case ClassComponent: - return describeClassComponentFrame(fiber.type, source, owner); + { + if ( + currentlyProcessingQueue === sharedQueue && + !didWarnUpdateInsideUpdate + ) { + var componentName = getComponentNameFromFiber(fiber); - default: - return ""; + error( + "An update (setState, replaceState, or forceUpdate) was scheduled " + + "from inside an update function. Update functions should be pure, " + + "with zero side-effects. Consider using componentDidUpdate or a " + + "callback.\n\nPlease update the following component: %s", + componentName + ); + + didWarnUpdateInsideUpdate = true; + } } - } - function getStackByFiberInDevAndProd(workInProgress) { - try { - var info = ""; - var node = workInProgress; + if (isUnsafeClassRenderPhaseUpdate()) { + // This is an unsafe render phase update. Add directly to the update + // queue so we can process it immediately during the current render. + var pending = sharedQueue.pending; - do { - info += describeFiber(node); // $FlowFixMe[incompatible-type] we bail out when we get a null + if (pending === null) { + // This is the first update. Create a circular list. + update.next = update; + } else { + update.next = pending.next; + pending.next = update; + } - node = node.return; - } while (node); + sharedQueue.pending = update; // Update the childLanes even though we're most likely already rendering + // this fiber. This is for backwards compatibility in the case where you + // update a different component during render phase than the one that is + // currently renderings (a pattern that is accompanied by a warning). - return info; - } catch (x) { - return "\nError generating stack: " + x.message + "\n" + x.stack; + return unsafe_markUpdateLaneFromFiberToRoot(fiber, lane); + } else { + return enqueueConcurrentClassUpdate(fiber, sharedQueue, update, lane); } } + function entangleTransitions(root, fiber, lane) { + var updateQueue = fiber.updateQueue; - var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; - var current = null; - var isRendering = false; - function getCurrentFiberOwnerNameInDevOrNull() { - { - if (current === null) { - return null; - } + if (updateQueue === null) { + // Only occurs if the fiber has been unmounted. + return; + } - var owner = current._debugOwner; + var sharedQueue = updateQueue.shared; - if (owner !== null && typeof owner !== "undefined") { - return getComponentNameFromFiber(owner); - } - } + if (isTransitionLane(lane)) { + var queueLanes = sharedQueue.lanes; // If any entangled lanes are no longer pending on the root, then they must + // have finished. We can remove them from the shared queue, which represents + // a superset of the actually pending lanes. In some cases we may entangle + // more than we need to, but that's OK. In fact it's worse if we *don't* + // entangle when we should. - return null; - } + queueLanes = intersectLanes(queueLanes, root.pendingLanes); // Entangle the new transition lane with the other transition lanes. - function getCurrentFiberStackInDev() { - { - if (current === null) { - return ""; - } // Safe because if current fiber exists, we are reconciling, - // and it is guaranteed to be the work-in-progress version. + var newQueueLanes = mergeLanes(queueLanes, lane); + sharedQueue.lanes = newQueueLanes; // Even if queue.lanes already include lane, we don't know for certain if + // the lane finished since the last time we entangled it. So we need to + // entangle it again, just to be sure. - return getStackByFiberInDevAndProd(current); + markRootEntangled(root, newQueueLanes); } } + function enqueueCapturedUpdate(workInProgress, capturedUpdate) { + // Captured updates are updates that are thrown by a child during the render + // phase. They should be discarded if the render is aborted. Therefore, + // we should only put them on the work-in-progress queue, not the current one. + var queue = workInProgress.updateQueue; // Check if the work-in-progress queue is a clone. - function resetCurrentFiber() { - { - ReactDebugCurrentFrame.getCurrentStack = null; - current = null; - isRendering = false; - } - } - function setCurrentFiber(fiber) { - { - ReactDebugCurrentFrame.getCurrentStack = - fiber === null ? null : getCurrentFiberStackInDev; - current = fiber; - isRendering = false; - } - } - function getCurrentFiber() { - { - return current; - } - } - function setIsRendering(rendering) { - { - isRendering = rendering; - } - } + var current = workInProgress.alternate; - var ReactStrictModeWarnings = { - recordUnsafeLifecycleWarnings: function (fiber, instance) {}, - flushPendingUnsafeLifecycleWarnings: function () {}, - recordLegacyContextWarning: function (fiber, instance) {}, - flushLegacyContextWarning: function () {}, - discardPendingWarnings: function () {} - }; + if (current !== null) { + var currentQueue = current.updateQueue; - { - var findStrictRoot = function (fiber) { - var maybeStrictRoot = null; - var node = fiber; + if (queue === currentQueue) { + // The work-in-progress queue is the same as current. This happens when + // we bail out on a parent fiber that then captures an error thrown by + // a child. Since we want to append the update only to the work-in + // -progress queue, we need to clone the updates. We usually clone during + // processUpdateQueue, but that didn't happen in this case because we + // skipped over the parent when we bailed out. + var newFirst = null; + var newLast = null; + var firstBaseUpdate = queue.firstBaseUpdate; - while (node !== null) { - if (node.mode & StrictLegacyMode) { - maybeStrictRoot = node; + if (firstBaseUpdate !== null) { + // Loop through the updates and clone them. + var update = firstBaseUpdate; + + do { + var clone = { + lane: update.lane, + tag: update.tag, + payload: update.payload, + // When this update is rebased, we should not fire its + // callback again. + callback: null, + next: null + }; + + if (newLast === null) { + newFirst = newLast = clone; + } else { + newLast.next = clone; + newLast = clone; + } // $FlowFixMe[incompatible-type] we bail out when we get a null + + update = update.next; + } while (update !== null); // Append the captured update the end of the cloned list. + + if (newLast === null) { + newFirst = newLast = capturedUpdate; + } else { + newLast.next = capturedUpdate; + newLast = capturedUpdate; + } + } else { + // There are no base updates. + newFirst = newLast = capturedUpdate; } - node = node.return; + queue = { + baseState: currentQueue.baseState, + firstBaseUpdate: newFirst, + lastBaseUpdate: newLast, + shared: currentQueue.shared, + callbacks: currentQueue.callbacks + }; + workInProgress.updateQueue = queue; + return; } + } // Append the update to the end of the list. - return maybeStrictRoot; - }; + var lastBaseUpdate = queue.lastBaseUpdate; - var setToSortedString = function (set) { - var array = []; - set.forEach(function (value) { - array.push(value); - }); - return array.sort().join(", "); - }; + if (lastBaseUpdate === null) { + queue.firstBaseUpdate = capturedUpdate; + } else { + lastBaseUpdate.next = capturedUpdate; + } - var pendingComponentWillMountWarnings = []; - var pendingUNSAFE_ComponentWillMountWarnings = []; - var pendingComponentWillReceivePropsWarnings = []; - var pendingUNSAFE_ComponentWillReceivePropsWarnings = []; - var pendingComponentWillUpdateWarnings = []; - var pendingUNSAFE_ComponentWillUpdateWarnings = []; // Tracks components we have already warned about. + queue.lastBaseUpdate = capturedUpdate; + } - var didWarnAboutUnsafeLifecycles = new Set(); + function getStateFromUpdate( + workInProgress, + queue, + update, + prevState, + nextProps, + instance + ) { + switch (update.tag) { + case ReplaceState: { + var payload = update.payload; - ReactStrictModeWarnings.recordUnsafeLifecycleWarnings = function ( - fiber, - instance - ) { - // Dedupe strategy: Warn once per component. - if (didWarnAboutUnsafeLifecycles.has(fiber.type)) { - return; - } + if (typeof payload === "function") { + // Updater function + { + enterDisallowedContextReadInDEV(); + } - if ( - typeof instance.componentWillMount === "function" && // Don't warn about react-lifecycles-compat polyfilled components. - instance.componentWillMount.__suppressDeprecationWarning !== true - ) { - pendingComponentWillMountWarnings.push(fiber); - } + var nextState = payload.call(instance, prevState, nextProps); - if ( - fiber.mode & StrictLegacyMode && - typeof instance.UNSAFE_componentWillMount === "function" - ) { - pendingUNSAFE_ComponentWillMountWarnings.push(fiber); - } + { + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); - if ( - typeof instance.componentWillReceiveProps === "function" && - instance.componentWillReceiveProps.__suppressDeprecationWarning !== - true - ) { - pendingComponentWillReceivePropsWarnings.push(fiber); - } + try { + payload.call(instance, prevState, nextProps); + } finally { + setIsStrictModeForDevtools(false); + } + } - if ( - fiber.mode & StrictLegacyMode && - typeof instance.UNSAFE_componentWillReceiveProps === "function" - ) { - pendingUNSAFE_ComponentWillReceivePropsWarnings.push(fiber); - } + exitDisallowedContextReadInDEV(); + } - if ( - typeof instance.componentWillUpdate === "function" && - instance.componentWillUpdate.__suppressDeprecationWarning !== true - ) { - pendingComponentWillUpdateWarnings.push(fiber); + return nextState; + } // State object + + return payload; } - if ( - fiber.mode & StrictLegacyMode && - typeof instance.UNSAFE_componentWillUpdate === "function" - ) { - pendingUNSAFE_ComponentWillUpdateWarnings.push(fiber); + case CaptureUpdate: { + workInProgress.flags = + (workInProgress.flags & ~ShouldCapture) | DidCapture; } - }; + // Intentional fallthrough - ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = - function () { - // We do an initial pass to gather component names - var componentWillMountUniqueNames = new Set(); + case UpdateState: { + var _payload = update.payload; + var partialState; - if (pendingComponentWillMountWarnings.length > 0) { - pendingComponentWillMountWarnings.forEach(function (fiber) { - componentWillMountUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingComponentWillMountWarnings = []; - } + if (typeof _payload === "function") { + // Updater function + { + enterDisallowedContextReadInDEV(); + } - var UNSAFE_componentWillMountUniqueNames = new Set(); + partialState = _payload.call(instance, prevState, nextProps); - if (pendingUNSAFE_ComponentWillMountWarnings.length > 0) { - pendingUNSAFE_ComponentWillMountWarnings.forEach(function (fiber) { - UNSAFE_componentWillMountUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingUNSAFE_ComponentWillMountWarnings = []; - } + { + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); - var componentWillReceivePropsUniqueNames = new Set(); + try { + _payload.call(instance, prevState, nextProps); + } finally { + setIsStrictModeForDevtools(false); + } + } - if (pendingComponentWillReceivePropsWarnings.length > 0) { - pendingComponentWillReceivePropsWarnings.forEach(function (fiber) { - componentWillReceivePropsUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingComponentWillReceivePropsWarnings = []; + exitDisallowedContextReadInDEV(); + } + } else { + // Partial state object + partialState = _payload; } - var UNSAFE_componentWillReceivePropsUniqueNames = new Set(); + if (partialState === null || partialState === undefined) { + // Null and undefined are treated as no-ops. + return prevState; + } // Merge the partial state and the previous state. - if (pendingUNSAFE_ComponentWillReceivePropsWarnings.length > 0) { - pendingUNSAFE_ComponentWillReceivePropsWarnings.forEach( - function (fiber) { - UNSAFE_componentWillReceivePropsUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - } - ); - pendingUNSAFE_ComponentWillReceivePropsWarnings = []; - } + return assign({}, prevState, partialState); + } - var componentWillUpdateUniqueNames = new Set(); + case ForceUpdate: { + hasForceUpdate = true; + return prevState; + } + } - if (pendingComponentWillUpdateWarnings.length > 0) { - pendingComponentWillUpdateWarnings.forEach(function (fiber) { - componentWillUpdateUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingComponentWillUpdateWarnings = []; - } + return prevState; + } - var UNSAFE_componentWillUpdateUniqueNames = new Set(); + var didReadFromEntangledAsyncAction = false; // Each call to processUpdateQueue should be accompanied by a call to this. It's + // only in a separate function because in updateHostRoot, it must happen after + // all the context stacks have been pushed to, to prevent a stack mismatch. A + // bit unfortunate. - if (pendingUNSAFE_ComponentWillUpdateWarnings.length > 0) { - pendingUNSAFE_ComponentWillUpdateWarnings.forEach(function (fiber) { - UNSAFE_componentWillUpdateUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingUNSAFE_ComponentWillUpdateWarnings = []; - } // Finally, we flush all the warnings - // UNSAFE_ ones before the deprecated ones, since they'll be 'louder' + function suspendIfUpdateReadFromEntangledAsyncAction() { + // Check if this update is part of a pending async action. If so, we'll + // need to suspend until the action has finished, so that it's batched + // together with future updates in the same action. + // TODO: Once we support hooks inside useMemo (or an equivalent + // memoization boundary like Forget), hoist this logic so that it only + // suspends if the memo boundary produces a new value. + if (didReadFromEntangledAsyncAction) { + var entangledActionThenable = peekEntangledActionThenable(); - if (UNSAFE_componentWillMountUniqueNames.size > 0) { - var sortedNames = setToSortedString( - UNSAFE_componentWillMountUniqueNames - ); + if (entangledActionThenable !== null) { + // TODO: Instead of the throwing the thenable directly, throw a + // special object like `use` does so we can detect if it's captured + // by userspace. + throw entangledActionThenable; + } + } + } + function processUpdateQueue(workInProgress, props, instance, renderLanes) { + didReadFromEntangledAsyncAction = false; // This is always non-null on a ClassComponent or HostRoot - error( - "Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code. " + - "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + - "* Move code with side effects to componentDidMount, and set initial state in the constructor.\n" + - "\nPlease update the following components: %s", - sortedNames - ); - } + var queue = workInProgress.updateQueue; + hasForceUpdate = false; - if (UNSAFE_componentWillReceivePropsUniqueNames.size > 0) { - var _sortedNames = setToSortedString( - UNSAFE_componentWillReceivePropsUniqueNames - ); + { + currentlyProcessingQueue = queue.shared; + } - error( - "Using UNSAFE_componentWillReceiveProps in strict mode is not recommended " + - "and may indicate bugs in your code. " + - "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + - "* Move data fetching code or side effects to componentDidUpdate.\n" + - "* If you're updating state whenever props change, " + - "refactor your code to use memoization techniques or move it to " + - "static getDerivedStateFromProps. Learn more at: https://reactjs.org/link/derived-state\n" + - "\nPlease update the following components: %s", - _sortedNames - ); - } + var firstBaseUpdate = queue.firstBaseUpdate; + var lastBaseUpdate = queue.lastBaseUpdate; // Check if there are pending updates. If so, transfer them to the base queue. - if (UNSAFE_componentWillUpdateUniqueNames.size > 0) { - var _sortedNames2 = setToSortedString( - UNSAFE_componentWillUpdateUniqueNames - ); + var pendingQueue = queue.shared.pending; - error( - "Using UNSAFE_componentWillUpdate in strict mode is not recommended " + - "and may indicate bugs in your code. " + - "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + - "* Move data fetching code or side effects to componentDidUpdate.\n" + - "\nPlease update the following components: %s", - _sortedNames2 - ); - } + if (pendingQueue !== null) { + queue.shared.pending = null; // The pending queue is circular. Disconnect the pointer between first + // and last so that it's non-circular. - if (componentWillMountUniqueNames.size > 0) { - var _sortedNames3 = setToSortedString( - componentWillMountUniqueNames - ); + var lastPendingUpdate = pendingQueue; + var firstPendingUpdate = lastPendingUpdate.next; + lastPendingUpdate.next = null; // Append pending updates to base queue - warn( - "componentWillMount has been renamed, and is not recommended for use. " + - "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + - "* Move code with side effects to componentDidMount, and set initial state in the constructor.\n" + - "* Rename componentWillMount to UNSAFE_componentWillMount to suppress " + - "this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. " + - "To rename all deprecated lifecycles to their new names, you can run " + - "`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n" + - "\nPlease update the following components: %s", - _sortedNames3 - ); - } + if (lastBaseUpdate === null) { + firstBaseUpdate = firstPendingUpdate; + } else { + lastBaseUpdate.next = firstPendingUpdate; + } - if (componentWillReceivePropsUniqueNames.size > 0) { - var _sortedNames4 = setToSortedString( - componentWillReceivePropsUniqueNames - ); + lastBaseUpdate = lastPendingUpdate; // If there's a current queue, and it's different from the base queue, then + // we need to transfer the updates to that queue, too. Because the base + // queue is a singly-linked list with no cycles, we can append to both + // lists and take advantage of structural sharing. + // TODO: Pass `current` as argument - warn( - "componentWillReceiveProps has been renamed, and is not recommended for use. " + - "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + - "* Move data fetching code or side effects to componentDidUpdate.\n" + - "* If you're updating state whenever props change, refactor your " + - "code to use memoization techniques or move it to " + - "static getDerivedStateFromProps. Learn more at: https://reactjs.org/link/derived-state\n" + - "* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress " + - "this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. " + - "To rename all deprecated lifecycles to their new names, you can run " + - "`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n" + - "\nPlease update the following components: %s", - _sortedNames4 - ); - } + var current = workInProgress.alternate; - if (componentWillUpdateUniqueNames.size > 0) { - var _sortedNames5 = setToSortedString( - componentWillUpdateUniqueNames - ); + if (current !== null) { + // This is always non-null on a ClassComponent or HostRoot + var currentQueue = current.updateQueue; + var currentLastBaseUpdate = currentQueue.lastBaseUpdate; - warn( - "componentWillUpdate has been renamed, and is not recommended for use. " + - "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + - "* Move data fetching code or side effects to componentDidUpdate.\n" + - "* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress " + - "this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. " + - "To rename all deprecated lifecycles to their new names, you can run " + - "`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n" + - "\nPlease update the following components: %s", - _sortedNames5 - ); + if (currentLastBaseUpdate !== lastBaseUpdate) { + if (currentLastBaseUpdate === null) { + currentQueue.firstBaseUpdate = firstPendingUpdate; + } else { + currentLastBaseUpdate.next = firstPendingUpdate; + } + + currentQueue.lastBaseUpdate = lastPendingUpdate; } - }; + } + } // These values may change as we process the queue. - var pendingLegacyContextWarning = new Map(); // Tracks components we have already warned about. + if (firstBaseUpdate !== null) { + // Iterate through the list of updates to compute the result. + var newState = queue.baseState; // TODO: Don't need to accumulate this. Instead, we can remove renderLanes + // from the original lanes. - var didWarnAboutLegacyContext = new Set(); + var newLanes = NoLanes; + var newBaseState = null; + var newFirstBaseUpdate = null; + var newLastBaseUpdate = null; + var update = firstBaseUpdate; - ReactStrictModeWarnings.recordLegacyContextWarning = function ( - fiber, - instance - ) { - var strictRoot = findStrictRoot(fiber); + do { + // An extra OffscreenLane bit is added to updates that were made to + // a hidden tree, so that we can distinguish them from updates that were + // already there when the tree was hidden. + var updateLane = removeLanes(update.lane, OffscreenLane); + var isHiddenUpdate = updateLane !== update.lane; // Check if this update was made while the tree was hidden. If so, then + // it's not a "base" update and we should disregard the extra base lanes + // that were added to renderLanes when we entered the Offscreen tree. - if (strictRoot === null) { - error( - "Expected to find a StrictMode component in a strict mode tree. " + - "This error is likely caused by a bug in React. Please file an issue." - ); + var shouldSkipUpdate = isHiddenUpdate + ? !isSubsetOfLanes(getWorkInProgressRootRenderLanes(), updateLane) + : !isSubsetOfLanes(renderLanes, updateLane); - return; - } // Dedup strategy: Warn once per component. + if (shouldSkipUpdate) { + // Priority is insufficient. Skip this update. If this is the first + // skipped update, the previous update/state is the new base + // update/state. + var clone = { + lane: updateLane, + tag: update.tag, + payload: update.payload, + callback: update.callback, + next: null + }; - if (didWarnAboutLegacyContext.has(fiber.type)) { - return; - } + if (newLastBaseUpdate === null) { + newFirstBaseUpdate = newLastBaseUpdate = clone; + newBaseState = newState; + } else { + newLastBaseUpdate = newLastBaseUpdate.next = clone; + } // Update the remaining priority in the queue. - var warningsForRoot = pendingLegacyContextWarning.get(strictRoot); + newLanes = mergeLanes(newLanes, updateLane); + } else { + // This update does have sufficient priority. + // Check if this update is part of a pending async action. If so, + // we'll need to suspend until the action has finished, so that it's + // batched together with future updates in the same action. + if ( + updateLane !== NoLane && + updateLane === peekEntangledActionLane() + ) { + didReadFromEntangledAsyncAction = true; + } - if ( - fiber.type.contextTypes != null || - fiber.type.childContextTypes != null || - (instance !== null && typeof instance.getChildContext === "function") - ) { - if (warningsForRoot === undefined) { - warningsForRoot = []; - pendingLegacyContextWarning.set(strictRoot, warningsForRoot); - } + if (newLastBaseUpdate !== null) { + var _clone = { + // This update is going to be committed so we never want uncommit + // it. Using NoLane works because 0 is a subset of all bitmasks, so + // this will never be skipped by the check above. + lane: NoLane, + tag: update.tag, + payload: update.payload, + // When this update is rebased, we should not fire its + // callback again. + callback: null, + next: null + }; + newLastBaseUpdate = newLastBaseUpdate.next = _clone; + } // Process this update. - warningsForRoot.push(fiber); - } - }; + newState = getStateFromUpdate( + workInProgress, + queue, + update, + newState, + props, + instance + ); + var callback = update.callback; - ReactStrictModeWarnings.flushLegacyContextWarning = function () { - pendingLegacyContextWarning.forEach(function (fiberArray, strictRoot) { - if (fiberArray.length === 0) { - return; - } + if (callback !== null) { + workInProgress.flags |= Callback; - var firstFiber = fiberArray[0]; - var uniqueNames = new Set(); - fiberArray.forEach(function (fiber) { - uniqueNames.add(getComponentNameFromFiber(fiber) || "Component"); - didWarnAboutLegacyContext.add(fiber.type); - }); - var sortedNames = setToSortedString(uniqueNames); + if (isHiddenUpdate) { + workInProgress.flags |= Visibility; + } - try { - setCurrentFiber(firstFiber); + var callbacks = queue.callbacks; - error( - "Legacy context API has been detected within a strict-mode tree." + - "\n\nThe old API will be supported in all 16.x releases, but applications " + - "using it should migrate to the new version." + - "\n\nPlease update the following components: %s" + - "\n\nLearn more about this warning here: https://reactjs.org/link/legacy-context", - sortedNames - ); - } finally { - resetCurrentFiber(); + if (callbacks === null) { + queue.callbacks = [callback]; + } else { + callbacks.push(callback); + } + } + } // $FlowFixMe[incompatible-type] we bail out when we get a null + + update = update.next; + + if (update === null) { + pendingQueue = queue.shared.pending; + + if (pendingQueue === null) { + break; + } else { + // An update was scheduled from inside a reducer. Add the new + // pending updates to the end of the list and keep processing. + var _lastPendingUpdate = pendingQueue; // Intentionally unsound. Pending updates form a circular list, but we + // unravel them when transferring them to the base queue. + + var _firstPendingUpdate = _lastPendingUpdate.next; + _lastPendingUpdate.next = null; + update = _firstPendingUpdate; + queue.lastBaseUpdate = _lastPendingUpdate; + queue.shared.pending = null; + } } - }); - }; + } while (true); - ReactStrictModeWarnings.discardPendingWarnings = function () { - pendingComponentWillMountWarnings = []; - pendingUNSAFE_ComponentWillMountWarnings = []; - pendingComponentWillReceivePropsWarnings = []; - pendingUNSAFE_ComponentWillReceivePropsWarnings = []; - pendingComponentWillUpdateWarnings = []; - pendingUNSAFE_ComponentWillUpdateWarnings = []; - pendingLegacyContextWarning = new Map(); - }; - } + if (newLastBaseUpdate === null) { + newBaseState = newState; + } - /* - * The `'' + value` pattern (used in perf-sensitive code) throws for Symbol - * and Temporal.* types. See https://github.com/facebook/react/pull/22064. - * - * The functions in this module will throw an easier-to-understand, - * easier-to-debug exception with a clear errors message message explaining the - * problem. (Instead of a confusing exception thrown inside the implementation - * of the `value` object). - */ - // $FlowFixMe[incompatible-return] only called in DEV, so void return is not possible. - function typeName(value) { - { - // toStringTag is needed for namespaced types like Temporal.Instant - var hasToStringTag = typeof Symbol === "function" && Symbol.toStringTag; - var type = - (hasToStringTag && value[Symbol.toStringTag]) || - value.constructor.name || - "Object"; // $FlowFixMe[incompatible-return] + queue.baseState = newBaseState; + queue.firstBaseUpdate = newFirstBaseUpdate; + queue.lastBaseUpdate = newLastBaseUpdate; - return type; + if (firstBaseUpdate === null) { + // `queue.lanes` is used for entangling transitions. We can set it back to + // zero once the queue is empty. + queue.shared.lanes = NoLanes; + } // Set the remaining expiration time to be whatever is remaining in the queue. + // This should be fine because the only two other things that contribute to + // expiration time are props and context. We're already in the middle of the + // begin phase by the time we start processing the queue, so we've already + // dealt with the props. Context in components that specify + // shouldComponentUpdate is tricky; but we'll have to account for + // that regardless. + + markSkippedUpdateLanes(newLanes); + workInProgress.lanes = newLanes; + workInProgress.memoizedState = newState; } - } // $FlowFixMe[incompatible-return] only called in DEV, so void return is not possible. - function willCoercionThrow(value) { { - try { - testStringCoercion(value); - return false; - } catch (e) { - return true; - } + currentlyProcessingQueue = null; } } - function testStringCoercion(value) { - // If you ended up here by following an exception call stack, here's what's - // happened: you supplied an object or symbol value to React (as a prop, key, - // DOM attribute, CSS property, string ref, etc.) and when React tried to - // coerce it to a string using `'' + value`, an exception was thrown. - // - // The most common types that will cause this exception are `Symbol` instances - // and Temporal objects like `Temporal.Instant`. But any object that has a - // `valueOf` or `[Symbol.toPrimitive]` method that throws will also cause this - // exception. (Library authors do this to prevent users from using built-in - // numeric operators like `+` or comparison operators like `>=` because custom - // methods are needed to perform accurate arithmetic or comparison.) - // - // To fix the problem, coerce this object or symbol value to a string before - // passing it to React. The most reliable way is usually `String(value)`. - // - // To find which value is throwing, check the browser or debugger console. - // Before this exception was thrown, there should be `console.error` output - // that shows the type (Symbol, Temporal.PlainDate, etc.) that caused the - // problem and how that type was used: key, atrribute, input value prop, etc. - // In most cases, this console output also shows the component and its - // ancestor components where the exception happened. - // - // eslint-disable-next-line react-internal/safe-string-coercion - return "" + value; + function callCallback(callback, context) { + if (typeof callback !== "function") { + throw new Error( + "Invalid argument passed as callback. Expected a function. Instead " + + ("received: " + callback) + ); + } + + callback.call(context); } - function checkKeyStringCoercion(value) { - { - if (willCoercionThrow(value)) { - error( - "The provided key is an unsupported type %s." + - " This value must be coerced to a string before using it here.", - typeName(value) - ); - return testStringCoercion(value); // throw (to help callers find troubleshooting comments) - } - } + function resetHasForceUpdateBeforeProcessing() { + hasForceUpdate = false; } - function checkPropStringCoercion(value, propName) { - { - if (willCoercionThrow(value)) { - error( - "The provided `%s` prop is an unsupported type %s." + - " This value must be coerced to a string before using it here.", - propName, - typeName(value) - ); + function checkHasForceUpdateAfterProcessing() { + return hasForceUpdate; + } + function deferHiddenCallbacks(updateQueue) { + // When an update finishes on a hidden component, its callback should not + // be fired until/unless the component is made visible again. Stash the + // callback on the shared queue object so it can be fired later. + var newHiddenCallbacks = updateQueue.callbacks; - return testStringCoercion(value); // throw (to help callers find troubleshooting comments) + if (newHiddenCallbacks !== null) { + var existingHiddenCallbacks = updateQueue.shared.hiddenCallbacks; + + if (existingHiddenCallbacks === null) { + updateQueue.shared.hiddenCallbacks = newHiddenCallbacks; + } else { + updateQueue.shared.hiddenCallbacks = + existingHiddenCallbacks.concat(newHiddenCallbacks); } } } + function commitHiddenCallbacks(updateQueue, context) { + // This component is switching from hidden -> visible. Commit any callbacks + // that were previously deferred. + var hiddenCallbacks = updateQueue.shared.hiddenCallbacks; - var ReactCurrentActQueue$3 = ReactSharedInternals.ReactCurrentActQueue; // An error that is thrown (e.g. by `use`) to trigger Suspense. If we - // detect this is caught by userspace, we'll log a warning in development. - - var SuspenseException = new Error( - "Suspense Exception: This is not a real error! It's an implementation " + - "detail of `use` to interrupt the current render. You must either " + - "rethrow it immediately, or move the `use` call outside of the " + - "`try/catch` block. Capturing without rethrowing will lead to " + - "unexpected behavior.\n\n" + - "To handle async errors, wrap your component in an error boundary, or " + - "call the promise's `.catch` method and pass the result to `use`" - ); - var SuspenseyCommitException = new Error( - "Suspense Exception: This is not a real error, and should not leak into " + - "userspace. If you're seeing this, it's likely a bug in React." - ); // This is a noop thenable that we use to trigger a fallback in throwException. - // TODO: It would be better to refactor throwException into multiple functions - // so we can trigger a fallback directly without having to check the type. But - // for now this will do. + if (hiddenCallbacks !== null) { + updateQueue.shared.hiddenCallbacks = null; - var noopSuspenseyCommitThenable = { - then: function () { - { - error( - "Internal React error: A listener was unexpectedly attached to a " + - '"noop" thenable. This is a bug in React. Please file an issue.' - ); + for (var i = 0; i < hiddenCallbacks.length; i++) { + var callback = hiddenCallbacks[i]; + callCallback(callback, context); } } - }; - function createThenableState() { - // The ThenableState is created the first time a component suspends. If it - // suspends again, we'll reuse the same state. - return []; - } - function isThenableResolved(thenable) { - var status = thenable.status; - return status === "fulfilled" || status === "rejected"; } + function commitCallbacks(updateQueue, context) { + var callbacks = updateQueue.callbacks; - function noop() {} + if (callbacks !== null) { + updateQueue.callbacks = null; - function trackUsedThenable(thenableState, thenable, index) { - if (ReactCurrentActQueue$3.current !== null) { - ReactCurrentActQueue$3.didUsePromise = true; + for (var i = 0; i < callbacks.length; i++) { + var callback = callbacks[i]; + callCallback(callback, context); + } } + } - var previous = thenableState[index]; - - if (previous === undefined) { - thenableState.push(thenable); - } else { - if (previous !== thenable) { - // Reuse the previous thenable, and drop the new one. We can assume - // they represent the same value, because components are idempotent. - // Avoid an unhandled rejection errors for the Promises that we'll - // intentionally ignore. - thenable.then(noop, noop); - thenable = previous; - } - } // We use an expando to track the status and result of a thenable so that we - // can synchronously unwrap the value. Think of this as an extension of the - // Promise API, or a custom interface that is a superset of Thenable. - // - // If the thenable doesn't have a status, set it to "pending" and attach - // a listener that will update its status and result when it resolves. + /** + * 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. + */ - switch (thenable.status) { - case "fulfilled": { - var fulfilledValue = thenable.value; - return fulfilledValue; - } + function shallowEqual(objA, objB) { + if (objectIs(objA, objB)) { + return true; + } - case "rejected": { - var rejectedError = thenable.reason; - checkIfUseWrappedInAsyncCatch(rejectedError); - throw rejectedError; + 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++) { + var currentKey = keysA[i]; + + if ( + !hasOwnProperty.call(objB, currentKey) || // $FlowFixMe[incompatible-use] lost refinement of `objB` + !objectIs(objA[currentKey], objB[currentKey]) + ) { + return false; } + } - default: { - if (typeof thenable.status === "string") { - // Only instrument the thenable if the status if not defined. If - // it's defined, but an unknown value, assume it's been instrumented by - // some custom userspace implementation. We treat it as "pending". - // Attach a dummy listener, to ensure that any lazy initialization can - // happen. Flight lazily parses JSON when the value is actually awaited. - thenable.then(noop, noop); - } else { - // This is an uncached thenable that we haven't seen before. - // Detect infinite ping loops caused by uncached promises. - var root = getWorkInProgressRoot(); + return true; + } - if (root !== null && root.shellSuspendCounter > 100) { - // This root has suspended repeatedly in the shell without making any - // progress (i.e. committing something). This is highly suggestive of - // an infinite ping loop, often caused by an accidental Async Client - // Component. - // - // During a transition, we can suspend the work loop until the promise - // to resolve, but this is a sync render, so that's not an option. We - // also can't show a fallback, because none was provided. So our last - // resort is to throw an error. - // - // TODO: Remove this error in a future release. Other ways of handling - // this case include forcing a concurrent render, or putting the whole - // root into offscreen mode. - throw new Error( - "async/await is not yet supported in Client Components, only " + - "Server Components. This error is often caused by accidentally " + - "adding `'use client'` to a module that was originally written " + - "for the server." - ); - } + function describeFiber(fiber) { + var owner = fiber._debugOwner ? fiber._debugOwner.type : null; - var pendingThenable = thenable; - pendingThenable.status = "pending"; - pendingThenable.then( - function (fulfilledValue) { - if (thenable.status === "pending") { - var fulfilledThenable = thenable; - fulfilledThenable.status = "fulfilled"; - fulfilledThenable.value = fulfilledValue; - } - }, - function (error) { - if (thenable.status === "pending") { - var rejectedThenable = thenable; - rejectedThenable.status = "rejected"; - rejectedThenable.reason = error; - } - } - ); // Check one more time in case the thenable resolved synchronously. + switch (fiber.tag) { + case HostHoistable: + case HostSingleton: + case HostComponent: + return describeBuiltInComponentFrame(fiber.type, owner); - switch (thenable.status) { - case "fulfilled": { - var fulfilledThenable = thenable; - return fulfilledThenable.value; - } + case LazyComponent: + return describeBuiltInComponentFrame("Lazy", owner); - case "rejected": { - var rejectedThenable = thenable; - var _rejectedError = rejectedThenable.reason; - checkIfUseWrappedInAsyncCatch(_rejectedError); - throw _rejectedError; - } - } - } // Suspend. - // - // Throwing here is an implementation detail that allows us to unwind the - // call stack. But we shouldn't allow it to leak into userspace. Throw an - // opaque placeholder value instead of the actual thenable. If it doesn't - // get captured by the work loop, log a warning, because that means - // something in userspace must have caught it. + case SuspenseComponent: + return describeBuiltInComponentFrame("Suspense", owner); - suspendedThenable = thenable; + case SuspenseListComponent: + return describeBuiltInComponentFrame("SuspenseList", owner); - { - needsToResetSuspendedThenableDEV = true; - } + case FunctionComponent: + case IndeterminateComponent: + case SimpleMemoComponent: + return describeFunctionComponentFrame(fiber.type, owner); - throw SuspenseException; - } + case ForwardRef: + return describeFunctionComponentFrame(fiber.type.render, owner); + + case ClassComponent: + return describeClassComponentFrame(fiber.type, owner); + + default: + return ""; } } - // passed to the rest of the Suspense implementation — which, for historical - // reasons, expects to receive a thenable. - var suspendedThenable = null; - var needsToResetSuspendedThenableDEV = false; - function getSuspendedThenable() { - // This is called right after `use` suspends by throwing an exception. `use` - // throws an opaque value instead of the thenable itself so that it can't be - // caught in userspace. Then the work loop accesses the actual thenable using - // this function. - if (suspendedThenable === null) { - throw new Error( - "Expected a suspended thenable. This is a bug in React. Please file " + - "an issue." - ); - } + function getStackByFiberInDevAndProd(workInProgress) { + try { + var info = ""; + var node = workInProgress; - var thenable = suspendedThenable; - suspendedThenable = null; + do { + info += describeFiber(node); // $FlowFixMe[incompatible-type] we bail out when we get a null + + node = node.return; + } while (node); + + return info; + } catch (x) { + return "\nError generating stack: " + x.message + "\n" + x.stack; + } + } + var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; + var current = null; + var isRendering = false; + function getCurrentFiberOwnerNameInDevOrNull() { { - needsToResetSuspendedThenableDEV = false; + if (current === null) { + return null; + } + + var owner = current._debugOwner; + + if (owner !== null && typeof owner !== "undefined") { + return getComponentNameFromFiber(owner); + } } - return thenable; + return null; } - function checkIfUseWrappedInTryCatch() { + + function getCurrentFiberStackInDev() { { - // This was set right before SuspenseException was thrown, and it should - // have been cleared when the exception was handled. If it wasn't, - // it must have been caught by userspace. - if (needsToResetSuspendedThenableDEV) { - needsToResetSuspendedThenableDEV = false; - return true; - } + if (current === null) { + return ""; + } // Safe because if current fiber exists, we are reconciling, + // and it is guaranteed to be the work-in-progress version. + + return getStackByFiberInDevAndProd(current); } + } - return false; + function resetCurrentFiber() { + { + ReactDebugCurrentFrame.getCurrentStack = null; + current = null; + isRendering = false; + } } - function checkIfUseWrappedInAsyncCatch(rejectedReason) { - // This check runs in prod, too, because it prevents a more confusing - // downstream error, where SuspenseException is caught by a promise and - // thrown asynchronously. - // TODO: Another way to prevent SuspenseException from leaking into an async - // execution context is to check the dispatcher every time `use` is called, - // or some equivalent. That might be preferable for other reasons, too, since - // it matches how we prevent similar mistakes for other hooks. - if (rejectedReason === SuspenseException) { - throw new Error( - "Hooks are not supported inside an async component. This " + - "error is often caused by accidentally adding `'use client'` " + - "to a module that was originally written for the server." - ); + function setCurrentFiber(fiber) { + { + ReactDebugCurrentFrame.getCurrentStack = + fiber === null ? null : getCurrentFiberStackInDev; + current = fiber; + isRendering = false; + } + } + function getCurrentFiber() { + { + return current; + } + } + function setIsRendering(rendering) { + { + isRendering = rendering; } } - var thenableState$1 = null; - var thenableIndexCounter$1 = 0; - var didWarnAboutMaps; - var didWarnAboutGenerators; - var didWarnAboutStringRefs; - var ownerHasKeyUseWarning; - var ownerHasFunctionTypeWarning; - - var warnForMissingKey = function (child, returnFiber) {}; + var ReactStrictModeWarnings = { + recordUnsafeLifecycleWarnings: function (fiber, instance) {}, + flushPendingUnsafeLifecycleWarnings: function () {}, + recordLegacyContextWarning: function (fiber, instance) {}, + flushLegacyContextWarning: function () {}, + discardPendingWarnings: function () {} + }; { - didWarnAboutMaps = false; - didWarnAboutGenerators = false; - didWarnAboutStringRefs = {}; - /** - * Warn if there's no key explicitly set on dynamic arrays of children or - * object keys are not valid. This allows us to keep track of children between - * updates. - */ + var findStrictRoot = function (fiber) { + var maybeStrictRoot = null; + var node = fiber; - ownerHasKeyUseWarning = {}; - ownerHasFunctionTypeWarning = {}; + while (node !== null) { + if (node.mode & StrictLegacyMode) { + maybeStrictRoot = node; + } - warnForMissingKey = function (child, returnFiber) { - if (child === null || typeof child !== "object") { - return; + node = node.return; } - if (!child._store || child._store.validated || child.key != null) { - return; - } + return maybeStrictRoot; + }; - if (typeof child._store !== "object") { - throw new Error( - "React Component in warnForMissingKey should have a _store. " + - "This error is likely caused by a bug in React. Please file an issue." - ); - } // $FlowFixMe[cannot-write] unable to narrow type from mixed to writable object + var setToSortedString = function (set) { + var array = []; + set.forEach(function (value) { + array.push(value); + }); + return array.sort().join(", "); + }; - child._store.validated = true; - var componentName = - getComponentNameFromFiber(returnFiber) || "Component"; + var pendingComponentWillMountWarnings = []; + var pendingUNSAFE_ComponentWillMountWarnings = []; + var pendingComponentWillReceivePropsWarnings = []; + var pendingUNSAFE_ComponentWillReceivePropsWarnings = []; + var pendingComponentWillUpdateWarnings = []; + var pendingUNSAFE_ComponentWillUpdateWarnings = []; // Tracks components we have already warned about. - if (ownerHasKeyUseWarning[componentName]) { + var didWarnAboutUnsafeLifecycles = new Set(); + + ReactStrictModeWarnings.recordUnsafeLifecycleWarnings = function ( + fiber, + instance + ) { + // Dedupe strategy: Warn once per component. + if (didWarnAboutUnsafeLifecycles.has(fiber.type)) { return; } - ownerHasKeyUseWarning[componentName] = true; - - error( - "Each child in a list should have a unique " + - '"key" prop. See https://reactjs.org/link/warning-keys for ' + - "more information." - ); - }; - } + if ( + typeof instance.componentWillMount === "function" && // Don't warn about react-lifecycles-compat polyfilled components. + instance.componentWillMount.__suppressDeprecationWarning !== true + ) { + pendingComponentWillMountWarnings.push(fiber); + } - function isReactClass(type) { - return type.prototype && type.prototype.isReactComponent; - } + if ( + fiber.mode & StrictLegacyMode && + typeof instance.UNSAFE_componentWillMount === "function" + ) { + pendingUNSAFE_ComponentWillMountWarnings.push(fiber); + } - function unwrapThenable(thenable) { - var index = thenableIndexCounter$1; - thenableIndexCounter$1 += 1; + if ( + typeof instance.componentWillReceiveProps === "function" && + instance.componentWillReceiveProps.__suppressDeprecationWarning !== + true + ) { + pendingComponentWillReceivePropsWarnings.push(fiber); + } - if (thenableState$1 === null) { - thenableState$1 = createThenableState(); - } + if ( + fiber.mode & StrictLegacyMode && + typeof instance.UNSAFE_componentWillReceiveProps === "function" + ) { + pendingUNSAFE_ComponentWillReceivePropsWarnings.push(fiber); + } - return trackUsedThenable(thenableState$1, thenable, index); - } + if ( + typeof instance.componentWillUpdate === "function" && + instance.componentWillUpdate.__suppressDeprecationWarning !== true + ) { + pendingComponentWillUpdateWarnings.push(fiber); + } - function coerceRef(returnFiber, current, element) { - var mixedRef = element.ref; + if ( + fiber.mode & StrictLegacyMode && + typeof instance.UNSAFE_componentWillUpdate === "function" + ) { + pendingUNSAFE_ComponentWillUpdateWarnings.push(fiber); + } + }; - if ( - mixedRef !== null && - typeof mixedRef !== "function" && - typeof mixedRef !== "object" - ) { - { - if ( - // We warn in ReactElement.js if owner and self are equal for string refs - // because these cannot be automatically converted to an arrow function - // using a codemod. Therefore, we don't have to warn about string refs again. - !( - element._owner && - element._self && - element._owner.stateNode !== element._self - ) && // Will already throw with "Function components cannot have string refs" - !(element._owner && element._owner.tag !== ClassComponent) && // Will already warn with "Function components cannot be given refs" - !( - typeof element.type === "function" && !isReactClass(element.type) - ) && // Will already throw with "Element ref was specified as a string (someStringRef) but no owner was set" - element._owner - ) { - var componentName = - getComponentNameFromFiber(returnFiber) || "Component"; + ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = + function () { + // We do an initial pass to gather component names + var componentWillMountUniqueNames = new Set(); - if (!didWarnAboutStringRefs[componentName]) { - error( - 'Component "%s" contains the string ref "%s". Support for string refs ' + - "will be removed in a future major release. We recommend using " + - "useRef() or createRef() instead. " + - "Learn more about using refs safely here: " + - "https://reactjs.org/link/strict-mode-string-ref", - componentName, - mixedRef + if (pendingComponentWillMountWarnings.length > 0) { + pendingComponentWillMountWarnings.forEach(function (fiber) { + componentWillMountUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" ); - - didWarnAboutStringRefs[componentName] = true; - } + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingComponentWillMountWarnings = []; } - } - - if (element._owner) { - var owner = element._owner; - var inst; - if (owner) { - var ownerFiber = owner; + var UNSAFE_componentWillMountUniqueNames = new Set(); - if (ownerFiber.tag !== ClassComponent) { - throw new Error( - "Function components cannot have string refs. " + - "We recommend using useRef() instead. " + - "Learn more about using refs safely here: " + - "https://reactjs.org/link/strict-mode-string-ref" + if (pendingUNSAFE_ComponentWillMountWarnings.length > 0) { + pendingUNSAFE_ComponentWillMountWarnings.forEach(function (fiber) { + UNSAFE_componentWillMountUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" ); - } - - inst = ownerFiber.stateNode; + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingUNSAFE_ComponentWillMountWarnings = []; } - if (!inst) { - throw new Error( - "Missing owner for string ref " + - mixedRef + - ". This error is likely caused by a " + - "bug in React. Please file an issue." - ); - } // Assigning this to a const so Flow knows it won't change in the closure - - var resolvedInst = inst; + var componentWillReceivePropsUniqueNames = new Set(); - { - checkPropStringCoercion(mixedRef, "ref"); + if (pendingComponentWillReceivePropsWarnings.length > 0) { + pendingComponentWillReceivePropsWarnings.forEach(function (fiber) { + componentWillReceivePropsUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingComponentWillReceivePropsWarnings = []; } - var stringRef = "" + mixedRef; // Check if previous string ref matches new string ref + var UNSAFE_componentWillReceivePropsUniqueNames = new Set(); - if ( - current !== null && - current.ref !== null && - typeof current.ref === "function" && - current.ref._stringRef === stringRef - ) { - return current.ref; + if (pendingUNSAFE_ComponentWillReceivePropsWarnings.length > 0) { + pendingUNSAFE_ComponentWillReceivePropsWarnings.forEach( + function (fiber) { + UNSAFE_componentWillReceivePropsUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + } + ); + pendingUNSAFE_ComponentWillReceivePropsWarnings = []; } - var ref = function (value) { - var refs = resolvedInst.refs; + var componentWillUpdateUniqueNames = new Set(); - if (value === null) { - delete refs[stringRef]; - } else { - refs[stringRef] = value; - } - }; + if (pendingComponentWillUpdateWarnings.length > 0) { + pendingComponentWillUpdateWarnings.forEach(function (fiber) { + componentWillUpdateUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingComponentWillUpdateWarnings = []; + } - ref._stringRef = stringRef; - return ref; - } else { - if (typeof mixedRef !== "string") { - throw new Error( - "Expected ref to be a function, a string, an object returned by React.createRef(), or null." + var UNSAFE_componentWillUpdateUniqueNames = new Set(); + + if (pendingUNSAFE_ComponentWillUpdateWarnings.length > 0) { + pendingUNSAFE_ComponentWillUpdateWarnings.forEach(function (fiber) { + UNSAFE_componentWillUpdateUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingUNSAFE_ComponentWillUpdateWarnings = []; + } // Finally, we flush all the warnings + // UNSAFE_ ones before the deprecated ones, since they'll be 'louder' + + if (UNSAFE_componentWillMountUniqueNames.size > 0) { + var sortedNames = setToSortedString( + UNSAFE_componentWillMountUniqueNames + ); + + error( + "Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code. " + + "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + + "* Move code with side effects to componentDidMount, and set initial state in the constructor.\n" + + "\nPlease update the following components: %s", + sortedNames ); } - if (!element._owner) { - throw new Error( - "Element ref was specified as a string (" + - mixedRef + - ") but no owner was set. This could happen for one of" + - " the following reasons:\n" + - "1. You may be adding a ref to a function component\n" + - "2. You may be adding a ref to a component that was not created inside a component's render method\n" + - "3. You have multiple copies of React loaded\n" + - "See https://reactjs.org/link/refs-must-have-owner for more information." + if (UNSAFE_componentWillReceivePropsUniqueNames.size > 0) { + var _sortedNames = setToSortedString( + UNSAFE_componentWillReceivePropsUniqueNames + ); + + error( + "Using UNSAFE_componentWillReceiveProps in strict mode is not recommended " + + "and may indicate bugs in your code. " + + "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + + "* Move data fetching code or side effects to componentDidUpdate.\n" + + "* If you're updating state whenever props change, " + + "refactor your code to use memoization techniques or move it to " + + "static getDerivedStateFromProps. Learn more at: https://reactjs.org/link/derived-state\n" + + "\nPlease update the following components: %s", + _sortedNames ); } - } - } - return mixedRef; - } + if (UNSAFE_componentWillUpdateUniqueNames.size > 0) { + var _sortedNames2 = setToSortedString( + UNSAFE_componentWillUpdateUniqueNames + ); - function throwOnInvalidObjectType(returnFiber, newChild) { - // $FlowFixMe[method-unbinding] - var childString = Object.prototype.toString.call(newChild); - throw new Error( - "Objects are not valid as a React child (found: " + - (childString === "[object Object]" - ? "object with keys {" + Object.keys(newChild).join(", ") + "}" - : childString) + - "). " + - "If you meant to render a collection of children, use an array " + - "instead." - ); - } + error( + "Using UNSAFE_componentWillUpdate in strict mode is not recommended " + + "and may indicate bugs in your code. " + + "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + + "* Move data fetching code or side effects to componentDidUpdate.\n" + + "\nPlease update the following components: %s", + _sortedNames2 + ); + } - function warnOnFunctionType(returnFiber) { - { - var componentName = - getComponentNameFromFiber(returnFiber) || "Component"; + if (componentWillMountUniqueNames.size > 0) { + var _sortedNames3 = setToSortedString( + componentWillMountUniqueNames + ); - if (ownerHasFunctionTypeWarning[componentName]) { - return; - } + warn( + "componentWillMount has been renamed, and is not recommended for use. " + + "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + + "* Move code with side effects to componentDidMount, and set initial state in the constructor.\n" + + "* Rename componentWillMount to UNSAFE_componentWillMount to suppress " + + "this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. " + + "To rename all deprecated lifecycles to their new names, you can run " + + "`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n" + + "\nPlease update the following components: %s", + _sortedNames3 + ); + } - ownerHasFunctionTypeWarning[componentName] = true; + if (componentWillReceivePropsUniqueNames.size > 0) { + var _sortedNames4 = setToSortedString( + componentWillReceivePropsUniqueNames + ); - error( - "Functions are not valid as a React child. This may happen if " + - "you return a Component instead of from render. " + - "Or maybe you meant to call this function rather than return it." - ); - } - } + warn( + "componentWillReceiveProps has been renamed, and is not recommended for use. " + + "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + + "* Move data fetching code or side effects to componentDidUpdate.\n" + + "* If you're updating state whenever props change, refactor your " + + "code to use memoization techniques or move it to " + + "static getDerivedStateFromProps. Learn more at: https://reactjs.org/link/derived-state\n" + + "* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress " + + "this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. " + + "To rename all deprecated lifecycles to their new names, you can run " + + "`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n" + + "\nPlease update the following components: %s", + _sortedNames4 + ); + } - function resolveLazy(lazyType) { - var payload = lazyType._payload; - var init = lazyType._init; - return init(payload); - } // This wrapper function exists because I expect to clone the code in each path - // to be able to optimize each path individually by branching early. This needs - // a compiler or we can do it manually. Helpers that don't need this branching - // live outside of this function. + if (componentWillUpdateUniqueNames.size > 0) { + var _sortedNames5 = setToSortedString( + componentWillUpdateUniqueNames + ); - function createChildReconciler(shouldTrackSideEffects) { - function deleteChild(returnFiber, childToDelete) { - if (!shouldTrackSideEffects) { - // Noop. - return; - } + warn( + "componentWillUpdate has been renamed, and is not recommended for use. " + + "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + + "* Move data fetching code or side effects to componentDidUpdate.\n" + + "* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress " + + "this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. " + + "To rename all deprecated lifecycles to their new names, you can run " + + "`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n" + + "\nPlease update the following components: %s", + _sortedNames5 + ); + } + }; - var deletions = returnFiber.deletions; + var pendingLegacyContextWarning = new Map(); // Tracks components we have already warned about. - if (deletions === null) { - returnFiber.deletions = [childToDelete]; - returnFiber.flags |= ChildDeletion; - } else { - deletions.push(childToDelete); - } - } + var didWarnAboutLegacyContext = new Set(); - 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. + ReactStrictModeWarnings.recordLegacyContextWarning = function ( + fiber, + instance + ) { + var strictRoot = findStrictRoot(fiber); - var childToDelete = currentFirstChild; + if (strictRoot === null) { + error( + "Expected to find a StrictMode component in a strict mode tree. " + + "This error is likely caused by a bug in React. Please file an issue." + ); - while (childToDelete !== null) { - deleteChild(returnFiber, childToDelete); - childToDelete = childToDelete.sibling; - } + return; + } // Dedup strategy: Warn once per component. - return null; - } + if (didWarnAboutLegacyContext.has(fiber.type)) { + return; + } - function mapRemainingChildren(returnFiber, currentFirstChild) { - // Add the remaining children to a temporary map so that we can find them by - // keys quickly. Implicit (null) keys get added to this set with their index - // instead. - var existingChildren = new Map(); - var existingChild = currentFirstChild; + var warningsForRoot = pendingLegacyContextWarning.get(strictRoot); - while (existingChild !== null) { - if (existingChild.key !== null) { - existingChildren.set(existingChild.key, existingChild); - } else { - existingChildren.set(existingChild.index, existingChild); + if ( + fiber.type.contextTypes != null || + fiber.type.childContextTypes != null || + (instance !== null && typeof instance.getChildContext === "function") + ) { + if (warningsForRoot === undefined) { + warningsForRoot = []; + pendingLegacyContextWarning.set(strictRoot, warningsForRoot); } - existingChild = existingChild.sibling; + warningsForRoot.push(fiber); } + }; - return existingChildren; - } + ReactStrictModeWarnings.flushLegacyContextWarning = function () { + pendingLegacyContextWarning.forEach(function (fiberArray, strictRoot) { + if (fiberArray.length === 0) { + return; + } - function useFiber(fiber, pendingProps) { - // We currently set sibling to null and index to 0 here because it is easy - // to forget to do before returning it. E.g. for the single child case. - var clone = createWorkInProgress(fiber, pendingProps); - clone.index = 0; - clone.sibling = null; - return clone; - } + var firstFiber = fiberArray[0]; + var uniqueNames = new Set(); + fiberArray.forEach(function (fiber) { + uniqueNames.add(getComponentNameFromFiber(fiber) || "Component"); + didWarnAboutLegacyContext.add(fiber.type); + }); + var sortedNames = setToSortedString(uniqueNames); - function placeChild(newFiber, lastPlacedIndex, newIndex) { - newFiber.index = newIndex; + try { + setCurrentFiber(firstFiber); - if (!shouldTrackSideEffects) { - // During hydration, the useId algorithm needs to know which fibers are - // part of a list of children (arrays, iterators). - newFiber.flags |= Forked; - return lastPlacedIndex; - } + error( + "Legacy context API has been detected within a strict-mode tree." + + "\n\nThe old API will be supported in all 16.x releases, but applications " + + "using it should migrate to the new version." + + "\n\nPlease update the following components: %s" + + "\n\nLearn more about this warning here: https://reactjs.org/link/legacy-context", + sortedNames + ); + } finally { + resetCurrentFiber(); + } + }); + }; - var current = newFiber.alternate; + ReactStrictModeWarnings.discardPendingWarnings = function () { + pendingComponentWillMountWarnings = []; + pendingUNSAFE_ComponentWillMountWarnings = []; + pendingComponentWillReceivePropsWarnings = []; + pendingUNSAFE_ComponentWillReceivePropsWarnings = []; + pendingComponentWillUpdateWarnings = []; + pendingUNSAFE_ComponentWillUpdateWarnings = []; + pendingLegacyContextWarning = new Map(); + }; + } - if (current !== null) { - var oldIndex = current.index; + /* + * The `'' + value` pattern (used in perf-sensitive code) throws for Symbol + * and Temporal.* types. See https://github.com/facebook/react/pull/22064. + * + * The functions in this module will throw an easier-to-understand, + * easier-to-debug exception with a clear errors message message explaining the + * problem. (Instead of a confusing exception thrown inside the implementation + * of the `value` object). + */ + // $FlowFixMe[incompatible-return] only called in DEV, so void return is not possible. + function typeName(value) { + { + // toStringTag is needed for namespaced types like Temporal.Instant + var hasToStringTag = typeof Symbol === "function" && Symbol.toStringTag; + var type = + (hasToStringTag && value[Symbol.toStringTag]) || + value.constructor.name || + "Object"; // $FlowFixMe[incompatible-return] - if (oldIndex < lastPlacedIndex) { - // This is a move. - newFiber.flags |= Placement | PlacementDEV; - return lastPlacedIndex; - } else { - // This item can stay in place. - return oldIndex; - } - } else { - // This is an insertion. - newFiber.flags |= Placement | PlacementDEV; - return lastPlacedIndex; + return type; + } + } // $FlowFixMe[incompatible-return] only called in DEV, so void return is not possible. + + function willCoercionThrow(value) { + { + try { + testStringCoercion(value); + return false; + } catch (e) { + return true; } } + } - function placeSingleChild(newFiber) { - // This is simpler for the single child case. We only need to do a - // placement for inserting new children. - if (shouldTrackSideEffects && newFiber.alternate === null) { - newFiber.flags |= Placement | PlacementDEV; + function testStringCoercion(value) { + // If you ended up here by following an exception call stack, here's what's + // happened: you supplied an object or symbol value to React (as a prop, key, + // DOM attribute, CSS property, string ref, etc.) and when React tried to + // coerce it to a string using `'' + value`, an exception was thrown. + // + // The most common types that will cause this exception are `Symbol` instances + // and Temporal objects like `Temporal.Instant`. But any object that has a + // `valueOf` or `[Symbol.toPrimitive]` method that throws will also cause this + // exception. (Library authors do this to prevent users from using built-in + // numeric operators like `+` or comparison operators like `>=` because custom + // methods are needed to perform accurate arithmetic or comparison.) + // + // To fix the problem, coerce this object or symbol value to a string before + // passing it to React. The most reliable way is usually `String(value)`. + // + // To find which value is throwing, check the browser or debugger console. + // Before this exception was thrown, there should be `console.error` output + // that shows the type (Symbol, Temporal.PlainDate, etc.) that caused the + // problem and how that type was used: key, atrribute, input value prop, etc. + // In most cases, this console output also shows the component and its + // ancestor components where the exception happened. + // + // eslint-disable-next-line react-internal/safe-string-coercion + return "" + value; + } + function checkKeyStringCoercion(value) { + { + if (willCoercionThrow(value)) { + error( + "The provided key is an unsupported type %s." + + " This value must be coerced to a string before using it here.", + typeName(value) + ); + + return testStringCoercion(value); // throw (to help callers find troubleshooting comments) } + } + } + function checkPropStringCoercion(value, propName) { + { + if (willCoercionThrow(value)) { + error( + "The provided `%s` prop is an unsupported type %s." + + " This value must be coerced to a string before using it here.", + propName, + typeName(value) + ); - return newFiber; + return testStringCoercion(value); // throw (to help callers find troubleshooting comments) + } } + } - function updateTextNode(returnFiber, current, textContent, lanes) { - if (current === null || current.tag !== HostText) { - // Insert - var created = createFiberFromText( - textContent, - returnFiber.mode, - lanes + var ReactCurrentActQueue$2 = ReactSharedInternals.ReactCurrentActQueue; + + function getThenablesFromState(state) { + { + var devState = state; + return devState.thenables; + } + } // An error that is thrown (e.g. by `use`) to trigger Suspense. If we + // detect this is caught by userspace, we'll log a warning in development. + + var SuspenseException = new Error( + "Suspense Exception: This is not a real error! It's an implementation " + + "detail of `use` to interrupt the current render. You must either " + + "rethrow it immediately, or move the `use` call outside of the " + + "`try/catch` block. Capturing without rethrowing will lead to " + + "unexpected behavior.\n\n" + + "To handle async errors, wrap your component in an error boundary, or " + + "call the promise's `.catch` method and pass the result to `use`" + ); + var SuspenseyCommitException = new Error( + "Suspense Exception: This is not a real error, and should not leak into " + + "userspace. If you're seeing this, it's likely a bug in React." + ); // This is a noop thenable that we use to trigger a fallback in throwException. + // TODO: It would be better to refactor throwException into multiple functions + // so we can trigger a fallback directly without having to check the type. But + // for now this will do. + + var noopSuspenseyCommitThenable = { + then: function () { + { + error( + "Internal React error: A listener was unexpectedly attached to a " + + '"noop" thenable. This is a bug in React. Please file an issue.' ); - created.return = returnFiber; - return created; - } else { - // Update - var existing = useFiber(current, textContent); - existing.return = returnFiber; - return existing; } } + }; + function createThenableState() { + // The ThenableState is created the first time a component suspends. If it + // suspends again, we'll reuse the same state. + { + return { + didWarnAboutUncachedPromise: false, + thenables: [] + }; + } + } + function isThenableResolved(thenable) { + var status = thenable.status; + return status === "fulfilled" || status === "rejected"; + } - function updateElement(returnFiber, current, element, lanes) { - var elementType = element.type; + function noop() {} - if (elementType === REACT_FRAGMENT_TYPE) { - return updateFragment( - returnFiber, - current, - element.props.children, - lanes, - element.key - ); + function trackUsedThenable(thenableState, thenable, index) { + if (ReactCurrentActQueue$2.current !== null) { + ReactCurrentActQueue$2.didUsePromise = true; + } + + var trackedThenables = getThenablesFromState(thenableState); + var previous = trackedThenables[index]; + + if (previous === undefined) { + trackedThenables.push(thenable); + } else { + if (previous !== thenable) { + // Reuse the previous thenable, and drop the new one. We can assume + // they represent the same value, because components are idempotent. + { + var thenableStateDev = thenableState; + + if (!thenableStateDev.didWarnAboutUncachedPromise) { + // We should only warn the first time an uncached thenable is + // discovered per component, because if there are multiple, the + // subsequent ones are likely derived from the first. + // + // We track this on the thenableState instead of deduping using the + // component name like we usually do, because in the case of a + // promise-as-React-node, the owner component is likely different from + // the parent that's currently being reconciled. We'd have to track + // the owner using state, which we're trying to move away from. Though + // since this is dev-only, maybe that'd be OK. + // + // However, another benefit of doing it this way is we might + // eventually have a thenableState per memo/Forget boundary instead + // of per component, so this would allow us to have more + // granular warnings. + thenableStateDev.didWarnAboutUncachedPromise = true; // TODO: This warning should link to a corresponding docs page. + + error( + "A component was suspended by an uncached promise. Creating " + + "promises inside a Client Component or hook is not yet " + + "supported, except via a Suspense-compatible library or framework." + ); + } + } // Avoid an unhandled rejection errors for the Promises that we'll + // intentionally ignore. + + thenable.then(noop, noop); + thenable = previous; } + } // We use an expando to track the status and result of a thenable so that we + // can synchronously unwrap the value. Think of this as an extension of the + // Promise API, or a custom interface that is a superset of Thenable. + // + // If the thenable doesn't have a status, set it to "pending" and attach + // a listener that will update its status and result when it resolves. - if (current !== null) { - if ( - current.elementType === elementType || // Keep this check inline so it only runs on the false path: - isCompatibleFamilyForHotReloading(current, element) || // Lazy types should reconcile their resolved type. - // We need to do this after the Hot Reloading check above, - // because hot reloading has different semantics than prod because - // it doesn't resuspend. So we can't let the call below suspend. - (typeof elementType === "object" && - elementType !== null && - elementType.$$typeof === REACT_LAZY_TYPE && - resolveLazy(elementType) === current.type) - ) { - // Move based on index - var existing = useFiber(current, element.props); - existing.ref = coerceRef(returnFiber, current, element); - existing.return = returnFiber; + switch (thenable.status) { + case "fulfilled": { + var fulfilledValue = thenable.value; + return fulfilledValue; + } - { - existing._debugSource = element._source; - existing._debugOwner = element._owner; + case "rejected": { + var rejectedError = thenable.reason; + checkIfUseWrappedInAsyncCatch(rejectedError); + throw rejectedError; + } + + default: { + if (typeof thenable.status === "string") { + // Only instrument the thenable if the status if not defined. If + // it's defined, but an unknown value, assume it's been instrumented by + // some custom userspace implementation. We treat it as "pending". + // Attach a dummy listener, to ensure that any lazy initialization can + // happen. Flight lazily parses JSON when the value is actually awaited. + thenable.then(noop, noop); + } else { + // This is an uncached thenable that we haven't seen before. + // Detect infinite ping loops caused by uncached promises. + var root = getWorkInProgressRoot(); + + if (root !== null && root.shellSuspendCounter > 100) { + // This root has suspended repeatedly in the shell without making any + // progress (i.e. committing something). This is highly suggestive of + // an infinite ping loop, often caused by an accidental Async Client + // Component. + // + // During a transition, we can suspend the work loop until the promise + // to resolve, but this is a sync render, so that's not an option. We + // also can't show a fallback, because none was provided. So our last + // resort is to throw an error. + // + // TODO: Remove this error in a future release. Other ways of handling + // this case include forcing a concurrent render, or putting the whole + // root into offscreen mode. + throw new Error( + "async/await is not yet supported in Client Components, only " + + "Server Components. This error is often caused by accidentally " + + "adding `'use client'` to a module that was originally written " + + "for the server." + ); } - return existing; - } - } // Insert + var pendingThenable = thenable; + pendingThenable.status = "pending"; + pendingThenable.then( + function (fulfilledValue) { + if (thenable.status === "pending") { + var fulfilledThenable = thenable; + fulfilledThenable.status = "fulfilled"; + fulfilledThenable.value = fulfilledValue; + } + }, + function (error) { + if (thenable.status === "pending") { + var rejectedThenable = thenable; + rejectedThenable.status = "rejected"; + rejectedThenable.reason = error; + } + } + ); // Check one more time in case the thenable resolved synchronously. + + switch (thenable.status) { + case "fulfilled": { + var fulfilledThenable = thenable; + return fulfilledThenable.value; + } + + case "rejected": { + var rejectedThenable = thenable; + var _rejectedError = rejectedThenable.reason; + checkIfUseWrappedInAsyncCatch(_rejectedError); + throw _rejectedError; + } + } + } // Suspend. + // + // Throwing here is an implementation detail that allows us to unwind the + // call stack. But we shouldn't allow it to leak into userspace. Throw an + // opaque placeholder value instead of the actual thenable. If it doesn't + // get captured by the work loop, log a warning, because that means + // something in userspace must have caught it. + + suspendedThenable = thenable; - var created = createFiberFromElement(element, returnFiber.mode, lanes); - created.ref = coerceRef(returnFiber, current, element); - created.return = returnFiber; - return created; - } + { + needsToResetSuspendedThenableDEV = true; + } - function updatePortal(returnFiber, current, portal, lanes) { - if ( - current === null || - current.tag !== HostPortal || - current.stateNode.containerInfo !== portal.containerInfo || - current.stateNode.implementation !== portal.implementation - ) { - // Insert - var created = createFiberFromPortal(portal, returnFiber.mode, lanes); - created.return = returnFiber; - return created; - } else { - // Update - var existing = useFiber(current, portal.children || []); - existing.return = returnFiber; - return existing; + throw SuspenseException; } } + } + // passed to the rest of the Suspense implementation — which, for historical + // reasons, expects to receive a thenable. - function updateFragment(returnFiber, current, fragment, lanes, key) { - if (current === null || current.tag !== Fragment) { - // Insert - var created = createFiberFromFragment( - fragment, - returnFiber.mode, - lanes, - key - ); - created.return = returnFiber; - return created; - } else { - // Update - var existing = useFiber(current, fragment); - existing.return = returnFiber; - return existing; - } + var suspendedThenable = null; + var needsToResetSuspendedThenableDEV = false; + function getSuspendedThenable() { + // This is called right after `use` suspends by throwing an exception. `use` + // throws an opaque value instead of the thenable itself so that it can't be + // caught in userspace. Then the work loop accesses the actual thenable using + // this function. + if (suspendedThenable === null) { + throw new Error( + "Expected a suspended thenable. This is a bug in React. Please file " + + "an issue." + ); } - function createChild(returnFiber, newChild, lanes) { - if ( - (typeof newChild === "string" && newChild !== "") || - typeof newChild === "number" - ) { - // Text nodes don't have keys. If the previous node is implicitly keyed - // we can continue to replace it without aborting even if it is not a text - // node. - var created = createFiberFromText( - "" + newChild, - returnFiber.mode, - lanes - ); - created.return = returnFiber; - return created; - } - - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: { - var _created = createFiberFromElement( - newChild, - returnFiber.mode, - lanes - ); - - _created.ref = coerceRef(returnFiber, null, newChild); - _created.return = returnFiber; - return _created; - } + var thenable = suspendedThenable; + suspendedThenable = null; - case REACT_PORTAL_TYPE: { - var _created2 = createFiberFromPortal( - newChild, - returnFiber.mode, - lanes - ); + { + needsToResetSuspendedThenableDEV = false; + } - _created2.return = returnFiber; - return _created2; - } + return thenable; + } + function checkIfUseWrappedInTryCatch() { + { + // This was set right before SuspenseException was thrown, and it should + // have been cleared when the exception was handled. If it wasn't, + // it must have been caught by userspace. + if (needsToResetSuspendedThenableDEV) { + needsToResetSuspendedThenableDEV = false; + return true; + } + } - case REACT_LAZY_TYPE: { - var payload = newChild._payload; - var init = newChild._init; - return createChild(returnFiber, init(payload), lanes); - } - } + return false; + } + function checkIfUseWrappedInAsyncCatch(rejectedReason) { + // This check runs in prod, too, because it prevents a more confusing + // downstream error, where SuspenseException is caught by a promise and + // thrown asynchronously. + // TODO: Another way to prevent SuspenseException from leaking into an async + // execution context is to check the dispatcher every time `use` is called, + // or some equivalent. That might be preferable for other reasons, too, since + // it matches how we prevent similar mistakes for other hooks. + if (rejectedReason === SuspenseException) { + throw new Error( + "Hooks are not supported inside an async component. This " + + "error is often caused by accidentally adding `'use client'` " + + "to a module that was originally written for the server." + ); + } + } - if (isArray(newChild) || getIteratorFn(newChild)) { - var _created3 = createFiberFromFragment( - newChild, - returnFiber.mode, - lanes, - null - ); + var thenableState$1 = null; + var thenableIndexCounter$1 = 0; + var didWarnAboutMaps; + var didWarnAboutGenerators; + var didWarnAboutStringRefs; + var ownerHasKeyUseWarning; + var ownerHasFunctionTypeWarning; - _created3.return = returnFiber; - return _created3; - } // Usable node types - // - // Unwrap the inner value and recursively call this function again. + var warnForMissingKey = function (child, returnFiber) {}; - if (typeof newChild.then === "function") { - var thenable = newChild; - return createChild(returnFiber, unwrapThenable(thenable), lanes); - } + { + didWarnAboutMaps = false; + didWarnAboutGenerators = false; + didWarnAboutStringRefs = {}; + /** + * Warn if there's no key explicitly set on dynamic arrays of children or + * object keys are not valid. This allows us to keep track of children between + * updates. + */ - if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) { - var context = newChild; - return createChild( - returnFiber, - readContextDuringReconcilation(returnFiber, context, lanes), - lanes - ); - } + ownerHasKeyUseWarning = {}; + ownerHasFunctionTypeWarning = {}; - throwOnInvalidObjectType(returnFiber, newChild); + warnForMissingKey = function (child, returnFiber) { + if (child === null || typeof child !== "object") { + return; } - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber); - } + if (!child._store || child._store.validated || child.key != null) { + return; } - return null; - } - - function updateSlot(returnFiber, oldFiber, newChild, lanes) { - // Update the fiber if the keys match, otherwise return null. - var key = oldFiber !== null ? oldFiber.key : null; + if (typeof child._store !== "object") { + throw new Error( + "React Component in warnForMissingKey should have a _store. " + + "This error is likely caused by a bug in React. Please file an issue." + ); + } // $FlowFixMe[cannot-write] unable to narrow type from mixed to writable object - if ( - (typeof newChild === "string" && newChild !== "") || - typeof newChild === "number" - ) { - // Text nodes don't have keys. If the previous node is implicitly keyed - // we can continue to replace it without aborting even if it is not a text - // node. - if (key !== null) { - return null; - } + child._store.validated = true; + var componentName = + getComponentNameFromFiber(returnFiber) || "Component"; - return updateTextNode(returnFiber, oldFiber, "" + newChild, lanes); + if (ownerHasKeyUseWarning[componentName]) { + return; } - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: { - if (newChild.key === key) { - return updateElement(returnFiber, oldFiber, newChild, lanes); - } else { - return null; - } - } + ownerHasKeyUseWarning[componentName] = true; - case REACT_PORTAL_TYPE: { - if (newChild.key === key) { - return updatePortal(returnFiber, oldFiber, newChild, lanes); - } else { - return null; - } - } + error( + "Each child in a list should have a unique " + + '"key" prop. See https://reactjs.org/link/warning-keys for ' + + "more information." + ); + }; + } - case REACT_LAZY_TYPE: { - var payload = newChild._payload; - var init = newChild._init; - return updateSlot(returnFiber, oldFiber, init(payload), lanes); - } - } + function isReactClass(type) { + return type.prototype && type.prototype.isReactComponent; + } + + function unwrapThenable(thenable) { + var index = thenableIndexCounter$1; + thenableIndexCounter$1 += 1; - if (isArray(newChild) || getIteratorFn(newChild)) { - if (key !== null) { - return null; - } + if (thenableState$1 === null) { + thenableState$1 = createThenableState(); + } - return updateFragment(returnFiber, oldFiber, newChild, lanes, null); - } // Usable node types - // - // Unwrap the inner value and recursively call this function again. + return trackUsedThenable(thenableState$1, thenable, index); + } - if (typeof newChild.then === "function") { - var thenable = newChild; - return updateSlot( - returnFiber, - oldFiber, - unwrapThenable(thenable), - lanes - ); - } + function coerceRef(returnFiber, current, element) { + var mixedRef = element.ref; + if ( + mixedRef !== null && + typeof mixedRef !== "function" && + typeof mixedRef !== "object" + ) { + { if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE + // Will already throw with "Function components cannot have string refs" + !(element._owner && element._owner.tag !== ClassComponent) && // Will already warn with "Function components cannot be given refs" + !( + typeof element.type === "function" && !isReactClass(element.type) + ) && // Will already throw with "Element ref was specified as a string (someStringRef) but no owner was set" + element._owner ) { - var context = newChild; - return updateSlot( - returnFiber, - oldFiber, - readContextDuringReconcilation(returnFiber, context, lanes), - lanes - ); - } + var componentName = + getComponentNameFromFiber(returnFiber) || "Component"; - throwOnInvalidObjectType(returnFiber, newChild); - } + if (!didWarnAboutStringRefs[componentName]) { + error( + 'Component "%s" contains the string ref "%s". Support for string refs ' + + "will be removed in a future major release. We recommend using " + + "useRef() or createRef() instead. " + + "Learn more about using refs safely here: " + + "https://reactjs.org/link/strict-mode-string-ref", + componentName, + mixedRef + ); - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber); + didWarnAboutStringRefs[componentName] = true; + } } } - return null; - } - - function updateFromMap( - existingChildren, - returnFiber, - newIdx, - newChild, - lanes - ) { - if ( - (typeof newChild === "string" && newChild !== "") || - typeof newChild === "number" - ) { - // Text nodes don't have keys, so we neither have to check the old nor - // new node for the key. If both are text nodes, they match. - var matchedFiber = existingChildren.get(newIdx) || null; - return updateTextNode( - returnFiber, - matchedFiber, - "" + newChild, - lanes - ); - } - - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: { - var _matchedFiber = - existingChildren.get( - newChild.key === null ? newIdx : newChild.key - ) || null; - - return updateElement(returnFiber, _matchedFiber, newChild, lanes); - } + if (element._owner) { + var owner = element._owner; + var inst; - case REACT_PORTAL_TYPE: { - var _matchedFiber2 = - existingChildren.get( - newChild.key === null ? newIdx : newChild.key - ) || null; + if (owner) { + var ownerFiber = owner; - return updatePortal(returnFiber, _matchedFiber2, newChild, lanes); + if (ownerFiber.tag !== ClassComponent) { + throw new Error( + "Function components cannot have string refs. " + + "We recommend using useRef() instead. " + + "Learn more about using refs safely here: " + + "https://reactjs.org/link/strict-mode-string-ref" + ); } - case REACT_LAZY_TYPE: - var payload = newChild._payload; - var init = newChild._init; - return updateFromMap( - existingChildren, - returnFiber, - newIdx, - init(payload), - lanes - ); + inst = ownerFiber.stateNode; } - if (isArray(newChild) || getIteratorFn(newChild)) { - var _matchedFiber3 = existingChildren.get(newIdx) || null; - - return updateFragment( - returnFiber, - _matchedFiber3, - newChild, - lanes, - null + if (!inst) { + throw new Error( + "Missing owner for string ref " + + mixedRef + + ". This error is likely caused by a " + + "bug in React. Please file an issue." ); - } // Usable node types - // - // Unwrap the inner value and recursively call this function again. + } // Assigning this to a const so Flow knows it won't change in the closure - if (typeof newChild.then === "function") { - var thenable = newChild; - return updateFromMap( - existingChildren, - returnFiber, - newIdx, - unwrapThenable(thenable), - lanes - ); + var resolvedInst = inst; + + { + checkPropStringCoercion(mixedRef, "ref"); } + var stringRef = "" + mixedRef; // Check if previous string ref matches new string ref + if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE + current !== null && + current.ref !== null && + typeof current.ref === "function" && + current.ref._stringRef === stringRef ) { - var context = newChild; - return updateFromMap( - existingChildren, - returnFiber, - newIdx, - readContextDuringReconcilation(returnFiber, context, lanes), - lanes - ); + return current.ref; } - throwOnInvalidObjectType(returnFiber, newChild); - } - - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber); - } - } + var ref = function (value) { + var refs = resolvedInst.refs; - return null; - } - /** - * Warns if there is a duplicate or missing key - */ + if (value === null) { + delete refs[stringRef]; + } else { + refs[stringRef] = value; + } + }; - function warnOnInvalidKey(child, knownKeys, returnFiber) { - { - if (typeof child !== "object" || child === null) { - return knownKeys; + ref._stringRef = stringRef; + return ref; + } else { + if (typeof mixedRef !== "string") { + throw new Error( + "Expected ref to be a function, a string, an object returned by React.createRef(), or null." + ); } - switch (child.$$typeof) { - case REACT_ELEMENT_TYPE: - case REACT_PORTAL_TYPE: - warnForMissingKey(child, returnFiber); - var key = child.key; - - if (typeof key !== "string") { - break; - } - - if (knownKeys === null) { - knownKeys = new Set(); - knownKeys.add(key); - break; - } + if (!element._owner) { + throw new Error( + "Element ref was specified as a string (" + + mixedRef + + ") but no owner was set. This could happen for one of" + + " the following reasons:\n" + + "1. You may be adding a ref to a function component\n" + + "2. You may be adding a ref to a component that was not created inside a component's render method\n" + + "3. You have multiple copies of React loaded\n" + + "See https://reactjs.org/link/refs-must-have-owner for more information." + ); + } + } + } - if (!knownKeys.has(key)) { - knownKeys.add(key); - break; - } + return mixedRef; + } - error( - "Encountered two children with the same key, `%s`. " + - "Keys should be unique so that components maintain their identity " + - "across updates. Non-unique keys may cause children to be " + - "duplicated and/or omitted — the behavior is unsupported and " + - "could change in a future version.", - key - ); + function throwOnInvalidObjectType(returnFiber, newChild) { + // $FlowFixMe[method-unbinding] + var childString = Object.prototype.toString.call(newChild); + throw new Error( + "Objects are not valid as a React child (found: " + + (childString === "[object Object]" + ? "object with keys {" + Object.keys(newChild).join(", ") + "}" + : childString) + + "). " + + "If you meant to render a collection of children, use an array " + + "instead." + ); + } - break; + function warnOnFunctionType(returnFiber) { + { + var componentName = + getComponentNameFromFiber(returnFiber) || "Component"; - case REACT_LAZY_TYPE: - var payload = child._payload; - var init = child._init; - warnOnInvalidKey(init(payload), knownKeys, returnFiber); - break; - } + if (ownerHasFunctionTypeWarning[componentName]) { + return; } - return knownKeys; + ownerHasFunctionTypeWarning[componentName] = true; + + error( + "Functions are not valid as a React child. This may happen if " + + "you return a Component instead of from render. " + + "Or maybe you meant to call this function rather than return it." + ); } + } - function reconcileChildrenArray( - returnFiber, - currentFirstChild, - newChildren, - lanes - ) { - // This algorithm can't optimize by searching from both ends since we - // don't have backpointers on fibers. I'm trying to see how far we can get - // with that model. If it ends up not being worth the tradeoffs, we can - // add it later. - // Even with a two ended optimization, we'd want to optimize for the case - // where there are few changes and brute force the comparison instead of - // going for the Map. It'd like to explore hitting that path first in - // forward-only mode and only go for the Map once we notice that we need - // lots of look ahead. This doesn't handle reversal as well as two ended - // search but that's unusual. Besides, for the two ended optimization to - // work on Iterables, we'd need to copy the whole set. - // In this first iteration, we'll just live with hitting the bad case - // (adding everything to a Map) in for every insert/move. - // If you change this code, also update reconcileChildrenIterator() which - // uses the same algorithm. - { - // First, validate keys. - var knownKeys = null; + function resolveLazy(lazyType) { + var payload = lazyType._payload; + var init = lazyType._init; + return init(payload); + } // This wrapper function exists because I expect to clone the code in each path + // to be able to optimize each path individually by branching early. This needs + // a compiler or we can do it manually. Helpers that don't need this branching + // live outside of this function. - for (var i = 0; i < newChildren.length; i++) { - var child = newChildren[i]; - knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber); - } + function createChildReconciler(shouldTrackSideEffects) { + function deleteChild(returnFiber, childToDelete) { + if (!shouldTrackSideEffects) { + // Noop. + return; } - var resultingFirstChild = null; - var previousNewFiber = null; - var oldFiber = currentFirstChild; - var lastPlacedIndex = 0; - var newIdx = 0; - var nextOldFiber = null; + var deletions = returnFiber.deletions; - for (; oldFiber !== null && newIdx < newChildren.length; newIdx++) { - if (oldFiber.index > newIdx) { - nextOldFiber = oldFiber; - oldFiber = null; - } else { - nextOldFiber = oldFiber.sibling; - } + if (deletions === null) { + returnFiber.deletions = [childToDelete]; + returnFiber.flags |= ChildDeletion; + } else { + deletions.push(childToDelete); + } + } - var newFiber = updateSlot( - returnFiber, - oldFiber, - newChildren[newIdx], - lanes - ); + function deleteRemainingChildren(returnFiber, currentFirstChild) { + if (!shouldTrackSideEffects) { + // Noop. + return null; + } // TODO: For the shouldClone case, this could be micro-optimized a bit by + // assuming that after the first child we've already added everything. - if (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; - } + var childToDelete = currentFirstChild; - break; - } + while (childToDelete !== null) { + deleteChild(returnFiber, childToDelete); + childToDelete = childToDelete.sibling; + } - if (shouldTrackSideEffects) { - if (oldFiber && newFiber.alternate === null) { - // We matched the slot, but we didn't reuse the existing fiber, so we - // need to delete the existing child. - deleteChild(returnFiber, oldFiber); - } - } + return null; + } - lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); + function mapRemainingChildren(returnFiber, currentFirstChild) { + // Add the remaining children to a temporary map so that we can find them by + // keys quickly. Implicit (null) keys get added to this set with their index + // instead. + var existingChildren = new Map(); + var existingChild = currentFirstChild; - if (previousNewFiber === null) { - // TODO: Move out of the loop. This only happens for the first run. - resultingFirstChild = newFiber; + while (existingChild !== null) { + if (existingChild.key !== null) { + existingChildren.set(existingChild.key, existingChild); } 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; + existingChildren.set(existingChild.index, existingChild); } - previousNewFiber = newFiber; - oldFiber = nextOldFiber; + existingChild = existingChild.sibling; } - if (newIdx === newChildren.length) { - // We've reached the end of the new children. We can delete the rest. - deleteRemainingChildren(returnFiber, oldFiber); + return existingChildren; + } - return resultingFirstChild; - } + function useFiber(fiber, pendingProps) { + // We currently set sibling to null and index to 0 here because it is easy + // to forget to do before returning it. E.g. for the single child case. + var clone = createWorkInProgress(fiber, pendingProps); + clone.index = 0; + clone.sibling = null; + return clone; + } - if (oldFiber === null) { - // If we don't have any more existing children we can choose a fast path - // since the rest will all be insertions. - for (; newIdx < newChildren.length; newIdx++) { - var _newFiber = createChild( - returnFiber, - newChildren[newIdx], - lanes - ); + function placeChild(newFiber, lastPlacedIndex, newIndex) { + newFiber.index = newIndex; - if (_newFiber === null) { - continue; - } + if (!shouldTrackSideEffects) { + // During hydration, the useId algorithm needs to know which fibers are + // part of a list of children (arrays, iterators). + newFiber.flags |= Forked; + return lastPlacedIndex; + } - lastPlacedIndex = placeChild(_newFiber, lastPlacedIndex, newIdx); + var current = newFiber.alternate; - if (previousNewFiber === null) { - // TODO: Move out of the loop. This only happens for the first run. - resultingFirstChild = _newFiber; - } else { - previousNewFiber.sibling = _newFiber; - } + if (current !== null) { + var oldIndex = current.index; - previousNewFiber = _newFiber; + if (oldIndex < lastPlacedIndex) { + // This is a move. + newFiber.flags |= Placement | PlacementDEV; + return lastPlacedIndex; + } else { + // This item can stay in place. + return oldIndex; } + } else { + // This is an insertion. + newFiber.flags |= Placement | PlacementDEV; + return lastPlacedIndex; + } + } - return resultingFirstChild; - } // Add all children to a key map for quick lookups. + function placeSingleChild(newFiber) { + // This is simpler for the single child case. We only need to do a + // placement for inserting new children. + if (shouldTrackSideEffects && newFiber.alternate === null) { + newFiber.flags |= Placement | PlacementDEV; + } - var existingChildren = mapRemainingChildren(returnFiber, oldFiber); // Keep scanning and use the map to restore deleted items as moves. + return newFiber; + } - for (; newIdx < newChildren.length; newIdx++) { - var _newFiber2 = updateFromMap( - existingChildren, - returnFiber, - newIdx, - newChildren[newIdx], + function updateTextNode(returnFiber, current, textContent, lanes) { + if (current === null || current.tag !== HostText) { + // Insert + var created = createFiberFromText( + textContent, + returnFiber.mode, lanes ); + created.return = returnFiber; + return created; + } else { + // Update + var existing = useFiber(current, textContent); + existing.return = returnFiber; + return existing; + } + } - if (_newFiber2 !== null) { - if (shouldTrackSideEffects) { - if (_newFiber2.alternate !== null) { - // The new fiber is a work in progress, but if there exists a - // current, that means that we reused the fiber. We need to delete - // it from the child list so that we don't add it to the deletion - // list. - existingChildren.delete( - _newFiber2.key === null ? newIdx : _newFiber2.key - ); - } - } + function updateElement(returnFiber, current, element, lanes) { + var elementType = element.type; + + if (elementType === REACT_FRAGMENT_TYPE) { + return updateFragment( + returnFiber, + current, + element.props.children, + lanes, + element.key + ); + } - lastPlacedIndex = placeChild(_newFiber2, lastPlacedIndex, newIdx); + if (current !== null) { + if ( + current.elementType === elementType || // Keep this check inline so it only runs on the false path: + isCompatibleFamilyForHotReloading(current, element) || // Lazy types should reconcile their resolved type. + // We need to do this after the Hot Reloading check above, + // because hot reloading has different semantics than prod because + // it doesn't resuspend. So we can't let the call below suspend. + (typeof elementType === "object" && + elementType !== null && + elementType.$$typeof === REACT_LAZY_TYPE && + resolveLazy(elementType) === current.type) + ) { + // Move based on index + var existing = useFiber(current, element.props); + existing.ref = coerceRef(returnFiber, current, element); + existing.return = returnFiber; - if (previousNewFiber === null) { - resultingFirstChild = _newFiber2; - } else { - previousNewFiber.sibling = _newFiber2; + { + existing._debugOwner = element._owner; } - previousNewFiber = _newFiber2; + return existing; } - } + } // Insert - if (shouldTrackSideEffects) { - // Any existing children that weren't consumed above were deleted. We need - // to add them to the deletion list. - existingChildren.forEach(function (child) { - return deleteChild(returnFiber, child); - }); - } + var created = createFiberFromElement(element, returnFiber.mode, lanes); + created.ref = coerceRef(returnFiber, current, element); + created.return = returnFiber; + return created; + } - return resultingFirstChild; + function updatePortal(returnFiber, current, portal, lanes) { + if ( + current === null || + current.tag !== HostPortal || + current.stateNode.containerInfo !== portal.containerInfo || + current.stateNode.implementation !== portal.implementation + ) { + // Insert + var created = createFiberFromPortal(portal, returnFiber.mode, lanes); + created.return = returnFiber; + return created; + } else { + // Update + var existing = useFiber(current, portal.children || []); + existing.return = returnFiber; + return existing; + } } - function reconcileChildrenIterator( - returnFiber, - currentFirstChild, - newChildrenIterable, - lanes - ) { - // This is the same implementation as reconcileChildrenArray(), - // but using the iterator instead. - var iteratorFn = getIteratorFn(newChildrenIterable); + function updateFragment(returnFiber, current, fragment, lanes, key) { + if (current === null || current.tag !== Fragment) { + // Insert + var created = createFiberFromFragment( + fragment, + returnFiber.mode, + lanes, + key + ); + created.return = returnFiber; + return created; + } else { + // Update + var existing = useFiber(current, fragment); + existing.return = returnFiber; + return existing; + } + } - if (typeof iteratorFn !== "function") { - throw new Error( - "An object is not an iterable. This error is likely caused by a bug in " + - "React. Please file an issue." + function createChild(returnFiber, newChild, lanes) { + if ( + (typeof newChild === "string" && newChild !== "") || + typeof newChild === "number" + ) { + // Text nodes don't have keys. If the previous node is implicitly keyed + // we can continue to replace it without aborting even if it is not a text + // node. + var created = createFiberFromText( + "" + newChild, + returnFiber.mode, + lanes ); + created.return = returnFiber; + return created; } - { - // We don't support rendering Generators because it's a mutation. - // See https://github.com/facebook/react/issues/12995 - if ( - typeof Symbol === "function" && // $FlowFixMe[prop-missing] Flow doesn't know about toStringTag - newChildrenIterable[Symbol.toStringTag] === "Generator" - ) { - if (!didWarnAboutGenerators) { - error( - "Using Generators as children is unsupported and will likely yield " + - "unexpected results because enumerating a generator mutates it. " + - "You may convert it to an array with `Array.from()` or the " + - "`[...spread]` operator before rendering. Keep in mind " + - "you might need to polyfill these features for older browsers." + if (typeof newChild === "object" && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: { + var _created = createFiberFromElement( + newChild, + returnFiber.mode, + lanes ); - } - - didWarnAboutGenerators = true; - } // Warn about using Maps as children - if (newChildrenIterable.entries === iteratorFn) { - if (!didWarnAboutMaps) { - error( - "Using Maps as children is not supported. " + - "Use an array of keyed ReactElements instead." - ); + _created.ref = coerceRef(returnFiber, null, newChild); + _created.return = returnFiber; + return _created; } - didWarnAboutMaps = true; - } // First, validate keys. - // We'll get a different iterator later for the main pass. - - var _newChildren = iteratorFn.call(newChildrenIterable); - - if (_newChildren) { - var knownKeys = null; + case REACT_PORTAL_TYPE: { + var _created2 = createFiberFromPortal( + newChild, + returnFiber.mode, + lanes + ); - var _step = _newChildren.next(); + _created2.return = returnFiber; + return _created2; + } - for (; !_step.done; _step = _newChildren.next()) { - var child = _step.value; - knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber); + case REACT_LAZY_TYPE: { + var payload = newChild._payload; + var init = newChild._init; + return createChild(returnFiber, init(payload), lanes); } } - } - var newChildren = iteratorFn.call(newChildrenIterable); - - if (newChildren == null) { - throw new Error("An iterable object provided no iterator."); - } + if (isArray(newChild) || getIteratorFn(newChild)) { + var _created3 = createFiberFromFragment( + newChild, + returnFiber.mode, + lanes, + null + ); - var resultingFirstChild = null; - var previousNewFiber = null; - var oldFiber = currentFirstChild; - var lastPlacedIndex = 0; - var newIdx = 0; - var nextOldFiber = null; - var step = newChildren.next(); + _created3.return = returnFiber; + return _created3; + } // Usable node types + // + // Unwrap the inner value and recursively call this function again. - for ( - ; - oldFiber !== null && !step.done; - newIdx++, step = newChildren.next() - ) { - if (oldFiber.index > newIdx) { - nextOldFiber = oldFiber; - oldFiber = null; - } else { - nextOldFiber = oldFiber.sibling; + if (typeof newChild.then === "function") { + var thenable = newChild; + return createChild(returnFiber, unwrapThenable(thenable), lanes); } - var newFiber = updateSlot(returnFiber, oldFiber, step.value, lanes); + if (newChild.$$typeof === REACT_CONTEXT_TYPE) { + var context = newChild; + return createChild( + returnFiber, + readContextDuringReconcilation(returnFiber, context, lanes), + lanes + ); + } - 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; - } + throwOnInvalidObjectType(returnFiber, newChild); + } - break; + { + if (typeof newChild === "function") { + warnOnFunctionType(returnFiber); } + } - if (shouldTrackSideEffects) { - if (oldFiber && newFiber.alternate === null) { - // We matched the slot, but we didn't reuse the existing fiber, so we - // need to delete the existing child. - deleteChild(returnFiber, oldFiber); - } - } + return null; + } - lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); + function updateSlot(returnFiber, oldFiber, newChild, lanes) { + // Update the fiber if the keys match, otherwise return null. + var key = oldFiber !== null ? oldFiber.key : null; - if (previousNewFiber === null) { - // TODO: Move out of the loop. This only happens for the first run. - resultingFirstChild = newFiber; - } else { - // TODO: Defer siblings if we're not at the right index for this slot. - // I.e. if we had null values before, then we want to defer this - // for each null value. However, we also don't want to call updateSlot - // with the previous one. - previousNewFiber.sibling = newFiber; + if ( + (typeof newChild === "string" && newChild !== "") || + typeof newChild === "number" + ) { + // Text nodes don't have keys. If the previous node is implicitly keyed + // we can continue to replace it without aborting even if it is not a text + // node. + if (key !== null) { + return null; } - previousNewFiber = newFiber; - oldFiber = nextOldFiber; + return updateTextNode(returnFiber, oldFiber, "" + newChild, lanes); } - if (step.done) { - // We've reached the end of the new children. We can delete the rest. - deleteRemainingChildren(returnFiber, oldFiber); + if (typeof newChild === "object" && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: { + if (newChild.key === key) { + return updateElement(returnFiber, oldFiber, newChild, lanes); + } else { + return null; + } + } - return resultingFirstChild; - } + case REACT_PORTAL_TYPE: { + if (newChild.key === key) { + return updatePortal(returnFiber, oldFiber, newChild, lanes); + } else { + return null; + } + } - if (oldFiber === null) { - // If we don't have any more existing children we can choose a fast path - // since the rest will all be insertions. - for (; !step.done; newIdx++, step = newChildren.next()) { - var _newFiber3 = createChild(returnFiber, step.value, lanes); + case REACT_LAZY_TYPE: { + var payload = newChild._payload; + var init = newChild._init; + return updateSlot(returnFiber, oldFiber, init(payload), lanes); + } + } - if (_newFiber3 === null) { - continue; + if (isArray(newChild) || getIteratorFn(newChild)) { + if (key !== null) { + return null; } - lastPlacedIndex = placeChild(_newFiber3, lastPlacedIndex, newIdx); + return updateFragment(returnFiber, oldFiber, newChild, lanes, null); + } // Usable node types + // + // Unwrap the inner value and recursively call this function again. - if (previousNewFiber === null) { - // TODO: Move out of the loop. This only happens for the first run. - resultingFirstChild = _newFiber3; - } else { - previousNewFiber.sibling = _newFiber3; - } + if (typeof newChild.then === "function") { + var thenable = newChild; + return updateSlot( + returnFiber, + oldFiber, + unwrapThenable(thenable), + lanes + ); + } - previousNewFiber = _newFiber3; + if (newChild.$$typeof === REACT_CONTEXT_TYPE) { + var context = newChild; + return updateSlot( + returnFiber, + oldFiber, + readContextDuringReconcilation(returnFiber, context, lanes), + lanes + ); } - return resultingFirstChild; - } // Add all children to a key map for quick lookups. + throwOnInvalidObjectType(returnFiber, newChild); + } - var existingChildren = mapRemainingChildren(returnFiber, oldFiber); // Keep scanning and use the map to restore deleted items as moves. + { + if (typeof newChild === "function") { + warnOnFunctionType(returnFiber); + } + } - for (; !step.done; newIdx++, step = newChildren.next()) { - var _newFiber4 = updateFromMap( - existingChildren, + return null; + } + + function updateFromMap( + existingChildren, + returnFiber, + newIdx, + newChild, + lanes + ) { + if ( + (typeof newChild === "string" && newChild !== "") || + typeof newChild === "number" + ) { + // Text nodes don't have keys, so we neither have to check the old nor + // new node for the key. If both are text nodes, they match. + var matchedFiber = existingChildren.get(newIdx) || null; + return updateTextNode( returnFiber, - newIdx, - step.value, + matchedFiber, + "" + newChild, lanes ); + } - if (_newFiber4 !== null) { - if (shouldTrackSideEffects) { - if (_newFiber4.alternate !== null) { - // The new fiber is a work in progress, but if there exists a - // current, that means that we reused the fiber. We need to delete - // it from the child list so that we don't add it to the deletion - // list. - existingChildren.delete( - _newFiber4.key === null ? newIdx : _newFiber4.key - ); - } + if (typeof newChild === "object" && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: { + var _matchedFiber = + existingChildren.get( + newChild.key === null ? newIdx : newChild.key + ) || null; + + return updateElement(returnFiber, _matchedFiber, newChild, lanes); } - lastPlacedIndex = placeChild(_newFiber4, lastPlacedIndex, newIdx); + case REACT_PORTAL_TYPE: { + var _matchedFiber2 = + existingChildren.get( + newChild.key === null ? newIdx : newChild.key + ) || null; - if (previousNewFiber === null) { - resultingFirstChild = _newFiber4; - } else { - previousNewFiber.sibling = _newFiber4; + return updatePortal(returnFiber, _matchedFiber2, newChild, lanes); } - previousNewFiber = _newFiber4; + case REACT_LAZY_TYPE: + var payload = newChild._payload; + var init = newChild._init; + return updateFromMap( + existingChildren, + returnFiber, + newIdx, + init(payload), + lanes + ); } - } - - 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, - lanes - ) { - // There's no need to check for keys on text nodes since we don't have a - // way to define them. - if (currentFirstChild !== null && currentFirstChild.tag === HostText) { - // We already have an existing node so let's just update it and delete - // the rest. - deleteRemainingChildren(returnFiber, currentFirstChild.sibling); - var existing = useFiber(currentFirstChild, textContent); - existing.return = returnFiber; - return existing; - } // The existing first child is not a text node so we need to create one - // and delete the existing ones. - deleteRemainingChildren(returnFiber, currentFirstChild); - var created = createFiberFromText(textContent, returnFiber.mode, lanes); - created.return = returnFiber; - return created; - } + if (isArray(newChild) || getIteratorFn(newChild)) { + var _matchedFiber3 = existingChildren.get(newIdx) || null; - function reconcileSingleElement( - returnFiber, - currentFirstChild, - element, - lanes - ) { - var key = element.key; - var child = currentFirstChild; + return updateFragment( + returnFiber, + _matchedFiber3, + newChild, + lanes, + null + ); + } // Usable node types + // + // Unwrap the inner value and recursively call this function again. - while (child !== null) { - // TODO: If key === null and child.key === null, then this only applies to - // the first item in the list. - if (child.key === key) { - var elementType = element.type; + if (typeof newChild.then === "function") { + var thenable = newChild; + return updateFromMap( + existingChildren, + returnFiber, + newIdx, + unwrapThenable(thenable), + lanes + ); + } - if (elementType === REACT_FRAGMENT_TYPE) { - if (child.tag === Fragment) { - deleteRemainingChildren(returnFiber, child.sibling); - var existing = useFiber(child, element.props.children); - existing.return = returnFiber; + if (newChild.$$typeof === REACT_CONTEXT_TYPE) { + var context = newChild; + return updateFromMap( + existingChildren, + returnFiber, + newIdx, + readContextDuringReconcilation(returnFiber, context, lanes), + lanes + ); + } - { - existing._debugSource = element._source; - existing._debugOwner = element._owner; - } + throwOnInvalidObjectType(returnFiber, newChild); + } - return existing; - } - } else { - if ( - child.elementType === elementType || // Keep this check inline so it only runs on the false path: - isCompatibleFamilyForHotReloading(child, element) || // Lazy types should reconcile their resolved type. - // We need to do this after the Hot Reloading check above, - // because hot reloading has different semantics than prod because - // it doesn't resuspend. So we can't let the call below suspend. - (typeof elementType === "object" && - elementType !== null && - elementType.$$typeof === REACT_LAZY_TYPE && - resolveLazy(elementType) === child.type) - ) { - deleteRemainingChildren(returnFiber, child.sibling); + { + if (typeof newChild === "function") { + warnOnFunctionType(returnFiber); + } + } - var _existing = useFiber(child, element.props); + return null; + } + /** + * Warns if there is a duplicate or missing key + */ - _existing.ref = coerceRef(returnFiber, child, element); - _existing.return = returnFiber; + function warnOnInvalidKey(child, knownKeys, returnFiber) { + { + if (typeof child !== "object" || child === null) { + return knownKeys; + } - { - _existing._debugSource = element._source; - _existing._debugOwner = element._owner; - } + switch (child.$$typeof) { + case REACT_ELEMENT_TYPE: + case REACT_PORTAL_TYPE: + warnForMissingKey(child, returnFiber); + var key = child.key; - return _existing; + if (typeof key !== "string") { + break; } - } // Didn't match. - - deleteRemainingChildren(returnFiber, child); - break; - } else { - deleteChild(returnFiber, child); - } - child = child.sibling; - } + if (knownKeys === null) { + knownKeys = new Set(); + knownKeys.add(key); + break; + } - if (element.type === REACT_FRAGMENT_TYPE) { - var created = createFiberFromFragment( - element.props.children, - returnFiber.mode, - lanes, - element.key - ); - created.return = returnFiber; - return created; - } else { - var _created4 = createFiberFromElement( - element, - returnFiber.mode, - lanes - ); + if (!knownKeys.has(key)) { + knownKeys.add(key); + break; + } - _created4.ref = coerceRef(returnFiber, currentFirstChild, element); - _created4.return = returnFiber; - return _created4; - } - } + error( + "Encountered two children with the same key, `%s`. " + + "Keys should be unique so that components maintain their identity " + + "across updates. Non-unique keys may cause children to be " + + "duplicated and/or omitted — the behavior is unsupported and " + + "could change in a future version.", + key + ); - function reconcileSinglePortal( - returnFiber, - currentFirstChild, - portal, - lanes - ) { - var key = portal.key; - var child = currentFirstChild; + break; - while (child !== null) { - // TODO: If key === null and child.key === null, then this only applies to - // the first item in the list. - if (child.key === key) { - if ( - child.tag === HostPortal && - child.stateNode.containerInfo === portal.containerInfo && - child.stateNode.implementation === portal.implementation - ) { - deleteRemainingChildren(returnFiber, child.sibling); - var existing = useFiber(child, portal.children || []); - existing.return = returnFiber; - return existing; - } else { - deleteRemainingChildren(returnFiber, child); + case REACT_LAZY_TYPE: + var payload = child._payload; + var init = child._init; + warnOnInvalidKey(init(payload), knownKeys, returnFiber); break; - } - } else { - deleteChild(returnFiber, child); } - - child = child.sibling; } - var created = createFiberFromPortal(portal, returnFiber.mode, lanes); - created.return = returnFiber; - return created; - } // This API will tag the children with the side-effect of the reconciliation - // itself. They will be added to the side-effect list as we pass through the - // children and the parent. + return knownKeys; + } - function reconcileChildFibersImpl( + function reconcileChildrenArray( returnFiber, currentFirstChild, - newChild, + newChildren, lanes ) { - // This function is not recursive. - // If the top level item is an array, we treat it as a set of children, - // not as a fragment. Nested arrays on the other hand will be treated as - // fragment nodes. Recursion happens at the normal flow. - // Handle top level unkeyed fragments as if they were arrays. - // This leads to an ambiguity between <>{[...]} and <>.... - // We treat the ambiguous cases above the same. - // TODO: Let's use recursion like we do for Usable nodes? - var isUnkeyedTopLevelFragment = - typeof newChild === "object" && - newChild !== null && - newChild.type === REACT_FRAGMENT_TYPE && - newChild.key === null; + // This algorithm can't optimize by searching from both ends since we + // don't have backpointers on fibers. I'm trying to see how far we can get + // with that model. If it ends up not being worth the tradeoffs, we can + // add it later. + // Even with a two ended optimization, we'd want to optimize for the case + // where there are few changes and brute force the comparison instead of + // going for the Map. It'd like to explore hitting that path first in + // forward-only mode and only go for the Map once we notice that we need + // lots of look ahead. This doesn't handle reversal as well as two ended + // search but that's unusual. Besides, for the two ended optimization to + // work on Iterables, we'd need to copy the whole set. + // In this first iteration, we'll just live with hitting the bad case + // (adding everything to a Map) in for every insert/move. + // If you change this code, also update reconcileChildrenIterator() which + // uses the same algorithm. + { + // First, validate keys. + var knownKeys = null; - if (isUnkeyedTopLevelFragment) { - newChild = newChild.props.children; - } // Handle object types + for (var i = 0; i < newChildren.length; i++) { + var child = newChildren[i]; + knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber); + } + } - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: - return placeSingleChild( - reconcileSingleElement( - returnFiber, - currentFirstChild, - newChild, - lanes - ) - ); + var resultingFirstChild = null; + var previousNewFiber = null; + var oldFiber = currentFirstChild; + var lastPlacedIndex = 0; + var newIdx = 0; + var nextOldFiber = null; - case REACT_PORTAL_TYPE: - return placeSingleChild( - reconcileSinglePortal( - returnFiber, - currentFirstChild, - newChild, - lanes - ) - ); + for (; oldFiber !== null && newIdx < newChildren.length; newIdx++) { + if (oldFiber.index > newIdx) { + nextOldFiber = oldFiber; + oldFiber = null; + } else { + nextOldFiber = oldFiber.sibling; + } - case REACT_LAZY_TYPE: - var payload = newChild._payload; - var init = newChild._init; // TODO: This function is supposed to be non-recursive. + var newFiber = updateSlot( + returnFiber, + oldFiber, + newChildren[newIdx], + lanes + ); - return reconcileChildFibers( - returnFiber, - currentFirstChild, - init(payload), - lanes - ); - } + if (newFiber === null) { + // TODO: This breaks on empty slots like null children. That's + // unfortunate because it triggers the slow path all the time. We need + // a better way to communicate whether this was a miss or null, + // boolean, undefined, etc. + if (oldFiber === null) { + oldFiber = nextOldFiber; + } - if (isArray(newChild)) { - return reconcileChildrenArray( - returnFiber, - currentFirstChild, - newChild, - lanes - ); + break; } - if (getIteratorFn(newChild)) { - return reconcileChildrenIterator( - returnFiber, - currentFirstChild, - newChild, - lanes - ); - } // Usables are a valid React node type. When React encounters a Usable in - // a child position, it unwraps it using the same algorithm as `use`. For - // example, for promises, React will throw an exception to unwind the - // stack, then replay the component once the promise resolves. - // - // A difference from `use` is that React will keep unwrapping the value - // until it reaches a non-Usable type. - // - // e.g. Usable>> should resolve to T - // - // The structure is a bit unfortunate. Ideally, we shouldn't need to - // replay the entire begin phase of the parent fiber in order to reconcile - // the children again. This would require a somewhat significant refactor, - // because reconcilation happens deep within the begin phase, and - // depending on the type of work, not always at the end. We should - // consider as an future improvement. - - if (typeof newChild.then === "function") { - var thenable = newChild; - return reconcileChildFibersImpl( - returnFiber, - currentFirstChild, - unwrapThenable(thenable), - lanes - ); + if (shouldTrackSideEffects) { + if (oldFiber && newFiber.alternate === null) { + // We matched the slot, but we didn't reuse the existing fiber, so we + // need to delete the existing child. + deleteChild(returnFiber, oldFiber); + } } - if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) { - var context = newChild; - return reconcileChildFibersImpl( - returnFiber, - currentFirstChild, - readContextDuringReconcilation(returnFiber, context, lanes), - lanes - ); + 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; } - throwOnInvalidObjectType(returnFiber, newChild); + previousNewFiber = newFiber; + oldFiber = nextOldFiber; } - if ( - (typeof newChild === "string" && newChild !== "") || - typeof newChild === "number" - ) { - return placeSingleChild( - reconcileSingleTextNode( - returnFiber, - currentFirstChild, - "" + newChild, - lanes - ) - ); - } + if (newIdx === newChildren.length) { + // We've reached the end of the new children. We can delete the rest. + deleteRemainingChildren(returnFiber, oldFiber); - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber); - } - } // Remaining cases are all treated as empty. + return resultingFirstChild; + } - return deleteRemainingChildren(returnFiber, currentFirstChild); - } + if (oldFiber === null) { + // If we don't have any more existing children we can choose a fast path + // since the rest will all be insertions. + for (; newIdx < newChildren.length; newIdx++) { + var _newFiber = createChild( + returnFiber, + newChildren[newIdx], + lanes + ); - function reconcileChildFibers( - returnFiber, - currentFirstChild, - newChild, - lanes - ) { - // This indirection only exists so we can reset `thenableState` at the end. - // It should get inlined by Closure. - thenableIndexCounter$1 = 0; - var firstChildFiber = reconcileChildFibersImpl( - returnFiber, - currentFirstChild, - newChild, - lanes - ); - thenableState$1 = null; // Don't bother to reset `thenableIndexCounter` to 0 because it always gets - // set at the beginning. + if (_newFiber === null) { + continue; + } - return firstChildFiber; - } + lastPlacedIndex = placeChild(_newFiber, lastPlacedIndex, newIdx); - return reconcileChildFibers; - } + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = _newFiber; + } else { + previousNewFiber.sibling = _newFiber; + } - var reconcileChildFibers = createChildReconciler(true); - var mountChildFibers = createChildReconciler(false); - function resetChildReconcilerOnUnwind() { - // On unwind, clear any pending thenables that were used. - thenableState$1 = null; - thenableIndexCounter$1 = 0; - } - function cloneChildFibers(current, workInProgress) { - if (current !== null && workInProgress.child !== current.child) { - throw new Error("Resuming work not yet implemented."); - } + previousNewFiber = _newFiber; + } - if (workInProgress.child === null) { - return; - } + return resultingFirstChild; + } // Add all children to a key map for quick lookups. - var currentChild = workInProgress.child; - var newChild = createWorkInProgress( - currentChild, - currentChild.pendingProps - ); - workInProgress.child = newChild; - newChild.return = workInProgress; + var existingChildren = mapRemainingChildren(returnFiber, oldFiber); // Keep scanning and use the map to restore deleted items as moves. - while (currentChild.sibling !== null) { - currentChild = currentChild.sibling; - newChild = newChild.sibling = createWorkInProgress( - currentChild, - currentChild.pendingProps - ); - newChild.return = workInProgress; - } + for (; newIdx < newChildren.length; newIdx++) { + var _newFiber2 = updateFromMap( + existingChildren, + returnFiber, + newIdx, + newChildren[newIdx], + lanes + ); - newChild.sibling = null; - } // Reset a workInProgress child set to prepare it for a second pass. + if (_newFiber2 !== null) { + if (shouldTrackSideEffects) { + if (_newFiber2.alternate !== null) { + // The new fiber is a work in progress, but if there exists a + // current, that means that we reused the fiber. We need to delete + // it from the child list so that we don't add it to the deletion + // list. + existingChildren.delete( + _newFiber2.key === null ? newIdx : _newFiber2.key + ); + } + } - function resetChildFibers(workInProgress, lanes) { - var child = workInProgress.child; + lastPlacedIndex = placeChild(_newFiber2, lastPlacedIndex, newIdx); - while (child !== null) { - resetWorkInProgress(child, lanes); - child = child.sibling; - } - } + if (previousNewFiber === null) { + resultingFirstChild = _newFiber2; + } else { + previousNewFiber.sibling = _newFiber2; + } - // TODO: This isn't being used yet, but it's intended to replace the - // InvisibleParentContext that is currently managed by SuspenseContext. + previousNewFiber = _newFiber2; + } + } - var currentTreeHiddenStackCursor = createCursor(null); - var prevEntangledRenderLanesCursor = createCursor(NoLanes); - function pushHiddenContext(fiber, context) { - var prevEntangledRenderLanes = getEntangledRenderLanes(); - push(prevEntangledRenderLanesCursor, prevEntangledRenderLanes, fiber); - push(currentTreeHiddenStackCursor, context, fiber); // When rendering a subtree that's currently hidden, we must include all - // lanes that would have rendered if the hidden subtree hadn't been deferred. - // That is, in order to reveal content from hidden -> visible, we must commit - // all the updates that we skipped when we originally hid the tree. + 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); + }); + } - setEntangledRenderLanes( - mergeLanes(prevEntangledRenderLanes, context.baseLanes) - ); - } - function reuseHiddenContextOnStack(fiber) { - // This subtree is not currently hidden, so we don't need to add any lanes - // to the render lanes. But we still need to push something to avoid a - // context mismatch. Reuse the existing context on the stack. - push(prevEntangledRenderLanesCursor, getEntangledRenderLanes(), fiber); - push( - currentTreeHiddenStackCursor, - currentTreeHiddenStackCursor.current, - fiber - ); - } - function popHiddenContext(fiber) { - // Restore the previous render lanes from the stack - setEntangledRenderLanes(prevEntangledRenderLanesCursor.current); - pop(currentTreeHiddenStackCursor, fiber); - pop(prevEntangledRenderLanesCursor, fiber); - } - function isCurrentTreeHidden() { - return currentTreeHiddenStackCursor.current !== null; - } + return resultingFirstChild; + } - // suspends, i.e. it's the nearest `catch` block on the stack. + function reconcileChildrenIterator( + returnFiber, + currentFirstChild, + newChildrenIterable, + lanes + ) { + // This is the same implementation as reconcileChildrenArray(), + // but using the iterator instead. + var iteratorFn = getIteratorFn(newChildrenIterable); - var suspenseHandlerStackCursor = createCursor(null); // Represents the outermost boundary that is not visible in the current tree. - // Everything above this is the "shell". When this is null, it means we're - // rendering in the shell of the app. If it's non-null, it means we're rendering - // deeper than the shell, inside a new tree that wasn't already visible. - // - // The main way we use this concept is to determine whether showing a fallback - // would result in a desirable or undesirable loading state. Activing a fallback - // in the shell is considered an undersirable loading state, because it would - // mean hiding visible (albeit stale) content in the current tree — we prefer to - // show the stale content, rather than switch to a fallback. But showing a - // fallback in a new tree is fine, because there's no stale content to - // prefer instead. + if (typeof iteratorFn !== "function") { + throw new Error( + "An object is not an iterable. This error is likely caused by a bug in " + + "React. Please file an issue." + ); + } - var shellBoundary = null; - function getShellBoundary() { - return shellBoundary; - } - function pushPrimaryTreeSuspenseHandler(handler) { - // TODO: Pass as argument - var current = handler.alternate; - // propagated a single level. For example, when ForceSuspenseFallback is set, - // it should only force the nearest Suspense boundary into fallback mode. + { + // We don't support rendering Generators because it's a mutation. + // See https://github.com/facebook/react/issues/12995 + if ( + typeof Symbol === "function" && // $FlowFixMe[prop-missing] Flow doesn't know about toStringTag + newChildrenIterable[Symbol.toStringTag] === "Generator" + ) { + if (!didWarnAboutGenerators) { + error( + "Using Generators as children is unsupported and will likely yield " + + "unexpected results because enumerating a generator mutates it. " + + "You may convert it to an array with `Array.from()` or the " + + "`[...spread]` operator before rendering. Keep in mind " + + "you might need to polyfill these features for older browsers." + ); + } - pushSuspenseListContext( - handler, - setDefaultShallowSuspenseListContext(suspenseStackCursor.current) - ); // Experimental feature: Some Suspense boundaries are marked as having an - // to push a nested Suspense handler, because it will get replaced by the - // outer fallback, anyway. Consider this as a future optimization. + didWarnAboutGenerators = true; + } // Warn about using Maps as children - push(suspenseHandlerStackCursor, handler, handler); + if (newChildrenIterable.entries === iteratorFn) { + if (!didWarnAboutMaps) { + error( + "Using Maps as children is not supported. " + + "Use an array of keyed ReactElements instead." + ); + } - if (shellBoundary === null) { - if (current === null || isCurrentTreeHidden()) { - // This boundary is not visible in the current UI. - shellBoundary = handler; - } else { - var prevState = current.memoizedState; + didWarnAboutMaps = true; + } // First, validate keys. + // We'll get a different iterator later for the main pass. - if (prevState !== null) { - // This boundary is showing a fallback in the current UI. - shellBoundary = handler; - } - } - } - } - function pushFallbackTreeSuspenseHandler(fiber) { - // We're about to render the fallback. If something in the fallback suspends, - // it's akin to throwing inside of a `catch` block. This boundary should not - // capture. Reuse the existing handler on the stack. - reuseSuspenseHandlerOnStack(fiber); - } - function pushOffscreenSuspenseHandler(fiber) { - if (fiber.tag === OffscreenComponent) { - // A SuspenseList context is only pushed here to avoid a push/pop mismatch. - // Reuse the current value on the stack. - // TODO: We can avoid needing to push here by by forking popSuspenseHandler - // into separate functions for Suspense and Offscreen. - pushSuspenseListContext(fiber, suspenseStackCursor.current); - push(suspenseHandlerStackCursor, fiber, fiber); + var _newChildren = iteratorFn.call(newChildrenIterable); - if (shellBoundary !== null); - else { - var current = fiber.alternate; + if (_newChildren) { + var knownKeys = null; - if (current !== null) { - var prevState = current.memoizedState; + var _step = _newChildren.next(); - if (prevState !== null) { - // This is the first boundary in the stack that's already showing - // a fallback. So everything outside is considered the shell. - shellBoundary = fiber; + for (; !_step.done; _step = _newChildren.next()) { + var child = _step.value; + knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber); } } } - } else { - // This is a LegacyHidden component. - reuseSuspenseHandlerOnStack(fiber); - } - } - function reuseSuspenseHandlerOnStack(fiber) { - pushSuspenseListContext(fiber, suspenseStackCursor.current); - push(suspenseHandlerStackCursor, getSuspenseHandler(), fiber); - } - function getSuspenseHandler() { - return suspenseHandlerStackCursor.current; - } - function popSuspenseHandler(fiber) { - pop(suspenseHandlerStackCursor, fiber); - if (shellBoundary === fiber) { - // Popping back into the shell. - shellBoundary = null; - } - - popSuspenseListContext(fiber); - } // SuspenseList context - // TODO: Move to a separate module? We may change the SuspenseList - // implementation to hide/show in the commit phase, anyway. + var newChildren = iteratorFn.call(newChildrenIterable); - var DefaultSuspenseContext = 0; - var SubtreeSuspenseContextMask = 1; // ForceSuspenseFallback can be used by SuspenseList to force newly added - // items into their fallback state during one of the render passes. + if (newChildren == null) { + throw new Error("An iterable object provided no iterator."); + } - var ForceSuspenseFallback = 2; - var suspenseStackCursor = createCursor(DefaultSuspenseContext); - function hasSuspenseListContext(parentContext, flag) { - return (parentContext & flag) !== 0; - } - function setDefaultShallowSuspenseListContext(parentContext) { - return parentContext & SubtreeSuspenseContextMask; - } - function setShallowSuspenseListContext(parentContext, shallowContext) { - return (parentContext & SubtreeSuspenseContextMask) | shallowContext; - } - function pushSuspenseListContext(fiber, newContext) { - push(suspenseStackCursor, newContext, fiber); - } - function popSuspenseListContext(fiber) { - pop(suspenseStackCursor, fiber); - } + var resultingFirstChild = null; + var previousNewFiber = null; + var oldFiber = currentFirstChild; + var lastPlacedIndex = 0; + var newIdx = 0; + var nextOldFiber = null; + var step = newChildren.next(); - // A non-null SuspenseState means that it is blocked for one reason or another. - // - A non-null dehydrated field means it's blocked pending hydration. - // - A non-null dehydrated field can use isSuspenseInstancePending or - // isSuspenseInstanceFallback to query the reason for being dehydrated. - // - A null dehydrated field means it's blocked by something suspending and - // we're currently showing a fallback instead. + for ( + ; + oldFiber !== null && !step.done; + newIdx++, step = newChildren.next() + ) { + if (oldFiber.index > newIdx) { + nextOldFiber = oldFiber; + oldFiber = null; + } else { + nextOldFiber = oldFiber.sibling; + } - function findFirstSuspended(row) { - var node = row; + var newFiber = updateSlot(returnFiber, oldFiber, step.value, lanes); - while (node !== null) { - if (node.tag === SuspenseComponent) { - var state = node.memoizedState; + if (newFiber === null) { + // TODO: This breaks on empty slots like null children. That's + // unfortunate because it triggers the slow path all the time. We need + // a better way to communicate whether this was a miss or null, + // boolean, undefined, etc. + if (oldFiber === null) { + oldFiber = nextOldFiber; + } - if (state !== null) { - var dehydrated = state.dehydrated; + break; + } - if ( - dehydrated === null || - isSuspenseInstancePending() || - isSuspenseInstanceFallback() - ) { - return node; + 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); } } - } else if ( - node.tag === SuspenseListComponent && // revealOrder undefined can't be trusted because it don't - // keep track of whether it suspended or not. - node.memoizedProps.revealOrder !== undefined - ) { - var didSuspend = (node.flags & DidCapture) !== NoFlags$1; - if (didSuspend) { - return node; + 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; } - } else if (node.child !== null) { - node.child.return = node; - node = node.child; - continue; - } - if (node === row) { - return null; + previousNewFiber = newFiber; + oldFiber = nextOldFiber; } - while (node.sibling === null) { - if (node.return === null || node.return === row) { - return null; - } + if (step.done) { + // We've reached the end of the new children. We can delete the rest. + deleteRemainingChildren(returnFiber, oldFiber); - node = node.return; + return resultingFirstChild; } - node.sibling.return = node.return; - node = node.sibling; - } + if (oldFiber === null) { + // If we don't have any more existing children we can choose a fast path + // since the rest will all be insertions. + for (; !step.done; newIdx++, step = newChildren.next()) { + var _newFiber3 = createChild(returnFiber, step.value, lanes); - return null; - } + if (_newFiber3 === null) { + continue; + } - var NoFlags = - /* */ - 0; // Represents whether effect should fire. + lastPlacedIndex = placeChild(_newFiber3, lastPlacedIndex, newIdx); - var HasEffect = - /* */ - 1; // Represents the phase in which the effect (not the clean-up) fires. + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = _newFiber3; + } else { + previousNewFiber.sibling = _newFiber3; + } - var Insertion = - /* */ - 2; - var Layout = - /* */ - 4; - var Passive = - /* */ - 8; + previousNewFiber = _newFiber3; + } - var ReactCurrentActQueue$2 = ReactSharedInternals.ReactCurrentActQueue; // A linked list of all the roots with pending work. In an idiomatic app, - // there's only a single root, but we do support multi root apps, hence this - // extra complexity. But this module is optimized for the single root case. + return resultingFirstChild; + } // Add all children to a key map for quick lookups. - var firstScheduledRoot = null; - var lastScheduledRoot = null; // Used to prevent redundant mircotasks from being scheduled. + var existingChildren = mapRemainingChildren(returnFiber, oldFiber); // Keep scanning and use the map to restore deleted items as moves. - var didScheduleMicrotask = false; // `act` "microtasks" are scheduled on the `act` queue instead of an actual - // microtask, so we have to dedupe those separately. This wouldn't be an issue - // if we required all `act` calls to be awaited, which we might in the future. + for (; !step.done; newIdx++, step = newChildren.next()) { + var _newFiber4 = updateFromMap( + existingChildren, + returnFiber, + newIdx, + step.value, + lanes + ); - var didScheduleMicrotask_act = false; // Used to quickly bail out of flushSync if there's no sync work to do. + 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 + ); + } + } - var mightHavePendingSyncWork = false; - var isFlushingWork = false; - var currentEventTransitionLane = NoLane; - function ensureRootIsScheduled(root) { - // This function is called whenever a root receives an update. It does two - // things 1) it ensures the root is in the root schedule, and 2) it ensures - // there's a pending microtask to process the root schedule. - // - // Most of the actual scheduling logic does not happen until - // `scheduleTaskForRootDuringMicrotask` runs. - // Add the root to the schedule - if (root === lastScheduledRoot || root.next !== null); - else { - if (lastScheduledRoot === null) { - firstScheduledRoot = lastScheduledRoot = root; - } else { - lastScheduledRoot.next = root; - lastScheduledRoot = root; - } - } // Any time a root received an update, we set this to true until the next time - // we process the schedule. If it's false, then we can quickly exit flushSync - // without consulting the schedule. + lastPlacedIndex = placeChild(_newFiber4, lastPlacedIndex, newIdx); - mightHavePendingSyncWork = true; // At the end of the current event, go through each of the roots and ensure - // there's a task scheduled for each one at the correct priority. + if (previousNewFiber === null) { + resultingFirstChild = _newFiber4; + } else { + previousNewFiber.sibling = _newFiber4; + } - if (ReactCurrentActQueue$2.current !== null) { - // We're inside an `act` scope. - if (!didScheduleMicrotask_act) { - didScheduleMicrotask_act = true; - scheduleImmediateTask(processRootScheduleInMicrotask); + previousNewFiber = _newFiber4; + } } - } else { - if (!didScheduleMicrotask) { - didScheduleMicrotask = true; - scheduleImmediateTask(processRootScheduleInMicrotask); + + if (shouldTrackSideEffects) { + // Any existing children that weren't consumed above were deleted. We need + // to add them to the deletion list. + existingChildren.forEach(function (child) { + return deleteChild(returnFiber, child); + }); } - } - if (ReactCurrentActQueue$2.isBatchingLegacy && root.tag === LegacyRoot) { - // Special `act` case: Record whenever a legacy update is scheduled. - ReactCurrentActQueue$2.didScheduleLegacyUpdate = true; + return resultingFirstChild; } - } - function flushSyncWorkOnAllRoots() { - // This is allowed to be called synchronously, but the caller should check - // the execution context first. - flushSyncWorkAcrossRoots_impl(false); - } - function flushSyncWorkOnLegacyRootsOnly() { - // This is allowed to be called synchronously, but the caller should check - // the execution context first. - flushSyncWorkAcrossRoots_impl(true); - } - function flushSyncWorkAcrossRoots_impl(onlyLegacy) { - if (isFlushingWork) { - // Prevent reentrancy. - // TODO: Is this overly defensive? The callers must check the execution - // context first regardless. - return; + function reconcileSingleTextNode( + returnFiber, + currentFirstChild, + textContent, + lanes + ) { + // There's no need to check for keys on text nodes since we don't have a + // way to define them. + if (currentFirstChild !== null && currentFirstChild.tag === HostText) { + // We already have an existing node so let's just update it and delete + // the rest. + deleteRemainingChildren(returnFiber, currentFirstChild.sibling); + var existing = useFiber(currentFirstChild, textContent); + existing.return = returnFiber; + return existing; + } // The existing first child is not a text node so we need to create one + // and delete the existing ones. + + deleteRemainingChildren(returnFiber, currentFirstChild); + var created = createFiberFromText(textContent, returnFiber.mode, lanes); + created.return = returnFiber; + return created; } - if (!mightHavePendingSyncWork) { - // Fast path. There's no sync work to do. - return; - } // There may or may not be synchronous work scheduled. Let's check. + function reconcileSingleElement( + returnFiber, + currentFirstChild, + element, + lanes + ) { + var key = element.key; + var child = currentFirstChild; - var didPerformSomeWork; - var errors = null; - isFlushingWork = true; + while (child !== null) { + // TODO: If key === null and child.key === null, then this only applies to + // the first item in the list. + if (child.key === key) { + var elementType = element.type; - do { - didPerformSomeWork = false; - var root = firstScheduledRoot; + if (elementType === REACT_FRAGMENT_TYPE) { + if (child.tag === Fragment) { + deleteRemainingChildren(returnFiber, child.sibling); + var existing = useFiber(child, element.props.children); + existing.return = returnFiber; - while (root !== null) { - if (onlyLegacy && root.tag !== LegacyRoot); - else { - var workInProgressRoot = getWorkInProgressRoot(); - var workInProgressRootRenderLanes = - getWorkInProgressRootRenderLanes(); - var nextLanes = getNextLanes( - root, - root === workInProgressRoot - ? workInProgressRootRenderLanes - : NoLanes - ); + { + existing._debugOwner = element._owner; + } - if (includesSyncLane(nextLanes)) { - // This root has pending sync work. Flush it now. - try { - didPerformSomeWork = true; - performSyncWorkOnRoot(root, nextLanes); - } catch (error) { - // Collect errors so we can rethrow them at the end - if (errors === null) { - errors = [error]; - } else { - errors.push(error); + return existing; + } + } else { + if ( + child.elementType === elementType || // Keep this check inline so it only runs on the false path: + isCompatibleFamilyForHotReloading(child, element) || // Lazy types should reconcile their resolved type. + // We need to do this after the Hot Reloading check above, + // because hot reloading has different semantics than prod because + // it doesn't resuspend. So we can't let the call below suspend. + (typeof elementType === "object" && + elementType !== null && + elementType.$$typeof === REACT_LAZY_TYPE && + resolveLazy(elementType) === child.type) + ) { + deleteRemainingChildren(returnFiber, child.sibling); + + var _existing = useFiber(child, element.props); + + _existing.ref = coerceRef(returnFiber, child, element); + _existing.return = returnFiber; + + { + _existing._debugOwner = element._owner; } + + return _existing; } - } + } // Didn't match. + + deleteRemainingChildren(returnFiber, child); + break; + } else { + deleteChild(returnFiber, child); } - root = root.next; + child = child.sibling; } - } while (didPerformSomeWork); - isFlushingWork = false; // If any errors were thrown, rethrow them right before exiting. - // TODO: Consider returning these to the caller, to allow them to decide - // how/when to rethrow. + if (element.type === REACT_FRAGMENT_TYPE) { + var created = createFiberFromFragment( + element.props.children, + returnFiber.mode, + lanes, + element.key + ); + created.return = returnFiber; + return created; + } else { + var _created4 = createFiberFromElement( + element, + returnFiber.mode, + lanes + ); - if (errors !== null) { - if (errors.length > 1) { - if (typeof AggregateError === "function") { - // eslint-disable-next-line no-undef - throw new AggregateError(errors); - } else { - for (var i = 1; i < errors.length; i++) { - scheduleImmediateTask(throwError.bind(null, errors[i])); - } + _created4.ref = coerceRef(returnFiber, currentFirstChild, element); + _created4.return = returnFiber; + return _created4; + } + } - var firstError = errors[0]; - throw firstError; + function reconcileSinglePortal( + returnFiber, + currentFirstChild, + portal, + lanes + ) { + var key = portal.key; + var child = currentFirstChild; + + while (child !== null) { + // TODO: If key === null and child.key === null, then this only applies to + // the first item in the list. + if (child.key === key) { + if ( + child.tag === HostPortal && + child.stateNode.containerInfo === portal.containerInfo && + child.stateNode.implementation === portal.implementation + ) { + deleteRemainingChildren(returnFiber, child.sibling); + var existing = useFiber(child, portal.children || []); + existing.return = returnFiber; + return existing; + } else { + deleteRemainingChildren(returnFiber, child); + break; + } + } else { + deleteChild(returnFiber, child); } - } else { - var error = errors[0]; - throw error; - } - } - } - - function throwError(error) { - throw error; - } - function processRootScheduleInMicrotask() { - // This function is always called inside a microtask. It should never be - // called synchronously. - didScheduleMicrotask = false; + child = child.sibling; + } - { - didScheduleMicrotask_act = false; - } // We'll recompute this as we iterate through all the roots and schedule them. + var created = createFiberFromPortal(portal, returnFiber.mode, lanes); + created.return = returnFiber; + return created; + } // This API will tag the children with the side-effect of the reconciliation + // itself. They will be added to the side-effect list as we pass through the + // children and the parent. - mightHavePendingSyncWork = false; - var currentTime = now$1(); - var prev = null; - var root = firstScheduledRoot; + function reconcileChildFibersImpl( + returnFiber, + currentFirstChild, + newChild, + lanes + ) { + // This function is not recursive. + // If the top level item is an array, we treat it as a set of children, + // not as a fragment. Nested arrays on the other hand will be treated as + // fragment nodes. Recursion happens at the normal flow. + // Handle top level unkeyed fragments as if they were arrays. + // This leads to an ambiguity between <>{[...]} and <>.... + // We treat the ambiguous cases above the same. + // TODO: Let's use recursion like we do for Usable nodes? + var isUnkeyedTopLevelFragment = + typeof newChild === "object" && + newChild !== null && + newChild.type === REACT_FRAGMENT_TYPE && + newChild.key === null; - while (root !== null) { - var next = root.next; + if (isUnkeyedTopLevelFragment) { + newChild = newChild.props.children; + } // Handle object types - if ( - currentEventTransitionLane !== NoLane && - shouldAttemptEagerTransition() - ) { - // A transition was scheduled during an event, but we're going to try to - // render it synchronously anyway. We do this during a popstate event to - // preserve the scroll position of the previous page. - upgradePendingLaneToSync(root, currentEventTransitionLane); - } + if (typeof newChild === "object" && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return placeSingleChild( + reconcileSingleElement( + returnFiber, + currentFirstChild, + newChild, + lanes + ) + ); - var nextLanes = scheduleTaskForRootDuringMicrotask(root, currentTime); + case REACT_PORTAL_TYPE: + return placeSingleChild( + reconcileSinglePortal( + returnFiber, + currentFirstChild, + newChild, + lanes + ) + ); - if (nextLanes === NoLane) { - // This root has no more pending work. Remove it from the schedule. To - // guard against subtle reentrancy bugs, this microtask is the only place - // we do this — you can add roots to the schedule whenever, but you can - // only remove them here. - // Null this out so we know it's been removed from the schedule. - root.next = null; + case REACT_LAZY_TYPE: + var payload = newChild._payload; + var init = newChild._init; // TODO: This function is supposed to be non-recursive. - if (prev === null) { - // This is the new head of the list - firstScheduledRoot = next; - } else { - prev.next = next; + return reconcileChildFibers( + returnFiber, + currentFirstChild, + init(payload), + lanes + ); } - if (next === null) { - // This is the new tail of the list - lastScheduledRoot = prev; + if (isArray(newChild)) { + return reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChild, + lanes + ); } - } else { - // This root still has work. Keep it in the list. - prev = root; - if (includesSyncLane(nextLanes)) { - mightHavePendingSyncWork = true; + if (getIteratorFn(newChild)) { + return reconcileChildrenIterator( + returnFiber, + currentFirstChild, + newChild, + lanes + ); + } // Usables are a valid React node type. When React encounters a Usable in + // a child position, it unwraps it using the same algorithm as `use`. For + // example, for promises, React will throw an exception to unwind the + // stack, then replay the component once the promise resolves. + // + // A difference from `use` is that React will keep unwrapping the value + // until it reaches a non-Usable type. + // + // e.g. Usable>> should resolve to T + // + // The structure is a bit unfortunate. Ideally, we shouldn't need to + // replay the entire begin phase of the parent fiber in order to reconcile + // the children again. This would require a somewhat significant refactor, + // because reconcilation happens deep within the begin phase, and + // depending on the type of work, not always at the end. We should + // consider as an future improvement. + + if (typeof newChild.then === "function") { + var thenable = newChild; + return reconcileChildFibersImpl( + returnFiber, + currentFirstChild, + unwrapThenable(thenable), + lanes + ); } - } - root = next; - } + if (newChild.$$typeof === REACT_CONTEXT_TYPE) { + var context = newChild; + return reconcileChildFibersImpl( + returnFiber, + currentFirstChild, + readContextDuringReconcilation(returnFiber, context, lanes), + lanes + ); + } - currentEventTransitionLane = NoLane; // At the end of the microtask, flush any pending synchronous work. This has - // to come at the end, because it does actual rendering work that might throw. + throwOnInvalidObjectType(returnFiber, newChild); + } - flushSyncWorkOnAllRoots(); - } + if ( + (typeof newChild === "string" && newChild !== "") || + typeof newChild === "number" + ) { + return placeSingleChild( + reconcileSingleTextNode( + returnFiber, + currentFirstChild, + "" + newChild, + lanes + ) + ); + } - function scheduleTaskForRootDuringMicrotask(root, currentTime) { - // This function is always called inside a microtask, or at the very end of a - // rendering task right before we yield to the main thread. It should never be - // called synchronously. - // - // TODO: Unless enableDeferRootSchedulingToMicrotask is off. We need to land - // that ASAP to unblock additional features we have planned. - // - // This function also never performs React work synchronously; it should - // only schedule work to be performed later, in a separate task or microtask. - // Check if any lanes are being starved by other work. If so, mark them as - // expired so we know to work on those next. - markStarvedLanesAsExpired(root, currentTime); // Determine the next lanes to work on, and their priority. + { + if (typeof newChild === "function") { + warnOnFunctionType(returnFiber); + } + } // Remaining cases are all treated as empty. - var workInProgressRoot = getWorkInProgressRoot(); - var workInProgressRootRenderLanes = getWorkInProgressRootRenderLanes(); - var nextLanes = getNextLanes( - root, - root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes - ); - var existingCallbackNode = root.callbackNode; + return deleteRemainingChildren(returnFiber, currentFirstChild); + } - if ( - // Check if there's nothing to work on - nextLanes === NoLanes || // If this root is currently suspended and waiting for data to resolve, don't - // schedule a task to render it. We'll either wait for a ping, or wait to - // receive an update. - // - // Suspended render phase - (root === workInProgressRoot && isWorkLoopSuspendedOnData()) || // Suspended commit phase - root.cancelPendingCommit !== null + function reconcileChildFibers( + returnFiber, + currentFirstChild, + newChild, + lanes ) { - // Fast path: There's nothing to work on. - if (existingCallbackNode !== null) { - cancelCallback(existingCallbackNode); - } - - root.callbackNode = null; - root.callbackPriority = NoLane; - return NoLane; - } // Schedule a new callback in the host environment. - - if (includesSyncLane(nextLanes)) { - // Synchronous work is always flushed at the end of the microtask, so we - // don't need to schedule an additional task. - if (existingCallbackNode !== null) { - cancelCallback(existingCallbackNode); - } + // This indirection only exists so we can reset `thenableState` at the end. + // It should get inlined by Closure. + thenableIndexCounter$1 = 0; + var firstChildFiber = reconcileChildFibersImpl( + returnFiber, + currentFirstChild, + newChild, + lanes + ); + thenableState$1 = null; // Don't bother to reset `thenableIndexCounter` to 0 because it always gets + // set at the beginning. - root.callbackPriority = SyncLane; - root.callbackNode = null; - return SyncLane; - } else { - // We use the highest priority lane to represent the priority of the callback. - var existingCallbackPriority = root.callbackPriority; - var newCallbackPriority = getHighestPriorityLane(nextLanes); + return firstChildFiber; + } - if ( - newCallbackPriority === existingCallbackPriority && // Special case related to `act`. If the currently scheduled task is a - // Scheduler task, rather than an `act` task, cancel it and re-schedule - // on the `act` queue. - !( - ReactCurrentActQueue$2.current !== null && - existingCallbackNode !== fakeActCallbackNode$1 - ) - ) { - // The priority hasn't changed. We can reuse the existing task. - return newCallbackPriority; - } else { - // Cancel the existing callback. We'll schedule a new one below. - cancelCallback(existingCallbackNode); - } + return reconcileChildFibers; + } - var schedulerPriorityLevel; + var reconcileChildFibers = createChildReconciler(true); + var mountChildFibers = createChildReconciler(false); + function resetChildReconcilerOnUnwind() { + // On unwind, clear any pending thenables that were used. + thenableState$1 = null; + thenableIndexCounter$1 = 0; + } + function cloneChildFibers(current, workInProgress) { + if (current !== null && workInProgress.child !== current.child) { + throw new Error("Resuming work not yet implemented."); + } - switch (lanesToEventPriority(nextLanes)) { - case DiscreteEventPriority: - schedulerPriorityLevel = ImmediatePriority; - break; + if (workInProgress.child === null) { + return; + } - case ContinuousEventPriority: - schedulerPriorityLevel = UserBlockingPriority; - break; + var currentChild = workInProgress.child; + var newChild = createWorkInProgress( + currentChild, + currentChild.pendingProps + ); + workInProgress.child = newChild; + newChild.return = workInProgress; - case DefaultEventPriority: - schedulerPriorityLevel = NormalPriority; - break; + while (currentChild.sibling !== null) { + currentChild = currentChild.sibling; + newChild = newChild.sibling = createWorkInProgress( + currentChild, + currentChild.pendingProps + ); + newChild.return = workInProgress; + } - case IdleEventPriority: - schedulerPriorityLevel = IdlePriority; - break; + newChild.sibling = null; + } // Reset a workInProgress child set to prepare it for a second pass. - default: - schedulerPriorityLevel = NormalPriority; - break; - } + function resetChildFibers(workInProgress, lanes) { + var child = workInProgress.child; - var newCallbackNode = scheduleCallback$1( - schedulerPriorityLevel, - performConcurrentWorkOnRoot.bind(null, root) - ); - root.callbackPriority = newCallbackPriority; - root.callbackNode = newCallbackNode; - return newCallbackPriority; + while (child !== null) { + resetWorkInProgress(child, lanes); + child = child.sibling; } } - function getContinuationForRoot(root, originalCallbackNode) { - // This is called at the end of `performConcurrentWorkOnRoot` to determine - // if we need to schedule a continuation task. - // - // Usually `scheduleTaskForRootDuringMicrotask` only runs inside a microtask; - // however, since most of the logic for determining if we need a continuation - // versus a new task is the same, we cheat a bit and call it here. This is - // only safe to do because we know we're at the end of the browser task. - // So although it's not an actual microtask, it might as well be. - scheduleTaskForRootDuringMicrotask(root, now$1()); + // TODO: This isn't being used yet, but it's intended to replace the + // InvisibleParentContext that is currently managed by SuspenseContext. - if (root.callbackNode === originalCallbackNode) { - // The task node scheduled for this root is the same one that's - // currently executed. Need to return a continuation. - return performConcurrentWorkOnRoot.bind(null, root); - } + var currentTreeHiddenStackCursor = createCursor(null); + var prevEntangledRenderLanesCursor = createCursor(NoLanes); + function pushHiddenContext(fiber, context) { + var prevEntangledRenderLanes = getEntangledRenderLanes(); + push(prevEntangledRenderLanesCursor, prevEntangledRenderLanes, fiber); + push(currentTreeHiddenStackCursor, context, fiber); // When rendering a subtree that's currently hidden, we must include all + // lanes that would have rendered if the hidden subtree hadn't been deferred. + // That is, in order to reveal content from hidden -> visible, we must commit + // all the updates that we skipped when we originally hid the tree. - return null; + setEntangledRenderLanes( + mergeLanes(prevEntangledRenderLanes, context.baseLanes) + ); + } + function reuseHiddenContextOnStack(fiber) { + // This subtree is not currently hidden, so we don't need to add any lanes + // to the render lanes. But we still need to push something to avoid a + // context mismatch. Reuse the existing context on the stack. + push(prevEntangledRenderLanesCursor, getEntangledRenderLanes(), fiber); + push( + currentTreeHiddenStackCursor, + currentTreeHiddenStackCursor.current, + fiber + ); + } + function popHiddenContext(fiber) { + // Restore the previous render lanes from the stack + setEntangledRenderLanes(prevEntangledRenderLanesCursor.current); + pop(currentTreeHiddenStackCursor, fiber); + pop(prevEntangledRenderLanesCursor, fiber); + } + function isCurrentTreeHidden() { + return currentTreeHiddenStackCursor.current !== null; } - var fakeActCallbackNode$1 = {}; - function scheduleCallback$1(priorityLevel, callback) { - if (ReactCurrentActQueue$2.current !== null) { - // Special case: We're inside an `act` scope (a testing utility). - // Instead of scheduling work in the host environment, add it to a - // fake internal queue that's managed by the `act` implementation. - ReactCurrentActQueue$2.current.push(callback); - return fakeActCallbackNode$1; - } else { - return scheduleCallback$2(priorityLevel, callback); - } + // suspends, i.e. it's the nearest `catch` block on the stack. + + var suspenseHandlerStackCursor = createCursor(null); // Represents the outermost boundary that is not visible in the current tree. + // Everything above this is the "shell". When this is null, it means we're + // rendering in the shell of the app. If it's non-null, it means we're rendering + // deeper than the shell, inside a new tree that wasn't already visible. + // + // The main way we use this concept is to determine whether showing a fallback + // would result in a desirable or undesirable loading state. Activing a fallback + // in the shell is considered an undersirable loading state, because it would + // mean hiding visible (albeit stale) content in the current tree — we prefer to + // show the stale content, rather than switch to a fallback. But showing a + // fallback in a new tree is fine, because there's no stale content to + // prefer instead. + + var shellBoundary = null; + function getShellBoundary() { + return shellBoundary; } + function pushPrimaryTreeSuspenseHandler(handler) { + // TODO: Pass as argument + var current = handler.alternate; + // propagated a single level. For example, when ForceSuspenseFallback is set, + // it should only force the nearest Suspense boundary into fallback mode. - function cancelCallback(callbackNode) { - if (callbackNode === fakeActCallbackNode$1); - else if (callbackNode !== null) { - cancelCallback$1(callbackNode); + pushSuspenseListContext( + handler, + setDefaultShallowSuspenseListContext(suspenseStackCursor.current) + ); // Experimental feature: Some Suspense boundaries are marked as having an + // to push a nested Suspense handler, because it will get replaced by the + // outer fallback, anyway. Consider this as a future optimization. + + push(suspenseHandlerStackCursor, handler, handler); + + if (shellBoundary === null) { + if (current === null || isCurrentTreeHidden()) { + // This boundary is not visible in the current UI. + shellBoundary = handler; + } else { + var prevState = current.memoizedState; + + if (prevState !== null) { + // This boundary is showing a fallback in the current UI. + shellBoundary = handler; + } + } } } + function pushFallbackTreeSuspenseHandler(fiber) { + // We're about to render the fallback. If something in the fallback suspends, + // it's akin to throwing inside of a `catch` block. This boundary should not + // capture. Reuse the existing handler on the stack. + reuseSuspenseHandlerOnStack(fiber); + } + function pushOffscreenSuspenseHandler(fiber) { + if (fiber.tag === OffscreenComponent) { + // A SuspenseList context is only pushed here to avoid a push/pop mismatch. + // Reuse the current value on the stack. + // TODO: We can avoid needing to push here by by forking popSuspenseHandler + // into separate functions for Suspense and Offscreen. + pushSuspenseListContext(fiber, suspenseStackCursor.current); + push(suspenseHandlerStackCursor, fiber, fiber); - function scheduleImmediateTask(cb) { - if (ReactCurrentActQueue$2.current !== null) { - // Special case: Inside an `act` scope, we push microtasks to the fake `act` - // callback queue. This is because we currently support calling `act` - // without awaiting the result. The plan is to deprecate that, and require - // that you always await the result so that the microtasks have a chance to - // run. But it hasn't happened yet. - ReactCurrentActQueue$2.current.push(function () { - cb(); - return null; - }); - } // TODO: Can we land supportsMicrotasks? Which environments don't support it? - // Alternatively, can we move this check to the host config? + if (shellBoundary !== null); + else { + var current = fiber.alternate; - { - // If microtasks are not supported, use Scheduler. - scheduleCallback$2(ImmediatePriority, cb); + if (current !== null) { + var prevState = current.memoizedState; + + if (prevState !== null) { + // This is the first boundary in the stack that's already showing + // a fallback. So everything outside is considered the shell. + shellBoundary = fiber; + } + } + } + } else { + // This is a LegacyHidden component. + reuseSuspenseHandlerOnStack(fiber); } } + function reuseSuspenseHandlerOnStack(fiber) { + pushSuspenseListContext(fiber, suspenseStackCursor.current); + push(suspenseHandlerStackCursor, getSuspenseHandler(), fiber); + } + function getSuspenseHandler() { + return suspenseHandlerStackCursor.current; + } + function popSuspenseHandler(fiber) { + pop(suspenseHandlerStackCursor, fiber); - function requestTransitionLane() { - // The algorithm for assigning an update to a lane should be stable for all - // updates at the same priority within the same event. To do this, the - // inputs to the algorithm must be the same. - // - // The trick we use is to cache the first of each of these inputs within an - // event. Then reset the cached values once we can be sure the event is - // over. Our heuristic for that is whenever we enter a concurrent work loop. - if (currentEventTransitionLane === NoLane) { - // All transitions within the same event are assigned the same lane. - currentEventTransitionLane = claimNextTransitionLane(); + if (shellBoundary === fiber) { + // Popping back into the shell. + shellBoundary = null; } - return currentEventTransitionLane; - } + popSuspenseListContext(fiber); + } // SuspenseList context + // TODO: Move to a separate module? We may change the SuspenseList + // implementation to hide/show in the commit phase, anyway. + + var DefaultSuspenseContext = 0; + var SubtreeSuspenseContextMask = 1; // ForceSuspenseFallback can be used by SuspenseList to force newly added + // items into their fallback state during one of the render passes. - // transition updates that occur while the async action is still in progress - // are treated as part of the action. - // - // The ideal behavior would be to treat each async function as an independent - // action. However, without a mechanism like AsyncContext, we can't tell which - // action an update corresponds to. So instead, we entangle them all into one. - // The listeners to notify once the entangled scope completes. + var ForceSuspenseFallback = 2; + var suspenseStackCursor = createCursor(DefaultSuspenseContext); + function hasSuspenseListContext(parentContext, flag) { + return (parentContext & flag) !== 0; + } + function setDefaultShallowSuspenseListContext(parentContext) { + return parentContext & SubtreeSuspenseContextMask; + } + function setShallowSuspenseListContext(parentContext, shallowContext) { + return (parentContext & SubtreeSuspenseContextMask) | shallowContext; + } + function pushSuspenseListContext(fiber, newContext) { + push(suspenseStackCursor, newContext, fiber); + } + function popSuspenseListContext(fiber) { + pop(suspenseStackCursor, fiber); + } - var currentEntangledListeners = null; // The number of pending async actions in the entangled scope. + // A non-null SuspenseState means that it is blocked for one reason or another. + // - A non-null dehydrated field means it's blocked pending hydration. + // - A non-null dehydrated field can use isSuspenseInstancePending or + // isSuspenseInstanceFallback to query the reason for being dehydrated. + // - A null dehydrated field means it's blocked by something suspending and + // we're currently showing a fallback instead. - var currentEntangledPendingCount = 0; // The transition lane shared by all updates in the entangled scope. + function findFirstSuspended(row) { + var node = row; - var currentEntangledLane = NoLane; - function requestAsyncActionContext( - actionReturnValue, // If this is provided, this resulting thenable resolves to this value instead - // of the return value of the action. This is a perf trick to avoid composing - // an extra async function. - overrideReturnValue - ) { - // This is an async action. - // - // Return a thenable that resolves once the action scope (i.e. the async - // function passed to startTransition) has finished running. - var thenable = actionReturnValue; - var entangledListeners; - - if (currentEntangledListeners === null) { - // There's no outer async action scope. Create a new one. - entangledListeners = currentEntangledListeners = []; - currentEntangledPendingCount = 0; - currentEntangledLane = requestTransitionLane(); - } else { - entangledListeners = currentEntangledListeners; - } + while (node !== null) { + if (node.tag === SuspenseComponent) { + var state = node.memoizedState; - currentEntangledPendingCount++; // Create a thenable that represents the result of this action, but doesn't - // resolve until the entire entangled scope has finished. - // - // Expressed using promises: - // const [thisResult] = await Promise.all([thisAction, entangledAction]); - // return thisResult; - - var resultThenable = createResultThenable(entangledListeners); - var resultStatus = "pending"; - var resultValue; - var rejectedReason; - thenable.then( - function (value) { - resultStatus = "fulfilled"; - resultValue = - overrideReturnValue !== null ? overrideReturnValue : value; - pingEngtangledActionScope(); - }, - function (error) { - resultStatus = "rejected"; - rejectedReason = error; - pingEngtangledActionScope(); - } - ); // Attach a listener to fill in the result. - - entangledListeners.push(function () { - switch (resultStatus) { - case "fulfilled": { - var fulfilledThenable = resultThenable; - fulfilledThenable.status = "fulfilled"; - fulfilledThenable.value = resultValue; - break; - } + if (state !== null) { + var dehydrated = state.dehydrated; - case "rejected": { - var rejectedThenable = resultThenable; - rejectedThenable.status = "rejected"; - rejectedThenable.reason = rejectedReason; - break; + if ( + dehydrated === null || + isSuspenseInstancePending() || + isSuspenseInstanceFallback() + ) { + return node; + } } + } else if ( + node.tag === SuspenseListComponent && // revealOrder undefined can't be trusted because it don't + // keep track of whether it suspended or not. + node.memoizedProps.revealOrder !== undefined + ) { + var didSuspend = (node.flags & DidCapture) !== NoFlags$1; - case "pending": - default: { - // The listener above should have been called first, so `resultStatus` - // should already be set to the correct value. - throw new Error( - "Thenable should have already resolved. This " + - "is a bug in React." - ); + if (didSuspend) { + return node; } + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; } - }); - return resultThenable; - } - function requestSyncActionContext( - actionReturnValue, // If this is provided, this resulting thenable resolves to this value instead - // of the return value of the action. This is a perf trick to avoid composing - // an extra async function. - overrideReturnValue - ) { - var resultValue = - overrideReturnValue !== null ? overrideReturnValue : actionReturnValue; // This is not an async action, but it may be part of an outer async action. - if (currentEntangledListeners === null) { - return resultValue; - } else { - // Return a thenable that does not resolve until the entangled actions - // have finished. - var entangledListeners = currentEntangledListeners; - var resultThenable = createResultThenable(entangledListeners); - entangledListeners.push(function () { - var fulfilledThenable = resultThenable; - fulfilledThenable.status = "fulfilled"; - fulfilledThenable.value = resultValue; - }); - return resultThenable; - } - } + if (node === row) { + return null; + } - function pingEngtangledActionScope() { - if ( - currentEntangledListeners !== null && - --currentEntangledPendingCount === 0 - ) { - // All the actions have finished. Close the entangled async action scope - // and notify all the listeners. - var listeners = currentEntangledListeners; - currentEntangledListeners = null; - currentEntangledLane = NoLane; + while (node.sibling === null) { + if (node.return === null || node.return === row) { + return null; + } - for (var i = 0; i < listeners.length; i++) { - var listener = listeners[i]; - listener(); + node = node.return; } + + node.sibling.return = node.return; + node = node.sibling; } - } - function createResultThenable(entangledListeners) { - // Waits for the entangled async action to complete, then resolves to the - // result of an individual action. - var resultThenable = { - status: "pending", - value: null, - reason: null, - then: function (resolve) { - // This is a bit of a cheat. `resolve` expects a value of type `S` to be - // passed, but because we're instrumenting the `status` field ourselves, - // and we know this thenable will only be used by React, we also know - // the value isn't actually needed. So we add the resolve function - // directly to the entangled listeners. - // - // This is also why we don't need to check if the thenable is still - // pending; the Suspense implementation already performs that check. - var ping = resolve; - entangledListeners.push(ping); - } - }; - return resultThenable; + return null; } - function peekEntangledActionLane() { - return currentEntangledLane; - } + var NoFlags = + /* */ + 0; // Represents whether effect should fire. + + var HasEffect = + /* */ + 1; // Represents the phase in which the effect (not the clean-up) fires. + + var Insertion = + /* */ + 2; + var Layout = + /* */ + 4; + var Passive = + /* */ + 8; var ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher, ReactCurrentBatchConfig$2 = ReactSharedInternals.ReactCurrentBatchConfig; @@ -10510,7 +10565,7 @@ to return true:wantsResponderID| | } } - function warnIfAsyncClientComponent(Component, componentDoesIncludeHooks) { + function warnIfAsyncClientComponent(Component) { { // This dev-only check only works for detecting native async functions, // not transpiled ones. There's also a prod check that we use to prevent @@ -10522,43 +10577,20 @@ to return true:wantsResponderID| | "[object AsyncFunction]"; if (isAsyncFunction) { - // Encountered an async Client Component. This is not yet supported, - // except in certain constrained cases, like during a route navigation. + // Encountered an async Client Component. This is not yet supported. var componentName = getComponentNameFromFiber( currentlyRenderingFiber$1 ); if (!didWarnAboutAsyncClientComponent.has(componentName)) { - didWarnAboutAsyncClientComponent.add(componentName); // Check if this is a sync update. We use the "root" render lanes here - // because the "subtree" render lanes may include additional entangled - // lanes related to revealing previously hidden content. + didWarnAboutAsyncClientComponent.add(componentName); - var root = getWorkInProgressRoot(); - var rootRenderLanes = getWorkInProgressRootRenderLanes(); - - if (root !== null && includesBlockingLane(root, rootRenderLanes)) { - error( - "async/await is not yet supported in Client Components, only " + - "Server Components. This error is often caused by accidentally " + - "adding `'use client'` to a module that was originally written " + - "for the server." - ); - } else { - // This is a concurrent (Transition, Retry, etc) render. We don't - // warn in these cases. - // - // However, Async Components are forbidden to include hooks, even - // during a transition, so let's check for that here. - // - // TODO: Add a corresponding warning to Server Components runtime. - if (componentDoesIncludeHooks) { - error( - "Hooks are not supported inside an async component. This " + - "error is often caused by accidentally adding `'use client'` " + - "to a module that was originally written for the server." - ); - } - } + error( + "async/await is not yet supported in Client Components, only " + + "Server Components. This error is often caused by accidentally " + + "adding `'use client'` to a module that was originally written " + + "for the server." + ); } } } @@ -10641,6 +10673,7 @@ to return true:wantsResponderID| | ignorePreviousDependencies = current !== null && current.type !== workInProgress.type; + warnIfAsyncClientComponent(Component); } workInProgress.memoizedState = null; @@ -10700,7 +10733,8 @@ to return true:wantsResponderID| | // // There are plenty of tests to ensure this behavior is correct. - var shouldDoubleRenderDEV = debugRenderPhaseSideEffectsForStrictMode; + var shouldDoubleRenderDEV = + (workInProgress.mode & StrictLegacyMode) !== NoMode; shouldDoubleInvokeUserFnsInHooksDEV = shouldDoubleRenderDEV; var children = Component(props, secondArg); shouldDoubleInvokeUserFnsInHooksDEV = false; // Check if there was a render phase update @@ -10716,16 +10750,29 @@ to return true:wantsResponderID| | ); } - finishRenderingHooks(current, workInProgress, Component); + if (shouldDoubleRenderDEV) { + // In development, components are invoked twice to help detect side effects. + setIsStrictModeForDevtools(true); + + try { + children = renderWithHooksAgain( + workInProgress, + Component, + props, + secondArg + ); + } finally { + setIsStrictModeForDevtools(false); + } + } + + finishRenderingHooks(current, workInProgress); return children; } function finishRenderingHooks(current, workInProgress, Component) { { workInProgress._debugHookTypes = hookTypesDev; - var componentDoesIncludeHooks = - workInProgressHook !== null || thenableIndexCounter !== 0; - warnIfAsyncClientComponent(Component, componentDoesIncludeHooks); } // We can assume the previous dispatcher is always this one, since we set it // at the beginning of the render phase and there's no re-entrance. @@ -10827,7 +10874,7 @@ to return true:wantsResponderID| | props, secondArg ); - finishRenderingHooks(current, workInProgress, Component); + finishRenderingHooks(current, workInProgress); return children; } @@ -11099,10 +11146,7 @@ to return true:wantsResponderID| | // This is a thenable. var thenable = usable; return useThenable(thenable); - } else if ( - usable.$$typeof === REACT_CONTEXT_TYPE || - usable.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) { + } else if (usable.$$typeof === REACT_CONTEXT_TYPE) { var context = usable; return readContext(context); } @@ -11124,6 +11168,12 @@ to return true:wantsResponderID| | if (init !== undefined) { initialState = init(initialArg); + + if (shouldDoubleInvokeUserFnsInHooksDEV) { + setIsStrictModeForDevtools(true); + init(initialArg); + setIsStrictModeForDevtools(false); + } } else { initialState = initialArg; } @@ -11208,6 +11258,7 @@ to return true:wantsResponderID| | var newBaseQueueFirst = null; var newBaseQueueLast = null; var update = first; + var didReadFromEntangledAsyncAction = false; do { // An extra OffscreenLane bit is added to updates that were made to @@ -11267,6 +11318,12 @@ to return true:wantsResponderID| | next: null }; newBaseQueueLast = newBaseQueueLast.next = _clone; + } // Check if this update is part of a pending async action. If so, + // we'll need to suspend until the action has finished, so that it's + // batched together with future updates in the same action. + + if (updateLane === peekEntangledActionLane()) { + didReadFromEntangledAsyncAction = true; } } // Process this update. @@ -11296,7 +11353,23 @@ to return true:wantsResponderID| | // different from the current state. if (!objectIs(newState, hook.memoizedState)) { - markWorkInProgressReceivedUpdate(); + markWorkInProgressReceivedUpdate(); // Check if this update is part of a pending async action. If so, we'll + // need to suspend until the action has finished, so that it's batched + // together with future updates in the same action. + // TODO: Once we support hooks inside useMemo (or an equivalent + // memoization boundary like Forget), hoist this logic so that it only + // suspends if the memo boundary produces a new value. + + if (didReadFromEntangledAsyncAction) { + var entangledActionThenable = peekEntangledActionThenable(); + + if (entangledActionThenable !== null) { + // TODO: Instead of the throwing the thenable directly, throw a + // special object like `use` does so we can detect if it's captured + // by userspace. + throw entangledActionThenable; + } + } } hook.memoizedState = newState; @@ -11596,8 +11669,16 @@ to return true:wantsResponderID| | var hook = mountWorkInProgressHook(); if (typeof initialState === "function") { - // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types - initialState = initialState(); + var initialStateInitializer = initialState; // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types + + initialState = initialStateInitializer(); + + if (shouldDoubleInvokeUserFnsInHooksDEV) { + setIsStrictModeForDevtools(true); // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types + + initialStateInitializer(); + setIsStrictModeForDevtools(false); + } } hook.memoizedState = hook.baseState = initialState; @@ -11881,12 +11962,14 @@ to return true:wantsResponderID| | function mountMemo(nextCreate, deps) { var hook = mountWorkInProgressHook(); var nextDeps = deps === undefined ? null : deps; + var nextValue = nextCreate(); if (shouldDoubleInvokeUserFnsInHooksDEV) { + setIsStrictModeForDevtools(true); nextCreate(); + setIsStrictModeForDevtools(false); } - var nextValue = nextCreate(); hook.memoizedState = [nextValue, nextDeps]; return nextValue; } @@ -11904,11 +11987,14 @@ to return true:wantsResponderID| | } } + var nextValue = nextCreate(); + if (shouldDoubleInvokeUserFnsInHooksDEV) { + setIsStrictModeForDevtools(true); nextCreate(); + setIsStrictModeForDevtools(false); } - var nextValue = nextCreate(); hook.memoizedState = [nextValue, nextDeps]; return nextValue; } @@ -12023,7 +12109,9 @@ to return true:wantsResponderID| | higherEventPriority(previousPriority, ContinuousEventPriority) ); var prevTransition = ReactCurrentBatchConfig$2.transition; - var currentTransition = {}; + var currentTransition = { + _callbacks: new Set() + }; { ReactCurrentBatchConfig$2.transition = null; @@ -12036,7 +12124,7 @@ to return true:wantsResponderID| | } try { - var returnValue, thenable, entangledResult, _entangledResult2; + var returnValue, thenable, thenableForFinishedState; if (enableAsyncActions); else { // Async actions are not enabled. @@ -13460,6 +13548,17 @@ to return true:wantsResponderID| | var partialState = getDerivedStateFromProps(nextProps, prevState); { + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); + + try { + // Invoke the function an extra time to help detect side-effects. + partialState = getDerivedStateFromProps(nextProps, prevState); + } finally { + setIsStrictModeForDevtools(false); + } + } + warnOnUndefinedDerivedState(ctor, partialState); } // Merge the partial state and the previous state. @@ -13566,6 +13665,21 @@ to return true:wantsResponderID| | ); { + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); + + try { + // Invoke the function an extra time to help detect side-effects. + shouldUpdate = instance.shouldComponentUpdate( + newProps, + newState, + nextContext + ); + } finally { + setIsStrictModeForDevtools(false); + } + } + if (shouldUpdate === undefined) { error( "%s.shouldComponentUpdate(): Returned undefined instead of a " + @@ -13886,6 +14000,18 @@ to return true:wantsResponderID| | var instance = new ctor(props, context); // Instantiate twice to help detect side-effects. + { + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); + + try { + instance = new ctor(props, context); // eslint-disable-line no-new + } finally { + setIsStrictModeForDevtools(false); + } + } + } + var state = (workInProgress.memoizedState = instance.state !== null && instance.state !== undefined ? instance.state @@ -14141,6 +14267,7 @@ to return true:wantsResponderID| | // process them now. processUpdateQueue(workInProgress, newProps, instance, renderLanes); + suspendIfUpdateReadFromEntangledAsyncAction(); instance.state = workInProgress.memoizedState; } @@ -14208,6 +14335,7 @@ to return true:wantsResponderID| | var oldState = workInProgress.memoizedState; var newState = (instance.state = oldState); processUpdateQueue(workInProgress, newProps, instance, renderLanes); + suspendIfUpdateReadFromEntangledAsyncAction(); newState = workInProgress.memoizedState; if ( @@ -14360,6 +14488,7 @@ to return true:wantsResponderID| | var oldState = workInProgress.memoizedState; var newState = (instance.state = oldState); processUpdateQueue(workInProgress, newProps, instance, renderLanes); + suspendIfUpdateReadFromEntangledAsyncAction(); newState = workInProgress.memoizedState; if ( @@ -14933,7 +15062,7 @@ to return true:wantsResponderID| | } } - return; + return false; } case OffscreenComponent: { @@ -14968,7 +15097,7 @@ to return true:wantsResponderID| | attachPingListener(root, wakeable, rootRenderLanes); } - return; + return false; } } } @@ -14991,7 +15120,7 @@ to return true:wantsResponderID| | // and potentially log a warning. Revisit this for a future release. attachPingListener(root, wakeable, rootRenderLanes); renderDidSuspendDelayIfPossible(); - return; + return false; } else { // In a legacy root, suspending without a boundary is always an error. var uncaughtSuspenseError = new Error( @@ -15011,6 +15140,12 @@ to return true:wantsResponderID| | // over and traverse parent path again, this time treating the exception // as an error. + if (returnFiber === null) { + // There's no return fiber, which means the root errored. This should never + // happen. Return `true` to trigger a fatal error (panic). + return true; + } + var workInProgress = returnFiber; do { @@ -15026,7 +15161,7 @@ to return true:wantsResponderID| | lane ); enqueueCapturedUpdate(workInProgress, update); - return; + return false; } case ClassComponent: @@ -15055,7 +15190,7 @@ to return true:wantsResponderID| | ); enqueueCapturedUpdate(workInProgress, _update); - return; + return false; } break; @@ -15063,6 +15198,8 @@ to return true:wantsResponderID| | workInProgress = workInProgress.return; } while (workInProgress !== null); + + return false; } var ReactCurrentOwner$2 = ReactSharedInternals.ReactCurrentOwner; // A special exception that's used to unwind the stack when an update flows @@ -15293,7 +15430,6 @@ to return true:wantsResponderID| | Component.type, null, nextProps, - null, workInProgress, workInProgress.mode, renderLanes @@ -15926,6 +16062,16 @@ to return true:wantsResponderID| | setIsRendering(true); nextChildren = instance.render(); + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); + + try { + instance.render(); + } finally { + setIsStrictModeForDevtools(false); + } + } + setIsRendering(false); } } // React DevTools reads this flag. @@ -15987,6 +16133,10 @@ to return true:wantsResponderID| | cloneUpdateQueue(current, workInProgress); processUpdateQueue(workInProgress, nextProps, null, renderLanes); var nextState = workInProgress.memoizedState; + // it needs to happen after the `pushCacheProvider` call above to avoid a + // context stack mismatch. A bit unfortunate. + + suspendIfUpdateReadFromEntangledAsyncAction(); // Caution: React DevTools currently depends on this property // being called "element". var nextChildren = nextState.element; @@ -16360,18 +16510,14 @@ to return true:wantsResponderID| | if (workInProgress.ref !== null) { var info = ""; + var componentName = getComponentNameFromType(Component) || "Unknown"; var ownerName = getCurrentFiberOwnerNameInDevOrNull(); if (ownerName) { info += "\n\nCheck the render method of `" + ownerName + "`."; } - var warningKey = ownerName || ""; - var debugSource = workInProgress._debugSource; - - if (debugSource) { - warningKey = debugSource.fileName + ":" + debugSource.lineNumber; - } + var warningKey = componentName + "|" + (ownerName || ""); if (!didWarnAboutFunctionRefs[warningKey]) { didWarnAboutFunctionRefs[warningKey] = true; @@ -16386,32 +16532,33 @@ to return true:wantsResponderID| | } if (Component.defaultProps !== undefined) { - var componentName = getComponentNameFromType(Component) || "Unknown"; + var _componentName3 = + getComponentNameFromType(Component) || "Unknown"; - if (!didWarnAboutDefaultPropsOnFunctionComponent[componentName]) { + if (!didWarnAboutDefaultPropsOnFunctionComponent[_componentName3]) { error( "%s: Support for defaultProps will be removed from function components " + "in a future major release. Use JavaScript default parameters instead.", - componentName + _componentName3 ); - didWarnAboutDefaultPropsOnFunctionComponent[componentName] = true; + didWarnAboutDefaultPropsOnFunctionComponent[_componentName3] = true; } } if (typeof Component.getDerivedStateFromProps === "function") { - var _componentName3 = + var _componentName4 = getComponentNameFromType(Component) || "Unknown"; if ( - !didWarnAboutGetDerivedStateOnFunctionComponent[_componentName3] + !didWarnAboutGetDerivedStateOnFunctionComponent[_componentName4] ) { error( "%s: Function components do not support getDerivedStateFromProps.", - _componentName3 + _componentName4 ); - didWarnAboutGetDerivedStateOnFunctionComponent[_componentName3] = + didWarnAboutGetDerivedStateOnFunctionComponent[_componentName4] = true; } } @@ -16420,16 +16567,16 @@ to return true:wantsResponderID| | typeof Component.contextType === "object" && Component.contextType !== null ) { - var _componentName4 = + var _componentName5 = getComponentNameFromType(Component) || "Unknown"; - if (!didWarnAboutContextTypeOnFunctionComponent[_componentName4]) { + if (!didWarnAboutContextTypeOnFunctionComponent[_componentName5]) { error( "%s: Function components do not support contextType.", - _componentName4 + _componentName5 ); - didWarnAboutContextTypeOnFunctionComponent[_componentName4] = true; + didWarnAboutContextTypeOnFunctionComponent[_componentName5] = true; } } } @@ -18035,7 +18182,6 @@ to return true:wantsResponderID| | workInProgress.type, workInProgress.key, workInProgress.pendingProps, - workInProgress._debugSource || null, workInProgress._debugOwner || null, workInProgress.mode, workInProgress.lanes @@ -18360,9 +18506,7 @@ to return true:wantsResponderID| | var currentValue = valueCursor.current; { - { - context._currentValue = currentValue; - } + context._currentValue = currentValue; { var currentRenderer = rendererCursorDEV.current; @@ -18645,9 +18789,25 @@ to return true:wantsResponderID| | var ReactCurrentBatchConfig$1 = ReactSharedInternals.ReactCurrentBatchConfig; - var NoTransition = null; function requestCurrentTransition() { - return ReactCurrentBatchConfig$1.transition; + var transition = ReactCurrentBatchConfig$1.transition; + + if (transition !== null) { + // Whenever a transition update is scheduled, register a callback on the + // transition object so we can get the return value of the scope function. + transition._callbacks.add(handleAsyncAction); + } + + return transition; + } + + function handleAsyncAction(transition, thenable) {} + + function notifyTransitionCallbacks(transition, returnValue) { + var callbacks = transition._callbacks; + callbacks.forEach(function (callback) { + return callback(transition, returnValue); + }); } // When retrying a Suspense/Offscreen boundary, we restore the cache that was function getSuspendedCache() { { @@ -20930,7 +21090,6 @@ to return true:wantsResponderID| | fiber.stateNode = null; { - fiber._debugSource = null; fiber._debugOwner = null; } // Theoretically, nothing in here should be necessary, because we already // disconnected the fiber from the tree. So even if something leaks this @@ -21820,8 +21979,9 @@ to return true:wantsResponderID| | current !== null && current.memoizedState !== null; { - if (isShowingFallback !== wasShowingFallback) { - // A fallback is either appearing or disappearing. + if (isShowingFallback && !wasShowingFallback) { + // Old behavior. Only mark when a fallback appears, not when + // it disappears. markCommitTimeOfFallback(); } } @@ -23193,17 +23353,17 @@ to return true:wantsResponderID| | return pickArbitraryLane(workInProgressRootRenderLanes); } - var isTransition = requestCurrentTransition() !== NoTransition; + var transition = requestCurrentTransition(); - if (isTransition) { - if (ReactCurrentBatchConfig.transition !== null) { - var transition = ReactCurrentBatchConfig.transition; + if (transition !== null) { + { + var batchConfigTransition = ReactCurrentBatchConfig.transition; - if (!transition._updatedFibers) { - transition._updatedFibers = new Set(); + if (!batchConfigTransition._updatedFibers) { + batchConfigTransition._updatedFibers = new Set(); } - transition._updatedFibers.add(fiber); + batchConfigTransition._updatedFibers.add(fiber); } var actionScopeLane = peekEntangledActionLane(); @@ -23270,7 +23430,7 @@ to return true:wantsResponderID| | workInProgressDeferredLane = OffscreenLane; } else { // Everything else is spawned as a transition. - workInProgressDeferredLane = requestTransitionLane(); + workInProgressDeferredLane = claimNextTransitionLane(); } } // Mark the parent Suspense boundary so it knows to spawn the deferred lane. @@ -23642,7 +23802,7 @@ to return true:wantsResponderID| | workInProgressDeferredLane ); } else { - if (includesOnlyRetries(lanes) && alwaysThrottleRetries) { + if (includesOnlyRetries(lanes) && exitStatus === RootSuspended) { // This render only included retries, no updates. Throttle committing // retries so that we don't show too many loading states too quickly. var msUntilTimeout = @@ -24331,7 +24491,7 @@ to return true:wantsResponderID| | // Unwind then continue with the normal work loop. workInProgressSuspendedReason = NotSuspended; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(unitOfWork, thrownValue); + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); break; } } @@ -24428,7 +24588,7 @@ to return true:wantsResponderID| | // Unwind then continue with the normal work loop. workInProgressSuspendedReason = NotSuspended; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(unitOfWork, thrownValue); + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); break; } @@ -24493,7 +24653,7 @@ to return true:wantsResponderID| | // Otherwise, unwind then continue with the normal work loop. workInProgressSuspendedReason = NotSuspended; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(unitOfWork, thrownValue); + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); } break; @@ -24558,7 +24718,7 @@ to return true:wantsResponderID| | workInProgressSuspendedReason = NotSuspended; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(unitOfWork, thrownValue); + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); break; } @@ -24569,7 +24729,7 @@ to return true:wantsResponderID| | // always unwind. workInProgressSuspendedReason = NotSuspended; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(unitOfWork, thrownValue); + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); break; } @@ -24787,7 +24947,7 @@ to return true:wantsResponderID| | ReactCurrentOwner$1.current = null; } - function throwAndUnwindWorkLoop(unitOfWork, thrownValue) { + function throwAndUnwindWorkLoop(root, unitOfWork, thrownValue) { // This is a fork of performUnitOfWork specifcally for unwinding a fiber // that threw an exception. // @@ -24796,40 +24956,33 @@ to return true:wantsResponderID| | resetSuspendedWorkLoopOnUnwind(unitOfWork); var returnFiber = unitOfWork.return; - if (returnFiber === null || workInProgressRoot === null) { - // Expected to be working on a non-root fiber. This is a fatal error - // because there's no ancestor that can handle it; the root is - // supposed to capture all errors that weren't caught by an error - // boundary. - workInProgressRootExitStatus = RootFatalErrored; - workInProgressRootFatalError = thrownValue; // Set `workInProgress` to null. This represents advancing to the next - // sibling, or the parent if there are no siblings. But since the root - // has no siblings nor a parent, we set it to null. Usually this is - // handled by `completeUnitOfWork` or `unwindWork`, but since we're - // intentionally not calling those, we need set it here. - // TODO: Consider calling `unwindWork` to pop the contexts. - - workInProgress = null; - return; - } - try { // Find and mark the nearest Suspense or error boundary that can handle // this "exception". - throwException( - workInProgressRoot, + var didFatal = throwException( + root, returnFiber, unitOfWork, thrownValue, workInProgressRootRenderLanes ); + + if (didFatal) { + panicOnRootError(thrownValue); + return; + } } catch (error) { // We had trouble processing the error. An example of this happening is // when accessing the `componentDidCatch` property of an error boundary // throws an error. A weird edge case. There's a regression test for this. // To prevent an infinite loop, bubble the error up to the next parent. - workInProgress = returnFiber; - throw error; + if (returnFiber !== null) { + workInProgress = returnFiber; + throw error; + } else { + panicOnRootError(thrownValue); + return; + } } if (unitOfWork.flags & Incomplete) { @@ -24849,6 +25002,22 @@ to return true:wantsResponderID| | } } + function panicOnRootError(error) { + // There's no ancestor that can handle this exception. This should never + // happen because the root is supposed to capture all errors that weren't + // caught by an error boundary. This is a fatal error, or panic condition, + // because we've run out of ways to recover. + workInProgressRootExitStatus = RootFatalErrored; + workInProgressRootFatalError = error; // Set `workInProgress` to null. This represents advancing to the next + // sibling, or the parent if there are no siblings. But since the root + // has no siblings nor a parent, we set it to null. Usually this is + // handled by `completeUnitOfWork` or `unwindWork`, but since we're + // intentionally not calling those, we need set it here. + // TODO: Consider calling `unwindWork` to pop the contexts. + + workInProgress = null; + } + function completeUnitOfWork(unitOfWork) { // Attempt to complete the current unit of work, then move to the next // sibling. If there are no more siblings, return to the parent fiber. @@ -26605,7 +26774,6 @@ to return true:wantsResponderID| | { // This isn't directly used but is handy for debugging internals: - this._debugSource = null; this._debugOwner = null; this._debugNeedsRemount = false; this._debugHookTypes = null; @@ -26687,7 +26855,6 @@ to return true:wantsResponderID| | { // DEV-only fields - workInProgress._debugSource = current._debugSource; workInProgress._debugOwner = current._debugOwner; workInProgress._debugHookTypes = current._debugHookTypes; } @@ -26843,7 +27010,7 @@ to return true:wantsResponderID| | if (tag === ConcurrentRoot) { mode = ConcurrentMode; - if (isStrictMode === true || createRootStrictEffectsByDefault) { + if (isStrictMode === true) { mode |= StrictLegacyMode | StrictEffectsMode; } } else { @@ -26863,7 +27030,6 @@ to return true:wantsResponderID| | type, // React$ElementType key, pendingProps, - source, owner, mode, lanes @@ -27011,18 +27177,15 @@ to return true:wantsResponderID| | fiber.lanes = lanes; { - fiber._debugSource = source; fiber._debugOwner = owner; } return fiber; } function createFiberFromElement(element, mode, lanes) { - var source = null; var owner = null; { - source = element._source; owner = element._owner; } @@ -27033,14 +27196,12 @@ to return true:wantsResponderID| | type, key, pendingProps, - source, owner, mode, lanes ); { - fiber._debugSource = element._source; fiber._debugOwner = element._owner; } @@ -27169,7 +27330,6 @@ to return true:wantsResponderID| | target.treeBaseDuration = source.treeBaseDuration; } - target._debugSource = source._debugSource; target._debugOwner = source._debugOwner; target._debugNeedsRemount = source._debugNeedsRemount; target._debugHookTypes = source._debugHookTypes; @@ -27285,7 +27445,7 @@ to return true:wantsResponderID| | return root; } - var ReactVersion = "18.3.0-canary-b2d637128-20240123"; + var ReactVersion = "18.3.0-canary-03d6f7cf0-20240209"; function createPortal$1( children, @@ -28062,7 +28222,6 @@ to return true:wantsResponderID| | getInspectorData: function (findNodeHandle) { return { props: getHostProps(fiber), - source: fiber._debugSource, measure: function (callback) { // If this is Fabric, we'll find a shadow node and use that to measure. var hostFiber = findCurrentHostFiber(fiber); @@ -28125,7 +28284,7 @@ to return true:wantsResponderID| | hierarchy: [], props: emptyObject, selectedIndex: null, - source: null + componentStack: "" }; } @@ -28134,14 +28293,15 @@ to return true:wantsResponderID| | var instance = lastNonHostInstance(fiberHierarchy); var hierarchy = createHierarchy(fiberHierarchy); var props = getHostProps(instance); - var source = instance._debugSource; var selectedIndex = fiberHierarchy.indexOf(instance); + var componentStack = + fiber !== null ? getStackByFiberInDevAndProd(fiber) : ""; return { closestInstance: instance, hierarchy: hierarchy, props: props, selectedIndex: selectedIndex, - source: source + componentStack: componentStack }; } } diff --git a/packages/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js b/packages/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js index 1d396a6955bb69..7f6b01afe37c76 100644 --- a/packages/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js +++ b/packages/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js @@ -8,7 +8,7 @@ * @nolint * @providesModule ReactNativeRenderer-prod * @preventMunge - * @generated SignedSource<<4ecc3a9a1d106cd926941ba53c67e4ec>> + * @generated SignedSource<> */ "use strict"; @@ -940,7 +940,7 @@ eventPluginOrder = Array.prototype.slice.call([ "ReactNativeBridgeEventPlugin" ]); recomputePluginOrdering(); -var injectedNamesToPlugins$jscomp$inline_236 = { +var injectedNamesToPlugins$jscomp$inline_238 = { ResponderEventPlugin: ResponderEventPlugin, ReactNativeBridgeEventPlugin: { eventTypes: {}, @@ -986,32 +986,32 @@ var injectedNamesToPlugins$jscomp$inline_236 = { } } }, - isOrderingDirty$jscomp$inline_237 = !1, - pluginName$jscomp$inline_238; -for (pluginName$jscomp$inline_238 in injectedNamesToPlugins$jscomp$inline_236) + isOrderingDirty$jscomp$inline_239 = !1, + pluginName$jscomp$inline_240; +for (pluginName$jscomp$inline_240 in injectedNamesToPlugins$jscomp$inline_238) if ( - injectedNamesToPlugins$jscomp$inline_236.hasOwnProperty( - pluginName$jscomp$inline_238 + injectedNamesToPlugins$jscomp$inline_238.hasOwnProperty( + pluginName$jscomp$inline_240 ) ) { - var pluginModule$jscomp$inline_239 = - injectedNamesToPlugins$jscomp$inline_236[pluginName$jscomp$inline_238]; + var pluginModule$jscomp$inline_241 = + injectedNamesToPlugins$jscomp$inline_238[pluginName$jscomp$inline_240]; if ( - !namesToPlugins.hasOwnProperty(pluginName$jscomp$inline_238) || - namesToPlugins[pluginName$jscomp$inline_238] !== - pluginModule$jscomp$inline_239 + !namesToPlugins.hasOwnProperty(pluginName$jscomp$inline_240) || + namesToPlugins[pluginName$jscomp$inline_240] !== + pluginModule$jscomp$inline_241 ) { - if (namesToPlugins[pluginName$jscomp$inline_238]) + if (namesToPlugins[pluginName$jscomp$inline_240]) throw Error( "EventPluginRegistry: Cannot inject two different event plugins using the same name, `" + - (pluginName$jscomp$inline_238 + "`.") + (pluginName$jscomp$inline_240 + "`.") ); - namesToPlugins[pluginName$jscomp$inline_238] = - pluginModule$jscomp$inline_239; - isOrderingDirty$jscomp$inline_237 = !0; + namesToPlugins[pluginName$jscomp$inline_240] = + pluginModule$jscomp$inline_241; + isOrderingDirty$jscomp$inline_239 = !0; } } -isOrderingDirty$jscomp$inline_237 && recomputePluginOrdering(); +isOrderingDirty$jscomp$inline_239 && recomputePluginOrdering(); var instanceCache = new Map(), instanceProps = new Map(); function getInstanceFromTag(tag) { @@ -1166,7 +1166,6 @@ var ReactSharedInternals = REACT_PROFILER_TYPE = Symbol.for("react.profiler"), REACT_PROVIDER_TYPE = Symbol.for("react.provider"), REACT_CONTEXT_TYPE = Symbol.for("react.context"), - REACT_SERVER_CONTEXT_TYPE = Symbol.for("react.server_context"), REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"), REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"), REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"), @@ -1850,6 +1849,12 @@ function getLanesToRetrySynchronouslyOnError(root, originallyAttemptedLanes) { root = root.pendingLanes & -536870913; return 0 !== root ? root : root & 536870912 ? 536870912 : 0; } +function claimNextTransitionLane() { + var lane = nextTransitionLane; + nextTransitionLane <<= 1; + 0 === (nextTransitionLane & 4194176) && (nextTransitionLane = 128); + return lane; +} function claimNextRetryLane() { var lane = nextRetryLane; nextRetryLane <<= 1; @@ -1972,14 +1977,14 @@ function getPublicInstance(instance) { } var scheduleTimeout = setTimeout, cancelTimeout = clearTimeout; -function describeComponentFrame(name, source, ownerName) { - source = ""; - ownerName && (source = " (created by " + ownerName + ")"); - return "\n in " + (name || "Unknown") + source; +function describeComponentFrame(name, ownerName) { + var sourceInfo = ""; + ownerName && (sourceInfo = " (created by " + ownerName + ")"); + return "\n in " + (name || "Unknown") + sourceInfo; } -function describeFunctionComponentFrame(fn, source) { +function describeFunctionComponentFrame(fn) { return fn - ? describeComponentFrame(fn.displayName || fn.name || null, source, null) + ? describeComponentFrame(fn.displayName || fn.name || null, null) : ""; } var hasOwnProperty = Object.prototype.hasOwnProperty, @@ -2201,6 +2206,209 @@ function getRootForUpdatedFiber(sourceFiber) { (sourceFiber = parent), (parent = sourceFiber.return); return 3 === sourceFiber.tag ? sourceFiber.stateNode : null; } +var firstScheduledRoot = null, + lastScheduledRoot = null, + didScheduleMicrotask = !1, + mightHavePendingSyncWork = !1, + isFlushingWork = !1, + currentEventTransitionLane = 0; +function ensureRootIsScheduled(root) { + root !== lastScheduledRoot && + null === root.next && + (null === lastScheduledRoot + ? (firstScheduledRoot = lastScheduledRoot = root) + : (lastScheduledRoot = lastScheduledRoot.next = root)); + mightHavePendingSyncWork = !0; + didScheduleMicrotask || + ((didScheduleMicrotask = !0), + scheduleCallback$2(ImmediatePriority, processRootScheduleInMicrotask)); + scheduleTaskForRootDuringMicrotask(root, now()); +} +function flushSyncWorkAcrossRoots_impl(onlyLegacy) { + if (!isFlushingWork && mightHavePendingSyncWork) { + var errors = null; + isFlushingWork = !0; + do { + var didPerformSomeWork = !1; + for (var root = firstScheduledRoot; null !== root; ) { + if (!onlyLegacy || 0 === root.tag) { + var workInProgressRootRenderLanes$11 = workInProgressRootRenderLanes, + nextLanes = getNextLanes( + root, + root === workInProgressRoot ? workInProgressRootRenderLanes$11 : 0 + ); + if (0 !== (nextLanes & 3)) + try { + didPerformSomeWork = !0; + workInProgressRootRenderLanes$11 = root; + if (0 !== (executionContext & 6)) + throw Error("Should not already be working."); + if (!flushPassiveEffects()) { + var exitStatus = renderRootSync( + workInProgressRootRenderLanes$11, + nextLanes + ); + if ( + 0 !== workInProgressRootRenderLanes$11.tag && + 2 === exitStatus + ) { + var originallyAttemptedLanes = nextLanes, + errorRetryLanes = getLanesToRetrySynchronouslyOnError( + workInProgressRootRenderLanes$11, + originallyAttemptedLanes + ); + 0 !== errorRetryLanes && + ((nextLanes = errorRetryLanes), + (exitStatus = recoverFromConcurrentError( + workInProgressRootRenderLanes$11, + originallyAttemptedLanes, + errorRetryLanes + ))); + } + if (1 === exitStatus) + throw ( + ((originallyAttemptedLanes = workInProgressRootFatalError), + prepareFreshStack(workInProgressRootRenderLanes$11, 0), + markRootSuspended( + workInProgressRootRenderLanes$11, + nextLanes, + 0 + ), + ensureRootIsScheduled(workInProgressRootRenderLanes$11), + originallyAttemptedLanes) + ); + 6 === exitStatus + ? markRootSuspended( + workInProgressRootRenderLanes$11, + nextLanes, + workInProgressDeferredLane + ) + : ((workInProgressRootRenderLanes$11.finishedWork = + workInProgressRootRenderLanes$11.current.alternate), + (workInProgressRootRenderLanes$11.finishedLanes = + nextLanes), + commitRoot( + workInProgressRootRenderLanes$11, + workInProgressRootRecoverableErrors, + workInProgressTransitions, + workInProgressDeferredLane + )); + } + ensureRootIsScheduled(workInProgressRootRenderLanes$11); + } catch (error) { + null === errors ? (errors = [error]) : errors.push(error); + } + } + root = root.next; + } + } while (didPerformSomeWork); + isFlushingWork = !1; + if (null !== errors) { + if (1 < errors.length) { + if ("function" === typeof AggregateError) + throw new AggregateError(errors); + for (onlyLegacy = 1; onlyLegacy < errors.length; onlyLegacy++) + (didPerformSomeWork = throwError.bind(null, errors[onlyLegacy])), + scheduleCallback$2(ImmediatePriority, didPerformSomeWork); + } + throw errors[0]; + } + } +} +function throwError(error) { + throw error; +} +function processRootScheduleInMicrotask() { + mightHavePendingSyncWork = didScheduleMicrotask = !1; + for ( + var currentTime = now(), prev = null, root = firstScheduledRoot; + null !== root; + + ) { + var next = root.next, + nextLanes = scheduleTaskForRootDuringMicrotask(root, currentTime); + 0 === nextLanes + ? ((root.next = null), + null === prev ? (firstScheduledRoot = next) : (prev.next = next), + null === next && (lastScheduledRoot = prev)) + : ((prev = root), + 0 !== (nextLanes & 3) && (mightHavePendingSyncWork = !0)); + root = next; + } + currentEventTransitionLane = 0; + flushSyncWorkAcrossRoots_impl(!1); +} +function scheduleTaskForRootDuringMicrotask(root, currentTime) { + for ( + var suspendedLanes = root.suspendedLanes, + pingedLanes = root.pingedLanes, + expirationTimes = root.expirationTimes, + lanes = root.pendingLanes & -62914561; + 0 < lanes; + + ) { + var index$5 = 31 - clz32(lanes), + lane = 1 << index$5, + expirationTime = expirationTimes[index$5]; + if (-1 === expirationTime) { + if (0 === (lane & suspendedLanes) || 0 !== (lane & pingedLanes)) + expirationTimes[index$5] = computeExpirationTime(lane, currentTime); + } else expirationTime <= currentTime && (root.expiredLanes |= lane); + lanes &= ~lane; + } + currentTime = workInProgressRoot; + suspendedLanes = workInProgressRootRenderLanes; + suspendedLanes = getNextLanes( + root, + root === currentTime ? suspendedLanes : 0 + ); + pingedLanes = root.callbackNode; + if ( + 0 === suspendedLanes || + (root === currentTime && 2 === workInProgressSuspendedReason) || + null !== root.cancelPendingCommit + ) + return ( + null !== pingedLanes && + null !== pingedLanes && + cancelCallback$1(pingedLanes), + (root.callbackNode = null), + (root.callbackPriority = 0) + ); + if (0 !== (suspendedLanes & 3)) + return ( + null !== pingedLanes && + null !== pingedLanes && + cancelCallback$1(pingedLanes), + (root.callbackPriority = 2), + (root.callbackNode = null), + 2 + ); + currentTime = suspendedLanes & -suspendedLanes; + if (currentTime === root.callbackPriority) return currentTime; + null !== pingedLanes && cancelCallback$1(pingedLanes); + switch (lanesToEventPriority(suspendedLanes)) { + case 2: + suspendedLanes = ImmediatePriority; + break; + case 8: + suspendedLanes = UserBlockingPriority; + break; + case 32: + suspendedLanes = NormalPriority; + break; + case 268435456: + suspendedLanes = IdlePriority; + break; + default: + suspendedLanes = NormalPriority; + } + pingedLanes = performConcurrentWorkOnRoot.bind(null, root); + suspendedLanes = scheduleCallback$2(suspendedLanes, pingedLanes); + root.callbackPriority = currentTime; + root.callbackNode = suspendedLanes; + return currentTime; +} var hasForceUpdate = !1; function initializeUpdateQueue(fiber) { fiber.updateQueue = { @@ -2464,21 +2672,21 @@ function describeFiber(fiber) { case 26: case 27: case 5: - return describeComponentFrame(fiber.type, null, null); + return describeComponentFrame(fiber.type, null); case 16: - return describeComponentFrame("Lazy", null, null); + return describeComponentFrame("Lazy", null); case 13: - return describeComponentFrame("Suspense", null, null); + return describeComponentFrame("Suspense", null); case 19: - return describeComponentFrame("SuspenseList", null, null); + return describeComponentFrame("SuspenseList", null); case 0: case 2: case 15: - return describeFunctionComponentFrame(fiber.type, null); + return describeFunctionComponentFrame(fiber.type); case 11: - return describeFunctionComponentFrame(fiber.type.render, null); + return describeFunctionComponentFrame(fiber.type.render); case 1: - return (fiber = describeFunctionComponentFrame(fiber.type, null)), fiber; + return (fiber = describeFunctionComponentFrame(fiber.type)), fiber; default: return ""; } @@ -2742,7 +2950,6 @@ function createChildReconciler(shouldTrackSideEffects) { element.key, element.props, null, - null, returnFiber.mode, lanes ); @@ -2805,7 +3012,6 @@ function createChildReconciler(shouldTrackSideEffects) { newChild.key, newChild.props, null, - null, returnFiber.mode, lanes )), @@ -2840,10 +3046,7 @@ function createChildReconciler(shouldTrackSideEffects) { ); if ("function" === typeof newChild.then) return createChild(returnFiber, unwrapThenable(newChild), lanes); - if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) + if (newChild.$$typeof === REACT_CONTEXT_TYPE) return createChild( returnFiber, readContextDuringReconcilation(returnFiber, newChild, lanes), @@ -2889,10 +3092,7 @@ function createChildReconciler(shouldTrackSideEffects) { unwrapThenable(newChild), lanes ); - if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) + if (newChild.$$typeof === REACT_CONTEXT_TYPE) return updateSlot( returnFiber, oldFiber, @@ -2959,10 +3159,7 @@ function createChildReconciler(shouldTrackSideEffects) { unwrapThenable(newChild), lanes ); - if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) + if (newChild.$$typeof === REACT_CONTEXT_TYPE) return updateFromMap( existingChildren, returnFiber, @@ -3211,7 +3408,6 @@ function createChildReconciler(shouldTrackSideEffects) { newChild.key, newChild.props, null, - null, returnFiber.mode, lanes )), @@ -3294,10 +3490,7 @@ function createChildReconciler(shouldTrackSideEffects) { unwrapThenable(newChild), lanes ); - if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) + if (newChild.$$typeof === REACT_CONTEXT_TYPE) return reconcileChildFibersImpl( returnFiber, currentFirstChild, @@ -3420,217 +3613,6 @@ function findFirstSuspended(row) { } return null; } -var firstScheduledRoot = null, - lastScheduledRoot = null, - didScheduleMicrotask = !1, - mightHavePendingSyncWork = !1, - isFlushingWork = !1, - currentEventTransitionLane = 0; -function ensureRootIsScheduled(root) { - root !== lastScheduledRoot && - null === root.next && - (null === lastScheduledRoot - ? (firstScheduledRoot = lastScheduledRoot = root) - : (lastScheduledRoot = lastScheduledRoot.next = root)); - mightHavePendingSyncWork = !0; - didScheduleMicrotask || - ((didScheduleMicrotask = !0), - scheduleCallback$2(ImmediatePriority, processRootScheduleInMicrotask)); -} -function flushSyncWorkAcrossRoots_impl(onlyLegacy) { - if (!isFlushingWork && mightHavePendingSyncWork) { - var errors = null; - isFlushingWork = !0; - do { - var didPerformSomeWork = !1; - for (var root = firstScheduledRoot; null !== root; ) { - if (!onlyLegacy || 0 === root.tag) { - var workInProgressRootRenderLanes$28 = workInProgressRootRenderLanes, - nextLanes = getNextLanes( - root, - root === workInProgressRoot ? workInProgressRootRenderLanes$28 : 0 - ); - if (0 !== (nextLanes & 3)) - try { - didPerformSomeWork = !0; - workInProgressRootRenderLanes$28 = root; - if (0 !== (executionContext & 6)) - throw Error("Should not already be working."); - if (!flushPassiveEffects()) { - var exitStatus = renderRootSync( - workInProgressRootRenderLanes$28, - nextLanes - ); - if ( - 0 !== workInProgressRootRenderLanes$28.tag && - 2 === exitStatus - ) { - var originallyAttemptedLanes = nextLanes, - errorRetryLanes = getLanesToRetrySynchronouslyOnError( - workInProgressRootRenderLanes$28, - originallyAttemptedLanes - ); - 0 !== errorRetryLanes && - ((nextLanes = errorRetryLanes), - (exitStatus = recoverFromConcurrentError( - workInProgressRootRenderLanes$28, - originallyAttemptedLanes, - errorRetryLanes - ))); - } - if (1 === exitStatus) - throw ( - ((originallyAttemptedLanes = workInProgressRootFatalError), - prepareFreshStack(workInProgressRootRenderLanes$28, 0), - markRootSuspended( - workInProgressRootRenderLanes$28, - nextLanes, - 0 - ), - ensureRootIsScheduled(workInProgressRootRenderLanes$28), - originallyAttemptedLanes) - ); - 6 === exitStatus - ? markRootSuspended( - workInProgressRootRenderLanes$28, - nextLanes, - workInProgressDeferredLane - ) - : ((workInProgressRootRenderLanes$28.finishedWork = - workInProgressRootRenderLanes$28.current.alternate), - (workInProgressRootRenderLanes$28.finishedLanes = - nextLanes), - commitRoot( - workInProgressRootRenderLanes$28, - workInProgressRootRecoverableErrors, - workInProgressTransitions, - workInProgressDeferredLane - )); - } - ensureRootIsScheduled(workInProgressRootRenderLanes$28); - } catch (error) { - null === errors ? (errors = [error]) : errors.push(error); - } - } - root = root.next; - } - } while (didPerformSomeWork); - isFlushingWork = !1; - if (null !== errors) { - if (1 < errors.length) { - if ("function" === typeof AggregateError) - throw new AggregateError(errors); - for (onlyLegacy = 1; onlyLegacy < errors.length; onlyLegacy++) - (didPerformSomeWork = throwError.bind(null, errors[onlyLegacy])), - scheduleCallback$2(ImmediatePriority, didPerformSomeWork); - } - throw errors[0]; - } - } -} -function throwError(error) { - throw error; -} -function processRootScheduleInMicrotask() { - mightHavePendingSyncWork = didScheduleMicrotask = !1; - for ( - var currentTime = now(), prev = null, root = firstScheduledRoot; - null !== root; - - ) { - var next = root.next, - nextLanes = scheduleTaskForRootDuringMicrotask(root, currentTime); - 0 === nextLanes - ? ((root.next = null), - null === prev ? (firstScheduledRoot = next) : (prev.next = next), - null === next && (lastScheduledRoot = prev)) - : ((prev = root), - 0 !== (nextLanes & 3) && (mightHavePendingSyncWork = !0)); - root = next; - } - currentEventTransitionLane = 0; - flushSyncWorkAcrossRoots_impl(!1); -} -function scheduleTaskForRootDuringMicrotask(root, currentTime) { - for ( - var suspendedLanes = root.suspendedLanes, - pingedLanes = root.pingedLanes, - expirationTimes = root.expirationTimes, - lanes = root.pendingLanes & -62914561; - 0 < lanes; - - ) { - var index$5 = 31 - clz32(lanes), - lane = 1 << index$5, - expirationTime = expirationTimes[index$5]; - if (-1 === expirationTime) { - if (0 === (lane & suspendedLanes) || 0 !== (lane & pingedLanes)) - expirationTimes[index$5] = computeExpirationTime(lane, currentTime); - } else expirationTime <= currentTime && (root.expiredLanes |= lane); - lanes &= ~lane; - } - currentTime = workInProgressRoot; - suspendedLanes = workInProgressRootRenderLanes; - suspendedLanes = getNextLanes( - root, - root === currentTime ? suspendedLanes : 0 - ); - pingedLanes = root.callbackNode; - if ( - 0 === suspendedLanes || - (root === currentTime && 2 === workInProgressSuspendedReason) || - null !== root.cancelPendingCommit - ) - return ( - null !== pingedLanes && - null !== pingedLanes && - cancelCallback$1(pingedLanes), - (root.callbackNode = null), - (root.callbackPriority = 0) - ); - if (0 !== (suspendedLanes & 3)) - return ( - null !== pingedLanes && - null !== pingedLanes && - cancelCallback$1(pingedLanes), - (root.callbackPriority = 2), - (root.callbackNode = null), - 2 - ); - currentTime = suspendedLanes & -suspendedLanes; - if (currentTime === root.callbackPriority) return currentTime; - null !== pingedLanes && cancelCallback$1(pingedLanes); - switch (lanesToEventPriority(suspendedLanes)) { - case 2: - suspendedLanes = ImmediatePriority; - break; - case 8: - suspendedLanes = UserBlockingPriority; - break; - case 32: - suspendedLanes = NormalPriority; - break; - case 268435456: - suspendedLanes = IdlePriority; - break; - default: - suspendedLanes = NormalPriority; - } - pingedLanes = performConcurrentWorkOnRoot.bind(null, root); - suspendedLanes = scheduleCallback$2(suspendedLanes, pingedLanes); - root.callbackPriority = currentTime; - root.callbackNode = suspendedLanes; - return currentTime; -} -function requestTransitionLane() { - if (0 === currentEventTransitionLane) { - var lane = nextTransitionLane; - nextTransitionLane <<= 1; - 0 === (nextTransitionLane & 4194176) && (nextTransitionLane = 128); - currentEventTransitionLane = lane; - } - return currentEventTransitionLane; -} var ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher, ReactCurrentBatchConfig$2 = ReactSharedInternals.ReactCurrentBatchConfig, renderLanes = 0, @@ -3808,11 +3790,7 @@ function useThenable(thenable) { function use(usable) { if (null !== usable && "object" === typeof usable) { if ("function" === typeof usable.then) return useThenable(usable); - if ( - usable.$$typeof === REACT_CONTEXT_TYPE || - usable.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) - return readContext(usable); + if (usable.$$typeof === REACT_CONTEXT_TYPE) return readContext(usable); } throw Error("An unsupported type was passed to use(): " + String(usable)); } @@ -3996,7 +3974,11 @@ function forceStoreRerender(fiber) { } function mountStateImpl(initialState) { var hook = mountWorkInProgressHook(); - "function" === typeof initialState && (initialState = initialState()); + if ("function" === typeof initialState) { + var initialStateInitializer = initialState; + initialState = initialStateInitializer(); + shouldDoubleInvokeUserFnsInHooksDEV && initialStateInitializer(); + } hook.memoizedState = hook.baseState = initialState; hook.queue = { pending: null, @@ -4097,10 +4079,10 @@ function updateMemo(nextCreate, deps) { var prevState = hook.memoizedState; if (null !== deps && areHookInputsEqual(deps, prevState[1])) return prevState[0]; + prevState = nextCreate(); shouldDoubleInvokeUserFnsInHooksDEV && nextCreate(); - nextCreate = nextCreate(); - hook.memoizedState = [nextCreate, deps]; - return nextCreate; + hook.memoizedState = [prevState, deps]; + return prevState; } function mountDeferredValueImpl(hook, value, initialValue) { return void 0 !== initialValue && 0 === (renderLanes & 1073741824) @@ -4130,10 +4112,11 @@ function startTransition(fiber, queue, pendingState, finishedState, callback) { var previousPriority = currentUpdatePriority; currentUpdatePriority = 0 !== previousPriority && 8 > previousPriority ? previousPriority : 8; - var prevTransition = ReactCurrentBatchConfig$2.transition; + var prevTransition = ReactCurrentBatchConfig$2.transition, + currentTransition = { _callbacks: new Set() }; ReactCurrentBatchConfig$2.transition = null; dispatchSetState(fiber, queue, pendingState); - ReactCurrentBatchConfig$2.transition = {}; + ReactCurrentBatchConfig$2.transition = currentTransition; try { dispatchSetState(fiber, queue, finishedState), callback(); } catch (error) { @@ -4276,21 +4259,24 @@ var ContextOnlyDispatcher = { useMemo: function (nextCreate, deps) { var hook = mountWorkInProgressHook(); deps = void 0 === deps ? null : deps; + var nextValue = nextCreate(); shouldDoubleInvokeUserFnsInHooksDEV && nextCreate(); - nextCreate = nextCreate(); - hook.memoizedState = [nextCreate, deps]; - return nextCreate; + hook.memoizedState = [nextValue, deps]; + return nextValue; }, useReducer: function (reducer, initialArg, init) { var hook = mountWorkInProgressHook(); - initialArg = void 0 !== init ? init(initialArg) : initialArg; - hook.memoizedState = hook.baseState = initialArg; + if (void 0 !== init) { + var initialState = init(initialArg); + shouldDoubleInvokeUserFnsInHooksDEV && init(initialArg); + } else initialState = initialArg; + hook.memoizedState = hook.baseState = initialState; reducer = { pending: null, lanes: 0, dispatch: null, lastRenderedReducer: reducer, - lastRenderedState: initialArg + lastRenderedState: initialState }; hook.queue = reducer; reducer = reducer.dispatch = dispatchReducerAction.bind( @@ -4674,6 +4660,153 @@ function createClassErrorUpdate(fiber, errorInfo, lane) { }); return lane; } +function throwException( + root, + returnFiber, + sourceFiber, + value, + rootRenderLanes +) { + sourceFiber.flags |= 32768; + if ( + null !== value && + "object" === typeof value && + "function" === typeof value.then + ) { + var tag = sourceFiber.tag; + 0 !== (sourceFiber.mode & 1) || + (0 !== tag && 11 !== tag && 15 !== tag) || + ((tag = sourceFiber.alternate) + ? ((sourceFiber.updateQueue = tag.updateQueue), + (sourceFiber.memoizedState = tag.memoizedState), + (sourceFiber.lanes = tag.lanes)) + : ((sourceFiber.updateQueue = null), + (sourceFiber.memoizedState = null))); + tag = suspenseHandlerStackCursor.current; + if (null !== tag) { + switch (tag.tag) { + case 13: + return ( + sourceFiber.mode & 1 && + (null === shellBoundary + ? renderDidSuspendDelayIfPossible() + : null === tag.alternate && + 0 === workInProgressRootExitStatus && + (workInProgressRootExitStatus = 3)), + (tag.flags &= -257), + 0 === (tag.mode & 1) + ? tag === returnFiber + ? (tag.flags |= 65536) + : ((tag.flags |= 128), + (sourceFiber.flags |= 131072), + (sourceFiber.flags &= -52805), + 1 === sourceFiber.tag && + (null === sourceFiber.alternate + ? (sourceFiber.tag = 17) + : ((returnFiber = createUpdate(2)), + (returnFiber.tag = 2), + enqueueUpdate(sourceFiber, returnFiber, 2))), + (sourceFiber.lanes |= 2)) + : ((tag.flags |= 65536), (tag.lanes = rootRenderLanes)), + value === noopSuspenseyCommitThenable + ? (tag.flags |= 16384) + : ((returnFiber = tag.updateQueue), + null === returnFiber + ? (tag.updateQueue = new Set([value])) + : returnFiber.add(value), + tag.mode & 1 && + attachPingListener(root, value, rootRenderLanes)), + !1 + ); + case 22: + if (tag.mode & 1) + return ( + (tag.flags |= 65536), + value === noopSuspenseyCommitThenable + ? (tag.flags |= 16384) + : ((returnFiber = tag.updateQueue), + null === returnFiber + ? ((returnFiber = { + transitions: null, + markerInstances: null, + retryQueue: new Set([value]) + }), + (tag.updateQueue = returnFiber)) + : ((sourceFiber = returnFiber.retryQueue), + null === sourceFiber + ? (returnFiber.retryQueue = new Set([value])) + : sourceFiber.add(value)), + attachPingListener(root, value, rootRenderLanes)), + !1 + ); + } + throw Error( + "Unexpected Suspense handler tag (" + + tag.tag + + "). This is a bug in React." + ); + } + if (1 === root.tag) + return ( + attachPingListener(root, value, rootRenderLanes), + renderDidSuspendDelayIfPossible(), + !1 + ); + value = Error( + "A component suspended while responding to synchronous input. This will cause the UI to be replaced with a loading indicator. To fix, updates that suspend should be wrapped with startTransition." + ); + } + root = value = createCapturedValueAtFiber(value, sourceFiber); + 4 !== workInProgressRootExitStatus && (workInProgressRootExitStatus = 2); + null === workInProgressRootConcurrentErrors + ? (workInProgressRootConcurrentErrors = [root]) + : workInProgressRootConcurrentErrors.push(root); + if (null === returnFiber) return !0; + root = returnFiber; + do { + switch (root.tag) { + case 3: + return ( + (root.flags |= 65536), + (rootRenderLanes &= -rootRenderLanes), + (root.lanes |= rootRenderLanes), + (rootRenderLanes = createRootErrorUpdate( + root, + value, + rootRenderLanes + )), + enqueueCapturedUpdate(root, rootRenderLanes), + !1 + ); + case 1: + if ( + ((returnFiber = value), + (sourceFiber = root.type), + (tag = root.stateNode), + 0 === (root.flags & 128) && + ("function" === typeof sourceFiber.getDerivedStateFromError || + (null !== tag && + "function" === typeof tag.componentDidCatch && + (null === legacyErrorBoundariesThatAlreadyFailed || + !legacyErrorBoundariesThatAlreadyFailed.has(tag))))) + ) + return ( + (root.flags |= 65536), + (rootRenderLanes &= -rootRenderLanes), + (root.lanes |= rootRenderLanes), + (rootRenderLanes = createClassErrorUpdate( + root, + returnFiber, + rootRenderLanes + )), + enqueueCapturedUpdate(root, rootRenderLanes), + !1 + ); + } + root = root.return; + } while (null !== root); + return !1; +} var ReactCurrentOwner$1 = ReactSharedInternals.ReactCurrentOwner, SelectiveHydrationException = Error( "This is not a real error. It's an implementation detail of React's selective hydration feature. If this leaks into userspace, it's a bug in React. Please file an issue." @@ -4748,7 +4881,6 @@ function updateMemoComponent( Component.type, null, nextProps, - null, workInProgress, workInProgress.mode, renderLanes @@ -5804,6 +5936,7 @@ function readContextForConsumer(consumer, context) { return value; } var ReactCurrentBatchConfig$1 = ReactSharedInternals.ReactCurrentBatchConfig; +function handleAsyncAction() {} function scheduleRetryEffect(workInProgress, retryQueue) { null !== retryQueue ? (workInProgress.flags |= 4) @@ -6948,11 +7081,11 @@ function commitMutationEffectsOnFiber(finishedWork, root) { offscreenSubtreeIsHidden && ((finishedWork = finishedWork.updateQueue), null !== finishedWork && - ((current = finishedWork.callbacks), - null !== current && - ((flags = finishedWork.shared.hiddenCallbacks), + ((flags = finishedWork.callbacks), + null !== flags && + ((current = finishedWork.shared.hiddenCallbacks), (finishedWork.shared.hiddenCallbacks = - null === flags ? current : flags.concat(current))))); + null === current ? flags : current.concat(flags))))); break; case 26: case 27: @@ -6994,13 +7127,13 @@ function commitMutationEffectsOnFiber(finishedWork, root) { throw Error( "This should have a text node initialized. This error is likely caused by a bug in React. Please file an issue." ); - current = finishedWork.stateNode; - flags = finishedWork.memoizedProps; + flags = finishedWork.stateNode; + current = finishedWork.memoizedProps; try { ReactNativePrivateInterface.UIManager.updateView( - current, + flags, "RCTRawText", - { text: flags } + { text: current } ); } catch (error$91) { captureCommitPhaseError(finishedWork, finishedWork.return, error$91); @@ -7019,14 +7152,15 @@ function commitMutationEffectsOnFiber(finishedWork, root) { recursivelyTraverseMutationEffects(root, finishedWork); commitReconciliationEffects(finishedWork); finishedWork.child.flags & 8192 && - (null !== finishedWork.memoizedState) !== - (null !== current && null !== current.memoizedState) && - (globalMostRecentFallbackTime = now()); + ((current = null !== current && null !== current.memoizedState), + null === finishedWork.memoizedState || + current || + (globalMostRecentFallbackTime = now())); flags & 4 && - ((current = finishedWork.updateQueue), - null !== current && + ((flags = finishedWork.updateQueue), + null !== flags && ((finishedWork.updateQueue = null), - attachSuspenseRetryListeners(finishedWork, current))); + attachSuspenseRetryListeners(finishedWork, flags))); break; case 22: flags & 512 && @@ -7141,21 +7275,21 @@ function commitMutationEffectsOnFiber(finishedWork, root) { root = root.sibling; } flags & 4 && - ((current = finishedWork.updateQueue), - null !== current && - ((flags = current.retryQueue), - null !== flags && - ((current.retryQueue = null), - attachSuspenseRetryListeners(finishedWork, flags)))); + ((flags = finishedWork.updateQueue), + null !== flags && + ((current = flags.retryQueue), + null !== current && + ((flags.retryQueue = null), + attachSuspenseRetryListeners(finishedWork, current)))); break; case 19: recursivelyTraverseMutationEffects(root, finishedWork); commitReconciliationEffects(finishedWork); flags & 4 && - ((current = finishedWork.updateQueue), - null !== current && + ((flags = finishedWork.updateQueue), + null !== flags && ((finishedWork.updateQueue = null), - attachSuspenseRetryListeners(finishedWork, current))); + attachSuspenseRetryListeners(finishedWork, flags))); break; case 21: break; @@ -7647,8 +7781,14 @@ function requestUpdateLane(fiber) { if (0 === (fiber.mode & 1)) return 2; if (0 !== (executionContext & 2) && 0 !== workInProgressRootRenderLanes) return workInProgressRootRenderLanes & -workInProgressRootRenderLanes; - if (null !== ReactCurrentBatchConfig$1.transition) - return requestTransitionLane(); + fiber = ReactCurrentBatchConfig$1.transition; + null !== fiber && fiber._callbacks.add(handleAsyncAction); + if (null !== fiber) + return ( + 0 === currentEventTransitionLane && + (currentEventTransitionLane = claimNextTransitionLane()), + currentEventTransitionLane + ); fiber = currentUpdatePriority; return 0 !== fiber ? fiber : 32; } @@ -7657,7 +7797,7 @@ function requestDeferredLane() { (workInProgressDeferredLane = 0 !== (workInProgressRootRenderLanes & 536870912) ? 536870912 - : requestTransitionLane()); + : claimNextTransitionLane()); var suspenseHandler = suspenseHandlerStackCursor.current; null !== suspenseHandler && (suspenseHandler.flags |= 32); return workInProgressDeferredLane; @@ -7702,26 +7842,25 @@ function performConcurrentWorkOnRoot(root, didTimeout) { root === workInProgressRoot ? workInProgressRootRenderLanes : 0 ); if (0 === lanes) return null; - var shouldTimeSlice = - 0 === (lanes & 60) && 0 === (lanes & root.expiredLanes) && !didTimeout; - didTimeout = shouldTimeSlice + var exitStatus = (didTimeout = + 0 === (lanes & 60) && 0 === (lanes & root.expiredLanes) && !didTimeout) ? renderRootConcurrent(root, lanes) : renderRootSync(root, lanes); - if (0 !== didTimeout) { - var renderWasConcurrent = shouldTimeSlice; + if (0 !== exitStatus) { + var renderWasConcurrent = didTimeout; do { - if (6 === didTimeout) markRootSuspended(root, lanes, 0); + if (6 === exitStatus) markRootSuspended(root, lanes, 0); else { - shouldTimeSlice = root.current.alternate; + didTimeout = root.current.alternate; if ( renderWasConcurrent && - !isRenderConsistentWithExternalStores(shouldTimeSlice) + !isRenderConsistentWithExternalStores(didTimeout) ) { - didTimeout = renderRootSync(root, lanes); + exitStatus = renderRootSync(root, lanes); renderWasConcurrent = !1; continue; } - if (2 === didTimeout) { + if (2 === exitStatus) { renderWasConcurrent = lanes; var errorRetryLanes = getLanesToRetrySynchronouslyOnError( root, @@ -7729,13 +7868,13 @@ function performConcurrentWorkOnRoot(root, didTimeout) { ); 0 !== errorRetryLanes && ((lanes = errorRetryLanes), - (didTimeout = recoverFromConcurrentError( + (exitStatus = recoverFromConcurrentError( root, renderWasConcurrent, errorRetryLanes ))); } - if (1 === didTimeout) + if (1 === exitStatus) throw ( ((originalCallbackNode = workInProgressRootFatalError), prepareFreshStack(root, 0), @@ -7743,11 +7882,11 @@ function performConcurrentWorkOnRoot(root, didTimeout) { ensureRootIsScheduled(root), originalCallbackNode) ); - root.finishedWork = shouldTimeSlice; + root.finishedWork = didTimeout; root.finishedLanes = lanes; a: { renderWasConcurrent = root; - switch (didTimeout) { + switch (exitStatus) { case 0: case 1: throw Error("Root did not complete. This is a bug in React."); @@ -7770,8 +7909,9 @@ function performConcurrentWorkOnRoot(root, didTimeout) { } if ( (lanes & 62914560) === lanes && - ((didTimeout = globalMostRecentFallbackTime + 300 - now()), - 10 < didTimeout) + 3 === exitStatus && + ((exitStatus = globalMostRecentFallbackTime + 300 - now()), + 10 < exitStatus) ) { markRootSuspended( renderWasConcurrent, @@ -7783,19 +7923,19 @@ function performConcurrentWorkOnRoot(root, didTimeout) { commitRootWhenReady.bind( null, renderWasConcurrent, - shouldTimeSlice, + didTimeout, workInProgressRootRecoverableErrors, workInProgressTransitions, lanes, workInProgressDeferredLane ), - didTimeout + exitStatus ); break a; } commitRootWhenReady( renderWasConcurrent, - shouldTimeSlice, + didTimeout, workInProgressRootRecoverableErrors, workInProgressTransitions, lanes, @@ -8044,7 +8184,7 @@ function renderRootSync(root, lanes) { default: (workInProgressSuspendedReason = 0), (workInProgressThrownValue = null), - throwAndUnwindWorkLoop(unitOfWork, thrownValue); + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); } } workLoopSync(); @@ -8086,7 +8226,7 @@ function renderRootConcurrent(root, lanes) { case 1: workInProgressSuspendedReason = 0; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(lanes, thrownValue); + throwAndUnwindWorkLoop(root, lanes, thrownValue); break; case 2: if (isThenableResolved(thrownValue)) { @@ -8116,7 +8256,7 @@ function renderRootConcurrent(root, lanes) { replaySuspendedUnitOfWork(lanes)) : ((workInProgressSuspendedReason = 0), (workInProgressThrownValue = null), - throwAndUnwindWorkLoop(lanes, thrownValue)); + throwAndUnwindWorkLoop(root, lanes, thrownValue)); break; case 5: switch (workInProgress.tag) { @@ -8139,12 +8279,12 @@ function renderRootConcurrent(root, lanes) { } workInProgressSuspendedReason = 0; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(lanes, thrownValue); + throwAndUnwindWorkLoop(root, lanes, thrownValue); break; case 6: workInProgressSuspendedReason = 0; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(lanes, thrownValue); + throwAndUnwindWorkLoop(root, lanes, thrownValue); break; case 8: resetWorkInProgressStack(); @@ -8235,191 +8375,55 @@ function replaySuspendedUnitOfWork(unitOfWork) { : (workInProgress = current); ReactCurrentOwner.current = null; } -function throwAndUnwindWorkLoop(unitOfWork, thrownValue) { +function throwAndUnwindWorkLoop(root, unitOfWork, thrownValue) { resetContextDependencies(); resetHooksOnUnwind(unitOfWork); thenableState$1 = null; thenableIndexCounter$1 = 0; var returnFiber = unitOfWork.return; - if (null === returnFiber || null === workInProgressRoot) - (workInProgressRootExitStatus = 1), - (workInProgressRootFatalError = thrownValue), - (workInProgress = null); - else { - try { - a: { - var root = workInProgressRoot, - value = thrownValue; - thrownValue = workInProgressRootRenderLanes; - unitOfWork.flags |= 32768; - if ( - null !== value && - "object" === typeof value && - "function" === typeof value.then - ) { - var wakeable = value, - tag = unitOfWork.tag; - if ( - 0 === (unitOfWork.mode & 1) && - (0 === tag || 11 === tag || 15 === tag) - ) { - var currentSource = unitOfWork.alternate; - currentSource - ? ((unitOfWork.updateQueue = currentSource.updateQueue), - (unitOfWork.memoizedState = currentSource.memoizedState), - (unitOfWork.lanes = currentSource.lanes)) - : ((unitOfWork.updateQueue = null), - (unitOfWork.memoizedState = null)); - } - var suspenseBoundary = suspenseHandlerStackCursor.current; - if (null !== suspenseBoundary) { - switch (suspenseBoundary.tag) { - case 13: - unitOfWork.mode & 1 && - (null === shellBoundary - ? renderDidSuspendDelayIfPossible() - : null === suspenseBoundary.alternate && - 0 === workInProgressRootExitStatus && - (workInProgressRootExitStatus = 3)); - suspenseBoundary.flags &= -257; - if (0 === (suspenseBoundary.mode & 1)) - if (suspenseBoundary === returnFiber) - suspenseBoundary.flags |= 65536; - else { - suspenseBoundary.flags |= 128; - unitOfWork.flags |= 131072; - unitOfWork.flags &= -52805; - if (1 === unitOfWork.tag) - if (null === unitOfWork.alternate) unitOfWork.tag = 17; - else { - var update = createUpdate(2); - update.tag = 2; - enqueueUpdate(unitOfWork, update, 2); - } - unitOfWork.lanes |= 2; - } - else - (suspenseBoundary.flags |= 65536), - (suspenseBoundary.lanes = thrownValue); - if (wakeable === noopSuspenseyCommitThenable) - suspenseBoundary.flags |= 16384; - else { - var retryQueue = suspenseBoundary.updateQueue; - null === retryQueue - ? (suspenseBoundary.updateQueue = new Set([wakeable])) - : retryQueue.add(wakeable); - suspenseBoundary.mode & 1 && - attachPingListener(root, wakeable, thrownValue); - } - break a; - case 22: - if (suspenseBoundary.mode & 1) { - suspenseBoundary.flags |= 65536; - if (wakeable === noopSuspenseyCommitThenable) - suspenseBoundary.flags |= 16384; - else { - var offscreenQueue = suspenseBoundary.updateQueue; - if (null === offscreenQueue) { - var newOffscreenQueue = { - transitions: null, - markerInstances: null, - retryQueue: new Set([wakeable]) - }; - suspenseBoundary.updateQueue = newOffscreenQueue; - } else { - var retryQueue$33 = offscreenQueue.retryQueue; - null === retryQueue$33 - ? (offscreenQueue.retryQueue = new Set([wakeable])) - : retryQueue$33.add(wakeable); - } - attachPingListener(root, wakeable, thrownValue); - } - break a; - } - } - throw Error( - "Unexpected Suspense handler tag (" + - suspenseBoundary.tag + - "). This is a bug in React." - ); - } - if (1 === root.tag) { - attachPingListener(root, wakeable, thrownValue); - renderDidSuspendDelayIfPossible(); - break a; - } else - value = Error( - "A component suspended while responding to synchronous input. This will cause the UI to be replaced with a loading indicator. To fix, updates that suspend should be wrapped with startTransition." - ); - } - root = value = createCapturedValueAtFiber(value, unitOfWork); - 4 !== workInProgressRootExitStatus && - (workInProgressRootExitStatus = 2); - null === workInProgressRootConcurrentErrors - ? (workInProgressRootConcurrentErrors = [root]) - : workInProgressRootConcurrentErrors.push(root); - root = returnFiber; - do { - switch (root.tag) { - case 3: - var errorInfo = value; - root.flags |= 65536; - thrownValue &= -thrownValue; - root.lanes |= thrownValue; - var update$jscomp$0 = createRootErrorUpdate( - root, - errorInfo, - thrownValue - ); - enqueueCapturedUpdate(root, update$jscomp$0); - break a; - case 1: - tag = value; - var ctor = root.type, - instance = root.stateNode; - if ( - 0 === (root.flags & 128) && - ("function" === typeof ctor.getDerivedStateFromError || - (null !== instance && - "function" === typeof instance.componentDidCatch && - (null === legacyErrorBoundariesThatAlreadyFailed || - !legacyErrorBoundariesThatAlreadyFailed.has(instance)))) - ) { - root.flags |= 65536; - update$jscomp$0 = thrownValue & -thrownValue; - root.lanes |= update$jscomp$0; - errorInfo = createClassErrorUpdate(root, tag, update$jscomp$0); - enqueueCapturedUpdate(root, errorInfo); - break a; - } - } - root = root.return; - } while (null !== root); - } - } catch (error) { - throw ((workInProgress = returnFiber), error); + try { + if ( + throwException( + root, + returnFiber, + unitOfWork, + thrownValue, + workInProgressRootRenderLanes + ) + ) { + workInProgressRootExitStatus = 1; + workInProgressRootFatalError = thrownValue; + workInProgress = null; + return; } - if (unitOfWork.flags & 32768) - a: { - do { - returnFiber = unwindWork(unitOfWork.alternate, unitOfWork); - if (null !== returnFiber) { - returnFiber.flags &= 32767; - workInProgress = returnFiber; - break a; - } - unitOfWork = unitOfWork.return; - null !== unitOfWork && - ((unitOfWork.flags |= 32768), - (unitOfWork.subtreeFlags = 0), - (unitOfWork.deletions = null)); - workInProgress = unitOfWork; - } while (null !== unitOfWork); - workInProgressRootExitStatus = 6; - workInProgress = null; - } - else completeUnitOfWork(unitOfWork); + } catch (error) { + if (null !== returnFiber) throw ((workInProgress = returnFiber), error); + workInProgressRootExitStatus = 1; + workInProgressRootFatalError = thrownValue; + workInProgress = null; + return; } + if (unitOfWork.flags & 32768) + a: { + root = unitOfWork; + do { + unitOfWork = unwindWork(root.alternate, root); + if (null !== unitOfWork) { + unitOfWork.flags &= 32767; + workInProgress = unitOfWork; + break a; + } + root = root.return; + null !== root && + ((root.flags |= 32768), + (root.subtreeFlags = 0), + (root.deletions = null)); + workInProgress = root; + } while (null !== root); + workInProgressRootExitStatus = 6; + workInProgress = null; + } + else completeUnitOfWork(unitOfWork); } function completeUnitOfWork(unitOfWork) { var completedWork = unitOfWork; @@ -9267,21 +9271,20 @@ function createFiberFromTypeAndProps( type, key, pendingProps, - source, owner, mode, lanes ) { - owner = 2; - source = type; - if ("function" === typeof type) shouldConstruct(type) && (owner = 1); - else if ("string" === typeof type) owner = 5; + var fiberTag = 2; + owner = type; + if ("function" === typeof type) shouldConstruct(type) && (fiberTag = 1); + else if ("string" === typeof type) fiberTag = 5; else a: switch (type) { case REACT_FRAGMENT_TYPE: return createFiberFromFragment(pendingProps.children, mode, lanes, key); case REACT_STRICT_MODE_TYPE: - owner = 8; + fiberTag = 8; mode |= 8; 0 !== (mode & 1) && (mode |= 16); break; @@ -9312,20 +9315,20 @@ function createFiberFromTypeAndProps( if ("object" === typeof type && null !== type) switch (type.$$typeof) { case REACT_PROVIDER_TYPE: - owner = 10; + fiberTag = 10; break a; case REACT_CONTEXT_TYPE: - owner = 9; + fiberTag = 9; break a; case REACT_FORWARD_REF_TYPE: - owner = 11; + fiberTag = 11; break a; case REACT_MEMO_TYPE: - owner = 14; + fiberTag = 14; break a; case REACT_LAZY_TYPE: - owner = 16; - source = null; + fiberTag = 16; + owner = null; break a; } throw Error( @@ -9333,9 +9336,9 @@ function createFiberFromTypeAndProps( ((null == type ? type : typeof type) + ".") ); } - key = createFiber(owner, pendingProps, key, mode); + key = createFiber(fiberTag, pendingProps, key, mode); key.elementType = type; - key.type = source; + key.type = owner; key.lanes = lanes; return key; } @@ -9584,7 +9587,7 @@ var roots = new Map(), devToolsConfig$jscomp$inline_1114 = { findFiberByHostInstance: getInstanceFromTag, bundleType: 0, - version: "18.3.0-canary-b2d637128-20240123", + version: "18.3.0-canary-03d6f7cf0-20240209", rendererPackageName: "react-native-renderer", rendererConfig: { getInspectorDataForInstance: getInspectorDataForInstance, @@ -9600,7 +9603,7 @@ var roots = new Map(), }.bind(null, findNodeHandle) } }; -var internals$jscomp$inline_1370 = { +var internals$jscomp$inline_1353 = { bundleType: devToolsConfig$jscomp$inline_1114.bundleType, version: devToolsConfig$jscomp$inline_1114.version, rendererPackageName: devToolsConfig$jscomp$inline_1114.rendererPackageName, @@ -9627,19 +9630,19 @@ var internals$jscomp$inline_1370 = { scheduleRoot: null, setRefreshHandler: null, getCurrentFiber: null, - reconcilerVersion: "18.3.0-canary-b2d637128-20240123" + reconcilerVersion: "18.3.0-canary-03d6f7cf0-20240209" }; if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) { - var hook$jscomp$inline_1371 = __REACT_DEVTOOLS_GLOBAL_HOOK__; + var hook$jscomp$inline_1354 = __REACT_DEVTOOLS_GLOBAL_HOOK__; if ( - !hook$jscomp$inline_1371.isDisabled && - hook$jscomp$inline_1371.supportsFiber + !hook$jscomp$inline_1354.isDisabled && + hook$jscomp$inline_1354.supportsFiber ) try { - (rendererID = hook$jscomp$inline_1371.inject( - internals$jscomp$inline_1370 + (rendererID = hook$jscomp$inline_1354.inject( + internals$jscomp$inline_1353 )), - (injectedHook = hook$jscomp$inline_1371); + (injectedHook = hook$jscomp$inline_1354); } catch (err) {} } exports.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = { diff --git a/packages/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.js b/packages/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.js index 4f7eec628d0651..c67b0c4dbd76ee 100644 --- a/packages/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.js +++ b/packages/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.js @@ -8,7 +8,7 @@ * @nolint * @providesModule ReactNativeRenderer-profiling * @preventMunge - * @generated SignedSource<> + * @generated SignedSource<<5df973db061e36edfd192d75fab51c36>> */ "use strict"; @@ -944,7 +944,7 @@ eventPluginOrder = Array.prototype.slice.call([ "ReactNativeBridgeEventPlugin" ]); recomputePluginOrdering(); -var injectedNamesToPlugins$jscomp$inline_251 = { +var injectedNamesToPlugins$jscomp$inline_253 = { ResponderEventPlugin: ResponderEventPlugin, ReactNativeBridgeEventPlugin: { eventTypes: {}, @@ -990,32 +990,32 @@ var injectedNamesToPlugins$jscomp$inline_251 = { } } }, - isOrderingDirty$jscomp$inline_252 = !1, - pluginName$jscomp$inline_253; -for (pluginName$jscomp$inline_253 in injectedNamesToPlugins$jscomp$inline_251) + isOrderingDirty$jscomp$inline_254 = !1, + pluginName$jscomp$inline_255; +for (pluginName$jscomp$inline_255 in injectedNamesToPlugins$jscomp$inline_253) if ( - injectedNamesToPlugins$jscomp$inline_251.hasOwnProperty( - pluginName$jscomp$inline_253 + injectedNamesToPlugins$jscomp$inline_253.hasOwnProperty( + pluginName$jscomp$inline_255 ) ) { - var pluginModule$jscomp$inline_254 = - injectedNamesToPlugins$jscomp$inline_251[pluginName$jscomp$inline_253]; + var pluginModule$jscomp$inline_256 = + injectedNamesToPlugins$jscomp$inline_253[pluginName$jscomp$inline_255]; if ( - !namesToPlugins.hasOwnProperty(pluginName$jscomp$inline_253) || - namesToPlugins[pluginName$jscomp$inline_253] !== - pluginModule$jscomp$inline_254 + !namesToPlugins.hasOwnProperty(pluginName$jscomp$inline_255) || + namesToPlugins[pluginName$jscomp$inline_255] !== + pluginModule$jscomp$inline_256 ) { - if (namesToPlugins[pluginName$jscomp$inline_253]) + if (namesToPlugins[pluginName$jscomp$inline_255]) throw Error( "EventPluginRegistry: Cannot inject two different event plugins using the same name, `" + - (pluginName$jscomp$inline_253 + "`.") + (pluginName$jscomp$inline_255 + "`.") ); - namesToPlugins[pluginName$jscomp$inline_253] = - pluginModule$jscomp$inline_254; - isOrderingDirty$jscomp$inline_252 = !0; + namesToPlugins[pluginName$jscomp$inline_255] = + pluginModule$jscomp$inline_256; + isOrderingDirty$jscomp$inline_254 = !0; } } -isOrderingDirty$jscomp$inline_252 && recomputePluginOrdering(); +isOrderingDirty$jscomp$inline_254 && recomputePluginOrdering(); var instanceCache = new Map(), instanceProps = new Map(); function getInstanceFromTag(tag) { @@ -1170,7 +1170,6 @@ var ReactSharedInternals = REACT_PROFILER_TYPE = Symbol.for("react.profiler"), REACT_PROVIDER_TYPE = Symbol.for("react.provider"), REACT_CONTEXT_TYPE = Symbol.for("react.context"), - REACT_SERVER_CONTEXT_TYPE = Symbol.for("react.server_context"), REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"), REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"), REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"), @@ -1872,6 +1871,12 @@ function getLanesToRetrySynchronouslyOnError(root, originallyAttemptedLanes) { root = root.pendingLanes & -536870913; return 0 !== root ? root : root & 536870912 ? 536870912 : 0; } +function claimNextTransitionLane() { + var lane = nextTransitionLane; + nextTransitionLane <<= 1; + 0 === (nextTransitionLane & 4194176) && (nextTransitionLane = 128); + return lane; +} function claimNextRetryLane() { var lane = nextRetryLane; nextRetryLane <<= 1; @@ -2024,14 +2029,14 @@ function getPublicInstance(instance) { } var scheduleTimeout = setTimeout, cancelTimeout = clearTimeout; -function describeComponentFrame(name, source, ownerName) { - source = ""; - ownerName && (source = " (created by " + ownerName + ")"); - return "\n in " + (name || "Unknown") + source; +function describeComponentFrame(name, ownerName) { + var sourceInfo = ""; + ownerName && (sourceInfo = " (created by " + ownerName + ")"); + return "\n in " + (name || "Unknown") + sourceInfo; } -function describeFunctionComponentFrame(fn, source) { +function describeFunctionComponentFrame(fn) { return fn - ? describeComponentFrame(fn.displayName || fn.name || null, source, null) + ? describeComponentFrame(fn.displayName || fn.name || null, null) : ""; } var hasOwnProperty = Object.prototype.hasOwnProperty, @@ -2253,6 +2258,211 @@ function getRootForUpdatedFiber(sourceFiber) { (sourceFiber = parent), (parent = sourceFiber.return); return 3 === sourceFiber.tag ? sourceFiber.stateNode : null; } +var firstScheduledRoot = null, + lastScheduledRoot = null, + didScheduleMicrotask = !1, + mightHavePendingSyncWork = !1, + isFlushingWork = !1, + currentEventTransitionLane = 0; +function ensureRootIsScheduled(root) { + root !== lastScheduledRoot && + null === root.next && + (null === lastScheduledRoot + ? (firstScheduledRoot = lastScheduledRoot = root) + : (lastScheduledRoot = lastScheduledRoot.next = root)); + mightHavePendingSyncWork = !0; + didScheduleMicrotask || + ((didScheduleMicrotask = !0), + scheduleCallback$2(ImmediatePriority, processRootScheduleInMicrotask)); + scheduleTaskForRootDuringMicrotask(root, now$1()); +} +function flushSyncWorkAcrossRoots_impl(onlyLegacy) { + if (!isFlushingWork && mightHavePendingSyncWork) { + var errors = null; + isFlushingWork = !0; + do { + var didPerformSomeWork = !1; + for (var root = firstScheduledRoot; null !== root; ) { + if (!onlyLegacy || 0 === root.tag) { + var workInProgressRootRenderLanes$13 = workInProgressRootRenderLanes, + nextLanes = getNextLanes( + root, + root === workInProgressRoot ? workInProgressRootRenderLanes$13 : 0 + ); + if (0 !== (nextLanes & 3)) + try { + didPerformSomeWork = !0; + workInProgressRootRenderLanes$13 = root; + if (0 !== (executionContext & 6)) + throw Error("Should not already be working."); + if (!flushPassiveEffects()) { + currentUpdateIsNested = nestedUpdateScheduled; + nestedUpdateScheduled = !1; + var exitStatus = renderRootSync( + workInProgressRootRenderLanes$13, + nextLanes + ); + if ( + 0 !== workInProgressRootRenderLanes$13.tag && + 2 === exitStatus + ) { + var originallyAttemptedLanes = nextLanes, + errorRetryLanes = getLanesToRetrySynchronouslyOnError( + workInProgressRootRenderLanes$13, + originallyAttemptedLanes + ); + 0 !== errorRetryLanes && + ((nextLanes = errorRetryLanes), + (exitStatus = recoverFromConcurrentError( + workInProgressRootRenderLanes$13, + originallyAttemptedLanes, + errorRetryLanes + ))); + } + if (1 === exitStatus) + throw ( + ((originallyAttemptedLanes = workInProgressRootFatalError), + prepareFreshStack(workInProgressRootRenderLanes$13, 0), + markRootSuspended( + workInProgressRootRenderLanes$13, + nextLanes, + 0 + ), + ensureRootIsScheduled(workInProgressRootRenderLanes$13), + originallyAttemptedLanes) + ); + 6 === exitStatus + ? markRootSuspended( + workInProgressRootRenderLanes$13, + nextLanes, + workInProgressDeferredLane + ) + : ((workInProgressRootRenderLanes$13.finishedWork = + workInProgressRootRenderLanes$13.current.alternate), + (workInProgressRootRenderLanes$13.finishedLanes = + nextLanes), + commitRoot( + workInProgressRootRenderLanes$13, + workInProgressRootRecoverableErrors, + workInProgressTransitions, + workInProgressDeferredLane + )); + } + ensureRootIsScheduled(workInProgressRootRenderLanes$13); + } catch (error) { + null === errors ? (errors = [error]) : errors.push(error); + } + } + root = root.next; + } + } while (didPerformSomeWork); + isFlushingWork = !1; + if (null !== errors) { + if (1 < errors.length) { + if ("function" === typeof AggregateError) + throw new AggregateError(errors); + for (onlyLegacy = 1; onlyLegacy < errors.length; onlyLegacy++) + (didPerformSomeWork = throwError.bind(null, errors[onlyLegacy])), + scheduleCallback$2(ImmediatePriority, didPerformSomeWork); + } + throw errors[0]; + } + } +} +function throwError(error) { + throw error; +} +function processRootScheduleInMicrotask() { + mightHavePendingSyncWork = didScheduleMicrotask = !1; + for ( + var currentTime = now$1(), prev = null, root = firstScheduledRoot; + null !== root; + + ) { + var next = root.next, + nextLanes = scheduleTaskForRootDuringMicrotask(root, currentTime); + 0 === nextLanes + ? ((root.next = null), + null === prev ? (firstScheduledRoot = next) : (prev.next = next), + null === next && (lastScheduledRoot = prev)) + : ((prev = root), + 0 !== (nextLanes & 3) && (mightHavePendingSyncWork = !0)); + root = next; + } + currentEventTransitionLane = 0; + flushSyncWorkAcrossRoots_impl(!1); +} +function scheduleTaskForRootDuringMicrotask(root, currentTime) { + for ( + var suspendedLanes = root.suspendedLanes, + pingedLanes = root.pingedLanes, + expirationTimes = root.expirationTimes, + lanes = root.pendingLanes & -62914561; + 0 < lanes; + + ) { + var index$5 = 31 - clz32(lanes), + lane = 1 << index$5, + expirationTime = expirationTimes[index$5]; + if (-1 === expirationTime) { + if (0 === (lane & suspendedLanes) || 0 !== (lane & pingedLanes)) + expirationTimes[index$5] = computeExpirationTime(lane, currentTime); + } else expirationTime <= currentTime && (root.expiredLanes |= lane); + lanes &= ~lane; + } + currentTime = workInProgressRoot; + suspendedLanes = workInProgressRootRenderLanes; + suspendedLanes = getNextLanes( + root, + root === currentTime ? suspendedLanes : 0 + ); + pingedLanes = root.callbackNode; + if ( + 0 === suspendedLanes || + (root === currentTime && 2 === workInProgressSuspendedReason) || + null !== root.cancelPendingCommit + ) + return ( + null !== pingedLanes && + null !== pingedLanes && + cancelCallback$1(pingedLanes), + (root.callbackNode = null), + (root.callbackPriority = 0) + ); + if (0 !== (suspendedLanes & 3)) + return ( + null !== pingedLanes && + null !== pingedLanes && + cancelCallback$1(pingedLanes), + (root.callbackPriority = 2), + (root.callbackNode = null), + 2 + ); + currentTime = suspendedLanes & -suspendedLanes; + if (currentTime === root.callbackPriority) return currentTime; + null !== pingedLanes && cancelCallback$1(pingedLanes); + switch (lanesToEventPriority(suspendedLanes)) { + case 2: + suspendedLanes = ImmediatePriority; + break; + case 8: + suspendedLanes = UserBlockingPriority; + break; + case 32: + suspendedLanes = NormalPriority; + break; + case 268435456: + suspendedLanes = IdlePriority; + break; + default: + suspendedLanes = NormalPriority; + } + pingedLanes = performConcurrentWorkOnRoot.bind(null, root); + suspendedLanes = scheduleCallback$2(suspendedLanes, pingedLanes); + root.callbackPriority = currentTime; + root.callbackNode = suspendedLanes; + return currentTime; +} var hasForceUpdate = !1; function initializeUpdateQueue(fiber) { fiber.updateQueue = { @@ -2516,21 +2726,21 @@ function describeFiber(fiber) { case 26: case 27: case 5: - return describeComponentFrame(fiber.type, null, null); + return describeComponentFrame(fiber.type, null); case 16: - return describeComponentFrame("Lazy", null, null); + return describeComponentFrame("Lazy", null); case 13: - return describeComponentFrame("Suspense", null, null); + return describeComponentFrame("Suspense", null); case 19: - return describeComponentFrame("SuspenseList", null, null); + return describeComponentFrame("SuspenseList", null); case 0: case 2: case 15: - return describeFunctionComponentFrame(fiber.type, null); + return describeFunctionComponentFrame(fiber.type); case 11: - return describeFunctionComponentFrame(fiber.type.render, null); + return describeFunctionComponentFrame(fiber.type.render); case 1: - return (fiber = describeFunctionComponentFrame(fiber.type, null)), fiber; + return (fiber = describeFunctionComponentFrame(fiber.type)), fiber; default: return ""; } @@ -2794,7 +3004,6 @@ function createChildReconciler(shouldTrackSideEffects) { element.key, element.props, null, - null, returnFiber.mode, lanes ); @@ -2857,7 +3066,6 @@ function createChildReconciler(shouldTrackSideEffects) { newChild.key, newChild.props, null, - null, returnFiber.mode, lanes )), @@ -2892,10 +3100,7 @@ function createChildReconciler(shouldTrackSideEffects) { ); if ("function" === typeof newChild.then) return createChild(returnFiber, unwrapThenable(newChild), lanes); - if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) + if (newChild.$$typeof === REACT_CONTEXT_TYPE) return createChild( returnFiber, readContextDuringReconcilation(returnFiber, newChild, lanes), @@ -2941,10 +3146,7 @@ function createChildReconciler(shouldTrackSideEffects) { unwrapThenable(newChild), lanes ); - if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) + if (newChild.$$typeof === REACT_CONTEXT_TYPE) return updateSlot( returnFiber, oldFiber, @@ -3011,10 +3213,7 @@ function createChildReconciler(shouldTrackSideEffects) { unwrapThenable(newChild), lanes ); - if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) + if (newChild.$$typeof === REACT_CONTEXT_TYPE) return updateFromMap( existingChildren, returnFiber, @@ -3263,7 +3462,6 @@ function createChildReconciler(shouldTrackSideEffects) { newChild.key, newChild.props, null, - null, returnFiber.mode, lanes )), @@ -3346,10 +3544,7 @@ function createChildReconciler(shouldTrackSideEffects) { unwrapThenable(newChild), lanes ); - if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) + if (newChild.$$typeof === REACT_CONTEXT_TYPE) return reconcileChildFibersImpl( returnFiber, currentFirstChild, @@ -3472,219 +3667,6 @@ function findFirstSuspended(row) { } return null; } -var firstScheduledRoot = null, - lastScheduledRoot = null, - didScheduleMicrotask = !1, - mightHavePendingSyncWork = !1, - isFlushingWork = !1, - currentEventTransitionLane = 0; -function ensureRootIsScheduled(root) { - root !== lastScheduledRoot && - null === root.next && - (null === lastScheduledRoot - ? (firstScheduledRoot = lastScheduledRoot = root) - : (lastScheduledRoot = lastScheduledRoot.next = root)); - mightHavePendingSyncWork = !0; - didScheduleMicrotask || - ((didScheduleMicrotask = !0), - scheduleCallback$2(ImmediatePriority, processRootScheduleInMicrotask)); -} -function flushSyncWorkAcrossRoots_impl(onlyLegacy) { - if (!isFlushingWork && mightHavePendingSyncWork) { - var errors = null; - isFlushingWork = !0; - do { - var didPerformSomeWork = !1; - for (var root = firstScheduledRoot; null !== root; ) { - if (!onlyLegacy || 0 === root.tag) { - var workInProgressRootRenderLanes$30 = workInProgressRootRenderLanes, - nextLanes = getNextLanes( - root, - root === workInProgressRoot ? workInProgressRootRenderLanes$30 : 0 - ); - if (0 !== (nextLanes & 3)) - try { - didPerformSomeWork = !0; - workInProgressRootRenderLanes$30 = root; - if (0 !== (executionContext & 6)) - throw Error("Should not already be working."); - if (!flushPassiveEffects()) { - currentUpdateIsNested = nestedUpdateScheduled; - nestedUpdateScheduled = !1; - var exitStatus = renderRootSync( - workInProgressRootRenderLanes$30, - nextLanes - ); - if ( - 0 !== workInProgressRootRenderLanes$30.tag && - 2 === exitStatus - ) { - var originallyAttemptedLanes = nextLanes, - errorRetryLanes = getLanesToRetrySynchronouslyOnError( - workInProgressRootRenderLanes$30, - originallyAttemptedLanes - ); - 0 !== errorRetryLanes && - ((nextLanes = errorRetryLanes), - (exitStatus = recoverFromConcurrentError( - workInProgressRootRenderLanes$30, - originallyAttemptedLanes, - errorRetryLanes - ))); - } - if (1 === exitStatus) - throw ( - ((originallyAttemptedLanes = workInProgressRootFatalError), - prepareFreshStack(workInProgressRootRenderLanes$30, 0), - markRootSuspended( - workInProgressRootRenderLanes$30, - nextLanes, - 0 - ), - ensureRootIsScheduled(workInProgressRootRenderLanes$30), - originallyAttemptedLanes) - ); - 6 === exitStatus - ? markRootSuspended( - workInProgressRootRenderLanes$30, - nextLanes, - workInProgressDeferredLane - ) - : ((workInProgressRootRenderLanes$30.finishedWork = - workInProgressRootRenderLanes$30.current.alternate), - (workInProgressRootRenderLanes$30.finishedLanes = - nextLanes), - commitRoot( - workInProgressRootRenderLanes$30, - workInProgressRootRecoverableErrors, - workInProgressTransitions, - workInProgressDeferredLane - )); - } - ensureRootIsScheduled(workInProgressRootRenderLanes$30); - } catch (error) { - null === errors ? (errors = [error]) : errors.push(error); - } - } - root = root.next; - } - } while (didPerformSomeWork); - isFlushingWork = !1; - if (null !== errors) { - if (1 < errors.length) { - if ("function" === typeof AggregateError) - throw new AggregateError(errors); - for (onlyLegacy = 1; onlyLegacy < errors.length; onlyLegacy++) - (didPerformSomeWork = throwError.bind(null, errors[onlyLegacy])), - scheduleCallback$2(ImmediatePriority, didPerformSomeWork); - } - throw errors[0]; - } - } -} -function throwError(error) { - throw error; -} -function processRootScheduleInMicrotask() { - mightHavePendingSyncWork = didScheduleMicrotask = !1; - for ( - var currentTime = now$1(), prev = null, root = firstScheduledRoot; - null !== root; - - ) { - var next = root.next, - nextLanes = scheduleTaskForRootDuringMicrotask(root, currentTime); - 0 === nextLanes - ? ((root.next = null), - null === prev ? (firstScheduledRoot = next) : (prev.next = next), - null === next && (lastScheduledRoot = prev)) - : ((prev = root), - 0 !== (nextLanes & 3) && (mightHavePendingSyncWork = !0)); - root = next; - } - currentEventTransitionLane = 0; - flushSyncWorkAcrossRoots_impl(!1); -} -function scheduleTaskForRootDuringMicrotask(root, currentTime) { - for ( - var suspendedLanes = root.suspendedLanes, - pingedLanes = root.pingedLanes, - expirationTimes = root.expirationTimes, - lanes = root.pendingLanes & -62914561; - 0 < lanes; - - ) { - var index$5 = 31 - clz32(lanes), - lane = 1 << index$5, - expirationTime = expirationTimes[index$5]; - if (-1 === expirationTime) { - if (0 === (lane & suspendedLanes) || 0 !== (lane & pingedLanes)) - expirationTimes[index$5] = computeExpirationTime(lane, currentTime); - } else expirationTime <= currentTime && (root.expiredLanes |= lane); - lanes &= ~lane; - } - currentTime = workInProgressRoot; - suspendedLanes = workInProgressRootRenderLanes; - suspendedLanes = getNextLanes( - root, - root === currentTime ? suspendedLanes : 0 - ); - pingedLanes = root.callbackNode; - if ( - 0 === suspendedLanes || - (root === currentTime && 2 === workInProgressSuspendedReason) || - null !== root.cancelPendingCommit - ) - return ( - null !== pingedLanes && - null !== pingedLanes && - cancelCallback$1(pingedLanes), - (root.callbackNode = null), - (root.callbackPriority = 0) - ); - if (0 !== (suspendedLanes & 3)) - return ( - null !== pingedLanes && - null !== pingedLanes && - cancelCallback$1(pingedLanes), - (root.callbackPriority = 2), - (root.callbackNode = null), - 2 - ); - currentTime = suspendedLanes & -suspendedLanes; - if (currentTime === root.callbackPriority) return currentTime; - null !== pingedLanes && cancelCallback$1(pingedLanes); - switch (lanesToEventPriority(suspendedLanes)) { - case 2: - suspendedLanes = ImmediatePriority; - break; - case 8: - suspendedLanes = UserBlockingPriority; - break; - case 32: - suspendedLanes = NormalPriority; - break; - case 268435456: - suspendedLanes = IdlePriority; - break; - default: - suspendedLanes = NormalPriority; - } - pingedLanes = performConcurrentWorkOnRoot.bind(null, root); - suspendedLanes = scheduleCallback$2(suspendedLanes, pingedLanes); - root.callbackPriority = currentTime; - root.callbackNode = suspendedLanes; - return currentTime; -} -function requestTransitionLane() { - if (0 === currentEventTransitionLane) { - var lane = nextTransitionLane; - nextTransitionLane <<= 1; - 0 === (nextTransitionLane & 4194176) && (nextTransitionLane = 128); - currentEventTransitionLane = lane; - } - return currentEventTransitionLane; -} var ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher, ReactCurrentBatchConfig$2 = ReactSharedInternals.ReactCurrentBatchConfig, renderLanes = 0, @@ -3862,11 +3844,7 @@ function useThenable(thenable) { function use(usable) { if (null !== usable && "object" === typeof usable) { if ("function" === typeof usable.then) return useThenable(usable); - if ( - usable.$$typeof === REACT_CONTEXT_TYPE || - usable.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) - return readContext(usable); + if (usable.$$typeof === REACT_CONTEXT_TYPE) return readContext(usable); } throw Error("An unsupported type was passed to use(): " + String(usable)); } @@ -4050,7 +4028,11 @@ function forceStoreRerender(fiber) { } function mountStateImpl(initialState) { var hook = mountWorkInProgressHook(); - "function" === typeof initialState && (initialState = initialState()); + if ("function" === typeof initialState) { + var initialStateInitializer = initialState; + initialState = initialStateInitializer(); + shouldDoubleInvokeUserFnsInHooksDEV && initialStateInitializer(); + } hook.memoizedState = hook.baseState = initialState; hook.queue = { pending: null, @@ -4151,10 +4133,10 @@ function updateMemo(nextCreate, deps) { var prevState = hook.memoizedState; if (null !== deps && areHookInputsEqual(deps, prevState[1])) return prevState[0]; + prevState = nextCreate(); shouldDoubleInvokeUserFnsInHooksDEV && nextCreate(); - nextCreate = nextCreate(); - hook.memoizedState = [nextCreate, deps]; - return nextCreate; + hook.memoizedState = [prevState, deps]; + return prevState; } function mountDeferredValueImpl(hook, value, initialValue) { return void 0 !== initialValue && 0 === (renderLanes & 1073741824) @@ -4184,10 +4166,11 @@ function startTransition(fiber, queue, pendingState, finishedState, callback) { var previousPriority = currentUpdatePriority; currentUpdatePriority = 0 !== previousPriority && 8 > previousPriority ? previousPriority : 8; - var prevTransition = ReactCurrentBatchConfig$2.transition; + var prevTransition = ReactCurrentBatchConfig$2.transition, + currentTransition = { _callbacks: new Set() }; ReactCurrentBatchConfig$2.transition = null; dispatchSetState(fiber, queue, pendingState); - ReactCurrentBatchConfig$2.transition = {}; + ReactCurrentBatchConfig$2.transition = currentTransition; try { dispatchSetState(fiber, queue, finishedState), callback(); } catch (error) { @@ -4330,21 +4313,24 @@ var ContextOnlyDispatcher = { useMemo: function (nextCreate, deps) { var hook = mountWorkInProgressHook(); deps = void 0 === deps ? null : deps; + var nextValue = nextCreate(); shouldDoubleInvokeUserFnsInHooksDEV && nextCreate(); - nextCreate = nextCreate(); - hook.memoizedState = [nextCreate, deps]; - return nextCreate; + hook.memoizedState = [nextValue, deps]; + return nextValue; }, useReducer: function (reducer, initialArg, init) { var hook = mountWorkInProgressHook(); - initialArg = void 0 !== init ? init(initialArg) : initialArg; - hook.memoizedState = hook.baseState = initialArg; + if (void 0 !== init) { + var initialState = init(initialArg); + shouldDoubleInvokeUserFnsInHooksDEV && init(initialArg); + } else initialState = initialArg; + hook.memoizedState = hook.baseState = initialState; reducer = { pending: null, lanes: 0, dispatch: null, lastRenderedReducer: reducer, - lastRenderedState: initialArg + lastRenderedState: initialState }; hook.queue = reducer; reducer = reducer.dispatch = dispatchReducerAction.bind( @@ -4790,6 +4776,154 @@ function createClassErrorUpdate(fiber, errorInfo, lane) { }); return lane; } +function throwException( + root, + returnFiber, + sourceFiber, + value, + rootRenderLanes +) { + sourceFiber.flags |= 32768; + isDevToolsPresent && restorePendingUpdaters(root, rootRenderLanes); + if ( + null !== value && + "object" === typeof value && + "function" === typeof value.then + ) { + var tag = sourceFiber.tag; + 0 !== (sourceFiber.mode & 1) || + (0 !== tag && 11 !== tag && 15 !== tag) || + ((tag = sourceFiber.alternate) + ? ((sourceFiber.updateQueue = tag.updateQueue), + (sourceFiber.memoizedState = tag.memoizedState), + (sourceFiber.lanes = tag.lanes)) + : ((sourceFiber.updateQueue = null), + (sourceFiber.memoizedState = null))); + tag = suspenseHandlerStackCursor.current; + if (null !== tag) { + switch (tag.tag) { + case 13: + return ( + sourceFiber.mode & 1 && + (null === shellBoundary + ? renderDidSuspendDelayIfPossible() + : null === tag.alternate && + 0 === workInProgressRootExitStatus && + (workInProgressRootExitStatus = 3)), + (tag.flags &= -257), + 0 === (tag.mode & 1) + ? tag === returnFiber + ? (tag.flags |= 65536) + : ((tag.flags |= 128), + (sourceFiber.flags |= 131072), + (sourceFiber.flags &= -52805), + 1 === sourceFiber.tag && + (null === sourceFiber.alternate + ? (sourceFiber.tag = 17) + : ((returnFiber = createUpdate(2)), + (returnFiber.tag = 2), + enqueueUpdate(sourceFiber, returnFiber, 2))), + (sourceFiber.lanes |= 2)) + : ((tag.flags |= 65536), (tag.lanes = rootRenderLanes)), + value === noopSuspenseyCommitThenable + ? (tag.flags |= 16384) + : ((returnFiber = tag.updateQueue), + null === returnFiber + ? (tag.updateQueue = new Set([value])) + : returnFiber.add(value), + tag.mode & 1 && + attachPingListener(root, value, rootRenderLanes)), + !1 + ); + case 22: + if (tag.mode & 1) + return ( + (tag.flags |= 65536), + value === noopSuspenseyCommitThenable + ? (tag.flags |= 16384) + : ((returnFiber = tag.updateQueue), + null === returnFiber + ? ((returnFiber = { + transitions: null, + markerInstances: null, + retryQueue: new Set([value]) + }), + (tag.updateQueue = returnFiber)) + : ((sourceFiber = returnFiber.retryQueue), + null === sourceFiber + ? (returnFiber.retryQueue = new Set([value])) + : sourceFiber.add(value)), + attachPingListener(root, value, rootRenderLanes)), + !1 + ); + } + throw Error( + "Unexpected Suspense handler tag (" + + tag.tag + + "). This is a bug in React." + ); + } + if (1 === root.tag) + return ( + attachPingListener(root, value, rootRenderLanes), + renderDidSuspendDelayIfPossible(), + !1 + ); + value = Error( + "A component suspended while responding to synchronous input. This will cause the UI to be replaced with a loading indicator. To fix, updates that suspend should be wrapped with startTransition." + ); + } + root = value = createCapturedValueAtFiber(value, sourceFiber); + 4 !== workInProgressRootExitStatus && (workInProgressRootExitStatus = 2); + null === workInProgressRootConcurrentErrors + ? (workInProgressRootConcurrentErrors = [root]) + : workInProgressRootConcurrentErrors.push(root); + if (null === returnFiber) return !0; + root = returnFiber; + do { + switch (root.tag) { + case 3: + return ( + (root.flags |= 65536), + (rootRenderLanes &= -rootRenderLanes), + (root.lanes |= rootRenderLanes), + (rootRenderLanes = createRootErrorUpdate( + root, + value, + rootRenderLanes + )), + enqueueCapturedUpdate(root, rootRenderLanes), + !1 + ); + case 1: + if ( + ((returnFiber = value), + (sourceFiber = root.type), + (tag = root.stateNode), + 0 === (root.flags & 128) && + ("function" === typeof sourceFiber.getDerivedStateFromError || + (null !== tag && + "function" === typeof tag.componentDidCatch && + (null === legacyErrorBoundariesThatAlreadyFailed || + !legacyErrorBoundariesThatAlreadyFailed.has(tag))))) + ) + return ( + (root.flags |= 65536), + (rootRenderLanes &= -rootRenderLanes), + (root.lanes |= rootRenderLanes), + (rootRenderLanes = createClassErrorUpdate( + root, + returnFiber, + rootRenderLanes + )), + enqueueCapturedUpdate(root, rootRenderLanes), + !1 + ); + } + root = root.return; + } while (null !== root); + return !1; +} var ReactCurrentOwner$1 = ReactSharedInternals.ReactCurrentOwner, SelectiveHydrationException = Error( "This is not a real error. It's an implementation detail of React's selective hydration feature. If this leaks into userspace, it's a bug in React. Please file an issue." @@ -4864,7 +4998,6 @@ function updateMemoComponent( Component.type, null, nextProps, - null, workInProgress, workInProgress.mode, renderLanes @@ -5944,6 +6077,7 @@ function readContextForConsumer(consumer, context) { return value; } var ReactCurrentBatchConfig$1 = ReactSharedInternals.ReactCurrentBatchConfig; +function handleAsyncAction() {} function scheduleRetryEffect(workInProgress, retryQueue) { null !== retryQueue ? (workInProgress.flags |= 4) @@ -7303,11 +7437,11 @@ function commitMutationEffectsOnFiber(finishedWork, root) { offscreenSubtreeIsHidden && ((finishedWork = finishedWork.updateQueue), null !== finishedWork && - ((current = finishedWork.callbacks), - null !== current && - ((flags = finishedWork.shared.hiddenCallbacks), + ((flags = finishedWork.callbacks), + null !== flags && + ((current = finishedWork.shared.hiddenCallbacks), (finishedWork.shared.hiddenCallbacks = - null === flags ? current : flags.concat(current))))); + null === current ? flags : current.concat(flags))))); break; case 26: case 27: @@ -7349,13 +7483,13 @@ function commitMutationEffectsOnFiber(finishedWork, root) { throw Error( "This should have a text node initialized. This error is likely caused by a bug in React. Please file an issue." ); - current = finishedWork.stateNode; - flags = finishedWork.memoizedProps; + flags = finishedWork.stateNode; + current = finishedWork.memoizedProps; try { ReactNativePrivateInterface.UIManager.updateView( - current, + flags, "RCTRawText", - { text: flags } + { text: current } ); } catch (error$105) { captureCommitPhaseError(finishedWork, finishedWork.return, error$105); @@ -7374,14 +7508,15 @@ function commitMutationEffectsOnFiber(finishedWork, root) { recursivelyTraverseMutationEffects(root, finishedWork); commitReconciliationEffects(finishedWork); finishedWork.child.flags & 8192 && - (null !== finishedWork.memoizedState) !== - (null !== current && null !== current.memoizedState) && - (globalMostRecentFallbackTime = now$1()); + ((current = null !== current && null !== current.memoizedState), + null === finishedWork.memoizedState || + current || + (globalMostRecentFallbackTime = now$1())); flags & 4 && - ((current = finishedWork.updateQueue), - null !== current && + ((flags = finishedWork.updateQueue), + null !== flags && ((finishedWork.updateQueue = null), - attachSuspenseRetryListeners(finishedWork, current))); + attachSuspenseRetryListeners(finishedWork, flags))); break; case 22: flags & 512 && @@ -7496,21 +7631,21 @@ function commitMutationEffectsOnFiber(finishedWork, root) { root = root.sibling; } flags & 4 && - ((current = finishedWork.updateQueue), - null !== current && - ((flags = current.retryQueue), - null !== flags && - ((current.retryQueue = null), - attachSuspenseRetryListeners(finishedWork, flags)))); + ((flags = finishedWork.updateQueue), + null !== flags && + ((current = flags.retryQueue), + null !== current && + ((flags.retryQueue = null), + attachSuspenseRetryListeners(finishedWork, current)))); break; case 19: recursivelyTraverseMutationEffects(root, finishedWork); commitReconciliationEffects(finishedWork); flags & 4 && - ((current = finishedWork.updateQueue), - null !== current && + ((flags = finishedWork.updateQueue), + null !== flags && ((finishedWork.updateQueue = null), - attachSuspenseRetryListeners(finishedWork, current))); + attachSuspenseRetryListeners(finishedWork, flags))); break; case 21: break; @@ -8045,8 +8180,14 @@ function requestUpdateLane(fiber) { if (0 === (fiber.mode & 1)) return 2; if (0 !== (executionContext & 2) && 0 !== workInProgressRootRenderLanes) return workInProgressRootRenderLanes & -workInProgressRootRenderLanes; - if (null !== ReactCurrentBatchConfig$1.transition) - return requestTransitionLane(); + fiber = ReactCurrentBatchConfig$1.transition; + null !== fiber && fiber._callbacks.add(handleAsyncAction); + if (null !== fiber) + return ( + 0 === currentEventTransitionLane && + (currentEventTransitionLane = claimNextTransitionLane()), + currentEventTransitionLane + ); fiber = currentUpdatePriority; return 0 !== fiber ? fiber : 32; } @@ -8055,7 +8196,7 @@ function requestDeferredLane() { (workInProgressDeferredLane = 0 !== (workInProgressRootRenderLanes & 536870912) ? 536870912 - : requestTransitionLane()); + : claimNextTransitionLane()); var suspenseHandler = suspenseHandlerStackCursor.current; null !== suspenseHandler && (suspenseHandler.flags |= 32); return workInProgressDeferredLane; @@ -8102,26 +8243,25 @@ function performConcurrentWorkOnRoot(root, didTimeout) { root === workInProgressRoot ? workInProgressRootRenderLanes : 0 ); if (0 === lanes) return null; - var shouldTimeSlice = - 0 === (lanes & 60) && 0 === (lanes & root.expiredLanes) && !didTimeout; - didTimeout = shouldTimeSlice + var exitStatus = (didTimeout = + 0 === (lanes & 60) && 0 === (lanes & root.expiredLanes) && !didTimeout) ? renderRootConcurrent(root, lanes) : renderRootSync(root, lanes); - if (0 !== didTimeout) { - var renderWasConcurrent = shouldTimeSlice; + if (0 !== exitStatus) { + var renderWasConcurrent = didTimeout; do { - if (6 === didTimeout) markRootSuspended(root, lanes, 0); + if (6 === exitStatus) markRootSuspended(root, lanes, 0); else { - shouldTimeSlice = root.current.alternate; + didTimeout = root.current.alternate; if ( renderWasConcurrent && - !isRenderConsistentWithExternalStores(shouldTimeSlice) + !isRenderConsistentWithExternalStores(didTimeout) ) { - didTimeout = renderRootSync(root, lanes); + exitStatus = renderRootSync(root, lanes); renderWasConcurrent = !1; continue; } - if (2 === didTimeout) { + if (2 === exitStatus) { renderWasConcurrent = lanes; var errorRetryLanes = getLanesToRetrySynchronouslyOnError( root, @@ -8129,13 +8269,13 @@ function performConcurrentWorkOnRoot(root, didTimeout) { ); 0 !== errorRetryLanes && ((lanes = errorRetryLanes), - (didTimeout = recoverFromConcurrentError( + (exitStatus = recoverFromConcurrentError( root, renderWasConcurrent, errorRetryLanes ))); } - if (1 === didTimeout) + if (1 === exitStatus) throw ( ((originalCallbackNode = workInProgressRootFatalError), prepareFreshStack(root, 0), @@ -8143,11 +8283,11 @@ function performConcurrentWorkOnRoot(root, didTimeout) { ensureRootIsScheduled(root), originalCallbackNode) ); - root.finishedWork = shouldTimeSlice; + root.finishedWork = didTimeout; root.finishedLanes = lanes; a: { renderWasConcurrent = root; - switch (didTimeout) { + switch (exitStatus) { case 0: case 1: throw Error("Root did not complete. This is a bug in React."); @@ -8170,8 +8310,9 @@ function performConcurrentWorkOnRoot(root, didTimeout) { } if ( (lanes & 62914560) === lanes && - ((didTimeout = globalMostRecentFallbackTime + 300 - now$1()), - 10 < didTimeout) + 3 === exitStatus && + ((exitStatus = globalMostRecentFallbackTime + 300 - now$1()), + 10 < exitStatus) ) { markRootSuspended( renderWasConcurrent, @@ -8183,19 +8324,19 @@ function performConcurrentWorkOnRoot(root, didTimeout) { commitRootWhenReady.bind( null, renderWasConcurrent, - shouldTimeSlice, + didTimeout, workInProgressRootRecoverableErrors, workInProgressTransitions, lanes, workInProgressDeferredLane ), - didTimeout + exitStatus ); break a; } commitRootWhenReady( renderWasConcurrent, - shouldTimeSlice, + didTimeout, workInProgressRootRecoverableErrors, workInProgressTransitions, lanes, @@ -8455,7 +8596,7 @@ function renderRootSync(root, lanes) { default: (workInProgressSuspendedReason = 0), (workInProgressThrownValue = null), - throwAndUnwindWorkLoop(memoizedUpdaters, thrownValue); + throwAndUnwindWorkLoop(root, memoizedUpdaters, thrownValue); } } workLoopSync(); @@ -8507,7 +8648,7 @@ function renderRootConcurrent(root, lanes) { case 1: workInProgressSuspendedReason = 0; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(lanes, memoizedUpdaters); + throwAndUnwindWorkLoop(root, lanes, memoizedUpdaters); break; case 2: if (isThenableResolved(memoizedUpdaters)) { @@ -8537,7 +8678,7 @@ function renderRootConcurrent(root, lanes) { replaySuspendedUnitOfWork(lanes)) : ((workInProgressSuspendedReason = 0), (workInProgressThrownValue = null), - throwAndUnwindWorkLoop(lanes, memoizedUpdaters)); + throwAndUnwindWorkLoop(root, lanes, memoizedUpdaters)); break; case 5: switch (workInProgress.tag) { @@ -8560,12 +8701,12 @@ function renderRootConcurrent(root, lanes) { } workInProgressSuspendedReason = 0; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(lanes, memoizedUpdaters); + throwAndUnwindWorkLoop(root, lanes, memoizedUpdaters); break; case 6: workInProgressSuspendedReason = 0; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(lanes, memoizedUpdaters); + throwAndUnwindWorkLoop(root, lanes, memoizedUpdaters); break; case 8: resetWorkInProgressStack(); @@ -8665,200 +8806,63 @@ function replaySuspendedUnitOfWork(unitOfWork) { : (workInProgress = current); ReactCurrentOwner.current = null; } -function throwAndUnwindWorkLoop(unitOfWork, thrownValue) { +function throwAndUnwindWorkLoop(root, unitOfWork, thrownValue) { resetContextDependencies(); resetHooksOnUnwind(unitOfWork); thenableState$1 = null; thenableIndexCounter$1 = 0; var returnFiber = unitOfWork.return; - if (null === returnFiber || null === workInProgressRoot) - (workInProgressRootExitStatus = 1), - (workInProgressRootFatalError = thrownValue), - (workInProgress = null); - else { - try { - a: { - var root = workInProgressRoot, - value = thrownValue; - thrownValue = workInProgressRootRenderLanes; - unitOfWork.flags |= 32768; - isDevToolsPresent && restorePendingUpdaters(root, thrownValue); - if ( - null !== value && - "object" === typeof value && - "function" === typeof value.then - ) { - var wakeable = value, - tag = unitOfWork.tag; - if ( - 0 === (unitOfWork.mode & 1) && - (0 === tag || 11 === tag || 15 === tag) - ) { - var currentSource = unitOfWork.alternate; - currentSource - ? ((unitOfWork.updateQueue = currentSource.updateQueue), - (unitOfWork.memoizedState = currentSource.memoizedState), - (unitOfWork.lanes = currentSource.lanes)) - : ((unitOfWork.updateQueue = null), - (unitOfWork.memoizedState = null)); - } - var suspenseBoundary = suspenseHandlerStackCursor.current; - if (null !== suspenseBoundary) { - switch (suspenseBoundary.tag) { - case 13: - unitOfWork.mode & 1 && - (null === shellBoundary - ? renderDidSuspendDelayIfPossible() - : null === suspenseBoundary.alternate && - 0 === workInProgressRootExitStatus && - (workInProgressRootExitStatus = 3)); - suspenseBoundary.flags &= -257; - if (0 === (suspenseBoundary.mode & 1)) - if (suspenseBoundary === returnFiber) - suspenseBoundary.flags |= 65536; - else { - suspenseBoundary.flags |= 128; - unitOfWork.flags |= 131072; - unitOfWork.flags &= -52805; - if (1 === unitOfWork.tag) - if (null === unitOfWork.alternate) unitOfWork.tag = 17; - else { - var update = createUpdate(2); - update.tag = 2; - enqueueUpdate(unitOfWork, update, 2); - } - unitOfWork.lanes |= 2; - } - else - (suspenseBoundary.flags |= 65536), - (suspenseBoundary.lanes = thrownValue); - if (wakeable === noopSuspenseyCommitThenable) - suspenseBoundary.flags |= 16384; - else { - var retryQueue = suspenseBoundary.updateQueue; - null === retryQueue - ? (suspenseBoundary.updateQueue = new Set([wakeable])) - : retryQueue.add(wakeable); - suspenseBoundary.mode & 1 && - attachPingListener(root, wakeable, thrownValue); - } - break a; - case 22: - if (suspenseBoundary.mode & 1) { - suspenseBoundary.flags |= 65536; - if (wakeable === noopSuspenseyCommitThenable) - suspenseBoundary.flags |= 16384; - else { - var offscreenQueue = suspenseBoundary.updateQueue; - if (null === offscreenQueue) { - var newOffscreenQueue = { - transitions: null, - markerInstances: null, - retryQueue: new Set([wakeable]) - }; - suspenseBoundary.updateQueue = newOffscreenQueue; - } else { - var retryQueue$35 = offscreenQueue.retryQueue; - null === retryQueue$35 - ? (offscreenQueue.retryQueue = new Set([wakeable])) - : retryQueue$35.add(wakeable); - } - attachPingListener(root, wakeable, thrownValue); - } - break a; - } - } - throw Error( - "Unexpected Suspense handler tag (" + - suspenseBoundary.tag + - "). This is a bug in React." - ); - } - if (1 === root.tag) { - attachPingListener(root, wakeable, thrownValue); - renderDidSuspendDelayIfPossible(); - break a; - } else - value = Error( - "A component suspended while responding to synchronous input. This will cause the UI to be replaced with a loading indicator. To fix, updates that suspend should be wrapped with startTransition." - ); - } - root = value = createCapturedValueAtFiber(value, unitOfWork); - 4 !== workInProgressRootExitStatus && - (workInProgressRootExitStatus = 2); - null === workInProgressRootConcurrentErrors - ? (workInProgressRootConcurrentErrors = [root]) - : workInProgressRootConcurrentErrors.push(root); - root = returnFiber; - do { - switch (root.tag) { - case 3: - var errorInfo = value; - root.flags |= 65536; - thrownValue &= -thrownValue; - root.lanes |= thrownValue; - var update$jscomp$0 = createRootErrorUpdate( - root, - errorInfo, - thrownValue - ); - enqueueCapturedUpdate(root, update$jscomp$0); - break a; - case 1: - tag = value; - var ctor = root.type, - instance = root.stateNode; - if ( - 0 === (root.flags & 128) && - ("function" === typeof ctor.getDerivedStateFromError || - (null !== instance && - "function" === typeof instance.componentDidCatch && - (null === legacyErrorBoundariesThatAlreadyFailed || - !legacyErrorBoundariesThatAlreadyFailed.has(instance)))) - ) { - root.flags |= 65536; - update$jscomp$0 = thrownValue & -thrownValue; - root.lanes |= update$jscomp$0; - errorInfo = createClassErrorUpdate(root, tag, update$jscomp$0); - enqueueCapturedUpdate(root, errorInfo); - break a; - } - } - root = root.return; - } while (null !== root); - } - } catch (error) { - throw ((workInProgress = returnFiber), error); + try { + if ( + throwException( + root, + returnFiber, + unitOfWork, + thrownValue, + workInProgressRootRenderLanes + ) + ) { + workInProgressRootExitStatus = 1; + workInProgressRootFatalError = thrownValue; + workInProgress = null; + return; } - if (unitOfWork.flags & 32768) - a: { - do { - returnFiber = unwindWork(unitOfWork.alternate, unitOfWork); - if (null !== returnFiber) { - returnFiber.flags &= 32767; - workInProgress = returnFiber; - break a; - } - if (0 !== (unitOfWork.mode & 2)) { - stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, !1); - returnFiber = unitOfWork.actualDuration; - for (update$jscomp$0 = unitOfWork.child; null !== update$jscomp$0; ) - (returnFiber += update$jscomp$0.actualDuration), - (update$jscomp$0 = update$jscomp$0.sibling); - unitOfWork.actualDuration = returnFiber; - } - unitOfWork = unitOfWork.return; - null !== unitOfWork && - ((unitOfWork.flags |= 32768), - (unitOfWork.subtreeFlags = 0), - (unitOfWork.deletions = null)); - workInProgress = unitOfWork; - } while (null !== unitOfWork); - workInProgressRootExitStatus = 6; - workInProgress = null; - } - else completeUnitOfWork(unitOfWork); + } catch (error) { + if (null !== returnFiber) throw ((workInProgress = returnFiber), error); + workInProgressRootExitStatus = 1; + workInProgressRootFatalError = thrownValue; + workInProgress = null; + return; } + if (unitOfWork.flags & 32768) + a: { + root = unitOfWork; + do { + unitOfWork = unwindWork(root.alternate, root); + if (null !== unitOfWork) { + unitOfWork.flags &= 32767; + workInProgress = unitOfWork; + break a; + } + if (0 !== (root.mode & 2)) { + stopProfilerTimerIfRunningAndRecordDelta(root, !1); + unitOfWork = root.actualDuration; + for (thrownValue = root.child; null !== thrownValue; ) + (unitOfWork += thrownValue.actualDuration), + (thrownValue = thrownValue.sibling); + root.actualDuration = unitOfWork; + } + root = root.return; + null !== root && + ((root.flags |= 32768), + (root.subtreeFlags = 0), + (root.deletions = null)); + workInProgress = root; + } while (null !== root); + workInProgressRootExitStatus = 6; + workInProgress = null; + } + else completeUnitOfWork(unitOfWork); } function completeUnitOfWork(unitOfWork) { var completedWork = unitOfWork; @@ -9777,21 +9781,20 @@ function createFiberFromTypeAndProps( type, key, pendingProps, - source, owner, mode, lanes ) { - owner = 2; - source = type; - if ("function" === typeof type) shouldConstruct(type) && (owner = 1); - else if ("string" === typeof type) owner = 5; + var fiberTag = 2; + owner = type; + if ("function" === typeof type) shouldConstruct(type) && (fiberTag = 1); + else if ("string" === typeof type) fiberTag = 5; else a: switch (type) { case REACT_FRAGMENT_TYPE: return createFiberFromFragment(pendingProps.children, mode, lanes, key); case REACT_STRICT_MODE_TYPE: - owner = 8; + fiberTag = 8; mode |= 8; 0 !== (mode & 1) && (mode |= 16); break; @@ -9823,20 +9826,20 @@ function createFiberFromTypeAndProps( if ("object" === typeof type && null !== type) switch (type.$$typeof) { case REACT_PROVIDER_TYPE: - owner = 10; + fiberTag = 10; break a; case REACT_CONTEXT_TYPE: - owner = 9; + fiberTag = 9; break a; case REACT_FORWARD_REF_TYPE: - owner = 11; + fiberTag = 11; break a; case REACT_MEMO_TYPE: - owner = 14; + fiberTag = 14; break a; case REACT_LAZY_TYPE: - owner = 16; - source = null; + fiberTag = 16; + owner = null; break a; } throw Error( @@ -9844,9 +9847,9 @@ function createFiberFromTypeAndProps( ((null == type ? type : typeof type) + ".") ); } - key = createFiber(owner, pendingProps, key, mode); + key = createFiber(fiberTag, pendingProps, key, mode); key.elementType = type; - key.type = source; + key.type = owner; key.lanes = lanes; return key; } @@ -10099,7 +10102,7 @@ var roots = new Map(), devToolsConfig$jscomp$inline_1154 = { findFiberByHostInstance: getInstanceFromTag, bundleType: 0, - version: "18.3.0-canary-b2d637128-20240123", + version: "18.3.0-canary-03d6f7cf0-20240209", rendererPackageName: "react-native-renderer", rendererConfig: { getInspectorDataForInstance: getInspectorDataForInstance, @@ -10115,7 +10118,7 @@ var roots = new Map(), }.bind(null, findNodeHandle) } }; -var internals$jscomp$inline_1406 = { +var internals$jscomp$inline_1389 = { bundleType: devToolsConfig$jscomp$inline_1154.bundleType, version: devToolsConfig$jscomp$inline_1154.version, rendererPackageName: devToolsConfig$jscomp$inline_1154.rendererPackageName, @@ -10142,19 +10145,19 @@ var internals$jscomp$inline_1406 = { scheduleRoot: null, setRefreshHandler: null, getCurrentFiber: null, - reconcilerVersion: "18.3.0-canary-b2d637128-20240123" + reconcilerVersion: "18.3.0-canary-03d6f7cf0-20240209" }; if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) { - var hook$jscomp$inline_1407 = __REACT_DEVTOOLS_GLOBAL_HOOK__; + var hook$jscomp$inline_1390 = __REACT_DEVTOOLS_GLOBAL_HOOK__; if ( - !hook$jscomp$inline_1407.isDisabled && - hook$jscomp$inline_1407.supportsFiber + !hook$jscomp$inline_1390.isDisabled && + hook$jscomp$inline_1390.supportsFiber ) try { - (rendererID = hook$jscomp$inline_1407.inject( - internals$jscomp$inline_1406 + (rendererID = hook$jscomp$inline_1390.inject( + internals$jscomp$inline_1389 )), - (injectedHook = hook$jscomp$inline_1407); + (injectedHook = hook$jscomp$inline_1390); } catch (err) {} } exports.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = {