From 5b6d4927a103660fb45d18d1a8da8fc57392682e Mon Sep 17 00:00:00 2001 From: acdlite Date: Thu, 25 Jan 2024 04:59:43 +0000 Subject: [PATCH] Batch async actions even if useTransition is unmounted (#28078) If there are multiple updates inside an async action, they should all be rendered in the same batch, even if they are separate by an async operation (`await`). We currently implement this by suspending in the `useTransition` hook to block the update from committing until all possible updates have been scheduled by the action. The reason we did it this way is so you can "cancel" an action by navigating away from the UI that triggered it. The problem with that approach, though, is that even if you navigate away from the `useTransition` hook, the action may have updated shared parts of the UI that are still in the tree. So we may need to continue suspending even after the `useTransition` hook is deleted. In other words, the lifetime of an async action scope is longer than the lifetime of a particular `useTransition` hook. The solution is to suspend whenever _any_ update that is part of the async action scope is unwrapped during render. So, inside useState and useReducer. This fixes a related issue where an optimistic update is reverted before the async action has finished, because we were relying on the `useTransition` hook to prevent the optimistic update from finishing. This also prepares us to support async actions being passed to the non-hook form of `startTransition` (though this isn't implemented yet). DiffTrain build for commit https://github.com/facebook/react/commit/11c9fd0c53133f24f5270d36591b65b8fc2ebd25. --- .../cjs/ReactTestRenderer-dev.js | 6216 ++++++++-------- .../cjs/ReactTestRenderer-prod.js | 1325 ++-- .../cjs/ReactTestRenderer-profiling.js | 1411 ++-- .../RKJSModules/vendor/react/cjs/React-dev.js | 2 +- .../vendor/react/cjs/React-prod.js | 2 +- .../vendor/react/cjs/React-profiling.js | 2 +- .../Libraries/Renderer/REVISION | 2 +- .../implementations/ReactFabric-dev.fb.js | 6308 +++++++++-------- .../implementations/ReactFabric-prod.fb.js | 942 +-- .../ReactFabric-profiling.fb.js | 1219 ++-- .../ReactNativeRenderer-dev.fb.js | 6258 ++++++++-------- .../ReactNativeRenderer-prod.fb.js | 947 +-- .../ReactNativeRenderer-profiling.fb.js | 1089 +-- 13 files changed, 12952 insertions(+), 12771 deletions(-) diff --git a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-dev.js b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-dev.js index 7d183fcd8f3db..c24024d654bc4 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-dev.js +++ b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-dev.js @@ -7,7 +7,7 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<> + * @generated SignedSource<<6f91cae5b10795257ddec042012ed6d4>> */ "use strict"; @@ -3086,3673 +3086,3665 @@ if (__DEV__) { } } - 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 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 hasForceUpdate = false; - var didWarnUpdateInsideUpdate; - var currentlyProcessingQueue; + var firstScheduledRoot = null; + var lastScheduledRoot = null; // Used to prevent redundant mircotasks from being scheduled. - { - didWarnUpdateInsideUpdate = false; - currentlyProcessingQueue = null; - } + 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. - 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; + var didScheduleMicrotask_act = false; // Used to quickly bail out of flushSync if there's no sync work to do. - if (queue === currentQueue) { - var clone = { - baseState: currentQueue.baseState, - firstBaseUpdate: currentQueue.firstBaseUpdate, - lastBaseUpdate: currentQueue.lastBaseUpdate, - shared: currentQueue.shared, - callbacks: null - }; - workInProgress.updateQueue = clone; + var mightHavePendingSyncWork = false; + var isFlushingWork = false; + var currentEventTransitionLane = NoLane; + function ensureRootIsScheduled(root) { + // This function is called whenever a root receives an update. It does two + // things 1) it ensures the root is in the root schedule, and 2) it ensures + // there's a pending microtask to process the root schedule. + // + // Most of the actual scheduling logic does not happen until + // `scheduleTaskForRootDuringMicrotask` runs. + // Add the root to the schedule + if (root === lastScheduledRoot || root.next !== null); + else { + if (lastScheduledRoot === null) { + firstScheduledRoot = lastScheduledRoot = root; + } else { + lastScheduledRoot.next = root; + lastScheduledRoot = root; + } + } // Any time a root received an update, we set this to true until the next time + // we process the schedule. If it's false, then we can quickly exit flushSync + // without consulting the schedule. + + mightHavePendingSyncWork = true; // At the end of the current event, go through each of the roots and ensure + // there's a task scheduled for each one at the correct priority. + + if (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); + } + } + + if (ReactCurrentActQueue$3.isBatchingLegacy && root.tag === LegacyRoot) { + // Special `act` case: Record whenever a legacy update is scheduled. + ReactCurrentActQueue$3.didScheduleLegacyUpdate = true; } } - function createUpdate(lane) { - var update = { - lane: lane, - tag: UpdateState, - payload: null, - callback: null, - next: null - }; - return update; + 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 enqueueUpdate(fiber, update, lane) { - var updateQueue = fiber.updateQueue; - if (updateQueue === null) { - // Only occurs if the fiber has been unmounted. - return null; + 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 ( - currentlyProcessingQueue === sharedQueue && - !didWarnUpdateInsideUpdate - ) { - var componentName = getComponentNameFromFiber(fiber); + var didPerformSomeWork; + var errors = null; + isFlushingWork = true; - error( - "An update (setState, replaceState, or forceUpdate) was scheduled " + - "from inside an update function. Update functions should be pure, " + - "with zero side-effects. Consider using componentDidUpdate or a " + - "callback.\n\nPlease update the following component: %s", - componentName - ); + do { + didPerformSomeWork = false; + var root = firstScheduledRoot; - didWarnUpdateInsideUpdate = true; - } - } + while (root !== null) { + if (onlyLegacy && root.tag !== LegacyRoot); + else { + var workInProgressRoot = getWorkInProgressRoot(); + var workInProgressRootRenderLanes = + getWorkInProgressRootRenderLanes(); + var nextLanes = getNextLanes( + root, + root === workInProgressRoot + ? workInProgressRootRenderLanes + : NoLanes + ); - if (isUnsafeClassRenderPhaseUpdate()) { - // This is an unsafe render phase update. Add directly to the update - // queue so we can process it immediately during the current render. - var pending = sharedQueue.pending; + if (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); + } + } + } + } - if (pending === null) { - // This is the first update. Create a circular list. - update.next = update; - } else { - update.next = pending.next; - pending.next = update; + root = root.next; } + } while (didPerformSomeWork); - 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). + 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. - return unsafe_markUpdateLaneFromFiberToRoot(fiber, lane); - } else { - return enqueueConcurrentClassUpdate(fiber, sharedQueue, update, lane); - } - } - function entangleTransitions(root, fiber, lane) { - var updateQueue = fiber.updateQueue; + 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])); + } - if (updateQueue === null) { - // Only occurs if the fiber has been unmounted. - return; + var firstError = errors[0]; + throw firstError; + } + } else { + var error = errors[0]; + throw error; + } } + } - var sharedQueue = updateQueue.shared; - - 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. + function throwError(error) { + throw error; + } - queueLanes = intersectLanes(queueLanes, root.pendingLanes); // Entangle the new transition lane with the other transition lanes. + function processRootScheduleInMicrotask() { + // This function is always called inside a microtask. It should never be + // called synchronously. + didScheduleMicrotask = false; - var newQueueLanes = mergeLanes(queueLanes, lane); - sharedQueue.lanes = newQueueLanes; // Even if queue.lanes already include lane, we don't know for certain if - // the lane finished since the last time we entangled it. So we need to - // entangle it again, just to be sure. + { + didScheduleMicrotask_act = false; + } // We'll recompute this as we iterate through all the roots and schedule them. - 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. + mightHavePendingSyncWork = false; + var currentTime = now$1(); + var prev = null; + var root = firstScheduledRoot; - var current = workInProgress.alternate; + while (root !== null) { + var next = root.next; - if (current !== null) { - var currentQueue = current.updateQueue; - - if (queue === currentQueue) { - // The work-in-progress queue is the same as current. This happens when - // we bail out on a parent fiber that then captures an error thrown by - // a child. Since we want to append the update only to the work-in - // -progress queue, we need to clone the updates. We usually clone during - // processUpdateQueue, but that didn't happen in this case because we - // skipped over the parent when we bailed out. - var newFirst = null; - var newLast = null; - var firstBaseUpdate = queue.firstBaseUpdate; - - if (firstBaseUpdate !== null) { - // Loop through the updates and clone them. - var update = firstBaseUpdate; - - do { - var clone = { - lane: update.lane, - tag: update.tag, - payload: update.payload, - // When this update is rebased, we should not fire its - // callback again. - callback: null, - next: null - }; + if ( + 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 (newLast === null) { - newFirst = newLast = clone; - } else { - newLast.next = clone; - newLast = clone; - } // $FlowFixMe[incompatible-type] we bail out when we get a null + var nextLanes = scheduleTaskForRootDuringMicrotask(root, currentTime); - update = update.next; - } while (update !== null); // Append the captured update the end of the cloned list. + if (nextLanes === NoLane) { + // This root has no more pending work. Remove it from the schedule. To + // guard against subtle reentrancy bugs, this microtask is the only place + // we do this — you can add roots to the schedule whenever, but you can + // only remove them here. + // Null this out so we know it's been removed from the schedule. + root.next = null; - if (newLast === null) { - newFirst = newLast = capturedUpdate; - } else { - newLast.next = capturedUpdate; - newLast = capturedUpdate; - } + if (prev === null) { + // This is the new head of the list + firstScheduledRoot = next; } else { - // There are no base updates. - newFirst = newLast = capturedUpdate; + prev.next = next; } - queue = { - baseState: currentQueue.baseState, - firstBaseUpdate: newFirst, - lastBaseUpdate: newLast, - shared: currentQueue.shared, - callbacks: currentQueue.callbacks - }; - workInProgress.updateQueue = queue; - return; - } - } // Append the update to the end of the list. + if (next === null) { + // This is the new tail of the list + lastScheduledRoot = prev; + } + } else { + // This root still has work. Keep it in the list. + prev = root; - var lastBaseUpdate = queue.lastBaseUpdate; + if (includesSyncLane(nextLanes)) { + mightHavePendingSyncWork = true; + } + } - if (lastBaseUpdate === null) { - queue.firstBaseUpdate = capturedUpdate; - } else { - lastBaseUpdate.next = capturedUpdate; + root = next; } - queue.lastBaseUpdate = capturedUpdate; - } + currentEventTransitionLane = NoLane; // At the end of the microtask, flush any pending synchronous work. This has + // to come at the end, because it does actual rendering work that might throw. - function getStateFromUpdate( - workInProgress, - queue, - update, - prevState, - nextProps, - instance - ) { - switch (update.tag) { - case ReplaceState: { - var payload = update.payload; + flushSyncWorkOnAllRoots(); + } - if (typeof payload === "function") { - // Updater function - { - enterDisallowedContextReadInDEV(); - } + 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 nextState = payload.call(instance, prevState, nextProps); + var workInProgressRoot = getWorkInProgressRoot(); + var workInProgressRootRenderLanes = getWorkInProgressRootRenderLanes(); + var nextLanes = getNextLanes( + root, + root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes + ); + var existingCallbackNode = root.callbackNode; - { - exitDisallowedContextReadInDEV(); - } + if ( + // Check if there's nothing to work on + nextLanes === NoLanes || // If this root is currently suspended and waiting for data to resolve, don't + // schedule a task to render it. We'll either wait for a ping, or wait to + // receive an update. + // + // Suspended render phase + (root === workInProgressRoot && isWorkLoopSuspendedOnData()) || // Suspended commit phase + root.cancelPendingCommit !== null + ) { + // Fast path: There's nothing to work on. + if (existingCallbackNode !== null) { + cancelCallback(existingCallbackNode); + } - return nextState; - } // State object + root.callbackNode = null; + root.callbackPriority = NoLane; + return NoLane; + } // Schedule a new callback in the host environment. - return payload; + 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); } - case CaptureUpdate: { - workInProgress.flags = - (workInProgress.flags & ~ShouldCapture) | DidCapture; + root.callbackPriority = SyncLane; + root.callbackNode = null; + return SyncLane; + } else { + // We use the highest priority lane to represent the priority of the callback. + var existingCallbackPriority = root.callbackPriority; + var newCallbackPriority = getHighestPriorityLane(nextLanes); + + if ( + newCallbackPriority === existingCallbackPriority && // Special case related to `act`. If the currently scheduled task is a + // Scheduler task, rather than an `act` task, cancel it and re-schedule + // on the `act` queue. + !( + 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); } - // Intentional fallthrough - case UpdateState: { - var _payload = update.payload; - var partialState; + var schedulerPriorityLevel; - if (typeof _payload === "function") { - // Updater function - { - enterDisallowedContextReadInDEV(); - } + switch (lanesToEventPriority(nextLanes)) { + case DiscreteEventPriority: + schedulerPriorityLevel = ImmediatePriority; + break; - partialState = _payload.call(instance, prevState, nextProps); + case ContinuousEventPriority: + schedulerPriorityLevel = UserBlockingPriority; + break; - { - exitDisallowedContextReadInDEV(); - } - } else { - // Partial state object - partialState = _payload; - } + case DefaultEventPriority: + schedulerPriorityLevel = NormalPriority$1; + break; - if (partialState === null || partialState === undefined) { - // Null and undefined are treated as no-ops. - return prevState; - } // Merge the partial state and the previous state. + case IdleEventPriority: + schedulerPriorityLevel = IdlePriority; + break; - return assign({}, prevState, partialState); + default: + schedulerPriorityLevel = NormalPriority$1; + break; } - case ForceUpdate: { - hasForceUpdate = true; - return prevState; - } + var newCallbackNode = scheduleCallback$2( + schedulerPriorityLevel, + performConcurrentWorkOnRoot.bind(null, root) + ); + root.callbackPriority = newCallbackPriority; + root.callbackNode = newCallbackNode; + return newCallbackPriority; } - - return prevState; } - function processUpdateQueue(workInProgress, props, instance, renderLanes) { - // This is always non-null on a ClassComponent or HostRoot - var queue = workInProgress.updateQueue; - hasForceUpdate = false; + 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()); - { - currentlyProcessingQueue = queue.shared; - } - - var firstBaseUpdate = queue.firstBaseUpdate; - var lastBaseUpdate = queue.lastBaseUpdate; // Check if there are pending updates. If so, transfer them to the base queue. - - var pendingQueue = queue.shared.pending; - - if (pendingQueue !== null) { - queue.shared.pending = null; // The pending queue is circular. Disconnect the pointer between first - // and last so that it's non-circular. - - var lastPendingUpdate = pendingQueue; - var firstPendingUpdate = lastPendingUpdate.next; - lastPendingUpdate.next = null; // Append pending updates to base queue - - if (lastBaseUpdate === null) { - firstBaseUpdate = firstPendingUpdate; - } else { - lastBaseUpdate.next = firstPendingUpdate; - } - - lastBaseUpdate = lastPendingUpdate; // If there's a current queue, and it's different from the base queue, then - // we need to transfer the updates to that queue, too. Because the base - // queue is a singly-linked list with no cycles, we can append to both - // lists and take advantage of structural sharing. - // TODO: Pass `current` as argument + 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 current = workInProgress.alternate; + return null; + } + var fakeActCallbackNode$1 = {}; - if (current !== null) { - // This is always non-null on a ClassComponent or HostRoot - var currentQueue = current.updateQueue; - var currentLastBaseUpdate = currentQueue.lastBaseUpdate; + function scheduleCallback$2(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$3(priorityLevel, callback); + } + } - if (currentLastBaseUpdate !== lastBaseUpdate) { - if (currentLastBaseUpdate === null) { - currentQueue.firstBaseUpdate = firstPendingUpdate; - } else { - currentLastBaseUpdate.next = firstPendingUpdate; - } + function cancelCallback(callbackNode) { + if (callbackNode === fakeActCallbackNode$1); + else if (callbackNode !== null) { + cancelCallback$1(callbackNode); + } + } - currentQueue.lastBaseUpdate = lastPendingUpdate; - } - } - } // These values may change as we process the queue. + 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 (firstBaseUpdate !== null) { - // Iterate through the list of updates to compute the result. - var newState = queue.baseState; // TODO: Don't need to accumulate this. Instead, we can remove renderLanes - // from the original lanes. + { + // If microtasks are not supported, use Scheduler. + scheduleCallback$3(ImmediatePriority, cb); + } + } - var newLanes = NoLanes; - var newBaseState = null; - var newFirstBaseUpdate = null; - var newLastBaseUpdate = null; - var update = firstBaseUpdate; + 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(); + } - do { - // An extra OffscreenLane bit is added to updates that were made to - // a hidden tree, so that we can distinguish them from updates that were - // already there when the tree was hidden. - var updateLane = removeLanes(update.lane, OffscreenLane); - var isHiddenUpdate = updateLane !== update.lane; // Check if this update was made while the tree was hidden. If so, then - // it's not a "base" update and we should disregard the extra base lanes - // that were added to renderLanes when we entered the Offscreen tree. + return currentEventTransitionLane; + } - var shouldSkipUpdate = isHiddenUpdate - ? !isSubsetOfLanes(getWorkInProgressRootRenderLanes(), updateLane) - : !isSubsetOfLanes(renderLanes, updateLane); + // 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. - if (shouldSkipUpdate) { - // Priority is insufficient. Skip this update. If this is the first - // skipped update, the previous update/state is the new base - // update/state. - var clone = { - lane: updateLane, - tag: update.tag, - payload: update.payload, - callback: update.callback, - next: null - }; + var currentEntangledListeners = null; // The number of pending async actions in the entangled scope. - if (newLastBaseUpdate === null) { - newFirstBaseUpdate = newLastBaseUpdate = clone; - newBaseState = newState; - } else { - newLastBaseUpdate = newLastBaseUpdate.next = clone; - } // Update the remaining priority in the queue. + var currentEntangledPendingCount = 0; // The transition lane shared by all updates in the entangled scope. - 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. + 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. - newState = getStateFromUpdate( - workInProgress, - queue, - update, - newState, - props, - instance - ); - var callback = update.callback; + var currentEntangledActionThenable = null; + function entangleAsyncAction(thenable) { + // `thenable` is the return value of the async action scope function. Create + // a combined thenable that resolves once every entangled scope function + // has finished. + if (currentEntangledListeners === null) { + // There's no outer async action scope. Create a new one. + var entangledListeners = (currentEntangledListeners = []); + currentEntangledPendingCount = 0; + currentEntangledLane = requestTransitionLane(); + var entangledThenable = { + status: "pending", + value: undefined, + then: function (resolve) { + entangledListeners.push(resolve); + } + }; + currentEntangledActionThenable = entangledThenable; + } - if (callback !== null) { - workInProgress.flags |= Callback; + currentEntangledPendingCount++; + thenable.then(pingEngtangledActionScope, pingEngtangledActionScope); + return thenable; + } - if (isHiddenUpdate) { - workInProgress.flags |= Visibility; - } + function pingEngtangledActionScope() { + if ( + currentEntangledListeners !== null && + --currentEntangledPendingCount === 0 + ) { + // All the actions have finished. Close the entangled async action scope + // and notify all the listeners. + if (currentEntangledActionThenable !== null) { + var fulfilledThenable = currentEntangledActionThenable; + fulfilledThenable.status = "fulfilled"; + } - var callbacks = queue.callbacks; + var listeners = currentEntangledListeners; + currentEntangledListeners = null; + currentEntangledLane = NoLane; + currentEntangledActionThenable = null; - if (callbacks === null) { - queue.callbacks = [callback]; - } else { - callbacks.push(callback); - } - } - } // $FlowFixMe[incompatible-type] we bail out when we get a null + for (var i = 0; i < listeners.length; i++) { + var listener = listeners[i]; + listener(); + } + } + } - update = update.next; + 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 (update === null) { - pendingQueue = queue.shared.pending; + 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; - 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. + 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. - var _firstPendingUpdate = _lastPendingUpdate.next; - _lastPendingUpdate.next = null; - update = _firstPendingUpdate; - queue.lastBaseUpdate = _lastPendingUpdate; - queue.shared.pending = null; - } + listener(undefined); } - } while (true); - - if (newLastBaseUpdate === null) { - newBaseState = newState; } + ); + return thenableWithOverride; + } + function peekEntangledActionLane() { + return currentEntangledLane; + } + function peekEntangledActionThenable() { + return currentEntangledActionThenable; + } - queue.baseState = newBaseState; - queue.firstBaseUpdate = newFirstBaseUpdate; - queue.lastBaseUpdate = newLastBaseUpdate; + var UpdateState = 0; + var ReplaceState = 1; + var ForceUpdate = 2; + var CaptureUpdate = 3; // Global state that is reset at the beginning of calling `processUpdateQueue`. + // It should only be read right after calling `processUpdateQueue`, via + // `checkHasForceUpdateAfterProcessing`. - if (firstBaseUpdate === null) { - // `queue.lanes` is used for entangling transitions. We can set it back to - // zero once the queue is empty. - queue.shared.lanes = NoLanes; - } // Set the remaining expiration time to be whatever is remaining in the queue. - // This should be fine because the only two other things that contribute to - // expiration time are props and context. We're already in the middle of the - // begin phase by the time we start processing the queue, so we've already - // dealt with the props. Context in components that specify - // shouldComponentUpdate is tricky; but we'll have to account for - // that regardless. + var hasForceUpdate = false; + var didWarnUpdateInsideUpdate; + var currentlyProcessingQueue; - markSkippedUpdateLanes(newLanes); - workInProgress.lanes = newLanes; - workInProgress.memoizedState = newState; - } + { + didWarnUpdateInsideUpdate = false; + currentlyProcessingQueue = null; + } - { - 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; - function callCallback(callback, context) { - if (typeof callback !== "function") { - throw new Error( - "Invalid argument passed as callback. Expected a function. Instead " + - ("received: " + callback) - ); + if (updateQueue === null) { + // Only occurs if the fiber has been unmounted. + return null; } - callback.call(context); - } + var sharedQueue = updateQueue.shared; - function resetHasForceUpdateBeforeProcessing() { - hasForceUpdate = false; - } - function checkHasForceUpdateAfterProcessing() { - return hasForceUpdate; - } - function deferHiddenCallbacks(updateQueue) { - // When an update finishes on a hidden component, its callback should not - // be fired until/unless the component is made visible again. Stash the - // callback on the shared queue object so it can be fired later. - var newHiddenCallbacks = updateQueue.callbacks; + { + if ( + currentlyProcessingQueue === sharedQueue && + !didWarnUpdateInsideUpdate + ) { + var componentName = getComponentNameFromFiber(fiber); - if (newHiddenCallbacks !== null) { - var existingHiddenCallbacks = updateQueue.shared.hiddenCallbacks; + error( + "An update (setState, replaceState, or forceUpdate) was scheduled " + + "from inside an update function. Update functions should be pure, " + + "with zero side-effects. Consider using componentDidUpdate or a " + + "callback.\n\nPlease update the following component: %s", + componentName + ); - if (existingHiddenCallbacks === null) { - updateQueue.shared.hiddenCallbacks = newHiddenCallbacks; - } else { - updateQueue.shared.hiddenCallbacks = - existingHiddenCallbacks.concat(newHiddenCallbacks); + didWarnUpdateInsideUpdate = true; } } - } - 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; + 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; - for (var i = 0; i < hiddenCallbacks.length; i++) { - var callback = hiddenCallbacks[i]; - callCallback(callback, context); + if (pending === null) { + // This is the first update. Create a circular list. + update.next = update; + } else { + update.next = pending.next; + pending.next = update; } - } - } - function commitCallbacks(updateQueue, context) { - var callbacks = updateQueue.callbacks; - if (callbacks !== null) { - updateQueue.callbacks = null; + sharedQueue.pending = update; // Update the childLanes even though we're most likely already rendering + // this fiber. This is for backwards compatibility in the case where you + // update a different component during render phase than the one that is + // currently renderings (a pattern that is accompanied by a warning). - for (var i = 0; i < callbacks.length; i++) { - var callback = callbacks[i]; - callCallback(callback, context); - } + return unsafe_markUpdateLaneFromFiberToRoot(fiber, lane); + } else { + return enqueueConcurrentClassUpdate(fiber, sharedQueue, update, lane); } } + function entangleTransitions(root, fiber, lane) { + var updateQueue = fiber.updateQueue; - /** - * 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; + if (updateQueue === null) { + // Only occurs if the fiber has been unmounted. + return; } - if ( - typeof objA !== "object" || - objA === null || - typeof objB !== "object" || - objB === null - ) { - return false; - } + var sharedQueue = updateQueue.shared; - var keysA = Object.keys(objA); - var keysB = Object.keys(objB); + if (isTransitionLane(lane)) { + var queueLanes = sharedQueue.lanes; // If any entangled lanes are no longer pending on the root, then they must + // have finished. We can remove them from the shared queue, which represents + // a superset of the actually pending lanes. In some cases we may entangle + // more than we need to, but that's OK. In fact it's worse if we *don't* + // entangle when we should. - if (keysA.length !== keysB.length) { - return false; - } // Test for A's keys different from B. + queueLanes = intersectLanes(queueLanes, root.pendingLanes); // Entangle the new transition lane with the other transition lanes. - for (var i = 0; i < keysA.length; i++) { - var currentKey = keysA[i]; + var newQueueLanes = mergeLanes(queueLanes, lane); + sharedQueue.lanes = newQueueLanes; // Even if queue.lanes already include lane, we don't know for certain if + // the lane finished since the last time we entangled it. So we need to + // entangle it again, just to be sure. - if ( - !hasOwnProperty.call(objB, currentKey) || // $FlowFixMe[incompatible-use] lost refinement of `objB` - !objectIs(objA[currentKey], objB[currentKey]) - ) { - return false; - } + markRootEntangled(root, newQueueLanes); } - - return true; } + 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 describeFiber(fiber) { - var owner = fiber._debugOwner ? fiber._debugOwner.type : null; - var source = fiber._debugSource; + var current = workInProgress.alternate; - switch (fiber.tag) { - case HostHoistable: - case HostSingleton: - case HostComponent: - return describeBuiltInComponentFrame(fiber.type, source, owner); + if (current !== null) { + var currentQueue = current.updateQueue; - case LazyComponent: - return describeBuiltInComponentFrame("Lazy", source, owner); + if (queue === currentQueue) { + // The work-in-progress queue is the same as current. This happens when + // we bail out on a parent fiber that then captures an error thrown by + // a child. Since we want to append the update only to the work-in + // -progress queue, we need to clone the updates. We usually clone during + // processUpdateQueue, but that didn't happen in this case because we + // skipped over the parent when we bailed out. + var newFirst = null; + var newLast = null; + var firstBaseUpdate = queue.firstBaseUpdate; - case SuspenseComponent: - return describeBuiltInComponentFrame("Suspense", source, owner); + if (firstBaseUpdate !== null) { + // Loop through the updates and clone them. + var update = firstBaseUpdate; - case SuspenseListComponent: - return describeBuiltInComponentFrame("SuspenseList", source, owner); + 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 + }; - case FunctionComponent: - case IndeterminateComponent: - case SimpleMemoComponent: - return describeFunctionComponentFrame(fiber.type, source, owner); + if (newLast === null) { + newFirst = newLast = clone; + } else { + newLast.next = clone; + newLast = clone; + } // $FlowFixMe[incompatible-type] we bail out when we get a null - case ForwardRef: - return describeFunctionComponentFrame( - fiber.type.render, - source, - owner - ); + update = update.next; + } while (update !== null); // Append the captured update the end of the cloned list. - case ClassComponent: - return describeClassComponentFrame(fiber.type, source, owner); + if (newLast === null) { + newFirst = newLast = capturedUpdate; + } else { + newLast.next = capturedUpdate; + newLast = capturedUpdate; + } + } else { + // There are no base updates. + newFirst = newLast = capturedUpdate; + } - default: - 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. + + var lastBaseUpdate = queue.lastBaseUpdate; + + if (lastBaseUpdate === null) { + queue.firstBaseUpdate = capturedUpdate; + } else { + lastBaseUpdate.next = capturedUpdate; } + + queue.lastBaseUpdate = capturedUpdate; } - function getStackByFiberInDevAndProd(workInProgress) { - try { - var info = ""; - var node = workInProgress; + function getStateFromUpdate( + workInProgress, + queue, + update, + prevState, + nextProps, + instance + ) { + switch (update.tag) { + case ReplaceState: { + var payload = update.payload; - do { - info += describeFiber(node); // $FlowFixMe[incompatible-type] we bail out when we get a null + if (typeof payload === "function") { + // Updater function + { + enterDisallowedContextReadInDEV(); + } - node = node.return; - } while (node); + var nextState = payload.call(instance, prevState, nextProps); - return info; - } catch (x) { - return "\nError generating stack: " + x.message + "\n" + x.stack; - } - } + { + exitDisallowedContextReadInDEV(); + } - var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; - var current = null; - var isRendering = false; - function getCurrentFiberOwnerNameInDevOrNull() { - { - if (current === null) { - return null; + return nextState; + } // State object + + return payload; } - var owner = current._debugOwner; + case CaptureUpdate: { + workInProgress.flags = + (workInProgress.flags & ~ShouldCapture) | DidCapture; + } + // Intentional fallthrough - if (owner !== null && typeof owner !== "undefined") { - return getComponentNameFromFiber(owner); + case UpdateState: { + var _payload = update.payload; + var partialState; + + if (typeof _payload === "function") { + // Updater function + { + enterDisallowedContextReadInDEV(); + } + + partialState = _payload.call(instance, prevState, nextProps); + + { + exitDisallowedContextReadInDEV(); + } + } else { + // Partial state object + partialState = _payload; + } + + if (partialState === null || partialState === undefined) { + // Null and undefined are treated as no-ops. + return prevState; + } // Merge the partial state and the previous state. + + return assign({}, prevState, partialState); + } + + case ForceUpdate: { + hasForceUpdate = true; + return prevState; } } - return null; + return prevState; } - 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 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. - return getStackByFiberInDevAndProd(current); - } - } + 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(); - 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; + 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 setIsRendering(rendering) { + function processUpdateQueue(workInProgress, props, instance, renderLanes) { + didReadFromEntangledAsyncAction = false; // This is always non-null on a ClassComponent or HostRoot + + var queue = workInProgress.updateQueue; + hasForceUpdate = false; + { - isRendering = rendering; + currentlyProcessingQueue = queue.shared; } - } - var ReactStrictModeWarnings = { - recordUnsafeLifecycleWarnings: function (fiber, instance) {}, - flushPendingUnsafeLifecycleWarnings: function () {}, - recordLegacyContextWarning: function (fiber, instance) {}, - flushLegacyContextWarning: function () {}, - discardPendingWarnings: function () {} - }; + var firstBaseUpdate = queue.firstBaseUpdate; + var lastBaseUpdate = queue.lastBaseUpdate; // Check if there are pending updates. If so, transfer them to the base queue. - { - var findStrictRoot = function (fiber) { - var maybeStrictRoot = null; - var node = fiber; + var pendingQueue = queue.shared.pending; - while (node !== null) { - if (node.mode & StrictLegacyMode) { - maybeStrictRoot = node; - } + 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. - node = node.return; + var lastPendingUpdate = pendingQueue; + var firstPendingUpdate = lastPendingUpdate.next; + lastPendingUpdate.next = null; // Append pending updates to base queue + + if (lastBaseUpdate === null) { + firstBaseUpdate = firstPendingUpdate; + } else { + lastBaseUpdate.next = firstPendingUpdate; } - return maybeStrictRoot; - }; + lastBaseUpdate = lastPendingUpdate; // If there's a current queue, and it's different from the base queue, then + // we need to transfer the updates to that queue, too. Because the base + // queue is a singly-linked list with no cycles, we can append to both + // lists and take advantage of structural sharing. + // TODO: Pass `current` as argument - var setToSortedString = function (set) { - var array = []; - set.forEach(function (value) { - array.push(value); - }); - return array.sort().join(", "); - }; + var current = workInProgress.alternate; - var pendingComponentWillMountWarnings = []; - var pendingUNSAFE_ComponentWillMountWarnings = []; - var pendingComponentWillReceivePropsWarnings = []; - var pendingUNSAFE_ComponentWillReceivePropsWarnings = []; - var pendingComponentWillUpdateWarnings = []; - var pendingUNSAFE_ComponentWillUpdateWarnings = []; // Tracks components we have already warned about. + if (current !== null) { + // This is always non-null on a ClassComponent or HostRoot + var currentQueue = current.updateQueue; + var currentLastBaseUpdate = currentQueue.lastBaseUpdate; - var didWarnAboutUnsafeLifecycles = new Set(); + if (currentLastBaseUpdate !== lastBaseUpdate) { + if (currentLastBaseUpdate === null) { + currentQueue.firstBaseUpdate = firstPendingUpdate; + } else { + currentLastBaseUpdate.next = firstPendingUpdate; + } - ReactStrictModeWarnings.recordUnsafeLifecycleWarnings = function ( - fiber, - instance - ) { - // Dedupe strategy: Warn once per component. - if (didWarnAboutUnsafeLifecycles.has(fiber.type)) { - return; + currentQueue.lastBaseUpdate = lastPendingUpdate; + } } + } // These values may change as we process the queue. - if ( - typeof instance.componentWillMount === "function" && // Don't warn about react-lifecycles-compat polyfilled components. - instance.componentWillMount.__suppressDeprecationWarning !== true - ) { - pendingComponentWillMountWarnings.push(fiber); - } + if (firstBaseUpdate !== null) { + // Iterate through the list of updates to compute the result. + var newState = queue.baseState; // TODO: Don't need to accumulate this. Instead, we can remove renderLanes + // from the original lanes. - if ( - fiber.mode & StrictLegacyMode && - typeof instance.UNSAFE_componentWillMount === "function" - ) { - pendingUNSAFE_ComponentWillMountWarnings.push(fiber); - } + var newLanes = NoLanes; + var newBaseState = null; + var newFirstBaseUpdate = null; + var newLastBaseUpdate = null; + var update = firstBaseUpdate; - if ( - typeof instance.componentWillReceiveProps === "function" && - instance.componentWillReceiveProps.__suppressDeprecationWarning !== - true - ) { - pendingComponentWillReceivePropsWarnings.push(fiber); - } - - if ( - fiber.mode & StrictLegacyMode && - typeof instance.UNSAFE_componentWillReceiveProps === "function" - ) { - pendingUNSAFE_ComponentWillReceivePropsWarnings.push(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 ( - typeof instance.componentWillUpdate === "function" && - instance.componentWillUpdate.__suppressDeprecationWarning !== true - ) { - pendingComponentWillUpdateWarnings.push(fiber); - } + var shouldSkipUpdate = isHiddenUpdate + ? !isSubsetOfLanes(getWorkInProgressRootRenderLanes(), updateLane) + : !isSubsetOfLanes(renderLanes, updateLane); - if ( - fiber.mode & StrictLegacyMode && - typeof instance.UNSAFE_componentWillUpdate === "function" - ) { - pendingUNSAFE_ComponentWillUpdateWarnings.push(fiber); - } - }; + 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 + }; - ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = - function () { - // We do an initial pass to gather component names - var componentWillMountUniqueNames = new Set(); + if (newLastBaseUpdate === null) { + newFirstBaseUpdate = newLastBaseUpdate = clone; + newBaseState = newState; + } else { + newLastBaseUpdate = newLastBaseUpdate.next = clone; + } // Update the remaining priority in the queue. - if (pendingComponentWillMountWarnings.length > 0) { - pendingComponentWillMountWarnings.forEach(function (fiber) { - componentWillMountUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingComponentWillMountWarnings = []; - } + 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; + } - var UNSAFE_componentWillMountUniqueNames = new Set(); + if (newLastBaseUpdate !== null) { + var _clone = { + // This update is going to be committed so we never want uncommit + // it. Using NoLane works because 0 is a subset of all bitmasks, so + // this will never be skipped by the check above. + lane: NoLane, + tag: update.tag, + payload: update.payload, + // When this update is rebased, we should not fire its + // callback again. + callback: null, + next: null + }; + newLastBaseUpdate = newLastBaseUpdate.next = _clone; + } // Process this update. - if (pendingUNSAFE_ComponentWillMountWarnings.length > 0) { - pendingUNSAFE_ComponentWillMountWarnings.forEach(function (fiber) { - UNSAFE_componentWillMountUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingUNSAFE_ComponentWillMountWarnings = []; - } + newState = getStateFromUpdate( + workInProgress, + queue, + update, + newState, + props, + instance + ); + var callback = update.callback; - var componentWillReceivePropsUniqueNames = new Set(); + if (callback !== null) { + workInProgress.flags |= Callback; - if (pendingComponentWillReceivePropsWarnings.length > 0) { - pendingComponentWillReceivePropsWarnings.forEach(function (fiber) { - componentWillReceivePropsUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingComponentWillReceivePropsWarnings = []; - } + if (isHiddenUpdate) { + workInProgress.flags |= Visibility; + } - var UNSAFE_componentWillReceivePropsUniqueNames = new Set(); + var callbacks = queue.callbacks; - if (pendingUNSAFE_ComponentWillReceivePropsWarnings.length > 0) { - pendingUNSAFE_ComponentWillReceivePropsWarnings.forEach( - function (fiber) { - UNSAFE_componentWillReceivePropsUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); + if (callbacks === null) { + queue.callbacks = [callback]; + } else { + callbacks.push(callback); } - ); - pendingUNSAFE_ComponentWillReceivePropsWarnings = []; - } + } + } // $FlowFixMe[incompatible-type] we bail out when we get a null - var componentWillUpdateUniqueNames = new Set(); + update = update.next; - if (pendingComponentWillUpdateWarnings.length > 0) { - pendingComponentWillUpdateWarnings.forEach(function (fiber) { - componentWillUpdateUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingComponentWillUpdateWarnings = []; - } + if (update === null) { + pendingQueue = queue.shared.pending; - var UNSAFE_componentWillUpdateUniqueNames = new Set(); + if (pendingQueue === null) { + break; + } else { + // An update was scheduled from inside a reducer. Add the new + // pending updates to the end of the list and keep processing. + var _lastPendingUpdate = pendingQueue; // Intentionally unsound. Pending updates form a circular list, but we + // unravel them when transferring them to the base queue. - if (pendingUNSAFE_ComponentWillUpdateWarnings.length > 0) { - pendingUNSAFE_ComponentWillUpdateWarnings.forEach(function (fiber) { - UNSAFE_componentWillUpdateUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingUNSAFE_ComponentWillUpdateWarnings = []; - } // Finally, we flush all the warnings - // UNSAFE_ ones before the deprecated ones, since they'll be 'louder' + var _firstPendingUpdate = _lastPendingUpdate.next; + _lastPendingUpdate.next = null; + update = _firstPendingUpdate; + queue.lastBaseUpdate = _lastPendingUpdate; + queue.shared.pending = null; + } + } + } while (true); - if (UNSAFE_componentWillMountUniqueNames.size > 0) { - var sortedNames = setToSortedString( - UNSAFE_componentWillMountUniqueNames - ); + if (newLastBaseUpdate === null) { + newBaseState = newState; + } - 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 - ); - } + queue.baseState = newBaseState; + queue.firstBaseUpdate = newFirstBaseUpdate; + queue.lastBaseUpdate = newLastBaseUpdate; - if (UNSAFE_componentWillReceivePropsUniqueNames.size > 0) { - var _sortedNames = setToSortedString( - UNSAFE_componentWillReceivePropsUniqueNames - ); + 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. - 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 - ); - } + markSkippedUpdateLanes(newLanes); + workInProgress.lanes = newLanes; + workInProgress.memoizedState = newState; + } - if (UNSAFE_componentWillUpdateUniqueNames.size > 0) { - var _sortedNames2 = setToSortedString( - UNSAFE_componentWillUpdateUniqueNames - ); + { + currentlyProcessingQueue = null; + } + } - 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 callCallback(callback, context) { + if (typeof callback !== "function") { + throw new Error( + "Invalid argument passed as callback. Expected a function. Instead " + + ("received: " + callback) + ); + } - if (componentWillMountUniqueNames.size > 0) { - var _sortedNames3 = setToSortedString( - componentWillMountUniqueNames - ); + callback.call(context); + } - 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 - ); - } + function resetHasForceUpdateBeforeProcessing() { + hasForceUpdate = false; + } + function checkHasForceUpdateAfterProcessing() { + return hasForceUpdate; + } + function deferHiddenCallbacks(updateQueue) { + // When an update finishes on a hidden component, its callback should not + // be fired until/unless the component is made visible again. Stash the + // callback on the shared queue object so it can be fired later. + var newHiddenCallbacks = updateQueue.callbacks; - if (componentWillReceivePropsUniqueNames.size > 0) { - var _sortedNames4 = setToSortedString( - componentWillReceivePropsUniqueNames - ); + if (newHiddenCallbacks !== null) { + var existingHiddenCallbacks = updateQueue.shared.hiddenCallbacks; - warn( - "componentWillReceiveProps has been renamed, and is not recommended for use. " + - "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + - "* Move data fetching code or side effects to componentDidUpdate.\n" + - "* If you're updating state whenever props change, refactor your " + - "code to use memoization techniques or move it to " + - "static getDerivedStateFromProps. Learn more at: https://reactjs.org/link/derived-state\n" + - "* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress " + - "this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. " + - "To rename all deprecated lifecycles to their new names, you can run " + - "`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n" + - "\nPlease update the following components: %s", - _sortedNames4 - ); - } + if (existingHiddenCallbacks === null) { + updateQueue.shared.hiddenCallbacks = newHiddenCallbacks; + } else { + updateQueue.shared.hiddenCallbacks = + existingHiddenCallbacks.concat(newHiddenCallbacks); + } + } + } + function commitHiddenCallbacks(updateQueue, context) { + // This component is switching from hidden -> visible. Commit any callbacks + // that were previously deferred. + var hiddenCallbacks = updateQueue.shared.hiddenCallbacks; - if (componentWillUpdateUniqueNames.size > 0) { - var _sortedNames5 = setToSortedString( - componentWillUpdateUniqueNames - ); + if (hiddenCallbacks !== null) { + updateQueue.shared.hiddenCallbacks = null; - 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 - ); - } - }; + for (var i = 0; i < hiddenCallbacks.length; i++) { + var callback = hiddenCallbacks[i]; + callCallback(callback, context); + } + } + } + function commitCallbacks(updateQueue, context) { + var callbacks = updateQueue.callbacks; - var pendingLegacyContextWarning = new Map(); // Tracks components we have already warned about. + if (callbacks !== null) { + updateQueue.callbacks = null; - var didWarnAboutLegacyContext = new Set(); + for (var i = 0; i < callbacks.length; i++) { + var callback = callbacks[i]; + callCallback(callback, context); + } + } + } - ReactStrictModeWarnings.recordLegacyContextWarning = function ( - fiber, - instance - ) { - var strictRoot = findStrictRoot(fiber); + /** + * Performs equality by iterating through keys on an object and returning false + * when any key has values which are not strictly equal between the arguments. + * Returns true when the values of all keys are strictly equal. + */ - if (strictRoot === null) { - error( - "Expected to find a StrictMode component in a strict mode tree. " + - "This error is likely caused by a bug in React. Please file an issue." - ); + function shallowEqual(objA, objB) { + if (objectIs(objA, objB)) { + return true; + } - return; - } // Dedup strategy: Warn once per component. + if ( + typeof objA !== "object" || + objA === null || + typeof objB !== "object" || + objB === null + ) { + return false; + } - if (didWarnAboutLegacyContext.has(fiber.type)) { - return; - } + var keysA = Object.keys(objA); + var keysB = Object.keys(objB); - var warningsForRoot = pendingLegacyContextWarning.get(strictRoot); + 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 ( - fiber.type.contextTypes != null || - fiber.type.childContextTypes != null || - (instance !== null && typeof instance.getChildContext === "function") + !hasOwnProperty.call(objB, currentKey) || // $FlowFixMe[incompatible-use] lost refinement of `objB` + !objectIs(objA[currentKey], objB[currentKey]) ) { - if (warningsForRoot === undefined) { - warningsForRoot = []; - pendingLegacyContextWarning.set(strictRoot, warningsForRoot); - } - - warningsForRoot.push(fiber); + return false; } - }; + } - ReactStrictModeWarnings.flushLegacyContextWarning = function () { - pendingLegacyContextWarning.forEach(function (fiberArray, strictRoot) { - if (fiberArray.length === 0) { - return; - } + return true; + } - 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 describeFiber(fiber) { + var owner = fiber._debugOwner ? fiber._debugOwner.type : null; + var source = fiber._debugSource; - try { - setCurrentFiber(firstFiber); + switch (fiber.tag) { + case HostHoistable: + case HostSingleton: + case HostComponent: + return describeBuiltInComponentFrame(fiber.type, source, owner); - 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(); - } - }); - }; + case LazyComponent: + return describeBuiltInComponentFrame("Lazy", source, owner); - ReactStrictModeWarnings.discardPendingWarnings = function () { - pendingComponentWillMountWarnings = []; - pendingUNSAFE_ComponentWillMountWarnings = []; - pendingComponentWillReceivePropsWarnings = []; - pendingUNSAFE_ComponentWillReceivePropsWarnings = []; - pendingComponentWillUpdateWarnings = []; - pendingUNSAFE_ComponentWillUpdateWarnings = []; - pendingLegacyContextWarning = new Map(); - }; - } + case SuspenseComponent: + return describeBuiltInComponentFrame("Suspense", source, owner); - /* - * 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] + case SuspenseListComponent: + return describeBuiltInComponentFrame("SuspenseList", source, owner); - return type; - } - } // $FlowFixMe[incompatible-return] only called in DEV, so void return is not possible. + case FunctionComponent: + case IndeterminateComponent: + case SimpleMemoComponent: + return describeFunctionComponentFrame(fiber.type, source, owner); - function willCoercionThrow(value) { - { - try { - testStringCoercion(value); - return false; - } catch (e) { - return true; - } + case ForwardRef: + return describeFunctionComponentFrame( + fiber.type.render, + source, + owner + ); + + case ClassComponent: + return describeClassComponentFrame(fiber.type, source, owner); + + default: + return ""; } } - 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 getStackByFiberInDevAndProd(workInProgress) { + try { + var info = ""; + var node = workInProgress; + + 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; + } } - function checkPropStringCoercion(value, propName) { + + var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; + var current = null; + var isRendering = false; + function getCurrentFiberOwnerNameInDevOrNull() { { - if (willCoercionThrow(value)) { - error( - "The provided `%s` prop is an unsupported type %s." + - " This value must be coerced to a string before using it here.", - propName, - typeName(value) - ); + if (current === null) { + return null; + } - return testStringCoercion(value); // throw (to help callers find troubleshooting comments) + var owner = current._debugOwner; + + if (owner !== null && typeof owner !== "undefined") { + return getComponentNameFromFiber(owner); } } + + return null; } - 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. + 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 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. + return getStackByFiberInDevAndProd(current); + } + } - var noopSuspenseyCommitThenable = { - then: function () { - { - error( - "Internal React error: A listener was unexpectedly attached to a " + - '"noop" thenable. This is a bug in React. Please file an issue.' - ); - } + function resetCurrentFiber() { + { + ReactDebugCurrentFrame.getCurrentStack = null; + current = null; + isRendering = false; } - }; - 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 setCurrentFiber(fiber) { + { + ReactDebugCurrentFrame.getCurrentStack = + fiber === null ? null : getCurrentFiberStackInDev; + current = fiber; + isRendering = false; + } } - - function noop() {} - - function trackUsedThenable(thenableState, thenable, index) { - if (ReactCurrentActQueue$3.current !== null) { - ReactCurrentActQueue$3.didUsePromise = true; + function getCurrentFiber() { + { + return current; + } + } + function setIsRendering(rendering) { + { + isRendering = rendering; } + } - var previous = thenableState[index]; + var ReactStrictModeWarnings = { + recordUnsafeLifecycleWarnings: function (fiber, instance) {}, + flushPendingUnsafeLifecycleWarnings: function () {}, + recordLegacyContextWarning: function (fiber, instance) {}, + flushLegacyContextWarning: function () {}, + discardPendingWarnings: function () {} + }; - 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. + { + var findStrictRoot = function (fiber) { + var maybeStrictRoot = null; + var node = fiber; - switch (thenable.status) { - case "fulfilled": { - var fulfilledValue = thenable.value; - return fulfilledValue; - } + while (node !== null) { + if (node.mode & StrictLegacyMode) { + maybeStrictRoot = node; + } - case "rejected": { - var rejectedError = thenable.reason; - checkIfUseWrappedInAsyncCatch(rejectedError); - throw rejectedError; + node = node.return; } - 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 maybeStrictRoot; + }; - if (root !== null && root.shellSuspendCounter > 100) { - // This root has suspended repeatedly in the shell without making any - // progress (i.e. committing something). This is highly suggestive of - // an infinite ping loop, often caused by an accidental Async Client - // Component. - // - // During a transition, we can suspend the work loop until the promise - // to resolve, but this is a sync render, so that's not an option. We - // also can't show a fallback, because none was provided. So our last - // resort is to throw an error. - // - // TODO: Remove this error in a future release. Other ways of handling - // this case include forcing a concurrent render, or putting the whole - // root into offscreen mode. - throw new Error( - "async/await is not yet supported in Client Components, only " + - "Server Components. This error is often caused by accidentally " + - "adding `'use client'` to a module that was originally written " + - "for the server." - ); - } + var setToSortedString = function (set) { + var array = []; + set.forEach(function (value) { + array.push(value); + }); + return array.sort().join(", "); + }; - var pendingThenable = thenable; - pendingThenable.status = "pending"; - pendingThenable.then( - function (fulfilledValue) { - if (thenable.status === "pending") { - var fulfilledThenable = thenable; - fulfilledThenable.status = "fulfilled"; - fulfilledThenable.value = fulfilledValue; - } - }, - function (error) { - if (thenable.status === "pending") { - var rejectedThenable = thenable; - rejectedThenable.status = "rejected"; - rejectedThenable.reason = error; - } - } - ); // Check one more time in case the thenable resolved synchronously. + var pendingComponentWillMountWarnings = []; + var pendingUNSAFE_ComponentWillMountWarnings = []; + var pendingComponentWillReceivePropsWarnings = []; + var pendingUNSAFE_ComponentWillReceivePropsWarnings = []; + var pendingComponentWillUpdateWarnings = []; + var pendingUNSAFE_ComponentWillUpdateWarnings = []; // Tracks components we have already warned about. - switch (thenable.status) { - case "fulfilled": { - var fulfilledThenable = thenable; - return fulfilledThenable.value; - } + var didWarnAboutUnsafeLifecycles = new Set(); - 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. + ReactStrictModeWarnings.recordUnsafeLifecycleWarnings = function ( + fiber, + instance + ) { + // Dedupe strategy: Warn once per component. + if (didWarnAboutUnsafeLifecycles.has(fiber.type)) { + return; + } - suspendedThenable = thenable; - - { - needsToResetSuspendedThenableDEV = true; - } + if ( + typeof instance.componentWillMount === "function" && // Don't warn about react-lifecycles-compat polyfilled components. + instance.componentWillMount.__suppressDeprecationWarning !== true + ) { + pendingComponentWillMountWarnings.push(fiber); + } - throw SuspenseException; + if ( + fiber.mode & StrictLegacyMode && + typeof instance.UNSAFE_componentWillMount === "function" + ) { + pendingUNSAFE_ComponentWillMountWarnings.push(fiber); } - } - } - // 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." - ); - } + if ( + typeof instance.componentWillReceiveProps === "function" && + instance.componentWillReceiveProps.__suppressDeprecationWarning !== + true + ) { + pendingComponentWillReceivePropsWarnings.push(fiber); + } - var thenable = suspendedThenable; - suspendedThenable = null; + if ( + fiber.mode & StrictLegacyMode && + typeof instance.UNSAFE_componentWillReceiveProps === "function" + ) { + pendingUNSAFE_ComponentWillReceivePropsWarnings.push(fiber); + } - { - needsToResetSuspendedThenableDEV = false; - } + if ( + typeof instance.componentWillUpdate === "function" && + instance.componentWillUpdate.__suppressDeprecationWarning !== true + ) { + pendingComponentWillUpdateWarnings.push(fiber); + } - return thenable; - } - function checkIfUseWrappedInTryCatch() { - { - // This was set right before SuspenseException was thrown, and it should - // have been cleared when the exception was handled. If it wasn't, - // it must have been caught by userspace. - if (needsToResetSuspendedThenableDEV) { - needsToResetSuspendedThenableDEV = false; - return true; + if ( + fiber.mode & StrictLegacyMode && + typeof instance.UNSAFE_componentWillUpdate === "function" + ) { + pendingUNSAFE_ComponentWillUpdateWarnings.push(fiber); } - } + }; - 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." - ); - } - } + ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = + function () { + // We do an initial pass to gather component names + var componentWillMountUniqueNames = new Set(); - var thenableState$1 = null; - var thenableIndexCounter$1 = 0; - var didWarnAboutMaps; - var didWarnAboutGenerators; - var didWarnAboutStringRefs; - var ownerHasKeyUseWarning; - var ownerHasFunctionTypeWarning; + if (pendingComponentWillMountWarnings.length > 0) { + pendingComponentWillMountWarnings.forEach(function (fiber) { + componentWillMountUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingComponentWillMountWarnings = []; + } - var warnForMissingKey = function (child, returnFiber) {}; + var UNSAFE_componentWillMountUniqueNames = new Set(); - { - 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 (pendingUNSAFE_ComponentWillMountWarnings.length > 0) { + pendingUNSAFE_ComponentWillMountWarnings.forEach(function (fiber) { + UNSAFE_componentWillMountUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingUNSAFE_ComponentWillMountWarnings = []; + } - ownerHasKeyUseWarning = {}; - ownerHasFunctionTypeWarning = {}; + var componentWillReceivePropsUniqueNames = new Set(); - warnForMissingKey = function (child, returnFiber) { - if (child === null || typeof child !== "object") { - return; - } + if (pendingComponentWillReceivePropsWarnings.length > 0) { + pendingComponentWillReceivePropsWarnings.forEach(function (fiber) { + componentWillReceivePropsUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingComponentWillReceivePropsWarnings = []; + } - if (!child._store || child._store.validated || child.key != null) { - return; - } + var UNSAFE_componentWillReceivePropsUniqueNames = new Set(); - 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 (pendingUNSAFE_ComponentWillReceivePropsWarnings.length > 0) { + pendingUNSAFE_ComponentWillReceivePropsWarnings.forEach( + function (fiber) { + UNSAFE_componentWillReceivePropsUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + } + ); + pendingUNSAFE_ComponentWillReceivePropsWarnings = []; + } - child._store.validated = true; - var componentName = - getComponentNameFromFiber(returnFiber) || "Component"; + var componentWillUpdateUniqueNames = new Set(); - if (ownerHasKeyUseWarning[componentName]) { - return; - } + if (pendingComponentWillUpdateWarnings.length > 0) { + pendingComponentWillUpdateWarnings.forEach(function (fiber) { + componentWillUpdateUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingComponentWillUpdateWarnings = []; + } - ownerHasKeyUseWarning[componentName] = true; + var UNSAFE_componentWillUpdateUniqueNames = new Set(); - error( - "Each child in a list should have a unique " + - '"key" prop. See https://reactjs.org/link/warning-keys for ' + - "more information." - ); - }; - } + 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 isReactClass(type) { - return type.prototype && type.prototype.isReactComponent; - } + if (UNSAFE_componentWillMountUniqueNames.size > 0) { + var sortedNames = setToSortedString( + UNSAFE_componentWillMountUniqueNames + ); - function unwrapThenable(thenable) { - var index = thenableIndexCounter$1; - thenableIndexCounter$1 += 1; + 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 (thenableState$1 === null) { - thenableState$1 = createThenableState(); - } + if (UNSAFE_componentWillReceivePropsUniqueNames.size > 0) { + var _sortedNames = setToSortedString( + UNSAFE_componentWillReceivePropsUniqueNames + ); - return trackUsedThenable(thenableState$1, thenable, index); - } + 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 + ); + } - function coerceRef(returnFiber, current, element) { - var mixedRef = element.ref; + if (UNSAFE_componentWillUpdateUniqueNames.size > 0) { + var _sortedNames2 = setToSortedString( + UNSAFE_componentWillUpdateUniqueNames + ); - 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"; - - 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 - ); - - didWarnAboutStringRefs[componentName] = true; - } - } - } - - if (element._owner) { - var owner = element._owner; - var inst; - - if (owner) { - var ownerFiber = owner; - - 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" - ); - } - - inst = ownerFiber.stateNode; + 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 (!inst) { - throw new Error( - "Missing owner for string ref " + - mixedRef + - ". This error is likely caused by a " + - "bug in React. Please file an issue." + if (componentWillMountUniqueNames.size > 0) { + var _sortedNames3 = setToSortedString( + componentWillMountUniqueNames ); - } // Assigning this to a const so Flow knows it won't change in the closure - - var resolvedInst = inst; - { - checkPropStringCoercion(mixedRef, "ref"); + warn( + "componentWillMount has been renamed, and is not recommended for use. " + + "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + + "* Move code with side effects to componentDidMount, and set initial state in the constructor.\n" + + "* Rename componentWillMount to UNSAFE_componentWillMount to suppress " + + "this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. " + + "To rename all deprecated lifecycles to their new names, you can run " + + "`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n" + + "\nPlease update the following components: %s", + _sortedNames3 + ); } - var stringRef = "" + mixedRef; // Check if previous string ref matches new string ref + if (componentWillReceivePropsUniqueNames.size > 0) { + var _sortedNames4 = setToSortedString( + componentWillReceivePropsUniqueNames + ); - if ( - current !== null && - current.ref !== null && - typeof current.ref === "function" && - current.ref._stringRef === stringRef - ) { - return current.ref; + 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 ref = function (value) { - var refs = resolvedInst.refs; - - if (value === null) { - delete refs[stringRef]; - } else { - refs[stringRef] = value; - } - }; - - ref._stringRef = stringRef; - return ref; - } else { - if (typeof mixedRef !== "string") { - throw new Error( - "Expected ref to be a function, a string, an object returned by React.createRef(), or null." + if (componentWillUpdateUniqueNames.size > 0) { + var _sortedNames5 = setToSortedString( + componentWillUpdateUniqueNames ); - } - 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." + warn( + "componentWillUpdate has been renamed, and is not recommended for use. " + + "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + + "* Move data fetching code or side effects to componentDidUpdate.\n" + + "* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress " + + "this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. " + + "To rename all deprecated lifecycles to their new names, you can run " + + "`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n" + + "\nPlease update the following components: %s", + _sortedNames5 ); } - } - } - - return mixedRef; - } - - function throwOnInvalidObjectType(returnFiber, newChild) { - // $FlowFixMe[method-unbinding] - var childString = Object.prototype.toString.call(newChild); - throw new Error( - "Objects are not valid as a React child (found: " + - (childString === "[object Object]" - ? "object with keys {" + Object.keys(newChild).join(", ") + "}" - : childString) + - "). " + - "If you meant to render a collection of children, use an array " + - "instead." - ); - } - - function warnOnFunctionType(returnFiber) { - { - var componentName = - getComponentNameFromFiber(returnFiber) || "Component"; + }; - if (ownerHasFunctionTypeWarning[componentName]) { - return; - } + var pendingLegacyContextWarning = new Map(); // Tracks components we have already warned about. - ownerHasFunctionTypeWarning[componentName] = true; + var didWarnAboutLegacyContext = new Set(); - 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." - ); - } - } + ReactStrictModeWarnings.recordLegacyContextWarning = function ( + fiber, + instance + ) { + var strictRoot = findStrictRoot(fiber); - 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 (strictRoot === null) { + error( + "Expected to find a StrictMode component in a strict mode tree. " + + "This error is likely caused by a bug in React. Please file an issue." + ); - function createChildReconciler(shouldTrackSideEffects) { - function deleteChild(returnFiber, childToDelete) { - if (!shouldTrackSideEffects) { - // Noop. return; - } - - var deletions = returnFiber.deletions; + } // Dedup strategy: Warn once per component. - if (deletions === null) { - returnFiber.deletions = [childToDelete]; - returnFiber.flags |= ChildDeletion; - } else { - deletions.push(childToDelete); + if (didWarnAboutLegacyContext.has(fiber.type)) { + return; } - } - function deleteRemainingChildren(returnFiber, currentFirstChild) { - if (!shouldTrackSideEffects) { - // Noop. - return null; - } // TODO: For the shouldClone case, this could be micro-optimized a bit by - // assuming that after the first child we've already added everything. + var warningsForRoot = pendingLegacyContextWarning.get(strictRoot); - var childToDelete = currentFirstChild; + if ( + fiber.type.contextTypes != null || + fiber.type.childContextTypes != null || + (instance !== null && typeof instance.getChildContext === "function") + ) { + if (warningsForRoot === undefined) { + warningsForRoot = []; + pendingLegacyContextWarning.set(strictRoot, warningsForRoot); + } - while (childToDelete !== null) { - deleteChild(returnFiber, childToDelete); - childToDelete = childToDelete.sibling; + warningsForRoot.push(fiber); } + }; - return null; - } + ReactStrictModeWarnings.flushLegacyContextWarning = function () { + pendingLegacyContextWarning.forEach(function (fiberArray, strictRoot) { + if (fiberArray.length === 0) { + 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 firstFiber = fiberArray[0]; + var uniqueNames = new Set(); + fiberArray.forEach(function (fiber) { + uniqueNames.add(getComponentNameFromFiber(fiber) || "Component"); + didWarnAboutLegacyContext.add(fiber.type); + }); + var sortedNames = setToSortedString(uniqueNames); - while (existingChild !== null) { - if (existingChild.key !== null) { - existingChildren.set(existingChild.key, existingChild); - } else { - existingChildren.set(existingChild.index, existingChild); + try { + setCurrentFiber(firstFiber); + + error( + "Legacy context API has been detected within a strict-mode tree." + + "\n\nThe old API will be supported in all 16.x releases, but applications " + + "using it should migrate to the new version." + + "\n\nPlease update the following components: %s" + + "\n\nLearn more about this warning here: https://reactjs.org/link/legacy-context", + sortedNames + ); + } finally { + resetCurrentFiber(); } + }); + }; - existingChild = existingChild.sibling; - } + ReactStrictModeWarnings.discardPendingWarnings = function () { + pendingComponentWillMountWarnings = []; + pendingUNSAFE_ComponentWillMountWarnings = []; + pendingComponentWillReceivePropsWarnings = []; + pendingUNSAFE_ComponentWillReceivePropsWarnings = []; + pendingComponentWillUpdateWarnings = []; + pendingUNSAFE_ComponentWillUpdateWarnings = []; + pendingLegacyContextWarning = new Map(); + }; + } - return existingChildren; - } + /* + * The `'' + value` pattern (used in perf-sensitive code) throws for Symbol + * and Temporal.* types. See https://github.com/facebook/react/pull/22064. + * + * The functions in this module will throw an easier-to-understand, + * easier-to-debug exception with a clear errors message message explaining the + * problem. (Instead of a confusing exception thrown inside the implementation + * of the `value` object). + */ + // $FlowFixMe[incompatible-return] only called in DEV, so void return is not possible. + function typeName(value) { + { + // toStringTag is needed for namespaced types like Temporal.Instant + var hasToStringTag = typeof Symbol === "function" && Symbol.toStringTag; + var type = + (hasToStringTag && value[Symbol.toStringTag]) || + value.constructor.name || + "Object"; // $FlowFixMe[incompatible-return] - function useFiber(fiber, pendingProps) { - // We currently set sibling to null and index to 0 here because it is easy - // to forget to do before returning it. E.g. for the single child case. - var clone = createWorkInProgress(fiber, pendingProps); - clone.index = 0; - clone.sibling = null; - return clone; + return type; } + } // $FlowFixMe[incompatible-return] only called in DEV, so void return is not possible. - function placeChild(newFiber, lastPlacedIndex, newIndex) { - newFiber.index = newIndex; - - if (!shouldTrackSideEffects) { - // During hydration, the useId algorithm needs to know which fibers are - // part of a list of children (arrays, iterators). - newFiber.flags |= Forked; - return lastPlacedIndex; + function willCoercionThrow(value) { + { + try { + testStringCoercion(value); + return false; + } catch (e) { + return true; } + } + } - var current = newFiber.alternate; - - if (current !== null) { - var oldIndex = current.index; + function testStringCoercion(value) { + // If you ended up here by following an exception call stack, here's what's + // happened: you supplied an object or symbol value to React (as a prop, key, + // DOM attribute, CSS property, string ref, etc.) and when React tried to + // coerce it to a string using `'' + value`, an exception was thrown. + // + // The most common types that will cause this exception are `Symbol` instances + // and Temporal objects like `Temporal.Instant`. But any object that has a + // `valueOf` or `[Symbol.toPrimitive]` method that throws will also cause this + // exception. (Library authors do this to prevent users from using built-in + // numeric operators like `+` or comparison operators like `>=` because custom + // methods are needed to perform accurate arithmetic or comparison.) + // + // To fix the problem, coerce this object or symbol value to a string before + // passing it to React. The most reliable way is usually `String(value)`. + // + // To find which value is throwing, check the browser or debugger console. + // Before this exception was thrown, there should be `console.error` output + // that shows the type (Symbol, Temporal.PlainDate, etc.) that caused the + // problem and how that type was used: key, atrribute, input value prop, etc. + // In most cases, this console output also shows the component and its + // ancestor components where the exception happened. + // + // eslint-disable-next-line react-internal/safe-string-coercion + return "" + value; + } + function checkPropStringCoercion(value, propName) { + { + if (willCoercionThrow(value)) { + error( + "The provided `%s` prop is an unsupported type %s." + + " This value must be coerced to a string before using it here.", + propName, + typeName(value) + ); - 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 testStringCoercion(value); // throw (to help callers find troubleshooting comments) } } + } - 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 ReactCurrentActQueue$2 = ReactSharedInternals.ReactCurrentActQueue; // An error that is thrown (e.g. by `use`) to trigger Suspense. If we + // detect this is caught by userspace, we'll log a warning in development. - return newFiber; - } + 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. - function updateTextNode(returnFiber, current, textContent, lanes) { - if (current === null || current.tag !== HostText) { - // Insert - var created = createFiberFromText( - textContent, - returnFiber.mode, - lanes + 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 []; + } + 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; + } - if (current !== null) { - if ( - current.elementType === elementType || // Keep this check inline so it only runs on the false path: - isCompatibleFamilyForHotReloading(current, element) || // Lazy types should reconcile their resolved type. - // We need to do this after the Hot Reloading check above, - // because hot reloading has different semantics than prod because - // it doesn't resuspend. So we can't let the call below suspend. - (typeof elementType === "object" && - elementType !== null && - elementType.$$typeof === REACT_LAZY_TYPE && - resolveLazy(elementType) === current.type) - ) { - // Move based on index - var existing = useFiber(current, element.props); - existing.ref = coerceRef(returnFiber, current, element); - existing.return = returnFiber; + var previous = thenableState[index]; - { - existing._debugSource = element._source; - existing._debugOwner = element._owner; - } + 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. - return existing; - } - } // Insert + switch (thenable.status) { + case "fulfilled": { + var fulfilledValue = thenable.value; + return fulfilledValue; + } - var created = createFiberFromElement(element, returnFiber.mode, lanes); - created.ref = coerceRef(returnFiber, current, element); - created.return = returnFiber; - return created; - } - - 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 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; + case "rejected": { + var rejectedError = thenable.reason; + checkIfUseWrappedInAsyncCatch(rejectedError); + throw rejectedError; } - } - 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; - } + default: { + if (typeof thenable.status === "string") { + // Only instrument the thenable if the status if not defined. If + // it's defined, but an unknown value, assume it's been instrumented by + // some custom userspace implementation. We treat it as "pending". + // Attach a dummy listener, to ensure that any lazy initialization can + // happen. Flight lazily parses JSON when the value is actually awaited. + thenable.then(noop, noop); + } else { + // This is an uncached thenable that we haven't seen before. + // Detect infinite ping loops caused by uncached promises. + var root = getWorkInProgressRoot(); - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: { - var _created = createFiberFromElement( - newChild, - returnFiber.mode, - lanes + 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." ); - - _created.ref = coerceRef(returnFiber, null, newChild); - _created.return = returnFiber; - return _created; } - case REACT_PORTAL_TYPE: { - var _created2 = createFiberFromPortal( - newChild, - returnFiber.mode, - lanes - ); + var pendingThenable = thenable; + pendingThenable.status = "pending"; + pendingThenable.then( + function (fulfilledValue) { + if (thenable.status === "pending") { + var fulfilledThenable = thenable; + fulfilledThenable.status = "fulfilled"; + fulfilledThenable.value = fulfilledValue; + } + }, + function (error) { + if (thenable.status === "pending") { + var rejectedThenable = thenable; + rejectedThenable.status = "rejected"; + rejectedThenable.reason = error; + } + } + ); // Check one more time in case the thenable resolved synchronously. - _created2.return = returnFiber; - return _created2; - } + switch (thenable.status) { + case "fulfilled": { + var fulfilledThenable = thenable; + return fulfilledThenable.value; + } - case REACT_LAZY_TYPE: { - var payload = newChild._payload; - var init = newChild._init; - return createChild(returnFiber, init(payload), lanes); + case "rejected": { + var rejectedThenable = thenable; + var _rejectedError = rejectedThenable.reason; + checkIfUseWrappedInAsyncCatch(_rejectedError); + throw _rejectedError; + } } - } - - if (isArray(newChild) || getIteratorFn(newChild)) { - var _created3 = createFiberFromFragment( - newChild, - returnFiber.mode, - lanes, - null - ); - - _created3.return = returnFiber; - return _created3; - } // Usable node types + } // Suspend. // - // Unwrap the inner value and recursively call this function again. + // Throwing here is an implementation detail that allows us to unwind the + // call stack. But we shouldn't allow it to leak into userspace. Throw an + // opaque placeholder value instead of the actual thenable. If it doesn't + // get captured by the work loop, log a warning, because that means + // something in userspace must have caught it. - if (typeof newChild.then === "function") { - var thenable = newChild; - return createChild(returnFiber, unwrapThenable(thenable), lanes); - } + suspendedThenable = thenable; - if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) { - var context = newChild; - return createChild( - returnFiber, - readContextDuringReconcilation(returnFiber, context, lanes), - lanes - ); + { + needsToResetSuspendedThenableDEV = true; } - throwOnInvalidObjectType(returnFiber, newChild); - } - - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber); - } + throw SuspenseException; } + } + } + // passed to the rest of the Suspense implementation — which, for historical + // reasons, expects to receive a thenable. - return null; + 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 updateSlot(returnFiber, oldFiber, newChild, lanes) { - // Update the fiber if the keys match, otherwise return null. - var key = oldFiber !== null ? oldFiber.key : null; + var thenable = suspendedThenable; + suspendedThenable = null; - if ( - (typeof newChild === "string" && newChild !== "") || - typeof newChild === "number" - ) { - // Text nodes don't have keys. If the previous node is implicitly keyed - // we can continue to replace it without aborting even if it is not a text - // node. - if (key !== null) { - return null; - } + { + needsToResetSuspendedThenableDEV = false; + } - return updateTextNode(returnFiber, oldFiber, "" + newChild, lanes); + return thenable; + } + function checkIfUseWrappedInTryCatch() { + { + // This was set right before SuspenseException was thrown, and it should + // have been cleared when the exception was handled. If it wasn't, + // it must have been caught by userspace. + if (needsToResetSuspendedThenableDEV) { + needsToResetSuspendedThenableDEV = false; + return true; } + } - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: { - if (newChild.key === key) { - return updateElement(returnFiber, oldFiber, newChild, lanes); - } else { - return null; - } - } - - case REACT_PORTAL_TYPE: { - if (newChild.key === key) { - return updatePortal(returnFiber, oldFiber, newChild, lanes); - } else { - return null; - } - } - - case REACT_LAZY_TYPE: { - var payload = newChild._payload; - var init = newChild._init; - return updateSlot(returnFiber, oldFiber, init(payload), lanes); - } - } + 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)) { - if (key !== null) { - return null; - } + var thenableState$1 = null; + var thenableIndexCounter$1 = 0; + var didWarnAboutMaps; + var didWarnAboutGenerators; + var didWarnAboutStringRefs; + var ownerHasKeyUseWarning; + var ownerHasFunctionTypeWarning; - return updateFragment(returnFiber, oldFiber, newChild, lanes, null); - } // 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 updateSlot( - returnFiber, - oldFiber, - 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 updateSlot( - returnFiber, - oldFiber, - 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 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 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 + + child._store.validated = true; + var componentName = + getComponentNameFromFiber(returnFiber) || "Component"; + + if (ownerHasKeyUseWarning[componentName]) { + return; } - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: { - var _matchedFiber = - existingChildren.get( - newChild.key === null ? newIdx : newChild.key - ) || null; + ownerHasKeyUseWarning[componentName] = true; - return updateElement(returnFiber, _matchedFiber, newChild, lanes); - } + error( + "Each child in a list should have a unique " + + '"key" prop. See https://reactjs.org/link/warning-keys for ' + + "more information." + ); + }; + } - case REACT_PORTAL_TYPE: { - var _matchedFiber2 = - existingChildren.get( - newChild.key === null ? newIdx : newChild.key - ) || null; + function isReactClass(type) { + return type.prototype && type.prototype.isReactComponent; + } - return updatePortal(returnFiber, _matchedFiber2, newChild, lanes); - } + function unwrapThenable(thenable) { + var index = thenableIndexCounter$1; + thenableIndexCounter$1 += 1; - case REACT_LAZY_TYPE: - var payload = newChild._payload; - var init = newChild._init; - return updateFromMap( - existingChildren, - returnFiber, - newIdx, - init(payload), - lanes + if (thenableState$1 === null) { + thenableState$1 = createThenableState(); + } + + return trackUsedThenable(thenableState$1, thenable, index); + } + + function coerceRef(returnFiber, current, element) { + var mixedRef = element.ref; + + 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"; + + 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 ); + + didWarnAboutStringRefs[componentName] = true; + } } + } - if (isArray(newChild) || getIteratorFn(newChild)) { - var _matchedFiber3 = existingChildren.get(newIdx) || null; + if (element._owner) { + var owner = element._owner; + var inst; - return updateFragment( - returnFiber, - _matchedFiber3, - newChild, - lanes, - null - ); - } // Usable node types - // - // Unwrap the inner value and recursively call this function again. + if (owner) { + var ownerFiber = owner; - if (typeof newChild.then === "function") { - var thenable = newChild; - return updateFromMap( - existingChildren, - returnFiber, - newIdx, - unwrapThenable(thenable), - 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" + ); + } + + inst = ownerFiber.stateNode; } - if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) { - var context = newChild; - return updateFromMap( - existingChildren, - returnFiber, - newIdx, - readContextDuringReconcilation(returnFiber, context, lanes), - lanes + if (!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 - throwOnInvalidObjectType(returnFiber, newChild); - } + var resolvedInst = inst; - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber); + { + checkPropStringCoercion(mixedRef, "ref"); } - } - return null; - } - /** - * Warns if there is a duplicate or missing key - */ + var stringRef = "" + mixedRef; // Check if previous string ref matches new string ref - function warnOnInvalidKey(child, knownKeys, returnFiber) { - { - if (typeof child !== "object" || child === null) { - return knownKeys; + if ( + current !== null && + current.ref !== null && + typeof current.ref === "function" && + current.ref._stringRef === stringRef + ) { + return current.ref; } - switch (child.$$typeof) { - case REACT_ELEMENT_TYPE: - case REACT_PORTAL_TYPE: - warnForMissingKey(child, returnFiber); - var key = child.key; + var ref = function (value) { + var refs = resolvedInst.refs; - if (typeof key !== "string") { - break; - } + if (value === null) { + delete refs[stringRef]; + } else { + refs[stringRef] = value; + } + }; + + ref._stringRef = stringRef; + return ref; + } else { + if (typeof mixedRef !== "string") { + throw new Error( + "Expected ref to be a function, a string, an object returned by React.createRef(), or null." + ); + } - if (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; - lastPlacedIndex = placeChild(_newFiber2, lastPlacedIndex, newIdx); + if (elementType === REACT_FRAGMENT_TYPE) { + return updateFragment( + returnFiber, + current, + element.props.children, + lanes, + element.key + ); + } - if (previousNewFiber === null) { - resultingFirstChild = _newFiber2; - } else { - previousNewFiber.sibling = _newFiber2; + 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; + + { + existing._debugSource = element._source; + 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 (isArray(newChild) || getIteratorFn(newChild)) { + var _created3 = createFiberFromFragment( + newChild, + returnFiber.mode, + lanes, + null + ); - if (newChildren == null) { - throw new Error("An iterable object provided no iterator."); - } + _created3.return = returnFiber; + return _created3; + } // Usable node types + // + // Unwrap the inner value and recursively call this function again. - var resultingFirstChild = null; - var previousNewFiber = null; - var oldFiber = currentFirstChild; - var lastPlacedIndex = 0; - var newIdx = 0; - var nextOldFiber = null; - var step = newChildren.next(); + if (typeof newChild.then === "function") { + var thenable = newChild; + return createChild(returnFiber, unwrapThenable(thenable), lanes); + } - for ( - ; - oldFiber !== null && !step.done; - newIdx++, step = newChildren.next() - ) { - if (oldFiber.index > newIdx) { - nextOldFiber = oldFiber; - oldFiber = null; - } else { - nextOldFiber = oldFiber.sibling; + if ( + newChild.$$typeof === REACT_CONTEXT_TYPE || + newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE + ) { + var context = newChild; + return createChild( + returnFiber, + readContextDuringReconcilation(returnFiber, context, lanes), + lanes + ); } - var newFiber = updateSlot(returnFiber, oldFiber, step.value, 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 || + newChild.$$typeof === REACT_SERVER_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 || + newChild.$$typeof === REACT_SERVER_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; + } + + break; } - if (isArray(newChild)) { - return reconcileChildrenArray( - returnFiber, - currentFirstChild, - newChild, - 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 (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. + lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); - if (typeof newChild.then === "function") { - var thenable = newChild; - return reconcileChildFibersImpl( - returnFiber, - currentFirstChild, - unwrapThenable(thenable), - lanes - ); + 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 ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) { - var context = newChild; - return reconcileChildFibersImpl( + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } + + if (newIdx === newChildren.length) { + // We've reached the end of the new children. We can delete the rest. + deleteRemainingChildren(returnFiber, oldFiber); + + return resultingFirstChild; + } + + if (oldFiber === null) { + // If we don't have any more existing children we can choose a fast path + // since the rest will all be insertions. + for (; newIdx < newChildren.length; newIdx++) { + var _newFiber = createChild( returnFiber, - currentFirstChild, - readContextDuringReconcilation(returnFiber, context, lanes), + newChildren[newIdx], lanes ); + + if (_newFiber === null) { + continue; + } + + lastPlacedIndex = placeChild(_newFiber, lastPlacedIndex, newIdx); + + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = _newFiber; + } else { + previousNewFiber.sibling = _newFiber; + } + + previousNewFiber = _newFiber; } - throwOnInvalidObjectType(returnFiber, newChild); - } + return resultingFirstChild; + } // Add all children to a key map for quick lookups. - if ( - (typeof newChild === "string" && newChild !== "") || - typeof newChild === "number" - ) { - return placeSingleChild( - reconcileSingleTextNode( - returnFiber, - currentFirstChild, - "" + newChild, - lanes - ) + var existingChildren = mapRemainingChildren(returnFiber, oldFiber); // Keep scanning and use the map to restore deleted items as moves. + + for (; newIdx < newChildren.length; newIdx++) { + var _newFiber2 = updateFromMap( + existingChildren, + returnFiber, + newIdx, + newChildren[newIdx], + lanes ); - } - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber); + if (_newFiber2 !== null) { + if (shouldTrackSideEffects) { + if (_newFiber2.alternate !== null) { + // The new fiber is a work in progress, but if there exists a + // current, that means that we reused the fiber. We need to delete + // it from the child list so that we don't add it to the deletion + // list. + existingChildren.delete( + _newFiber2.key === null ? newIdx : _newFiber2.key + ); + } + } + + lastPlacedIndex = placeChild(_newFiber2, lastPlacedIndex, newIdx); + + if (previousNewFiber === null) { + resultingFirstChild = _newFiber2; + } else { + previousNewFiber.sibling = _newFiber2; + } + + previousNewFiber = _newFiber2; } - } // Remaining cases are all treated as empty. + } - return deleteRemainingChildren(returnFiber, currentFirstChild); + 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 reconcileChildFibers( + function reconcileChildrenIterator( returnFiber, currentFirstChild, - newChild, + newChildrenIterable, lanes ) { - // This indirection only exists so we can reset `thenableState` at the end. - // It should get inlined by Closure. - thenableIndexCounter$1 = 0; - var firstChildFiber = reconcileChildFibersImpl( - returnFiber, - currentFirstChild, - newChild, - lanes - ); - thenableState$1 = null; // Don't bother to reset `thenableIndexCounter` to 0 because it always gets - // set at the beginning. - - return firstChildFiber; - } - - return reconcileChildFibers; - } + // This is the same implementation as reconcileChildrenArray(), + // but using the iterator instead. + var iteratorFn = getIteratorFn(newChildrenIterable); - var reconcileChildFibers = createChildReconciler(true); - var mountChildFibers = createChildReconciler(false); - function resetChildReconcilerOnUnwind() { - // On unwind, clear any pending thenables that were used. - thenableState$1 = null; - thenableIndexCounter$1 = 0; - } - function cloneChildFibers(current, workInProgress) { - if (current !== null && workInProgress.child !== current.child) { - throw new Error("Resuming work not yet implemented."); - } + if (typeof iteratorFn !== "function") { + throw new Error( + "An object is not an iterable. This error is likely caused by a bug in " + + "React. Please file an issue." + ); + } - if (workInProgress.child === null) { - return; - } + { + // We don't support rendering Generators because it's a mutation. + // See https://github.com/facebook/react/issues/12995 + if ( + typeof Symbol === "function" && // $FlowFixMe[prop-missing] Flow doesn't know about toStringTag + newChildrenIterable[Symbol.toStringTag] === "Generator" + ) { + if (!didWarnAboutGenerators) { + error( + "Using Generators as children is unsupported and will likely yield " + + "unexpected results because enumerating a generator mutates it. " + + "You may convert it to an array with `Array.from()` or the " + + "`[...spread]` operator before rendering. Keep in mind " + + "you might need to polyfill these features for older browsers." + ); + } - var currentChild = workInProgress.child; - var newChild = createWorkInProgress( - currentChild, - currentChild.pendingProps - ); - workInProgress.child = newChild; - newChild.return = workInProgress; + didWarnAboutGenerators = true; + } // Warn about using Maps as children - while (currentChild.sibling !== null) { - currentChild = currentChild.sibling; - newChild = newChild.sibling = createWorkInProgress( - currentChild, - currentChild.pendingProps - ); - newChild.return = workInProgress; - } + if (newChildrenIterable.entries === iteratorFn) { + if (!didWarnAboutMaps) { + error( + "Using Maps as children is not supported. " + + "Use an array of keyed ReactElements instead." + ); + } - newChild.sibling = null; - } // Reset a workInProgress child set to prepare it for a second pass. + didWarnAboutMaps = true; + } // First, validate keys. + // We'll get a different iterator later for the main pass. - function resetChildFibers(workInProgress, lanes) { - var child = workInProgress.child; + var _newChildren = iteratorFn.call(newChildrenIterable); - while (child !== null) { - resetWorkInProgress(child, lanes); - child = child.sibling; - } - } + if (_newChildren) { + var knownKeys = null; - // TODO: This isn't being used yet, but it's intended to replace the - // InvisibleParentContext that is currently managed by SuspenseContext. + var _step = _newChildren.next(); - 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. + for (; !_step.done; _step = _newChildren.next()) { + var child = _step.value; + knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber); + } + } + } - 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 newChildren = iteratorFn.call(newChildrenIterable); - // suspends, i.e. it's the nearest `catch` block on the stack. + if (newChildren == null) { + throw new Error("An iterable object provided no iterator."); + } - 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 resultingFirstChild = null; + var previousNewFiber = null; + var oldFiber = currentFirstChild; + var lastPlacedIndex = 0; + var newIdx = 0; + var nextOldFiber = null; + var step = newChildren.next(); - 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. + for ( + ; + oldFiber !== null && !step.done; + newIdx++, step = newChildren.next() + ) { + if (oldFiber.index > newIdx) { + nextOldFiber = oldFiber; + oldFiber = null; + } else { + nextOldFiber = oldFiber.sibling; + } - pushSuspenseListContext( - handler, - setDefaultShallowSuspenseListContext(suspenseStackCursor.current) - ); // Experimental feature: Some Suspense boundaries are marked as having an - // to push a nested Suspense handler, because it will get replaced by the - // outer fallback, anyway. Consider this as a future optimization. + var newFiber = updateSlot(returnFiber, oldFiber, step.value, lanes); - push(suspenseHandlerStackCursor, handler, handler); + 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 (shellBoundary === null) { - if (current === null || isCurrentTreeHidden()) { - // This boundary is not visible in the current UI. - shellBoundary = handler; - } else { - var prevState = current.memoizedState; + break; + } - if (prevState !== null) { - // This boundary is showing a fallback in the current UI. - shellBoundary = handler; + if (shouldTrackSideEffects) { + if (oldFiber && newFiber.alternate === null) { + // We matched the slot, but we didn't reuse the existing fiber, so we + // need to delete the existing child. + deleteChild(returnFiber, oldFiber); + } + } + + lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); + + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = newFiber; + } else { + // TODO: Defer siblings if we're not at the right index for this slot. + // I.e. if we had null values before, then we want to defer this + // for each null value. However, we also don't want to call updateSlot + // with the previous one. + previousNewFiber.sibling = newFiber; } + + previousNewFiber = newFiber; + oldFiber = nextOldFiber; } - } - } - function pushFallbackTreeSuspenseHandler(fiber) { - // We're about to render the fallback. If something in the fallback suspends, - // it's akin to throwing inside of a `catch` block. This boundary should not - // capture. Reuse the existing handler on the stack. - reuseSuspenseHandlerOnStack(fiber); - } - function pushOffscreenSuspenseHandler(fiber) { - if (fiber.tag === OffscreenComponent) { - // A SuspenseList context is only pushed here to avoid a push/pop mismatch. - // Reuse the current value on the stack. - // TODO: We can avoid needing to push here by by forking popSuspenseHandler - // into separate functions for Suspense and Offscreen. - pushSuspenseListContext(fiber, suspenseStackCursor.current); - push(suspenseHandlerStackCursor, fiber, fiber); - if (shellBoundary !== null); - else { - var current = fiber.alternate; + if (step.done) { + // We've reached the end of the new children. We can delete the rest. + deleteRemainingChildren(returnFiber, oldFiber); - if (current !== null) { - var prevState = current.memoizedState; + return resultingFirstChild; + } - if (prevState !== null) { - // This is the first boundary in the stack that's already showing - // a fallback. So everything outside is considered the shell. - shellBoundary = fiber; + if (oldFiber === null) { + // If we don't have any more existing children we can choose a fast path + // since the rest will all be insertions. + for (; !step.done; newIdx++, step = newChildren.next()) { + var _newFiber3 = createChild(returnFiber, step.value, lanes); + + if (_newFiber3 === null) { + continue; } - } - } - } 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; - } + lastPlacedIndex = placeChild(_newFiber3, lastPlacedIndex, newIdx); - popSuspenseListContext(fiber); - } // SuspenseList context - // TODO: Move to a separate module? We may change the SuspenseList - // implementation to hide/show in the commit phase, anyway. + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = _newFiber3; + } else { + previousNewFiber.sibling = _newFiber3; + } - 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. + previousNewFiber = _newFiber3; + } - 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); - } + return resultingFirstChild; + } // Add all children to a key map for quick lookups. - // 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 existingChildren = mapRemainingChildren(returnFiber, oldFiber); // Keep scanning and use the map to restore deleted items as moves. - function findFirstSuspended(row) { - var node = row; + for (; !step.done; newIdx++, step = newChildren.next()) { + var _newFiber4 = updateFromMap( + existingChildren, + returnFiber, + newIdx, + step.value, + lanes + ); - while (node !== null) { - if (node.tag === SuspenseComponent) { - var state = node.memoizedState; + 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 (state !== null) { - var dehydrated = state.dehydrated; + lastPlacedIndex = placeChild(_newFiber4, lastPlacedIndex, newIdx); - if ( - dehydrated === null || - isSuspenseInstancePending() || - isSuspenseInstanceFallback() - ) { - return node; + if (previousNewFiber === null) { + resultingFirstChild = _newFiber4; + } else { + previousNewFiber.sibling = _newFiber4; } - } - } 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; + previousNewFiber = _newFiber4; } - } else if (node.child !== null) { - node.child.return = node; - node = node.child; - continue; } - if (node === row) { - return null; + 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); + }); } - while (node.sibling === null) { - if (node.return === null || node.return === row) { - return null; - } + return resultingFirstChild; + } - node = node.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. - node.sibling.return = node.return; - node = node.sibling; + deleteRemainingChildren(returnFiber, currentFirstChild); + var created = createFiberFromText(textContent, returnFiber.mode, lanes); + created.return = returnFiber; + return created; } - return null; - } + function reconcileSingleElement( + returnFiber, + currentFirstChild, + element, + lanes + ) { + var key = element.key; + var child = currentFirstChild; - var NoFlags = - /* */ - 0; // Represents whether effect should fire. + while (child !== null) { + // TODO: If key === null and child.key === null, then this only applies to + // the first item in the list. + if (child.key === key) { + var elementType = element.type; - var HasEffect = - /* */ - 1; // Represents the phase in which the effect (not the clean-up) fires. + if (elementType === REACT_FRAGMENT_TYPE) { + if (child.tag === Fragment) { + deleteRemainingChildren(returnFiber, child.sibling); + var existing = useFiber(child, element.props.children); + existing.return = returnFiber; - var Insertion = - /* */ - 2; - var Layout = - /* */ - 4; - var Passive = - /* */ - 8; + { + existing._debugSource = element._source; + existing._debugOwner = element._owner; + } - 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 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 firstScheduledRoot = null; - var lastScheduledRoot = null; // Used to prevent redundant mircotasks from being scheduled. + var _existing = useFiber(child, element.props); - 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. + _existing.ref = coerceRef(returnFiber, child, element); + _existing.return = returnFiber; - var didScheduleMicrotask_act = false; // Used to quickly bail out of flushSync if there's no sync work to do. + { + _existing._debugSource = element._source; + _existing._debugOwner = element._owner; + } - 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. + return _existing; + } + } // Didn't match. - 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. + deleteRemainingChildren(returnFiber, child); + break; + } else { + deleteChild(returnFiber, child); + } - if (ReactCurrentActQueue$2.current !== null) { - // We're inside an `act` scope. - if (!didScheduleMicrotask_act) { - didScheduleMicrotask_act = true; - scheduleImmediateTask(processRootScheduleInMicrotask); - } - } else { - if (!didScheduleMicrotask) { - didScheduleMicrotask = true; - scheduleImmediateTask(processRootScheduleInMicrotask); + child = child.sibling; } - } - - if (ReactCurrentActQueue$2.isBatchingLegacy && root.tag === LegacyRoot) { - // Special `act` case: Record whenever a legacy update is scheduled. - ReactCurrentActQueue$2.didScheduleLegacyUpdate = true; - } - } - function flushSyncWorkOnAllRoots() { - // This is allowed to be called synchronously, but the caller should check - // the execution context first. - flushSyncWorkAcrossRoots_impl(false); - } - function flushSyncWorkOnLegacyRootsOnly() { - // This is allowed to be called synchronously, but the caller should check - // the execution context first. - flushSyncWorkAcrossRoots_impl(true); - } - - function flushSyncWorkAcrossRoots_impl(onlyLegacy) { - if (isFlushingWork) { - // Prevent reentrancy. - // TODO: Is this overly defensive? The callers must check the execution - // context first regardless. - return; - } - - if (!mightHavePendingSyncWork) { - // Fast path. There's no sync work to do. - return; - } // There may or may not be synchronous work scheduled. Let's check. - - var didPerformSomeWork; - var errors = null; - isFlushingWork = true; - - do { - didPerformSomeWork = false; - var root = firstScheduledRoot; - while (root !== null) { - if (onlyLegacy && root.tag !== LegacyRoot); - else { - var workInProgressRoot = getWorkInProgressRoot(); - var workInProgressRootRenderLanes = - getWorkInProgressRootRenderLanes(); - var nextLanes = getNextLanes( - root, - root === workInProgressRoot - ? workInProgressRootRenderLanes - : NoLanes - ); + 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 (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); - } - } + _created4.ref = coerceRef(returnFiber, currentFirstChild, element); + _created4.return = returnFiber; + return _created4; + } + } + + 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); } - 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. + var created = createFiberFromPortal(portal, returnFiber.mode, lanes); + created.return = returnFiber; + return created; + } // This API will tag the children with the side-effect of the reconciliation + // itself. They will be added to the side-effect list as we pass through the + // children and the parent. - if (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])); - } + 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; - var firstError = errors[0]; - throw firstError; + if (isUnkeyedTopLevelFragment) { + newChild = newChild.props.children; + } // Handle object types + + if (typeof newChild === "object" && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return placeSingleChild( + reconcileSingleElement( + returnFiber, + currentFirstChild, + newChild, + lanes + ) + ); + + case REACT_PORTAL_TYPE: + return placeSingleChild( + reconcileSinglePortal( + returnFiber, + currentFirstChild, + newChild, + lanes + ) + ); + + case REACT_LAZY_TYPE: + var payload = newChild._payload; + var init = newChild._init; // TODO: This function is supposed to be non-recursive. + + return reconcileChildFibers( + returnFiber, + currentFirstChild, + init(payload), + lanes + ); } - } else { - var error = errors[0]; - throw error; - } - } - } - function throwError(error) { - throw error; - } + if (isArray(newChild)) { + return reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChild, + lanes + ); + } - function processRootScheduleInMicrotask() { - // This function is always called inside a microtask. It should never be - // called synchronously. - didScheduleMicrotask = false; + 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. - { - didScheduleMicrotask_act = false; - } // We'll recompute this as we iterate through all the roots and schedule them. + if (typeof newChild.then === "function") { + var thenable = newChild; + return reconcileChildFibersImpl( + returnFiber, + currentFirstChild, + unwrapThenable(thenable), + lanes + ); + } - mightHavePendingSyncWork = false; - var currentTime = now$1(); - var prev = null; - var root = firstScheduledRoot; + if ( + newChild.$$typeof === REACT_CONTEXT_TYPE || + newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE + ) { + var context = newChild; + return reconcileChildFibersImpl( + returnFiber, + currentFirstChild, + readContextDuringReconcilation(returnFiber, context, lanes), + lanes + ); + } - while (root !== null) { - var next = root.next; + throwOnInvalidObjectType(returnFiber, newChild); + } if ( - currentEventTransitionLane !== NoLane && - shouldAttemptEagerTransition() + (typeof newChild === "string" && newChild !== "") || + typeof newChild === "number" ) { - // 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); + return placeSingleChild( + reconcileSingleTextNode( + returnFiber, + currentFirstChild, + "" + newChild, + lanes + ) + ); } - var nextLanes = scheduleTaskForRootDuringMicrotask(root, currentTime); - - if (nextLanes === NoLane) { - // This root has no more pending work. Remove it from the schedule. To - // guard against subtle reentrancy bugs, this microtask is the only place - // we do this — you can add roots to the schedule whenever, but you can - // only remove them here. - // Null this out so we know it's been removed from the schedule. - root.next = null; - - if (prev === null) { - // This is the new head of the list - firstScheduledRoot = next; - } else { - prev.next = next; + { + if (typeof newChild === "function") { + warnOnFunctionType(returnFiber); } + } // Remaining cases are all treated as empty. - 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; + return deleteRemainingChildren(returnFiber, currentFirstChild); + } - if (includesSyncLane(nextLanes)) { - mightHavePendingSyncWork = true; - } - } + 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. - root = next; + return firstChildFiber; } - 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. + return reconcileChildFibers; + } - flushSyncWorkOnAllRoots(); + 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."); + } - 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 (workInProgress.child === null) { + return; + } - var workInProgressRoot = getWorkInProgressRoot(); - var workInProgressRootRenderLanes = getWorkInProgressRootRenderLanes(); - var nextLanes = getNextLanes( - root, - root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes + var currentChild = workInProgress.child; + var newChild = createWorkInProgress( + currentChild, + currentChild.pendingProps ); - var existingCallbackNode = root.callbackNode; + workInProgress.child = newChild; + newChild.return = workInProgress; - 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); - } + while (currentChild.sibling !== null) { + currentChild = currentChild.sibling; + newChild = newChild.sibling = createWorkInProgress( + currentChild, + currentChild.pendingProps + ); + newChild.return = workInProgress; + } - root.callbackNode = null; - root.callbackPriority = NoLane; - return NoLane; - } // Schedule a new callback in the host environment. + newChild.sibling = null; + } // Reset a workInProgress child set to prepare it for a second pass. - 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); - } + function resetChildFibers(workInProgress, lanes) { + var child = workInProgress.child; - 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); + while (child !== null) { + resetWorkInProgress(child, lanes); + child = child.sibling; + } + } - 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); - } + // TODO: This isn't being used yet, but it's intended to replace the + // InvisibleParentContext that is currently managed by SuspenseContext. - var schedulerPriorityLevel; + 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. - switch (lanesToEventPriority(nextLanes)) { - case DiscreteEventPriority: - schedulerPriorityLevel = ImmediatePriority; - break; + 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; + } - case ContinuousEventPriority: - schedulerPriorityLevel = UserBlockingPriority; - break; + // suspends, i.e. it's the nearest `catch` block on the stack. - case DefaultEventPriority: - schedulerPriorityLevel = NormalPriority$1; - break; + 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. - case IdleEventPriority: - schedulerPriorityLevel = IdlePriority; - break; + 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. - default: - schedulerPriorityLevel = NormalPriority$1; - break; - } + pushSuspenseListContext( + handler, + setDefaultShallowSuspenseListContext(suspenseStackCursor.current) + ); // Experimental feature: Some Suspense boundaries are marked as having an + // to push a nested Suspense handler, because it will get replaced by the + // outer fallback, anyway. Consider this as a future optimization. - var newCallbackNode = scheduleCallback$2( - schedulerPriorityLevel, - performConcurrentWorkOnRoot.bind(null, root) - ); - root.callbackPriority = newCallbackPriority; - root.callbackNode = newCallbackNode; - return newCallbackPriority; - } - } + push(suspenseHandlerStackCursor, handler, handler); - function getContinuationForRoot(root, originalCallbackNode) { - // This is called at the end of `performConcurrentWorkOnRoot` to determine - // if we need to schedule a continuation task. - // - // Usually `scheduleTaskForRootDuringMicrotask` only runs inside a microtask; - // however, since most of the logic for determining if we need a continuation - // versus a new task is the same, we cheat a bit and call it here. This is - // only safe to do because we know we're at the end of the browser task. - // So although it's not an actual microtask, it might as well be. - scheduleTaskForRootDuringMicrotask(root, now$1()); + if (shellBoundary === null) { + if (current === null || isCurrentTreeHidden()) { + // This boundary is not visible in the current UI. + shellBoundary = handler; + } else { + var prevState = current.memoizedState; - if (root.callbackNode === originalCallbackNode) { - // The task node scheduled for this root is the same one that's - // currently executed. Need to return a continuation. - return performConcurrentWorkOnRoot.bind(null, root); + if (prevState !== null) { + // This boundary is showing a fallback in the current UI. + shellBoundary = handler; + } + } } - - return null; } - var fakeActCallbackNode$1 = {}; + function pushFallbackTreeSuspenseHandler(fiber) { + // We're about to render the fallback. If something in the fallback suspends, + // it's akin to throwing inside of a `catch` block. This boundary should not + // capture. Reuse the existing handler on the stack. + reuseSuspenseHandlerOnStack(fiber); + } + function pushOffscreenSuspenseHandler(fiber) { + if (fiber.tag === OffscreenComponent) { + // A SuspenseList context is only pushed here to avoid a push/pop mismatch. + // Reuse the current value on the stack. + // TODO: We can avoid needing to push here by by forking popSuspenseHandler + // into separate functions for Suspense and Offscreen. + pushSuspenseListContext(fiber, suspenseStackCursor.current); + push(suspenseHandlerStackCursor, fiber, fiber); + + if (shellBoundary !== null); + else { + var current = fiber.alternate; - function scheduleCallback$2(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; + 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 { - return scheduleCallback$3(priorityLevel, callback); + // This is a LegacyHidden component. + reuseSuspenseHandlerOnStack(fiber); } } - - function cancelCallback(callbackNode) { - if (callbackNode === fakeActCallbackNode$1); - else if (callbackNode !== null) { - cancelCallback$1(callbackNode); - } + function reuseSuspenseHandlerOnStack(fiber) { + pushSuspenseListContext(fiber, suspenseStackCursor.current); + push(suspenseHandlerStackCursor, getSuspenseHandler(), 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 microtasks are not supported, use Scheduler. - scheduleCallback$3(ImmediatePriority, cb); - } + 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. - // 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 DefaultSuspenseContext = 0; + var SubtreeSuspenseContextMask = 1; // ForceSuspenseFallback can be used by SuspenseList to force newly added + // items into their fallback state during one of the render passes. - var currentEntangledListeners = null; // The number of pending async actions in the entangled scope. + 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 currentEntangledPendingCount = 0; // The transition lane shared by all updates 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 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; + function findFirstSuspended(row) { + var node = row; - 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; @@ -7702,6 +7694,7 @@ if (__DEV__) { 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 @@ -7745,7 +7738,16 @@ if (__DEV__) { markSkippedUpdateLanes(updateLane); } else { // This update does have sufficient priority. - // Check if this is an optimistic update. + // 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; + } // Check if this is an optimistic update. + var revertLane = update.revertLane; if (revertLane === NoLane) { @@ -7837,7 +7839,23 @@ if (__DEV__) { // 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; @@ -8297,14 +8315,10 @@ if (__DEV__) { return finishRunningFormStateAction(actionQueue, setState); } ); - var entangledResult = requestAsyncActionContext(thenable, null); - setState(entangledResult); + entangleAsyncAction(thenable); + setState(thenable); } else { - // This is either `returnValue` or a thenable that resolves to - // `returnValue`, depending on whether we're inside an async action scope. - var _entangledResult = requestSyncActionContext(returnValue, null); - - setState(_entangledResult); + setState(returnValue); var nextState = returnValue; actionQueue.state = nextState; finishRunningFormStateAction(actionQueue, setState); @@ -8895,24 +8909,17 @@ if (__DEV__) { typeof returnValue === "object" && typeof returnValue.then === "function" ) { - var thenable = returnValue; // This is a thenable that resolves to `finishedState` once the async - // action scope has finished. + var thenable = returnValue; + entangleAsyncAction(thenable); // Create a thenable that resolves to `finishedState` once the async + // action has completed. - var entangledResult = requestAsyncActionContext( + var thenableForFinishedState = chainThenableValue( thenable, finishedState ); - dispatchSetState(fiber, queue, entangledResult); + dispatchSetState(fiber, queue, thenableForFinishedState); } else { - // This is either `finishedState` or a thenable that resolves to - // `finishedState`, depending on whether we're inside an async - // action scope. - var _entangledResult2 = requestSyncActionContext( - returnValue, - finishedState - ); - - dispatchSetState(fiber, queue, _entangledResult2); + dispatchSetState(fiber, queue, finishedState); } } } catch (error) { @@ -11454,6 +11461,7 @@ if (__DEV__) { // process them now. processUpdateQueue(workInProgress, newProps, instance, renderLanes); + suspendIfUpdateReadFromEntangledAsyncAction(); instance.state = workInProgress.memoizedState; } @@ -11521,6 +11529,7 @@ if (__DEV__) { var oldState = workInProgress.memoizedState; var newState = (instance.state = oldState); processUpdateQueue(workInProgress, newProps, instance, renderLanes); + suspendIfUpdateReadFromEntangledAsyncAction(); newState = workInProgress.memoizedState; if ( @@ -11673,6 +11682,7 @@ if (__DEV__) { var oldState = workInProgress.memoizedState; var newState = (instance.state = oldState); processUpdateQueue(workInProgress, newProps, instance, renderLanes); + suspendIfUpdateReadFromEntangledAsyncAction(); newState = workInProgress.memoizedState; if ( @@ -12223,7 +12233,7 @@ if (__DEV__) { } } - return; + return false; } case OffscreenComponent: { @@ -12258,7 +12268,7 @@ if (__DEV__) { attachPingListener(root, wakeable, rootRenderLanes); } - return; + return false; } } } @@ -12281,7 +12291,7 @@ if (__DEV__) { // 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( @@ -12301,6 +12311,12 @@ if (__DEV__) { // 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 { @@ -12316,7 +12332,7 @@ if (__DEV__) { lane ); enqueueCapturedUpdate(workInProgress, update); - return; + return false; } case ClassComponent: @@ -12345,7 +12361,7 @@ if (__DEV__) { ); enqueueCapturedUpdate(workInProgress, _update); - return; + return false; } break; @@ -12353,6 +12369,8 @@ if (__DEV__) { workInProgress = workInProgress.return; } while (workInProgress !== null); + + return false; } var ReactCurrentOwner$1 = ReactSharedInternals.ReactCurrentOwner; // A special exception that's used to unwind the stack when an update flows @@ -12963,6 +12981,7 @@ if (__DEV__) { if (includesSomeLane(current.lanes, renderLanes)) { cloneUpdateQueue(current, workInProgress); processUpdateQueue(workInProgress, null, null, renderLanes); + suspendIfUpdateReadFromEntangledAsyncAction(); } var prevState = current.memoizedState; @@ -13394,7 +13413,11 @@ if (__DEV__) { // The root cache refreshed. propagateContextChange(workInProgress, CacheContext, renderLanes); } - } // Caution: React DevTools currently depends on this property + } // This would ideally go inside processUpdateQueue, but because it suspends, + // it needs to happen after the `pushCacheProvider` call above to avoid a + // context stack mismatch. A bit unfortunate. + + suspendIfUpdateReadFromEntangledAsyncAction(); // Caution: React DevTools currently depends on this property // being called "element". var nextChildren = nextState.element; @@ -22672,7 +22695,7 @@ if (__DEV__) { // Unwind then continue with the normal work loop. workInProgressSuspendedReason = NotSuspended; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(unitOfWork, thrownValue); + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); break; } } @@ -22755,7 +22778,7 @@ if (__DEV__) { // Unwind then continue with the normal work loop. workInProgressSuspendedReason = NotSuspended; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(unitOfWork, thrownValue); + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); break; } @@ -22820,7 +22843,7 @@ if (__DEV__) { // Otherwise, unwind then continue with the normal work loop. workInProgressSuspendedReason = NotSuspended; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(unitOfWork, thrownValue); + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); } break; @@ -22885,7 +22908,7 @@ if (__DEV__) { workInProgressSuspendedReason = NotSuspended; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(unitOfWork, thrownValue); + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); break; } @@ -22896,7 +22919,7 @@ if (__DEV__) { // always unwind. workInProgressSuspendedReason = NotSuspended; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(unitOfWork, thrownValue); + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); break; } @@ -23115,7 +23138,7 @@ if (__DEV__) { ReactCurrentOwner.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. // @@ -23124,40 +23147,33 @@ if (__DEV__) { 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) { @@ -23177,6 +23193,22 @@ if (__DEV__) { } } + 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. @@ -25540,7 +25572,7 @@ if (__DEV__) { return root; } - var ReactVersion = "18.3.0-canary-2efb14260-20240124"; + var ReactVersion = "18.3.0-canary-11c9fd0c5-20240124"; // Might add PROFILE later. diff --git a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-prod.js b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-prod.js index 43af05c397046..6a3faf1adfe45 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-prod.js +++ b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-prod.js @@ -7,7 +7,7 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<> + * @generated SignedSource<<9932d13e942d3ba6b8d1169bf8e60373>> */ "use strict"; @@ -786,6 +786,276 @@ 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$3(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$7 = workInProgressRootRenderLanes, + nextLanes = getNextLanes( + root, + root === workInProgressRoot ? workInProgressRootRenderLanes$7 : 0 + ); + if (0 !== (nextLanes & 3)) + try { + didPerformSomeWork = !0; + workInProgressRootRenderLanes$7 = root; + if (0 !== (executionContext & 6)) + throw Error("Should not already be working."); + if (!flushPassiveEffects()) { + var exitStatus = renderRootSync( + workInProgressRootRenderLanes$7, + nextLanes + ); + if ( + 0 !== workInProgressRootRenderLanes$7.tag && + 2 === exitStatus + ) { + var originallyAttemptedLanes = nextLanes, + errorRetryLanes = getLanesToRetrySynchronouslyOnError( + workInProgressRootRenderLanes$7, + originallyAttemptedLanes + ); + 0 !== errorRetryLanes && + ((nextLanes = errorRetryLanes), + (exitStatus = recoverFromConcurrentError( + workInProgressRootRenderLanes$7, + originallyAttemptedLanes, + errorRetryLanes + ))); + } + if (1 === exitStatus) + throw ( + ((originallyAttemptedLanes = workInProgressRootFatalError), + prepareFreshStack(workInProgressRootRenderLanes$7, 0), + markRootSuspended( + workInProgressRootRenderLanes$7, + nextLanes, + 0 + ), + ensureRootIsScheduled(workInProgressRootRenderLanes$7), + originallyAttemptedLanes) + ); + 6 === exitStatus + ? markRootSuspended( + workInProgressRootRenderLanes$7, + nextLanes, + workInProgressDeferredLane + ) + : ((workInProgressRootRenderLanes$7.finishedWork = + workInProgressRootRenderLanes$7.current.alternate), + (workInProgressRootRenderLanes$7.finishedLanes = nextLanes), + commitRoot( + workInProgressRootRenderLanes$7, + workInProgressRootRecoverableErrors, + workInProgressTransitions, + workInProgressDeferredLane + )); + } + ensureRootIsScheduled(workInProgressRootRenderLanes$7); + } 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$3(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$2 = 31 - clz32(lanes), + lane = 1 << index$2, + expirationTime = expirationTimes[index$2]; + if (-1 === expirationTime) { + if (0 === (lane & suspendedLanes) || 0 !== (lane & pingedLanes)) + expirationTimes[index$2] = 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$1; + break; + case 268435456: + suspendedLanes = IdlePriority; + break; + default: + suspendedLanes = NormalPriority$1; + } + pingedLanes = performConcurrentWorkOnRoot.bind(null, root); + suspendedLanes = scheduleCallback$3(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 currentEntangledListeners = null, + currentEntangledPendingCount = 0, + currentEntangledLane = 0, + currentEntangledActionThenable = null; +function entangleAsyncAction(thenable) { + if (null === currentEntangledListeners) { + var entangledListeners = (currentEntangledListeners = []); + currentEntangledPendingCount = 0; + currentEntangledLane = requestTransitionLane(); + currentEntangledActionThenable = { + status: "pending", + value: void 0, + then: function (resolve) { + entangledListeners.push(resolve); + } + }; + } + currentEntangledPendingCount++; + thenable.then(pingEngtangledActionScope, pingEngtangledActionScope); + return thenable; +} +function pingEngtangledActionScope() { + if ( + null !== currentEntangledListeners && + 0 === --currentEntangledPendingCount + ) { + null !== currentEntangledActionThenable && + (currentEntangledActionThenable.status = "fulfilled"); + var listeners = currentEntangledListeners; + currentEntangledListeners = null; + currentEntangledLane = 0; + currentEntangledActionThenable = null; + for (var i = 0; i < listeners.length; i++) (0, listeners[i])(); + } +} +function chainThenableValue(thenable, result) { + var listeners = [], + thenableWithOverride = { + status: "pending", + value: null, + reason: null, + then: function (resolve) { + listeners.push(resolve); + } + }; + thenable.then( + function () { + thenableWithOverride.status = "fulfilled"; + thenableWithOverride.value = result; + for (var i = 0; i < listeners.length; i++) (0, listeners[i])(result); + }, + function (error) { + thenableWithOverride.status = "rejected"; + thenableWithOverride.reason = error; + for (error = 0; error < listeners.length; error++) + (0, listeners[error])(void 0); + } + ); + return thenableWithOverride; +} var hasForceUpdate = !1; function initializeUpdateQueue(fiber) { fiber.updateQueue = { @@ -881,12 +1151,20 @@ function enqueueCapturedUpdate(workInProgress, capturedUpdate) { : (workInProgress.next = capturedUpdate); queue.lastBaseUpdate = capturedUpdate; } +var didReadFromEntangledAsyncAction = !1; +function suspendIfUpdateReadFromEntangledAsyncAction() { + if (didReadFromEntangledAsyncAction) { + var entangledActionThenable = currentEntangledActionThenable; + if (null !== entangledActionThenable) throw entangledActionThenable; + } +} function processUpdateQueue( workInProgress$jscomp$0, props, instance$jscomp$0, renderLanes ) { + didReadFromEntangledAsyncAction = !1; var queue = workInProgress$jscomp$0.updateQueue; hasForceUpdate = !1; var firstBaseUpdate = queue.firstBaseUpdate, @@ -924,6 +1202,9 @@ function processUpdateQueue( ? (workInProgressRootRenderLanes & updateLane) === updateLane : (renderLanes & updateLane) === updateLane ) { + 0 !== updateLane && + updateLane === currentEntangledLane && + (didReadFromEntangledAsyncAction = !0); null !== current && (current = current.next = { @@ -1907,379 +2188,91 @@ function createChildReconciler(shouldTrackSideEffects) { 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$3(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$24 = workInProgressRootRenderLanes, - nextLanes = getNextLanes( - root, - root === workInProgressRoot ? workInProgressRootRenderLanes$24 : 0 - ); - if (0 !== (nextLanes & 3)) - try { - didPerformSomeWork = !0; - workInProgressRootRenderLanes$24 = root; - if (0 !== (executionContext & 6)) - throw Error("Should not already be working."); - if (!flushPassiveEffects()) { - var exitStatus = renderRootSync( - workInProgressRootRenderLanes$24, - nextLanes - ); - if ( - 0 !== workInProgressRootRenderLanes$24.tag && - 2 === exitStatus - ) { - var originallyAttemptedLanes = nextLanes, - errorRetryLanes = getLanesToRetrySynchronouslyOnError( - workInProgressRootRenderLanes$24, - originallyAttemptedLanes - ); - 0 !== errorRetryLanes && - ((nextLanes = errorRetryLanes), - (exitStatus = recoverFromConcurrentError( - workInProgressRootRenderLanes$24, - originallyAttemptedLanes, - errorRetryLanes - ))); - } - if (1 === exitStatus) - throw ( - ((originallyAttemptedLanes = workInProgressRootFatalError), - prepareFreshStack(workInProgressRootRenderLanes$24, 0), - markRootSuspended( - workInProgressRootRenderLanes$24, - nextLanes, - 0 - ), - ensureRootIsScheduled(workInProgressRootRenderLanes$24), - originallyAttemptedLanes) - ); - 6 === exitStatus - ? markRootSuspended( - workInProgressRootRenderLanes$24, - nextLanes, - workInProgressDeferredLane - ) - : ((workInProgressRootRenderLanes$24.finishedWork = - workInProgressRootRenderLanes$24.current.alternate), - (workInProgressRootRenderLanes$24.finishedLanes = - nextLanes), - commitRoot( - workInProgressRootRenderLanes$24, - workInProgressRootRecoverableErrors, - workInProgressTransitions, - workInProgressDeferredLane - )); - } - ensureRootIsScheduled(workInProgressRootRenderLanes$24); - } 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$3(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$2 = 31 - clz32(lanes), - lane = 1 << index$2, - expirationTime = expirationTimes[index$2]; - if (-1 === expirationTime) { - if (0 === (lane & suspendedLanes) || 0 !== (lane & pingedLanes)) - expirationTimes[index$2] = 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 + 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$1; - break; - case 268435456: - suspendedLanes = IdlePriority; - break; - default: - suspendedLanes = NormalPriority$1; + thenableState$1 = null; + return returnFiber; } - pingedLanes = performConcurrentWorkOnRoot.bind(null, root); - suspendedLanes = scheduleCallback$3(suspendedLanes, pingedLanes); - root.callbackPriority = currentTime; - root.callbackNode = suspendedLanes; - return currentTime; + return reconcileChildFibers; } -function requestTransitionLane() { - if (0 === currentEventTransitionLane) { - var lane = nextTransitionLane; - nextTransitionLane <<= 1; - 0 === (nextTransitionLane & 4194176) && (nextTransitionLane = 128); - currentEventTransitionLane = lane; - } - return currentEventTransitionLane; +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; } -var currentEntangledListeners = null, - currentEntangledPendingCount = 0, - currentEntangledLane = 0; -function requestAsyncActionContext(actionReturnValue, overrideReturnValue) { - if (null === currentEntangledListeners) { - var entangledListeners = (currentEntangledListeners = []); - currentEntangledPendingCount = 0; - currentEntangledLane = requestTransitionLane(); - } else entangledListeners = currentEntangledListeners; - currentEntangledPendingCount++; - var resultThenable = createResultThenable(entangledListeners), - resultStatus = "pending", - resultValue, - rejectedReason; - actionReturnValue.then( - function (value) { - resultStatus = "fulfilled"; - resultValue = null !== overrideReturnValue ? overrideReturnValue : value; - pingEngtangledActionScope(); - }, - function (error) { - resultStatus = "rejected"; - rejectedReason = error; - pingEngtangledActionScope(); - } - ); - entangledListeners.push(function () { - switch (resultStatus) { - case "fulfilled": - resultThenable.status = "fulfilled"; - resultThenable.value = resultValue; - break; - case "rejected": - resultThenable.status = "rejected"; - resultThenable.reason = rejectedReason; - break; - default: - throw Error( - "Thenable should have already resolved. This is a bug in React." - ); +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); } - }); - return resultThenable; -} -function requestSyncActionContext(actionReturnValue, overrideReturnValue) { - var resultValue = - null !== overrideReturnValue ? overrideReturnValue : actionReturnValue; - if (null === currentEntangledListeners) return resultValue; - actionReturnValue = currentEntangledListeners; - var resultThenable = createResultThenable(actionReturnValue); - actionReturnValue.push(function () { - resultThenable.status = "fulfilled"; - resultThenable.value = resultValue; - }); - return resultThenable; + } else reuseSuspenseHandlerOnStack(fiber); } -function pingEngtangledActionScope() { - if ( - null !== currentEntangledListeners && - 0 === --currentEntangledPendingCount - ) { - var listeners = currentEntangledListeners; - currentEntangledListeners = null; - for (var i = (currentEntangledLane = 0); i < listeners.length; i++) - (0, listeners[i])(); - } +function reuseSuspenseHandlerOnStack() { + push(suspenseStackCursor, suspenseStackCursor.current); + push(suspenseHandlerStackCursor, suspenseHandlerStackCursor.current); } -function createResultThenable(entangledListeners) { - return { - status: "pending", - value: null, - reason: null, - then: function (resolve) { - entangledListeners.push(resolve); +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 ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher, ReactCurrentBatchConfig$2 = ReactSharedInternals.ReactCurrentBatchConfig, @@ -2537,7 +2530,8 @@ function updateReducerImpl(hook, current, reducer) { current = baseQueue.next; var newBaseQueueFirst = (baseFirst = null), newBaseQueueLast = null, - update = current; + update = current, + didReadFromEntangledAsyncAction$26 = !1; do { var updateLane = update.lane & -536870913; if ( @@ -2545,6 +2539,9 @@ function updateReducerImpl(hook, current, reducer) { ? (workInProgressRootRenderLanes & updateLane) === updateLane : (renderLanes & updateLane) === updateLane ) { + 0 !== updateLane && + updateLane === currentEntangledLane && + (didReadFromEntangledAsyncAction$26 = !0); updateLane = update.revertLane; if (0 === updateLane) null !== newBaseQueueLast && @@ -2561,7 +2558,7 @@ function updateReducerImpl(hook, current, reducer) { update = update.next; continue; } else { - var clone$27 = { + var clone$28 = { lane: 0, revertLane: update.revertLane, action: update.action, @@ -2570,9 +2567,9 @@ function updateReducerImpl(hook, current, reducer) { next: null }; null === newBaseQueueLast - ? ((newBaseQueueFirst = newBaseQueueLast = clone$27), + ? ((newBaseQueueFirst = newBaseQueueLast = clone$28), (baseFirst = pendingQueue)) - : (newBaseQueueLast = newBaseQueueLast.next = clone$27); + : (newBaseQueueLast = newBaseQueueLast.next = clone$28); currentlyRenderingFiber$1.lanes |= updateLane; workInProgressRootSkippedLanes |= updateLane; } @@ -2583,7 +2580,7 @@ function updateReducerImpl(hook, current, reducer) { ? update.eagerState : reducer(pendingQueue, updateLane); } else - (clone$27 = { + (clone$28 = { lane: updateLane, revertLane: update.revertLane, action: update.action, @@ -2592,9 +2589,9 @@ function updateReducerImpl(hook, current, reducer) { next: null }), null === newBaseQueueLast - ? ((newBaseQueueFirst = newBaseQueueLast = clone$27), + ? ((newBaseQueueFirst = newBaseQueueLast = clone$28), (baseFirst = pendingQueue)) - : (newBaseQueueLast = newBaseQueueLast.next = clone$27), + : (newBaseQueueLast = newBaseQueueLast.next = clone$28), (currentlyRenderingFiber$1.lanes |= updateLane), (workInProgressRootSkippedLanes |= updateLane); update = update.next; @@ -2602,7 +2599,13 @@ function updateReducerImpl(hook, current, reducer) { null === newBaseQueueLast ? (baseFirst = pendingQueue) : (newBaseQueueLast.next = newBaseQueueFirst); - objectIs(pendingQueue, hook.memoizedState) || (didReceiveUpdate = !0); + if ( + !objectIs(pendingQueue, hook.memoizedState) && + ((didReceiveUpdate = !0), + didReadFromEntangledAsyncAction$26 && + ((reducer = currentEntangledActionThenable), null !== reducer)) + ) + throw reducer; hook.memoizedState = pendingQueue; hook.baseState = baseFirst; hook.baseQueue = newBaseQueueLast; @@ -2746,28 +2749,23 @@ function runFormStateAction(actionQueue, setState, payload) { ReactCurrentBatchConfig$2.transition = {}; try { var returnValue = action(prevState, payload); - if ( - null !== returnValue && - "object" === typeof returnValue && - "function" === typeof returnValue.then - ) { - returnValue.then( - function (nextState) { - actionQueue.state = nextState; - finishRunningFormStateAction(actionQueue, setState); - }, - function () { - return finishRunningFormStateAction(actionQueue, setState); - } - ); - var entangledResult = requestAsyncActionContext(returnValue, null); - setState(entangledResult); - } else { - var entangledResult$29 = requestSyncActionContext(returnValue, null); - setState(entangledResult$29); - actionQueue.state = returnValue; - finishRunningFormStateAction(actionQueue, setState); - } + null !== returnValue && + "object" === typeof returnValue && + "function" === typeof returnValue.then + ? (returnValue.then( + function (nextState) { + actionQueue.state = nextState; + finishRunningFormStateAction(actionQueue, setState); + }, + function () { + return finishRunningFormStateAction(actionQueue, setState); + } + ), + entangleAsyncAction(returnValue), + setState(returnValue)) + : (setState(returnValue), + (actionQueue.state = returnValue), + finishRunningFormStateAction(actionQueue, setState)); } catch (error) { setState({ then: function () {}, status: "rejected", reason: error }), finishRunningFormStateAction(actionQueue, setState); @@ -2948,18 +2946,13 @@ function startTransition(fiber, queue, pendingState, finishedState, callback) { "object" === typeof returnValue && "function" === typeof returnValue.then ) { - var entangledResult = requestAsyncActionContext( - returnValue, - finishedState - ); - dispatchSetState(fiber, queue, entangledResult); - } else { - var entangledResult$31 = requestSyncActionContext( + entangleAsyncAction(returnValue); + var thenableForFinishedState = chainThenableValue( returnValue, finishedState ); - dispatchSetState(fiber, queue, entangledResult$31); - } + dispatchSetState(fiber, queue, thenableForFinishedState); + } else dispatchSetState(fiber, queue, finishedState); } catch (error) { dispatchSetState(fiber, queue, { then: function () {}, @@ -3560,6 +3553,7 @@ function mountClassInstance(workInProgress, ctor, newProps, renderLanes) { ctor !== instance.state && classComponentUpdater.enqueueReplaceState(instance, instance.state, null), processUpdateQueue(workInProgress, newProps, instance, renderLanes), + suspendIfUpdateReadFromEntangledAsyncAction(), (instance.state = workInProgress.memoizedState)); "function" === typeof instance.componentDidMount && (workInProgress.flags |= 4194308); @@ -3631,6 +3625,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." @@ -3946,6 +4087,7 @@ function updateClassComponent( var oldState = workInProgress.memoizedState; instance.state = oldState; processUpdateQueue(workInProgress, nextProps, instance, renderLanes); + suspendIfUpdateReadFromEntangledAsyncAction(); oldContext = workInProgress.memoizedState; oldProps !== nextProps || oldState !== oldContext || @@ -4025,6 +4167,7 @@ function updateClassComponent( oldState = workInProgress.memoizedState; instance.state = oldState; processUpdateQueue(workInProgress, nextProps, instance, renderLanes); + suspendIfUpdateReadFromEntangledAsyncAction(); var newState = workInProgress.memoizedState; oldProps !== hasNewLifecycles || oldState !== newState || @@ -4948,14 +5091,14 @@ function cutOffTailIfNeeded(renderState, hasRenderedATailFallback) { break; case "collapsed": lastTailNode = renderState.tail; - for (var lastTailNode$63 = null; null !== lastTailNode; ) - null !== lastTailNode.alternate && (lastTailNode$63 = lastTailNode), + for (var lastTailNode$62 = null; null !== lastTailNode; ) + null !== lastTailNode.alternate && (lastTailNode$62 = lastTailNode), (lastTailNode = lastTailNode.sibling); - null === lastTailNode$63 + null === lastTailNode$62 ? hasRenderedATailFallback || null === renderState.tail ? (renderState.tail = null) : (renderState.tail.sibling = null) - : (lastTailNode$63.sibling = null); + : (lastTailNode$62.sibling = null); } } function bubbleProperties(completedWork) { @@ -4965,19 +5108,19 @@ function bubbleProperties(completedWork) { newChildLanes = 0, subtreeFlags = 0; if (didBailout) - for (var child$64 = completedWork.child; null !== child$64; ) - (newChildLanes |= child$64.lanes | child$64.childLanes), - (subtreeFlags |= child$64.subtreeFlags & 31457280), - (subtreeFlags |= child$64.flags & 31457280), - (child$64.return = completedWork), - (child$64 = child$64.sibling); + for (var child$63 = completedWork.child; null !== child$63; ) + (newChildLanes |= child$63.lanes | child$63.childLanes), + (subtreeFlags |= child$63.subtreeFlags & 31457280), + (subtreeFlags |= child$63.flags & 31457280), + (child$63.return = completedWork), + (child$63 = child$63.sibling); else - for (child$64 = completedWork.child; null !== child$64; ) - (newChildLanes |= child$64.lanes | child$64.childLanes), - (subtreeFlags |= child$64.subtreeFlags), - (subtreeFlags |= child$64.flags), - (child$64.return = completedWork), - (child$64 = child$64.sibling); + for (child$63 = completedWork.child; null !== child$63; ) + (newChildLanes |= child$63.lanes | child$63.childLanes), + (subtreeFlags |= child$63.subtreeFlags), + (subtreeFlags |= child$63.flags), + (child$63.return = completedWork), + (child$63 = child$63.sibling); completedWork.subtreeFlags |= subtreeFlags; completedWork.childLanes = newChildLanes; return didBailout; @@ -5138,11 +5281,11 @@ function completeWork(current, workInProgress, renderLanes) { null !== newProps.alternate.memoizedState && null !== newProps.alternate.memoizedState.cachePool && (index = newProps.alternate.memoizedState.cachePool.pool); - var cache$68 = null; + var cache$67 = null; null !== newProps.memoizedState && null !== newProps.memoizedState.cachePool && - (cache$68 = newProps.memoizedState.cachePool.pool); - cache$68 !== index && (newProps.flags |= 2048); + (cache$67 = newProps.memoizedState.cachePool.pool); + cache$67 !== index && (newProps.flags |= 2048); } renderLanes !== current && renderLanes && @@ -5169,8 +5312,8 @@ function completeWork(current, workInProgress, renderLanes) { index = workInProgress.memoizedState; if (null === index) return bubbleProperties(workInProgress), null; newProps = 0 !== (workInProgress.flags & 128); - cache$68 = index.rendering; - if (null === cache$68) + cache$67 = index.rendering; + if (null === cache$67) if (newProps) cutOffTailIfNeeded(index, !1); else { if ( @@ -5178,11 +5321,11 @@ function completeWork(current, workInProgress, renderLanes) { (null !== current && 0 !== (current.flags & 128)) ) for (current = workInProgress.child; null !== current; ) { - cache$68 = findFirstSuspended(current); - if (null !== cache$68) { + cache$67 = findFirstSuspended(current); + if (null !== cache$67) { workInProgress.flags |= 128; cutOffTailIfNeeded(index, !1); - current = cache$68.updateQueue; + current = cache$67.updateQueue; workInProgress.updateQueue = current; scheduleRetryEffect(workInProgress, current); workInProgress.subtreeFlags = 0; @@ -5207,7 +5350,7 @@ function completeWork(current, workInProgress, renderLanes) { } else { if (!newProps) - if (((current = findFirstSuspended(cache$68)), null !== current)) { + if (((current = findFirstSuspended(cache$67)), null !== current)) { if ( ((workInProgress.flags |= 128), (newProps = !0), @@ -5217,7 +5360,7 @@ function completeWork(current, workInProgress, renderLanes) { cutOffTailIfNeeded(index, !0), null === index.tail && "hidden" === index.tailMode && - !cache$68.alternate) + !cache$67.alternate) ) return bubbleProperties(workInProgress), null; } else @@ -5229,13 +5372,13 @@ function completeWork(current, workInProgress, renderLanes) { cutOffTailIfNeeded(index, !1), (workInProgress.lanes = 4194304)); index.isBackwards - ? ((cache$68.sibling = workInProgress.child), - (workInProgress.child = cache$68)) + ? ((cache$67.sibling = workInProgress.child), + (workInProgress.child = cache$67)) : ((current = index.last), null !== current - ? (current.sibling = cache$68) - : (workInProgress.child = cache$68), - (index.last = cache$68)); + ? (current.sibling = cache$67) + : (workInProgress.child = cache$67), + (index.last = cache$67)); } if (null !== index.tail) return ( @@ -5448,8 +5591,8 @@ function safelyDetachRef(current, nearestMountedAncestor) { else if ("function" === typeof ref) try { ref(null); - } catch (error$84) { - captureCommitPhaseError(current, nearestMountedAncestor, error$84); + } catch (error$83) { + captureCommitPhaseError(current, nearestMountedAncestor, error$83); } else ref.current = null; } @@ -5555,10 +5698,10 @@ function commitHookEffectListMount(flags, finishedWork) { var effect = (finishedWork = finishedWork.next); do { if ((effect.tag & flags) === flags) { - var create$85 = effect.create, + var create$84 = effect.create, inst = effect.inst; - create$85 = create$85(); - inst.destroy = create$85; + create$84 = create$84(); + inst.destroy = create$84; } effect = effect.next; } while (effect !== finishedWork); @@ -5612,11 +5755,11 @@ function commitLayoutEffectOnFiber(finishedRoot, current, finishedWork) { current, finishedRoot.__reactInternalSnapshotBeforeUpdate ); - } catch (error$86) { + } catch (error$85) { captureCommitPhaseError( finishedWork, finishedWork.return, - error$86 + error$85 ); } } @@ -5993,8 +6136,8 @@ function commitMutationEffectsOnFiber(finishedWork, root) { } try { commitHookEffectListUnmount(5, finishedWork, finishedWork.return); - } catch (error$94) { - captureCommitPhaseError(finishedWork, finishedWork.return, error$94); + } catch (error$93) { + captureCommitPhaseError(finishedWork, finishedWork.return, error$93); } } break; @@ -6032,8 +6175,8 @@ function commitMutationEffectsOnFiber(finishedWork, root) { finishedWork.updateQueue = null; try { (flags.type = type), (flags.props = existingHiddenCallbacks); - } catch (error$97) { - captureCommitPhaseError(finishedWork, finishedWork.return, error$97); + } catch (error$96) { + captureCommitPhaseError(finishedWork, finishedWork.return, error$96); } } break; @@ -6049,8 +6192,8 @@ function commitMutationEffectsOnFiber(finishedWork, root) { existingHiddenCallbacks = finishedWork.memoizedProps; try { flags.text = existingHiddenCallbacks; - } catch (error$98) { - captureCommitPhaseError(finishedWork, finishedWork.return, error$98); + } catch (error$97) { + captureCommitPhaseError(finishedWork, finishedWork.return, error$97); } } break; @@ -6134,11 +6277,11 @@ function commitMutationEffectsOnFiber(finishedWork, root) { wasHidden.stateNode.isHidden = existingHiddenCallbacks ? !0 : !1; - } catch (error$88) { + } catch (error$87) { captureCommitPhaseError( finishedWork, finishedWork.return, - error$88 + error$87 ); } } else if ( @@ -6216,12 +6359,12 @@ function commitReconciliationEffects(finishedWork) { break; case 3: case 4: - var parent$89 = JSCompiler_inline_result.stateNode.containerInfo, - before$90 = getHostSibling(finishedWork); + var parent$88 = JSCompiler_inline_result.stateNode.containerInfo, + before$89 = getHostSibling(finishedWork); insertOrAppendPlacementNodeIntoContainer( finishedWork, - before$90, - parent$89 + before$89, + parent$88 ); break; default: @@ -7290,13 +7433,13 @@ function renderRootSync(root, lanes) { default: (workInProgressSuspendedReason = 0), (workInProgressThrownValue = null), - throwAndUnwindWorkLoop(unitOfWork, thrownValue); + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); } } workLoopSync(); break; - } catch (thrownValue$106) { - handleThrow(root, thrownValue$106); + } catch (thrownValue$105) { + handleThrow(root, thrownValue$105); } while (1); lanes && root.shellSuspendCounter++; @@ -7334,7 +7477,7 @@ function renderRootConcurrent(root, lanes) { case 1: workInProgressSuspendedReason = 0; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(lanes, thrownValue); + throwAndUnwindWorkLoop(root, lanes, thrownValue); break; case 2: if (isThenableResolved(thrownValue)) { @@ -7364,7 +7507,7 @@ function renderRootConcurrent(root, lanes) { replaySuspendedUnitOfWork(lanes)) : ((workInProgressSuspendedReason = 0), (workInProgressThrownValue = null), - throwAndUnwindWorkLoop(lanes, thrownValue)); + throwAndUnwindWorkLoop(root, lanes, thrownValue)); break; case 5: switch (workInProgress.tag) { @@ -7387,12 +7530,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(); @@ -7404,8 +7547,8 @@ function renderRootConcurrent(root, lanes) { } workLoopConcurrent(); break; - } catch (thrownValue$108) { - handleThrow(root, thrownValue$108); + } catch (thrownValue$107) { + handleThrow(root, thrownValue$107); } while (1); resetContextDependencies(); @@ -7484,191 +7627,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; @@ -8161,6 +8168,7 @@ beginWork = function (current, workInProgress, renderLanes) { pushProvider(workInProgress, CacheContext, nextCache); nextCache !== context.cache && propagateContextChange(workInProgress, CacheContext, renderLanes); + suspendIfUpdateReadFromEntangledAsyncAction(); context = hasContext.element; context === Component ? (workInProgress = bailoutOnAlreadyFinishedWork( @@ -8378,7 +8386,8 @@ beginWork = function (current, workInProgress, renderLanes) { pushProvider(workInProgress, CacheContext, context)) : (0 !== (current.lanes & renderLanes) && (cloneUpdateQueue(current, workInProgress), - processUpdateQueue(workInProgress, null, null, renderLanes)), + processUpdateQueue(workInProgress, null, null, renderLanes), + suspendIfUpdateReadFromEntangledAsyncAction()), (context = current.memoizedState), (hasContext = workInProgress.memoizedState), context.parent !== Component @@ -9117,19 +9126,19 @@ function wrapFiber(fiber) { fiberToWrapper.set(fiber, wrapper)); return wrapper; } -var devToolsConfig$jscomp$inline_1037 = { +var devToolsConfig$jscomp$inline_1031 = { findFiberByHostInstance: function () { throw Error("TestRenderer does not support findFiberByHostInstance()"); }, bundleType: 0, - version: "18.3.0-canary-2efb14260-20240124", + version: "18.3.0-canary-11c9fd0c5-20240124", rendererPackageName: "react-test-renderer" }; -var internals$jscomp$inline_1230 = { - bundleType: devToolsConfig$jscomp$inline_1037.bundleType, - version: devToolsConfig$jscomp$inline_1037.version, - rendererPackageName: devToolsConfig$jscomp$inline_1037.rendererPackageName, - rendererConfig: devToolsConfig$jscomp$inline_1037.rendererConfig, +var internals$jscomp$inline_1207 = { + bundleType: devToolsConfig$jscomp$inline_1031.bundleType, + version: devToolsConfig$jscomp$inline_1031.version, + rendererPackageName: devToolsConfig$jscomp$inline_1031.rendererPackageName, + rendererConfig: devToolsConfig$jscomp$inline_1031.rendererConfig, overrideHookState: null, overrideHookStateDeletePath: null, overrideHookStateRenamePath: null, @@ -9146,26 +9155,26 @@ var internals$jscomp$inline_1230 = { return null === fiber ? null : fiber.stateNode; }, findFiberByHostInstance: - devToolsConfig$jscomp$inline_1037.findFiberByHostInstance || + devToolsConfig$jscomp$inline_1031.findFiberByHostInstance || emptyFindFiberByHostInstance, findHostInstancesForRefresh: null, scheduleRefresh: null, scheduleRoot: null, setRefreshHandler: null, getCurrentFiber: null, - reconcilerVersion: "18.3.0-canary-2efb14260-20240124" + reconcilerVersion: "18.3.0-canary-11c9fd0c5-20240124" }; if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) { - var hook$jscomp$inline_1231 = __REACT_DEVTOOLS_GLOBAL_HOOK__; + var hook$jscomp$inline_1208 = __REACT_DEVTOOLS_GLOBAL_HOOK__; if ( - !hook$jscomp$inline_1231.isDisabled && - hook$jscomp$inline_1231.supportsFiber + !hook$jscomp$inline_1208.isDisabled && + hook$jscomp$inline_1208.supportsFiber ) try { - (rendererID = hook$jscomp$inline_1231.inject( - internals$jscomp$inline_1230 + (rendererID = hook$jscomp$inline_1208.inject( + internals$jscomp$inline_1207 )), - (injectedHook = hook$jscomp$inline_1231); + (injectedHook = hook$jscomp$inline_1208); } catch (err) {} } exports._Scheduler = Scheduler; diff --git a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-profiling.js b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-profiling.js index 6f69e920e56ad..481ce28566fd8 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-profiling.js +++ b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-profiling.js @@ -7,7 +7,7 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<> + * @generated SignedSource<> */ "use strict"; @@ -804,6 +804,278 @@ 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$3(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$7 = workInProgressRootRenderLanes, + nextLanes = getNextLanes( + root, + root === workInProgressRoot ? workInProgressRootRenderLanes$7 : 0 + ); + if (0 !== (nextLanes & 3)) + try { + didPerformSomeWork = !0; + workInProgressRootRenderLanes$7 = root; + if (0 !== (executionContext & 6)) + throw Error("Should not already be working."); + if (!flushPassiveEffects()) { + currentUpdateIsNested = nestedUpdateScheduled; + nestedUpdateScheduled = !1; + var exitStatus = renderRootSync( + workInProgressRootRenderLanes$7, + nextLanes + ); + if ( + 0 !== workInProgressRootRenderLanes$7.tag && + 2 === exitStatus + ) { + var originallyAttemptedLanes = nextLanes, + errorRetryLanes = getLanesToRetrySynchronouslyOnError( + workInProgressRootRenderLanes$7, + originallyAttemptedLanes + ); + 0 !== errorRetryLanes && + ((nextLanes = errorRetryLanes), + (exitStatus = recoverFromConcurrentError( + workInProgressRootRenderLanes$7, + originallyAttemptedLanes, + errorRetryLanes + ))); + } + if (1 === exitStatus) + throw ( + ((originallyAttemptedLanes = workInProgressRootFatalError), + prepareFreshStack(workInProgressRootRenderLanes$7, 0), + markRootSuspended( + workInProgressRootRenderLanes$7, + nextLanes, + 0 + ), + ensureRootIsScheduled(workInProgressRootRenderLanes$7), + originallyAttemptedLanes) + ); + 6 === exitStatus + ? markRootSuspended( + workInProgressRootRenderLanes$7, + nextLanes, + workInProgressDeferredLane + ) + : ((workInProgressRootRenderLanes$7.finishedWork = + workInProgressRootRenderLanes$7.current.alternate), + (workInProgressRootRenderLanes$7.finishedLanes = nextLanes), + commitRoot( + workInProgressRootRenderLanes$7, + workInProgressRootRecoverableErrors, + workInProgressTransitions, + workInProgressDeferredLane + )); + } + ensureRootIsScheduled(workInProgressRootRenderLanes$7); + } 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$3(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$2 = 31 - clz32(lanes), + lane = 1 << index$2, + expirationTime = expirationTimes[index$2]; + if (-1 === expirationTime) { + if (0 === (lane & suspendedLanes) || 0 !== (lane & pingedLanes)) + expirationTimes[index$2] = 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$1; + break; + case 268435456: + suspendedLanes = IdlePriority; + break; + default: + suspendedLanes = NormalPriority$1; + } + pingedLanes = performConcurrentWorkOnRoot.bind(null, root); + suspendedLanes = scheduleCallback$3(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 currentEntangledListeners = null, + currentEntangledPendingCount = 0, + currentEntangledLane = 0, + currentEntangledActionThenable = null; +function entangleAsyncAction(thenable) { + if (null === currentEntangledListeners) { + var entangledListeners = (currentEntangledListeners = []); + currentEntangledPendingCount = 0; + currentEntangledLane = requestTransitionLane(); + currentEntangledActionThenable = { + status: "pending", + value: void 0, + then: function (resolve) { + entangledListeners.push(resolve); + } + }; + } + currentEntangledPendingCount++; + thenable.then(pingEngtangledActionScope, pingEngtangledActionScope); + return thenable; +} +function pingEngtangledActionScope() { + if ( + null !== currentEntangledListeners && + 0 === --currentEntangledPendingCount + ) { + null !== currentEntangledActionThenable && + (currentEntangledActionThenable.status = "fulfilled"); + var listeners = currentEntangledListeners; + currentEntangledListeners = null; + currentEntangledLane = 0; + currentEntangledActionThenable = null; + for (var i = 0; i < listeners.length; i++) (0, listeners[i])(); + } +} +function chainThenableValue(thenable, result) { + var listeners = [], + thenableWithOverride = { + status: "pending", + value: null, + reason: null, + then: function (resolve) { + listeners.push(resolve); + } + }; + thenable.then( + function () { + thenableWithOverride.status = "fulfilled"; + thenableWithOverride.value = result; + for (var i = 0; i < listeners.length; i++) (0, listeners[i])(result); + }, + function (error) { + thenableWithOverride.status = "rejected"; + thenableWithOverride.reason = error; + for (error = 0; error < listeners.length; error++) + (0, listeners[error])(void 0); + } + ); + return thenableWithOverride; +} var hasForceUpdate = !1; function initializeUpdateQueue(fiber) { fiber.updateQueue = { @@ -899,12 +1171,20 @@ function enqueueCapturedUpdate(workInProgress, capturedUpdate) { : (workInProgress.next = capturedUpdate); queue.lastBaseUpdate = capturedUpdate; } +var didReadFromEntangledAsyncAction = !1; +function suspendIfUpdateReadFromEntangledAsyncAction() { + if (didReadFromEntangledAsyncAction) { + var entangledActionThenable = currentEntangledActionThenable; + if (null !== entangledActionThenable) throw entangledActionThenable; + } +} function processUpdateQueue( workInProgress$jscomp$0, props, instance$jscomp$0, renderLanes ) { + didReadFromEntangledAsyncAction = !1; var queue = workInProgress$jscomp$0.updateQueue; hasForceUpdate = !1; var firstBaseUpdate = queue.firstBaseUpdate, @@ -942,6 +1222,9 @@ function processUpdateQueue( ? (workInProgressRootRenderLanes & updateLane) === updateLane : (renderLanes & updateLane) === updateLane ) { + 0 !== updateLane && + updateLane === currentEntangledLane && + (didReadFromEntangledAsyncAction = !0); null !== current && (current = current.next = { @@ -1922,384 +2205,94 @@ function createChildReconciler(shouldTrackSideEffects) { 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$3(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$24 = workInProgressRootRenderLanes, - nextLanes = getNextLanes( - root, - root === workInProgressRoot ? workInProgressRootRenderLanes$24 : 0 - ); - if (0 !== (nextLanes & 3)) - try { - didPerformSomeWork = !0; - workInProgressRootRenderLanes$24 = root; - if (0 !== (executionContext & 6)) - throw Error("Should not already be working."); - if (!flushPassiveEffects()) { - currentUpdateIsNested = nestedUpdateScheduled; - nestedUpdateScheduled = !1; - var exitStatus = renderRootSync( - workInProgressRootRenderLanes$24, - nextLanes - ); - if ( - 0 !== workInProgressRootRenderLanes$24.tag && - 2 === exitStatus - ) { - var originallyAttemptedLanes = nextLanes, - errorRetryLanes = getLanesToRetrySynchronouslyOnError( - workInProgressRootRenderLanes$24, - originallyAttemptedLanes - ); - 0 !== errorRetryLanes && - ((nextLanes = errorRetryLanes), - (exitStatus = recoverFromConcurrentError( - workInProgressRootRenderLanes$24, - originallyAttemptedLanes, - errorRetryLanes - ))); - } - if (1 === exitStatus) - throw ( - ((originallyAttemptedLanes = workInProgressRootFatalError), - prepareFreshStack(workInProgressRootRenderLanes$24, 0), - markRootSuspended( - workInProgressRootRenderLanes$24, - nextLanes, - 0 - ), - ensureRootIsScheduled(workInProgressRootRenderLanes$24), - originallyAttemptedLanes) - ); - 6 === exitStatus - ? markRootSuspended( - workInProgressRootRenderLanes$24, - nextLanes, - workInProgressDeferredLane - ) - : ((workInProgressRootRenderLanes$24.finishedWork = - workInProgressRootRenderLanes$24.current.alternate), - (workInProgressRootRenderLanes$24.finishedLanes = - nextLanes), - commitRoot( - workInProgressRootRenderLanes$24, - workInProgressRootRecoverableErrors, - workInProgressTransitions, - workInProgressDeferredLane - )); - } - ensureRootIsScheduled(workInProgressRootRenderLanes$24); - } 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$3(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$2 = 31 - clz32(lanes), - lane = 1 << index$2, - expirationTime = expirationTimes[index$2]; - if (-1 === expirationTime) { - if (0 === (lane & suspendedLanes) || 0 !== (lane & pingedLanes)) - expirationTimes[index$2] = 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$1; - break; - case 268435456: - suspendedLanes = IdlePriority; - break; - default: - suspendedLanes = NormalPriority$1; + thenableIndexCounter$1 = 0; + returnFiber = reconcileChildFibersImpl( + returnFiber, + currentFirstChild, + newChild, + lanes + ); + thenableState$1 = null; + return returnFiber; } - pingedLanes = performConcurrentWorkOnRoot.bind(null, root); - suspendedLanes = scheduleCallback$3(suspendedLanes, pingedLanes); - root.callbackPriority = currentTime; - root.callbackNode = suspendedLanes; - return currentTime; + return reconcileChildFibers; } -function requestTransitionLane() { - if (0 === currentEventTransitionLane) { - var lane = nextTransitionLane; - nextTransitionLane <<= 1; - 0 === (nextTransitionLane & 4194176) && (nextTransitionLane = 128); - currentEventTransitionLane = lane; - } - return currentEventTransitionLane; +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; } -var currentEntangledListeners = null, - currentEntangledPendingCount = 0, - currentEntangledLane = 0; -function requestAsyncActionContext(actionReturnValue, overrideReturnValue) { - if (null === currentEntangledListeners) { - var entangledListeners = (currentEntangledListeners = []); - currentEntangledPendingCount = 0; - currentEntangledLane = requestTransitionLane(); - } else entangledListeners = currentEntangledListeners; - currentEntangledPendingCount++; - var resultThenable = createResultThenable(entangledListeners), - resultStatus = "pending", - resultValue, - rejectedReason; - actionReturnValue.then( - function (value) { - resultStatus = "fulfilled"; - resultValue = null !== overrideReturnValue ? overrideReturnValue : value; - pingEngtangledActionScope(); - }, - function (error) { - resultStatus = "rejected"; - rejectedReason = error; - pingEngtangledActionScope(); - } - ); - entangledListeners.push(function () { - switch (resultStatus) { - case "fulfilled": - resultThenable.status = "fulfilled"; - resultThenable.value = resultValue; - break; - case "rejected": - resultThenable.status = "rejected"; - resultThenable.reason = rejectedReason; - break; - default: - throw Error( - "Thenable should have already resolved. This is a bug in React." - ); +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); } - }); - return resultThenable; -} -function requestSyncActionContext(actionReturnValue, overrideReturnValue) { - var resultValue = - null !== overrideReturnValue ? overrideReturnValue : actionReturnValue; - if (null === currentEntangledListeners) return resultValue; - actionReturnValue = currentEntangledListeners; - var resultThenable = createResultThenable(actionReturnValue); - actionReturnValue.push(function () { - resultThenable.status = "fulfilled"; - resultThenable.value = resultValue; - }); - return resultThenable; + } else reuseSuspenseHandlerOnStack(fiber); } -function pingEngtangledActionScope() { - if ( - null !== currentEntangledListeners && - 0 === --currentEntangledPendingCount - ) { - var listeners = currentEntangledListeners; - currentEntangledListeners = null; - for (var i = (currentEntangledLane = 0); i < listeners.length; i++) - (0, listeners[i])(); - } +function reuseSuspenseHandlerOnStack() { + push(suspenseStackCursor, suspenseStackCursor.current); + push(suspenseHandlerStackCursor, suspenseHandlerStackCursor.current); } -function createResultThenable(entangledListeners) { - return { - status: "pending", - value: null, - reason: null, - then: function (resolve) { - entangledListeners.push(resolve); +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 ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher, ReactCurrentBatchConfig$2 = ReactSharedInternals.ReactCurrentBatchConfig, @@ -2557,7 +2550,8 @@ function updateReducerImpl(hook, current, reducer) { current = baseQueue.next; var newBaseQueueFirst = (baseFirst = null), newBaseQueueLast = null, - update = current; + update = current, + didReadFromEntangledAsyncAction$26 = !1; do { var updateLane = update.lane & -536870913; if ( @@ -2565,6 +2559,9 @@ function updateReducerImpl(hook, current, reducer) { ? (workInProgressRootRenderLanes & updateLane) === updateLane : (renderLanes & updateLane) === updateLane ) { + 0 !== updateLane && + updateLane === currentEntangledLane && + (didReadFromEntangledAsyncAction$26 = !0); updateLane = update.revertLane; if (0 === updateLane) null !== newBaseQueueLast && @@ -2581,7 +2578,7 @@ function updateReducerImpl(hook, current, reducer) { update = update.next; continue; } else { - var clone$27 = { + var clone$28 = { lane: 0, revertLane: update.revertLane, action: update.action, @@ -2590,9 +2587,9 @@ function updateReducerImpl(hook, current, reducer) { next: null }; null === newBaseQueueLast - ? ((newBaseQueueFirst = newBaseQueueLast = clone$27), + ? ((newBaseQueueFirst = newBaseQueueLast = clone$28), (baseFirst = pendingQueue)) - : (newBaseQueueLast = newBaseQueueLast.next = clone$27); + : (newBaseQueueLast = newBaseQueueLast.next = clone$28); currentlyRenderingFiber$1.lanes |= updateLane; workInProgressRootSkippedLanes |= updateLane; } @@ -2603,7 +2600,7 @@ function updateReducerImpl(hook, current, reducer) { ? update.eagerState : reducer(pendingQueue, updateLane); } else - (clone$27 = { + (clone$28 = { lane: updateLane, revertLane: update.revertLane, action: update.action, @@ -2612,9 +2609,9 @@ function updateReducerImpl(hook, current, reducer) { next: null }), null === newBaseQueueLast - ? ((newBaseQueueFirst = newBaseQueueLast = clone$27), + ? ((newBaseQueueFirst = newBaseQueueLast = clone$28), (baseFirst = pendingQueue)) - : (newBaseQueueLast = newBaseQueueLast.next = clone$27), + : (newBaseQueueLast = newBaseQueueLast.next = clone$28), (currentlyRenderingFiber$1.lanes |= updateLane), (workInProgressRootSkippedLanes |= updateLane); update = update.next; @@ -2622,7 +2619,13 @@ function updateReducerImpl(hook, current, reducer) { null === newBaseQueueLast ? (baseFirst = pendingQueue) : (newBaseQueueLast.next = newBaseQueueFirst); - objectIs(pendingQueue, hook.memoizedState) || (didReceiveUpdate = !0); + if ( + !objectIs(pendingQueue, hook.memoizedState) && + ((didReceiveUpdate = !0), + didReadFromEntangledAsyncAction$26 && + ((reducer = currentEntangledActionThenable), null !== reducer)) + ) + throw reducer; hook.memoizedState = pendingQueue; hook.baseState = baseFirst; hook.baseQueue = newBaseQueueLast; @@ -2766,28 +2769,23 @@ function runFormStateAction(actionQueue, setState, payload) { ReactCurrentBatchConfig$2.transition = {}; try { var returnValue = action(prevState, payload); - if ( - null !== returnValue && - "object" === typeof returnValue && - "function" === typeof returnValue.then - ) { - returnValue.then( - function (nextState) { - actionQueue.state = nextState; - finishRunningFormStateAction(actionQueue, setState); - }, - function () { - return finishRunningFormStateAction(actionQueue, setState); - } - ); - var entangledResult = requestAsyncActionContext(returnValue, null); - setState(entangledResult); - } else { - var entangledResult$29 = requestSyncActionContext(returnValue, null); - setState(entangledResult$29); - actionQueue.state = returnValue; - finishRunningFormStateAction(actionQueue, setState); - } + null !== returnValue && + "object" === typeof returnValue && + "function" === typeof returnValue.then + ? (returnValue.then( + function (nextState) { + actionQueue.state = nextState; + finishRunningFormStateAction(actionQueue, setState); + }, + function () { + return finishRunningFormStateAction(actionQueue, setState); + } + ), + entangleAsyncAction(returnValue), + setState(returnValue)) + : (setState(returnValue), + (actionQueue.state = returnValue), + finishRunningFormStateAction(actionQueue, setState)); } catch (error) { setState({ then: function () {}, status: "rejected", reason: error }), finishRunningFormStateAction(actionQueue, setState); @@ -2968,18 +2966,13 @@ function startTransition(fiber, queue, pendingState, finishedState, callback) { "object" === typeof returnValue && "function" === typeof returnValue.then ) { - var entangledResult = requestAsyncActionContext( - returnValue, - finishedState - ); - dispatchSetState(fiber, queue, entangledResult); - } else { - var entangledResult$31 = requestSyncActionContext( + entangleAsyncAction(returnValue); + var thenableForFinishedState = chainThenableValue( returnValue, finishedState ); - dispatchSetState(fiber, queue, entangledResult$31); - } + dispatchSetState(fiber, queue, thenableForFinishedState); + } else dispatchSetState(fiber, queue, finishedState); } catch (error) { dispatchSetState(fiber, queue, { then: function () {}, @@ -3642,6 +3635,7 @@ function mountClassInstance(workInProgress, ctor, newProps, renderLanes) { ctor !== instance.state && classComponentUpdater.enqueueReplaceState(instance, instance.state, null), processUpdateQueue(workInProgress, newProps, instance, renderLanes), + suspendIfUpdateReadFromEntangledAsyncAction(), (instance.state = workInProgress.memoizedState)); "function" === typeof instance.componentDidMount && (workInProgress.flags |= 4194308); @@ -3713,6 +3707,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." @@ -4028,6 +4169,7 @@ function updateClassComponent( var oldState = workInProgress.memoizedState; instance.state = oldState; processUpdateQueue(workInProgress, nextProps, instance, renderLanes); + suspendIfUpdateReadFromEntangledAsyncAction(); oldContext = workInProgress.memoizedState; oldProps !== nextProps || oldState !== oldContext || @@ -4107,6 +4249,7 @@ function updateClassComponent( oldState = workInProgress.memoizedState; instance.state = oldState; processUpdateQueue(workInProgress, nextProps, instance, renderLanes); + suspendIfUpdateReadFromEntangledAsyncAction(); var newState = workInProgress.memoizedState; oldProps !== hasNewLifecycles || oldState !== newState || @@ -5054,14 +5197,14 @@ function cutOffTailIfNeeded(renderState, hasRenderedATailFallback) { break; case "collapsed": lastTailNode = renderState.tail; - for (var lastTailNode$64 = null; null !== lastTailNode; ) - null !== lastTailNode.alternate && (lastTailNode$64 = lastTailNode), + for (var lastTailNode$63 = null; null !== lastTailNode; ) + null !== lastTailNode.alternate && (lastTailNode$63 = lastTailNode), (lastTailNode = lastTailNode.sibling); - null === lastTailNode$64 + null === lastTailNode$63 ? hasRenderedATailFallback || null === renderState.tail ? (renderState.tail = null) : (renderState.tail.sibling = null) - : (lastTailNode$64.sibling = null); + : (lastTailNode$63.sibling = null); } } function bubbleProperties(completedWork) { @@ -5073,53 +5216,53 @@ function bubbleProperties(completedWork) { if (didBailout) if (0 !== (completedWork.mode & 2)) { for ( - var treeBaseDuration$66 = completedWork.selfBaseDuration, - child$67 = completedWork.child; - null !== child$67; + var treeBaseDuration$65 = completedWork.selfBaseDuration, + child$66 = completedWork.child; + null !== child$66; ) - (newChildLanes |= child$67.lanes | child$67.childLanes), - (subtreeFlags |= child$67.subtreeFlags & 31457280), - (subtreeFlags |= child$67.flags & 31457280), - (treeBaseDuration$66 += child$67.treeBaseDuration), - (child$67 = child$67.sibling); - completedWork.treeBaseDuration = treeBaseDuration$66; + (newChildLanes |= child$66.lanes | child$66.childLanes), + (subtreeFlags |= child$66.subtreeFlags & 31457280), + (subtreeFlags |= child$66.flags & 31457280), + (treeBaseDuration$65 += child$66.treeBaseDuration), + (child$66 = child$66.sibling); + completedWork.treeBaseDuration = treeBaseDuration$65; } else for ( - treeBaseDuration$66 = completedWork.child; - null !== treeBaseDuration$66; + treeBaseDuration$65 = completedWork.child; + null !== treeBaseDuration$65; ) (newChildLanes |= - treeBaseDuration$66.lanes | treeBaseDuration$66.childLanes), - (subtreeFlags |= treeBaseDuration$66.subtreeFlags & 31457280), - (subtreeFlags |= treeBaseDuration$66.flags & 31457280), - (treeBaseDuration$66.return = completedWork), - (treeBaseDuration$66 = treeBaseDuration$66.sibling); + treeBaseDuration$65.lanes | treeBaseDuration$65.childLanes), + (subtreeFlags |= treeBaseDuration$65.subtreeFlags & 31457280), + (subtreeFlags |= treeBaseDuration$65.flags & 31457280), + (treeBaseDuration$65.return = completedWork), + (treeBaseDuration$65 = treeBaseDuration$65.sibling); else if (0 !== (completedWork.mode & 2)) { - treeBaseDuration$66 = completedWork.actualDuration; - child$67 = completedWork.selfBaseDuration; + treeBaseDuration$65 = completedWork.actualDuration; + child$66 = completedWork.selfBaseDuration; for (var child = completedWork.child; null !== child; ) (newChildLanes |= child.lanes | child.childLanes), (subtreeFlags |= child.subtreeFlags), (subtreeFlags |= child.flags), - (treeBaseDuration$66 += child.actualDuration), - (child$67 += child.treeBaseDuration), + (treeBaseDuration$65 += child.actualDuration), + (child$66 += child.treeBaseDuration), (child = child.sibling); - completedWork.actualDuration = treeBaseDuration$66; - completedWork.treeBaseDuration = child$67; + completedWork.actualDuration = treeBaseDuration$65; + completedWork.treeBaseDuration = child$66; } else for ( - treeBaseDuration$66 = completedWork.child; - null !== treeBaseDuration$66; + treeBaseDuration$65 = completedWork.child; + null !== treeBaseDuration$65; ) (newChildLanes |= - treeBaseDuration$66.lanes | treeBaseDuration$66.childLanes), - (subtreeFlags |= treeBaseDuration$66.subtreeFlags), - (subtreeFlags |= treeBaseDuration$66.flags), - (treeBaseDuration$66.return = completedWork), - (treeBaseDuration$66 = treeBaseDuration$66.sibling); + treeBaseDuration$65.lanes | treeBaseDuration$65.childLanes), + (subtreeFlags |= treeBaseDuration$65.subtreeFlags), + (subtreeFlags |= treeBaseDuration$65.flags), + (treeBaseDuration$65.return = completedWork), + (treeBaseDuration$65 = treeBaseDuration$65.sibling); completedWork.subtreeFlags |= subtreeFlags; completedWork.childLanes = newChildLanes; return didBailout; @@ -5290,11 +5433,11 @@ function completeWork(current, workInProgress, renderLanes) { null !== newProps.alternate.memoizedState && null !== newProps.alternate.memoizedState.cachePool && (index = newProps.alternate.memoizedState.cachePool.pool); - var cache$74 = null; + var cache$73 = null; null !== newProps.memoizedState && null !== newProps.memoizedState.cachePool && - (cache$74 = newProps.memoizedState.cachePool.pool); - cache$74 !== index && (newProps.flags |= 2048); + (cache$73 = newProps.memoizedState.cachePool.pool); + cache$73 !== index && (newProps.flags |= 2048); } renderLanes !== current && renderLanes && @@ -5326,8 +5469,8 @@ function completeWork(current, workInProgress, renderLanes) { index = workInProgress.memoizedState; if (null === index) return bubbleProperties(workInProgress), null; newProps = 0 !== (workInProgress.flags & 128); - cache$74 = index.rendering; - if (null === cache$74) + cache$73 = index.rendering; + if (null === cache$73) if (newProps) cutOffTailIfNeeded(index, !1); else { if ( @@ -5335,11 +5478,11 @@ function completeWork(current, workInProgress, renderLanes) { (null !== current && 0 !== (current.flags & 128)) ) for (current = workInProgress.child; null !== current; ) { - cache$74 = findFirstSuspended(current); - if (null !== cache$74) { + cache$73 = findFirstSuspended(current); + if (null !== cache$73) { workInProgress.flags |= 128; cutOffTailIfNeeded(index, !1); - current = cache$74.updateQueue; + current = cache$73.updateQueue; workInProgress.updateQueue = current; scheduleRetryEffect(workInProgress, current); workInProgress.subtreeFlags = 0; @@ -5364,7 +5507,7 @@ function completeWork(current, workInProgress, renderLanes) { } else { if (!newProps) - if (((current = findFirstSuspended(cache$74)), null !== current)) { + if (((current = findFirstSuspended(cache$73)), null !== current)) { if ( ((workInProgress.flags |= 128), (newProps = !0), @@ -5374,7 +5517,7 @@ function completeWork(current, workInProgress, renderLanes) { cutOffTailIfNeeded(index, !0), null === index.tail && "hidden" === index.tailMode && - !cache$74.alternate) + !cache$73.alternate) ) return bubbleProperties(workInProgress), null; } else @@ -5386,13 +5529,13 @@ function completeWork(current, workInProgress, renderLanes) { cutOffTailIfNeeded(index, !1), (workInProgress.lanes = 4194304)); index.isBackwards - ? ((cache$74.sibling = workInProgress.child), - (workInProgress.child = cache$74)) + ? ((cache$73.sibling = workInProgress.child), + (workInProgress.child = cache$73)) : ((current = index.last), null !== current - ? (current.sibling = cache$74) - : (workInProgress.child = cache$74), - (index.last = cache$74)); + ? (current.sibling = cache$73) + : (workInProgress.child = cache$73), + (index.last = cache$73)); } if (null !== index.tail) return ( @@ -5646,8 +5789,8 @@ function safelyDetachRef(current, nearestMountedAncestor) { recordLayoutEffectDuration(current); } else ref(null); - } catch (error$90) { - captureCommitPhaseError(current, nearestMountedAncestor, error$90); + } catch (error$89) { + captureCommitPhaseError(current, nearestMountedAncestor, error$89); } else ref.current = null; } @@ -5753,10 +5896,10 @@ function commitHookEffectListMount(flags, finishedWork) { var effect = (finishedWork = finishedWork.next); do { if ((effect.tag & flags) === flags) { - var create$91 = effect.create, + var create$90 = effect.create, inst = effect.inst; - create$91 = create$91(); - inst.destroy = create$91; + create$90 = create$90(); + inst.destroy = create$90; } effect = effect.next; } while (effect !== finishedWork); @@ -5774,8 +5917,8 @@ function commitHookLayoutEffects(finishedWork, hookFlags) { } else try { commitHookEffectListMount(hookFlags, finishedWork); - } catch (error$93) { - captureCommitPhaseError(finishedWork, finishedWork.return, error$93); + } catch (error$92) { + captureCommitPhaseError(finishedWork, finishedWork.return, error$92); } } function commitClassCallbacks(finishedWork) { @@ -5855,11 +5998,11 @@ function commitLayoutEffectOnFiber(finishedRoot, current, finishedWork) { } else try { finishedRoot.componentDidMount(); - } catch (error$94) { + } catch (error$93) { captureCommitPhaseError( finishedWork, finishedWork.return, - error$94 + error$93 ); } else { @@ -5876,11 +6019,11 @@ function commitLayoutEffectOnFiber(finishedRoot, current, finishedWork) { current, finishedRoot.__reactInternalSnapshotBeforeUpdate ); - } catch (error$95) { + } catch (error$94) { captureCommitPhaseError( finishedWork, finishedWork.return, - error$95 + error$94 ); } recordLayoutEffectDuration(finishedWork); @@ -5891,11 +6034,11 @@ function commitLayoutEffectOnFiber(finishedRoot, current, finishedWork) { current, finishedRoot.__reactInternalSnapshotBeforeUpdate ); - } catch (error$96) { + } catch (error$95) { captureCommitPhaseError( finishedWork, finishedWork.return, - error$96 + error$95 ); } } @@ -6282,22 +6425,22 @@ function commitMutationEffectsOnFiber(finishedWork, root) { try { startLayoutEffectTimer(), commitHookEffectListUnmount(5, finishedWork, finishedWork.return); - } catch (error$105) { + } catch (error$104) { captureCommitPhaseError( finishedWork, finishedWork.return, - error$105 + error$104 ); } recordLayoutEffectDuration(finishedWork); } else try { commitHookEffectListUnmount(5, finishedWork, finishedWork.return); - } catch (error$106) { + } catch (error$105) { captureCommitPhaseError( finishedWork, finishedWork.return, - error$106 + error$105 ); } } @@ -6336,8 +6479,8 @@ function commitMutationEffectsOnFiber(finishedWork, root) { finishedWork.updateQueue = null; try { (flags.type = type), (flags.props = existingHiddenCallbacks); - } catch (error$109) { - captureCommitPhaseError(finishedWork, finishedWork.return, error$109); + } catch (error$108) { + captureCommitPhaseError(finishedWork, finishedWork.return, error$108); } } break; @@ -6353,8 +6496,8 @@ function commitMutationEffectsOnFiber(finishedWork, root) { existingHiddenCallbacks = finishedWork.memoizedProps; try { flags.text = existingHiddenCallbacks; - } catch (error$110) { - captureCommitPhaseError(finishedWork, finishedWork.return, error$110); + } catch (error$109) { + captureCommitPhaseError(finishedWork, finishedWork.return, error$109); } } break; @@ -6438,11 +6581,11 @@ function commitMutationEffectsOnFiber(finishedWork, root) { wasHidden.stateNode.isHidden = existingHiddenCallbacks ? !0 : !1; - } catch (error$99) { + } catch (error$98) { captureCommitPhaseError( finishedWork, finishedWork.return, - error$99 + error$98 ); } } else if ( @@ -6520,12 +6663,12 @@ function commitReconciliationEffects(finishedWork) { break; case 3: case 4: - var parent$100 = JSCompiler_inline_result.stateNode.containerInfo, - before$101 = getHostSibling(finishedWork); + var parent$99 = JSCompiler_inline_result.stateNode.containerInfo, + before$100 = getHostSibling(finishedWork); insertOrAppendPlacementNodeIntoContainer( finishedWork, - before$101, - parent$100 + before$100, + parent$99 ); break; default: @@ -6705,8 +6848,8 @@ function commitHookPassiveMountEffects(finishedWork, hookFlags) { } else try { commitHookEffectListMount(hookFlags, finishedWork); - } catch (error$114) { - captureCommitPhaseError(finishedWork, finishedWork.return, error$114); + } catch (error$113) { + captureCommitPhaseError(finishedWork, finishedWork.return, error$113); } } function commitOffscreenPassiveMountEffects(current, finishedWork) { @@ -7634,13 +7777,13 @@ function renderRootSync(root, lanes) { default: (workInProgressSuspendedReason = 0), (workInProgressThrownValue = null), - throwAndUnwindWorkLoop(unitOfWork, thrownValue); + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); } } workLoopSync(); break; - } catch (thrownValue$119) { - handleThrow(root, thrownValue$119); + } catch (thrownValue$118) { + handleThrow(root, thrownValue$118); } while (1); lanes && root.shellSuspendCounter++; @@ -7678,7 +7821,7 @@ function renderRootConcurrent(root, lanes) { case 1: workInProgressSuspendedReason = 0; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(lanes, thrownValue); + throwAndUnwindWorkLoop(root, lanes, thrownValue); break; case 2: if (isThenableResolved(thrownValue)) { @@ -7708,7 +7851,7 @@ function renderRootConcurrent(root, lanes) { replaySuspendedUnitOfWork(lanes)) : ((workInProgressSuspendedReason = 0), (workInProgressThrownValue = null), - throwAndUnwindWorkLoop(lanes, thrownValue)); + throwAndUnwindWorkLoop(root, lanes, thrownValue)); break; case 5: switch (workInProgress.tag) { @@ -7731,12 +7874,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(); @@ -7748,8 +7891,8 @@ function renderRootConcurrent(root, lanes) { } workLoopConcurrent(); break; - } catch (thrownValue$121) { - handleThrow(root, thrownValue$121); + } catch (thrownValue$120) { + handleThrow(root, thrownValue$120); } while (1); resetContextDependencies(); @@ -7838,199 +7981,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; - 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; @@ -8223,11 +8230,11 @@ function flushPassiveEffects() { _finishedWork$memoize = finishedWork.memoizedProps, id = _finishedWork$memoize.id, onPostCommit = _finishedWork$memoize.onPostCommit, - commitTime$92 = commitTime, + commitTime$91 = commitTime, phase = null === finishedWork.alternate ? "mount" : "update"; currentUpdateIsNested && (phase = "nested-update"); "function" === typeof onPostCommit && - onPostCommit(id, phase, passiveEffectDuration, commitTime$92); + onPostCommit(id, phase, passiveEffectDuration, commitTime$91); var parentFiber = finishedWork.return; b: for (; null !== parentFiber; ) { switch (parentFiber.tag) { @@ -8571,6 +8578,7 @@ beginWork = function (current, workInProgress, renderLanes) { pushProvider(workInProgress, CacheContext, nextCache); nextCache !== context.cache && propagateContextChange(workInProgress, CacheContext, renderLanes); + suspendIfUpdateReadFromEntangledAsyncAction(); context = hasContext.element; context === Component ? (workInProgress = bailoutOnAlreadyFinishedWork( @@ -8792,7 +8800,8 @@ beginWork = function (current, workInProgress, renderLanes) { pushProvider(workInProgress, CacheContext, context)) : (0 !== (current.lanes & renderLanes) && (cloneUpdateQueue(current, workInProgress), - processUpdateQueue(workInProgress, null, null, renderLanes)), + processUpdateQueue(workInProgress, null, null, renderLanes), + suspendIfUpdateReadFromEntangledAsyncAction()), (context = current.memoizedState), (hasContext = workInProgress.memoizedState), context.parent !== Component @@ -9545,19 +9554,19 @@ function wrapFiber(fiber) { fiberToWrapper.set(fiber, wrapper)); return wrapper; } -var devToolsConfig$jscomp$inline_1079 = { +var devToolsConfig$jscomp$inline_1073 = { findFiberByHostInstance: function () { throw Error("TestRenderer does not support findFiberByHostInstance()"); }, bundleType: 0, - version: "18.3.0-canary-2efb14260-20240124", + version: "18.3.0-canary-11c9fd0c5-20240124", rendererPackageName: "react-test-renderer" }; -var internals$jscomp$inline_1271 = { - bundleType: devToolsConfig$jscomp$inline_1079.bundleType, - version: devToolsConfig$jscomp$inline_1079.version, - rendererPackageName: devToolsConfig$jscomp$inline_1079.rendererPackageName, - rendererConfig: devToolsConfig$jscomp$inline_1079.rendererConfig, +var internals$jscomp$inline_1248 = { + bundleType: devToolsConfig$jscomp$inline_1073.bundleType, + version: devToolsConfig$jscomp$inline_1073.version, + rendererPackageName: devToolsConfig$jscomp$inline_1073.rendererPackageName, + rendererConfig: devToolsConfig$jscomp$inline_1073.rendererConfig, overrideHookState: null, overrideHookStateDeletePath: null, overrideHookStateRenamePath: null, @@ -9574,26 +9583,26 @@ var internals$jscomp$inline_1271 = { return null === fiber ? null : fiber.stateNode; }, findFiberByHostInstance: - devToolsConfig$jscomp$inline_1079.findFiberByHostInstance || + devToolsConfig$jscomp$inline_1073.findFiberByHostInstance || emptyFindFiberByHostInstance, findHostInstancesForRefresh: null, scheduleRefresh: null, scheduleRoot: null, setRefreshHandler: null, getCurrentFiber: null, - reconcilerVersion: "18.3.0-canary-2efb14260-20240124" + reconcilerVersion: "18.3.0-canary-11c9fd0c5-20240124" }; if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) { - var hook$jscomp$inline_1272 = __REACT_DEVTOOLS_GLOBAL_HOOK__; + var hook$jscomp$inline_1249 = __REACT_DEVTOOLS_GLOBAL_HOOK__; if ( - !hook$jscomp$inline_1272.isDisabled && - hook$jscomp$inline_1272.supportsFiber + !hook$jscomp$inline_1249.isDisabled && + hook$jscomp$inline_1249.supportsFiber ) try { - (rendererID = hook$jscomp$inline_1272.inject( - internals$jscomp$inline_1271 + (rendererID = hook$jscomp$inline_1249.inject( + internals$jscomp$inline_1248 )), - (injectedHook = hook$jscomp$inline_1272); + (injectedHook = hook$jscomp$inline_1249); } catch (err) {} } exports._Scheduler = Scheduler; diff --git a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-dev.js b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-dev.js index b52f346cc19db..651aa2f7efd68 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-dev.js +++ b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-dev.js @@ -24,7 +24,7 @@ if (__DEV__) { ) { __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error()); } - var ReactVersion = "18.3.0-canary-2efb14260-20240124"; + var ReactVersion = "18.3.0-canary-11c9fd0c5-20240124"; // ATTENTION // When adding new symbols to this file, diff --git a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-prod.js b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-prod.js index 74cad9e105353..dd73f635a8f6a 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-prod.js +++ b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-prod.js @@ -539,4 +539,4 @@ exports.useSyncExternalStore = function ( exports.useTransition = function () { return ReactCurrentDispatcher.current.useTransition(); }; -exports.version = "18.3.0-canary-2efb14260-20240124"; +exports.version = "18.3.0-canary-11c9fd0c5-20240124"; diff --git a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-profiling.js b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-profiling.js index e26e2d5a7a1fc..ddbc237f7aeb0 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-profiling.js +++ b/compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-profiling.js @@ -535,7 +535,7 @@ exports.useSyncExternalStore = function ( exports.useTransition = function () { return ReactCurrentDispatcher.current.useTransition(); }; -exports.version = "18.3.0-canary-2efb14260-20240124"; +exports.version = "18.3.0-canary-11c9fd0c5-20240124"; "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && diff --git a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/REVISION b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/REVISION index ec305d21b4333..60b652c8dec48 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/REVISION +++ b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/REVISION @@ -1 +1 @@ -2efb1426067322cdb08304432b3ac849dee52bd9 +11c9fd0c53133f24f5270d36591b65b8fc2ebd25 diff --git a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-dev.fb.js b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-dev.fb.js index 59ece46dca009..c2dd4dd531c6b 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-dev.fb.js +++ b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-dev.fb.js @@ -7,7 +7,7 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<<3bbc5516aa8fca4c50bd6b2679dc8923>> + * @generated SignedSource<<98889e37108bba6b8b4772891a2513c5>> */ "use strict"; @@ -6846,3738 +6846,3730 @@ 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 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 hasForceUpdate = false; - var didWarnUpdateInsideUpdate; - var currentlyProcessingQueue; + var firstScheduledRoot = null; + var lastScheduledRoot = null; // Used to prevent redundant mircotasks from being scheduled. - { - didWarnUpdateInsideUpdate = false; - currentlyProcessingQueue = null; - } + 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. - 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; + var didScheduleMicrotask_act = false; // Used to quickly bail out of flushSync if there's no sync work to do. - if (queue === currentQueue) { - var clone = { - baseState: currentQueue.baseState, - firstBaseUpdate: currentQueue.firstBaseUpdate, - lastBaseUpdate: currentQueue.lastBaseUpdate, - shared: currentQueue.shared, - callbacks: null - }; - workInProgress.updateQueue = clone; + var mightHavePendingSyncWork = false; + var isFlushingWork = false; + var currentEventTransitionLane = NoLane; + function ensureRootIsScheduled(root) { + // This function is called whenever a root receives an update. It does two + // things 1) it ensures the root is in the root schedule, and 2) it ensures + // there's a pending microtask to process the root schedule. + // + // Most of the actual scheduling logic does not happen until + // `scheduleTaskForRootDuringMicrotask` runs. + // Add the root to the schedule + if (root === lastScheduledRoot || root.next !== null); + else { + if (lastScheduledRoot === null) { + firstScheduledRoot = lastScheduledRoot = root; + } else { + lastScheduledRoot.next = root; + lastScheduledRoot = root; + } + } // Any time a root received an update, we set this to true until the next time + // we process the schedule. If it's false, then we can quickly exit flushSync + // without consulting the schedule. + + mightHavePendingSyncWork = true; // At the end of the current event, go through each of the roots and ensure + // there's a task scheduled for each one at the correct priority. + + if (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); + } + } + + if (!enableDeferRootSchedulingToMicrotask) { + // While this flag is disabled, we schedule the render task immediately + // instead of waiting a microtask. + // TODO: We need to land enableDeferRootSchedulingToMicrotask ASAP to + // unblock additional features we have planned. + scheduleTaskForRootDuringMicrotask(root, now$1()); + } + + if (ReactCurrentActQueue$3.isBatchingLegacy && root.tag === LegacyRoot) { + // Special `act` case: Record whenever a legacy update is scheduled. + ReactCurrentActQueue$3.didScheduleLegacyUpdate = true; } } - function createUpdate(lane) { - var update = { - lane: lane, - tag: UpdateState, - payload: null, - callback: null, - next: null - }; - return update; + 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 enqueueUpdate(fiber, update, lane) { - var updateQueue = fiber.updateQueue; - if (updateQueue === null) { - // Only occurs if the fiber has been unmounted. - return null; + 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 ( - currentlyProcessingQueue === sharedQueue && - !didWarnUpdateInsideUpdate - ) { - var componentName = getComponentNameFromFiber(fiber); + var didPerformSomeWork; + var errors = null; + isFlushingWork = true; - error( - "An update (setState, replaceState, or forceUpdate) was scheduled " + - "from inside an update function. Update functions should be pure, " + - "with zero side-effects. Consider using componentDidUpdate or a " + - "callback.\n\nPlease update the following component: %s", - componentName - ); + do { + didPerformSomeWork = false; + var root = firstScheduledRoot; - didWarnUpdateInsideUpdate = true; - } - } + while (root !== null) { + if (onlyLegacy && root.tag !== LegacyRoot); + else { + var workInProgressRoot = getWorkInProgressRoot(); + var workInProgressRootRenderLanes = + getWorkInProgressRootRenderLanes(); + var nextLanes = getNextLanes( + root, + root === workInProgressRoot + ? workInProgressRootRenderLanes + : NoLanes + ); - if (isUnsafeClassRenderPhaseUpdate()) { - // This is an unsafe render phase update. Add directly to the update - // queue so we can process it immediately during the current render. - var pending = sharedQueue.pending; + if (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); + } + } + } + } - if (pending === null) { - // This is the first update. Create a circular list. - update.next = update; - } else { - update.next = pending.next; - pending.next = update; + root = root.next; } + } while (didPerformSomeWork); - 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). + 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. - return unsafe_markUpdateLaneFromFiberToRoot(fiber, lane); - } else { - return enqueueConcurrentClassUpdate(fiber, sharedQueue, update, lane); + 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])); + } + + var firstError = errors[0]; + throw firstError; + } + } else { + var error = errors[0]; + throw error; + } } } - function entangleTransitions(root, fiber, lane) { - var updateQueue = fiber.updateQueue; - if (updateQueue === null) { - // Only occurs if the fiber has been unmounted. - return; - } + function throwError(error) { + throw error; + } - var sharedQueue = updateQueue.shared; + function processRootScheduleInMicrotask() { + // This function is always called inside a microtask. It should never be + // called synchronously. + didScheduleMicrotask = false; - 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. + { + didScheduleMicrotask_act = false; + } // We'll recompute this as we iterate through all the roots and schedule them. - queueLanes = intersectLanes(queueLanes, root.pendingLanes); // Entangle the new transition lane with the other transition lanes. + mightHavePendingSyncWork = false; + var currentTime = now$1(); + var prev = null; + 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) { + var next = root.next; - markRootEntangled(root, newQueueLanes); - } - } - function enqueueCapturedUpdate(workInProgress, capturedUpdate) { - // Captured updates are updates that are thrown by a child during the render - // phase. They should be discarded if the render is aborted. Therefore, - // we should only put them on the work-in-progress queue, not the current one. - var queue = workInProgress.updateQueue; // Check if the work-in-progress queue is a clone. - - var current = workInProgress.alternate; - - if (current !== null) { - var currentQueue = current.updateQueue; - - if (queue === currentQueue) { - // The work-in-progress queue is the same as current. This happens when - // we bail out on a parent fiber that then captures an error thrown by - // a child. Since we want to append the update only to the work-in - // -progress queue, we need to clone the updates. We usually clone during - // processUpdateQueue, but that didn't happen in this case because we - // skipped over the parent when we bailed out. - var newFirst = null; - var newLast = null; - var firstBaseUpdate = queue.firstBaseUpdate; - - if (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 ( + 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 (newLast === null) { - newFirst = newLast = clone; - } else { - newLast.next = clone; - newLast = clone; - } // $FlowFixMe[incompatible-type] we bail out when we get a null + var nextLanes = scheduleTaskForRootDuringMicrotask(root, currentTime); - update = update.next; - } while (update !== null); // Append the captured update the end of the cloned list. + if (nextLanes === NoLane) { + // This root has no more pending work. Remove it from the schedule. To + // guard against subtle reentrancy bugs, this microtask is the only place + // we do this — you can add roots to the schedule whenever, but you can + // only remove them here. + // Null this out so we know it's been removed from the schedule. + root.next = null; - if (newLast === null) { - newFirst = newLast = capturedUpdate; - } else { - newLast.next = capturedUpdate; - newLast = capturedUpdate; - } + if (prev === null) { + // This is the new head of the list + firstScheduledRoot = next; } else { - // There are no base updates. - newFirst = newLast = capturedUpdate; + prev.next = next; } - queue = { - baseState: currentQueue.baseState, - firstBaseUpdate: newFirst, - lastBaseUpdate: newLast, - shared: currentQueue.shared, - callbacks: currentQueue.callbacks - }; - workInProgress.updateQueue = queue; - return; - } - } // Append the update to the end of the list. + if (next === null) { + // This is the new tail of the list + lastScheduledRoot = prev; + } + } else { + // This root still has work. Keep it in the list. + prev = root; - var lastBaseUpdate = queue.lastBaseUpdate; + if (includesSyncLane(nextLanes)) { + mightHavePendingSyncWork = true; + } + } - if (lastBaseUpdate === null) { - queue.firstBaseUpdate = capturedUpdate; - } else { - lastBaseUpdate.next = capturedUpdate; + root = next; } - 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(); - } - - var nextState = payload.call(instance, prevState, nextProps); - - { - if (workInProgress.mode & StrictLegacyMode) { - setIsStrictModeForDevtools(true); + currentEventTransitionLane = NoLane; // At the end of the microtask, flush any pending synchronous work. This has + // to come at the end, because it does actual rendering work that might throw. - try { - payload.call(instance, prevState, nextProps); - } finally { - setIsStrictModeForDevtools(false); - } - } + flushSyncWorkOnAllRoots(); + } - exitDisallowedContextReadInDEV(); - } + 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. - return nextState; - } // State object + var workInProgressRoot = getWorkInProgressRoot(); + var workInProgressRootRenderLanes = getWorkInProgressRootRenderLanes(); + var nextLanes = getNextLanes( + root, + root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes + ); + var existingCallbackNode = root.callbackNode; - return payload; + 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); } - case CaptureUpdate: { - workInProgress.flags = - (workInProgress.flags & ~ShouldCapture) | DidCapture; + 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); } - // Intentional fallthrough - case UpdateState: { - var _payload = update.payload; - var partialState; + root.callbackPriority = SyncLane; + root.callbackNode = null; + return SyncLane; + } else { + // We use the highest priority lane to represent the priority of the callback. + var existingCallbackPriority = root.callbackPriority; + var newCallbackPriority = getHighestPriorityLane(nextLanes); - if (typeof _payload === "function") { - // Updater function - { - enterDisallowedContextReadInDEV(); - } + 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); + } - partialState = _payload.call(instance, prevState, nextProps); + var schedulerPriorityLevel; - { - if (workInProgress.mode & StrictLegacyMode) { - setIsStrictModeForDevtools(true); + switch (lanesToEventPriority(nextLanes)) { + case DiscreteEventPriority: + schedulerPriorityLevel = ImmediatePriority; + break; - try { - _payload.call(instance, prevState, nextProps); - } finally { - setIsStrictModeForDevtools(false); - } - } + case ContinuousEventPriority: + schedulerPriorityLevel = UserBlockingPriority; + break; - exitDisallowedContextReadInDEV(); - } - } else { - // Partial state object - partialState = _payload; - } + case DefaultEventPriority: + schedulerPriorityLevel = NormalPriority; + break; - if (partialState === null || partialState === undefined) { - // Null and undefined are treated as no-ops. - return prevState; - } // Merge the partial state and the previous state. + case IdleEventPriority: + schedulerPriorityLevel = IdlePriority; + break; - return assign({}, prevState, partialState); + default: + schedulerPriorityLevel = NormalPriority; + break; } - case ForceUpdate: { - hasForceUpdate = true; - return prevState; - } + var newCallbackNode = scheduleCallback$1( + schedulerPriorityLevel, + performConcurrentWorkOnRoot.bind(null, root) + ); + root.callbackPriority = newCallbackPriority; + root.callbackNode = newCallbackNode; + return newCallbackPriority; } - - return prevState; } - function processUpdateQueue(workInProgress, props, instance, renderLanes) { - // This is always non-null on a ClassComponent or HostRoot - var queue = workInProgress.updateQueue; - hasForceUpdate = false; + 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()); - { - currentlyProcessingQueue = queue.shared; + 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 firstBaseUpdate = queue.firstBaseUpdate; - var lastBaseUpdate = queue.lastBaseUpdate; // Check if there are pending updates. If so, transfer them to the base queue. + return null; + } + var fakeActCallbackNode$1 = {}; - var pendingQueue = queue.shared.pending; + 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); + } + } - 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 cancelCallback(callbackNode) { + if (callbackNode === fakeActCallbackNode$1); + else if (callbackNode !== null) { + cancelCallback$1(callbackNode); + } + } - var lastPendingUpdate = pendingQueue; - var firstPendingUpdate = lastPendingUpdate.next; - lastPendingUpdate.next = null; // Append pending updates to base queue + 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 (lastBaseUpdate === null) { - firstBaseUpdate = firstPendingUpdate; - } else { - lastBaseUpdate.next = firstPendingUpdate; - } + if (supportsMicrotasks) { + scheduleMicrotask(function () { + // In Safari, appending an iframe forces microtasks to run. + // https://github.com/facebook/react/issues/22459 + // We don't support running callbacks in the middle of render + // or commit so we need to check against that. + var executionContext = getExecutionContext(); - lastBaseUpdate = lastPendingUpdate; // If there's a current queue, and it's different from the base queue, then - // we need to transfer the updates to that queue, too. Because the base - // queue is a singly-linked list with no cycles, we can append to both - // lists and take advantage of structural sharing. - // TODO: Pass `current` as argument + if ( + (executionContext & (RenderContext | CommitContext)) !== + NoContext + ) { + // Note that this would still prematurely flush the callbacks + // if this happens outside render or commit phase (e.g. in an event). + // Intentionally using a macrotask instead of a microtask here. This is + // wrong semantically but it prevents an infinite loop. The bug is + // Safari's, not ours, so we just do our best to not crash even though + // the behavior isn't completely correct. + scheduleCallback$2(ImmediatePriority, cb); + return; + } - var current = workInProgress.alternate; + cb(); + }); + } else { + // If microtasks are not supported, use Scheduler. + scheduleCallback$2(ImmediatePriority, cb); + } + } - if (current !== null) { - // This is always non-null on a ClassComponent or HostRoot - var currentQueue = current.updateQueue; - var currentLastBaseUpdate = currentQueue.lastBaseUpdate; + 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 (currentLastBaseUpdate !== lastBaseUpdate) { - if (currentLastBaseUpdate === null) { - currentQueue.firstBaseUpdate = firstPendingUpdate; - } else { - currentLastBaseUpdate.next = firstPendingUpdate; - } + return currentEventTransitionLane; + } - currentQueue.lastBaseUpdate = lastPendingUpdate; - } - } - } // These values may change as we process the queue. + // 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. - 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 currentEntangledListeners = null; // The number of pending async actions in the entangled scope. - var newLanes = NoLanes; - var newBaseState = null; - var newFirstBaseUpdate = null; - var newLastBaseUpdate = null; - var update = firstBaseUpdate; + var currentEntangledPendingCount = 0; // The transition lane shared by all updates in the entangled scope. - 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 currentEntangledLane = NoLane; // A thenable that resolves when the entangled scope completes. It does not + // resolve to a particular value because it's only used for suspending the UI + // until the async action scope has completed. - var shouldSkipUpdate = isHiddenUpdate - ? !isSubsetOfLanes(getWorkInProgressRootRenderLanes(), updateLane) - : !isSubsetOfLanes(renderLanes, updateLane); + var currentEntangledActionThenable = null; + function entangleAsyncAction(thenable) { + // `thenable` is the return value of the async action scope function. Create + // a combined thenable that resolves once every entangled scope function + // has finished. + if (currentEntangledListeners === null) { + // There's no outer async action scope. Create a new one. + var entangledListeners = (currentEntangledListeners = []); + currentEntangledPendingCount = 0; + currentEntangledLane = requestTransitionLane(); + var entangledThenable = { + status: "pending", + value: undefined, + then: function (resolve) { + entangledListeners.push(resolve); + } + }; + currentEntangledActionThenable = entangledThenable; + } - 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 - }; + currentEntangledPendingCount++; + thenable.then(pingEngtangledActionScope, pingEngtangledActionScope); + return thenable; + } - if (newLastBaseUpdate === null) { - newFirstBaseUpdate = newLastBaseUpdate = clone; - newBaseState = newState; - } else { - newLastBaseUpdate = newLastBaseUpdate.next = clone; - } // Update the remaining priority in the queue. + function pingEngtangledActionScope() { + if ( + currentEntangledListeners !== null && + --currentEntangledPendingCount === 0 + ) { + // All the actions have finished. Close the entangled async action scope + // and notify all the listeners. + if (currentEntangledActionThenable !== null) { + var fulfilledThenable = currentEntangledActionThenable; + fulfilledThenable.status = "fulfilled"; + } - 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. + var listeners = currentEntangledListeners; + currentEntangledListeners = null; + currentEntangledLane = NoLane; + currentEntangledActionThenable = null; - newState = getStateFromUpdate( - workInProgress, - queue, - update, - newState, - props, - instance - ); - var callback = update.callback; + for (var i = 0; i < listeners.length; i++) { + var listener = listeners[i]; + listener(); + } + } + } - if (callback !== null) { - workInProgress.flags |= Callback; + 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 (isHiddenUpdate) { - workInProgress.flags |= Visibility; - } + 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; - var callbacks = queue.callbacks; + 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 (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; - } + listener(undefined); } - } while (true); - - if (newLastBaseUpdate === null) { - newBaseState = newState; } + ); + return thenableWithOverride; + } + function peekEntangledActionLane() { + return currentEntangledLane; + } + function peekEntangledActionThenable() { + return currentEntangledActionThenable; + } - queue.baseState = newBaseState; - queue.firstBaseUpdate = newFirstBaseUpdate; - queue.lastBaseUpdate = newLastBaseUpdate; + var UpdateState = 0; + var ReplaceState = 1; + var ForceUpdate = 2; + var CaptureUpdate = 3; // Global state that is reset at the beginning of calling `processUpdateQueue`. + // It should only be read right after calling `processUpdateQueue`, via + // `checkHasForceUpdateAfterProcessing`. - if (firstBaseUpdate === null) { - // `queue.lanes` is used for entangling transitions. We can set it back to - // zero once the queue is empty. - queue.shared.lanes = NoLanes; - } // Set the remaining expiration time to be whatever is remaining in the queue. - // This should be fine because the only two other things that contribute to - // expiration time are props and context. We're already in the middle of the - // begin phase by the time we start processing the queue, so we've already - // dealt with the props. Context in components that specify - // shouldComponentUpdate is tricky; but we'll have to account for - // that regardless. + var hasForceUpdate = false; + var didWarnUpdateInsideUpdate; + var currentlyProcessingQueue; - markSkippedUpdateLanes(newLanes); - workInProgress.lanes = newLanes; - workInProgress.memoizedState = newState; - } + { + didWarnUpdateInsideUpdate = false; + currentlyProcessingQueue = null; + } - { - 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; - function callCallback(callback, context) { - if (typeof callback !== "function") { - throw new Error( - "Invalid argument passed as callback. Expected a function. Instead " + - ("received: " + callback) - ); + if (updateQueue === null) { + // Only occurs if the fiber has been unmounted. + return null; } - callback.call(context); - } + var sharedQueue = updateQueue.shared; - function resetHasForceUpdateBeforeProcessing() { - hasForceUpdate = false; - } - function checkHasForceUpdateAfterProcessing() { - return hasForceUpdate; - } - function deferHiddenCallbacks(updateQueue) { - // When an update finishes on a hidden component, its callback should not - // be fired until/unless the component is made visible again. Stash the - // callback on the shared queue object so it can be fired later. - var newHiddenCallbacks = updateQueue.callbacks; + { + if ( + currentlyProcessingQueue === sharedQueue && + !didWarnUpdateInsideUpdate + ) { + var componentName = getComponentNameFromFiber(fiber); - if (newHiddenCallbacks !== null) { - var existingHiddenCallbacks = updateQueue.shared.hiddenCallbacks; + error( + "An update (setState, replaceState, or forceUpdate) was scheduled " + + "from inside an update function. Update functions should be pure, " + + "with zero side-effects. Consider using componentDidUpdate or a " + + "callback.\n\nPlease update the following component: %s", + componentName + ); - if (existingHiddenCallbacks === null) { - updateQueue.shared.hiddenCallbacks = newHiddenCallbacks; - } else { - updateQueue.shared.hiddenCallbacks = - existingHiddenCallbacks.concat(newHiddenCallbacks); + didWarnUpdateInsideUpdate = true; } } - } - 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; + 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; - for (var i = 0; i < hiddenCallbacks.length; i++) { - var callback = hiddenCallbacks[i]; - callCallback(callback, context); + if (pending === null) { + // This is the first update. Create a circular list. + update.next = update; + } else { + update.next = pending.next; + pending.next = update; } - } - } - function commitCallbacks(updateQueue, context) { - var callbacks = updateQueue.callbacks; - if (callbacks !== null) { - updateQueue.callbacks = null; + sharedQueue.pending = update; // Update the childLanes even though we're most likely already rendering + // this fiber. This is for backwards compatibility in the case where you + // update a different component during render phase than the one that is + // currently renderings (a pattern that is accompanied by a warning). - for (var i = 0; i < callbacks.length; i++) { - var callback = callbacks[i]; - callCallback(callback, context); - } + return unsafe_markUpdateLaneFromFiberToRoot(fiber, lane); + } else { + return enqueueConcurrentClassUpdate(fiber, sharedQueue, update, lane); } } + function entangleTransitions(root, fiber, lane) { + var updateQueue = fiber.updateQueue; - /** - * 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; + if (updateQueue === null) { + // Only occurs if the fiber has been unmounted. + return; } - if ( - typeof objA !== "object" || - objA === null || - typeof objB !== "object" || - objB === null - ) { - return false; - } + var sharedQueue = updateQueue.shared; - var keysA = Object.keys(objA); - var keysB = Object.keys(objB); + if (isTransitionLane(lane)) { + var queueLanes = sharedQueue.lanes; // If any entangled lanes are no longer pending on the root, then they must + // have finished. We can remove them from the shared queue, which represents + // a superset of the actually pending lanes. In some cases we may entangle + // more than we need to, but that's OK. In fact it's worse if we *don't* + // entangle when we should. - if (keysA.length !== keysB.length) { - return false; - } // Test for A's keys different from B. + queueLanes = intersectLanes(queueLanes, root.pendingLanes); // Entangle the new transition lane with the other transition lanes. - for (var i = 0; i < keysA.length; i++) { - var currentKey = keysA[i]; + var newQueueLanes = mergeLanes(queueLanes, lane); + sharedQueue.lanes = newQueueLanes; // Even if queue.lanes already include lane, we don't know for certain if + // the lane finished since the last time we entangled it. So we need to + // entangle it again, just to be sure. - if ( - !hasOwnProperty.call(objB, currentKey) || // $FlowFixMe[incompatible-use] lost refinement of `objB` - !objectIs(objA[currentKey], objB[currentKey]) - ) { - return false; - } + markRootEntangled(root, newQueueLanes); } - - return true; } + 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 describeFiber(fiber) { - var owner = fiber._debugOwner ? fiber._debugOwner.type : null; - var source = fiber._debugSource; - - switch (fiber.tag) { - case HostHoistable: - case HostSingleton: - case HostComponent: - return describeBuiltInComponentFrame(fiber.type, source, owner); + var current = workInProgress.alternate; - case LazyComponent: - return describeBuiltInComponentFrame("Lazy", source, owner); + if (current !== null) { + var currentQueue = current.updateQueue; - case SuspenseComponent: - return describeBuiltInComponentFrame("Suspense", source, owner); + if (queue === currentQueue) { + // The work-in-progress queue is the same as current. This happens when + // we bail out on a parent fiber that then captures an error thrown by + // a child. Since we want to append the update only to the work-in + // -progress queue, we need to clone the updates. We usually clone during + // processUpdateQueue, but that didn't happen in this case because we + // skipped over the parent when we bailed out. + var newFirst = null; + var newLast = null; + var firstBaseUpdate = queue.firstBaseUpdate; - case SuspenseListComponent: - return describeBuiltInComponentFrame("SuspenseList", source, owner); + if (firstBaseUpdate !== null) { + // Loop through the updates and clone them. + var update = firstBaseUpdate; - case FunctionComponent: - case IndeterminateComponent: - case SimpleMemoComponent: - return describeFunctionComponentFrame(fiber.type, source, owner); + 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 + }; - case ForwardRef: - return describeFunctionComponentFrame( - fiber.type.render, - source, - owner - ); + if (newLast === null) { + newFirst = newLast = clone; + } else { + newLast.next = clone; + newLast = clone; + } // $FlowFixMe[incompatible-type] we bail out when we get a null - case ClassComponent: - return describeClassComponentFrame(fiber.type, source, owner); + update = update.next; + } while (update !== null); // Append the captured update the end of the cloned list. - default: - return ""; + if (newLast === null) { + newFirst = newLast = capturedUpdate; + } else { + newLast.next = capturedUpdate; + newLast = capturedUpdate; + } + } else { + // There are no base updates. + newFirst = newLast = capturedUpdate; + } + + queue = { + baseState: currentQueue.baseState, + firstBaseUpdate: newFirst, + lastBaseUpdate: newLast, + shared: currentQueue.shared, + callbacks: currentQueue.callbacks + }; + workInProgress.updateQueue = queue; + return; + } + } // Append the update to the end of the list. + + var lastBaseUpdate = queue.lastBaseUpdate; + + if (lastBaseUpdate === null) { + queue.firstBaseUpdate = capturedUpdate; + } else { + lastBaseUpdate.next = capturedUpdate; } + + queue.lastBaseUpdate = capturedUpdate; } - function getStackByFiberInDevAndProd(workInProgress) { - try { - var info = ""; - var node = workInProgress; + function getStateFromUpdate( + workInProgress, + queue, + update, + prevState, + nextProps, + instance + ) { + switch (update.tag) { + case ReplaceState: { + var payload = update.payload; - do { - info += describeFiber(node); // $FlowFixMe[incompatible-type] we bail out when we get a null + if (typeof payload === "function") { + // Updater function + { + enterDisallowedContextReadInDEV(); + } - node = node.return; - } while (node); + var nextState = payload.call(instance, prevState, nextProps); - return info; - } catch (x) { - return "\nError generating stack: " + x.message + "\n" + x.stack; - } - } + { + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); - var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; - var current = null; - var isRendering = false; - function getCurrentFiberOwnerNameInDevOrNull() { - { - if (current === null) { - return null; + try { + payload.call(instance, prevState, nextProps); + } finally { + setIsStrictModeForDevtools(false); + } + } + + exitDisallowedContextReadInDEV(); + } + + return nextState; + } // State object + + return payload; } - var owner = current._debugOwner; + case CaptureUpdate: { + workInProgress.flags = + (workInProgress.flags & ~ShouldCapture) | DidCapture; + } + // Intentional fallthrough - if (owner !== null && typeof owner !== "undefined") { - return getComponentNameFromFiber(owner); + case UpdateState: { + var _payload = update.payload; + var partialState; + + if (typeof _payload === "function") { + // Updater function + { + enterDisallowedContextReadInDEV(); + } + + partialState = _payload.call(instance, prevState, nextProps); + + { + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); + + try { + _payload.call(instance, prevState, nextProps); + } finally { + setIsStrictModeForDevtools(false); + } + } + + exitDisallowedContextReadInDEV(); + } + } else { + // Partial state object + partialState = _payload; + } + + if (partialState === null || partialState === undefined) { + // Null and undefined are treated as no-ops. + return prevState; + } // Merge the partial state and the previous state. + + return assign({}, prevState, partialState); + } + + case ForceUpdate: { + hasForceUpdate = true; + return prevState; } } - return null; + return prevState; } - 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 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. - return getStackByFiberInDevAndProd(current); - } - } + 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(); - 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; + 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 setIsRendering(rendering) { + function processUpdateQueue(workInProgress, props, instance, renderLanes) { + didReadFromEntangledAsyncAction = false; // This is always non-null on a ClassComponent or HostRoot + + var queue = workInProgress.updateQueue; + hasForceUpdate = false; + { - isRendering = rendering; + currentlyProcessingQueue = queue.shared; } - } - var ReactStrictModeWarnings = { - recordUnsafeLifecycleWarnings: function (fiber, instance) {}, - flushPendingUnsafeLifecycleWarnings: function () {}, - recordLegacyContextWarning: function (fiber, instance) {}, - flushLegacyContextWarning: function () {}, - discardPendingWarnings: function () {} - }; + var firstBaseUpdate = queue.firstBaseUpdate; + var lastBaseUpdate = queue.lastBaseUpdate; // Check if there are pending updates. If so, transfer them to the base queue. - { - var findStrictRoot = function (fiber) { - var maybeStrictRoot = null; - var node = fiber; + var pendingQueue = queue.shared.pending; - while (node !== null) { - if (node.mode & StrictLegacyMode) { - maybeStrictRoot = node; - } + 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. - node = node.return; + var lastPendingUpdate = pendingQueue; + var firstPendingUpdate = lastPendingUpdate.next; + lastPendingUpdate.next = null; // Append pending updates to base queue + + if (lastBaseUpdate === null) { + firstBaseUpdate = firstPendingUpdate; + } else { + lastBaseUpdate.next = firstPendingUpdate; } - return maybeStrictRoot; - }; - - var setToSortedString = function (set) { - var array = []; - set.forEach(function (value) { - array.push(value); - }); - return array.sort().join(", "); - }; - - var pendingComponentWillMountWarnings = []; - var pendingUNSAFE_ComponentWillMountWarnings = []; - var pendingComponentWillReceivePropsWarnings = []; - var pendingUNSAFE_ComponentWillReceivePropsWarnings = []; - var pendingComponentWillUpdateWarnings = []; - var pendingUNSAFE_ComponentWillUpdateWarnings = []; // Tracks components we have already warned about. - - var didWarnAboutUnsafeLifecycles = new Set(); + 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 - ReactStrictModeWarnings.recordUnsafeLifecycleWarnings = function ( - fiber, - instance - ) { - // Dedupe strategy: Warn once per component. - if (didWarnAboutUnsafeLifecycles.has(fiber.type)) { - return; - } + var current = workInProgress.alternate; - if ( - typeof instance.componentWillMount === "function" && // Don't warn about react-lifecycles-compat polyfilled components. - instance.componentWillMount.__suppressDeprecationWarning !== true - ) { - pendingComponentWillMountWarnings.push(fiber); - } + if (current !== null) { + // This is always non-null on a ClassComponent or HostRoot + var currentQueue = current.updateQueue; + var currentLastBaseUpdate = currentQueue.lastBaseUpdate; - if ( - fiber.mode & StrictLegacyMode && - typeof instance.UNSAFE_componentWillMount === "function" - ) { - pendingUNSAFE_ComponentWillMountWarnings.push(fiber); - } + if (currentLastBaseUpdate !== lastBaseUpdate) { + if (currentLastBaseUpdate === null) { + currentQueue.firstBaseUpdate = firstPendingUpdate; + } else { + currentLastBaseUpdate.next = firstPendingUpdate; + } - if ( - typeof instance.componentWillReceiveProps === "function" && - instance.componentWillReceiveProps.__suppressDeprecationWarning !== - true - ) { - pendingComponentWillReceivePropsWarnings.push(fiber); + currentQueue.lastBaseUpdate = lastPendingUpdate; + } } + } // These values may change as we process the queue. - if ( - fiber.mode & StrictLegacyMode && - typeof instance.UNSAFE_componentWillReceiveProps === "function" - ) { - pendingUNSAFE_ComponentWillReceivePropsWarnings.push(fiber); - } + if (firstBaseUpdate !== null) { + // Iterate through the list of updates to compute the result. + var newState = queue.baseState; // TODO: Don't need to accumulate this. Instead, we can remove renderLanes + // from the original lanes. - if ( - typeof instance.componentWillUpdate === "function" && - instance.componentWillUpdate.__suppressDeprecationWarning !== true - ) { - pendingComponentWillUpdateWarnings.push(fiber); - } + var newLanes = NoLanes; + var newBaseState = null; + var newFirstBaseUpdate = null; + var newLastBaseUpdate = null; + var update = firstBaseUpdate; - if ( - fiber.mode & StrictLegacyMode && - typeof instance.UNSAFE_componentWillUpdate === "function" - ) { - pendingUNSAFE_ComponentWillUpdateWarnings.push(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. - ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = - function () { - // We do an initial pass to gather component names - var componentWillMountUniqueNames = new Set(); + var shouldSkipUpdate = isHiddenUpdate + ? !isSubsetOfLanes(getWorkInProgressRootRenderLanes(), updateLane) + : !isSubsetOfLanes(renderLanes, updateLane); - if (pendingComponentWillMountWarnings.length > 0) { - pendingComponentWillMountWarnings.forEach(function (fiber) { - componentWillMountUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingComponentWillMountWarnings = []; - } + if (shouldSkipUpdate) { + // Priority is insufficient. Skip this update. If this is the first + // skipped update, the previous update/state is the new base + // update/state. + var clone = { + lane: updateLane, + tag: update.tag, + payload: update.payload, + callback: update.callback, + next: null + }; - var UNSAFE_componentWillMountUniqueNames = new Set(); + if (newLastBaseUpdate === null) { + newFirstBaseUpdate = newLastBaseUpdate = clone; + newBaseState = newState; + } else { + newLastBaseUpdate = newLastBaseUpdate.next = clone; + } // Update the remaining priority in the queue. - if (pendingUNSAFE_ComponentWillMountWarnings.length > 0) { - pendingUNSAFE_ComponentWillMountWarnings.forEach(function (fiber) { - UNSAFE_componentWillMountUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingUNSAFE_ComponentWillMountWarnings = []; - } + 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; + } - var componentWillReceivePropsUniqueNames = new Set(); + if (newLastBaseUpdate !== null) { + var _clone = { + // This update is going to be committed so we never want uncommit + // it. Using NoLane works because 0 is a subset of all bitmasks, so + // this will never be skipped by the check above. + lane: NoLane, + tag: update.tag, + payload: update.payload, + // When this update is rebased, we should not fire its + // callback again. + callback: null, + next: null + }; + newLastBaseUpdate = newLastBaseUpdate.next = _clone; + } // Process this update. - if (pendingComponentWillReceivePropsWarnings.length > 0) { - pendingComponentWillReceivePropsWarnings.forEach(function (fiber) { - componentWillReceivePropsUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingComponentWillReceivePropsWarnings = []; - } + newState = getStateFromUpdate( + workInProgress, + queue, + update, + newState, + props, + instance + ); + var callback = update.callback; - var UNSAFE_componentWillReceivePropsUniqueNames = new Set(); + if (callback !== null) { + workInProgress.flags |= Callback; - if (pendingUNSAFE_ComponentWillReceivePropsWarnings.length > 0) { - pendingUNSAFE_ComponentWillReceivePropsWarnings.forEach( - function (fiber) { - UNSAFE_componentWillReceivePropsUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); + if (isHiddenUpdate) { + workInProgress.flags |= Visibility; } - ); - pendingUNSAFE_ComponentWillReceivePropsWarnings = []; - } - var componentWillUpdateUniqueNames = new Set(); + var callbacks = queue.callbacks; - if (pendingComponentWillUpdateWarnings.length > 0) { - pendingComponentWillUpdateWarnings.forEach(function (fiber) { - componentWillUpdateUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingComponentWillUpdateWarnings = []; - } + if (callbacks === null) { + queue.callbacks = [callback]; + } else { + callbacks.push(callback); + } + } + } // $FlowFixMe[incompatible-type] we bail out when we get a null - var UNSAFE_componentWillUpdateUniqueNames = new Set(); + update = update.next; - 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 (update === null) { + pendingQueue = queue.shared.pending; - if (UNSAFE_componentWillMountUniqueNames.size > 0) { - var sortedNames = setToSortedString( - UNSAFE_componentWillMountUniqueNames - ); + 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. - 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 _firstPendingUpdate = _lastPendingUpdate.next; + _lastPendingUpdate.next = null; + update = _firstPendingUpdate; + queue.lastBaseUpdate = _lastPendingUpdate; + queue.shared.pending = null; + } } + } while (true); - if (UNSAFE_componentWillReceivePropsUniqueNames.size > 0) { - var _sortedNames = setToSortedString( - UNSAFE_componentWillReceivePropsUniqueNames - ); + if (newLastBaseUpdate === null) { + newBaseState = newState; + } - 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 - ); - } + queue.baseState = newBaseState; + queue.firstBaseUpdate = newFirstBaseUpdate; + queue.lastBaseUpdate = newLastBaseUpdate; - if (UNSAFE_componentWillUpdateUniqueNames.size > 0) { - var _sortedNames2 = setToSortedString( - UNSAFE_componentWillUpdateUniqueNames - ); + 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. - 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 - ); - } + markSkippedUpdateLanes(newLanes); + workInProgress.lanes = newLanes; + workInProgress.memoizedState = newState; + } - if (componentWillMountUniqueNames.size > 0) { - var _sortedNames3 = setToSortedString( - componentWillMountUniqueNames - ); + { + currentlyProcessingQueue = null; + } + } - 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 - ); - } + function callCallback(callback, context) { + if (typeof callback !== "function") { + throw new Error( + "Invalid argument passed as callback. Expected a function. Instead " + + ("received: " + callback) + ); + } - if (componentWillReceivePropsUniqueNames.size > 0) { - var _sortedNames4 = setToSortedString( - componentWillReceivePropsUniqueNames - ); + callback.call(context); + } - 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 resetHasForceUpdateBeforeProcessing() { + hasForceUpdate = false; + } + function checkHasForceUpdateAfterProcessing() { + return hasForceUpdate; + } + function deferHiddenCallbacks(updateQueue) { + // When an update finishes on a hidden component, its callback should not + // be fired until/unless the component is made visible again. Stash the + // callback on the shared queue object so it can be fired later. + var newHiddenCallbacks = updateQueue.callbacks; - if (componentWillUpdateUniqueNames.size > 0) { - var _sortedNames5 = setToSortedString( - componentWillUpdateUniqueNames - ); + if (newHiddenCallbacks !== null) { + var existingHiddenCallbacks = updateQueue.shared.hiddenCallbacks; - 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 (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 pendingLegacyContextWarning = new Map(); // Tracks components we have already warned about. + if (hiddenCallbacks !== null) { + updateQueue.shared.hiddenCallbacks = null; - var didWarnAboutLegacyContext = new Set(); + for (var i = 0; i < hiddenCallbacks.length; i++) { + var callback = hiddenCallbacks[i]; + callCallback(callback, context); + } + } + } + function commitCallbacks(updateQueue, context) { + var callbacks = updateQueue.callbacks; - ReactStrictModeWarnings.recordLegacyContextWarning = function ( - fiber, - instance - ) { - var strictRoot = findStrictRoot(fiber); + if (callbacks !== null) { + updateQueue.callbacks = null; - 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." - ); + for (var i = 0; i < callbacks.length; i++) { + var callback = callbacks[i]; + callCallback(callback, context); + } + } + } - return; - } // Dedup strategy: Warn once per component. + /** + * Performs equality by iterating through keys on an object and returning false + * when any key has values which are not strictly equal between the arguments. + * Returns true when the values of all keys are strictly equal. + */ - if (didWarnAboutLegacyContext.has(fiber.type)) { - return; - } + function shallowEqual(objA, objB) { + if (objectIs(objA, objB)) { + return true; + } - var warningsForRoot = pendingLegacyContextWarning.get(strictRoot); + 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 ( - fiber.type.contextTypes != null || - fiber.type.childContextTypes != null || - (instance !== null && typeof instance.getChildContext === "function") + !hasOwnProperty.call(objB, currentKey) || // $FlowFixMe[incompatible-use] lost refinement of `objB` + !objectIs(objA[currentKey], objB[currentKey]) ) { - if (warningsForRoot === undefined) { - warningsForRoot = []; - pendingLegacyContextWarning.set(strictRoot, warningsForRoot); - } - - warningsForRoot.push(fiber); + return false; } - }; + } - ReactStrictModeWarnings.flushLegacyContextWarning = function () { - pendingLegacyContextWarning.forEach(function (fiberArray, strictRoot) { - if (fiberArray.length === 0) { - return; - } + return true; + } - 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 describeFiber(fiber) { + var owner = fiber._debugOwner ? fiber._debugOwner.type : null; + var source = fiber._debugSource; - try { - setCurrentFiber(firstFiber); + switch (fiber.tag) { + case HostHoistable: + case HostSingleton: + case HostComponent: + return describeBuiltInComponentFrame(fiber.type, source, owner); - 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(); - } - }); - }; + case LazyComponent: + return describeBuiltInComponentFrame("Lazy", source, owner); - ReactStrictModeWarnings.discardPendingWarnings = function () { - pendingComponentWillMountWarnings = []; - pendingUNSAFE_ComponentWillMountWarnings = []; - pendingComponentWillReceivePropsWarnings = []; - pendingUNSAFE_ComponentWillReceivePropsWarnings = []; - pendingComponentWillUpdateWarnings = []; - pendingUNSAFE_ComponentWillUpdateWarnings = []; - pendingLegacyContextWarning = new Map(); - }; - } + case SuspenseComponent: + return describeBuiltInComponentFrame("Suspense", source, owner); - /* - * 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] + case SuspenseListComponent: + return describeBuiltInComponentFrame("SuspenseList", source, owner); - return type; - } - } // $FlowFixMe[incompatible-return] only called in DEV, so void return is not possible. + case FunctionComponent: + case IndeterminateComponent: + case SimpleMemoComponent: + return describeFunctionComponentFrame(fiber.type, source, owner); - function willCoercionThrow(value) { - { - try { - testStringCoercion(value); - return false; - } catch (e) { - return true; - } + case ForwardRef: + return describeFunctionComponentFrame( + fiber.type.render, + source, + owner + ); + + case ClassComponent: + return describeClassComponentFrame(fiber.type, source, owner); + + default: + return ""; } } - 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) - ); + function getStackByFiberInDevAndProd(workInProgress) { + try { + var info = ""; + var node = workInProgress; - return testStringCoercion(value); // throw (to help callers find troubleshooting comments) - } + 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; } } - function checkPropStringCoercion(value, propName) { + + var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; + var current = null; + var isRendering = false; + function getCurrentFiberOwnerNameInDevOrNull() { { - if (willCoercionThrow(value)) { - error( - "The provided `%s` prop is an unsupported type %s." + - " This value must be coerced to a string before using it here.", - propName, - typeName(value) - ); + if (current === null) { + return null; + } - return testStringCoercion(value); // throw (to help callers find troubleshooting comments) + var owner = current._debugOwner; + + if (owner !== null && typeof owner !== "undefined") { + return getComponentNameFromFiber(owner); } } + + return null; } - 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. + 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 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. + return getStackByFiberInDevAndProd(current); + } + } - var noopSuspenseyCommitThenable = { - then: function () { - { - error( - "Internal React error: A listener was unexpectedly attached to a " + - '"noop" thenable. This is a bug in React. Please file an issue.' - ); - } + function resetCurrentFiber() { + { + ReactDebugCurrentFrame.getCurrentStack = null; + current = null; + isRendering = false; } - }; - 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 setCurrentFiber(fiber) { + { + ReactDebugCurrentFrame.getCurrentStack = + fiber === null ? null : getCurrentFiberStackInDev; + current = fiber; + isRendering = false; + } } - - function noop() {} - - function trackUsedThenable(thenableState, thenable, index) { - if (ReactCurrentActQueue$3.current !== null) { - ReactCurrentActQueue$3.didUsePromise = true; + function getCurrentFiber() { + { + return current; } + } + function setIsRendering(rendering) { + { + isRendering = rendering; + } + } - var previous = thenableState[index]; + var ReactStrictModeWarnings = { + recordUnsafeLifecycleWarnings: function (fiber, instance) {}, + flushPendingUnsafeLifecycleWarnings: function () {}, + recordLegacyContextWarning: function (fiber, instance) {}, + flushLegacyContextWarning: function () {}, + discardPendingWarnings: function () {} + }; - 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. + { + var findStrictRoot = function (fiber) { + var maybeStrictRoot = null; + var node = fiber; - switch (thenable.status) { - case "fulfilled": { - var fulfilledValue = thenable.value; - return fulfilledValue; - } + while (node !== null) { + if (node.mode & StrictLegacyMode) { + maybeStrictRoot = node; + } - case "rejected": { - var rejectedError = thenable.reason; - checkIfUseWrappedInAsyncCatch(rejectedError); - throw rejectedError; + node = node.return; } - 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 maybeStrictRoot; + }; - if (root !== null && root.shellSuspendCounter > 100) { - // This root has suspended repeatedly in the shell without making any - // progress (i.e. committing something). This is highly suggestive of - // an infinite ping loop, often caused by an accidental Async Client - // Component. - // - // During a transition, we can suspend the work loop until the promise - // to resolve, but this is a sync render, so that's not an option. We - // also can't show a fallback, because none was provided. So our last - // resort is to throw an error. - // - // TODO: Remove this error in a future release. Other ways of handling - // this case include forcing a concurrent render, or putting the whole - // root into offscreen mode. - throw new Error( - "async/await is not yet supported in Client Components, only " + - "Server Components. This error is often caused by accidentally " + - "adding `'use client'` to a module that was originally written " + - "for the server." - ); - } - - var pendingThenable = thenable; - pendingThenable.status = "pending"; - pendingThenable.then( - function (fulfilledValue) { - if (thenable.status === "pending") { - var fulfilledThenable = thenable; - fulfilledThenable.status = "fulfilled"; - fulfilledThenable.value = fulfilledValue; - } - }, - function (error) { - if (thenable.status === "pending") { - var rejectedThenable = thenable; - rejectedThenable.status = "rejected"; - rejectedThenable.reason = error; - } - } - ); // Check one more time in case the thenable resolved synchronously. + var setToSortedString = function (set) { + var array = []; + set.forEach(function (value) { + array.push(value); + }); + return array.sort().join(", "); + }; - switch (thenable.status) { - case "fulfilled": { - var fulfilledThenable = thenable; - return fulfilledThenable.value; - } + var pendingComponentWillMountWarnings = []; + var pendingUNSAFE_ComponentWillMountWarnings = []; + var pendingComponentWillReceivePropsWarnings = []; + var pendingUNSAFE_ComponentWillReceivePropsWarnings = []; + var pendingComponentWillUpdateWarnings = []; + var pendingUNSAFE_ComponentWillUpdateWarnings = []; // Tracks components we have already warned about. - case "rejected": { - var rejectedThenable = thenable; - var _rejectedError = rejectedThenable.reason; - checkIfUseWrappedInAsyncCatch(_rejectedError); - throw _rejectedError; - } - } - } // Suspend. - // - // Throwing here is an implementation detail that allows us to unwind the - // call stack. But we shouldn't allow it to leak into userspace. Throw an - // opaque placeholder value instead of the actual thenable. If it doesn't - // get captured by the work loop, log a warning, because that means - // something in userspace must have caught it. + var didWarnAboutUnsafeLifecycles = new Set(); - suspendedThenable = thenable; + ReactStrictModeWarnings.recordUnsafeLifecycleWarnings = function ( + fiber, + instance + ) { + // Dedupe strategy: Warn once per component. + if (didWarnAboutUnsafeLifecycles.has(fiber.type)) { + return; + } - { - needsToResetSuspendedThenableDEV = true; - } + if ( + typeof instance.componentWillMount === "function" && // Don't warn about react-lifecycles-compat polyfilled components. + instance.componentWillMount.__suppressDeprecationWarning !== true + ) { + pendingComponentWillMountWarnings.push(fiber); + } - throw SuspenseException; + if ( + fiber.mode & StrictLegacyMode && + typeof instance.UNSAFE_componentWillMount === "function" + ) { + pendingUNSAFE_ComponentWillMountWarnings.push(fiber); } - } - } - // 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." - ); - } + if ( + typeof instance.componentWillReceiveProps === "function" && + instance.componentWillReceiveProps.__suppressDeprecationWarning !== + true + ) { + pendingComponentWillReceivePropsWarnings.push(fiber); + } - var thenable = suspendedThenable; - suspendedThenable = null; + if ( + fiber.mode & StrictLegacyMode && + typeof instance.UNSAFE_componentWillReceiveProps === "function" + ) { + pendingUNSAFE_ComponentWillReceivePropsWarnings.push(fiber); + } - { - needsToResetSuspendedThenableDEV = false; - } + if ( + typeof instance.componentWillUpdate === "function" && + instance.componentWillUpdate.__suppressDeprecationWarning !== true + ) { + pendingComponentWillUpdateWarnings.push(fiber); + } - return thenable; - } - function checkIfUseWrappedInTryCatch() { - { - // This was set right before SuspenseException was thrown, and it should - // have been cleared when the exception was handled. If it wasn't, - // it must have been caught by userspace. - if (needsToResetSuspendedThenableDEV) { - needsToResetSuspendedThenableDEV = false; - return true; + if ( + fiber.mode & StrictLegacyMode && + typeof instance.UNSAFE_componentWillUpdate === "function" + ) { + pendingUNSAFE_ComponentWillUpdateWarnings.push(fiber); } - } + }; - 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." - ); - } - } + ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = + function () { + // We do an initial pass to gather component names + var componentWillMountUniqueNames = new Set(); - var thenableState$1 = null; - var thenableIndexCounter$1 = 0; - var didWarnAboutMaps; - var didWarnAboutGenerators; - var didWarnAboutStringRefs; - var ownerHasKeyUseWarning; - var ownerHasFunctionTypeWarning; + if (pendingComponentWillMountWarnings.length > 0) { + pendingComponentWillMountWarnings.forEach(function (fiber) { + componentWillMountUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingComponentWillMountWarnings = []; + } - var warnForMissingKey = function (child, returnFiber) {}; + var UNSAFE_componentWillMountUniqueNames = new Set(); - { - 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 (pendingUNSAFE_ComponentWillMountWarnings.length > 0) { + pendingUNSAFE_ComponentWillMountWarnings.forEach(function (fiber) { + UNSAFE_componentWillMountUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingUNSAFE_ComponentWillMountWarnings = []; + } - ownerHasKeyUseWarning = {}; - ownerHasFunctionTypeWarning = {}; + var componentWillReceivePropsUniqueNames = new Set(); - warnForMissingKey = function (child, returnFiber) { - if (child === null || typeof child !== "object") { - return; - } + if (pendingComponentWillReceivePropsWarnings.length > 0) { + pendingComponentWillReceivePropsWarnings.forEach(function (fiber) { + componentWillReceivePropsUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingComponentWillReceivePropsWarnings = []; + } - if (!child._store || child._store.validated || child.key != null) { - return; - } + var UNSAFE_componentWillReceivePropsUniqueNames = new Set(); - 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 (pendingUNSAFE_ComponentWillReceivePropsWarnings.length > 0) { + pendingUNSAFE_ComponentWillReceivePropsWarnings.forEach( + function (fiber) { + UNSAFE_componentWillReceivePropsUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + } + ); + pendingUNSAFE_ComponentWillReceivePropsWarnings = []; + } - child._store.validated = true; - var componentName = - getComponentNameFromFiber(returnFiber) || "Component"; + var componentWillUpdateUniqueNames = new Set(); - if (ownerHasKeyUseWarning[componentName]) { - 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 (pendingComponentWillUpdateWarnings.length > 0) { + pendingComponentWillUpdateWarnings.forEach(function (fiber) { + componentWillUpdateUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingComponentWillUpdateWarnings = []; + } - function isReactClass(type) { - return type.prototype && type.prototype.isReactComponent; - } + var UNSAFE_componentWillUpdateUniqueNames = new Set(); - function unwrapThenable(thenable) { - var index = thenableIndexCounter$1; - thenableIndexCounter$1 += 1; + 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 (thenableState$1 === null) { - thenableState$1 = createThenableState(); - } + if (UNSAFE_componentWillMountUniqueNames.size > 0) { + var sortedNames = setToSortedString( + UNSAFE_componentWillMountUniqueNames + ); - return trackUsedThenable(thenableState$1, thenable, index); - } + error( + "Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code. " + + "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + + "* Move code with side effects to componentDidMount, and set initial state in the constructor.\n" + + "\nPlease update the following components: %s", + sortedNames + ); + } - function coerceRef(returnFiber, current, element) { - var mixedRef = element.ref; + if (UNSAFE_componentWillReceivePropsUniqueNames.size > 0) { + var _sortedNames = setToSortedString( + UNSAFE_componentWillReceivePropsUniqueNames + ); - 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"; + error( + "Using UNSAFE_componentWillReceiveProps in strict mode is not recommended " + + "and may indicate bugs in your code. " + + "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + + "* Move data fetching code or side effects to componentDidUpdate.\n" + + "* If you're updating state whenever props change, " + + "refactor your code to use memoization techniques or move it to " + + "static getDerivedStateFromProps. Learn more at: https://reactjs.org/link/derived-state\n" + + "\nPlease update the following components: %s", + _sortedNames + ); + } - if (!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 (UNSAFE_componentWillUpdateUniqueNames.size > 0) { + var _sortedNames2 = setToSortedString( + UNSAFE_componentWillUpdateUniqueNames + ); - didWarnAboutStringRefs[componentName] = true; - } + 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 (element._owner) { - var owner = element._owner; - var inst; + if (componentWillMountUniqueNames.size > 0) { + var _sortedNames3 = setToSortedString( + componentWillMountUniqueNames + ); - if (owner) { - var ownerFiber = owner; + 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 (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 (componentWillReceivePropsUniqueNames.size > 0) { + var _sortedNames4 = setToSortedString( + componentWillReceivePropsUniqueNames + ); - inst = ownerFiber.stateNode; + warn( + "componentWillReceiveProps has been renamed, and is not recommended for use. " + + "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + + "* Move data fetching code or side effects to componentDidUpdate.\n" + + "* If you're updating state whenever props change, refactor your " + + "code to use memoization techniques or move it to " + + "static getDerivedStateFromProps. Learn more at: https://reactjs.org/link/derived-state\n" + + "* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress " + + "this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. " + + "To rename all deprecated lifecycles to their new names, you can run " + + "`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n" + + "\nPlease update the following components: %s", + _sortedNames4 + ); } - if (!inst) { - throw new Error( - "Missing owner for string ref " + - mixedRef + - ". This error is likely caused by a " + - "bug in React. Please file an issue." + if (componentWillUpdateUniqueNames.size > 0) { + var _sortedNames5 = setToSortedString( + componentWillUpdateUniqueNames ); - } // Assigning this to a const so Flow knows it won't change in the closure - - var resolvedInst = inst; - { - checkPropStringCoercion(mixedRef, "ref"); + 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 stringRef = "" + mixedRef; // Check if previous string ref matches new string ref + var pendingLegacyContextWarning = new Map(); // Tracks components we have already warned about. - if ( - current !== null && - current.ref !== null && - typeof current.ref === "function" && - current.ref._stringRef === stringRef - ) { - return current.ref; - } + var didWarnAboutLegacyContext = new Set(); - var ref = function (value) { - var refs = resolvedInst.refs; + ReactStrictModeWarnings.recordLegacyContextWarning = function ( + fiber, + instance + ) { + var strictRoot = findStrictRoot(fiber); - if (value === null) { - delete refs[stringRef]; - } else { - refs[stringRef] = value; - } - }; + 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." + ); - 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." - ); - } + return; + } // Dedup strategy: Warn once per component. - 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 (didWarnAboutLegacyContext.has(fiber.type)) { + return; } - } - return mixedRef; - } + var warningsForRoot = pendingLegacyContextWarning.get(strictRoot); - function throwOnInvalidObjectType(returnFiber, newChild) { - // $FlowFixMe[method-unbinding] - var childString = Object.prototype.toString.call(newChild); - throw new Error( - "Objects are not valid as a React child (found: " + - (childString === "[object Object]" - ? "object with keys {" + Object.keys(newChild).join(", ") + "}" - : childString) + - "). " + - "If you meant to render a collection of children, use an array " + - "instead." - ); - } - - function warnOnFunctionType(returnFiber) { - { - var componentName = - getComponentNameFromFiber(returnFiber) || "Component"; + if ( + fiber.type.contextTypes != null || + fiber.type.childContextTypes != null || + (instance !== null && typeof instance.getChildContext === "function") + ) { + if (warningsForRoot === undefined) { + warningsForRoot = []; + pendingLegacyContextWarning.set(strictRoot, warningsForRoot); + } - if (ownerHasFunctionTypeWarning[componentName]) { - return; + warningsForRoot.push(fiber); } + }; - 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." - ); - } - } + ReactStrictModeWarnings.flushLegacyContextWarning = function () { + pendingLegacyContextWarning.forEach(function (fiberArray, strictRoot) { + if (fiberArray.length === 0) { + return; + } - function resolveLazy(lazyType) { - var payload = lazyType._payload; - var init = lazyType._init; - return init(payload); - } // This wrapper function exists because I expect to clone the code in each path - // to be able to optimize each path individually by branching early. This needs - // a compiler or we can do it manually. Helpers that don't need this branching - // live outside of this function. + var 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 createChildReconciler(shouldTrackSideEffects) { - function deleteChild(returnFiber, childToDelete) { - if (!shouldTrackSideEffects) { - // Noop. - return; - } + try { + setCurrentFiber(firstFiber); - var deletions = returnFiber.deletions; + 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 (deletions === null) { - returnFiber.deletions = [childToDelete]; - returnFiber.flags |= ChildDeletion; - } else { - deletions.push(childToDelete); - } - } + ReactStrictModeWarnings.discardPendingWarnings = function () { + pendingComponentWillMountWarnings = []; + pendingUNSAFE_ComponentWillMountWarnings = []; + pendingComponentWillReceivePropsWarnings = []; + pendingUNSAFE_ComponentWillReceivePropsWarnings = []; + pendingComponentWillUpdateWarnings = []; + pendingUNSAFE_ComponentWillUpdateWarnings = []; + pendingLegacyContextWarning = new Map(); + }; + } - 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. + /* + * 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] - var childToDelete = currentFirstChild; + return type; + } + } // $FlowFixMe[incompatible-return] only called in DEV, so void return is not possible. - while (childToDelete !== null) { - deleteChild(returnFiber, childToDelete); - childToDelete = childToDelete.sibling; + function willCoercionThrow(value) { + { + try { + testStringCoercion(value); + return false; + } catch (e) { + return true; } - - return null; } + } - function mapRemainingChildren(returnFiber, currentFirstChild) { - // Add the remaining children to a temporary map so that we can find them by - // keys quickly. Implicit (null) keys get added to this set with their index - // instead. - var existingChildren = new Map(); - var existingChild = currentFirstChild; - - while (existingChild !== null) { - if (existingChild.key !== null) { - existingChildren.set(existingChild.key, existingChild); - } else { - existingChildren.set(existingChild.index, existingChild); - } + 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) + ); - existingChild = existingChild.sibling; + return testStringCoercion(value); // throw (to help callers find troubleshooting comments) } - - return existingChildren; } + } + 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 useFiber(fiber, pendingProps) { - // We currently set sibling to null and index to 0 here because it is easy - // to forget to do before returning it. E.g. for the single child case. - var clone = createWorkInProgress(fiber, pendingProps); - clone.index = 0; - clone.sibling = null; - return clone; + return testStringCoercion(value); // throw (to help callers find troubleshooting comments) + } } + } - function placeChild(newFiber, lastPlacedIndex, newIndex) { - newFiber.index = newIndex; + var ReactCurrentActQueue$2 = ReactSharedInternals.ReactCurrentActQueue; // An error that is thrown (e.g. by `use`) to trigger Suspense. If we + // detect this is caught by userspace, we'll log a warning in development. - if (!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; + var SuspenseException = new Error( + "Suspense Exception: This is not a real error! It's an implementation " + + "detail of `use` to interrupt the current render. You must either " + + "rethrow it immediately, or move the `use` call outside of the " + + "`try/catch` block. Capturing without rethrowing will lead to " + + "unexpected behavior.\n\n" + + "To handle async errors, wrap your component in an error boundary, or " + + "call the promise's `.catch` method and pass the result to `use`" + ); + var SuspenseyCommitException = new Error( + "Suspense Exception: This is not a real error, and should not leak into " + + "userspace. If you're seeing this, it's likely a bug in React." + ); // This is a noop thenable that we use to trigger a fallback in throwException. + // TODO: It would be better to refactor throwException into multiple functions + // so we can trigger a fallback directly without having to check the type. But + // for now this will do. + + var noopSuspenseyCommitThenable = { + then: function () { + { + error( + "Internal React error: A listener was unexpectedly attached to a " + + '"noop" thenable. This is a bug in React. Please file an issue.' + ); } + } + }; + function createThenableState() { + // The ThenableState is created the first time a component suspends. If it + // suspends again, we'll reuse the same state. + return []; + } + function isThenableResolved(thenable) { + var status = thenable.status; + return status === "fulfilled" || status === "rejected"; + } - var current = newFiber.alternate; + function noop() {} - if (current !== null) { - var oldIndex = current.index; + function trackUsedThenable(thenableState, thenable, index) { + if (ReactCurrentActQueue$2.current !== null) { + ReactCurrentActQueue$2.didUsePromise = true; + } - if (oldIndex < lastPlacedIndex) { - // This is a move. - newFiber.flags |= Placement | PlacementDEV; - return lastPlacedIndex; - } else { - // This item can stay in place. - return oldIndex; - } - } else { - // This is an insertion. - newFiber.flags |= Placement | PlacementDEV; - return lastPlacedIndex; - } - } + var previous = thenableState[index]; - function placeSingleChild(newFiber) { - // This is simpler for the single child case. We only need to do a - // placement for inserting new children. - if (shouldTrackSideEffects && newFiber.alternate === null) { - newFiber.flags |= Placement | PlacementDEV; + if (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. - return newFiber; - } + switch (thenable.status) { + case "fulfilled": { + var fulfilledValue = thenable.value; + return fulfilledValue; + } - 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; + case "rejected": { + var rejectedError = thenable.reason; + checkIfUseWrappedInAsyncCatch(rejectedError); + throw rejectedError; } - } - function updateElement(returnFiber, current, element, lanes) { - var elementType = element.type; + 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 (elementType === REACT_FRAGMENT_TYPE) { - return updateFragment( - returnFiber, - current, - element.props.children, - lanes, - element.key - ); - } + if (root !== null && root.shellSuspendCounter > 100) { + // This root has suspended repeatedly in the shell without making any + // progress (i.e. committing something). This is highly suggestive of + // an infinite ping loop, often caused by an accidental Async Client + // Component. + // + // During a transition, we can suspend the work loop until the promise + // to resolve, but this is a sync render, so that's not an option. We + // also can't show a fallback, because none was provided. So our last + // resort is to throw an error. + // + // TODO: Remove this error in a future release. Other ways of handling + // this case include forcing a concurrent render, or putting the whole + // root into offscreen mode. + throw new Error( + "async/await is not yet supported in Client Components, only " + + "Server Components. This error is often caused by accidentally " + + "adding `'use client'` to a module that was originally written " + + "for the server." + ); + } - if (current !== null) { - if ( - current.elementType === elementType || // Keep this check inline so it only runs on the false path: - isCompatibleFamilyForHotReloading(current, element) || // Lazy types should reconcile their resolved type. - // We need to do this after the Hot Reloading check above, - // because hot reloading has different semantics than prod because - // it doesn't resuspend. So we can't let the call below suspend. - (typeof elementType === "object" && - elementType !== null && - elementType.$$typeof === REACT_LAZY_TYPE && - resolveLazy(elementType) === current.type) - ) { - // Move based on index - var existing = useFiber(current, element.props); - existing.ref = coerceRef(returnFiber, current, element); - existing.return = returnFiber; + var 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. - { - existing._debugSource = element._source; - existing._debugOwner = element._owner; + 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. - return existing; + suspendedThenable = thenable; + + { + needsToResetSuspendedThenableDEV = true; } - } // Insert - var created = createFiberFromElement(element, returnFiber.mode, lanes); - created.ref = coerceRef(returnFiber, current, element); - created.return = returnFiber; - return created; + throw SuspenseException; + } } + } + // passed to the rest of the Suspense implementation — which, for historical + // reasons, expects to receive a thenable. - function updatePortal(returnFiber, current, portal, lanes) { - if ( - current === null || - current.tag !== HostPortal || - current.stateNode.containerInfo !== portal.containerInfo || - current.stateNode.implementation !== portal.implementation - ) { - // Insert - var created = createFiberFromPortal(portal, returnFiber.mode, lanes); - created.return = returnFiber; - return created; - } else { - // Update - var existing = useFiber(current, portal.children || []); - existing.return = returnFiber; - return existing; - } + var 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 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 thenable = suspendedThenable; + suspendedThenable = null; + + { + needsToResetSuspendedThenableDEV = false; } - 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; + return thenable; + } + function checkIfUseWrappedInTryCatch() { + { + // This was set right before SuspenseException was thrown, and it should + // have been cleared when the exception was handled. If it wasn't, + // it must have been caught by userspace. + if (needsToResetSuspendedThenableDEV) { + needsToResetSuspendedThenableDEV = false; + return true; } + } - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: { - var _created = createFiberFromElement( - newChild, - returnFiber.mode, - 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." + ); + } + } - _created.ref = coerceRef(returnFiber, null, newChild); - _created.return = returnFiber; - return _created; - } + var thenableState$1 = null; + var thenableIndexCounter$1 = 0; + var didWarnAboutMaps; + var didWarnAboutGenerators; + var didWarnAboutStringRefs; + var ownerHasKeyUseWarning; + var ownerHasFunctionTypeWarning; - case REACT_PORTAL_TYPE: { - var _created2 = createFiberFromPortal( - newChild, - returnFiber.mode, - lanes - ); + var warnForMissingKey = function (child, returnFiber) {}; - _created2.return = returnFiber; - return _created2; - } + { + 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. + */ - case REACT_LAZY_TYPE: { - var payload = newChild._payload; - var init = newChild._init; - return createChild(returnFiber, init(payload), lanes); - } - } + ownerHasKeyUseWarning = {}; + ownerHasFunctionTypeWarning = {}; - if (isArray(newChild) || getIteratorFn(newChild)) { - var _created3 = createFiberFromFragment( - newChild, - returnFiber.mode, - lanes, - null - ); + warnForMissingKey = function (child, returnFiber) { + if (child === null || typeof child !== "object") { + return; + } - _created3.return = returnFiber; - return _created3; - } // Usable node types - // - // Unwrap the inner value and recursively call this function again. + if (!child._store || child._store.validated || child.key != null) { + return; + } - if (typeof newChild.then === "function") { - var thenable = newChild; - return createChild(returnFiber, unwrapThenable(thenable), lanes); - } + if (typeof child._store !== "object") { + throw new Error( + "React Component in warnForMissingKey should have a _store. " + + "This error is likely caused by a bug in React. Please file an issue." + ); + } // $FlowFixMe[cannot-write] unable to narrow type from mixed to writable object - if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) { - var context = newChild; - return createChild( - returnFiber, - readContextDuringReconcilation(returnFiber, context, lanes), - lanes - ); - } + child._store.validated = true; + var componentName = + getComponentNameFromFiber(returnFiber) || "Component"; - throwOnInvalidObjectType(returnFiber, newChild); + if (ownerHasKeyUseWarning[componentName]) { + return; } - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber); - } - } + ownerHasKeyUseWarning[componentName] = true; - return null; - } + error( + "Each child in a list should have a unique " + + '"key" prop. See https://reactjs.org/link/warning-keys for ' + + "more information." + ); + }; + } - function updateSlot(returnFiber, oldFiber, newChild, lanes) { - // Update the fiber if the keys match, otherwise return null. - var key = oldFiber !== null ? oldFiber.key : null; + function isReactClass(type) { + return type.prototype && type.prototype.isReactComponent; + } - 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; - } + function unwrapThenable(thenable) { + var index = thenableIndexCounter$1; + thenableIndexCounter$1 += 1; - return updateTextNode(returnFiber, oldFiber, "" + newChild, lanes); - } + if (thenableState$1 === null) { + thenableState$1 = createThenableState(); + } - 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 trackUsedThenable(thenableState$1, thenable, index); + } - case REACT_PORTAL_TYPE: { - if (newChild.key === key) { - return updatePortal(returnFiber, oldFiber, newChild, lanes); - } else { - return null; - } - } + function coerceRef(returnFiber, current, element) { + var mixedRef = element.ref; - case REACT_LAZY_TYPE: { - var payload = newChild._payload; - var init = newChild._init; - return updateSlot(returnFiber, oldFiber, init(payload), lanes); + 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"; + + 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 + ); + + didWarnAboutStringRefs[componentName] = true; } } + } - if (isArray(newChild) || getIteratorFn(newChild)) { - if (key !== null) { - return null; + if (element._owner) { + var owner = element._owner; + var inst; + + if (owner) { + var ownerFiber = owner; + + 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" + ); } - return updateFragment(returnFiber, oldFiber, newChild, lanes, null); - } // Usable node types - // - // Unwrap the inner value and recursively call this function again. + inst = ownerFiber.stateNode; + } - if (typeof newChild.then === "function") { - var thenable = newChild; - return updateSlot( - returnFiber, - oldFiber, - unwrapThenable(thenable), - lanes + 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; + + { + 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 - ) { - var context = newChild; - return updateSlot( - returnFiber, - oldFiber, - readContextDuringReconcilation(returnFiber, context, lanes), - lanes - ); + current !== null && + current.ref !== null && + typeof current.ref === "function" && + current.ref._stringRef === stringRef + ) { + return current.ref; } - throwOnInvalidObjectType(returnFiber, newChild); - } + var ref = function (value) { + var refs = resolvedInst.refs; - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber); - } - } + if (value === null) { + delete refs[stringRef]; + } else { + refs[stringRef] = value; + } + }; - return null; - } + 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." + ); + } - 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 (!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 (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: { - var _matchedFiber = - existingChildren.get( - newChild.key === null ? newIdx : newChild.key - ) || null; + return mixedRef; + } - return updateElement(returnFiber, _matchedFiber, newChild, lanes); - } + function throwOnInvalidObjectType(returnFiber, newChild) { + // $FlowFixMe[method-unbinding] + var childString = Object.prototype.toString.call(newChild); + throw new Error( + "Objects are not valid as a React child (found: " + + (childString === "[object Object]" + ? "object with keys {" + Object.keys(newChild).join(", ") + "}" + : childString) + + "). " + + "If you meant to render a collection of children, use an array " + + "instead." + ); + } - case REACT_PORTAL_TYPE: { - var _matchedFiber2 = - existingChildren.get( - newChild.key === null ? newIdx : newChild.key - ) || null; + function warnOnFunctionType(returnFiber) { + { + var componentName = + getComponentNameFromFiber(returnFiber) || "Component"; - return updatePortal(returnFiber, _matchedFiber2, newChild, lanes); - } + if (ownerHasFunctionTypeWarning[componentName]) { + return; + } - case REACT_LAZY_TYPE: - var payload = newChild._payload; - var init = newChild._init; - return updateFromMap( - existingChildren, - returnFiber, - newIdx, - init(payload), - lanes - ); - } + ownerHasFunctionTypeWarning[componentName] = true; - if (isArray(newChild) || getIteratorFn(newChild)) { - var _matchedFiber3 = existingChildren.get(newIdx) || null; + error( + "Functions are not valid as a React child. This may happen if " + + "you return a Component instead of from render. " + + "Or maybe you meant to call this function rather than return it." + ); + } + } - return updateFragment( - returnFiber, - _matchedFiber3, - newChild, - lanes, - null - ); - } // Usable node types - // - // Unwrap the inner value and recursively call this function again. + function resolveLazy(lazyType) { + var payload = lazyType._payload; + var init = lazyType._init; + return init(payload); + } // This wrapper function exists because I expect to clone the code in each path + // to be able to optimize each path individually by branching early. This needs + // a compiler or we can do it manually. Helpers that don't need this branching + // live outside of this function. - if (typeof newChild.then === "function") { - var thenable = newChild; - return updateFromMap( - existingChildren, - returnFiber, - newIdx, - unwrapThenable(thenable), - lanes - ); - } + function createChildReconciler(shouldTrackSideEffects) { + function deleteChild(returnFiber, childToDelete) { + if (!shouldTrackSideEffects) { + // Noop. + return; + } - if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) { - var context = newChild; - return updateFromMap( - existingChildren, - returnFiber, - newIdx, - readContextDuringReconcilation(returnFiber, context, lanes), - lanes - ); - } + var deletions = returnFiber.deletions; - throwOnInvalidObjectType(returnFiber, newChild); + if (deletions === null) { + returnFiber.deletions = [childToDelete]; + returnFiber.flags |= ChildDeletion; + } else { + deletions.push(childToDelete); } + } - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber); - } + function deleteRemainingChildren(returnFiber, currentFirstChild) { + if (!shouldTrackSideEffects) { + // Noop. + return null; + } // TODO: For the shouldClone case, this could be micro-optimized a bit by + // assuming that after the first child we've already added everything. + + var childToDelete = currentFirstChild; + + while (childToDelete !== null) { + deleteChild(returnFiber, childToDelete); + childToDelete = childToDelete.sibling; } return null; } - /** - * Warns if there is a duplicate or missing key - */ - function warnOnInvalidKey(child, knownKeys, returnFiber) { - { - if (typeof child !== "object" || child === null) { - return knownKeys; + 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; + + while (existingChild !== null) { + if (existingChild.key !== null) { + existingChildren.set(existingChild.key, existingChild); + } else { + existingChildren.set(existingChild.index, existingChild); } - switch (child.$$typeof) { - case REACT_ELEMENT_TYPE: - case REACT_PORTAL_TYPE: - warnForMissingKey(child, returnFiber); - var key = child.key; + existingChild = existingChild.sibling; + } - if (typeof key !== "string") { - break; - } + return existingChildren; + } - if (knownKeys === null) { - knownKeys = new Set(); - knownKeys.add(key); - break; - } + 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 (!knownKeys.has(key)) { - knownKeys.add(key); - break; - } + function placeChild(newFiber, lastPlacedIndex, newIndex) { + newFiber.index = newIndex; - 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 - ); - - break; - - case REACT_LAZY_TYPE: - var payload = child._payload; - var init = child._init; - warnOnInvalidKey(init(payload), knownKeys, returnFiber); - break; - } + if (!shouldTrackSideEffects) { + // During hydration, the useId algorithm needs to know which fibers are + // part of a list of children (arrays, iterators). + newFiber.flags |= Forked; + return lastPlacedIndex; } - return knownKeys; - } + var current = newFiber.alternate; - function reconcileChildrenArray( - returnFiber, - currentFirstChild, - newChildren, - lanes - ) { - // This algorithm can't optimize by searching from both ends since we - // don't have backpointers on fibers. I'm trying to see how far we can get - // with that model. If it ends up not being worth the tradeoffs, we can - // add it later. - // Even with a two ended optimization, we'd want to optimize for the case - // where there are few changes and brute force the comparison instead of - // going for the Map. It'd like to explore hitting that path first in - // forward-only mode and only go for the Map once we notice that we need - // lots of look ahead. This doesn't handle reversal as well as two ended - // search but that's unusual. Besides, for the two ended optimization to - // work on Iterables, we'd need to copy the whole set. - // In this first iteration, we'll just live with hitting the bad case - // (adding everything to a Map) in for every insert/move. - // If you change this code, also update reconcileChildrenIterator() which - // uses the same algorithm. - { - // First, validate keys. - var knownKeys = null; + if (current !== null) { + var oldIndex = current.index; - for (var i = 0; i < newChildren.length; i++) { - var child = newChildren[i]; - knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber); + if (oldIndex < lastPlacedIndex) { + // This is a move. + newFiber.flags |= Placement | PlacementDEV; + return lastPlacedIndex; + } else { + // This item can stay in place. + return oldIndex; } + } else { + // This is an insertion. + newFiber.flags |= Placement | PlacementDEV; + return lastPlacedIndex; } + } - var resultingFirstChild = null; - var previousNewFiber = null; - var oldFiber = currentFirstChild; - var lastPlacedIndex = 0; - var newIdx = 0; - var nextOldFiber = null; + 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; + } - for (; oldFiber !== null && newIdx < newChildren.length; newIdx++) { - if (oldFiber.index > newIdx) { - nextOldFiber = oldFiber; - oldFiber = null; - } else { - nextOldFiber = oldFiber.sibling; - } + return newFiber; + } - var newFiber = updateSlot( - returnFiber, - oldFiber, - 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 (newFiber === null) { - // TODO: This breaks on empty slots like null children. That's - // unfortunate because it triggers the slow path all the time. We need - // a better way to communicate whether this was a miss or null, - // boolean, undefined, etc. - if (oldFiber === null) { - oldFiber = nextOldFiber; - } + function updateElement(returnFiber, current, element, lanes) { + var elementType = element.type; - break; - } + if (elementType === REACT_FRAGMENT_TYPE) { + return updateFragment( + returnFiber, + current, + element.props.children, + lanes, + element.key + ); + } - 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 (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; - lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); + { + existing._debugSource = element._source; + existing._debugOwner = element._owner; + } - if (previousNewFiber === null) { - // TODO: Move out of the loop. This only happens for the first run. - resultingFirstChild = newFiber; - } else { - // TODO: Defer siblings if we're not at the right index for this slot. - // I.e. if we had null values before, then we want to defer this - // for each null value. However, we also don't want to call updateSlot - // with the previous one. - previousNewFiber.sibling = newFiber; + return existing; } + } // Insert - previousNewFiber = newFiber; - oldFiber = nextOldFiber; + var created = createFiberFromElement(element, returnFiber.mode, lanes); + created.ref = coerceRef(returnFiber, current, element); + created.return = returnFiber; + return created; + } + + 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; } + } - if (newIdx === newChildren.length) { - // We've reached the end of the new children. We can delete the rest. - deleteRemainingChildren(returnFiber, oldFiber); + 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; + } + } - return resultingFirstChild; + 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 (oldFiber === null) { - // If we don't have any more existing children we can choose a fast path - // since the rest will all be insertions. - for (; newIdx < newChildren.length; newIdx++) { - var _newFiber = createChild( - returnFiber, - newChildren[newIdx], - lanes - ); + if (typeof newChild === "object" && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: { + var _created = createFiberFromElement( + newChild, + returnFiber.mode, + lanes + ); - if (_newFiber === null) { - continue; + _created.ref = coerceRef(returnFiber, null, newChild); + _created.return = returnFiber; + return _created; } - lastPlacedIndex = placeChild(_newFiber, lastPlacedIndex, newIdx); + case REACT_PORTAL_TYPE: { + var _created2 = createFiberFromPortal( + newChild, + returnFiber.mode, + lanes + ); - if (previousNewFiber === null) { - // TODO: Move out of the loop. This only happens for the first run. - resultingFirstChild = _newFiber; - } else { - previousNewFiber.sibling = _newFiber; + _created2.return = returnFiber; + return _created2; } - previousNewFiber = _newFiber; + case REACT_LAZY_TYPE: { + var payload = newChild._payload; + var init = newChild._init; + return createChild(returnFiber, init(payload), lanes); + } } - return resultingFirstChild; - } // Add all children to a key map for quick lookups. - - var existingChildren = mapRemainingChildren(returnFiber, oldFiber); // Keep scanning and use the map to restore deleted items as moves. - - for (; newIdx < newChildren.length; newIdx++) { - var _newFiber2 = updateFromMap( - existingChildren, - returnFiber, - newIdx, - newChildren[newIdx], - lanes - ); - - if (_newFiber2 !== null) { - if (shouldTrackSideEffects) { - if (_newFiber2.alternate !== null) { - // The new fiber is a work in progress, but if there exists a - // current, that means that we reused the fiber. We need to delete - // it from the child list so that we don't add it to the deletion - // list. - existingChildren.delete( - _newFiber2.key === null ? newIdx : _newFiber2.key - ); - } - } + if (isArray(newChild) || getIteratorFn(newChild)) { + var _created3 = createFiberFromFragment( + newChild, + returnFiber.mode, + lanes, + null + ); - lastPlacedIndex = placeChild(_newFiber2, lastPlacedIndex, newIdx); + _created3.return = returnFiber; + return _created3; + } // Usable node types + // + // Unwrap the inner value and recursively call this function again. - if (previousNewFiber === null) { - resultingFirstChild = _newFiber2; - } else { - previousNewFiber.sibling = _newFiber2; - } + if (typeof newChild.then === "function") { + var thenable = newChild; + return createChild(returnFiber, unwrapThenable(thenable), lanes); + } - previousNewFiber = _newFiber2; + if ( + newChild.$$typeof === REACT_CONTEXT_TYPE || + newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE + ) { + var context = newChild; + return createChild( + returnFiber, + readContextDuringReconcilation(returnFiber, context, lanes), + lanes + ); } + + throwOnInvalidObjectType(returnFiber, newChild); } - 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 (typeof newChild === "function") { + warnOnFunctionType(returnFiber); + } } - return resultingFirstChild; + return null; } - function reconcileChildrenIterator( - returnFiber, - currentFirstChild, - newChildrenIterable, - lanes - ) { - // This is the same implementation as reconcileChildrenArray(), - // but using the iterator instead. - var iteratorFn = getIteratorFn(newChildrenIterable); + 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 iteratorFn !== "function") { - throw new Error( - "An object is not an iterable. This error is likely caused by a bug in " + - "React. Please file an issue." - ); + if ( + (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; + } + + return updateTextNode(returnFiber, oldFiber, "" + newChild, lanes); } - { - // 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: { + if (newChild.key === key) { + return updateElement(returnFiber, oldFiber, newChild, lanes); + } else { + return null; + } } - 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." - ); + case REACT_PORTAL_TYPE: { + if (newChild.key === key) { + return updatePortal(returnFiber, oldFiber, newChild, lanes); + } else { + return null; + } } - 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; - - var _step = _newChildren.next(); - - 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 updateSlot(returnFiber, oldFiber, init(payload), lanes); } } - } - - var newChildren = iteratorFn.call(newChildrenIterable); - - if (newChildren == null) { - throw new Error("An iterable object provided no iterator."); - } - - var resultingFirstChild = null; - var previousNewFiber = null; - var oldFiber = currentFirstChild; - var lastPlacedIndex = 0; - var newIdx = 0; - var nextOldFiber = null; - var step = newChildren.next(); - - for ( - ; - oldFiber !== null && !step.done; - newIdx++, step = newChildren.next() - ) { - if (oldFiber.index > newIdx) { - nextOldFiber = oldFiber; - oldFiber = null; - } else { - nextOldFiber = oldFiber.sibling; - } - - var newFiber = updateSlot(returnFiber, oldFiber, step.value, lanes); - 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) || getIteratorFn(newChild)) { + if (key !== null) { + return null; } - break; + return updateFragment(returnFiber, oldFiber, newChild, lanes, null); + } // Usable node types + // + // Unwrap the inner value and recursively call this function again. + + if (typeof newChild.then === "function") { + var thenable = newChild; + return updateSlot( + returnFiber, + oldFiber, + unwrapThenable(thenable), + lanes + ); } - if (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 updateSlot( + returnFiber, + oldFiber, + readContextDuringReconcilation(returnFiber, context, lanes), + lanes + ); } - lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); + throwOnInvalidObjectType(returnFiber, newChild); + } - 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 === "function") { + warnOnFunctionType(returnFiber); } - - previousNewFiber = newFiber; - oldFiber = nextOldFiber; } - if (step.done) { - // We've reached the end of the new children. We can delete the rest. - deleteRemainingChildren(returnFiber, oldFiber); + return null; + } - return resultingFirstChild; + 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 (oldFiber === null) { - // If we don't have any more existing children we can choose a fast path - // since the rest will all be insertions. - for (; !step.done; newIdx++, step = newChildren.next()) { - var _newFiber3 = createChild(returnFiber, step.value, lanes); + if (typeof newChild === "object" && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: { + var _matchedFiber = + existingChildren.get( + newChild.key === null ? newIdx : newChild.key + ) || null; - if (_newFiber3 === null) { - continue; + return updateElement(returnFiber, _matchedFiber, newChild, lanes); } - lastPlacedIndex = placeChild(_newFiber3, lastPlacedIndex, newIdx); + case REACT_PORTAL_TYPE: { + var _matchedFiber2 = + existingChildren.get( + newChild.key === null ? newIdx : newChild.key + ) || null; - if (previousNewFiber === null) { - // TODO: Move out of the loop. This only happens for the first run. - resultingFirstChild = _newFiber3; - } else { - previousNewFiber.sibling = _newFiber3; + return updatePortal(returnFiber, _matchedFiber2, newChild, lanes); } - previousNewFiber = _newFiber3; + case REACT_LAZY_TYPE: + var payload = newChild._payload; + var init = newChild._init; + return updateFromMap( + existingChildren, + returnFiber, + newIdx, + init(payload), + lanes + ); } - return resultingFirstChild; - } // Add all children to a key map for quick lookups. - - var existingChildren = mapRemainingChildren(returnFiber, oldFiber); // Keep scanning and use the map to restore deleted items as moves. - - for (; !step.done; newIdx++, step = newChildren.next()) { - var _newFiber4 = updateFromMap( - existingChildren, - returnFiber, - newIdx, - step.value, - 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 (isArray(newChild) || getIteratorFn(newChild)) { + var _matchedFiber3 = existingChildren.get(newIdx) || null; - lastPlacedIndex = placeChild(_newFiber4, lastPlacedIndex, newIdx); + return updateFragment( + returnFiber, + _matchedFiber3, + newChild, + lanes, + null + ); + } // Usable node types + // + // Unwrap the inner value and recursively call this function again. - if (previousNewFiber === null) { - resultingFirstChild = _newFiber4; - } else { - previousNewFiber.sibling = _newFiber4; - } + if (typeof newChild.then === "function") { + var thenable = newChild; + return updateFromMap( + existingChildren, + returnFiber, + newIdx, + unwrapThenable(thenable), + lanes + ); + } - previousNewFiber = _newFiber4; + if ( + newChild.$$typeof === REACT_CONTEXT_TYPE || + newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE + ) { + var context = newChild; + return updateFromMap( + existingChildren, + returnFiber, + newIdx, + readContextDuringReconcilation(returnFiber, context, lanes), + lanes + ); } - } - if (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); - }); + throwOnInvalidObjectType(returnFiber, newChild); } - 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. + { + if (typeof newChild === "function") { + warnOnFunctionType(returnFiber); + } + } - deleteRemainingChildren(returnFiber, currentFirstChild); - var created = createFiberFromText(textContent, returnFiber.mode, lanes); - created.return = returnFiber; - return created; + return null; } + /** + * Warns if there is a duplicate or missing key + */ - function reconcileSingleElement( - returnFiber, - currentFirstChild, - element, - lanes - ) { - var key = element.key; - var child = currentFirstChild; + function warnOnInvalidKey(child, knownKeys, returnFiber) { + { + if (typeof child !== "object" || child === null) { + return knownKeys; + } - 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; + switch (child.$$typeof) { + case REACT_ELEMENT_TYPE: + case REACT_PORTAL_TYPE: + warnForMissingKey(child, returnFiber); + var key = child.key; - if (elementType === REACT_FRAGMENT_TYPE) { - if (child.tag === Fragment) { - deleteRemainingChildren(returnFiber, child.sibling); - var existing = useFiber(child, element.props.children); - existing.return = returnFiber; + if (typeof key !== "string") { + break; + } - { - existing._debugSource = element._source; - existing._debugOwner = element._owner; - } + if (knownKeys === null) { + knownKeys = new Set(); + knownKeys.add(key); + break; + } - return existing; + if (!knownKeys.has(key)) { + knownKeys.add(key); + break; } - } 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); + 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 + ); - _existing.ref = coerceRef(returnFiber, child, element); - _existing.return = returnFiber; + break; - { - _existing._debugSource = element._source; - _existing._debugOwner = element._owner; - } + case REACT_LAZY_TYPE: + var payload = child._payload; + var init = child._init; + warnOnInvalidKey(init(payload), knownKeys, returnFiber); + break; + } + } - return _existing; - } - } // Didn't match. + return knownKeys; + } - deleteRemainingChildren(returnFiber, child); - break; - } else { - deleteChild(returnFiber, child); - } - - child = child.sibling; - } - - if (element.type === REACT_FRAGMENT_TYPE) { - var created = createFiberFromFragment( - element.props.children, - returnFiber.mode, - lanes, - element.key - ); - created.return = returnFiber; - return created; - } else { - var _created4 = createFiberFromElement( - element, - returnFiber.mode, - lanes - ); - - _created4.ref = coerceRef(returnFiber, currentFirstChild, element); - _created4.return = returnFiber; - return _created4; - } - } - - function reconcileSinglePortal( + function reconcileChildrenArray( returnFiber, currentFirstChild, - portal, + newChildren, lanes ) { - var key = portal.key; - var child = currentFirstChild; + // 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; - while (child !== null) { - // TODO: If key === null and child.key === null, then this only applies to - // the first item in the list. - if (child.key === key) { - if ( - child.tag === HostPortal && - child.stateNode.containerInfo === portal.containerInfo && - child.stateNode.implementation === portal.implementation - ) { - deleteRemainingChildren(returnFiber, child.sibling); - var existing = useFiber(child, portal.children || []); - existing.return = returnFiber; - return existing; - } else { - deleteRemainingChildren(returnFiber, child); - break; - } - } else { - deleteChild(returnFiber, child); + for (var i = 0; i < newChildren.length; i++) { + var child = newChildren[i]; + knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber); } - - child = child.sibling; } - var created = createFiberFromPortal(portal, returnFiber.mode, lanes); - created.return = returnFiber; - return created; - } // This API will tag the children with the side-effect of the reconciliation - // itself. They will be added to the side-effect list as we pass through the - // children and the parent. - - function reconcileChildFibersImpl( - returnFiber, - currentFirstChild, - newChild, - lanes - ) { - // This function is not recursive. - // If the top level item is an array, we treat it as a set of children, - // not as a fragment. Nested arrays on the other hand will be treated as - // fragment nodes. Recursion happens at the normal flow. - // Handle top level unkeyed fragments as if they were arrays. - // This leads to an ambiguity between <>{[...]} and <>.... - // We treat the ambiguous cases above the same. - // TODO: Let's use recursion like we do for Usable nodes? - var isUnkeyedTopLevelFragment = - typeof newChild === "object" && - newChild !== null && - newChild.type === REACT_FRAGMENT_TYPE && - newChild.key === null; - - if (isUnkeyedTopLevelFragment) { - newChild = newChild.props.children; - } // Handle object types + var resultingFirstChild = null; + var previousNewFiber = null; + var oldFiber = currentFirstChild; + var lastPlacedIndex = 0; + var newIdx = 0; + var nextOldFiber = null; - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: - return placeSingleChild( - reconcileSingleElement( - 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_PORTAL_TYPE: - return placeSingleChild( - reconcileSinglePortal( - returnFiber, - currentFirstChild, - newChild, - lanes - ) - ); + var newFiber = updateSlot( + returnFiber, + oldFiber, + newChildren[newIdx], + lanes + ); - case REACT_LAZY_TYPE: - var payload = newChild._payload; - var init = newChild._init; // TODO: This function is supposed to be non-recursive. + if (newFiber === null) { + // TODO: This breaks on empty slots like null children. That's + // unfortunate because it triggers the slow path all the time. We need + // a better way to communicate whether this was a miss or null, + // boolean, undefined, etc. + if (oldFiber === null) { + oldFiber = nextOldFiber; + } - return reconcileChildFibers( - returnFiber, - currentFirstChild, - init(payload), - lanes - ); + break; } - if (isArray(newChild)) { - return reconcileChildrenArray( - returnFiber, - currentFirstChild, - newChild, - 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 (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. + lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); - if (typeof newChild.then === "function") { - var thenable = newChild; - return reconcileChildFibersImpl( - returnFiber, - currentFirstChild, - unwrapThenable(thenable), - lanes - ); + 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 ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) { - var context = newChild; - return reconcileChildFibersImpl( - returnFiber, - currentFirstChild, - readContextDuringReconcilation(returnFiber, context, lanes), - lanes - ); - } + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } - throwOnInvalidObjectType(returnFiber, newChild); + if (newIdx === newChildren.length) { + // We've reached the end of the new children. We can delete the rest. + deleteRemainingChildren(returnFiber, oldFiber); + + return resultingFirstChild; } - if ( - (typeof newChild === "string" && newChild !== "") || - typeof newChild === "number" - ) { - return placeSingleChild( - reconcileSingleTextNode( + 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, - currentFirstChild, - "" + newChild, + newChildren[newIdx], lanes - ) - ); - } + ); - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber); - } - } // Remaining cases are all treated as empty. + if (_newFiber === null) { + continue; + } - return deleteRemainingChildren(returnFiber, currentFirstChild); - } + lastPlacedIndex = placeChild(_newFiber, lastPlacedIndex, newIdx); - 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 (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = _newFiber; + } else { + previousNewFiber.sibling = _newFiber; + } - return firstChildFiber; - } + previousNewFiber = _newFiber; + } - return reconcileChildFibers; - } + return resultingFirstChild; + } // Add all children to a key map for quick lookups. - 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."); - } + var existingChildren = mapRemainingChildren(returnFiber, oldFiber); // Keep scanning and use the map to restore deleted items as moves. - if (workInProgress.child === null) { - return; - } + for (; newIdx < newChildren.length; newIdx++) { + var _newFiber2 = updateFromMap( + existingChildren, + returnFiber, + newIdx, + newChildren[newIdx], + lanes + ); - var currentChild = workInProgress.child; - var newChild = createWorkInProgress( - currentChild, - currentChild.pendingProps - ); - workInProgress.child = newChild; - newChild.return = workInProgress; + 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 + ); + } + } - while (currentChild.sibling !== null) { - currentChild = currentChild.sibling; - newChild = newChild.sibling = createWorkInProgress( - currentChild, - currentChild.pendingProps - ); - newChild.return = workInProgress; - } + lastPlacedIndex = placeChild(_newFiber2, lastPlacedIndex, newIdx); - newChild.sibling = null; - } // Reset a workInProgress child set to prepare it for a second pass. + if (previousNewFiber === null) { + resultingFirstChild = _newFiber2; + } else { + previousNewFiber.sibling = _newFiber2; + } - function resetChildFibers(workInProgress, lanes) { - var child = workInProgress.child; + previousNewFiber = _newFiber2; + } + } - while (child !== null) { - resetWorkInProgress(child, lanes); - child = child.sibling; + 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; } - } - // TODO: This isn't being used yet, but it's intended to replace the - // InvisibleParentContext that is currently managed by SuspenseContext. + function reconcileChildrenIterator( + returnFiber, + currentFirstChild, + newChildrenIterable, + lanes + ) { + // This is the same implementation as reconcileChildrenArray(), + // but using the iterator instead. + var iteratorFn = getIteratorFn(newChildrenIterable); - 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 (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." + ); + } - 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; - } + { + // 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." + ); + } - // suspends, i.e. it's the nearest `catch` block on the stack. + didWarnAboutGenerators = true; + } // Warn about using Maps as children - 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 (newChildrenIterable.entries === iteratorFn) { + if (!didWarnAboutMaps) { + error( + "Using Maps as children is not supported. " + + "Use an array of keyed ReactElements 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. + didWarnAboutMaps = true; + } // First, validate keys. + // We'll get a different iterator later for the main pass. - pushSuspenseListContext( - handler, - setDefaultShallowSuspenseListContext(suspenseStackCursor.current) - ); // Experimental feature: Some Suspense boundaries are marked as having an - // to push a nested Suspense handler, because it will get replaced by the - // outer fallback, anyway. Consider this as a future optimization. + var _newChildren = iteratorFn.call(newChildrenIterable); - push(suspenseHandlerStackCursor, handler, handler); + if (_newChildren) { + var knownKeys = null; - if (shellBoundary === null) { - if (current === null || isCurrentTreeHidden()) { - // This boundary is not visible in the current UI. - shellBoundary = handler; - } else { - var prevState = current.memoizedState; + var _step = _newChildren.next(); - if (prevState !== null) { - // This boundary is showing a fallback in the current UI. - shellBoundary = handler; + for (; !_step.done; _step = _newChildren.next()) { + var child = _step.value; + knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber); + } } } - } - } - function pushFallbackTreeSuspenseHandler(fiber) { - // We're about to render the fallback. If something in the fallback suspends, - // it's akin to throwing inside of a `catch` block. This boundary should not - // capture. Reuse the existing handler on the stack. - reuseSuspenseHandlerOnStack(fiber); - } - function pushOffscreenSuspenseHandler(fiber) { - if (fiber.tag === OffscreenComponent) { - // A SuspenseList context is only pushed here to avoid a push/pop mismatch. - // Reuse the current value on the stack. - // TODO: We can avoid needing to push here by by forking popSuspenseHandler - // into separate functions for Suspense and Offscreen. - pushSuspenseListContext(fiber, suspenseStackCursor.current); - push(suspenseHandlerStackCursor, fiber, fiber); - - if (shellBoundary !== null); - else { - var current = fiber.alternate; - if (current !== null) { - var prevState = current.memoizedState; + var newChildren = iteratorFn.call(newChildrenIterable); - if (prevState !== null) { - // This is the first boundary in the stack that's already showing - // a fallback. So everything outside is considered the shell. - shellBoundary = fiber; - } - } + if (newChildren == null) { + throw new Error("An iterable object provided no iterator."); } - } else { - // This is a LegacyHidden component. - reuseSuspenseHandlerOnStack(fiber); - } - } - function reuseSuspenseHandlerOnStack(fiber) { - pushSuspenseListContext(fiber, suspenseStackCursor.current); - push(suspenseHandlerStackCursor, getSuspenseHandler(), fiber); - } - function getSuspenseHandler() { - return suspenseHandlerStackCursor.current; - } - function popSuspenseHandler(fiber) { - pop(suspenseHandlerStackCursor, fiber); - - if (shellBoundary === fiber) { - // Popping back into the shell. - shellBoundary = null; - } - - popSuspenseListContext(fiber); - } // SuspenseList context - // TODO: Move to a separate module? We may change the SuspenseList - // implementation to hide/show in the commit phase, anyway. - - var DefaultSuspenseContext = 0; - var SubtreeSuspenseContextMask = 1; // ForceSuspenseFallback can be used by SuspenseList to force newly added - // items into their fallback state during one of the render passes. - var ForceSuspenseFallback = 2; - var suspenseStackCursor = createCursor(DefaultSuspenseContext); - function hasSuspenseListContext(parentContext, flag) { - return (parentContext & flag) !== 0; - } - function setDefaultShallowSuspenseListContext(parentContext) { - return parentContext & SubtreeSuspenseContextMask; - } - function setShallowSuspenseListContext(parentContext, shallowContext) { - return (parentContext & SubtreeSuspenseContextMask) | shallowContext; - } - function pushSuspenseListContext(fiber, newContext) { - push(suspenseStackCursor, newContext, fiber); - } - function popSuspenseListContext(fiber) { - pop(suspenseStackCursor, fiber); - } + 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 (!enableDeferRootSchedulingToMicrotask) { - // While this flag is disabled, we schedule the render task immediately - // instead of waiting a microtask. - // TODO: We need to land enableDeferRootSchedulingToMicrotask ASAP to - // unblock additional features we have planned. - scheduleTaskForRootDuringMicrotask(root, now$1()); + return resultingFirstChild; } - if (ReactCurrentActQueue$2.isBatchingLegacy && root.tag === LegacyRoot) { - // Special `act` case: Record whenever a legacy update is scheduled. - ReactCurrentActQueue$2.didScheduleLegacyUpdate = true; - } - } - function flushSyncWorkOnAllRoots() { - // This is allowed to be called synchronously, but the caller should check - // the execution context first. - flushSyncWorkAcrossRoots_impl(false); - } - function flushSyncWorkOnLegacyRootsOnly() { - // This is allowed to be called synchronously, but the caller should check - // the execution context first. - flushSyncWorkAcrossRoots_impl(true); - } + function 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. - function flushSyncWorkAcrossRoots_impl(onlyLegacy) { - if (isFlushingWork) { - // Prevent reentrancy. - // TODO: Is this overly defensive? The callers must check the execution - // context first regardless. - return; + 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. - - var didPerformSomeWork; - var errors = null; - isFlushingWork = true; + function reconcileSingleElement( + returnFiber, + currentFirstChild, + element, + lanes + ) { + var key = element.key; + var child = currentFirstChild; - do { - didPerformSomeWork = false; - var root = firstScheduledRoot; + 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; - while (root !== null) { - if (onlyLegacy && root.tag !== LegacyRoot); - else { - var workInProgressRoot = getWorkInProgressRoot(); - var workInProgressRootRenderLanes = - getWorkInProgressRootRenderLanes(); - var nextLanes = getNextLanes( - root, - root === workInProgressRoot - ? workInProgressRootRenderLanes - : NoLanes - ); + if (elementType === REACT_FRAGMENT_TYPE) { + if (child.tag === Fragment) { + deleteRemainingChildren(returnFiber, child.sibling); + var existing = useFiber(child, element.props.children); + existing.return = returnFiber; - 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); + { + existing._debugSource = element._source; + existing._debugOwner = element._owner; } + + 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); - root = root.next; - } - } while (didPerformSomeWork); + var _existing = useFiber(child, element.props); - 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. + _existing.ref = coerceRef(returnFiber, child, element); + _existing.return = returnFiber; - 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])); - } + { + _existing._debugSource = element._source; + _existing._debugOwner = element._owner; + } - var firstError = errors[0]; - throw firstError; + return _existing; + } + } // Didn't match. + + deleteRemainingChildren(returnFiber, child); + break; + } else { + deleteChild(returnFiber, child); } + + child = child.sibling; + } + + if (element.type === REACT_FRAGMENT_TYPE) { + var created = createFiberFromFragment( + element.props.children, + returnFiber.mode, + lanes, + element.key + ); + created.return = returnFiber; + return created; } else { - var error = errors[0]; - throw error; + var _created4 = createFiberFromElement( + element, + returnFiber.mode, + lanes + ); + + _created4.ref = coerceRef(returnFiber, currentFirstChild, element); + _created4.return = returnFiber; + return _created4; } } - } - function throwError(error) { - throw error; - } + function reconcileSinglePortal( + returnFiber, + currentFirstChild, + portal, + lanes + ) { + var key = portal.key; + var child = currentFirstChild; - function processRootScheduleInMicrotask() { - // This function is always called inside a microtask. It should never be - // called synchronously. - didScheduleMicrotask = false; + 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); + } - { - didScheduleMicrotask_act = false; - } // We'll recompute this as we iterate through all the roots and schedule them. + child = child.sibling; + } - mightHavePendingSyncWork = false; - var currentTime = now$1(); - var prev = null; - var root = firstScheduledRoot; + 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. - while (root !== null) { - var next = root.next; + function reconcileChildFibersImpl( + returnFiber, + currentFirstChild, + newChild, + lanes + ) { + // This function is not recursive. + // If the top level item is an array, we treat it as a set of children, + // not as a fragment. Nested arrays on the other hand will be treated as + // fragment nodes. Recursion happens at the normal flow. + // Handle top level unkeyed fragments as if they were arrays. + // This leads to an ambiguity between <>{[...]} and <>.... + // We treat the ambiguous cases above the same. + // TODO: Let's use recursion like we do for Usable nodes? + var isUnkeyedTopLevelFragment = + typeof newChild === "object" && + newChild !== null && + newChild.type === REACT_FRAGMENT_TYPE && + newChild.key === null; - if ( - 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 (isUnkeyedTopLevelFragment) { + newChild = newChild.props.children; + } // Handle object types - var nextLanes = scheduleTaskForRootDuringMicrotask(root, currentTime); + if (typeof newChild === "object" && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return placeSingleChild( + reconcileSingleElement( + 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_PORTAL_TYPE: + return placeSingleChild( + reconcileSinglePortal( + returnFiber, + currentFirstChild, + newChild, + lanes + ) + ); - if (prev === null) { - // This is the new head of the list - firstScheduledRoot = next; - } else { - prev.next = next; - } + case REACT_LAZY_TYPE: + var payload = newChild._payload; + var init = newChild._init; // TODO: This function is supposed to be non-recursive. - if (next === null) { - // This is the new tail of the list - lastScheduledRoot = prev; + return reconcileChildFibers( + returnFiber, + currentFirstChild, + init(payload), + lanes + ); } - } else { - // This root still has work. Keep it in the list. - prev = root; - if (includesSyncLane(nextLanes)) { - mightHavePendingSyncWork = true; + if (isArray(newChild)) { + return reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChild, + lanes + ); } - } - root = next; - } - - currentEventTransitionLane = NoLane; // At the end of the microtask, flush any pending synchronous work. This has - // to come at the end, because it does actual rendering work that might throw. - - flushSyncWorkOnAllRoots(); - } - - function scheduleTaskForRootDuringMicrotask(root, currentTime) { - // This function is always called inside a microtask, or at the very end of a - // rendering task right before we yield to the main thread. It should never be - // called synchronously. - // - // TODO: Unless enableDeferRootSchedulingToMicrotask is off. We need to land - // that ASAP to unblock additional features we have planned. - // - // This function also never performs React work synchronously; it should - // only schedule work to be performed later, in a separate task or microtask. - // Check if any lanes are being starved by other work. If so, mark them as - // expired so we know to work on those next. - markStarvedLanesAsExpired(root, currentTime); // Determine the next lanes to work on, and their priority. - - var workInProgressRoot = getWorkInProgressRoot(); - var workInProgressRootRenderLanes = getWorkInProgressRootRenderLanes(); - var nextLanes = getNextLanes( - root, - root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes - ); - var existingCallbackNode = root.callbackNode; + if (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 ( - // 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); - } + if (typeof newChild.then === "function") { + var thenable = newChild; + return reconcileChildFibersImpl( + returnFiber, + currentFirstChild, + unwrapThenable(thenable), + lanes + ); + } - root.callbackNode = null; - root.callbackPriority = NoLane; - return NoLane; - } // Schedule a new callback in the host environment. + if ( + newChild.$$typeof === REACT_CONTEXT_TYPE || + newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE + ) { + var context = newChild; + return reconcileChildFibersImpl( + returnFiber, + currentFirstChild, + readContextDuringReconcilation(returnFiber, context, lanes), + lanes + ); + } - if (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); + throwOnInvalidObjectType(returnFiber, newChild); } - root.callbackPriority = SyncLane; - root.callbackNode = null; - return SyncLane; - } else { - // We use the highest priority lane to represent the priority of the callback. - var existingCallbackPriority = root.callbackPriority; - var newCallbackPriority = getHighestPriorityLane(nextLanes); - if ( - newCallbackPriority === existingCallbackPriority && // Special case related to `act`. If the currently scheduled task is a - // Scheduler task, rather than an `act` task, cancel it and re-schedule - // on the `act` queue. - !( - ReactCurrentActQueue$2.current !== null && - existingCallbackNode !== fakeActCallbackNode$1 - ) + (typeof newChild === "string" && newChild !== "") || + typeof newChild === "number" ) { - // 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 placeSingleChild( + reconcileSingleTextNode( + returnFiber, + currentFirstChild, + "" + newChild, + lanes + ) + ); } - var schedulerPriorityLevel; + { + if (typeof newChild === "function") { + warnOnFunctionType(returnFiber); + } + } // Remaining cases are all treated as empty. - switch (lanesToEventPriority(nextLanes)) { - case DiscreteEventPriority: - schedulerPriorityLevel = ImmediatePriority; - break; + return deleteRemainingChildren(returnFiber, currentFirstChild); + } - case ContinuousEventPriority: - schedulerPriorityLevel = UserBlockingPriority; - break; + 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. - case DefaultEventPriority: - schedulerPriorityLevel = NormalPriority; - break; + return firstChildFiber; + } - case IdleEventPriority: - schedulerPriorityLevel = IdlePriority; - break; + return reconcileChildFibers; + } - default: - schedulerPriorityLevel = NormalPriority; - break; - } + 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."); + } - var newCallbackNode = scheduleCallback$1( - schedulerPriorityLevel, - performConcurrentWorkOnRoot.bind(null, root) + if (workInProgress.child === null) { + return; + } + + var currentChild = workInProgress.child; + var newChild = createWorkInProgress( + currentChild, + currentChild.pendingProps + ); + workInProgress.child = newChild; + newChild.return = workInProgress; + + while (currentChild.sibling !== null) { + currentChild = currentChild.sibling; + newChild = newChild.sibling = createWorkInProgress( + currentChild, + currentChild.pendingProps ); - root.callbackPriority = newCallbackPriority; - root.callbackNode = newCallbackNode; - return newCallbackPriority; + newChild.return = workInProgress; } - } - 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()); + newChild.sibling = null; + } // Reset a workInProgress child set to prepare it for a second pass. - 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); + function resetChildFibers(workInProgress, lanes) { + var child = workInProgress.child; + + while (child !== null) { + resetWorkInProgress(child, lanes); + child = child.sibling; } + } - return null; + // TODO: This isn't being used yet, but it's intended to replace the + // InvisibleParentContext that is currently managed by SuspenseContext. + + var currentTreeHiddenStackCursor = createCursor(null); + var prevEntangledRenderLanesCursor = createCursor(NoLanes); + function pushHiddenContext(fiber, context) { + var prevEntangledRenderLanes = getEntangledRenderLanes(); + push(prevEntangledRenderLanesCursor, prevEntangledRenderLanes, fiber); + push(currentTreeHiddenStackCursor, context, fiber); // When rendering a subtree that's currently hidden, we must include all + // lanes that would have rendered if the hidden subtree hadn't been deferred. + // That is, in order to reveal content from hidden -> visible, we must commit + // all the updates that we skipped when we originally hid the tree. + + setEntangledRenderLanes( + mergeLanes(prevEntangledRenderLanes, context.baseLanes) + ); + } + function reuseHiddenContextOnStack(fiber) { + // This subtree is not currently hidden, so we don't need to add any lanes + // to the render lanes. But we still need to push something to avoid a + // context mismatch. Reuse the existing context on the stack. + push(prevEntangledRenderLanesCursor, getEntangledRenderLanes(), fiber); + push( + currentTreeHiddenStackCursor, + currentTreeHiddenStackCursor.current, + fiber + ); + } + function popHiddenContext(fiber) { + // Restore the previous render lanes from the stack + setEntangledRenderLanes(prevEntangledRenderLanesCursor.current); + pop(currentTreeHiddenStackCursor, fiber); + pop(prevEntangledRenderLanesCursor, fiber); + } + function isCurrentTreeHidden() { + return currentTreeHiddenStackCursor.current !== null; } - 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 (supportsMicrotasks) { - scheduleMicrotask(function () { - // In Safari, appending an iframe forces microtasks to run. - // https://github.com/facebook/react/issues/22459 - // We don't support running callbacks in the middle of render - // or commit so we need to check against that. - var executionContext = getExecutionContext(); + if (shellBoundary !== null); + else { + var current = fiber.alternate; - if ( - (executionContext & (RenderContext | CommitContext)) !== - NoContext - ) { - // Note that this would still prematurely flush the callbacks - // if this happens outside render or commit phase (e.g. in an event). - // Intentionally using a macrotask instead of a microtask here. This is - // wrong semantically but it prevents an infinite loop. The bug is - // Safari's, not ours, so we just do our best to not crash even though - // the behavior isn't completely correct. - scheduleCallback$2(ImmediatePriority, cb); - return; - } + if (current !== null) { + var prevState = current.memoizedState; - cb(); - }); + 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 { - // If microtasks are not supported, use Scheduler. - scheduleCallback$2(ImmediatePriority, cb); + // 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. - // 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 DefaultSuspenseContext = 0; + var SubtreeSuspenseContextMask = 1; // ForceSuspenseFallback can be used by SuspenseList to force newly added + // items into their fallback state during one of the render passes. - var currentEntangledListeners = null; // The number of pending async actions in the entangled scope. + 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 currentEntangledPendingCount = 0; // The transition lane shared by all updates 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 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; + function findFirstSuspended(row) { + var node = row; - 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; @@ -11515,6 +11507,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 @@ -11557,6 +11550,17 @@ to return true:wantsResponderID| | ); markSkippedUpdateLanes(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; + } // Check if this is an optimistic update. + { // This is not an optimistic update, and we're going to apply it now. // But, if there were earlier updates that were skipped, we need to @@ -11603,7 +11607,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; @@ -12422,7 +12442,7 @@ to return true:wantsResponderID| | } try { - var returnValue, thenable, entangledResult, _entangledResult2; + var returnValue, thenable, thenableForFinishedState; if (enableAsyncActions); else { // Async actions are not enabled. @@ -14634,6 +14654,7 @@ to return true:wantsResponderID| | // process them now. processUpdateQueue(workInProgress, newProps, instance, renderLanes); + suspendIfUpdateReadFromEntangledAsyncAction(); instance.state = workInProgress.memoizedState; } @@ -14701,6 +14722,7 @@ to return true:wantsResponderID| | var oldState = workInProgress.memoizedState; var newState = (instance.state = oldState); processUpdateQueue(workInProgress, newProps, instance, renderLanes); + suspendIfUpdateReadFromEntangledAsyncAction(); newState = workInProgress.memoizedState; if ( @@ -14853,6 +14875,7 @@ to return true:wantsResponderID| | var oldState = workInProgress.memoizedState; var newState = (instance.state = oldState); processUpdateQueue(workInProgress, newProps, instance, renderLanes); + suspendIfUpdateReadFromEntangledAsyncAction(); newState = workInProgress.memoizedState; if ( @@ -15426,7 +15449,7 @@ to return true:wantsResponderID| | } } - return; + return false; } case OffscreenComponent: { @@ -15461,7 +15484,7 @@ to return true:wantsResponderID| | attachPingListener(root, wakeable, rootRenderLanes); } - return; + return false; } } } @@ -15484,7 +15507,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( @@ -15504,6 +15527,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 { @@ -15519,7 +15548,7 @@ to return true:wantsResponderID| | lane ); enqueueCapturedUpdate(workInProgress, update); - return; + return false; } case ClassComponent: @@ -15548,7 +15577,7 @@ to return true:wantsResponderID| | ); enqueueCapturedUpdate(workInProgress, _update); - return; + return false; } break; @@ -15556,6 +15585,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 @@ -16530,6 +16561,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; @@ -24801,7 +24836,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; } } @@ -24906,7 +24941,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; } @@ -24971,7 +25006,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; @@ -25036,7 +25071,7 @@ to return true:wantsResponderID| | workInProgressSuspendedReason = NotSuspended; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(unitOfWork, thrownValue); + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); break; } @@ -25047,7 +25082,7 @@ to return true:wantsResponderID| | // always unwind. workInProgressSuspendedReason = NotSuspended; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(unitOfWork, thrownValue); + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); break; } @@ -25275,7 +25310,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. // @@ -25284,40 +25319,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) { @@ -25337,6 +25365,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. @@ -27838,7 +27882,7 @@ to return true:wantsResponderID| | return root; } - var ReactVersion = "18.3.0-canary-58de2f66"; + var ReactVersion = "18.3.0-canary-2ee1c8bb"; function createPortal$1( children, diff --git a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-prod.fb.js b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-prod.fb.js index f2ad0a4382ffc..b0d2c4209eace 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-prod.fb.js +++ b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-prod.fb.js @@ -7,7 +7,7 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<<6e407622da5495d67c0b1b946f5635a4>> + * @generated SignedSource<<664105eacf4c13d26fd479b8d2c34d8a>> */ "use strict"; @@ -940,7 +940,7 @@ eventPluginOrder = Array.prototype.slice.call([ "ReactNativeBridgeEventPlugin" ]); recomputePluginOrdering(); -var injectedNamesToPlugins$jscomp$inline_235 = { +var injectedNamesToPlugins$jscomp$inline_236 = { ResponderEventPlugin: ResponderEventPlugin, ReactNativeBridgeEventPlugin: { eventTypes: {}, @@ -986,32 +986,32 @@ var injectedNamesToPlugins$jscomp$inline_235 = { } } }, - isOrderingDirty$jscomp$inline_236 = !1, - pluginName$jscomp$inline_237; -for (pluginName$jscomp$inline_237 in injectedNamesToPlugins$jscomp$inline_235) + isOrderingDirty$jscomp$inline_237 = !1, + pluginName$jscomp$inline_238; +for (pluginName$jscomp$inline_238 in injectedNamesToPlugins$jscomp$inline_236) if ( - injectedNamesToPlugins$jscomp$inline_235.hasOwnProperty( - pluginName$jscomp$inline_237 + injectedNamesToPlugins$jscomp$inline_236.hasOwnProperty( + pluginName$jscomp$inline_238 ) ) { - var pluginModule$jscomp$inline_238 = - injectedNamesToPlugins$jscomp$inline_235[pluginName$jscomp$inline_237]; + var pluginModule$jscomp$inline_239 = + injectedNamesToPlugins$jscomp$inline_236[pluginName$jscomp$inline_238]; if ( - !namesToPlugins.hasOwnProperty(pluginName$jscomp$inline_237) || - namesToPlugins[pluginName$jscomp$inline_237] !== - pluginModule$jscomp$inline_238 + !namesToPlugins.hasOwnProperty(pluginName$jscomp$inline_238) || + namesToPlugins[pluginName$jscomp$inline_238] !== + pluginModule$jscomp$inline_239 ) { - if (namesToPlugins[pluginName$jscomp$inline_237]) + if (namesToPlugins[pluginName$jscomp$inline_238]) throw Error( "EventPluginRegistry: Cannot inject two different event plugins using the same name, `" + - (pluginName$jscomp$inline_237 + "`.") + (pluginName$jscomp$inline_238 + "`.") ); - namesToPlugins[pluginName$jscomp$inline_237] = - pluginModule$jscomp$inline_238; - isOrderingDirty$jscomp$inline_236 = !0; + namesToPlugins[pluginName$jscomp$inline_238] = + pluginModule$jscomp$inline_239; + isOrderingDirty$jscomp$inline_237 = !0; } } -isOrderingDirty$jscomp$inline_236 && recomputePluginOrdering(); +isOrderingDirty$jscomp$inline_237 && recomputePluginOrdering(); var emptyObject$1 = {}, removedKeys = null, removedKeyCount = 0, @@ -2144,6 +2144,226 @@ 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), + scheduleImmediateTask(processRootScheduleInMicrotask)); + enableDeferRootSchedulingToMicrotask || + 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++) + scheduleImmediateTask(throwError.bind(null, errors[onlyLegacy])); + } + 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 scheduleImmediateTask(cb) { + useMicrotasksForSchedulingInFabric + ? scheduleMicrotask(function () { + 0 !== (executionContext & 6) + ? scheduleCallback$2(ImmediatePriority, cb) + : cb(); + }) + : scheduleCallback$2(ImmediatePriority, cb); +} +function requestTransitionLane() { + if (0 === currentEventTransitionLane) { + var lane = nextTransitionLane; + nextTransitionLane <<= 1; + 0 === (nextTransitionLane & 4194176) && (nextTransitionLane = 128); + currentEventTransitionLane = lane; + } + return currentEventTransitionLane; +} var hasForceUpdate = !1; function initializeUpdateQueue(fiber) { fiber.updateQueue = { @@ -3351,227 +3571,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), - scheduleImmediateTask(processRootScheduleInMicrotask)); - enableDeferRootSchedulingToMicrotask || - 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$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++) - scheduleImmediateTask(throwError.bind(null, errors[onlyLegacy])); - } - 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 scheduleImmediateTask(cb) { - useMicrotasksForSchedulingInFabric - ? scheduleMicrotask(function () { - 0 !== (executionContext & 6) - ? scheduleCallback$2(ImmediatePriority, cb) - : cb(); - }) - : scheduleCallback$2(ImmediatePriority, cb); -} -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, @@ -4666,6 +4665,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." @@ -5969,14 +6115,14 @@ function cutOffTailIfNeeded(renderState, hasRenderedATailFallback) { break; case "collapsed": lastTailNode = renderState.tail; - for (var lastTailNode$64 = null; null !== lastTailNode; ) - null !== lastTailNode.alternate && (lastTailNode$64 = lastTailNode), + for (var lastTailNode$65 = null; null !== lastTailNode; ) + null !== lastTailNode.alternate && (lastTailNode$65 = lastTailNode), (lastTailNode = lastTailNode.sibling); - null === lastTailNode$64 + null === lastTailNode$65 ? hasRenderedATailFallback || null === renderState.tail ? (renderState.tail = null) : (renderState.tail.sibling = null) - : (lastTailNode$64.sibling = null); + : (lastTailNode$65.sibling = null); } } function bubbleProperties(completedWork) { @@ -5986,19 +6132,19 @@ function bubbleProperties(completedWork) { newChildLanes = 0, subtreeFlags = 0; if (didBailout) - for (var child$65 = completedWork.child; null !== child$65; ) - (newChildLanes |= child$65.lanes | child$65.childLanes), - (subtreeFlags |= child$65.subtreeFlags & 31457280), - (subtreeFlags |= child$65.flags & 31457280), - (child$65.return = completedWork), - (child$65 = child$65.sibling); + for (var child$66 = completedWork.child; null !== child$66; ) + (newChildLanes |= child$66.lanes | child$66.childLanes), + (subtreeFlags |= child$66.subtreeFlags & 31457280), + (subtreeFlags |= child$66.flags & 31457280), + (child$66.return = completedWork), + (child$66 = child$66.sibling); else - for (child$65 = completedWork.child; null !== child$65; ) - (newChildLanes |= child$65.lanes | child$65.childLanes), - (subtreeFlags |= child$65.subtreeFlags), - (subtreeFlags |= child$65.flags), - (child$65.return = completedWork), - (child$65 = child$65.sibling); + for (child$66 = completedWork.child; null !== child$66; ) + (newChildLanes |= child$66.lanes | child$66.childLanes), + (subtreeFlags |= child$66.subtreeFlags), + (subtreeFlags |= child$66.flags), + (child$66.return = completedWork), + (child$66 = child$66.sibling); completedWork.subtreeFlags |= subtreeFlags; completedWork.childLanes = newChildLanes; return didBailout; @@ -6490,8 +6636,8 @@ function safelyDetachRef(current, nearestMountedAncestor) { else if ("function" === typeof ref) try { ref(null); - } catch (error$80) { - captureCommitPhaseError(current, nearestMountedAncestor, error$80); + } catch (error$81) { + captureCommitPhaseError(current, nearestMountedAncestor, error$81); } else ref.current = null; } @@ -6595,10 +6741,10 @@ function commitHookEffectListMount(flags, finishedWork) { var effect = (finishedWork = finishedWork.next); do { if ((effect.tag & flags) === flags) { - var create$81 = effect.create, + var create$82 = effect.create, inst = effect.inst; - create$81 = create$81(); - inst.destroy = create$81; + create$82 = create$82(); + inst.destroy = create$82; } effect = effect.next; } while (effect !== finishedWork); @@ -6661,11 +6807,11 @@ function commitLayoutEffectOnFiber(finishedRoot, current, finishedWork) { current, finishedRoot.__reactInternalSnapshotBeforeUpdate ); - } catch (error$82) { + } catch (error$83) { captureCommitPhaseError( finishedWork, finishedWork.return, - error$82 + error$83 ); } } @@ -6985,8 +7131,8 @@ function commitMutationEffectsOnFiber(finishedWork, root) { } try { commitHookEffectListUnmount(5, finishedWork, finishedWork.return); - } catch (error$84) { - captureCommitPhaseError(finishedWork, finishedWork.return, error$84); + } catch (error$85) { + captureCommitPhaseError(finishedWork, finishedWork.return, error$85); } } break; @@ -7962,13 +8108,13 @@ function renderRootSync(root, lanes) { default: (workInProgressSuspendedReason = 0), (workInProgressThrownValue = null), - throwAndUnwindWorkLoop(unitOfWork, thrownValue); + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); } } workLoopSync(); break; - } catch (thrownValue$92) { - handleThrow(root, thrownValue$92); + } catch (thrownValue$93) { + handleThrow(root, thrownValue$93); } while (1); lanes && root.shellSuspendCounter++; @@ -8004,7 +8150,7 @@ function renderRootConcurrent(root, lanes) { case 1: workInProgressSuspendedReason = 0; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(lanes, thrownValue); + throwAndUnwindWorkLoop(root, lanes, thrownValue); break; case 2: if (isThenableResolved(thrownValue)) { @@ -8034,7 +8180,7 @@ function renderRootConcurrent(root, lanes) { replaySuspendedUnitOfWork(lanes)) : ((workInProgressSuspendedReason = 0), (workInProgressThrownValue = null), - throwAndUnwindWorkLoop(lanes, thrownValue)); + throwAndUnwindWorkLoop(root, lanes, thrownValue)); break; case 5: switch (workInProgress.tag) { @@ -8057,12 +8203,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(); @@ -8074,8 +8220,8 @@ function renderRootConcurrent(root, lanes) { } workLoopConcurrent(); break; - } catch (thrownValue$94) { - handleThrow(root, thrownValue$94); + } catch (thrownValue$95) { + handleThrow(root, thrownValue$95); } while (1); resetContextDependencies(); @@ -8153,191 +8299,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$32 = offscreenQueue.retryQueue; - null === retryQueue$32 - ? (offscreenQueue.retryQueue = new Set([wakeable])) - : retryQueue$32.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; @@ -9550,10 +9560,10 @@ batchedUpdatesImpl = function (fn, a) { } }; var roots = new Map(), - devToolsConfig$jscomp$inline_1054 = { + devToolsConfig$jscomp$inline_1052 = { findFiberByHostInstance: getInstanceFromNode, bundleType: 0, - version: "18.3.0-canary-4aee1a03", + version: "18.3.0-canary-60bc647b", rendererPackageName: "react-native-renderer", rendererConfig: { getInspectorDataForInstance: getInspectorDataForInstance, @@ -9569,11 +9579,11 @@ var roots = new Map(), }.bind(null, findNodeHandle) } }; -var internals$jscomp$inline_1293 = { - bundleType: devToolsConfig$jscomp$inline_1054.bundleType, - version: devToolsConfig$jscomp$inline_1054.version, - rendererPackageName: devToolsConfig$jscomp$inline_1054.rendererPackageName, - rendererConfig: devToolsConfig$jscomp$inline_1054.rendererConfig, +var internals$jscomp$inline_1273 = { + bundleType: devToolsConfig$jscomp$inline_1052.bundleType, + version: devToolsConfig$jscomp$inline_1052.version, + rendererPackageName: devToolsConfig$jscomp$inline_1052.rendererPackageName, + rendererConfig: devToolsConfig$jscomp$inline_1052.rendererConfig, overrideHookState: null, overrideHookStateDeletePath: null, overrideHookStateRenamePath: null, @@ -9589,26 +9599,26 @@ var internals$jscomp$inline_1293 = { return null === fiber ? null : fiber.stateNode; }, findFiberByHostInstance: - devToolsConfig$jscomp$inline_1054.findFiberByHostInstance || + devToolsConfig$jscomp$inline_1052.findFiberByHostInstance || emptyFindFiberByHostInstance, findHostInstancesForRefresh: null, scheduleRefresh: null, scheduleRoot: null, setRefreshHandler: null, getCurrentFiber: null, - reconcilerVersion: "18.3.0-canary-4aee1a03" + reconcilerVersion: "18.3.0-canary-60bc647b" }; if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) { - var hook$jscomp$inline_1294 = __REACT_DEVTOOLS_GLOBAL_HOOK__; + var hook$jscomp$inline_1274 = __REACT_DEVTOOLS_GLOBAL_HOOK__; if ( - !hook$jscomp$inline_1294.isDisabled && - hook$jscomp$inline_1294.supportsFiber + !hook$jscomp$inline_1274.isDisabled && + hook$jscomp$inline_1274.supportsFiber ) try { - (rendererID = hook$jscomp$inline_1294.inject( - internals$jscomp$inline_1293 + (rendererID = hook$jscomp$inline_1274.inject( + internals$jscomp$inline_1273 )), - (injectedHook = hook$jscomp$inline_1294); + (injectedHook = hook$jscomp$inline_1274); } catch (err) {} } exports.createPortal = function (children, containerTag) { diff --git a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-profiling.fb.js b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-profiling.fb.js index d347d8e2b319a..61c82586e4c15 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-profiling.fb.js +++ b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactFabric-profiling.fb.js @@ -7,7 +7,7 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<> + * @generated SignedSource<> */ "use strict"; @@ -944,7 +944,7 @@ eventPluginOrder = Array.prototype.slice.call([ "ReactNativeBridgeEventPlugin" ]); recomputePluginOrdering(); -var injectedNamesToPlugins$jscomp$inline_251 = { +var injectedNamesToPlugins$jscomp$inline_252 = { 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_253 = !1, + pluginName$jscomp$inline_254; +for (pluginName$jscomp$inline_254 in injectedNamesToPlugins$jscomp$inline_252) if ( - injectedNamesToPlugins$jscomp$inline_251.hasOwnProperty( - pluginName$jscomp$inline_253 + injectedNamesToPlugins$jscomp$inline_252.hasOwnProperty( + pluginName$jscomp$inline_254 ) ) { - var pluginModule$jscomp$inline_254 = - injectedNamesToPlugins$jscomp$inline_251[pluginName$jscomp$inline_253]; + var pluginModule$jscomp$inline_255 = + injectedNamesToPlugins$jscomp$inline_252[pluginName$jscomp$inline_254]; if ( - !namesToPlugins.hasOwnProperty(pluginName$jscomp$inline_253) || - namesToPlugins[pluginName$jscomp$inline_253] !== - pluginModule$jscomp$inline_254 + !namesToPlugins.hasOwnProperty(pluginName$jscomp$inline_254) || + namesToPlugins[pluginName$jscomp$inline_254] !== + pluginModule$jscomp$inline_255 ) { - if (namesToPlugins[pluginName$jscomp$inline_253]) + if (namesToPlugins[pluginName$jscomp$inline_254]) throw Error( "EventPluginRegistry: Cannot inject two different event plugins using the same name, `" + - (pluginName$jscomp$inline_253 + "`.") + (pluginName$jscomp$inline_254 + "`.") ); - namesToPlugins[pluginName$jscomp$inline_253] = - pluginModule$jscomp$inline_254; - isOrderingDirty$jscomp$inline_252 = !0; + namesToPlugins[pluginName$jscomp$inline_254] = + pluginModule$jscomp$inline_255; + isOrderingDirty$jscomp$inline_253 = !0; } } -isOrderingDirty$jscomp$inline_252 && recomputePluginOrdering(); +isOrderingDirty$jscomp$inline_253 && recomputePluginOrdering(); var emptyObject$1 = {}, removedKeys = null, removedKeyCount = 0, @@ -2266,6 +2266,229 @@ 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), + scheduleImmediateTask(processRootScheduleInMicrotask)); + enableDeferRootSchedulingToMicrotask || + 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$12 = workInProgressRootRenderLanes, + nextLanes = getNextLanes( + root, + root === workInProgressRoot ? workInProgressRootRenderLanes$12 : 0 + ); + if (0 !== (nextLanes & 3)) + try { + didPerformSomeWork = !0; + workInProgressRootRenderLanes$12 = root; + if (0 !== (executionContext & 6)) + throw Error("Should not already be working."); + if (!flushPassiveEffects()) { + currentUpdateIsNested = nestedUpdateScheduled; + nestedUpdateScheduled = !1; + var exitStatus = renderRootSync( + workInProgressRootRenderLanes$12, + nextLanes + ); + if ( + 0 !== workInProgressRootRenderLanes$12.tag && + 2 === exitStatus + ) { + var originallyAttemptedLanes = nextLanes, + errorRetryLanes = getLanesToRetrySynchronouslyOnError( + workInProgressRootRenderLanes$12, + originallyAttemptedLanes + ); + 0 !== errorRetryLanes && + ((nextLanes = errorRetryLanes), + (exitStatus = recoverFromConcurrentError( + workInProgressRootRenderLanes$12, + originallyAttemptedLanes, + errorRetryLanes + ))); + } + if (1 === exitStatus) + throw ( + ((originallyAttemptedLanes = workInProgressRootFatalError), + prepareFreshStack(workInProgressRootRenderLanes$12, 0), + markRootSuspended( + workInProgressRootRenderLanes$12, + nextLanes, + 0 + ), + ensureRootIsScheduled(workInProgressRootRenderLanes$12), + originallyAttemptedLanes) + ); + 6 === exitStatus + ? markRootSuspended( + workInProgressRootRenderLanes$12, + nextLanes, + workInProgressDeferredLane + ) + : ((workInProgressRootRenderLanes$12.finishedWork = + workInProgressRootRenderLanes$12.current.alternate), + (workInProgressRootRenderLanes$12.finishedLanes = + nextLanes), + commitRoot( + workInProgressRootRenderLanes$12, + workInProgressRootRecoverableErrors, + workInProgressTransitions, + workInProgressDeferredLane + )); + } + ensureRootIsScheduled(workInProgressRootRenderLanes$12); + } 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++) + scheduleImmediateTask(throwError.bind(null, errors[onlyLegacy])); + } + 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$4 = 31 - clz32(lanes), + lane = 1 << index$4, + expirationTime = expirationTimes[index$4]; + if (-1 === expirationTime) { + if (0 === (lane & suspendedLanes) || 0 !== (lane & pingedLanes)) + expirationTimes[index$4] = 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 scheduleImmediateTask(cb) { + useMicrotasksForSchedulingInFabric + ? scheduleMicrotask(function () { + 0 !== (executionContext & 6) + ? scheduleCallback$2(ImmediatePriority, cb) + : cb(); + }) + : scheduleCallback$2(ImmediatePriority, cb); +} +function requestTransitionLane() { + if (0 === currentEventTransitionLane) { + var lane = nextTransitionLane; + nextTransitionLane <<= 1; + 0 === (nextTransitionLane & 4194176) && (nextTransitionLane = 128); + currentEventTransitionLane = lane; + } + return currentEventTransitionLane; +} var hasForceUpdate = !1; function initializeUpdateQueue(fiber) { fiber.updateQueue = { @@ -3362,339 +3585,116 @@ function createChildReconciler(shouldTrackSideEffects) { return ("string" === typeof newChild && "" !== newChild) || "number" === typeof newChild ? ((newChild = "" + newChild), - null !== currentFirstChild && 6 === currentFirstChild.tag - ? (deleteRemainingChildren(returnFiber, currentFirstChild.sibling), - (currentFirstChild = useFiber(currentFirstChild, newChild)), - (currentFirstChild.return = returnFiber), - (returnFiber = currentFirstChild)) - : (deleteRemainingChildren(returnFiber, currentFirstChild), - (currentFirstChild = createFiberFromText( - newChild, - returnFiber.mode, - lanes - )), - (currentFirstChild.return = returnFiber), - (returnFiber = currentFirstChild)), - 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), - scheduleImmediateTask(processRootScheduleInMicrotask)); - enableDeferRootSchedulingToMicrotask || - 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$29 = workInProgressRootRenderLanes, - nextLanes = getNextLanes( - root, - root === workInProgressRoot ? workInProgressRootRenderLanes$29 : 0 - ); - if (0 !== (nextLanes & 3)) - try { - didPerformSomeWork = !0; - workInProgressRootRenderLanes$29 = root; - if (0 !== (executionContext & 6)) - throw Error("Should not already be working."); - if (!flushPassiveEffects()) { - currentUpdateIsNested = nestedUpdateScheduled; - nestedUpdateScheduled = !1; - var exitStatus = renderRootSync( - workInProgressRootRenderLanes$29, - nextLanes - ); - if ( - 0 !== workInProgressRootRenderLanes$29.tag && - 2 === exitStatus - ) { - var originallyAttemptedLanes = nextLanes, - errorRetryLanes = getLanesToRetrySynchronouslyOnError( - workInProgressRootRenderLanes$29, - originallyAttemptedLanes - ); - 0 !== errorRetryLanes && - ((nextLanes = errorRetryLanes), - (exitStatus = recoverFromConcurrentError( - workInProgressRootRenderLanes$29, - originallyAttemptedLanes, - errorRetryLanes - ))); - } - if (1 === exitStatus) - throw ( - ((originallyAttemptedLanes = workInProgressRootFatalError), - prepareFreshStack(workInProgressRootRenderLanes$29, 0), - markRootSuspended( - workInProgressRootRenderLanes$29, - nextLanes, - 0 - ), - ensureRootIsScheduled(workInProgressRootRenderLanes$29), - originallyAttemptedLanes) - ); - 6 === exitStatus - ? markRootSuspended( - workInProgressRootRenderLanes$29, - nextLanes, - workInProgressDeferredLane - ) - : ((workInProgressRootRenderLanes$29.finishedWork = - workInProgressRootRenderLanes$29.current.alternate), - (workInProgressRootRenderLanes$29.finishedLanes = - nextLanes), - commitRoot( - workInProgressRootRenderLanes$29, - workInProgressRootRecoverableErrors, - workInProgressTransitions, - workInProgressDeferredLane - )); - } - ensureRootIsScheduled(workInProgressRootRenderLanes$29); - } 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++) - scheduleImmediateTask(throwError.bind(null, errors[onlyLegacy])); - } - 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$4 = 31 - clz32(lanes), - lane = 1 << index$4, - expirationTime = expirationTimes[index$4]; - if (-1 === expirationTime) { - if (0 === (lane & suspendedLanes) || 0 !== (lane & pingedLanes)) - expirationTimes[index$4] = 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 + null !== currentFirstChild && 6 === currentFirstChild.tag + ? (deleteRemainingChildren(returnFiber, currentFirstChild.sibling), + (currentFirstChild = useFiber(currentFirstChild, newChild)), + (currentFirstChild.return = returnFiber), + (returnFiber = currentFirstChild)) + : (deleteRemainingChildren(returnFiber, currentFirstChild), + (currentFirstChild = createFiberFromText( + newChild, + returnFiber.mode, + lanes + )), + (currentFirstChild.return = returnFiber), + (returnFiber = currentFirstChild)), + placeSingleChild(returnFiber)) + : deleteRemainingChildren(returnFiber, currentFirstChild); + } + 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; } -function scheduleImmediateTask(cb) { - useMicrotasksForSchedulingInFabric - ? scheduleMicrotask(function () { - 0 !== (executionContext & 6) - ? scheduleCallback$2(ImmediatePriority, cb) - : cb(); - }) - : scheduleCallback$2(ImmediatePriority, cb); +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 requestTransitionLane() { - if (0 === currentEventTransitionLane) { - var lane = nextTransitionLane; - nextTransitionLane <<= 1; - 0 === (nextTransitionLane & 4194176) && (nextTransitionLane = 128); - currentEventTransitionLane = lane; +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 currentEventTransitionLane; + return null; } var ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher, ReactCurrentBatchConfig$2 = ReactSharedInternals.ReactCurrentBatchConfig, @@ -4859,6 +4859,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." @@ -6193,14 +6341,14 @@ function cutOffTailIfNeeded(renderState, hasRenderedATailFallback) { break; case "collapsed": lastTailNode = renderState.tail; - for (var lastTailNode$68 = null; null !== lastTailNode; ) - null !== lastTailNode.alternate && (lastTailNode$68 = lastTailNode), + for (var lastTailNode$69 = null; null !== lastTailNode; ) + null !== lastTailNode.alternate && (lastTailNode$69 = lastTailNode), (lastTailNode = lastTailNode.sibling); - null === lastTailNode$68 + null === lastTailNode$69 ? hasRenderedATailFallback || null === renderState.tail ? (renderState.tail = null) : (renderState.tail.sibling = null) - : (lastTailNode$68.sibling = null); + : (lastTailNode$69.sibling = null); } } function bubbleProperties(completedWork) { @@ -6212,53 +6360,53 @@ function bubbleProperties(completedWork) { if (didBailout) if (0 !== (completedWork.mode & 2)) { for ( - var treeBaseDuration$70 = completedWork.selfBaseDuration, - child$71 = completedWork.child; - null !== child$71; + var treeBaseDuration$71 = completedWork.selfBaseDuration, + child$72 = completedWork.child; + null !== child$72; ) - (newChildLanes |= child$71.lanes | child$71.childLanes), - (subtreeFlags |= child$71.subtreeFlags & 31457280), - (subtreeFlags |= child$71.flags & 31457280), - (treeBaseDuration$70 += child$71.treeBaseDuration), - (child$71 = child$71.sibling); - completedWork.treeBaseDuration = treeBaseDuration$70; + (newChildLanes |= child$72.lanes | child$72.childLanes), + (subtreeFlags |= child$72.subtreeFlags & 31457280), + (subtreeFlags |= child$72.flags & 31457280), + (treeBaseDuration$71 += child$72.treeBaseDuration), + (child$72 = child$72.sibling); + completedWork.treeBaseDuration = treeBaseDuration$71; } else for ( - treeBaseDuration$70 = completedWork.child; - null !== treeBaseDuration$70; + treeBaseDuration$71 = completedWork.child; + null !== treeBaseDuration$71; ) (newChildLanes |= - treeBaseDuration$70.lanes | treeBaseDuration$70.childLanes), - (subtreeFlags |= treeBaseDuration$70.subtreeFlags & 31457280), - (subtreeFlags |= treeBaseDuration$70.flags & 31457280), - (treeBaseDuration$70.return = completedWork), - (treeBaseDuration$70 = treeBaseDuration$70.sibling); + treeBaseDuration$71.lanes | treeBaseDuration$71.childLanes), + (subtreeFlags |= treeBaseDuration$71.subtreeFlags & 31457280), + (subtreeFlags |= treeBaseDuration$71.flags & 31457280), + (treeBaseDuration$71.return = completedWork), + (treeBaseDuration$71 = treeBaseDuration$71.sibling); else if (0 !== (completedWork.mode & 2)) { - treeBaseDuration$70 = completedWork.actualDuration; - child$71 = completedWork.selfBaseDuration; + treeBaseDuration$71 = completedWork.actualDuration; + child$72 = completedWork.selfBaseDuration; for (var child = completedWork.child; null !== child; ) (newChildLanes |= child.lanes | child.childLanes), (subtreeFlags |= child.subtreeFlags), (subtreeFlags |= child.flags), - (treeBaseDuration$70 += child.actualDuration), - (child$71 += child.treeBaseDuration), + (treeBaseDuration$71 += child.actualDuration), + (child$72 += child.treeBaseDuration), (child = child.sibling); - completedWork.actualDuration = treeBaseDuration$70; - completedWork.treeBaseDuration = child$71; + completedWork.actualDuration = treeBaseDuration$71; + completedWork.treeBaseDuration = child$72; } else for ( - treeBaseDuration$70 = completedWork.child; - null !== treeBaseDuration$70; + treeBaseDuration$71 = completedWork.child; + null !== treeBaseDuration$71; ) (newChildLanes |= - treeBaseDuration$70.lanes | treeBaseDuration$70.childLanes), - (subtreeFlags |= treeBaseDuration$70.subtreeFlags), - (subtreeFlags |= treeBaseDuration$70.flags), - (treeBaseDuration$70.return = completedWork), - (treeBaseDuration$70 = treeBaseDuration$70.sibling); + treeBaseDuration$71.lanes | treeBaseDuration$71.childLanes), + (subtreeFlags |= treeBaseDuration$71.subtreeFlags), + (subtreeFlags |= treeBaseDuration$71.flags), + (treeBaseDuration$71.return = completedWork), + (treeBaseDuration$71 = treeBaseDuration$71.sibling); completedWork.subtreeFlags |= subtreeFlags; completedWork.childLanes = newChildLanes; return didBailout; @@ -6809,8 +6957,8 @@ function safelyDetachRef(current, nearestMountedAncestor) { recordLayoutEffectDuration(current); } else ref(null); - } catch (error$89) { - captureCommitPhaseError(current, nearestMountedAncestor, error$89); + } catch (error$90) { + captureCommitPhaseError(current, nearestMountedAncestor, error$90); } else ref.current = null; } @@ -6943,10 +7091,10 @@ function commitHookEffectListMount(flags, finishedWork) { injectedProfilingHooks.markComponentLayoutEffectMountStarted( finishedWork ); - var create$90 = effect.create, + var create$91 = effect.create, inst = effect.inst; - create$90 = create$90(); - inst.destroy = create$90; + create$91 = create$91(); + inst.destroy = create$91; 0 !== (flags & 8) ? null !== injectedProfilingHooks && "function" === @@ -6974,8 +7122,8 @@ function commitHookLayoutEffects(finishedWork, hookFlags) { } else try { commitHookEffectListMount(hookFlags, finishedWork); - } catch (error$92) { - captureCommitPhaseError(finishedWork, finishedWork.return, error$92); + } catch (error$93) { + captureCommitPhaseError(finishedWork, finishedWork.return, error$93); } } function commitClassCallbacks(finishedWork) { @@ -7064,11 +7212,11 @@ function commitLayoutEffectOnFiber(finishedRoot, current, finishedWork) { } else try { finishedRoot.componentDidMount(); - } catch (error$93) { + } catch (error$94) { captureCommitPhaseError( finishedWork, finishedWork.return, - error$93 + error$94 ); } else { @@ -7085,11 +7233,11 @@ function commitLayoutEffectOnFiber(finishedRoot, current, finishedWork) { current, finishedRoot.__reactInternalSnapshotBeforeUpdate ); - } catch (error$94) { + } catch (error$95) { captureCommitPhaseError( finishedWork, finishedWork.return, - error$94 + error$95 ); } recordLayoutEffectDuration(finishedWork); @@ -7100,11 +7248,11 @@ function commitLayoutEffectOnFiber(finishedRoot, current, finishedWork) { current, finishedRoot.__reactInternalSnapshotBeforeUpdate ); - } catch (error$95) { + } catch (error$96) { captureCommitPhaseError( finishedWork, finishedWork.return, - error$95 + error$96 ); } } @@ -7451,22 +7599,22 @@ function commitMutationEffectsOnFiber(finishedWork, root) { try { startLayoutEffectTimer(), commitHookEffectListUnmount(5, finishedWork, finishedWork.return); - } catch (error$98) { + } catch (error$99) { captureCommitPhaseError( finishedWork, finishedWork.return, - error$98 + error$99 ); } recordLayoutEffectDuration(finishedWork); } else try { commitHookEffectListUnmount(5, finishedWork, finishedWork.return); - } catch (error$99) { + } catch (error$100) { captureCommitPhaseError( finishedWork, finishedWork.return, - error$99 + error$100 ); } } @@ -7763,8 +7911,8 @@ function commitHookPassiveMountEffects(finishedWork, hookFlags) { } else try { commitHookEffectListMount(hookFlags, finishedWork); - } catch (error$107) { - captureCommitPhaseError(finishedWork, finishedWork.return, error$107); + } catch (error$108) { + captureCommitPhaseError(finishedWork, finishedWork.return, error$108); } } function recursivelyTraversePassiveMountEffects(root, parentFiber) { @@ -8525,13 +8673,13 @@ function renderRootSync(root, lanes) { default: (workInProgressSuspendedReason = 0), (workInProgressThrownValue = null), - throwAndUnwindWorkLoop(memoizedUpdaters, thrownValue); + throwAndUnwindWorkLoop(root, memoizedUpdaters, thrownValue); } } workLoopSync(); break; - } catch (thrownValue$108) { - handleThrow(root, thrownValue$108); + } catch (thrownValue$109) { + handleThrow(root, thrownValue$109); } while (1); lanes && root.shellSuspendCounter++; @@ -8579,7 +8727,7 @@ function renderRootConcurrent(root, lanes) { case 1: workInProgressSuspendedReason = 0; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(lanes, memoizedUpdaters); + throwAndUnwindWorkLoop(root, lanes, memoizedUpdaters); break; case 2: if (isThenableResolved(memoizedUpdaters)) { @@ -8609,7 +8757,7 @@ function renderRootConcurrent(root, lanes) { replaySuspendedUnitOfWork(lanes)) : ((workInProgressSuspendedReason = 0), (workInProgressThrownValue = null), - throwAndUnwindWorkLoop(lanes, memoizedUpdaters)); + throwAndUnwindWorkLoop(root, lanes, memoizedUpdaters)); break; case 5: switch (workInProgress.tag) { @@ -8632,12 +8780,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(); @@ -8648,8 +8796,8 @@ function renderRootConcurrent(root, lanes) { } workLoopConcurrent(); break; - } catch (thrownValue$110) { - handleThrow(root, thrownValue$110); + } catch (thrownValue$111) { + handleThrow(root, thrownValue$111); } while (1); resetContextDependencies(); @@ -8744,200 +8892,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; @@ -9125,11 +9136,11 @@ function flushPassiveEffects() { _finishedWork$memoize = finishedWork.memoizedProps, id = _finishedWork$memoize.id, onPostCommit = _finishedWork$memoize.onPostCommit, - commitTime$91 = commitTime, + commitTime$92 = commitTime, phase = null === finishedWork.alternate ? "mount" : "update"; currentUpdateIsNested && (phase = "nested-update"); "function" === typeof onPostCommit && - onPostCommit(id, phase, passiveEffectDuration, commitTime$91); + onPostCommit(id, phase, passiveEffectDuration, commitTime$92); var parentFiber = finishedWork.return; b: for (; null !== parentFiber; ) { switch (parentFiber.tag) { @@ -10252,10 +10263,10 @@ batchedUpdatesImpl = function (fn, a) { } }; var roots = new Map(), - devToolsConfig$jscomp$inline_1132 = { + devToolsConfig$jscomp$inline_1130 = { findFiberByHostInstance: getInstanceFromNode, bundleType: 0, - version: "18.3.0-canary-575afa21", + version: "18.3.0-canary-0c38bc9b", rendererPackageName: "react-native-renderer", rendererConfig: { getInspectorDataForInstance: getInspectorDataForInstance, @@ -10285,10 +10296,10 @@ var roots = new Map(), } catch (err) {} return hook.checkDCE ? !0 : !1; })({ - bundleType: devToolsConfig$jscomp$inline_1132.bundleType, - version: devToolsConfig$jscomp$inline_1132.version, - rendererPackageName: devToolsConfig$jscomp$inline_1132.rendererPackageName, - rendererConfig: devToolsConfig$jscomp$inline_1132.rendererConfig, + bundleType: devToolsConfig$jscomp$inline_1130.bundleType, + version: devToolsConfig$jscomp$inline_1130.version, + rendererPackageName: devToolsConfig$jscomp$inline_1130.rendererPackageName, + rendererConfig: devToolsConfig$jscomp$inline_1130.rendererConfig, overrideHookState: null, overrideHookStateDeletePath: null, overrideHookStateRenamePath: null, @@ -10304,14 +10315,14 @@ var roots = new Map(), return null === fiber ? null : fiber.stateNode; }, findFiberByHostInstance: - devToolsConfig$jscomp$inline_1132.findFiberByHostInstance || + devToolsConfig$jscomp$inline_1130.findFiberByHostInstance || emptyFindFiberByHostInstance, findHostInstancesForRefresh: null, scheduleRefresh: null, scheduleRoot: null, setRefreshHandler: null, getCurrentFiber: null, - reconcilerVersion: "18.3.0-canary-575afa21" + reconcilerVersion: "18.3.0-canary-0c38bc9b" }); exports.createPortal = function (children, containerTag) { return createPortal$1( diff --git a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js index 9dc389df37fac..3b09884b58edd 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js +++ b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js @@ -7,7 +7,7 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<<7117023f3b40093a08a4623516c9c86b>> + * @generated SignedSource<> */ "use strict"; @@ -7142,3714 +7142,3706 @@ 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 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 hasForceUpdate = false; - var didWarnUpdateInsideUpdate; - var currentlyProcessingQueue; + var firstScheduledRoot = null; + var lastScheduledRoot = null; // Used to prevent redundant mircotasks from being scheduled. - { - didWarnUpdateInsideUpdate = false; - currentlyProcessingQueue = null; - } + 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. - 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; + var didScheduleMicrotask_act = false; // Used to quickly bail out of flushSync if there's no sync work to do. - if (queue === currentQueue) { - var clone = { - baseState: currentQueue.baseState, - firstBaseUpdate: currentQueue.firstBaseUpdate, - lastBaseUpdate: currentQueue.lastBaseUpdate, - shared: currentQueue.shared, - callbacks: null - }; - workInProgress.updateQueue = clone; + var mightHavePendingSyncWork = false; + var isFlushingWork = false; + var currentEventTransitionLane = NoLane; + function ensureRootIsScheduled(root) { + // This function is called whenever a root receives an update. It does two + // things 1) it ensures the root is in the root schedule, and 2) it ensures + // there's a pending microtask to process the root schedule. + // + // Most of the actual scheduling logic does not happen until + // `scheduleTaskForRootDuringMicrotask` runs. + // Add the root to the schedule + if (root === lastScheduledRoot || root.next !== null); + else { + if (lastScheduledRoot === null) { + firstScheduledRoot = lastScheduledRoot = root; + } else { + lastScheduledRoot.next = root; + lastScheduledRoot = root; + } + } // Any time a root received an update, we set this to true until the next time + // we process the schedule. If it's false, then we can quickly exit flushSync + // without consulting the schedule. + + mightHavePendingSyncWork = true; // At the end of the current event, go through each of the roots and ensure + // there's a task scheduled for each one at the correct priority. + + if (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); + } + } + + if (!enableDeferRootSchedulingToMicrotask) { + // While this flag is disabled, we schedule the render task immediately + // instead of waiting a microtask. + // TODO: We need to land enableDeferRootSchedulingToMicrotask ASAP to + // unblock additional features we have planned. + scheduleTaskForRootDuringMicrotask(root, now$1()); + } + + if (ReactCurrentActQueue$3.isBatchingLegacy && root.tag === LegacyRoot) { + // Special `act` case: Record whenever a legacy update is scheduled. + ReactCurrentActQueue$3.didScheduleLegacyUpdate = true; } } - function createUpdate(lane) { - var update = { - lane: lane, - tag: UpdateState, - payload: null, - callback: null, - next: null - }; - return update; + 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 enqueueUpdate(fiber, update, lane) { - var updateQueue = fiber.updateQueue; - if (updateQueue === null) { - // Only occurs if the fiber has been unmounted. - return null; + 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 ( - currentlyProcessingQueue === sharedQueue && - !didWarnUpdateInsideUpdate - ) { - var componentName = getComponentNameFromFiber(fiber); + var didPerformSomeWork; + var errors = null; + isFlushingWork = true; - error( - "An update (setState, replaceState, or forceUpdate) was scheduled " + - "from inside an update function. Update functions should be pure, " + - "with zero side-effects. Consider using componentDidUpdate or a " + - "callback.\n\nPlease update the following component: %s", - componentName - ); + do { + didPerformSomeWork = false; + var root = firstScheduledRoot; - didWarnUpdateInsideUpdate = true; - } - } + while (root !== null) { + if (onlyLegacy && root.tag !== LegacyRoot); + else { + var workInProgressRoot = getWorkInProgressRoot(); + var workInProgressRootRenderLanes = + getWorkInProgressRootRenderLanes(); + var nextLanes = getNextLanes( + root, + root === workInProgressRoot + ? workInProgressRootRenderLanes + : NoLanes + ); - if (isUnsafeClassRenderPhaseUpdate()) { - // This is an unsafe render phase update. Add directly to the update - // queue so we can process it immediately during the current render. - var pending = sharedQueue.pending; + if (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); + } + } + } + } - if (pending === null) { - // This is the first update. Create a circular list. - update.next = update; - } else { - update.next = pending.next; - pending.next = update; + root = root.next; } + } while (didPerformSomeWork); - 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). + 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. - return unsafe_markUpdateLaneFromFiberToRoot(fiber, lane); - } else { - return enqueueConcurrentClassUpdate(fiber, sharedQueue, update, lane); + 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])); + } + + var firstError = errors[0]; + throw firstError; + } + } else { + var error = errors[0]; + throw error; + } } } - function entangleTransitions(root, fiber, lane) { - var updateQueue = fiber.updateQueue; - if (updateQueue === null) { - // Only occurs if the fiber has been unmounted. - return; - } + function throwError(error) { + throw error; + } - var sharedQueue = updateQueue.shared; + function processRootScheduleInMicrotask() { + // This function is always called inside a microtask. It should never be + // called synchronously. + didScheduleMicrotask = false; - 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. + { + didScheduleMicrotask_act = false; + } // We'll recompute this as we iterate through all the roots and schedule them. - queueLanes = intersectLanes(queueLanes, root.pendingLanes); // Entangle the new transition lane with the other transition lanes. + mightHavePendingSyncWork = false; + var currentTime = now$1(); + var prev = null; + 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) { + var next = root.next; - markRootEntangled(root, newQueueLanes); - } - } - function enqueueCapturedUpdate(workInProgress, capturedUpdate) { - // Captured updates are updates that are thrown by a child during the render - // phase. They should be discarded if the render is aborted. Therefore, - // we should only put them on the work-in-progress queue, not the current one. - var queue = workInProgress.updateQueue; // Check if the work-in-progress queue is a clone. - - var current = workInProgress.alternate; - - if (current !== null) { - var currentQueue = current.updateQueue; - - if (queue === currentQueue) { - // The work-in-progress queue is the same as current. This happens when - // we bail out on a parent fiber that then captures an error thrown by - // a child. Since we want to append the update only to the work-in - // -progress queue, we need to clone the updates. We usually clone during - // processUpdateQueue, but that didn't happen in this case because we - // skipped over the parent when we bailed out. - var newFirst = null; - var newLast = null; - var firstBaseUpdate = queue.firstBaseUpdate; - - if (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 ( + 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 (newLast === null) { - newFirst = newLast = clone; - } else { - newLast.next = clone; - newLast = clone; - } // $FlowFixMe[incompatible-type] we bail out when we get a null + var nextLanes = scheduleTaskForRootDuringMicrotask(root, currentTime); - update = update.next; - } while (update !== null); // Append the captured update the end of the cloned list. + if (nextLanes === NoLane) { + // This root has no more pending work. Remove it from the schedule. To + // guard against subtle reentrancy bugs, this microtask is the only place + // we do this — you can add roots to the schedule whenever, but you can + // only remove them here. + // Null this out so we know it's been removed from the schedule. + root.next = null; - if (newLast === null) { - newFirst = newLast = capturedUpdate; - } else { - newLast.next = capturedUpdate; - newLast = capturedUpdate; - } + if (prev === null) { + // This is the new head of the list + firstScheduledRoot = next; } else { - // There are no base updates. - newFirst = newLast = capturedUpdate; + prev.next = next; } - queue = { - baseState: currentQueue.baseState, - firstBaseUpdate: newFirst, - lastBaseUpdate: newLast, - shared: currentQueue.shared, - callbacks: currentQueue.callbacks - }; - workInProgress.updateQueue = queue; - return; - } - } // Append the update to the end of the list. + if (next === null) { + // This is the new tail of the list + lastScheduledRoot = prev; + } + } else { + // This root still has work. Keep it in the list. + prev = root; - var lastBaseUpdate = queue.lastBaseUpdate; + if (includesSyncLane(nextLanes)) { + mightHavePendingSyncWork = true; + } + } - if (lastBaseUpdate === null) { - queue.firstBaseUpdate = capturedUpdate; - } else { - lastBaseUpdate.next = capturedUpdate; + root = next; } - 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(); - } - - var nextState = payload.call(instance, prevState, nextProps); - - { - if (workInProgress.mode & StrictLegacyMode) { - setIsStrictModeForDevtools(true); + currentEventTransitionLane = NoLane; // At the end of the microtask, flush any pending synchronous work. This has + // to come at the end, because it does actual rendering work that might throw. - try { - payload.call(instance, prevState, nextProps); - } finally { - setIsStrictModeForDevtools(false); - } - } + flushSyncWorkOnAllRoots(); + } - exitDisallowedContextReadInDEV(); - } + 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. - return nextState; - } // State object + var workInProgressRoot = getWorkInProgressRoot(); + var workInProgressRootRenderLanes = getWorkInProgressRootRenderLanes(); + var nextLanes = getNextLanes( + root, + root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes + ); + var existingCallbackNode = root.callbackNode; - return payload; + 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); } - case CaptureUpdate: { - workInProgress.flags = - (workInProgress.flags & ~ShouldCapture) | DidCapture; + 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); } - // Intentional fallthrough - case UpdateState: { - var _payload = update.payload; - var partialState; + root.callbackPriority = SyncLane; + root.callbackNode = null; + return SyncLane; + } else { + // We use the highest priority lane to represent the priority of the callback. + var existingCallbackPriority = root.callbackPriority; + var newCallbackPriority = getHighestPriorityLane(nextLanes); - if (typeof _payload === "function") { - // Updater function - { - enterDisallowedContextReadInDEV(); - } + 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); + } - partialState = _payload.call(instance, prevState, nextProps); + var schedulerPriorityLevel; - { - if (workInProgress.mode & StrictLegacyMode) { - setIsStrictModeForDevtools(true); + switch (lanesToEventPriority(nextLanes)) { + case DiscreteEventPriority: + schedulerPriorityLevel = ImmediatePriority; + break; - try { - _payload.call(instance, prevState, nextProps); - } finally { - setIsStrictModeForDevtools(false); - } - } + case ContinuousEventPriority: + schedulerPriorityLevel = UserBlockingPriority; + break; - exitDisallowedContextReadInDEV(); - } - } else { - // Partial state object - partialState = _payload; - } + case DefaultEventPriority: + schedulerPriorityLevel = NormalPriority; + break; - if (partialState === null || partialState === undefined) { - // Null and undefined are treated as no-ops. - return prevState; - } // Merge the partial state and the previous state. + case IdleEventPriority: + schedulerPriorityLevel = IdlePriority; + break; - return assign({}, prevState, partialState); + default: + schedulerPriorityLevel = NormalPriority; + break; } - case ForceUpdate: { - hasForceUpdate = true; - return prevState; - } + var newCallbackNode = scheduleCallback$1( + schedulerPriorityLevel, + performConcurrentWorkOnRoot.bind(null, root) + ); + root.callbackPriority = newCallbackPriority; + root.callbackNode = newCallbackNode; + return newCallbackPriority; } - - return prevState; } - function processUpdateQueue(workInProgress, props, instance, renderLanes) { - // This is always non-null on a ClassComponent or HostRoot - var queue = workInProgress.updateQueue; - hasForceUpdate = false; + 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()); - { - currentlyProcessingQueue = queue.shared; + 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 firstBaseUpdate = queue.firstBaseUpdate; - var lastBaseUpdate = queue.lastBaseUpdate; // Check if there are pending updates. If so, transfer them to the base queue. + return null; + } + var fakeActCallbackNode$1 = {}; - var pendingQueue = queue.shared.pending; + 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); + } + } - 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 cancelCallback(callbackNode) { + if (callbackNode === fakeActCallbackNode$1); + else if (callbackNode !== null) { + cancelCallback$1(callbackNode); + } + } - var lastPendingUpdate = pendingQueue; - var firstPendingUpdate = lastPendingUpdate.next; - lastPendingUpdate.next = null; // Append pending updates to base queue + 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 (lastBaseUpdate === null) { - firstBaseUpdate = firstPendingUpdate; - } else { - lastBaseUpdate.next = firstPendingUpdate; - } + { + // If microtasks are not supported, use Scheduler. + scheduleCallback$2(ImmediatePriority, cb); + } + } - lastBaseUpdate = lastPendingUpdate; // If there's a current queue, and it's different from the base queue, then - // we need to transfer the updates to that queue, too. Because the base - // queue is a singly-linked list with no cycles, we can append to both - // lists and take advantage of structural sharing. - // TODO: Pass `current` as argument + function 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(); + } - var current = workInProgress.alternate; + return currentEventTransitionLane; + } - if (current !== null) { - // This is always non-null on a ClassComponent or HostRoot - var currentQueue = current.updateQueue; - var currentLastBaseUpdate = currentQueue.lastBaseUpdate; + // 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. - if (currentLastBaseUpdate !== lastBaseUpdate) { - if (currentLastBaseUpdate === null) { - currentQueue.firstBaseUpdate = firstPendingUpdate; - } else { - currentLastBaseUpdate.next = firstPendingUpdate; - } + var currentEntangledListeners = null; // The number of pending async actions in the entangled scope. - currentQueue.lastBaseUpdate = lastPendingUpdate; + var currentEntangledPendingCount = 0; // The transition lane shared by all updates in the entangled scope. + + var currentEntangledLane = NoLane; // A thenable that resolves when the entangled scope completes. It does not + // resolve to a particular value because it's only used for suspending the UI + // until the async action scope has completed. + + var currentEntangledActionThenable = null; + function entangleAsyncAction(thenable) { + // `thenable` is the return value of the async action scope function. Create + // a combined thenable that resolves once every entangled scope function + // has finished. + if (currentEntangledListeners === null) { + // There's no outer async action scope. Create a new one. + var entangledListeners = (currentEntangledListeners = []); + currentEntangledPendingCount = 0; + currentEntangledLane = requestTransitionLane(); + var entangledThenable = { + status: "pending", + value: undefined, + then: function (resolve) { + entangledListeners.push(resolve); } - } - } // These values may change as we process the queue. + }; + currentEntangledActionThenable = entangledThenable; + } - 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. + currentEntangledPendingCount++; + thenable.then(pingEngtangledActionScope, pingEngtangledActionScope); + return thenable; + } - var newLanes = NoLanes; - var newBaseState = null; - var newFirstBaseUpdate = null; - var newLastBaseUpdate = null; - var update = firstBaseUpdate; + function pingEngtangledActionScope() { + if ( + currentEntangledListeners !== null && + --currentEntangledPendingCount === 0 + ) { + // All the actions have finished. Close the entangled async action scope + // and notify all the listeners. + if (currentEntangledActionThenable !== null) { + var fulfilledThenable = currentEntangledActionThenable; + fulfilledThenable.status = "fulfilled"; + } - 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 listeners = currentEntangledListeners; + currentEntangledListeners = null; + currentEntangledLane = NoLane; + currentEntangledActionThenable = null; - var shouldSkipUpdate = isHiddenUpdate - ? !isSubsetOfLanes(getWorkInProgressRootRenderLanes(), updateLane) - : !isSubsetOfLanes(renderLanes, updateLane); + for (var i = 0; i < listeners.length; i++) { + var listener = listeners[i]; + listener(); + } + } + } - if (shouldSkipUpdate) { - // Priority is insufficient. Skip this update. If this is the first - // skipped update, the previous update/state is the new base - // update/state. - var clone = { - lane: updateLane, - tag: update.tag, - payload: update.payload, - callback: update.callback, - next: null - }; + function 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 (newLastBaseUpdate === null) { - newFirstBaseUpdate = newLastBaseUpdate = clone; - newBaseState = newState; - } else { - newLastBaseUpdate = newLastBaseUpdate.next = clone; - } // Update the remaining priority in the queue. + 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; - 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. + 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. - newState = getStateFromUpdate( - workInProgress, - queue, - update, - newState, - props, - instance - ); - var callback = update.callback; + listener(undefined); + } + } + ); + return thenableWithOverride; + } + function peekEntangledActionLane() { + return currentEntangledLane; + } + function peekEntangledActionThenable() { + return currentEntangledActionThenable; + } - if (callback !== null) { - workInProgress.flags |= Callback; + var UpdateState = 0; + var ReplaceState = 1; + var ForceUpdate = 2; + var CaptureUpdate = 3; // Global state that is reset at the beginning of calling `processUpdateQueue`. + // It should only be read right after calling `processUpdateQueue`, via + // `checkHasForceUpdateAfterProcessing`. - if (isHiddenUpdate) { - workInProgress.flags |= Visibility; - } + var hasForceUpdate = false; + var didWarnUpdateInsideUpdate; + var currentlyProcessingQueue; - var callbacks = queue.callbacks; + { + didWarnUpdateInsideUpdate = false; + currentlyProcessingQueue = null; + } - 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); - - if (newLastBaseUpdate === null) { - newBaseState = newState; - } - - queue.baseState = newBaseState; - queue.firstBaseUpdate = newFirstBaseUpdate; - queue.lastBaseUpdate = newLastBaseUpdate; - - 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; - } + 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; - { - currentlyProcessingQueue = null; + 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; - function callCallback(callback, context) { - if (typeof callback !== "function") { - throw new Error( - "Invalid argument passed as callback. Expected a function. Instead " + - ("received: " + callback) - ); + if (updateQueue === null) { + // Only occurs if the fiber has been unmounted. + return null; } - callback.call(context); - } + var sharedQueue = updateQueue.shared; - function resetHasForceUpdateBeforeProcessing() { - hasForceUpdate = false; - } - function checkHasForceUpdateAfterProcessing() { - return hasForceUpdate; - } - function deferHiddenCallbacks(updateQueue) { - // When an update finishes on a hidden component, its callback should not - // be fired until/unless the component is made visible again. Stash the - // callback on the shared queue object so it can be fired later. - var newHiddenCallbacks = updateQueue.callbacks; + { + if ( + currentlyProcessingQueue === sharedQueue && + !didWarnUpdateInsideUpdate + ) { + var componentName = getComponentNameFromFiber(fiber); - if (newHiddenCallbacks !== null) { - var existingHiddenCallbacks = updateQueue.shared.hiddenCallbacks; + error( + "An update (setState, replaceState, or forceUpdate) was scheduled " + + "from inside an update function. Update functions should be pure, " + + "with zero side-effects. Consider using componentDidUpdate or a " + + "callback.\n\nPlease update the following component: %s", + componentName + ); - if (existingHiddenCallbacks === null) { - updateQueue.shared.hiddenCallbacks = newHiddenCallbacks; - } else { - updateQueue.shared.hiddenCallbacks = - existingHiddenCallbacks.concat(newHiddenCallbacks); + didWarnUpdateInsideUpdate = true; } } - } - 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; + 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; - for (var i = 0; i < hiddenCallbacks.length; i++) { - var callback = hiddenCallbacks[i]; - callCallback(callback, context); + if (pending === null) { + // This is the first update. Create a circular list. + update.next = update; + } else { + update.next = pending.next; + pending.next = update; } - } - } - function commitCallbacks(updateQueue, context) { - var callbacks = updateQueue.callbacks; - if (callbacks !== null) { - updateQueue.callbacks = null; + sharedQueue.pending = update; // Update the childLanes even though we're most likely already rendering + // this fiber. This is for backwards compatibility in the case where you + // update a different component during render phase than the one that is + // currently renderings (a pattern that is accompanied by a warning). - for (var i = 0; i < callbacks.length; i++) { - var callback = callbacks[i]; - callCallback(callback, context); - } + return unsafe_markUpdateLaneFromFiberToRoot(fiber, lane); + } else { + return enqueueConcurrentClassUpdate(fiber, sharedQueue, update, lane); } } + function entangleTransitions(root, fiber, lane) { + var updateQueue = fiber.updateQueue; - /** - * 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; + if (updateQueue === null) { + // Only occurs if the fiber has been unmounted. + return; } - if ( - typeof objA !== "object" || - objA === null || - typeof objB !== "object" || - objB === null - ) { - return false; - } + var sharedQueue = updateQueue.shared; - var keysA = Object.keys(objA); - var keysB = Object.keys(objB); + if (isTransitionLane(lane)) { + var queueLanes = sharedQueue.lanes; // If any entangled lanes are no longer pending on the root, then they must + // have finished. We can remove them from the shared queue, which represents + // a superset of the actually pending lanes. In some cases we may entangle + // more than we need to, but that's OK. In fact it's worse if we *don't* + // entangle when we should. - if (keysA.length !== keysB.length) { - return false; - } // Test for A's keys different from B. + queueLanes = intersectLanes(queueLanes, root.pendingLanes); // Entangle the new transition lane with the other transition lanes. - for (var i = 0; i < keysA.length; i++) { - var currentKey = keysA[i]; + var newQueueLanes = mergeLanes(queueLanes, lane); + sharedQueue.lanes = newQueueLanes; // Even if queue.lanes already include lane, we don't know for certain if + // the lane finished since the last time we entangled it. So we need to + // entangle it again, just to be sure. - if ( - !hasOwnProperty.call(objB, currentKey) || // $FlowFixMe[incompatible-use] lost refinement of `objB` - !objectIs(objA[currentKey], objB[currentKey]) - ) { - return false; - } + markRootEntangled(root, newQueueLanes); } - - return true; } + 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 describeFiber(fiber) { - var owner = fiber._debugOwner ? fiber._debugOwner.type : null; - var source = fiber._debugSource; - - switch (fiber.tag) { - case HostHoistable: - case HostSingleton: - case HostComponent: - return describeBuiltInComponentFrame(fiber.type, source, owner); + var current = workInProgress.alternate; - case LazyComponent: - return describeBuiltInComponentFrame("Lazy", source, owner); + if (current !== null) { + var currentQueue = current.updateQueue; - case SuspenseComponent: - return describeBuiltInComponentFrame("Suspense", source, owner); + if (queue === currentQueue) { + // The work-in-progress queue is the same as current. This happens when + // we bail out on a parent fiber that then captures an error thrown by + // a child. Since we want to append the update only to the work-in + // -progress queue, we need to clone the updates. We usually clone during + // processUpdateQueue, but that didn't happen in this case because we + // skipped over the parent when we bailed out. + var newFirst = null; + var newLast = null; + var firstBaseUpdate = queue.firstBaseUpdate; - case SuspenseListComponent: - return describeBuiltInComponentFrame("SuspenseList", source, owner); + if (firstBaseUpdate !== null) { + // Loop through the updates and clone them. + var update = firstBaseUpdate; - case FunctionComponent: - case IndeterminateComponent: - case SimpleMemoComponent: - return describeFunctionComponentFrame(fiber.type, source, owner); + 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 + }; - case ForwardRef: - return describeFunctionComponentFrame( - fiber.type.render, - source, - owner - ); + if (newLast === null) { + newFirst = newLast = clone; + } else { + newLast.next = clone; + newLast = clone; + } // $FlowFixMe[incompatible-type] we bail out when we get a null - case ClassComponent: - return describeClassComponentFrame(fiber.type, source, owner); + update = update.next; + } while (update !== null); // Append the captured update the end of the cloned list. - default: - return ""; + if (newLast === null) { + newFirst = newLast = capturedUpdate; + } else { + newLast.next = capturedUpdate; + newLast = capturedUpdate; + } + } else { + // There are no base updates. + newFirst = newLast = capturedUpdate; + } + + queue = { + baseState: currentQueue.baseState, + firstBaseUpdate: newFirst, + lastBaseUpdate: newLast, + shared: currentQueue.shared, + callbacks: currentQueue.callbacks + }; + workInProgress.updateQueue = queue; + return; + } + } // Append the update to the end of the list. + + var lastBaseUpdate = queue.lastBaseUpdate; + + if (lastBaseUpdate === null) { + queue.firstBaseUpdate = capturedUpdate; + } else { + lastBaseUpdate.next = capturedUpdate; } + + queue.lastBaseUpdate = capturedUpdate; } - function getStackByFiberInDevAndProd(workInProgress) { - try { - var info = ""; - var node = workInProgress; + function getStateFromUpdate( + workInProgress, + queue, + update, + prevState, + nextProps, + instance + ) { + switch (update.tag) { + case ReplaceState: { + var payload = update.payload; - do { - info += describeFiber(node); // $FlowFixMe[incompatible-type] we bail out when we get a null + if (typeof payload === "function") { + // Updater function + { + enterDisallowedContextReadInDEV(); + } - node = node.return; - } while (node); + var nextState = payload.call(instance, prevState, nextProps); - return info; - } catch (x) { - return "\nError generating stack: " + x.message + "\n" + x.stack; - } - } + { + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); - var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; - var current = null; - var isRendering = false; - function getCurrentFiberOwnerNameInDevOrNull() { - { - if (current === null) { - return null; + try { + payload.call(instance, prevState, nextProps); + } finally { + setIsStrictModeForDevtools(false); + } + } + + exitDisallowedContextReadInDEV(); + } + + return nextState; + } // State object + + return payload; } - var owner = current._debugOwner; + case CaptureUpdate: { + workInProgress.flags = + (workInProgress.flags & ~ShouldCapture) | DidCapture; + } + // Intentional fallthrough - if (owner !== null && typeof owner !== "undefined") { - return getComponentNameFromFiber(owner); + case UpdateState: { + var _payload = update.payload; + var partialState; + + if (typeof _payload === "function") { + // Updater function + { + enterDisallowedContextReadInDEV(); + } + + partialState = _payload.call(instance, prevState, nextProps); + + { + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); + + try { + _payload.call(instance, prevState, nextProps); + } finally { + setIsStrictModeForDevtools(false); + } + } + + exitDisallowedContextReadInDEV(); + } + } else { + // Partial state object + partialState = _payload; + } + + if (partialState === null || partialState === undefined) { + // Null and undefined are treated as no-ops. + return prevState; + } // Merge the partial state and the previous state. + + return assign({}, prevState, partialState); + } + + case ForceUpdate: { + hasForceUpdate = true; + return prevState; } } - return null; + return prevState; } - 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 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. - return getStackByFiberInDevAndProd(current); - } - } + 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(); - 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; + 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 setIsRendering(rendering) { + function processUpdateQueue(workInProgress, props, instance, renderLanes) { + didReadFromEntangledAsyncAction = false; // This is always non-null on a ClassComponent or HostRoot + + var queue = workInProgress.updateQueue; + hasForceUpdate = false; + { - isRendering = rendering; + currentlyProcessingQueue = queue.shared; } - } - var ReactStrictModeWarnings = { - recordUnsafeLifecycleWarnings: function (fiber, instance) {}, - flushPendingUnsafeLifecycleWarnings: function () {}, - recordLegacyContextWarning: function (fiber, instance) {}, - flushLegacyContextWarning: function () {}, - discardPendingWarnings: function () {} - }; + var firstBaseUpdate = queue.firstBaseUpdate; + var lastBaseUpdate = queue.lastBaseUpdate; // Check if there are pending updates. If so, transfer them to the base queue. - { - var findStrictRoot = function (fiber) { - var maybeStrictRoot = null; - var node = fiber; + var pendingQueue = queue.shared.pending; - while (node !== null) { - if (node.mode & StrictLegacyMode) { - maybeStrictRoot = node; - } + 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. - node = node.return; + var lastPendingUpdate = pendingQueue; + var firstPendingUpdate = lastPendingUpdate.next; + lastPendingUpdate.next = null; // Append pending updates to base queue + + if (lastBaseUpdate === null) { + firstBaseUpdate = firstPendingUpdate; + } else { + lastBaseUpdate.next = firstPendingUpdate; } - return maybeStrictRoot; - }; + lastBaseUpdate = lastPendingUpdate; // If there's a current queue, and it's different from the base queue, then + // we need to transfer the updates to that queue, too. Because the base + // queue is a singly-linked list with no cycles, we can append to both + // lists and take advantage of structural sharing. + // TODO: Pass `current` as argument - var setToSortedString = function (set) { - var array = []; - set.forEach(function (value) { - array.push(value); - }); - return array.sort().join(", "); - }; + var current = workInProgress.alternate; - var pendingComponentWillMountWarnings = []; - var pendingUNSAFE_ComponentWillMountWarnings = []; - var pendingComponentWillReceivePropsWarnings = []; - var pendingUNSAFE_ComponentWillReceivePropsWarnings = []; - var pendingComponentWillUpdateWarnings = []; - var pendingUNSAFE_ComponentWillUpdateWarnings = []; // Tracks components we have already warned about. - - var didWarnAboutUnsafeLifecycles = new Set(); - - ReactStrictModeWarnings.recordUnsafeLifecycleWarnings = function ( - fiber, - instance - ) { - // Dedupe strategy: Warn once per component. - if (didWarnAboutUnsafeLifecycles.has(fiber.type)) { - return; - } - - if ( - typeof instance.componentWillMount === "function" && // Don't warn about react-lifecycles-compat polyfilled components. - instance.componentWillMount.__suppressDeprecationWarning !== true - ) { - pendingComponentWillMountWarnings.push(fiber); - } + if (current !== null) { + // This is always non-null on a ClassComponent or HostRoot + var currentQueue = current.updateQueue; + var currentLastBaseUpdate = currentQueue.lastBaseUpdate; - if ( - fiber.mode & StrictLegacyMode && - typeof instance.UNSAFE_componentWillMount === "function" - ) { - pendingUNSAFE_ComponentWillMountWarnings.push(fiber); - } + if (currentLastBaseUpdate !== lastBaseUpdate) { + if (currentLastBaseUpdate === null) { + currentQueue.firstBaseUpdate = firstPendingUpdate; + } else { + currentLastBaseUpdate.next = firstPendingUpdate; + } - if ( - typeof instance.componentWillReceiveProps === "function" && - instance.componentWillReceiveProps.__suppressDeprecationWarning !== - true - ) { - pendingComponentWillReceivePropsWarnings.push(fiber); + currentQueue.lastBaseUpdate = lastPendingUpdate; + } } + } // These values may change as we process the queue. - if ( - fiber.mode & StrictLegacyMode && - typeof instance.UNSAFE_componentWillReceiveProps === "function" - ) { - pendingUNSAFE_ComponentWillReceivePropsWarnings.push(fiber); - } + if (firstBaseUpdate !== null) { + // Iterate through the list of updates to compute the result. + var newState = queue.baseState; // TODO: Don't need to accumulate this. Instead, we can remove renderLanes + // from the original lanes. - if ( - typeof instance.componentWillUpdate === "function" && - instance.componentWillUpdate.__suppressDeprecationWarning !== true - ) { - pendingComponentWillUpdateWarnings.push(fiber); - } + var newLanes = NoLanes; + var newBaseState = null; + var newFirstBaseUpdate = null; + var newLastBaseUpdate = null; + var update = firstBaseUpdate; - if ( - fiber.mode & StrictLegacyMode && - typeof instance.UNSAFE_componentWillUpdate === "function" - ) { - pendingUNSAFE_ComponentWillUpdateWarnings.push(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. - ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = - function () { - // We do an initial pass to gather component names - var componentWillMountUniqueNames = new Set(); + var shouldSkipUpdate = isHiddenUpdate + ? !isSubsetOfLanes(getWorkInProgressRootRenderLanes(), updateLane) + : !isSubsetOfLanes(renderLanes, updateLane); - if (pendingComponentWillMountWarnings.length > 0) { - pendingComponentWillMountWarnings.forEach(function (fiber) { - componentWillMountUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingComponentWillMountWarnings = []; - } + if (shouldSkipUpdate) { + // Priority is insufficient. Skip this update. If this is the first + // skipped update, the previous update/state is the new base + // update/state. + var clone = { + lane: updateLane, + tag: update.tag, + payload: update.payload, + callback: update.callback, + next: null + }; - var UNSAFE_componentWillMountUniqueNames = new Set(); + if (newLastBaseUpdate === null) { + newFirstBaseUpdate = newLastBaseUpdate = clone; + newBaseState = newState; + } else { + newLastBaseUpdate = newLastBaseUpdate.next = clone; + } // Update the remaining priority in the queue. - if (pendingUNSAFE_ComponentWillMountWarnings.length > 0) { - pendingUNSAFE_ComponentWillMountWarnings.forEach(function (fiber) { - UNSAFE_componentWillMountUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingUNSAFE_ComponentWillMountWarnings = []; - } + 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; + } - var componentWillReceivePropsUniqueNames = new Set(); + if (newLastBaseUpdate !== null) { + var _clone = { + // This update is going to be committed so we never want uncommit + // it. Using NoLane works because 0 is a subset of all bitmasks, so + // this will never be skipped by the check above. + lane: NoLane, + tag: update.tag, + payload: update.payload, + // When this update is rebased, we should not fire its + // callback again. + callback: null, + next: null + }; + newLastBaseUpdate = newLastBaseUpdate.next = _clone; + } // Process this update. - if (pendingComponentWillReceivePropsWarnings.length > 0) { - pendingComponentWillReceivePropsWarnings.forEach(function (fiber) { - componentWillReceivePropsUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingComponentWillReceivePropsWarnings = []; - } + newState = getStateFromUpdate( + workInProgress, + queue, + update, + newState, + props, + instance + ); + var callback = update.callback; - var UNSAFE_componentWillReceivePropsUniqueNames = new Set(); + if (callback !== null) { + workInProgress.flags |= Callback; - if (pendingUNSAFE_ComponentWillReceivePropsWarnings.length > 0) { - pendingUNSAFE_ComponentWillReceivePropsWarnings.forEach( - function (fiber) { - UNSAFE_componentWillReceivePropsUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); + if (isHiddenUpdate) { + workInProgress.flags |= Visibility; } - ); - pendingUNSAFE_ComponentWillReceivePropsWarnings = []; - } - var componentWillUpdateUniqueNames = new Set(); + var callbacks = queue.callbacks; - if (pendingComponentWillUpdateWarnings.length > 0) { - pendingComponentWillUpdateWarnings.forEach(function (fiber) { - componentWillUpdateUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingComponentWillUpdateWarnings = []; - } + if (callbacks === null) { + queue.callbacks = [callback]; + } else { + callbacks.push(callback); + } + } + } // $FlowFixMe[incompatible-type] we bail out when we get a null - var UNSAFE_componentWillUpdateUniqueNames = new Set(); + update = update.next; - 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 (update === null) { + pendingQueue = queue.shared.pending; - if (UNSAFE_componentWillMountUniqueNames.size > 0) { - var sortedNames = setToSortedString( - UNSAFE_componentWillMountUniqueNames - ); + 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. - 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 _firstPendingUpdate = _lastPendingUpdate.next; + _lastPendingUpdate.next = null; + update = _firstPendingUpdate; + queue.lastBaseUpdate = _lastPendingUpdate; + queue.shared.pending = null; + } } + } while (true); - if (UNSAFE_componentWillReceivePropsUniqueNames.size > 0) { - var _sortedNames = setToSortedString( - UNSAFE_componentWillReceivePropsUniqueNames - ); + if (newLastBaseUpdate === null) { + newBaseState = newState; + } - 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 - ); - } + queue.baseState = newBaseState; + queue.firstBaseUpdate = newFirstBaseUpdate; + queue.lastBaseUpdate = newLastBaseUpdate; - if (UNSAFE_componentWillUpdateUniqueNames.size > 0) { - var _sortedNames2 = setToSortedString( - UNSAFE_componentWillUpdateUniqueNames - ); + 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. - 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 - ); - } + markSkippedUpdateLanes(newLanes); + workInProgress.lanes = newLanes; + workInProgress.memoizedState = newState; + } - if (componentWillMountUniqueNames.size > 0) { - var _sortedNames3 = setToSortedString( - componentWillMountUniqueNames - ); + { + currentlyProcessingQueue = null; + } + } - 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 - ); - } + function callCallback(callback, context) { + if (typeof callback !== "function") { + throw new Error( + "Invalid argument passed as callback. Expected a function. Instead " + + ("received: " + callback) + ); + } - if (componentWillReceivePropsUniqueNames.size > 0) { - var _sortedNames4 = setToSortedString( - componentWillReceivePropsUniqueNames - ); + callback.call(context); + } - 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 resetHasForceUpdateBeforeProcessing() { + hasForceUpdate = false; + } + function checkHasForceUpdateAfterProcessing() { + return hasForceUpdate; + } + function deferHiddenCallbacks(updateQueue) { + // When an update finishes on a hidden component, its callback should not + // be fired until/unless the component is made visible again. Stash the + // callback on the shared queue object so it can be fired later. + var newHiddenCallbacks = updateQueue.callbacks; - if (componentWillUpdateUniqueNames.size > 0) { - var _sortedNames5 = setToSortedString( - componentWillUpdateUniqueNames - ); + if (newHiddenCallbacks !== null) { + var existingHiddenCallbacks = updateQueue.shared.hiddenCallbacks; - 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 (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 pendingLegacyContextWarning = new Map(); // Tracks components we have already warned about. + if (hiddenCallbacks !== null) { + updateQueue.shared.hiddenCallbacks = null; - var didWarnAboutLegacyContext = new Set(); + for (var i = 0; i < hiddenCallbacks.length; i++) { + var callback = hiddenCallbacks[i]; + callCallback(callback, context); + } + } + } + function commitCallbacks(updateQueue, context) { + var callbacks = updateQueue.callbacks; - ReactStrictModeWarnings.recordLegacyContextWarning = function ( - fiber, - instance - ) { - var strictRoot = findStrictRoot(fiber); + if (callbacks !== null) { + updateQueue.callbacks = null; - 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." - ); + for (var i = 0; i < callbacks.length; i++) { + var callback = callbacks[i]; + callCallback(callback, context); + } + } + } - return; - } // Dedup strategy: Warn once per component. + /** + * Performs equality by iterating through keys on an object and returning false + * when any key has values which are not strictly equal between the arguments. + * Returns true when the values of all keys are strictly equal. + */ - if (didWarnAboutLegacyContext.has(fiber.type)) { - return; - } + function shallowEqual(objA, objB) { + if (objectIs(objA, objB)) { + return true; + } - var warningsForRoot = pendingLegacyContextWarning.get(strictRoot); + 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 ( - fiber.type.contextTypes != null || - fiber.type.childContextTypes != null || - (instance !== null && typeof instance.getChildContext === "function") + !hasOwnProperty.call(objB, currentKey) || // $FlowFixMe[incompatible-use] lost refinement of `objB` + !objectIs(objA[currentKey], objB[currentKey]) ) { - if (warningsForRoot === undefined) { - warningsForRoot = []; - pendingLegacyContextWarning.set(strictRoot, warningsForRoot); - } - - warningsForRoot.push(fiber); + return false; } - }; + } - ReactStrictModeWarnings.flushLegacyContextWarning = function () { - pendingLegacyContextWarning.forEach(function (fiberArray, strictRoot) { - if (fiberArray.length === 0) { - return; - } + return true; + } - 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 describeFiber(fiber) { + var owner = fiber._debugOwner ? fiber._debugOwner.type : null; + var source = fiber._debugSource; - try { - setCurrentFiber(firstFiber); + switch (fiber.tag) { + case HostHoistable: + case HostSingleton: + case HostComponent: + return describeBuiltInComponentFrame(fiber.type, source, owner); - 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(); - } - }); - }; + case LazyComponent: + return describeBuiltInComponentFrame("Lazy", source, owner); - ReactStrictModeWarnings.discardPendingWarnings = function () { - pendingComponentWillMountWarnings = []; - pendingUNSAFE_ComponentWillMountWarnings = []; - pendingComponentWillReceivePropsWarnings = []; - pendingUNSAFE_ComponentWillReceivePropsWarnings = []; - pendingComponentWillUpdateWarnings = []; - pendingUNSAFE_ComponentWillUpdateWarnings = []; - pendingLegacyContextWarning = new Map(); - }; - } + case SuspenseComponent: + return describeBuiltInComponentFrame("Suspense", source, owner); - /* - * 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] + case SuspenseListComponent: + return describeBuiltInComponentFrame("SuspenseList", source, owner); - return type; - } - } // $FlowFixMe[incompatible-return] only called in DEV, so void return is not possible. + case FunctionComponent: + case IndeterminateComponent: + case SimpleMemoComponent: + return describeFunctionComponentFrame(fiber.type, source, owner); - function willCoercionThrow(value) { - { - try { - testStringCoercion(value); - return false; - } catch (e) { - return true; - } + case ForwardRef: + return describeFunctionComponentFrame( + fiber.type.render, + source, + owner + ); + + case ClassComponent: + return describeClassComponentFrame(fiber.type, source, owner); + + default: + return ""; } } - 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) - ); + function getStackByFiberInDevAndProd(workInProgress) { + try { + var info = ""; + var node = workInProgress; - return testStringCoercion(value); // throw (to help callers find troubleshooting comments) - } + 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; } } - function checkPropStringCoercion(value, propName) { + + var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; + var current = null; + var isRendering = false; + function getCurrentFiberOwnerNameInDevOrNull() { { - if (willCoercionThrow(value)) { - error( - "The provided `%s` prop is an unsupported type %s." + - " This value must be coerced to a string before using it here.", - propName, - typeName(value) - ); + if (current === null) { + return null; + } - return testStringCoercion(value); // throw (to help callers find troubleshooting comments) + var owner = current._debugOwner; + + if (owner !== null && typeof owner !== "undefined") { + return getComponentNameFromFiber(owner); } } + + return null; } - 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. + 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 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. + return getStackByFiberInDevAndProd(current); + } + } - var noopSuspenseyCommitThenable = { - then: function () { - { - error( - "Internal React error: A listener was unexpectedly attached to a " + - '"noop" thenable. This is a bug in React. Please file an issue.' - ); - } + function resetCurrentFiber() { + { + ReactDebugCurrentFrame.getCurrentStack = null; + current = null; + isRendering = false; } - }; - 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 setCurrentFiber(fiber) { + { + ReactDebugCurrentFrame.getCurrentStack = + fiber === null ? null : getCurrentFiberStackInDev; + current = fiber; + isRendering = false; + } + } + function getCurrentFiber() { + { + return current; + } + } + function setIsRendering(rendering) { + { + isRendering = rendering; + } } - function noop() {} + var ReactStrictModeWarnings = { + recordUnsafeLifecycleWarnings: function (fiber, instance) {}, + flushPendingUnsafeLifecycleWarnings: function () {}, + recordLegacyContextWarning: function (fiber, instance) {}, + flushLegacyContextWarning: function () {}, + discardPendingWarnings: function () {} + }; - function trackUsedThenable(thenableState, thenable, index) { - if (ReactCurrentActQueue$3.current !== null) { - ReactCurrentActQueue$3.didUsePromise = true; - } + { + var findStrictRoot = function (fiber) { + var maybeStrictRoot = null; + var node = fiber; - var previous = thenableState[index]; + while (node !== null) { + if (node.mode & StrictLegacyMode) { + maybeStrictRoot = node; + } - 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; + node = node.return; } - } // We use an expando to track the status and result of a thenable so that we - // can synchronously unwrap the value. Think of this as an extension of the - // Promise API, or a custom interface that is a superset of Thenable. - // - // If the thenable doesn't have a status, set it to "pending" and attach - // a listener that will update its status and result when it resolves. - switch (thenable.status) { - case "fulfilled": { - var fulfilledValue = thenable.value; - return fulfilledValue; + return maybeStrictRoot; + }; + + var setToSortedString = function (set) { + var array = []; + set.forEach(function (value) { + array.push(value); + }); + return array.sort().join(", "); + }; + + var pendingComponentWillMountWarnings = []; + var pendingUNSAFE_ComponentWillMountWarnings = []; + var pendingComponentWillReceivePropsWarnings = []; + var pendingUNSAFE_ComponentWillReceivePropsWarnings = []; + var pendingComponentWillUpdateWarnings = []; + var pendingUNSAFE_ComponentWillUpdateWarnings = []; // Tracks components we have already warned about. + + var didWarnAboutUnsafeLifecycles = new Set(); + + ReactStrictModeWarnings.recordUnsafeLifecycleWarnings = function ( + fiber, + instance + ) { + // Dedupe strategy: Warn once per component. + if (didWarnAboutUnsafeLifecycles.has(fiber.type)) { + return; } - case "rejected": { - var rejectedError = thenable.reason; - checkIfUseWrappedInAsyncCatch(rejectedError); - throw rejectedError; + if ( + typeof instance.componentWillMount === "function" && // Don't warn about react-lifecycles-compat polyfilled components. + instance.componentWillMount.__suppressDeprecationWarning !== true + ) { + pendingComponentWillMountWarnings.push(fiber); } - default: { - if (typeof thenable.status === "string") { - // Only instrument the thenable if the status if not defined. If - // it's defined, but an unknown value, assume it's been instrumented by - // some custom userspace implementation. We treat it as "pending". - // Attach a dummy listener, to ensure that any lazy initialization can - // happen. Flight lazily parses JSON when the value is actually awaited. - thenable.then(noop, noop); - } else { - // This is an uncached thenable that we haven't seen before. - // Detect infinite ping loops caused by uncached promises. - var root = getWorkInProgressRoot(); - - if (root !== null && root.shellSuspendCounter > 100) { - // This root has suspended repeatedly in the shell without making any - // progress (i.e. committing something). This is highly suggestive of - // an infinite ping loop, often caused by an accidental Async Client - // Component. - // - // During a transition, we can suspend the work loop until the promise - // to resolve, but this is a sync render, so that's not an option. We - // also can't show a fallback, because none was provided. So our last - // resort is to throw an error. - // - // TODO: Remove this error in a future release. Other ways of handling - // this case include forcing a concurrent render, or putting the whole - // root into offscreen mode. - throw new Error( - "async/await is not yet supported in Client Components, only " + - "Server Components. This error is often caused by accidentally " + - "adding `'use client'` to a module that was originally written " + - "for the server." - ); - } - - var pendingThenable = thenable; - pendingThenable.status = "pending"; - pendingThenable.then( - function (fulfilledValue) { - if (thenable.status === "pending") { - var fulfilledThenable = thenable; - fulfilledThenable.status = "fulfilled"; - fulfilledThenable.value = fulfilledValue; - } - }, - function (error) { - if (thenable.status === "pending") { - var rejectedThenable = thenable; - rejectedThenable.status = "rejected"; - rejectedThenable.reason = error; - } - } - ); // Check one more time in case the thenable resolved synchronously. - - 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; - - { - needsToResetSuspendedThenableDEV = true; - } - - throw SuspenseException; + if ( + fiber.mode & StrictLegacyMode && + typeof instance.UNSAFE_componentWillMount === "function" + ) { + pendingUNSAFE_ComponentWillMountWarnings.push(fiber); } - } - } - // passed to the rest of the Suspense implementation — which, for historical - // reasons, expects to receive a thenable. - - var suspendedThenable = null; - var needsToResetSuspendedThenableDEV = false; - function getSuspendedThenable() { - // This is called right after `use` suspends by throwing an exception. `use` - // throws an opaque value instead of the thenable itself so that it can't be - // caught in userspace. Then the work loop accesses the actual thenable using - // this function. - if (suspendedThenable === null) { - throw new Error( - "Expected a suspended thenable. This is a bug in React. Please file " + - "an issue." - ); - } - - var thenable = suspendedThenable; - suspendedThenable = null; - - { - needsToResetSuspendedThenableDEV = false; - } - return thenable; - } - function checkIfUseWrappedInTryCatch() { - { - // This was set right before SuspenseException was thrown, and it should - // have been cleared when the exception was handled. If it wasn't, - // it must have been caught by userspace. - if (needsToResetSuspendedThenableDEV) { - needsToResetSuspendedThenableDEV = false; - return true; + if ( + typeof instance.componentWillReceiveProps === "function" && + instance.componentWillReceiveProps.__suppressDeprecationWarning !== + true + ) { + pendingComponentWillReceivePropsWarnings.push(fiber); } - } - - return false; - } - function checkIfUseWrappedInAsyncCatch(rejectedReason) { - // This check runs in prod, too, because it prevents a more confusing - // downstream error, where SuspenseException is caught by a promise and - // thrown asynchronously. - // TODO: Another way to prevent SuspenseException from leaking into an async - // execution context is to check the dispatcher every time `use` is called, - // or some equivalent. That might be preferable for other reasons, too, since - // it matches how we prevent similar mistakes for other hooks. - if (rejectedReason === SuspenseException) { - throw new Error( - "Hooks are not supported inside an async component. This " + - "error is often caused by accidentally adding `'use client'` " + - "to a module that was originally written for the server." - ); - } - } - - var thenableState$1 = null; - var thenableIndexCounter$1 = 0; - var didWarnAboutMaps; - var didWarnAboutGenerators; - var didWarnAboutStringRefs; - var ownerHasKeyUseWarning; - var ownerHasFunctionTypeWarning; - - var warnForMissingKey = function (child, returnFiber) {}; - { - didWarnAboutMaps = false; - didWarnAboutGenerators = false; - didWarnAboutStringRefs = {}; - /** - * Warn if there's no key explicitly set on dynamic arrays of children or - * object keys are not valid. This allows us to keep track of children between - * updates. - */ - - ownerHasKeyUseWarning = {}; - ownerHasFunctionTypeWarning = {}; - - warnForMissingKey = function (child, returnFiber) { - if (child === null || typeof child !== "object") { - return; + if ( + fiber.mode & StrictLegacyMode && + typeof instance.UNSAFE_componentWillReceiveProps === "function" + ) { + pendingUNSAFE_ComponentWillReceivePropsWarnings.push(fiber); } - if (!child._store || child._store.validated || child.key != null) { - return; + if ( + typeof instance.componentWillUpdate === "function" && + instance.componentWillUpdate.__suppressDeprecationWarning !== true + ) { + pendingComponentWillUpdateWarnings.push(fiber); } - 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 - - child._store.validated = true; - var componentName = - getComponentNameFromFiber(returnFiber) || "Component"; - - if (ownerHasKeyUseWarning[componentName]) { - return; + if ( + fiber.mode & StrictLegacyMode && + typeof instance.UNSAFE_componentWillUpdate === "function" + ) { + pendingUNSAFE_ComponentWillUpdateWarnings.push(fiber); } - - 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." - ); }; - } - function isReactClass(type) { - return type.prototype && type.prototype.isReactComponent; - } - - function unwrapThenable(thenable) { - var index = thenableIndexCounter$1; - thenableIndexCounter$1 += 1; + ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = + function () { + // We do an initial pass to gather component names + var componentWillMountUniqueNames = new Set(); - if (thenableState$1 === null) { - thenableState$1 = createThenableState(); - } + if (pendingComponentWillMountWarnings.length > 0) { + pendingComponentWillMountWarnings.forEach(function (fiber) { + componentWillMountUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingComponentWillMountWarnings = []; + } - return trackUsedThenable(thenableState$1, thenable, index); - } + var UNSAFE_componentWillMountUniqueNames = new Set(); - function coerceRef(returnFiber, current, element) { - var mixedRef = element.ref; + if (pendingUNSAFE_ComponentWillMountWarnings.length > 0) { + pendingUNSAFE_ComponentWillMountWarnings.forEach(function (fiber) { + UNSAFE_componentWillMountUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingUNSAFE_ComponentWillMountWarnings = []; + } - 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"; + var componentWillReceivePropsUniqueNames = 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 (pendingComponentWillReceivePropsWarnings.length > 0) { + pendingComponentWillReceivePropsWarnings.forEach(function (fiber) { + componentWillReceivePropsUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingComponentWillReceivePropsWarnings = []; + } - didWarnAboutStringRefs[componentName] = true; - } + var UNSAFE_componentWillReceivePropsUniqueNames = new Set(); + + if (pendingUNSAFE_ComponentWillReceivePropsWarnings.length > 0) { + pendingUNSAFE_ComponentWillReceivePropsWarnings.forEach( + function (fiber) { + UNSAFE_componentWillReceivePropsUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + } + ); + pendingUNSAFE_ComponentWillReceivePropsWarnings = []; } - } - if (element._owner) { - var owner = element._owner; - var inst; + var componentWillUpdateUniqueNames = new Set(); - if (owner) { - var ownerFiber = owner; + if (pendingComponentWillUpdateWarnings.length > 0) { + pendingComponentWillUpdateWarnings.forEach(function (fiber) { + componentWillUpdateUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingComponentWillUpdateWarnings = []; + } - 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" + 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' - inst = ownerFiber.stateNode; - } + if (UNSAFE_componentWillMountUniqueNames.size > 0) { + var sortedNames = setToSortedString( + UNSAFE_componentWillMountUniqueNames + ); - 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." + 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 ); - } // Assigning this to a const so Flow knows it won't change in the closure + } - var resolvedInst = inst; + if (UNSAFE_componentWillReceivePropsUniqueNames.size > 0) { + var _sortedNames = setToSortedString( + UNSAFE_componentWillReceivePropsUniqueNames + ); - { - checkPropStringCoercion(mixedRef, "ref"); + 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 stringRef = "" + mixedRef; // Check if previous string ref matches new string ref + if (UNSAFE_componentWillUpdateUniqueNames.size > 0) { + var _sortedNames2 = setToSortedString( + UNSAFE_componentWillUpdateUniqueNames + ); - if ( - current !== null && - current.ref !== null && - typeof current.ref === "function" && - current.ref._stringRef === stringRef - ) { - return current.ref; + 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 + ); } - var ref = function (value) { - var refs = resolvedInst.refs; - - if (value === null) { - delete refs[stringRef]; - } else { - refs[stringRef] = value; - } - }; + if (componentWillMountUniqueNames.size > 0) { + var _sortedNames3 = setToSortedString( + componentWillMountUniqueNames + ); - 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." + 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 (!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 (componentWillReceivePropsUniqueNames.size > 0) { + var _sortedNames4 = setToSortedString( + componentWillReceivePropsUniqueNames ); - } - } - } - return mixedRef; - } + 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 throwOnInvalidObjectType(returnFiber, newChild) { - // $FlowFixMe[method-unbinding] - var childString = Object.prototype.toString.call(newChild); - throw new Error( - "Objects are not valid as a React child (found: " + - (childString === "[object Object]" - ? "object with keys {" + Object.keys(newChild).join(", ") + "}" - : childString) + - "). " + - "If you meant to render a collection of children, use an array " + - "instead." - ); - } + if (componentWillUpdateUniqueNames.size > 0) { + var _sortedNames5 = setToSortedString( + componentWillUpdateUniqueNames + ); - function warnOnFunctionType(returnFiber) { - { - var componentName = - getComponentNameFromFiber(returnFiber) || "Component"; + 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 (ownerHasFunctionTypeWarning[componentName]) { - return; - } + var pendingLegacyContextWarning = new Map(); // Tracks components we have already warned about. - ownerHasFunctionTypeWarning[componentName] = true; + var didWarnAboutLegacyContext = new Set(); - 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." - ); - } - } + ReactStrictModeWarnings.recordLegacyContextWarning = function ( + fiber, + instance + ) { + var strictRoot = findStrictRoot(fiber); - 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 (strictRoot === null) { + error( + "Expected to find a StrictMode component in a strict mode tree. " + + "This error is likely caused by a bug in React. Please file an issue." + ); - function createChildReconciler(shouldTrackSideEffects) { - function deleteChild(returnFiber, childToDelete) { - if (!shouldTrackSideEffects) { - // Noop. return; - } - - var deletions = returnFiber.deletions; + } // Dedup strategy: Warn once per component. - if (deletions === null) { - returnFiber.deletions = [childToDelete]; - returnFiber.flags |= ChildDeletion; - } else { - deletions.push(childToDelete); + if (didWarnAboutLegacyContext.has(fiber.type)) { + return; } - } - function deleteRemainingChildren(returnFiber, currentFirstChild) { - if (!shouldTrackSideEffects) { - // Noop. - return null; - } // TODO: For the shouldClone case, this could be micro-optimized a bit by - // assuming that after the first child we've already added everything. + var warningsForRoot = pendingLegacyContextWarning.get(strictRoot); - var childToDelete = currentFirstChild; + if ( + fiber.type.contextTypes != null || + fiber.type.childContextTypes != null || + (instance !== null && typeof instance.getChildContext === "function") + ) { + if (warningsForRoot === undefined) { + warningsForRoot = []; + pendingLegacyContextWarning.set(strictRoot, warningsForRoot); + } - while (childToDelete !== null) { - deleteChild(returnFiber, childToDelete); - childToDelete = childToDelete.sibling; + warningsForRoot.push(fiber); } + }; - return null; - } + ReactStrictModeWarnings.flushLegacyContextWarning = function () { + pendingLegacyContextWarning.forEach(function (fiberArray, strictRoot) { + if (fiberArray.length === 0) { + 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 firstFiber = fiberArray[0]; + var uniqueNames = new Set(); + fiberArray.forEach(function (fiber) { + uniqueNames.add(getComponentNameFromFiber(fiber) || "Component"); + didWarnAboutLegacyContext.add(fiber.type); + }); + var sortedNames = setToSortedString(uniqueNames); - while (existingChild !== null) { - if (existingChild.key !== null) { - existingChildren.set(existingChild.key, existingChild); - } else { - existingChildren.set(existingChild.index, existingChild); + try { + setCurrentFiber(firstFiber); + + error( + "Legacy context API has been detected within a strict-mode tree." + + "\n\nThe old API will be supported in all 16.x releases, but applications " + + "using it should migrate to the new version." + + "\n\nPlease update the following components: %s" + + "\n\nLearn more about this warning here: https://reactjs.org/link/legacy-context", + sortedNames + ); + } finally { + resetCurrentFiber(); } + }); + }; - existingChild = existingChild.sibling; - } + ReactStrictModeWarnings.discardPendingWarnings = function () { + pendingComponentWillMountWarnings = []; + pendingUNSAFE_ComponentWillMountWarnings = []; + pendingComponentWillReceivePropsWarnings = []; + pendingUNSAFE_ComponentWillReceivePropsWarnings = []; + pendingComponentWillUpdateWarnings = []; + pendingUNSAFE_ComponentWillUpdateWarnings = []; + pendingLegacyContextWarning = new Map(); + }; + } - return existingChildren; - } + /* + * The `'' + value` pattern (used in perf-sensitive code) throws for Symbol + * and Temporal.* types. See https://github.com/facebook/react/pull/22064. + * + * The functions in this module will throw an easier-to-understand, + * easier-to-debug exception with a clear errors message message explaining the + * problem. (Instead of a confusing exception thrown inside the implementation + * of the `value` object). + */ + // $FlowFixMe[incompatible-return] only called in DEV, so void return is not possible. + function typeName(value) { + { + // toStringTag is needed for namespaced types like Temporal.Instant + var hasToStringTag = typeof Symbol === "function" && Symbol.toStringTag; + var type = + (hasToStringTag && value[Symbol.toStringTag]) || + value.constructor.name || + "Object"; // $FlowFixMe[incompatible-return] - function useFiber(fiber, pendingProps) { - // We currently set sibling to null and index to 0 here because it is easy - // to forget to do before returning it. E.g. for the single child case. - var clone = createWorkInProgress(fiber, pendingProps); - clone.index = 0; - clone.sibling = null; - return clone; + return type; } + } // $FlowFixMe[incompatible-return] only called in DEV, so void return is not possible. - function placeChild(newFiber, lastPlacedIndex, newIndex) { - newFiber.index = newIndex; - - if (!shouldTrackSideEffects) { - // During hydration, the useId algorithm needs to know which fibers are - // part of a list of children (arrays, iterators). - newFiber.flags |= Forked; - return lastPlacedIndex; + function willCoercionThrow(value) { + { + try { + testStringCoercion(value); + return false; + } catch (e) { + return true; } + } + } - var current = newFiber.alternate; - - if (current !== null) { - var oldIndex = current.index; + function testStringCoercion(value) { + // If you ended up here by following an exception call stack, here's what's + // happened: you supplied an object or symbol value to React (as a prop, key, + // DOM attribute, CSS property, string ref, etc.) and when React tried to + // coerce it to a string using `'' + value`, an exception was thrown. + // + // The most common types that will cause this exception are `Symbol` instances + // and Temporal objects like `Temporal.Instant`. But any object that has a + // `valueOf` or `[Symbol.toPrimitive]` method that throws will also cause this + // exception. (Library authors do this to prevent users from using built-in + // numeric operators like `+` or comparison operators like `>=` because custom + // methods are needed to perform accurate arithmetic or comparison.) + // + // To fix the problem, coerce this object or symbol value to a string before + // passing it to React. The most reliable way is usually `String(value)`. + // + // To find which value is throwing, check the browser or debugger console. + // Before this exception was thrown, there should be `console.error` output + // that shows the type (Symbol, Temporal.PlainDate, etc.) that caused the + // problem and how that type was used: key, atrribute, input value prop, etc. + // In most cases, this console output also shows the component and its + // ancestor components where the exception happened. + // + // eslint-disable-next-line react-internal/safe-string-coercion + return "" + value; + } + function checkKeyStringCoercion(value) { + { + if (willCoercionThrow(value)) { + error( + "The provided key is an unsupported type %s." + + " This value must be coerced to a string before using it here.", + typeName(value) + ); - if (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 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) + ); - function placeSingleChild(newFiber) { - // This is simpler for the single child case. We only need to do a - // placement for inserting new children. - if (shouldTrackSideEffects && newFiber.alternate === null) { - newFiber.flags |= Placement | PlacementDEV; + return testStringCoercion(value); // throw (to help callers find troubleshooting comments) } - - return newFiber; } + } - 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; - } - } + var ReactCurrentActQueue$2 = ReactSharedInternals.ReactCurrentActQueue; // An error that is thrown (e.g. by `use`) to trigger Suspense. If we + // detect this is caught by userspace, we'll log a warning in development. - function updateElement(returnFiber, current, element, lanes) { - var elementType = element.type; + 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 (elementType === REACT_FRAGMENT_TYPE) { - return updateFragment( - returnFiber, - current, - element.props.children, - lanes, - element.key + var noopSuspenseyCommitThenable = { + then: function () { + { + error( + "Internal React error: A listener was unexpectedly attached to a " + + '"noop" thenable. This is a bug in React. Please file an issue.' ); } + } + }; + function createThenableState() { + // The ThenableState is created the first time a component suspends. If it + // suspends again, we'll reuse the same state. + return []; + } + function isThenableResolved(thenable) { + var status = thenable.status; + return status === "fulfilled" || status === "rejected"; + } - 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; - - { - existing._debugSource = element._source; - existing._debugOwner = element._owner; - } - - return existing; - } - } // Insert + function noop() {} - var created = createFiberFromElement(element, returnFiber.mode, lanes); - created.ref = coerceRef(returnFiber, current, element); - created.return = returnFiber; - return created; + function trackUsedThenable(thenableState, thenable, index) { + if (ReactCurrentActQueue$2.current !== null) { + ReactCurrentActQueue$2.didUsePromise = 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; - } - } + var previous = thenableState[index]; - 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 (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; } - } - - 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 use an expando to track the status and result of a thenable so that we + // can synchronously unwrap the value. Think of this as an extension of the + // Promise API, or a custom interface that is a superset of Thenable. + // + // If the thenable doesn't have a status, set it to "pending" and attach + // a listener that will update its status and result when it resolves. + + switch (thenable.status) { + case "fulfilled": { + var fulfilledValue = thenable.value; + return fulfilledValue; } - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: { - var _created = createFiberFromElement( - newChild, - returnFiber.mode, - lanes - ); + case "rejected": { + var rejectedError = thenable.reason; + checkIfUseWrappedInAsyncCatch(rejectedError); + throw rejectedError; + } - _created.ref = coerceRef(returnFiber, null, newChild); - _created.return = returnFiber; - return _created; - } + 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(); - case REACT_PORTAL_TYPE: { - var _created2 = createFiberFromPortal( - newChild, - returnFiber.mode, - lanes + 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." ); - - _created2.return = returnFiber; - return _created2; } - case REACT_LAZY_TYPE: { - var payload = newChild._payload; - var init = newChild._init; - return createChild(returnFiber, init(payload), lanes); - } - } + var pendingThenable = thenable; + pendingThenable.status = "pending"; + pendingThenable.then( + function (fulfilledValue) { + if (thenable.status === "pending") { + var fulfilledThenable = thenable; + fulfilledThenable.status = "fulfilled"; + fulfilledThenable.value = fulfilledValue; + } + }, + function (error) { + if (thenable.status === "pending") { + var rejectedThenable = thenable; + rejectedThenable.status = "rejected"; + rejectedThenable.reason = error; + } + } + ); // Check one more time in case the thenable resolved synchronously. - if (isArray(newChild) || getIteratorFn(newChild)) { - var _created3 = createFiberFromFragment( - newChild, - returnFiber.mode, - lanes, - null - ); + switch (thenable.status) { + case "fulfilled": { + var fulfilledThenable = thenable; + return fulfilledThenable.value; + } - _created3.return = returnFiber; - return _created3; - } // Usable node types + case "rejected": { + var rejectedThenable = thenable; + var _rejectedError = rejectedThenable.reason; + checkIfUseWrappedInAsyncCatch(_rejectedError); + throw _rejectedError; + } + } + } // Suspend. // - // Unwrap the inner value and recursively call this function again. + // Throwing here is an implementation detail that allows us to unwind the + // call stack. But we shouldn't allow it to leak into userspace. Throw an + // opaque placeholder value instead of the actual thenable. If it doesn't + // get captured by the work loop, log a warning, because that means + // something in userspace must have caught it. - if (typeof newChild.then === "function") { - var thenable = newChild; - return createChild(returnFiber, unwrapThenable(thenable), lanes); - } + suspendedThenable = thenable; - if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) { - var context = newChild; - return createChild( - returnFiber, - readContextDuringReconcilation(returnFiber, context, lanes), - lanes - ); + { + needsToResetSuspendedThenableDEV = true; } - throwOnInvalidObjectType(returnFiber, newChild); - } - - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber); - } + throw SuspenseException; } + } + } + // passed to the rest of the Suspense implementation — which, for historical + // reasons, expects to receive a thenable. - return null; + 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 updateSlot(returnFiber, oldFiber, newChild, lanes) { - // Update the fiber if the keys match, otherwise return null. - var key = oldFiber !== null ? oldFiber.key : null; + var thenable = suspendedThenable; + suspendedThenable = null; - if ( - (typeof newChild === "string" && newChild !== "") || - typeof newChild === "number" - ) { - // Text nodes don't have keys. If the previous node is implicitly keyed - // we can continue to replace it without aborting even if it is not a text - // node. - if (key !== null) { - return null; - } + { + needsToResetSuspendedThenableDEV = false; + } - return updateTextNode(returnFiber, oldFiber, "" + newChild, lanes); + return thenable; + } + function checkIfUseWrappedInTryCatch() { + { + // This was set right before SuspenseException was thrown, and it should + // have been cleared when the exception was handled. If it wasn't, + // it must have been caught by userspace. + if (needsToResetSuspendedThenableDEV) { + needsToResetSuspendedThenableDEV = false; + return true; } + } - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: { - if (newChild.key === key) { - return updateElement(returnFiber, oldFiber, newChild, lanes); - } else { - return null; - } - } - - case REACT_PORTAL_TYPE: { - if (newChild.key === key) { - return updatePortal(returnFiber, oldFiber, newChild, lanes); - } else { - return null; - } - } - - case REACT_LAZY_TYPE: { - var payload = newChild._payload; - var init = newChild._init; - return updateSlot(returnFiber, oldFiber, init(payload), lanes); - } - } + 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)) { - if (key !== null) { - return null; - } + var thenableState$1 = null; + var thenableIndexCounter$1 = 0; + var didWarnAboutMaps; + var didWarnAboutGenerators; + var didWarnAboutStringRefs; + var ownerHasKeyUseWarning; + var ownerHasFunctionTypeWarning; - return updateFragment(returnFiber, oldFiber, newChild, lanes, null); - } // 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 updateSlot( - returnFiber, - oldFiber, - 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 updateSlot( - returnFiber, - oldFiber, - 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 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 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 + + child._store.validated = true; + var componentName = + getComponentNameFromFiber(returnFiber) || "Component"; + + if (ownerHasKeyUseWarning[componentName]) { + return; } - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: { - var _matchedFiber = - existingChildren.get( - newChild.key === null ? newIdx : newChild.key - ) || null; + ownerHasKeyUseWarning[componentName] = true; - return updateElement(returnFiber, _matchedFiber, newChild, lanes); - } + error( + "Each child in a list should have a unique " + + '"key" prop. See https://reactjs.org/link/warning-keys for ' + + "more information." + ); + }; + } - case REACT_PORTAL_TYPE: { - var _matchedFiber2 = - existingChildren.get( - newChild.key === null ? newIdx : newChild.key - ) || null; + function isReactClass(type) { + return type.prototype && type.prototype.isReactComponent; + } - return updatePortal(returnFiber, _matchedFiber2, newChild, lanes); - } + function unwrapThenable(thenable) { + var index = thenableIndexCounter$1; + thenableIndexCounter$1 += 1; - case REACT_LAZY_TYPE: - var payload = newChild._payload; - var init = newChild._init; - return updateFromMap( - existingChildren, - returnFiber, - newIdx, - init(payload), - lanes + if (thenableState$1 === null) { + thenableState$1 = createThenableState(); + } + + return trackUsedThenable(thenableState$1, thenable, index); + } + + function coerceRef(returnFiber, current, element) { + var mixedRef = element.ref; + + 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"; + + 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 ); + + didWarnAboutStringRefs[componentName] = true; + } } + } - if (isArray(newChild) || getIteratorFn(newChild)) { - var _matchedFiber3 = existingChildren.get(newIdx) || null; + if (element._owner) { + var owner = element._owner; + var inst; - return updateFragment( - returnFiber, - _matchedFiber3, - newChild, - lanes, - null - ); - } // Usable node types - // - // Unwrap the inner value and recursively call this function again. + if (owner) { + var ownerFiber = owner; - if (typeof newChild.then === "function") { - var thenable = newChild; - return updateFromMap( - existingChildren, - returnFiber, - newIdx, - unwrapThenable(thenable), - 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" + ); + } + + inst = ownerFiber.stateNode; } - if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) { - var context = newChild; - return updateFromMap( - existingChildren, - returnFiber, - newIdx, - readContextDuringReconcilation(returnFiber, context, lanes), - lanes + if (!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 - throwOnInvalidObjectType(returnFiber, newChild); - } + var resolvedInst = inst; - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber); + { + checkPropStringCoercion(mixedRef, "ref"); } - } - return null; - } - /** - * Warns if there is a duplicate or missing key - */ + var stringRef = "" + mixedRef; // Check if previous string ref matches new string ref - function warnOnInvalidKey(child, knownKeys, returnFiber) { - { - if (typeof child !== "object" || child === null) { - return knownKeys; + if ( + current !== null && + current.ref !== null && + typeof current.ref === "function" && + current.ref._stringRef === stringRef + ) { + return current.ref; } - switch (child.$$typeof) { - case REACT_ELEMENT_TYPE: - case REACT_PORTAL_TYPE: - warnForMissingKey(child, returnFiber); - var key = child.key; + var ref = function (value) { + var refs = resolvedInst.refs; - if (typeof key !== "string") { - break; - } + if (value === null) { + delete refs[stringRef]; + } else { + refs[stringRef] = value; + } + }; + + ref._stringRef = stringRef; + return ref; + } else { + if (typeof mixedRef !== "string") { + throw new Error( + "Expected ref to be a function, a string, an object returned by React.createRef(), or null." + ); + } - if (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; - lastPlacedIndex = placeChild(_newFiber2, lastPlacedIndex, newIdx); + if (elementType === REACT_FRAGMENT_TYPE) { + return updateFragment( + returnFiber, + current, + element.props.children, + lanes, + element.key + ); + } - if (previousNewFiber === null) { - resultingFirstChild = _newFiber2; - } else { - previousNewFiber.sibling = _newFiber2; + 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; + + { + existing._debugSource = element._source; + 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 (isArray(newChild) || getIteratorFn(newChild)) { + var _created3 = createFiberFromFragment( + newChild, + returnFiber.mode, + lanes, + null + ); - if (newChildren == null) { - throw new Error("An iterable object provided no iterator."); - } + _created3.return = returnFiber; + return _created3; + } // Usable node types + // + // Unwrap the inner value and recursively call this function again. - var resultingFirstChild = null; - var previousNewFiber = null; - var oldFiber = currentFirstChild; - var lastPlacedIndex = 0; - var newIdx = 0; - var nextOldFiber = null; - var step = newChildren.next(); + if (typeof newChild.then === "function") { + var thenable = newChild; + return createChild(returnFiber, unwrapThenable(thenable), lanes); + } - for ( - ; - oldFiber !== null && !step.done; - newIdx++, step = newChildren.next() - ) { - if (oldFiber.index > newIdx) { - nextOldFiber = oldFiber; - oldFiber = null; - } else { - nextOldFiber = oldFiber.sibling; + if ( + newChild.$$typeof === REACT_CONTEXT_TYPE || + newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE + ) { + var context = newChild; + return createChild( + returnFiber, + readContextDuringReconcilation(returnFiber, context, lanes), + lanes + ); } - var newFiber = updateSlot(returnFiber, oldFiber, step.value, 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 || + newChild.$$typeof === REACT_SERVER_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 || + newChild.$$typeof === REACT_SERVER_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; + } + + break; } - if (isArray(newChild)) { - return reconcileChildrenArray( - returnFiber, - currentFirstChild, - newChild, - 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 (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. + lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); - if (typeof newChild.then === "function") { - var thenable = newChild; - return reconcileChildFibersImpl( - returnFiber, - currentFirstChild, - unwrapThenable(thenable), - lanes - ); + 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 ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) { - var context = newChild; - return reconcileChildFibersImpl( + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } + + if (newIdx === newChildren.length) { + // We've reached the end of the new children. We can delete the rest. + deleteRemainingChildren(returnFiber, oldFiber); + + return resultingFirstChild; + } + + if (oldFiber === null) { + // If we don't have any more existing children we can choose a fast path + // since the rest will all be insertions. + for (; newIdx < newChildren.length; newIdx++) { + var _newFiber = createChild( returnFiber, - currentFirstChild, - readContextDuringReconcilation(returnFiber, context, lanes), + newChildren[newIdx], lanes ); + + if (_newFiber === null) { + continue; + } + + lastPlacedIndex = placeChild(_newFiber, lastPlacedIndex, newIdx); + + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = _newFiber; + } else { + previousNewFiber.sibling = _newFiber; + } + + previousNewFiber = _newFiber; } - throwOnInvalidObjectType(returnFiber, newChild); - } + return resultingFirstChild; + } // Add all children to a key map for quick lookups. - if ( - (typeof newChild === "string" && newChild !== "") || - typeof newChild === "number" - ) { - return placeSingleChild( - reconcileSingleTextNode( - returnFiber, - currentFirstChild, - "" + newChild, - lanes - ) + var existingChildren = mapRemainingChildren(returnFiber, oldFiber); // Keep scanning and use the map to restore deleted items as moves. + + for (; newIdx < newChildren.length; newIdx++) { + var _newFiber2 = updateFromMap( + existingChildren, + returnFiber, + newIdx, + newChildren[newIdx], + lanes ); - } - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber); + if (_newFiber2 !== null) { + if (shouldTrackSideEffects) { + if (_newFiber2.alternate !== null) { + // The new fiber is a work in progress, but if there exists a + // current, that means that we reused the fiber. We need to delete + // it from the child list so that we don't add it to the deletion + // list. + existingChildren.delete( + _newFiber2.key === null ? newIdx : _newFiber2.key + ); + } + } + + lastPlacedIndex = placeChild(_newFiber2, lastPlacedIndex, newIdx); + + if (previousNewFiber === null) { + resultingFirstChild = _newFiber2; + } else { + previousNewFiber.sibling = _newFiber2; + } + + previousNewFiber = _newFiber2; } - } // Remaining cases are all treated as empty. + } - return deleteRemainingChildren(returnFiber, currentFirstChild); + 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 reconcileChildFibers( + function reconcileChildrenIterator( returnFiber, currentFirstChild, - newChild, + newChildrenIterable, lanes ) { - // This indirection only exists so we can reset `thenableState` at the end. - // It should get inlined by Closure. - thenableIndexCounter$1 = 0; - var firstChildFiber = reconcileChildFibersImpl( - returnFiber, - currentFirstChild, - newChild, - lanes - ); - thenableState$1 = null; // Don't bother to reset `thenableIndexCounter` to 0 because it always gets - // set at the beginning. - - return firstChildFiber; - } + // This is the same implementation as reconcileChildrenArray(), + // but using the iterator instead. + var iteratorFn = getIteratorFn(newChildrenIterable); - return reconcileChildFibers; - } + 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 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."); - } + { + // 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 (workInProgress.child === null) { - return; - } + didWarnAboutGenerators = true; + } // Warn about using Maps as children - var currentChild = workInProgress.child; - var newChild = createWorkInProgress( - currentChild, - currentChild.pendingProps - ); - workInProgress.child = newChild; - newChild.return = workInProgress; + if (newChildrenIterable.entries === iteratorFn) { + if (!didWarnAboutMaps) { + error( + "Using Maps as children is not supported. " + + "Use an array of keyed ReactElements instead." + ); + } - while (currentChild.sibling !== null) { - currentChild = currentChild.sibling; - newChild = newChild.sibling = createWorkInProgress( - currentChild, - currentChild.pendingProps - ); - newChild.return = workInProgress; - } + didWarnAboutMaps = true; + } // First, validate keys. + // We'll get a different iterator later for the main pass. - newChild.sibling = null; - } // Reset a workInProgress child set to prepare it for a second pass. + var _newChildren = iteratorFn.call(newChildrenIterable); - function resetChildFibers(workInProgress, lanes) { - var child = workInProgress.child; + if (_newChildren) { + var knownKeys = null; - while (child !== null) { - resetWorkInProgress(child, lanes); - child = child.sibling; - } - } + var _step = _newChildren.next(); - // TODO: This isn't being used yet, but it's intended to replace the - // InvisibleParentContext that is currently managed by SuspenseContext. + for (; !_step.done; _step = _newChildren.next()) { + var child = _step.value; + knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber); + } + } + } - var currentTreeHiddenStackCursor = createCursor(null); - var prevEntangledRenderLanesCursor = createCursor(NoLanes); - function pushHiddenContext(fiber, context) { - var prevEntangledRenderLanes = getEntangledRenderLanes(); - push(prevEntangledRenderLanesCursor, prevEntangledRenderLanes, fiber); - push(currentTreeHiddenStackCursor, context, fiber); // When rendering a subtree that's currently hidden, we must include all - // lanes that would have rendered if the hidden subtree hadn't been deferred. - // That is, in order to reveal content from hidden -> visible, we must commit - // all the updates that we skipped when we originally hid the tree. + var newChildren = iteratorFn.call(newChildrenIterable); - 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; - } + if (newChildren == null) { + throw new Error("An iterable object provided no iterator."); + } - // suspends, i.e. it's the nearest `catch` block on the stack. + var resultingFirstChild = null; + var previousNewFiber = null; + var oldFiber = currentFirstChild; + var lastPlacedIndex = 0; + var newIdx = 0; + var nextOldFiber = null; + var step = newChildren.next(); - 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. + for ( + ; + oldFiber !== null && !step.done; + newIdx++, step = newChildren.next() + ) { + if (oldFiber.index > newIdx) { + nextOldFiber = oldFiber; + oldFiber = null; + } else { + nextOldFiber = oldFiber.sibling; + } - var shellBoundary = null; - function getShellBoundary() { - return shellBoundary; - } - function pushPrimaryTreeSuspenseHandler(handler) { - // TODO: Pass as argument - var current = handler.alternate; - // propagated a single level. For example, when ForceSuspenseFallback is set, - // it should only force the nearest Suspense boundary into fallback mode. + var newFiber = updateSlot(returnFiber, oldFiber, step.value, lanes); - pushSuspenseListContext( - handler, - setDefaultShallowSuspenseListContext(suspenseStackCursor.current) - ); // Experimental feature: Some Suspense boundaries are marked as having an - // to push a nested Suspense handler, because it will get replaced by the - // outer fallback, anyway. Consider this as a future optimization. + if (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; + } - push(suspenseHandlerStackCursor, handler, handler); + break; + } - if (shellBoundary === null) { - if (current === null || isCurrentTreeHidden()) { - // This boundary is not visible in the current UI. - shellBoundary = handler; - } else { - var prevState = current.memoizedState; + 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 (prevState !== null) { - // This boundary is showing a fallback in the current UI. - shellBoundary = handler; + lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); + + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = newFiber; + } else { + // TODO: Defer siblings if we're not at the right index for this slot. + // I.e. if we had null values before, then we want to defer this + // for each null value. However, we also don't want to call updateSlot + // with the previous one. + previousNewFiber.sibling = newFiber; } + + previousNewFiber = newFiber; + oldFiber = nextOldFiber; } - } - } - function pushFallbackTreeSuspenseHandler(fiber) { - // We're about to render the fallback. If something in the fallback suspends, - // it's akin to throwing inside of a `catch` block. This boundary should not - // capture. Reuse the existing handler on the stack. - reuseSuspenseHandlerOnStack(fiber); - } - function pushOffscreenSuspenseHandler(fiber) { - if (fiber.tag === OffscreenComponent) { - // A SuspenseList context is only pushed here to avoid a push/pop mismatch. - // Reuse the current value on the stack. - // TODO: We can avoid needing to push here by by forking popSuspenseHandler - // into separate functions for Suspense and Offscreen. - pushSuspenseListContext(fiber, suspenseStackCursor.current); - push(suspenseHandlerStackCursor, fiber, fiber); - if (shellBoundary !== null); - else { - var current = fiber.alternate; + if (step.done) { + // We've reached the end of the new children. We can delete the rest. + deleteRemainingChildren(returnFiber, oldFiber); - if (current !== null) { - var prevState = current.memoizedState; + return resultingFirstChild; + } - if (prevState !== null) { - // This is the first boundary in the stack that's already showing - // a fallback. So everything outside is considered the shell. - shellBoundary = fiber; + if (oldFiber === null) { + // If we don't have any more existing children we can choose a fast path + // since the rest will all be insertions. + for (; !step.done; newIdx++, step = newChildren.next()) { + var _newFiber3 = createChild(returnFiber, step.value, lanes); + + if (_newFiber3 === null) { + continue; } - } - } - } 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; - } + lastPlacedIndex = placeChild(_newFiber3, lastPlacedIndex, newIdx); - popSuspenseListContext(fiber); - } // SuspenseList context - // TODO: Move to a separate module? We may change the SuspenseList - // implementation to hide/show in the commit phase, anyway. + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = _newFiber3; + } else { + previousNewFiber.sibling = _newFiber3; + } - 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. + previousNewFiber = _newFiber3; + } - 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); - } + return resultingFirstChild; + } // Add all children to a key map for quick lookups. - // 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 existingChildren = mapRemainingChildren(returnFiber, oldFiber); // Keep scanning and use the map to restore deleted items as moves. - function findFirstSuspended(row) { - var node = row; + for (; !step.done; newIdx++, step = newChildren.next()) { + var _newFiber4 = updateFromMap( + existingChildren, + returnFiber, + newIdx, + step.value, + lanes + ); - while (node !== null) { - if (node.tag === SuspenseComponent) { - var state = node.memoizedState; + 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 (state !== null) { - var dehydrated = state.dehydrated; + lastPlacedIndex = placeChild(_newFiber4, lastPlacedIndex, newIdx); - if ( - dehydrated === null || - isSuspenseInstancePending() || - isSuspenseInstanceFallback() - ) { - return node; + if (previousNewFiber === null) { + resultingFirstChild = _newFiber4; + } else { + previousNewFiber.sibling = _newFiber4; } - } - } 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; + previousNewFiber = _newFiber4; } - } else if (node.child !== null) { - node.child.return = node; - node = node.child; - continue; } - if (node === row) { - return null; + 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); + }); } - while (node.sibling === null) { - if (node.return === null || node.return === row) { - return null; - } + return resultingFirstChild; + } - node = node.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. - node.sibling.return = node.return; - node = node.sibling; + deleteRemainingChildren(returnFiber, currentFirstChild); + var created = createFiberFromText(textContent, returnFiber.mode, lanes); + created.return = returnFiber; + return created; } - return null; - } + function reconcileSingleElement( + returnFiber, + currentFirstChild, + element, + lanes + ) { + var key = element.key; + var child = currentFirstChild; - var NoFlags = - /* */ - 0; // Represents whether effect should fire. + while (child !== null) { + // TODO: If key === null and child.key === null, then this only applies to + // the first item in the list. + if (child.key === key) { + var elementType = element.type; - var HasEffect = - /* */ - 1; // Represents the phase in which the effect (not the clean-up) fires. + if (elementType === REACT_FRAGMENT_TYPE) { + if (child.tag === Fragment) { + deleteRemainingChildren(returnFiber, child.sibling); + var existing = useFiber(child, element.props.children); + existing.return = returnFiber; - var Insertion = - /* */ - 2; - var Layout = - /* */ - 4; - var Passive = - /* */ - 8; + { + existing._debugSource = element._source; + existing._debugOwner = element._owner; + } - 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 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 firstScheduledRoot = null; - var lastScheduledRoot = null; // Used to prevent redundant mircotasks from being scheduled. + var _existing = useFiber(child, element.props); - 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. + _existing.ref = coerceRef(returnFiber, child, element); + _existing.return = returnFiber; - var didScheduleMicrotask_act = false; // Used to quickly bail out of flushSync if there's no sync work to do. + { + _existing._debugSource = element._source; + _existing._debugOwner = element._owner; + } - 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. + return _existing; + } + } // Didn't match. - 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. + deleteRemainingChildren(returnFiber, child); + break; + } else { + deleteChild(returnFiber, child); + } - if (ReactCurrentActQueue$2.current !== null) { - // We're inside an `act` scope. - if (!didScheduleMicrotask_act) { - didScheduleMicrotask_act = true; - scheduleImmediateTask(processRootScheduleInMicrotask); - } - } else { - if (!didScheduleMicrotask) { - didScheduleMicrotask = true; - scheduleImmediateTask(processRootScheduleInMicrotask); + child = child.sibling; } - } - - if (!enableDeferRootSchedulingToMicrotask) { - // While this flag is disabled, we schedule the render task immediately - // instead of waiting a microtask. - // TODO: We need to land enableDeferRootSchedulingToMicrotask ASAP to - // unblock additional features we have planned. - scheduleTaskForRootDuringMicrotask(root, now$1()); - } - - if (ReactCurrentActQueue$2.isBatchingLegacy && root.tag === LegacyRoot) { - // Special `act` case: Record whenever a legacy update is scheduled. - ReactCurrentActQueue$2.didScheduleLegacyUpdate = true; - } - } - function flushSyncWorkOnAllRoots() { - // This is allowed to be called synchronously, but the caller should check - // the execution context first. - flushSyncWorkAcrossRoots_impl(false); - } - function flushSyncWorkOnLegacyRootsOnly() { - // This is allowed to be called synchronously, but the caller should check - // the execution context first. - flushSyncWorkAcrossRoots_impl(true); - } - - function flushSyncWorkAcrossRoots_impl(onlyLegacy) { - if (isFlushingWork) { - // Prevent reentrancy. - // TODO: Is this overly defensive? The callers must check the execution - // context first regardless. - return; - } - - if (!mightHavePendingSyncWork) { - // Fast path. There's no sync work to do. - return; - } // There may or may not be synchronous work scheduled. Let's check. - var didPerformSomeWork; - var errors = null; - isFlushingWork = true; + 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 + ); - do { - didPerformSomeWork = false; - var root = firstScheduledRoot; + _created4.ref = coerceRef(returnFiber, currentFirstChild, element); + _created4.return = returnFiber; + return _created4; + } + } - while (root !== null) { - if (onlyLegacy && root.tag !== LegacyRoot); - else { - var workInProgressRoot = getWorkInProgressRoot(); - var workInProgressRootRenderLanes = - getWorkInProgressRootRenderLanes(); - var nextLanes = getNextLanes( - root, - root === workInProgressRoot - ? workInProgressRootRenderLanes - : NoLanes - ); + function reconcileSinglePortal( + returnFiber, + currentFirstChild, + portal, + lanes + ) { + var key = portal.key; + var child = currentFirstChild; - 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); - } - } + 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); } - 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. + var created = createFiberFromPortal(portal, returnFiber.mode, lanes); + created.return = returnFiber; + return created; + } // This API will tag the children with the side-effect of the reconciliation + // itself. They will be added to the side-effect list as we pass through the + // children and the parent. - if (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])); - } + 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; - var firstError = errors[0]; - throw firstError; + if (isUnkeyedTopLevelFragment) { + newChild = newChild.props.children; + } // Handle object types + + if (typeof newChild === "object" && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return placeSingleChild( + reconcileSingleElement( + returnFiber, + currentFirstChild, + newChild, + lanes + ) + ); + + case REACT_PORTAL_TYPE: + return placeSingleChild( + reconcileSinglePortal( + returnFiber, + currentFirstChild, + newChild, + lanes + ) + ); + + case REACT_LAZY_TYPE: + var payload = newChild._payload; + var init = newChild._init; // TODO: This function is supposed to be non-recursive. + + return reconcileChildFibers( + returnFiber, + currentFirstChild, + init(payload), + lanes + ); } - } else { - var error = errors[0]; - throw error; - } - } - } - function throwError(error) { - throw error; - } + if (isArray(newChild)) { + return reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChild, + lanes + ); + } - function processRootScheduleInMicrotask() { - // This function is always called inside a microtask. It should never be - // called synchronously. - didScheduleMicrotask = false; + 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. - { - didScheduleMicrotask_act = false; - } // We'll recompute this as we iterate through all the roots and schedule them. + if (typeof newChild.then === "function") { + var thenable = newChild; + return reconcileChildFibersImpl( + returnFiber, + currentFirstChild, + unwrapThenable(thenable), + lanes + ); + } - mightHavePendingSyncWork = false; - var currentTime = now$1(); - var prev = null; - var root = firstScheduledRoot; + if ( + newChild.$$typeof === REACT_CONTEXT_TYPE || + newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE + ) { + var context = newChild; + return reconcileChildFibersImpl( + returnFiber, + currentFirstChild, + readContextDuringReconcilation(returnFiber, context, lanes), + lanes + ); + } - while (root !== null) { - var next = root.next; + throwOnInvalidObjectType(returnFiber, newChild); + } if ( - currentEventTransitionLane !== NoLane && - shouldAttemptEagerTransition() + (typeof newChild === "string" && newChild !== "") || + typeof newChild === "number" ) { - // 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); + return placeSingleChild( + reconcileSingleTextNode( + returnFiber, + currentFirstChild, + "" + newChild, + lanes + ) + ); } - var nextLanes = scheduleTaskForRootDuringMicrotask(root, currentTime); - - if (nextLanes === NoLane) { - // This root has no more pending work. Remove it from the schedule. To - // guard against subtle reentrancy bugs, this microtask is the only place - // we do this — you can add roots to the schedule whenever, but you can - // only remove them here. - // Null this out so we know it's been removed from the schedule. - root.next = null; - - if (prev === null) { - // This is the new head of the list - firstScheduledRoot = next; - } else { - prev.next = next; + { + if (typeof newChild === "function") { + warnOnFunctionType(returnFiber); } + } // Remaining cases are all treated as empty. - 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; + return deleteRemainingChildren(returnFiber, currentFirstChild); + } - if (includesSyncLane(nextLanes)) { - mightHavePendingSyncWork = true; - } - } + 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. - root = next; + return firstChildFiber; } - 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. + return reconcileChildFibers; + } - flushSyncWorkOnAllRoots(); + 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."); + } - 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 (workInProgress.child === null) { + return; + } - var workInProgressRoot = getWorkInProgressRoot(); - var workInProgressRootRenderLanes = getWorkInProgressRootRenderLanes(); - var nextLanes = getNextLanes( - root, - root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes + var currentChild = workInProgress.child; + var newChild = createWorkInProgress( + currentChild, + currentChild.pendingProps ); - var existingCallbackNode = root.callbackNode; + workInProgress.child = newChild; + newChild.return = workInProgress; - 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); - } + while (currentChild.sibling !== null) { + currentChild = currentChild.sibling; + newChild = newChild.sibling = createWorkInProgress( + currentChild, + currentChild.pendingProps + ); + newChild.return = workInProgress; + } - root.callbackNode = null; - root.callbackPriority = NoLane; - return NoLane; - } // Schedule a new callback in the host environment. + newChild.sibling = null; + } // Reset a workInProgress child set to prepare it for a second pass. - 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); - } + function resetChildFibers(workInProgress, lanes) { + var child = workInProgress.child; - 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); + while (child !== null) { + resetWorkInProgress(child, lanes); + child = child.sibling; + } + } - 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); - } + // TODO: This isn't being used yet, but it's intended to replace the + // InvisibleParentContext that is currently managed by SuspenseContext. - var schedulerPriorityLevel; + 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. - switch (lanesToEventPriority(nextLanes)) { - case DiscreteEventPriority: - schedulerPriorityLevel = ImmediatePriority; - break; + 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; + } - case ContinuousEventPriority: - schedulerPriorityLevel = UserBlockingPriority; - break; + // suspends, i.e. it's the nearest `catch` block on the stack. - case DefaultEventPriority: - schedulerPriorityLevel = NormalPriority; - break; + 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. - case IdleEventPriority: - schedulerPriorityLevel = IdlePriority; - break; + 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. - default: - schedulerPriorityLevel = NormalPriority; - break; - } + pushSuspenseListContext( + handler, + setDefaultShallowSuspenseListContext(suspenseStackCursor.current) + ); // Experimental feature: Some Suspense boundaries are marked as having an + // to push a nested Suspense handler, because it will get replaced by the + // outer fallback, anyway. Consider this as a future optimization. - var newCallbackNode = scheduleCallback$1( - schedulerPriorityLevel, - performConcurrentWorkOnRoot.bind(null, root) - ); - root.callbackPriority = newCallbackPriority; - root.callbackNode = newCallbackNode; - return newCallbackPriority; - } - } + push(suspenseHandlerStackCursor, handler, handler); - function getContinuationForRoot(root, originalCallbackNode) { - // This is called at the end of `performConcurrentWorkOnRoot` to determine - // if we need to schedule a continuation task. - // - // Usually `scheduleTaskForRootDuringMicrotask` only runs inside a microtask; - // however, since most of the logic for determining if we need a continuation - // versus a new task is the same, we cheat a bit and call it here. This is - // only safe to do because we know we're at the end of the browser task. - // So although it's not an actual microtask, it might as well be. - scheduleTaskForRootDuringMicrotask(root, now$1()); + if (shellBoundary === null) { + if (current === null || isCurrentTreeHidden()) { + // This boundary is not visible in the current UI. + shellBoundary = handler; + } else { + var prevState = current.memoizedState; - if (root.callbackNode === originalCallbackNode) { - // The task node scheduled for this root is the same one that's - // currently executed. Need to return a continuation. - return performConcurrentWorkOnRoot.bind(null, root); + if (prevState !== null) { + // This boundary is showing a fallback in the current UI. + shellBoundary = handler; + } + } } + } + function pushFallbackTreeSuspenseHandler(fiber) { + // We're about to render the fallback. If something in the fallback suspends, + // it's akin to throwing inside of a `catch` block. This boundary should not + // capture. Reuse the existing handler on the stack. + reuseSuspenseHandlerOnStack(fiber); + } + function pushOffscreenSuspenseHandler(fiber) { + if (fiber.tag === OffscreenComponent) { + // A SuspenseList context is only pushed here to avoid a push/pop mismatch. + // Reuse the current value on the stack. + // TODO: We can avoid needing to push here by by forking popSuspenseHandler + // into separate functions for Suspense and Offscreen. + pushSuspenseListContext(fiber, suspenseStackCursor.current); + push(suspenseHandlerStackCursor, fiber, fiber); + + if (shellBoundary !== null); + else { + var current = fiber.alternate; - return null; - } - var fakeActCallbackNode$1 = {}; + if (current !== null) { + var prevState = current.memoizedState; - 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; + 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 { - return scheduleCallback$2(priorityLevel, callback); + // This is a LegacyHidden component. + reuseSuspenseHandlerOnStack(fiber); } } - - function cancelCallback(callbackNode) { - if (callbackNode === fakeActCallbackNode$1); - else if (callbackNode !== null) { - cancelCallback$1(callbackNode); - } + function reuseSuspenseHandlerOnStack(fiber) { + pushSuspenseListContext(fiber, suspenseStackCursor.current); + push(suspenseHandlerStackCursor, getSuspenseHandler(), 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 microtasks are not supported, use Scheduler. - scheduleCallback$2(ImmediatePriority, cb); - } + 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. - // 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 DefaultSuspenseContext = 0; + var SubtreeSuspenseContextMask = 1; // ForceSuspenseFallback can be used by SuspenseList to force newly added + // items into their fallback state during one of the render passes. - var currentEntangledListeners = null; // The number of pending async actions in the entangled scope. + 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 currentEntangledPendingCount = 0; // The transition lane shared by all updates 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 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; + function findFirstSuspended(row) { + var node = row; - 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; @@ -11787,6 +11779,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 @@ -11829,6 +11822,17 @@ to return true:wantsResponderID| | ); markSkippedUpdateLanes(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; + } // Check if this is an optimistic update. + { // This is not an optimistic update, and we're going to apply it now. // But, if there were earlier updates that were skipped, we need to @@ -11875,7 +11879,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; @@ -12694,7 +12714,7 @@ to return true:wantsResponderID| | } try { - var returnValue, thenable, entangledResult, _entangledResult2; + var returnValue, thenable, thenableForFinishedState; if (enableAsyncActions); else { // Async actions are not enabled. @@ -14906,6 +14926,7 @@ to return true:wantsResponderID| | // process them now. processUpdateQueue(workInProgress, newProps, instance, renderLanes); + suspendIfUpdateReadFromEntangledAsyncAction(); instance.state = workInProgress.memoizedState; } @@ -14973,6 +14994,7 @@ to return true:wantsResponderID| | var oldState = workInProgress.memoizedState; var newState = (instance.state = oldState); processUpdateQueue(workInProgress, newProps, instance, renderLanes); + suspendIfUpdateReadFromEntangledAsyncAction(); newState = workInProgress.memoizedState; if ( @@ -15125,6 +15147,7 @@ to return true:wantsResponderID| | var oldState = workInProgress.memoizedState; var newState = (instance.state = oldState); processUpdateQueue(workInProgress, newProps, instance, renderLanes); + suspendIfUpdateReadFromEntangledAsyncAction(); newState = workInProgress.memoizedState; if ( @@ -15698,7 +15721,7 @@ to return true:wantsResponderID| | } } - return; + return false; } case OffscreenComponent: { @@ -15733,7 +15756,7 @@ to return true:wantsResponderID| | attachPingListener(root, wakeable, rootRenderLanes); } - return; + return false; } } } @@ -15756,7 +15779,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( @@ -15776,6 +15799,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 { @@ -15791,7 +15820,7 @@ to return true:wantsResponderID| | lane ); enqueueCapturedUpdate(workInProgress, update); - return; + return false; } case ClassComponent: @@ -15820,7 +15849,7 @@ to return true:wantsResponderID| | ); enqueueCapturedUpdate(workInProgress, _update); - return; + return false; } break; @@ -15828,6 +15857,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 @@ -16802,6 +16833,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; @@ -25242,7 +25277,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; } } @@ -25347,7 +25382,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; } @@ -25412,7 +25447,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; @@ -25477,7 +25512,7 @@ to return true:wantsResponderID| | workInProgressSuspendedReason = NotSuspended; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(unitOfWork, thrownValue); + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); break; } @@ -25488,7 +25523,7 @@ to return true:wantsResponderID| | // always unwind. workInProgressSuspendedReason = NotSuspended; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(unitOfWork, thrownValue); + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); break; } @@ -25716,7 +25751,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. // @@ -25725,40 +25760,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) { @@ -25778,6 +25806,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. @@ -28279,7 +28323,7 @@ to return true:wantsResponderID| | return root; } - var ReactVersion = "18.3.0-canary-e2b49fad"; + var ReactVersion = "18.3.0-canary-08bfc409"; function createPortal$1( children, diff --git a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-prod.fb.js b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-prod.fb.js index d271b2ec3bfcf..ed72c5c2358e1 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-prod.fb.js +++ b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-prod.fb.js @@ -7,7 +7,7 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<> + * @generated SignedSource<<08089ec617b423b74bdd6b2f946a0fd5>> */ "use strict"; @@ -940,7 +940,7 @@ eventPluginOrder = Array.prototype.slice.call([ "ReactNativeBridgeEventPlugin" ]); recomputePluginOrdering(); -var injectedNamesToPlugins$jscomp$inline_241 = { +var injectedNamesToPlugins$jscomp$inline_242 = { ResponderEventPlugin: ResponderEventPlugin, ReactNativeBridgeEventPlugin: { eventTypes: {}, @@ -986,32 +986,32 @@ var injectedNamesToPlugins$jscomp$inline_241 = { } } }, - isOrderingDirty$jscomp$inline_242 = !1, - pluginName$jscomp$inline_243; -for (pluginName$jscomp$inline_243 in injectedNamesToPlugins$jscomp$inline_241) + isOrderingDirty$jscomp$inline_243 = !1, + pluginName$jscomp$inline_244; +for (pluginName$jscomp$inline_244 in injectedNamesToPlugins$jscomp$inline_242) if ( - injectedNamesToPlugins$jscomp$inline_241.hasOwnProperty( - pluginName$jscomp$inline_243 + injectedNamesToPlugins$jscomp$inline_242.hasOwnProperty( + pluginName$jscomp$inline_244 ) ) { - var pluginModule$jscomp$inline_244 = - injectedNamesToPlugins$jscomp$inline_241[pluginName$jscomp$inline_243]; + var pluginModule$jscomp$inline_245 = + injectedNamesToPlugins$jscomp$inline_242[pluginName$jscomp$inline_244]; if ( - !namesToPlugins.hasOwnProperty(pluginName$jscomp$inline_243) || - namesToPlugins[pluginName$jscomp$inline_243] !== - pluginModule$jscomp$inline_244 + !namesToPlugins.hasOwnProperty(pluginName$jscomp$inline_244) || + namesToPlugins[pluginName$jscomp$inline_244] !== + pluginModule$jscomp$inline_245 ) { - if (namesToPlugins[pluginName$jscomp$inline_243]) + if (namesToPlugins[pluginName$jscomp$inline_244]) throw Error( "EventPluginRegistry: Cannot inject two different event plugins using the same name, `" + - (pluginName$jscomp$inline_243 + "`.") + (pluginName$jscomp$inline_244 + "`.") ); - namesToPlugins[pluginName$jscomp$inline_243] = - pluginModule$jscomp$inline_244; - isOrderingDirty$jscomp$inline_242 = !0; + namesToPlugins[pluginName$jscomp$inline_244] = + pluginModule$jscomp$inline_245; + isOrderingDirty$jscomp$inline_243 = !0; } } -isOrderingDirty$jscomp$inline_242 && recomputePluginOrdering(); +isOrderingDirty$jscomp$inline_243 && recomputePluginOrdering(); var instanceCache = new Map(), instanceProps = new Map(); function getInstanceFromTag(tag) { @@ -2216,6 +2216,219 @@ 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)); + enableDeferRootSchedulingToMicrotask || + 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; +} +function requestTransitionLane() { + if (0 === currentEventTransitionLane) { + var lane = nextTransitionLane; + nextTransitionLane <<= 1; + 0 === (nextTransitionLane & 4194176) && (nextTransitionLane = 128); + currentEventTransitionLane = lane; + } + return currentEventTransitionLane; +} var hasForceUpdate = !1; function initializeUpdateQueue(fiber) { fiber.updateQueue = { @@ -3435,219 +3648,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)); - enableDeferRootSchedulingToMicrotask || - 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$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, @@ -4732,6 +4732,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." @@ -5924,14 +6071,14 @@ function cutOffTailIfNeeded(renderState, hasRenderedATailFallback) { break; case "collapsed": lastTailNode = renderState.tail; - for (var lastTailNode$64 = null; null !== lastTailNode; ) - null !== lastTailNode.alternate && (lastTailNode$64 = lastTailNode), + for (var lastTailNode$65 = null; null !== lastTailNode; ) + null !== lastTailNode.alternate && (lastTailNode$65 = lastTailNode), (lastTailNode = lastTailNode.sibling); - null === lastTailNode$64 + null === lastTailNode$65 ? hasRenderedATailFallback || null === renderState.tail ? (renderState.tail = null) : (renderState.tail.sibling = null) - : (lastTailNode$64.sibling = null); + : (lastTailNode$65.sibling = null); } } function bubbleProperties(completedWork) { @@ -5941,19 +6088,19 @@ function bubbleProperties(completedWork) { newChildLanes = 0, subtreeFlags = 0; if (didBailout) - for (var child$65 = completedWork.child; null !== child$65; ) - (newChildLanes |= child$65.lanes | child$65.childLanes), - (subtreeFlags |= child$65.subtreeFlags & 31457280), - (subtreeFlags |= child$65.flags & 31457280), - (child$65.return = completedWork), - (child$65 = child$65.sibling); + for (var child$66 = completedWork.child; null !== child$66; ) + (newChildLanes |= child$66.lanes | child$66.childLanes), + (subtreeFlags |= child$66.subtreeFlags & 31457280), + (subtreeFlags |= child$66.flags & 31457280), + (child$66.return = completedWork), + (child$66 = child$66.sibling); else - for (child$65 = completedWork.child; null !== child$65; ) - (newChildLanes |= child$65.lanes | child$65.childLanes), - (subtreeFlags |= child$65.subtreeFlags), - (subtreeFlags |= child$65.flags), - (child$65.return = completedWork), - (child$65 = child$65.sibling); + for (child$66 = completedWork.child; null !== child$66; ) + (newChildLanes |= child$66.lanes | child$66.childLanes), + (subtreeFlags |= child$66.subtreeFlags), + (subtreeFlags |= child$66.flags), + (child$66.return = completedWork), + (child$66 = child$66.sibling); completedWork.subtreeFlags |= subtreeFlags; completedWork.childLanes = newChildLanes; return didBailout; @@ -6405,8 +6552,8 @@ function safelyDetachRef(current, nearestMountedAncestor) { else if ("function" === typeof ref) try { ref(null); - } catch (error$80) { - captureCommitPhaseError(current, nearestMountedAncestor, error$80); + } catch (error$81) { + captureCommitPhaseError(current, nearestMountedAncestor, error$81); } else ref.current = null; } @@ -6510,10 +6657,10 @@ function commitHookEffectListMount(flags, finishedWork) { var effect = (finishedWork = finishedWork.next); do { if ((effect.tag & flags) === flags) { - var create$81 = effect.create, + var create$82 = effect.create, inst = effect.inst; - create$81 = create$81(); - inst.destroy = create$81; + create$82 = create$82(); + inst.destroy = create$82; } effect = effect.next; } while (effect !== finishedWork); @@ -6567,11 +6714,11 @@ function commitLayoutEffectOnFiber(finishedRoot, current, finishedWork) { current, finishedRoot.__reactInternalSnapshotBeforeUpdate ); - } catch (error$82) { + } catch (error$83) { captureCommitPhaseError( finishedWork, finishedWork.return, - error$82 + error$83 ); } } @@ -7060,8 +7207,8 @@ function commitMutationEffectsOnFiber(finishedWork, root) { } try { commitHookEffectListUnmount(5, finishedWork, finishedWork.return); - } catch (error$90) { - captureCommitPhaseError(finishedWork, finishedWork.return, error$90); + } catch (error$91) { + captureCommitPhaseError(finishedWork, finishedWork.return, error$91); } } break; @@ -7108,8 +7255,8 @@ function commitMutationEffectsOnFiber(finishedWork, root) { viewConfig.uiViewClassName, updatePayload ); - } catch (error$93) { - captureCommitPhaseError(finishedWork, finishedWork.return, error$93); + } catch (error$94) { + captureCommitPhaseError(finishedWork, finishedWork.return, error$94); } } break; @@ -7129,8 +7276,8 @@ function commitMutationEffectsOnFiber(finishedWork, root) { "RCTRawText", { text: current } ); - } catch (error$94) { - captureCommitPhaseError(finishedWork, finishedWork.return, error$94); + } catch (error$95) { + captureCommitPhaseError(finishedWork, finishedWork.return, error$95); } } break; @@ -7242,11 +7389,11 @@ function commitMutationEffectsOnFiber(finishedWork, root) { if (null === current) try { throw Error("Not yet implemented."); - } catch (error$84) { + } catch (error$85) { captureCommitPhaseError( finishedWork, finishedWork.return, - error$84 + error$85 ); } } else if ( @@ -7320,12 +7467,12 @@ function commitReconciliationEffects(finishedWork) { break; case 3: case 4: - var parent$85 = JSCompiler_inline_result.stateNode.containerInfo, - before$86 = getHostSibling(finishedWork); + var parent$86 = JSCompiler_inline_result.stateNode.containerInfo, + before$87 = getHostSibling(finishedWork); insertOrAppendPlacementNodeIntoContainer( finishedWork, - before$86, - parent$85 + before$87, + parent$86 ); break; default: @@ -8177,13 +8324,13 @@ function renderRootSync(root, lanes) { default: (workInProgressSuspendedReason = 0), (workInProgressThrownValue = null), - throwAndUnwindWorkLoop(unitOfWork, thrownValue); + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue); } } workLoopSync(); break; - } catch (thrownValue$98) { - handleThrow(root, thrownValue$98); + } catch (thrownValue$99) { + handleThrow(root, thrownValue$99); } while (1); lanes && root.shellSuspendCounter++; @@ -8219,7 +8366,7 @@ function renderRootConcurrent(root, lanes) { case 1: workInProgressSuspendedReason = 0; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(lanes, thrownValue); + throwAndUnwindWorkLoop(root, lanes, thrownValue); break; case 2: if (isThenableResolved(thrownValue)) { @@ -8249,7 +8396,7 @@ function renderRootConcurrent(root, lanes) { replaySuspendedUnitOfWork(lanes)) : ((workInProgressSuspendedReason = 0), (workInProgressThrownValue = null), - throwAndUnwindWorkLoop(lanes, thrownValue)); + throwAndUnwindWorkLoop(root, lanes, thrownValue)); break; case 5: switch (workInProgress.tag) { @@ -8272,12 +8419,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(); @@ -8289,8 +8436,8 @@ function renderRootConcurrent(root, lanes) { } workLoopConcurrent(); break; - } catch (thrownValue$100) { - handleThrow(root, thrownValue$100); + } catch (thrownValue$101) { + handleThrow(root, thrownValue$101); } while (1); resetContextDependencies(); @@ -8368,191 +8515,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$34 = offscreenQueue.retryQueue; - null === retryQueue$34 - ? (offscreenQueue.retryQueue = new Set([wakeable])) - : retryQueue$34.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; @@ -9772,10 +9783,10 @@ batchedUpdatesImpl = function (fn, a) { } }; var roots = new Map(), - devToolsConfig$jscomp$inline_1117 = { + devToolsConfig$jscomp$inline_1115 = { findFiberByHostInstance: getInstanceFromTag, bundleType: 0, - version: "18.3.0-canary-d76fd1b4", + version: "18.3.0-canary-eebf2655", rendererPackageName: "react-native-renderer", rendererConfig: { getInspectorDataForInstance: getInspectorDataForInstance, @@ -9791,11 +9802,11 @@ var roots = new Map(), }.bind(null, findNodeHandle) } }; -var internals$jscomp$inline_1370 = { - bundleType: devToolsConfig$jscomp$inline_1117.bundleType, - version: devToolsConfig$jscomp$inline_1117.version, - rendererPackageName: devToolsConfig$jscomp$inline_1117.rendererPackageName, - rendererConfig: devToolsConfig$jscomp$inline_1117.rendererConfig, +var internals$jscomp$inline_1350 = { + bundleType: devToolsConfig$jscomp$inline_1115.bundleType, + version: devToolsConfig$jscomp$inline_1115.version, + rendererPackageName: devToolsConfig$jscomp$inline_1115.rendererPackageName, + rendererConfig: devToolsConfig$jscomp$inline_1115.rendererConfig, overrideHookState: null, overrideHookStateDeletePath: null, overrideHookStateRenamePath: null, @@ -9811,26 +9822,26 @@ var internals$jscomp$inline_1370 = { return null === fiber ? null : fiber.stateNode; }, findFiberByHostInstance: - devToolsConfig$jscomp$inline_1117.findFiberByHostInstance || + devToolsConfig$jscomp$inline_1115.findFiberByHostInstance || emptyFindFiberByHostInstance, findHostInstancesForRefresh: null, scheduleRefresh: null, scheduleRoot: null, setRefreshHandler: null, getCurrentFiber: null, - reconcilerVersion: "18.3.0-canary-d76fd1b4" + reconcilerVersion: "18.3.0-canary-eebf2655" }; if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) { - var hook$jscomp$inline_1371 = __REACT_DEVTOOLS_GLOBAL_HOOK__; + var hook$jscomp$inline_1351 = __REACT_DEVTOOLS_GLOBAL_HOOK__; if ( - !hook$jscomp$inline_1371.isDisabled && - hook$jscomp$inline_1371.supportsFiber + !hook$jscomp$inline_1351.isDisabled && + hook$jscomp$inline_1351.supportsFiber ) try { - (rendererID = hook$jscomp$inline_1371.inject( - internals$jscomp$inline_1370 + (rendererID = hook$jscomp$inline_1351.inject( + internals$jscomp$inline_1350 )), - (injectedHook = hook$jscomp$inline_1371); + (injectedHook = hook$jscomp$inline_1351); } catch (err) {} } exports.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = { diff --git a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.fb.js b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.fb.js index 429a1515957ac..193b40a250a76 100644 --- a/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.fb.js +++ b/compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.fb.js @@ -7,7 +7,7 @@ * @noflow * @nolint * @preventMunge - * @generated SignedSource<<1ec259d95fb167ed4c8dd8c6c54e4cee>> + * @generated SignedSource<<375996f69ad5d47deb3462f97f5dbef9>> */ "use strict"; @@ -944,7 +944,7 @@ eventPluginOrder = Array.prototype.slice.call([ "ReactNativeBridgeEventPlugin" ]); recomputePluginOrdering(); -var injectedNamesToPlugins$jscomp$inline_257 = { +var injectedNamesToPlugins$jscomp$inline_258 = { ResponderEventPlugin: ResponderEventPlugin, ReactNativeBridgeEventPlugin: { eventTypes: {}, @@ -990,32 +990,32 @@ var injectedNamesToPlugins$jscomp$inline_257 = { } } }, - isOrderingDirty$jscomp$inline_258 = !1, - pluginName$jscomp$inline_259; -for (pluginName$jscomp$inline_259 in injectedNamesToPlugins$jscomp$inline_257) + isOrderingDirty$jscomp$inline_259 = !1, + pluginName$jscomp$inline_260; +for (pluginName$jscomp$inline_260 in injectedNamesToPlugins$jscomp$inline_258) if ( - injectedNamesToPlugins$jscomp$inline_257.hasOwnProperty( - pluginName$jscomp$inline_259 + injectedNamesToPlugins$jscomp$inline_258.hasOwnProperty( + pluginName$jscomp$inline_260 ) ) { - var pluginModule$jscomp$inline_260 = - injectedNamesToPlugins$jscomp$inline_257[pluginName$jscomp$inline_259]; + var pluginModule$jscomp$inline_261 = + injectedNamesToPlugins$jscomp$inline_258[pluginName$jscomp$inline_260]; if ( - !namesToPlugins.hasOwnProperty(pluginName$jscomp$inline_259) || - namesToPlugins[pluginName$jscomp$inline_259] !== - pluginModule$jscomp$inline_260 + !namesToPlugins.hasOwnProperty(pluginName$jscomp$inline_260) || + namesToPlugins[pluginName$jscomp$inline_260] !== + pluginModule$jscomp$inline_261 ) { - if (namesToPlugins[pluginName$jscomp$inline_259]) + if (namesToPlugins[pluginName$jscomp$inline_260]) throw Error( "EventPluginRegistry: Cannot inject two different event plugins using the same name, `" + - (pluginName$jscomp$inline_259 + "`.") + (pluginName$jscomp$inline_260 + "`.") ); - namesToPlugins[pluginName$jscomp$inline_259] = - pluginModule$jscomp$inline_260; - isOrderingDirty$jscomp$inline_258 = !0; + namesToPlugins[pluginName$jscomp$inline_260] = + pluginModule$jscomp$inline_261; + isOrderingDirty$jscomp$inline_259 = !0; } } -isOrderingDirty$jscomp$inline_258 && recomputePluginOrdering(); +isOrderingDirty$jscomp$inline_259 && recomputePluginOrdering(); var instanceCache = new Map(), instanceProps = new Map(); function getInstanceFromTag(tag) { @@ -2338,6 +2338,221 @@ 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)); + enableDeferRootSchedulingToMicrotask || + 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$14 = workInProgressRootRenderLanes, + nextLanes = getNextLanes( + root, + root === workInProgressRoot ? workInProgressRootRenderLanes$14 : 0 + ); + if (0 !== (nextLanes & 3)) + try { + didPerformSomeWork = !0; + workInProgressRootRenderLanes$14 = root; + if (0 !== (executionContext & 6)) + throw Error("Should not already be working."); + if (!flushPassiveEffects()) { + currentUpdateIsNested = nestedUpdateScheduled; + nestedUpdateScheduled = !1; + var exitStatus = renderRootSync( + workInProgressRootRenderLanes$14, + nextLanes + ); + if ( + 0 !== workInProgressRootRenderLanes$14.tag && + 2 === exitStatus + ) { + var originallyAttemptedLanes = nextLanes, + errorRetryLanes = getLanesToRetrySynchronouslyOnError( + workInProgressRootRenderLanes$14, + originallyAttemptedLanes + ); + 0 !== errorRetryLanes && + ((nextLanes = errorRetryLanes), + (exitStatus = recoverFromConcurrentError( + workInProgressRootRenderLanes$14, + originallyAttemptedLanes, + errorRetryLanes + ))); + } + if (1 === exitStatus) + throw ( + ((originallyAttemptedLanes = workInProgressRootFatalError), + prepareFreshStack(workInProgressRootRenderLanes$14, 0), + markRootSuspended( + workInProgressRootRenderLanes$14, + nextLanes, + 0 + ), + ensureRootIsScheduled(workInProgressRootRenderLanes$14), + originallyAttemptedLanes) + ); + 6 === exitStatus + ? markRootSuspended( + workInProgressRootRenderLanes$14, + nextLanes, + workInProgressDeferredLane + ) + : ((workInProgressRootRenderLanes$14.finishedWork = + workInProgressRootRenderLanes$14.current.alternate), + (workInProgressRootRenderLanes$14.finishedLanes = + nextLanes), + commitRoot( + workInProgressRootRenderLanes$14, + workInProgressRootRecoverableErrors, + workInProgressTransitions, + workInProgressDeferredLane + )); + } + ensureRootIsScheduled(workInProgressRootRenderLanes$14); + } 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$6 = 31 - clz32(lanes), + lane = 1 << index$6, + expirationTime = expirationTimes[index$6]; + if (-1 === expirationTime) { + if (0 === (lane & suspendedLanes) || 0 !== (lane & pingedLanes)) + expirationTimes[index$6] = 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 hasForceUpdate = !1; function initializeUpdateQueue(fiber) { fiber.updateQueue = { @@ -3513,264 +3728,49 @@ function pushPrimaryTreeSuspenseHandler(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)); - enableDeferRootSchedulingToMicrotask || - 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$31 = workInProgressRootRenderLanes, - nextLanes = getNextLanes( - root, - root === workInProgressRoot ? workInProgressRootRenderLanes$31 : 0 - ); - if (0 !== (nextLanes & 3)) - try { - didPerformSomeWork = !0; - workInProgressRootRenderLanes$31 = root; - if (0 !== (executionContext & 6)) - throw Error("Should not already be working."); - if (!flushPassiveEffects()) { - currentUpdateIsNested = nestedUpdateScheduled; - nestedUpdateScheduled = !1; - var exitStatus = renderRootSync( - workInProgressRootRenderLanes$31, - nextLanes - ); - if ( - 0 !== workInProgressRootRenderLanes$31.tag && - 2 === exitStatus - ) { - var originallyAttemptedLanes = nextLanes, - errorRetryLanes = getLanesToRetrySynchronouslyOnError( - workInProgressRootRenderLanes$31, - originallyAttemptedLanes - ); - 0 !== errorRetryLanes && - ((nextLanes = errorRetryLanes), - (exitStatus = recoverFromConcurrentError( - workInProgressRootRenderLanes$31, - originallyAttemptedLanes, - errorRetryLanes - ))); - } - if (1 === exitStatus) - throw ( - ((originallyAttemptedLanes = workInProgressRootFatalError), - prepareFreshStack(workInProgressRootRenderLanes$31, 0), - markRootSuspended( - workInProgressRootRenderLanes$31, - nextLanes, - 0 - ), - ensureRootIsScheduled(workInProgressRootRenderLanes$31), - originallyAttemptedLanes) - ); - 6 === exitStatus - ? markRootSuspended( - workInProgressRootRenderLanes$31, - nextLanes, - workInProgressDeferredLane - ) - : ((workInProgressRootRenderLanes$31.finishedWork = - workInProgressRootRenderLanes$31.current.alternate), - (workInProgressRootRenderLanes$31.finishedLanes = - nextLanes), - commitRoot( - workInProgressRootRenderLanes$31, - workInProgressRootRecoverableErrors, - workInProgressTransitions, - workInProgressDeferredLane - )); - } - ensureRootIsScheduled(workInProgressRootRenderLanes$31); - } 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]; + (push(suspenseStackCursor, suspenseStackCursor.current), + push(suspenseHandlerStackCursor, fiber), + null === shellBoundary) + ) { + var current = fiber.alternate; + null !== current && + null !== current.memoizedState && + (shellBoundary = fiber); } - } -} -function throwError(error) { - throw error; + } else reuseSuspenseHandlerOnStack(fiber); } -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 reuseSuspenseHandlerOnStack() { + push(suspenseStackCursor, suspenseStackCursor.current); + push(suspenseHandlerStackCursor, suspenseHandlerStackCursor.current); } -function scheduleTaskForRootDuringMicrotask(root, currentTime) { - for ( - var suspendedLanes = root.suspendedLanes, - pingedLanes = root.pingedLanes, - expirationTimes = root.expirationTimes, - lanes = root.pendingLanes & -62914561; - 0 < lanes; - - ) { - var index$6 = 31 - clz32(lanes), - lane = 1 << index$6, - expirationTime = expirationTimes[index$6]; - if (-1 === expirationTime) { - if (0 === (lane & suspendedLanes) || 0 !== (lane & pingedLanes)) - expirationTimes[index$6] = 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 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, @@ -4925,6 +4925,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." @@ -6148,14 +6296,14 @@ function cutOffTailIfNeeded(renderState, hasRenderedATailFallback) { break; case "collapsed": lastTailNode = renderState.tail; - for (var lastTailNode$68 = null; null !== lastTailNode; ) - null !== lastTailNode.alternate && (lastTailNode$68 = lastTailNode), + for (var lastTailNode$69 = null; null !== lastTailNode; ) + null !== lastTailNode.alternate && (lastTailNode$69 = lastTailNode), (lastTailNode = lastTailNode.sibling); - null === lastTailNode$68 + null === lastTailNode$69 ? hasRenderedATailFallback || null === renderState.tail ? (renderState.tail = null) : (renderState.tail.sibling = null) - : (lastTailNode$68.sibling = null); + : (lastTailNode$69.sibling = null); } } function bubbleProperties(completedWork) { @@ -6167,53 +6315,53 @@ function bubbleProperties(completedWork) { if (didBailout) if (0 !== (completedWork.mode & 2)) { for ( - var treeBaseDuration$70 = completedWork.selfBaseDuration, - child$71 = completedWork.child; - null !== child$71; + var treeBaseDuration$71 = completedWork.selfBaseDuration, + child$72 = completedWork.child; + null !== child$72; ) - (newChildLanes |= child$71.lanes | child$71.childLanes), - (subtreeFlags |= child$71.subtreeFlags & 31457280), - (subtreeFlags |= child$71.flags & 31457280), - (treeBaseDuration$70 += child$71.treeBaseDuration), - (child$71 = child$71.sibling); - completedWork.treeBaseDuration = treeBaseDuration$70; + (newChildLanes |= child$72.lanes | child$72.childLanes), + (subtreeFlags |= child$72.subtreeFlags & 31457280), + (subtreeFlags |= child$72.flags & 31457280), + (treeBaseDuration$71 += child$72.treeBaseDuration), + (child$72 = child$72.sibling); + completedWork.treeBaseDuration = treeBaseDuration$71; } else for ( - treeBaseDuration$70 = completedWork.child; - null !== treeBaseDuration$70; + treeBaseDuration$71 = completedWork.child; + null !== treeBaseDuration$71; ) (newChildLanes |= - treeBaseDuration$70.lanes | treeBaseDuration$70.childLanes), - (subtreeFlags |= treeBaseDuration$70.subtreeFlags & 31457280), - (subtreeFlags |= treeBaseDuration$70.flags & 31457280), - (treeBaseDuration$70.return = completedWork), - (treeBaseDuration$70 = treeBaseDuration$70.sibling); + treeBaseDuration$71.lanes | treeBaseDuration$71.childLanes), + (subtreeFlags |= treeBaseDuration$71.subtreeFlags & 31457280), + (subtreeFlags |= treeBaseDuration$71.flags & 31457280), + (treeBaseDuration$71.return = completedWork), + (treeBaseDuration$71 = treeBaseDuration$71.sibling); else if (0 !== (completedWork.mode & 2)) { - treeBaseDuration$70 = completedWork.actualDuration; - child$71 = completedWork.selfBaseDuration; + treeBaseDuration$71 = completedWork.actualDuration; + child$72 = completedWork.selfBaseDuration; for (var child = completedWork.child; null !== child; ) (newChildLanes |= child.lanes | child.childLanes), (subtreeFlags |= child.subtreeFlags), (subtreeFlags |= child.flags), - (treeBaseDuration$70 += child.actualDuration), - (child$71 += child.treeBaseDuration), + (treeBaseDuration$71 += child.actualDuration), + (child$72 += child.treeBaseDuration), (child = child.sibling); - completedWork.actualDuration = treeBaseDuration$70; - completedWork.treeBaseDuration = child$71; + completedWork.actualDuration = treeBaseDuration$71; + completedWork.treeBaseDuration = child$72; } else for ( - treeBaseDuration$70 = completedWork.child; - null !== treeBaseDuration$70; + treeBaseDuration$71 = completedWork.child; + null !== treeBaseDuration$71; ) (newChildLanes |= - treeBaseDuration$70.lanes | treeBaseDuration$70.childLanes), - (subtreeFlags |= treeBaseDuration$70.subtreeFlags), - (subtreeFlags |= treeBaseDuration$70.flags), - (treeBaseDuration$70.return = completedWork), - (treeBaseDuration$70 = treeBaseDuration$70.sibling); + treeBaseDuration$71.lanes | treeBaseDuration$71.childLanes), + (subtreeFlags |= treeBaseDuration$71.subtreeFlags), + (subtreeFlags |= treeBaseDuration$71.flags), + (treeBaseDuration$71.return = completedWork), + (treeBaseDuration$71 = treeBaseDuration$71.sibling); completedWork.subtreeFlags |= subtreeFlags; completedWork.childLanes = newChildLanes; return didBailout; @@ -6723,8 +6871,8 @@ function safelyDetachRef(current, nearestMountedAncestor) { recordLayoutEffectDuration(current); } else ref(null); - } catch (error$89) { - captureCommitPhaseError(current, nearestMountedAncestor, error$89); + } catch (error$90) { + captureCommitPhaseError(current, nearestMountedAncestor, error$90); } else ref.current = null; } @@ -6857,10 +7005,10 @@ function commitHookEffectListMount(flags, finishedWork) { injectedProfilingHooks.markComponentLayoutEffectMountStarted( finishedWork ); - var create$90 = effect.create, + var create$91 = effect.create, inst = effect.inst; - create$90 = create$90(); - inst.destroy = create$90; + create$91 = create$91(); + inst.destroy = create$91; 0 !== (flags & 8) ? null !== injectedProfilingHooks && "function" === @@ -6888,8 +7036,8 @@ function commitHookLayoutEffects(finishedWork, hookFlags) { } else try { commitHookEffectListMount(hookFlags, finishedWork); - } catch (error$92) { - captureCommitPhaseError(finishedWork, finishedWork.return, error$92); + } catch (error$93) { + captureCommitPhaseError(finishedWork, finishedWork.return, error$93); } } function commitClassCallbacks(finishedWork) { @@ -6969,11 +7117,11 @@ function commitLayoutEffectOnFiber(finishedRoot, current, finishedWork) { } else try { finishedRoot.componentDidMount(); - } catch (error$93) { + } catch (error$94) { captureCommitPhaseError( finishedWork, finishedWork.return, - error$93 + error$94 ); } else { @@ -6990,11 +7138,11 @@ function commitLayoutEffectOnFiber(finishedRoot, current, finishedWork) { current, finishedRoot.__reactInternalSnapshotBeforeUpdate ); - } catch (error$94) { + } catch (error$95) { captureCommitPhaseError( finishedWork, finishedWork.return, - error$94 + error$95 ); } recordLayoutEffectDuration(finishedWork); @@ -7005,11 +7153,11 @@ function commitLayoutEffectOnFiber(finishedRoot, current, finishedWork) { current, finishedRoot.__reactInternalSnapshotBeforeUpdate ); - } catch (error$95) { + } catch (error$96) { captureCommitPhaseError( finishedWork, finishedWork.return, - error$95 + error$96 ); } } @@ -7525,22 +7673,22 @@ function commitMutationEffectsOnFiber(finishedWork, root) { try { startLayoutEffectTimer(), commitHookEffectListUnmount(5, finishedWork, finishedWork.return); - } catch (error$104) { + } catch (error$105) { captureCommitPhaseError( finishedWork, finishedWork.return, - error$104 + error$105 ); } recordLayoutEffectDuration(finishedWork); } else try { commitHookEffectListUnmount(5, finishedWork, finishedWork.return); - } catch (error$105) { + } catch (error$106) { captureCommitPhaseError( finishedWork, finishedWork.return, - error$105 + error$106 ); } } @@ -7588,8 +7736,8 @@ function commitMutationEffectsOnFiber(finishedWork, root) { viewConfig.uiViewClassName, updatePayload ); - } catch (error$108) { - captureCommitPhaseError(finishedWork, finishedWork.return, error$108); + } catch (error$109) { + captureCommitPhaseError(finishedWork, finishedWork.return, error$109); } } break; @@ -7609,8 +7757,8 @@ function commitMutationEffectsOnFiber(finishedWork, root) { "RCTRawText", { text: current } ); - } catch (error$109) { - captureCommitPhaseError(finishedWork, finishedWork.return, error$109); + } catch (error$110) { + captureCommitPhaseError(finishedWork, finishedWork.return, error$110); } } break; @@ -7722,11 +7870,11 @@ function commitMutationEffectsOnFiber(finishedWork, root) { if (null === current) try { throw Error("Not yet implemented."); - } catch (error$98) { + } catch (error$99) { captureCommitPhaseError( finishedWork, finishedWork.return, - error$98 + error$99 ); } } else if ( @@ -7800,12 +7948,12 @@ function commitReconciliationEffects(finishedWork) { break; case 3: case 4: - var parent$99 = JSCompiler_inline_result.stateNode.containerInfo, - before$100 = getHostSibling(finishedWork); + var parent$100 = JSCompiler_inline_result.stateNode.containerInfo, + before$101 = getHostSibling(finishedWork); insertOrAppendPlacementNodeIntoContainer( finishedWork, - before$100, - parent$99 + before$101, + parent$100 ); break; default: @@ -7991,8 +8139,8 @@ function commitHookPassiveMountEffects(finishedWork, hookFlags) { } else try { commitHookEffectListMount(hookFlags, finishedWork); - } catch (error$113) { - captureCommitPhaseError(finishedWork, finishedWork.return, error$113); + } catch (error$114) { + captureCommitPhaseError(finishedWork, finishedWork.return, error$114); } } function recursivelyTraversePassiveMountEffects(root, parentFiber) { @@ -8740,13 +8888,13 @@ function renderRootSync(root, lanes) { default: (workInProgressSuspendedReason = 0), (workInProgressThrownValue = null), - throwAndUnwindWorkLoop(memoizedUpdaters, thrownValue); + throwAndUnwindWorkLoop(root, memoizedUpdaters, thrownValue); } } workLoopSync(); break; - } catch (thrownValue$114) { - handleThrow(root, thrownValue$114); + } catch (thrownValue$115) { + handleThrow(root, thrownValue$115); } while (1); lanes && root.shellSuspendCounter++; @@ -8794,7 +8942,7 @@ function renderRootConcurrent(root, lanes) { case 1: workInProgressSuspendedReason = 0; workInProgressThrownValue = null; - throwAndUnwindWorkLoop(lanes, memoizedUpdaters); + throwAndUnwindWorkLoop(root, lanes, memoizedUpdaters); break; case 2: if (isThenableResolved(memoizedUpdaters)) { @@ -8824,7 +8972,7 @@ function renderRootConcurrent(root, lanes) { replaySuspendedUnitOfWork(lanes)) : ((workInProgressSuspendedReason = 0), (workInProgressThrownValue = null), - throwAndUnwindWorkLoop(lanes, memoizedUpdaters)); + throwAndUnwindWorkLoop(root, lanes, memoizedUpdaters)); break; case 5: switch (workInProgress.tag) { @@ -8847,12 +8995,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(); @@ -8863,8 +9011,8 @@ function renderRootConcurrent(root, lanes) { } workLoopConcurrent(); break; - } catch (thrownValue$116) { - handleThrow(root, thrownValue$116); + } catch (thrownValue$117) { + handleThrow(root, thrownValue$117); } while (1); resetContextDependencies(); @@ -8959,200 +9107,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$37 = offscreenQueue.retryQueue; - null === retryQueue$37 - ? (offscreenQueue.retryQueue = new Set([wakeable])) - : retryQueue$37.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; @@ -9340,11 +9351,11 @@ function flushPassiveEffects() { _finishedWork$memoize = finishedWork.memoizedProps, id = _finishedWork$memoize.id, onPostCommit = _finishedWork$memoize.onPostCommit, - commitTime$91 = commitTime, + commitTime$92 = commitTime, phase = null === finishedWork.alternate ? "mount" : "update"; currentUpdateIsNested && (phase = "nested-update"); "function" === typeof onPostCommit && - onPostCommit(id, phase, passiveEffectDuration, commitTime$91); + onPostCommit(id, phase, passiveEffectDuration, commitTime$92); var parentFiber = finishedWork.return; b: for (; null !== parentFiber; ) { switch (parentFiber.tag) { @@ -10474,10 +10485,10 @@ batchedUpdatesImpl = function (fn, a) { } }; var roots = new Map(), - devToolsConfig$jscomp$inline_1195 = { + devToolsConfig$jscomp$inline_1193 = { findFiberByHostInstance: getInstanceFromTag, bundleType: 0, - version: "18.3.0-canary-f4e963ab", + version: "18.3.0-canary-aa92563e", rendererPackageName: "react-native-renderer", rendererConfig: { getInspectorDataForInstance: getInspectorDataForInstance, @@ -10507,10 +10518,10 @@ var roots = new Map(), } catch (err) {} return hook.checkDCE ? !0 : !1; })({ - bundleType: devToolsConfig$jscomp$inline_1195.bundleType, - version: devToolsConfig$jscomp$inline_1195.version, - rendererPackageName: devToolsConfig$jscomp$inline_1195.rendererPackageName, - rendererConfig: devToolsConfig$jscomp$inline_1195.rendererConfig, + bundleType: devToolsConfig$jscomp$inline_1193.bundleType, + version: devToolsConfig$jscomp$inline_1193.version, + rendererPackageName: devToolsConfig$jscomp$inline_1193.rendererPackageName, + rendererConfig: devToolsConfig$jscomp$inline_1193.rendererConfig, overrideHookState: null, overrideHookStateDeletePath: null, overrideHookStateRenamePath: null, @@ -10526,14 +10537,14 @@ var roots = new Map(), return null === fiber ? null : fiber.stateNode; }, findFiberByHostInstance: - devToolsConfig$jscomp$inline_1195.findFiberByHostInstance || + devToolsConfig$jscomp$inline_1193.findFiberByHostInstance || emptyFindFiberByHostInstance, findHostInstancesForRefresh: null, scheduleRefresh: null, scheduleRoot: null, setRefreshHandler: null, getCurrentFiber: null, - reconcilerVersion: "18.3.0-canary-f4e963ab" + reconcilerVersion: "18.3.0-canary-aa92563e" }); exports.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = { computeComponentStackForErrorReporting: function (reactTag) {